Line data Source code
1 : #ifndef HEADER_fd_src_archive_fd_ar_h 2 : #define HEADER_fd_src_archive_fd_ar_h 3 : 4 : /* AR(5) is a simple archive format combining multiple files into one. 5 : The file format is structurally similar to TAR. 6 : 7 : This package provides a simple streaming AR reader. 8 : 9 : ### File Format 10 : 11 : Reference: https://www.freebsd.org/cgi/man.cgi?query=ar&sektion=5 12 : 13 : +------------------------+ 14 : | Archive Magic | 8 bytes "<arch>!\n" 15 : +------------------------+ 16 : | File Header 0 | 60 bytes 17 : +------------------------+ 18 : | File Content | variable length 19 : | | 20 : +------------------------+ 21 : | File Header 1 | 60 bytes (aligned to 2 bytes) 22 : +------------------------+ 23 : | File Content | variable length 24 : | | 25 : .......................... 26 : 27 : ### Usage 28 : 29 : The `ar(1)` tool from GNU binutils can be used to create such archive files. 30 : 31 : ar rcDS <archive_file> <file> <file> <file...> 32 : 33 : Basic usage: 34 : 35 : ... at this point, stream should be pointed at the first byte 36 : ... of the ar file magic 37 : 38 : fd_ar_read_init( stream ); 39 : for(;;) { 40 : fd_ar_meta_t meta[1]; 41 : if( fd_ar_read_next( stream, meta ) ) break; 42 : 43 : ... at this point, stream is pointed at first byte of contents of 44 : ... the next unprocessed file in the ar and there are 45 : ... meta->filesz bytes ni this file 46 : ... process next file here, advancing the stream position exactly 47 : 48 : ... meta->filesz bytes before next iteration 49 : } 50 : 51 : More nuanced error handling and what not is possible. See 52 : descriptions below. */ 53 : 54 : #include "../fd_util_base.h" 55 : 56 : /* See note in fd_ar.c for details on use of long for these fields. */ 57 : 58 1140 : #define FD_AR_META_IDENT_SZ (17UL) /* 16 + 1 for '\0' termination */ 59 : 60 : struct fd_ar_meta { 61 : long mtime; 62 : long uid; 63 : long gid; 64 : long mode; 65 : long filesz; /* Guaranteed to be non-negative */ 66 : char ident[ FD_AR_META_IDENT_SZ ]; /* Guaranteed '\0' terminated */ 67 : }; 68 : 69 : typedef struct fd_ar_meta fd_ar_meta_t; 70 : 71 : FD_PROTOTYPES_BEGIN 72 : 73 : /* fd_ar_read_init starts reading an ar archive in the given stream. On 74 : entry, assumes stream is positioned on the first byte of the ar 75 : magic. If FD_HAS_HOSTED, stream is FILE * pointer. Otherwise stream 76 : should be the equivalent for that target. 77 : 78 : Returns 0 on success and non-zero strerror compatible error code on 79 : failure. If successful, the stream will be positioned on the first 80 : byte immediately after the ar magic. If not, the stream state is 81 : undefined. 82 : 83 : Error codes include: 84 : 85 : - EINVAL: NULL stream 86 : - ENOENT: failed due to EOF 87 : - EIO: failed due to stream i/o failure 88 : - EPROTO: failed due to malformed ar file (bad magic) */ 89 : 90 : int 91 : fd_ar_read_init( void * stream ); 92 : 93 : /* fd_ar_read_next starts reading the archive file in the given stream. 94 : On entry, assumes stream is positioned on the first byte immediately 95 : after the archive magic or the first byte immediately after the just 96 : processed archive file content. If FD_HAS_HOSTED, stream should 97 : point to an open FILE handle. Otherwise stream should be to the 98 : equivalent is provided for that target. 99 : 100 : Returns 0 on success and non-zero strerror compatible error code on 101 : failure. If successful, the stream will be positioned on the first 102 : byte of the file content to process next and meta will be populated 103 : with details from the archive header. 104 : 105 : If opt_meta is non-NULL, on success, *opt_meta will be populated with 106 : archive file metadata on return. Of note, the size of the file 107 : contents is opt_meta->filesz bytes (a non-negative number). 108 : Otherwise, *opt_meta will be untouched. 109 : 110 : Before fd_ar_read_next is called on the get the next file, it should 111 : position stream just after the last byte of the file contents. E.g. 112 : to skip over file contents in a hosted environment, provide opt_meta 113 : and do: 114 : 115 : fseek( stream, opt_meta->filesz, SEEK_CUR ) 116 : 117 : If the caller did not provide opt_meta to get the filesz, the caller 118 : should know via other means how to position the stream after the file 119 : contents. 120 : 121 : Error codes include: 122 : 123 : - EINVAL: NULL stream 124 : - ENOENT: failed due to EOF 125 : - EIO: failed due to stream i/o failure 126 : - EPROTO: failed due to malformed ar file (bad magic) */ 127 : 128 : int 129 : fd_ar_read_next( void * stream, 130 : fd_ar_meta_t * opt_meta ); 131 : 132 : /* FIXME: CONSIDER AN FD_AR_READ_FINI THAT WOULD MOVE THE STREAM POINTER 133 : TO THE END OF THE AR FILE? */ 134 : 135 : FD_PROTOTYPES_END 136 : 137 : #endif /* HEADER_fd_src_archive_fd_ar_h */