Fossil SCM
Use a Blob object rather than a custom printf function in order to construct the PAX header for tarballs.
Commit
02ce8b4a46822a7af941515516299701044750ad
Parent
2ef37b3b2a0c2dd…
1 file changed
+26
-70
+26
-70
| --- src/tar.c | ||
| +++ src/tar.c | ||
| @@ -28,13 +28,11 @@ | ||
| 28 | 28 | static struct tarball_t { |
| 29 | 29 | unsigned char *aHdr; /* Space for building headers */ |
| 30 | 30 | char *zSpaces; /* Spaces for padding */ |
| 31 | 31 | char *zPrevDir; /* Name of directory for previous entry */ |
| 32 | 32 | int nPrevDirAlloc; /* size of zPrevDir */ |
| 33 | - char *pScratch; /* scratch buffer used to build PAX data */ | |
| 34 | - int nScratchUsed; /* part of buffer containing data */ | |
| 35 | - int nScratchAlloc; /* size of buffer */ | |
| 33 | + Blob pax; /* PAX data */ | |
| 36 | 34 | } tball; |
| 37 | 35 | |
| 38 | 36 | |
| 39 | 37 | /* |
| 40 | 38 | ** field lengths of 'ustar' name and prefix fields. |
| @@ -55,13 +53,11 @@ | ||
| 55 | 53 | tball.zSpaces = (char*)&tball.aHdr[512]; |
| 56 | 54 | /* zPrevDir init */ |
| 57 | 55 | tball.zPrevDir = NULL; |
| 58 | 56 | tball.nPrevDirAlloc = 0; |
| 59 | 57 | /* scratch buffer init */ |
| 60 | - tball.pScratch = NULL; | |
| 61 | - tball.nScratchUsed = 0; | |
| 62 | - tball.nScratchAlloc = 0; | |
| 58 | + blob_zero(&tball.pax); | |
| 63 | 59 | |
| 64 | 60 | memcpy(&tball.aHdr[108], "0000000", 8); /* Owner ID */ |
| 65 | 61 | memcpy(&tball.aHdr[116], "0000000", 8); /* Group ID */ |
| 66 | 62 | memcpy(&tball.aHdr[257], "ustar\00000", 8); /* POSIX.1 format */ |
| 67 | 63 | memcpy(&tball.aHdr[265], "nobody", 7); /* Owner name */ |
| @@ -70,48 +66,10 @@ | ||
| 70 | 66 | db_multi_exec( |
| 71 | 67 | "CREATE TEMP TABLE dir(name UNIQUE);" |
| 72 | 68 | ); |
| 73 | 69 | } |
| 74 | 70 | |
| 75 | - | |
| 76 | -/* | |
| 77 | -** print to the scratch buffer | |
| 78 | -** | |
| 79 | -** used to build the Pax Interchange Format data, and create | |
| 80 | -** pseudo-file names for the header data. | |
| 81 | -** | |
| 82 | -** The buffer is grown automatically to accommodate the data. | |
| 83 | -*/ | |
| 84 | -static int scratch_printf( | |
| 85 | - const char *fmt, | |
| 86 | - ... | |
| 87 | -){ | |
| 88 | - for(;;){ | |
| 89 | - int newSize, minSpace, n; | |
| 90 | - /* calculate space in buffer */ | |
| 91 | - int space = tball.nScratchAlloc - tball.nScratchUsed; | |
| 92 | - /* format the string */ | |
| 93 | - va_list vl; | |
| 94 | - va_start(vl, fmt); | |
| 95 | - n = vsnprintf(&tball.pScratch[tball.nScratchUsed], space, fmt, vl); | |
| 96 | - assert(n >= 0); | |
| 97 | - va_end(vl); | |
| 98 | - /* if it fit we're done */ | |
| 99 | - if(n < space) | |
| 100 | - return n; | |
| 101 | - /* buffer too short: calculate reasonable new size */ | |
| 102 | - minSpace = tball.nScratchUsed+n+1; | |
| 103 | - newSize = 2 * tball.nScratchAlloc; | |
| 104 | - if(newSize < minSpace) | |
| 105 | - newSize = minSpace; | |
| 106 | - /* grow the buffer */ | |
| 107 | - tball.pScratch = fossil_realloc(tball.pScratch, newSize); | |
| 108 | - tball.nScratchAlloc = newSize; | |
| 109 | - /* loop to try again */ | |
| 110 | - } | |
| 111 | -} | |
| 112 | - | |
| 113 | 71 | |
| 114 | 72 | /* |
| 115 | 73 | ** verify that lla characters in 'zName' are in the |
| 116 | 74 | ** ISO646 (=ASCII) character set. |
| 117 | 75 | */ |
| @@ -120,12 +78,11 @@ | ||
| 120 | 78 | int nName /* path length */ |
| 121 | 79 | ){ |
| 122 | 80 | int i; |
| 123 | 81 | for(i = 0; i < nName; i++){ |
| 124 | 82 | unsigned char c = (unsigned char)zName[i]; |
| 125 | - if(c > 0x7e) | |
| 126 | - return 0; | |
| 83 | + if( c>0x7e ) return 0; | |
| 127 | 84 | } |
| 128 | 85 | return 1; |
| 129 | 86 | } |
| 130 | 87 | |
| 131 | 88 | |
| @@ -194,12 +151,11 @@ | ||
| 194 | 151 | for(i = 1; i+1 < nName; i++) |
| 195 | 152 | if(zName[i] == '/'){ |
| 196 | 153 | split = i+1; |
| 197 | 154 | /* if the split position is within USTAR_NAME_LEN bytes from |
| 198 | 155 | * the end we can quit */ |
| 199 | - if(nName - split <= USTAR_NAME_LEN) | |
| 200 | - break; | |
| 156 | + if(nName - split <= USTAR_NAME_LEN) break; | |
| 201 | 157 | } |
| 202 | 158 | } |
| 203 | 159 | return split; |
| 204 | 160 | } |
| 205 | 161 | |
| @@ -214,12 +170,13 @@ | ||
| 214 | 170 | char *pName, /* name field */ |
| 215 | 171 | char *pPrefix /* prefix field */ |
| 216 | 172 | ){ |
| 217 | 173 | int split = find_split_pos(zName, nName); |
| 218 | 174 | /* check whether both pieces fit */ |
| 219 | - if(nName - split > USTAR_NAME_LEN || split > USTAR_PREFIX_LEN+1) | |
| 175 | + if(nName - split > USTAR_NAME_LEN || split > USTAR_PREFIX_LEN+1){ | |
| 220 | 176 | return 0; /* no */ |
| 177 | + } | |
| 221 | 178 | |
| 222 | 179 | /* extract name */ |
| 223 | 180 | padded_copy(pName, USTAR_NAME_LEN, &zName[split], nName - split); |
| 224 | 181 | |
| 225 | 182 | /* extract prefix */ |
| @@ -242,17 +199,17 @@ | ||
| 242 | 199 | int bHeader /* is this a 'x' type tar header? */ |
| 243 | 200 | ){ |
| 244 | 201 | int split; |
| 245 | 202 | |
| 246 | 203 | /* if this is a Pax Interchange header prepend "PaxHeader/" |
| 247 | - * so we can tell files apart from metadata */ | |
| 248 | - if(bHeader){ | |
| 249 | - int n; | |
| 250 | - tball.nScratchUsed = 0; | |
| 251 | - n = scratch_printf("PaxHeader/%*.*s", nName, nName, zName); | |
| 252 | - zName = tball.pScratch; | |
| 253 | - nName = n; | |
| 204 | + ** so we can tell files apart from metadata */ | |
| 205 | + if( bHeader ){ | |
| 206 | + int n; | |
| 207 | + blob_reset(&tball.pax); | |
| 208 | + blob_appendf(&tball.pax, "PaxHeader/%*.*s", nName, nName, zName); | |
| 209 | + zName = blob_buffer(&tball.pax); | |
| 210 | + nName = blob_size(&tball.pax); | |
| 254 | 211 | } |
| 255 | 212 | |
| 256 | 213 | /* find the split position */ |
| 257 | 214 | split = find_split_pos(zName, nName); |
| 258 | 215 | |
| @@ -284,19 +241,19 @@ | ||
| 284 | 241 | for(n = blen; n > 0; ){ |
| 285 | 242 | blen++; next10 *= 10; |
| 286 | 243 | n /= 10; |
| 287 | 244 | } |
| 288 | 245 | /* adding the length extended the length field? */ |
| 289 | - if(blen > next10) | |
| 246 | + if(blen > next10){ | |
| 290 | 247 | blen++; |
| 248 | + } | |
| 291 | 249 | /* build the string */ |
| 292 | - n = scratch_printf("%d %s=%*.*s\n", blen, zField, nValue, nValue, zValue); | |
| 250 | + blob_appendf(&tball.pax, "%d %s=%*.*s\n", blen, zField, nValue, nValue, zValue); | |
| 293 | 251 | /* this _must_ be right */ |
| 294 | - if(n != blen) | |
| 252 | + if(blob_size(&tball.pax) != blen){ | |
| 295 | 253 | fossil_fatal("internal error: PAX tar header has bad length"); |
| 296 | - /* add length to scratch buffer */ | |
| 297 | - tball.nScratchUsed += blen; | |
| 254 | + } | |
| 298 | 255 | } |
| 299 | 256 | |
| 300 | 257 | |
| 301 | 258 | /* |
| 302 | 259 | ** set the header type, calculate the checksum and output |
| @@ -338,22 +295,24 @@ | ||
| 338 | 295 | int lastPage; |
| 339 | 296 | /* add a file name for interoperability with older programs */ |
| 340 | 297 | approximate_split_path(zName, nName, tball.aHdr, &tball.aHdr[345], 1); |
| 341 | 298 | |
| 342 | 299 | /* generate the Pax Interchange path header */ |
| 343 | - tball.nScratchUsed = 0; | |
| 300 | + blob_reset(&tball.pax); | |
| 344 | 301 | add_pax_header("path", zName, nName); |
| 345 | 302 | |
| 346 | 303 | /* set the header length, and write the header */ |
| 347 | - sqlite3_snprintf(12, (char*)&tball.aHdr[124], "%011o", tball.nScratchUsed); | |
| 304 | + sqlite3_snprintf(12, (char*)&tball.aHdr[124], "%011o", | |
| 305 | + blob_size(&tball.pax)); | |
| 348 | 306 | cksum_and_write_header('x'); |
| 349 | 307 | |
| 350 | 308 | /* write the Pax Interchange data */ |
| 351 | - gzip_step(tball.pScratch, tball.nScratchUsed); | |
| 352 | - lastPage = tball.nScratchUsed % 512; | |
| 353 | - if( lastPage!=0 ) | |
| 309 | + gzip_step(blob_buffer(&tball.pax), blob_size(&tball.pax)); | |
| 310 | + lastPage = blob_size(&tball.pax) % 512; | |
| 311 | + if( lastPage!=0 ){ | |
| 354 | 312 | gzip_step(tball.zSpaces, 512 - lastPage); |
| 313 | + } | |
| 355 | 314 | |
| 356 | 315 | /* generate an approximate path for the regular header */ |
| 357 | 316 | approximate_split_path(zName, nName, tball.aHdr, &tball.aHdr[345], 0); |
| 358 | 317 | } |
| 359 | 318 | /* set the size */ |
| @@ -431,14 +390,11 @@ | ||
| 431 | 390 | fossil_free(tball.aHdr); |
| 432 | 391 | tball.aHdr = 0; |
| 433 | 392 | fossil_free(tball.zPrevDir); |
| 434 | 393 | tball.zPrevDir = NULL; |
| 435 | 394 | tball.nPrevDirAlloc = 0; |
| 436 | - fossil_free(tball.pScratch); | |
| 437 | - tball.pScratch = NULL; | |
| 438 | - tball.nScratchUsed = 0; | |
| 439 | - tball.nScratchAlloc = 0; | |
| 395 | + blob_reset(&tball.pax); | |
| 440 | 396 | } |
| 441 | 397 | |
| 442 | 398 | |
| 443 | 399 | /* |
| 444 | 400 | ** COMMAND: test-tarball |
| 445 | 401 |
| --- src/tar.c | |
| +++ src/tar.c | |
| @@ -28,13 +28,11 @@ | |
| 28 | static struct tarball_t { |
| 29 | unsigned char *aHdr; /* Space for building headers */ |
| 30 | char *zSpaces; /* Spaces for padding */ |
| 31 | char *zPrevDir; /* Name of directory for previous entry */ |
| 32 | int nPrevDirAlloc; /* size of zPrevDir */ |
| 33 | char *pScratch; /* scratch buffer used to build PAX data */ |
| 34 | int nScratchUsed; /* part of buffer containing data */ |
| 35 | int nScratchAlloc; /* size of buffer */ |
| 36 | } tball; |
| 37 | |
| 38 | |
| 39 | /* |
| 40 | ** field lengths of 'ustar' name and prefix fields. |
| @@ -55,13 +53,11 @@ | |
| 55 | tball.zSpaces = (char*)&tball.aHdr[512]; |
| 56 | /* zPrevDir init */ |
| 57 | tball.zPrevDir = NULL; |
| 58 | tball.nPrevDirAlloc = 0; |
| 59 | /* scratch buffer init */ |
| 60 | tball.pScratch = NULL; |
| 61 | tball.nScratchUsed = 0; |
| 62 | tball.nScratchAlloc = 0; |
| 63 | |
| 64 | memcpy(&tball.aHdr[108], "0000000", 8); /* Owner ID */ |
| 65 | memcpy(&tball.aHdr[116], "0000000", 8); /* Group ID */ |
| 66 | memcpy(&tball.aHdr[257], "ustar\00000", 8); /* POSIX.1 format */ |
| 67 | memcpy(&tball.aHdr[265], "nobody", 7); /* Owner name */ |
| @@ -70,48 +66,10 @@ | |
| 70 | db_multi_exec( |
| 71 | "CREATE TEMP TABLE dir(name UNIQUE);" |
| 72 | ); |
| 73 | } |
| 74 | |
| 75 | |
| 76 | /* |
| 77 | ** print to the scratch buffer |
| 78 | ** |
| 79 | ** used to build the Pax Interchange Format data, and create |
| 80 | ** pseudo-file names for the header data. |
| 81 | ** |
| 82 | ** The buffer is grown automatically to accommodate the data. |
| 83 | */ |
| 84 | static int scratch_printf( |
| 85 | const char *fmt, |
| 86 | ... |
| 87 | ){ |
| 88 | for(;;){ |
| 89 | int newSize, minSpace, n; |
| 90 | /* calculate space in buffer */ |
| 91 | int space = tball.nScratchAlloc - tball.nScratchUsed; |
| 92 | /* format the string */ |
| 93 | va_list vl; |
| 94 | va_start(vl, fmt); |
| 95 | n = vsnprintf(&tball.pScratch[tball.nScratchUsed], space, fmt, vl); |
| 96 | assert(n >= 0); |
| 97 | va_end(vl); |
| 98 | /* if it fit we're done */ |
| 99 | if(n < space) |
| 100 | return n; |
| 101 | /* buffer too short: calculate reasonable new size */ |
| 102 | minSpace = tball.nScratchUsed+n+1; |
| 103 | newSize = 2 * tball.nScratchAlloc; |
| 104 | if(newSize < minSpace) |
| 105 | newSize = minSpace; |
| 106 | /* grow the buffer */ |
| 107 | tball.pScratch = fossil_realloc(tball.pScratch, newSize); |
| 108 | tball.nScratchAlloc = newSize; |
| 109 | /* loop to try again */ |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | |
| 114 | /* |
| 115 | ** verify that lla characters in 'zName' are in the |
| 116 | ** ISO646 (=ASCII) character set. |
| 117 | */ |
| @@ -120,12 +78,11 @@ | |
| 120 | int nName /* path length */ |
| 121 | ){ |
| 122 | int i; |
| 123 | for(i = 0; i < nName; i++){ |
| 124 | unsigned char c = (unsigned char)zName[i]; |
| 125 | if(c > 0x7e) |
| 126 | return 0; |
| 127 | } |
| 128 | return 1; |
| 129 | } |
| 130 | |
| 131 | |
| @@ -194,12 +151,11 @@ | |
| 194 | for(i = 1; i+1 < nName; i++) |
| 195 | if(zName[i] == '/'){ |
| 196 | split = i+1; |
| 197 | /* if the split position is within USTAR_NAME_LEN bytes from |
| 198 | * the end we can quit */ |
| 199 | if(nName - split <= USTAR_NAME_LEN) |
| 200 | break; |
| 201 | } |
| 202 | } |
| 203 | return split; |
| 204 | } |
| 205 | |
| @@ -214,12 +170,13 @@ | |
| 214 | char *pName, /* name field */ |
| 215 | char *pPrefix /* prefix field */ |
| 216 | ){ |
| 217 | int split = find_split_pos(zName, nName); |
| 218 | /* check whether both pieces fit */ |
| 219 | if(nName - split > USTAR_NAME_LEN || split > USTAR_PREFIX_LEN+1) |
| 220 | return 0; /* no */ |
| 221 | |
| 222 | /* extract name */ |
| 223 | padded_copy(pName, USTAR_NAME_LEN, &zName[split], nName - split); |
| 224 | |
| 225 | /* extract prefix */ |
| @@ -242,17 +199,17 @@ | |
| 242 | int bHeader /* is this a 'x' type tar header? */ |
| 243 | ){ |
| 244 | int split; |
| 245 | |
| 246 | /* if this is a Pax Interchange header prepend "PaxHeader/" |
| 247 | * so we can tell files apart from metadata */ |
| 248 | if(bHeader){ |
| 249 | int n; |
| 250 | tball.nScratchUsed = 0; |
| 251 | n = scratch_printf("PaxHeader/%*.*s", nName, nName, zName); |
| 252 | zName = tball.pScratch; |
| 253 | nName = n; |
| 254 | } |
| 255 | |
| 256 | /* find the split position */ |
| 257 | split = find_split_pos(zName, nName); |
| 258 | |
| @@ -284,19 +241,19 @@ | |
| 284 | for(n = blen; n > 0; ){ |
| 285 | blen++; next10 *= 10; |
| 286 | n /= 10; |
| 287 | } |
| 288 | /* adding the length extended the length field? */ |
| 289 | if(blen > next10) |
| 290 | blen++; |
| 291 | /* build the string */ |
| 292 | n = scratch_printf("%d %s=%*.*s\n", blen, zField, nValue, nValue, zValue); |
| 293 | /* this _must_ be right */ |
| 294 | if(n != blen) |
| 295 | fossil_fatal("internal error: PAX tar header has bad length"); |
| 296 | /* add length to scratch buffer */ |
| 297 | tball.nScratchUsed += blen; |
| 298 | } |
| 299 | |
| 300 | |
| 301 | /* |
| 302 | ** set the header type, calculate the checksum and output |
| @@ -338,22 +295,24 @@ | |
| 338 | int lastPage; |
| 339 | /* add a file name for interoperability with older programs */ |
| 340 | approximate_split_path(zName, nName, tball.aHdr, &tball.aHdr[345], 1); |
| 341 | |
| 342 | /* generate the Pax Interchange path header */ |
| 343 | tball.nScratchUsed = 0; |
| 344 | add_pax_header("path", zName, nName); |
| 345 | |
| 346 | /* set the header length, and write the header */ |
| 347 | sqlite3_snprintf(12, (char*)&tball.aHdr[124], "%011o", tball.nScratchUsed); |
| 348 | cksum_and_write_header('x'); |
| 349 | |
| 350 | /* write the Pax Interchange data */ |
| 351 | gzip_step(tball.pScratch, tball.nScratchUsed); |
| 352 | lastPage = tball.nScratchUsed % 512; |
| 353 | if( lastPage!=0 ) |
| 354 | gzip_step(tball.zSpaces, 512 - lastPage); |
| 355 | |
| 356 | /* generate an approximate path for the regular header */ |
| 357 | approximate_split_path(zName, nName, tball.aHdr, &tball.aHdr[345], 0); |
| 358 | } |
| 359 | /* set the size */ |
| @@ -431,14 +390,11 @@ | |
| 431 | fossil_free(tball.aHdr); |
| 432 | tball.aHdr = 0; |
| 433 | fossil_free(tball.zPrevDir); |
| 434 | tball.zPrevDir = NULL; |
| 435 | tball.nPrevDirAlloc = 0; |
| 436 | fossil_free(tball.pScratch); |
| 437 | tball.pScratch = NULL; |
| 438 | tball.nScratchUsed = 0; |
| 439 | tball.nScratchAlloc = 0; |
| 440 | } |
| 441 | |
| 442 | |
| 443 | /* |
| 444 | ** COMMAND: test-tarball |
| 445 |
| --- src/tar.c | |
| +++ src/tar.c | |
| @@ -28,13 +28,11 @@ | |
| 28 | static struct tarball_t { |
| 29 | unsigned char *aHdr; /* Space for building headers */ |
| 30 | char *zSpaces; /* Spaces for padding */ |
| 31 | char *zPrevDir; /* Name of directory for previous entry */ |
| 32 | int nPrevDirAlloc; /* size of zPrevDir */ |
| 33 | Blob pax; /* PAX data */ |
| 34 | } tball; |
| 35 | |
| 36 | |
| 37 | /* |
| 38 | ** field lengths of 'ustar' name and prefix fields. |
| @@ -55,13 +53,11 @@ | |
| 53 | tball.zSpaces = (char*)&tball.aHdr[512]; |
| 54 | /* zPrevDir init */ |
| 55 | tball.zPrevDir = NULL; |
| 56 | tball.nPrevDirAlloc = 0; |
| 57 | /* scratch buffer init */ |
| 58 | blob_zero(&tball.pax); |
| 59 | |
| 60 | memcpy(&tball.aHdr[108], "0000000", 8); /* Owner ID */ |
| 61 | memcpy(&tball.aHdr[116], "0000000", 8); /* Group ID */ |
| 62 | memcpy(&tball.aHdr[257], "ustar\00000", 8); /* POSIX.1 format */ |
| 63 | memcpy(&tball.aHdr[265], "nobody", 7); /* Owner name */ |
| @@ -70,48 +66,10 @@ | |
| 66 | db_multi_exec( |
| 67 | "CREATE TEMP TABLE dir(name UNIQUE);" |
| 68 | ); |
| 69 | } |
| 70 | |
| 71 | |
| 72 | /* |
| 73 | ** verify that lla characters in 'zName' are in the |
| 74 | ** ISO646 (=ASCII) character set. |
| 75 | */ |
| @@ -120,12 +78,11 @@ | |
| 78 | int nName /* path length */ |
| 79 | ){ |
| 80 | int i; |
| 81 | for(i = 0; i < nName; i++){ |
| 82 | unsigned char c = (unsigned char)zName[i]; |
| 83 | if( c>0x7e ) return 0; |
| 84 | } |
| 85 | return 1; |
| 86 | } |
| 87 | |
| 88 | |
| @@ -194,12 +151,11 @@ | |
| 151 | for(i = 1; i+1 < nName; i++) |
| 152 | if(zName[i] == '/'){ |
| 153 | split = i+1; |
| 154 | /* if the split position is within USTAR_NAME_LEN bytes from |
| 155 | * the end we can quit */ |
| 156 | if(nName - split <= USTAR_NAME_LEN) break; |
| 157 | } |
| 158 | } |
| 159 | return split; |
| 160 | } |
| 161 | |
| @@ -214,12 +170,13 @@ | |
| 170 | char *pName, /* name field */ |
| 171 | char *pPrefix /* prefix field */ |
| 172 | ){ |
| 173 | int split = find_split_pos(zName, nName); |
| 174 | /* check whether both pieces fit */ |
| 175 | if(nName - split > USTAR_NAME_LEN || split > USTAR_PREFIX_LEN+1){ |
| 176 | return 0; /* no */ |
| 177 | } |
| 178 | |
| 179 | /* extract name */ |
| 180 | padded_copy(pName, USTAR_NAME_LEN, &zName[split], nName - split); |
| 181 | |
| 182 | /* extract prefix */ |
| @@ -242,17 +199,17 @@ | |
| 199 | int bHeader /* is this a 'x' type tar header? */ |
| 200 | ){ |
| 201 | int split; |
| 202 | |
| 203 | /* if this is a Pax Interchange header prepend "PaxHeader/" |
| 204 | ** so we can tell files apart from metadata */ |
| 205 | if( bHeader ){ |
| 206 | int n; |
| 207 | blob_reset(&tball.pax); |
| 208 | blob_appendf(&tball.pax, "PaxHeader/%*.*s", nName, nName, zName); |
| 209 | zName = blob_buffer(&tball.pax); |
| 210 | nName = blob_size(&tball.pax); |
| 211 | } |
| 212 | |
| 213 | /* find the split position */ |
| 214 | split = find_split_pos(zName, nName); |
| 215 | |
| @@ -284,19 +241,19 @@ | |
| 241 | for(n = blen; n > 0; ){ |
| 242 | blen++; next10 *= 10; |
| 243 | n /= 10; |
| 244 | } |
| 245 | /* adding the length extended the length field? */ |
| 246 | if(blen > next10){ |
| 247 | blen++; |
| 248 | } |
| 249 | /* build the string */ |
| 250 | blob_appendf(&tball.pax, "%d %s=%*.*s\n", blen, zField, nValue, nValue, zValue); |
| 251 | /* this _must_ be right */ |
| 252 | if(blob_size(&tball.pax) != blen){ |
| 253 | fossil_fatal("internal error: PAX tar header has bad length"); |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | |
| 258 | /* |
| 259 | ** set the header type, calculate the checksum and output |
| @@ -338,22 +295,24 @@ | |
| 295 | int lastPage; |
| 296 | /* add a file name for interoperability with older programs */ |
| 297 | approximate_split_path(zName, nName, tball.aHdr, &tball.aHdr[345], 1); |
| 298 | |
| 299 | /* generate the Pax Interchange path header */ |
| 300 | blob_reset(&tball.pax); |
| 301 | add_pax_header("path", zName, nName); |
| 302 | |
| 303 | /* set the header length, and write the header */ |
| 304 | sqlite3_snprintf(12, (char*)&tball.aHdr[124], "%011o", |
| 305 | blob_size(&tball.pax)); |
| 306 | cksum_and_write_header('x'); |
| 307 | |
| 308 | /* write the Pax Interchange data */ |
| 309 | gzip_step(blob_buffer(&tball.pax), blob_size(&tball.pax)); |
| 310 | lastPage = blob_size(&tball.pax) % 512; |
| 311 | if( lastPage!=0 ){ |
| 312 | gzip_step(tball.zSpaces, 512 - lastPage); |
| 313 | } |
| 314 | |
| 315 | /* generate an approximate path for the regular header */ |
| 316 | approximate_split_path(zName, nName, tball.aHdr, &tball.aHdr[345], 0); |
| 317 | } |
| 318 | /* set the size */ |
| @@ -431,14 +390,11 @@ | |
| 390 | fossil_free(tball.aHdr); |
| 391 | tball.aHdr = 0; |
| 392 | fossil_free(tball.zPrevDir); |
| 393 | tball.zPrevDir = NULL; |
| 394 | tball.nPrevDirAlloc = 0; |
| 395 | blob_reset(&tball.pax); |
| 396 | } |
| 397 | |
| 398 | |
| 399 | /* |
| 400 | ** COMMAND: test-tarball |
| 401 |