@@ -89,6 +89,7 @@ static int write_null_bytes(mtar_t *tar, int n) {
8989
9090static int raw_to_header (mtar_header_t * h , const mtar_raw_header_t * rh ) {
9191 unsigned chksum1 , chksum2 ;
92+ mtar_size_t filesize ;
9293
9394 /* If the checksum starts with a null byte we assume the record is NULL */
9495 if (* rh -> checksum == '\0' ) {
@@ -105,24 +106,68 @@ static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) {
105106 /* Load raw header into header */
106107 sscanf (rh -> mode , "%o" , & h -> mode );
107108 sscanf (rh -> owner , "%o" , & h -> owner );
108- sscanf (rh -> size , "%12lo" , & h -> size );
109109 sscanf (rh -> mtime , "%o" , & h -> mtime );
110110 h -> type = rh -> type ;
111111 strcpy (h -> name , rh -> name );
112112 strcpy (h -> linkname , rh -> linkname );
113113
114+ /* Load size field */
115+ if ((rh -> size [0 ] & 0x80 ) == 0 ) {
116+ #ifdef _MSC_VER
117+ sscanf (rh -> size , "%12llo" , & h -> size );
118+ #else
119+ sscanf (rh -> size , "%12lo" , & h -> size );
120+ #endif
121+ } else {
122+ h -> size = (rh -> size [0 ] & 0x7f ) | (rh -> size [0 ] & 0x40 ? 0x80 : 0 );
123+ uint8_t * p8 = (uint8_t * )& rh -> size + 1 ;
124+ while (p8 != (uint8_t * )& rh -> size + sizeof (rh -> size )) {
125+ if (h -> size >= ((mtar_size_t )1 << (sizeof (h -> size ) - 1 ) * 8 )) {
126+ return MTAR_EFAILURE ;
127+ }
128+ h -> size = ((mtar_size_t )h -> size << 8 ) + * p8 ++ ;
129+ }
130+ }
131+
114132 return MTAR_ESUCCESS ;
115133}
116134
117135
118136static int header_to_raw (mtar_raw_header_t * rh , const mtar_header_t * h ) {
119137 unsigned chksum ;
138+ mtar_size_t filesize = h -> size ;
120139
121140 /* Load header into raw header */
122141 memset (rh , 0 , sizeof (* rh ));
142+
143+ /* Store size in ASCII octal digits or base-256 formats */
144+ if (sizeof (mtar_size_t ) <= 4 || filesize <= (mtar_size_t )0777777777777LL ) {
145+ #ifdef _MSC_VER
146+ sprintf (rh -> size , "%llo" , h -> size );
147+ #else
148+ sprintf (rh -> size , "%lo" , h -> size );
149+ #endif
150+ } else if (sizeof (filesize ) < sizeof (rh -> size )) {
151+ /* GNU tar uses "base-256 encoding" for very large numbers.
152+ * Encoding is binary, with highest bit always set as a marker
153+ * and sign in next-highest bit:
154+ * 80 00 .. 00 - zero
155+ * bf ff .. ff - largest positive number
156+ * ff ff .. ff - minus 1
157+ * c0 00 .. 00 - smallest negative number
158+ */
159+ uint8_t * p8 = (uint8_t * )& rh -> size + sizeof (rh -> size );
160+ do {
161+ * -- p8 = (uint8_t )filesize ;
162+ filesize >>= 8 ;
163+ } while (p8 != (uint8_t * )& rh -> size );
164+ * p8 |= 0x80 ;
165+ } else {
166+ return MTAR_EFAILURE ;
167+ }
168+
123169 sprintf (rh -> mode , "%o" , h -> mode );
124170 sprintf (rh -> owner , "%o" , h -> owner );
125- sprintf (rh -> size , "%lo" , h -> size );
126171 sprintf (rh -> mtime , "%o" , h -> mtime );
127172 rh -> type = h -> type ? h -> type : MTAR_TREG ;
128173 strcpy (rh -> name , h -> name );
@@ -332,9 +377,6 @@ int mtar_write_header(mtar_t *tar, const mtar_header_t *h) {
332377
333378int mtar_write_file_header (mtar_t * tar , const char * name , mtar_size_t size ) {
334379 mtar_header_t h ;
335- if (size >= 0777777777777 ) {
336- return MTAR_EFAILURE ;
337- }
338380 /* Build header */
339381 memset (& h , 0 , sizeof (h ));
340382 strcpy (h .name , name );
0 commit comments