Fossil SCM
Support symlinks in tarballs.
Commit
72e3bbd0710eb85dba76da3c5ab958cc57cb13c5
Parent
16da26c5858f115…
1 file changed
+20
-4
+20
-4
| --- src/tar.c | ||
| +++ src/tar.c | ||
| @@ -280,11 +280,12 @@ | ||
| 280 | 280 | const char *zName, /* Name of the object */ |
| 281 | 281 | int nName, /* Number of characters in zName */ |
| 282 | 282 | int iMode, /* Mode. 0644 or 0755 */ |
| 283 | 283 | unsigned int mTime, /* File modification time */ |
| 284 | 284 | int iSize, /* Size of the object in bytes */ |
| 285 | - char cType /* Type of object. '0'==file. '5'==directory */ | |
| 285 | + char cType /* Type of object: | |
| 286 | + '0'==file. '2'==symlink. '5'==directory */ | |
| 286 | 287 | ){ |
| 287 | 288 | /* set mode and modification time */ |
| 288 | 289 | sqlite3_snprintf(8, (char*)&tball.aHdr[100], "%07o", iMode); |
| 289 | 290 | sqlite3_snprintf(12, (char*)&tball.aHdr[136], "%011o", mTime); |
| 290 | 291 | |
| @@ -359,20 +360,35 @@ | ||
| 359 | 360 | ** Add a single file to the growing tarball. |
| 360 | 361 | */ |
| 361 | 362 | static void tar_add_file( |
| 362 | 363 | const char *zName, /* Name of the file. nul-terminated */ |
| 363 | 364 | Blob *pContent, /* Content of the file */ |
| 364 | - int isExe, /* True for executable files */ | |
| 365 | + int mPerm, /* 1: executable file, 2: symlink */ | |
| 365 | 366 | unsigned int mTime /* Last modification time of the file */ |
| 366 | 367 | ){ |
| 367 | 368 | int nName = strlen(zName); |
| 368 | 369 | int n = blob_size(pContent); |
| 369 | 370 | int lastPage; |
| 371 | + char cType = '0'; | |
| 370 | 372 | |
| 371 | 373 | /* length check moved to tar_split_path */ |
| 372 | 374 | tar_add_directory_of(zName, nName, mTime); |
| 373 | - tar_add_header(zName, nName, isExe ? 0755 : 0644, mTime, n, '0'); | |
| 375 | + | |
| 376 | + /* | |
| 377 | + * If we have a symlink, write its destination path (which is stored in | |
| 378 | + * pContent) into header, and set content length to 0 to avoid storing path | |
| 379 | + * as file content in the next step. Since 'linkname' header is limited to | |
| 380 | + * 100 bytes (-1 byte for terminating zero), if path is greater than that, | |
| 381 | + * store symlink as a plain-text file. (Not sure how TAR handles long links.) | |
| 382 | + */ | |
| 383 | + if( mPerm == 2 && n <= 100 ){ | |
| 384 | + sqlite3_snprintf(100, (char*)&tball.aHdr[157], "%s", blob_str(pContent)); | |
| 385 | + cType = '2'; | |
| 386 | + n = 0; | |
| 387 | + } | |
| 388 | + | |
| 389 | + tar_add_header(zName, nName, (mPerm > 0) ? 0755 : 0644, mTime, n, cType); | |
| 374 | 390 | if( n ){ |
| 375 | 391 | gzip_step(blob_buffer(pContent), n); |
| 376 | 392 | lastPage = n % 512; |
| 377 | 393 | if( lastPage!=0 ){ |
| 378 | 394 | gzip_step(tball.zSpaces, 512 - lastPage); |
| @@ -415,11 +431,11 @@ | ||
| 415 | 431 | tar_begin(); |
| 416 | 432 | for(i=3; i<g.argc; i++){ |
| 417 | 433 | blob_zero(&file); |
| 418 | 434 | blob_read_from_file(&file, g.argv[i]); |
| 419 | 435 | tar_add_file(g.argv[i], &file, |
| 420 | - file_isexe(g.argv[i]), file_mtime(g.argv[i])); | |
| 436 | + file_perm(g.argv[i]), file_mtime(g.argv[i])); | |
| 421 | 437 | blob_reset(&file); |
| 422 | 438 | } |
| 423 | 439 | tar_finish(&zip); |
| 424 | 440 | blob_write_to_file(&zip, g.argv[2]); |
| 425 | 441 | } |
| 426 | 442 |
| --- src/tar.c | |
| +++ src/tar.c | |
| @@ -280,11 +280,12 @@ | |
| 280 | const char *zName, /* Name of the object */ |
| 281 | int nName, /* Number of characters in zName */ |
| 282 | int iMode, /* Mode. 0644 or 0755 */ |
| 283 | unsigned int mTime, /* File modification time */ |
| 284 | int iSize, /* Size of the object in bytes */ |
| 285 | char cType /* Type of object. '0'==file. '5'==directory */ |
| 286 | ){ |
| 287 | /* set mode and modification time */ |
| 288 | sqlite3_snprintf(8, (char*)&tball.aHdr[100], "%07o", iMode); |
| 289 | sqlite3_snprintf(12, (char*)&tball.aHdr[136], "%011o", mTime); |
| 290 | |
| @@ -359,20 +360,35 @@ | |
| 359 | ** Add a single file to the growing tarball. |
| 360 | */ |
| 361 | static void tar_add_file( |
| 362 | const char *zName, /* Name of the file. nul-terminated */ |
| 363 | Blob *pContent, /* Content of the file */ |
| 364 | int isExe, /* True for executable files */ |
| 365 | unsigned int mTime /* Last modification time of the file */ |
| 366 | ){ |
| 367 | int nName = strlen(zName); |
| 368 | int n = blob_size(pContent); |
| 369 | int lastPage; |
| 370 | |
| 371 | /* length check moved to tar_split_path */ |
| 372 | tar_add_directory_of(zName, nName, mTime); |
| 373 | tar_add_header(zName, nName, isExe ? 0755 : 0644, mTime, n, '0'); |
| 374 | if( n ){ |
| 375 | gzip_step(blob_buffer(pContent), n); |
| 376 | lastPage = n % 512; |
| 377 | if( lastPage!=0 ){ |
| 378 | gzip_step(tball.zSpaces, 512 - lastPage); |
| @@ -415,11 +431,11 @@ | |
| 415 | tar_begin(); |
| 416 | for(i=3; i<g.argc; i++){ |
| 417 | blob_zero(&file); |
| 418 | blob_read_from_file(&file, g.argv[i]); |
| 419 | tar_add_file(g.argv[i], &file, |
| 420 | file_isexe(g.argv[i]), file_mtime(g.argv[i])); |
| 421 | blob_reset(&file); |
| 422 | } |
| 423 | tar_finish(&zip); |
| 424 | blob_write_to_file(&zip, g.argv[2]); |
| 425 | } |
| 426 |
| --- src/tar.c | |
| +++ src/tar.c | |
| @@ -280,11 +280,12 @@ | |
| 280 | const char *zName, /* Name of the object */ |
| 281 | int nName, /* Number of characters in zName */ |
| 282 | int iMode, /* Mode. 0644 or 0755 */ |
| 283 | unsigned int mTime, /* File modification time */ |
| 284 | int iSize, /* Size of the object in bytes */ |
| 285 | char cType /* Type of object: |
| 286 | '0'==file. '2'==symlink. '5'==directory */ |
| 287 | ){ |
| 288 | /* set mode and modification time */ |
| 289 | sqlite3_snprintf(8, (char*)&tball.aHdr[100], "%07o", iMode); |
| 290 | sqlite3_snprintf(12, (char*)&tball.aHdr[136], "%011o", mTime); |
| 291 | |
| @@ -359,20 +360,35 @@ | |
| 360 | ** Add a single file to the growing tarball. |
| 361 | */ |
| 362 | static void tar_add_file( |
| 363 | const char *zName, /* Name of the file. nul-terminated */ |
| 364 | Blob *pContent, /* Content of the file */ |
| 365 | int mPerm, /* 1: executable file, 2: symlink */ |
| 366 | unsigned int mTime /* Last modification time of the file */ |
| 367 | ){ |
| 368 | int nName = strlen(zName); |
| 369 | int n = blob_size(pContent); |
| 370 | int lastPage; |
| 371 | char cType = '0'; |
| 372 | |
| 373 | /* length check moved to tar_split_path */ |
| 374 | tar_add_directory_of(zName, nName, mTime); |
| 375 | |
| 376 | /* |
| 377 | * If we have a symlink, write its destination path (which is stored in |
| 378 | * pContent) into header, and set content length to 0 to avoid storing path |
| 379 | * as file content in the next step. Since 'linkname' header is limited to |
| 380 | * 100 bytes (-1 byte for terminating zero), if path is greater than that, |
| 381 | * store symlink as a plain-text file. (Not sure how TAR handles long links.) |
| 382 | */ |
| 383 | if( mPerm == 2 && n <= 100 ){ |
| 384 | sqlite3_snprintf(100, (char*)&tball.aHdr[157], "%s", blob_str(pContent)); |
| 385 | cType = '2'; |
| 386 | n = 0; |
| 387 | } |
| 388 | |
| 389 | tar_add_header(zName, nName, (mPerm > 0) ? 0755 : 0644, mTime, n, cType); |
| 390 | if( n ){ |
| 391 | gzip_step(blob_buffer(pContent), n); |
| 392 | lastPage = n % 512; |
| 393 | if( lastPage!=0 ){ |
| 394 | gzip_step(tball.zSpaces, 512 - lastPage); |
| @@ -415,11 +431,11 @@ | |
| 431 | tar_begin(); |
| 432 | for(i=3; i<g.argc; i++){ |
| 433 | blob_zero(&file); |
| 434 | blob_read_from_file(&file, g.argv[i]); |
| 435 | tar_add_file(g.argv[i], &file, |
| 436 | file_perm(g.argv[i]), file_mtime(g.argv[i])); |
| 437 | blob_reset(&file); |
| 438 | } |
| 439 | tar_finish(&zip); |
| 440 | blob_write_to_file(&zip, g.argv[2]); |
| 441 | } |
| 442 |