diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-29 07:45:33 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-29 07:45:33 +0100 |
commit | f94c9bf288290c9f4e5a7c2745922abd600e88ca (patch) | |
tree | 57289568fb310466798ae6b297fe46d6e3d2bfcf | |
parent | 2ce42e98d799de4c3389d9c4ce0a6b0d42dac7cc (diff) | |
download | busybox-w32-f94c9bf288290c9f4e5a7c2745922abd600e88ca.tar.gz busybox-w32-f94c9bf288290c9f4e5a7c2745922abd600e88ca.tar.bz2 busybox-w32-f94c9bf288290c9f4e5a7c2745922abd600e88ca.zip |
tar: fix bug 673 (misdetection of repeated dir as hardlink). +92 bytes
While at it, remove many superfluous ops on unpack:
mkdir("."), lots of umask() calls. Can remove more
by caching username->uid.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | archival/libunarchive/data_extract_all.c | 17 | ||||
-rw-r--r-- | archival/tar.c | 126 | ||||
-rw-r--r-- | libbb/make_directory.c | 63 |
3 files changed, 129 insertions, 77 deletions
diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c index 2fcddc404..1100410e6 100644 --- a/archival/libunarchive/data_extract_all.c +++ b/archival/libunarchive/data_extract_all.c | |||
@@ -13,9 +13,12 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
13 | int res; | 13 | int res; |
14 | 14 | ||
15 | if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { | 15 | if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { |
16 | char *name = xstrdup(file_header->name); | 16 | char *slash = strrchr(file_header->name, '/'); |
17 | bb_make_directory(dirname(name), -1, FILEUTILS_RECUR); | 17 | if (slash) { |
18 | free(name); | 18 | *slash = '\0'; |
19 | bb_make_directory(file_header->name, -1, FILEUTILS_RECUR); | ||
20 | *slash = '/'; | ||
21 | } | ||
19 | } | 22 | } |
20 | 23 | ||
21 | if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { | 24 | if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { |
@@ -52,8 +55,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
52 | 55 | ||
53 | /* Handle hard links separately | 56 | /* Handle hard links separately |
54 | * We identified hard links as regular files of size 0 with a symlink */ | 57 | * We identified hard links as regular files of size 0 with a symlink */ |
55 | if (S_ISREG(file_header->mode) && (file_header->link_target) | 58 | if (S_ISREG(file_header->mode) |
56 | && (file_header->size == 0) | 59 | && file_header->link_target |
60 | && file_header->size == 0 | ||
57 | ) { | 61 | ) { |
58 | /* hard link */ | 62 | /* hard link */ |
59 | res = link(file_header->link_target, file_header->name); | 63 | res = link(file_header->link_target, file_header->name); |
@@ -121,6 +125,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
121 | gid_t gid = file_header->gid; | 125 | gid_t gid = file_header->gid; |
122 | 126 | ||
123 | if (file_header->uname) { | 127 | if (file_header->uname) { |
128 | //TODO: cache last name/id pair? | ||
124 | struct passwd *pwd = getpwnam(file_header->uname); | 129 | struct passwd *pwd = getpwnam(file_header->uname); |
125 | if (pwd) uid = pwd->pw_uid; | 130 | if (pwd) uid = pwd->pw_uid; |
126 | } | 131 | } |
@@ -128,7 +133,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
128 | struct group *grp = getgrnam(file_header->gname); | 133 | struct group *grp = getgrnam(file_header->gname); |
129 | if (grp) gid = grp->gr_gid; | 134 | if (grp) gid = grp->gr_gid; |
130 | } | 135 | } |
131 | /* GNU tar 1.15.1 use chown, not lchown */ | 136 | /* GNU tar 1.15.1 uses chown, not lchown */ |
132 | chown(file_header->name, uid, gid); | 137 | chown(file_header->name, uid, gid); |
133 | } else | 138 | } else |
134 | #endif | 139 | #endif |
diff --git a/archival/tar.c b/archival/tar.c index 95982372d..699022ee5 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -26,13 +26,16 @@ | |||
26 | #include <fnmatch.h> | 26 | #include <fnmatch.h> |
27 | #include "libbb.h" | 27 | #include "libbb.h" |
28 | #include "unarchive.h" | 28 | #include "unarchive.h" |
29 | |||
30 | /* FIXME: Stop using this non-standard feature */ | 29 | /* FIXME: Stop using this non-standard feature */ |
31 | #ifndef FNM_LEADING_DIR | 30 | #ifndef FNM_LEADING_DIR |
32 | #define FNM_LEADING_DIR 0 | 31 | # define FNM_LEADING_DIR 0 |
33 | #endif | 32 | #endif |
34 | 33 | ||
35 | 34 | ||
35 | //#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) | ||
36 | #define DBG(...) ((void)0) | ||
37 | |||
38 | |||
36 | #define block_buf bb_common_bufsiz1 | 39 | #define block_buf bb_common_bufsiz1 |
37 | 40 | ||
38 | 41 | ||
@@ -52,8 +55,7 @@ | |||
52 | /* POSIX tar Header Block, from POSIX 1003.1-1990 */ | 55 | /* POSIX tar Header Block, from POSIX 1003.1-1990 */ |
53 | #define NAME_SIZE 100 | 56 | #define NAME_SIZE 100 |
54 | #define NAME_SIZE_STR "100" | 57 | #define NAME_SIZE_STR "100" |
55 | typedef struct TarHeader TarHeader; | 58 | typedef struct TarHeader { /* byte offset */ |
56 | struct TarHeader { /* byte offset */ | ||
57 | char name[NAME_SIZE]; /* 0-99 */ | 59 | char name[NAME_SIZE]; /* 0-99 */ |
58 | char mode[8]; /* 100-107 */ | 60 | char mode[8]; /* 100-107 */ |
59 | char uid[8]; /* 108-115 */ | 61 | char uid[8]; /* 108-115 */ |
@@ -75,39 +77,38 @@ struct TarHeader { /* byte offset */ | |||
75 | char devminor[8]; /* 337-344 */ | 77 | char devminor[8]; /* 337-344 */ |
76 | char prefix[155]; /* 345-499 */ | 78 | char prefix[155]; /* 345-499 */ |
77 | char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ | 79 | char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ |
78 | }; | 80 | } TarHeader; |
79 | 81 | ||
80 | /* | 82 | /* |
81 | ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are | 83 | ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are |
82 | ** the only functions that deal with the HardLinkInfo structure. | 84 | ** the only functions that deal with the HardLinkInfo structure. |
83 | ** Even these functions use the xxxHardLinkInfo() functions. | 85 | ** Even these functions use the xxxHardLinkInfo() functions. |
84 | */ | 86 | */ |
85 | typedef struct HardLinkInfo HardLinkInfo; | 87 | typedef struct HardLinkInfo { |
86 | struct HardLinkInfo { | 88 | struct HardLinkInfo *next; /* Next entry in list */ |
87 | HardLinkInfo *next; /* Next entry in list */ | 89 | dev_t dev; /* Device number */ |
88 | dev_t dev; /* Device number */ | 90 | ino_t ino; /* Inode number */ |
89 | ino_t ino; /* Inode number */ | 91 | // short linkCount; /* (Hard) Link Count */ |
90 | short linkCount; /* (Hard) Link Count */ | 92 | char name[1]; /* Start of filename (must be last) */ |
91 | char name[1]; /* Start of filename (must be last) */ | 93 | } HardLinkInfo; |
92 | }; | ||
93 | 94 | ||
94 | /* Some info to be carried along when creating a new tarball */ | 95 | /* Some info to be carried along when creating a new tarball */ |
95 | typedef struct TarBallInfo TarBallInfo; | 96 | typedef struct TarBallInfo { |
96 | struct TarBallInfo { | ||
97 | int tarFd; /* Open-for-write file descriptor | 97 | int tarFd; /* Open-for-write file descriptor |
98 | * for the tarball */ | 98 | * for the tarball */ |
99 | struct stat statBuf; /* Stat info for the tarball, letting | ||
100 | * us know the inode and device that the | ||
101 | * tarball lives, so we can avoid trying | ||
102 | * to include the tarball into itself */ | ||
103 | int verboseFlag; /* Whether to print extra stuff or not */ | 99 | int verboseFlag; /* Whether to print extra stuff or not */ |
104 | const llist_t *excludeList; /* List of files to not include */ | 100 | const llist_t *excludeList; /* List of files to not include */ |
105 | HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ | 101 | HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ |
106 | HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ | 102 | HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ |
107 | }; | 103 | //TODO: save only st_dev + st_ino |
104 | struct stat tarFileStatBuf; /* Stat info for the tarball, letting | ||
105 | * us know the inode and device that the | ||
106 | * tarball lives, so we can avoid trying | ||
107 | * to include the tarball into itself */ | ||
108 | } TarBallInfo; | ||
108 | 109 | ||
109 | /* A nice enum with all the possible tar file content types */ | 110 | /* A nice enum with all the possible tar file content types */ |
110 | enum TarFileType { | 111 | enum { |
111 | REGTYPE = '0', /* regular file */ | 112 | REGTYPE = '0', /* regular file */ |
112 | REGTYPE0 = '\0', /* regular file (ancient bug compat) */ | 113 | REGTYPE0 = '\0', /* regular file (ancient bug compat) */ |
113 | LNKTYPE = '1', /* hard link */ | 114 | LNKTYPE = '1', /* hard link */ |
@@ -120,7 +121,6 @@ enum TarFileType { | |||
120 | GNULONGLINK = 'K', /* GNU long (>100 chars) link name */ | 121 | GNULONGLINK = 'K', /* GNU long (>100 chars) link name */ |
121 | GNULONGNAME = 'L', /* GNU long (>100 chars) file name */ | 122 | GNULONGNAME = 'L', /* GNU long (>100 chars) file name */ |
122 | }; | 123 | }; |
123 | typedef enum TarFileType TarFileType; | ||
124 | 124 | ||
125 | /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ | 125 | /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ |
126 | static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr, | 126 | static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr, |
@@ -135,7 +135,8 @@ static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr, | |||
135 | *hlInfoHeadPtr = hlInfo; | 135 | *hlInfoHeadPtr = hlInfo; |
136 | hlInfo->dev = statbuf->st_dev; | 136 | hlInfo->dev = statbuf->st_dev; |
137 | hlInfo->ino = statbuf->st_ino; | 137 | hlInfo->ino = statbuf->st_ino; |
138 | hlInfo->linkCount = statbuf->st_nlink; | 138 | // hlInfo->linkCount = statbuf->st_nlink; |
139 | //TODO: "normalize" the name so that "./name/" == "name" etc? | ||
139 | strcpy(hlInfo->name, fileName); | 140 | strcpy(hlInfo->name, fileName); |
140 | } | 141 | } |
141 | 142 | ||
@@ -156,11 +157,18 @@ static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr) | |||
156 | } | 157 | } |
157 | 158 | ||
158 | /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ | 159 | /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ |
159 | static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf) | 160 | static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf, const char *filename) |
160 | { | 161 | { |
161 | while (hlInfo) { | 162 | while (hlInfo) { |
162 | if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev)) | 163 | if ((statbuf->st_ino == hlInfo->ino) |
164 | && (statbuf->st_dev == hlInfo->dev) | ||
165 | /* Name must NOT match. Think "tar cf t.tar file file" | ||
166 | * (same file tarred twice) */ | ||
167 | && strcmp(filename, hlInfo->name) != 0 | ||
168 | ) { | ||
169 | DBG("found hardlink:'%s'", hlInfo->name); | ||
163 | break; | 170 | break; |
171 | } | ||
164 | hlInfo = hlInfo->next; | 172 | hlInfo = hlInfo->next; |
165 | } | 173 | } |
166 | return hlInfo; | 174 | return hlInfo; |
@@ -171,7 +179,7 @@ static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf | |||
171 | * Stores low-order bits only if whole value does not fit. */ | 179 | * Stores low-order bits only if whole value does not fit. */ |
172 | static void putOctal(char *cp, int len, off_t value) | 180 | static void putOctal(char *cp, int len, off_t value) |
173 | { | 181 | { |
174 | char tempBuffer[sizeof(off_t)*3+1]; | 182 | char tempBuffer[sizeof(off_t)*3 + 1]; |
175 | char *tempString = tempBuffer; | 183 | char *tempString = tempBuffer; |
176 | int width; | 184 | int width; |
177 | 185 | ||
@@ -376,16 +384,19 @@ static int exclude_file(const llist_t *excluded_files, const char *file) | |||
376 | while (excluded_files) { | 384 | while (excluded_files) { |
377 | if (excluded_files->data[0] == '/') { | 385 | if (excluded_files->data[0] == '/') { |
378 | if (fnmatch(excluded_files->data, file, | 386 | if (fnmatch(excluded_files->data, file, |
379 | FNM_PATHNAME | FNM_LEADING_DIR) == 0) | 387 | FNM_PATHNAME | FNM_LEADING_DIR) == 0) |
380 | return 1; | 388 | return 1; |
381 | } else { | 389 | } else { |
382 | const char *p; | 390 | const char *p; |
383 | 391 | ||
384 | for (p = file; p[0] != '\0'; p++) { | 392 | for (p = file; p[0] != '\0'; p++) { |
385 | if ((p == file || p[-1] == '/') && p[0] != '/' && | 393 | if ((p == file || p[-1] == '/') |
386 | fnmatch(excluded_files->data, p, | 394 | && p[0] != '/' |
387 | FNM_PATHNAME | FNM_LEADING_DIR) == 0) | 395 | && fnmatch(excluded_files->data, p, |
396 | FNM_PATHNAME | FNM_LEADING_DIR) == 0 | ||
397 | ) { | ||
388 | return 1; | 398 | return 1; |
399 | } | ||
389 | } | 400 | } |
390 | } | 401 | } |
391 | excluded_files = excluded_files->link; | 402 | excluded_files = excluded_files->link; |
@@ -394,7 +405,7 @@ static int exclude_file(const llist_t *excluded_files, const char *file) | |||
394 | return 0; | 405 | return 0; |
395 | } | 406 | } |
396 | #else | 407 | #else |
397 | #define exclude_file(excluded_files, file) 0 | 408 | # define exclude_file(excluded_files, file) 0 |
398 | #endif | 409 | #endif |
399 | 410 | ||
400 | static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf, | 411 | static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf, |
@@ -404,6 +415,8 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb | |||
404 | const char *header_name; | 415 | const char *header_name; |
405 | int inputFileFd = -1; | 416 | int inputFileFd = -1; |
406 | 417 | ||
418 | DBG("writeFileToTarball('%s')", fileName); | ||
419 | |||
407 | /* Strip leading '/' (must be before memorizing hardlink's name) */ | 420 | /* Strip leading '/' (must be before memorizing hardlink's name) */ |
408 | header_name = fileName; | 421 | header_name = fileName; |
409 | while (header_name[0] == '/') { | 422 | while (header_name[0] == '/') { |
@@ -433,17 +446,20 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb | |||
433 | * by adding the file information to the HardLinkInfo linked list. | 446 | * by adding the file information to the HardLinkInfo linked list. |
434 | */ | 447 | */ |
435 | tbInfo->hlInfo = NULL; | 448 | tbInfo->hlInfo = NULL; |
436 | if (statbuf->st_nlink > 1) { | 449 | if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) { |
437 | tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf); | 450 | DBG("'%s': st_nlink > 1", header_name); |
438 | if (tbInfo->hlInfo == NULL) | 451 | tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf, header_name); |
452 | if (tbInfo->hlInfo == NULL) { | ||
453 | DBG("'%s': addHardLinkInfo", header_name); | ||
439 | addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name); | 454 | addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name); |
455 | } | ||
440 | } | 456 | } |
441 | 457 | ||
442 | /* It is a bad idea to store the archive we are in the process of creating, | 458 | /* It is a bad idea to store the archive we are in the process of creating, |
443 | * so check the device and inode to be sure that this particular file isn't | 459 | * so check the device and inode to be sure that this particular file isn't |
444 | * the new tarball */ | 460 | * the new tarball */ |
445 | if (tbInfo->statBuf.st_dev == statbuf->st_dev | 461 | if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev |
446 | && tbInfo->statBuf.st_ino == statbuf->st_ino | 462 | && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino |
447 | ) { | 463 | ) { |
448 | bb_error_msg("%s: file is the archive; skipping", fileName); | 464 | bb_error_msg("%s: file is the archive; skipping", fileName); |
449 | return TRUE; | 465 | return TRUE; |
@@ -505,37 +521,37 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb | |||
505 | } | 521 | } |
506 | 522 | ||
507 | #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 | 523 | #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 |
508 | #if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2) | 524 | # if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2) |
509 | #define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd) | 525 | # define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd) |
510 | #endif | 526 | # endif |
511 | /* Don't inline: vfork scares gcc and pessimizes code */ | 527 | /* Don't inline: vfork scares gcc and pessimizes code */ |
512 | static void NOINLINE vfork_compressor(int tar_fd, int gzip) | 528 | static void NOINLINE vfork_compressor(int tar_fd, int gzip) |
513 | { | 529 | { |
514 | pid_t gzipPid; | 530 | pid_t gzipPid; |
515 | #if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2 | 531 | # if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2 |
516 | const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; | 532 | const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; |
517 | #elif ENABLE_FEATURE_SEAMLESS_GZ | 533 | # elif ENABLE_FEATURE_SEAMLESS_GZ |
518 | const char *zip_exec = "gzip"; | 534 | const char *zip_exec = "gzip"; |
519 | #else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */ | 535 | # else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */ |
520 | const char *zip_exec = "bzip2"; | 536 | const char *zip_exec = "bzip2"; |
521 | #endif | 537 | # endif |
522 | // On Linux, vfork never unpauses parent early, although standard | 538 | // On Linux, vfork never unpauses parent early, although standard |
523 | // allows for that. Do we want to waste bytes checking for it? | 539 | // allows for that. Do we want to waste bytes checking for it? |
524 | #define WAIT_FOR_CHILD 0 | 540 | # define WAIT_FOR_CHILD 0 |
525 | volatile int vfork_exec_errno = 0; | 541 | volatile int vfork_exec_errno = 0; |
526 | struct fd_pair gzipDataPipe; | 542 | struct fd_pair gzipDataPipe; |
527 | #if WAIT_FOR_CHILD | 543 | # if WAIT_FOR_CHILD |
528 | struct fd_pair gzipStatusPipe; | 544 | struct fd_pair gzipStatusPipe; |
529 | xpiped_pair(gzipStatusPipe); | 545 | xpiped_pair(gzipStatusPipe); |
530 | #endif | 546 | # endif |
531 | xpiped_pair(gzipDataPipe); | 547 | xpiped_pair(gzipDataPipe); |
532 | 548 | ||
533 | signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ | 549 | signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ |
534 | 550 | ||
535 | #if defined(__GNUC__) && __GNUC__ | 551 | # if defined(__GNUC__) && __GNUC__ |
536 | /* Avoid vfork clobbering */ | 552 | /* Avoid vfork clobbering */ |
537 | (void) &zip_exec; | 553 | (void) &zip_exec; |
538 | #endif | 554 | # endif |
539 | 555 | ||
540 | gzipPid = vfork(); | 556 | gzipPid = vfork(); |
541 | if (gzipPid < 0) | 557 | if (gzipPid < 0) |
@@ -545,12 +561,12 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) | |||
545 | /* child */ | 561 | /* child */ |
546 | /* NB: close _first_, then move fds! */ | 562 | /* NB: close _first_, then move fds! */ |
547 | close(gzipDataPipe.wr); | 563 | close(gzipDataPipe.wr); |
548 | #if WAIT_FOR_CHILD | 564 | # if WAIT_FOR_CHILD |
549 | close(gzipStatusPipe.rd); | 565 | close(gzipStatusPipe.rd); |
550 | /* gzipStatusPipe.wr will close only on exec - | 566 | /* gzipStatusPipe.wr will close only on exec - |
551 | * parent waits for this close to happen */ | 567 | * parent waits for this close to happen */ |
552 | fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC); | 568 | fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC); |
553 | #endif | 569 | # endif |
554 | xmove_fd(gzipDataPipe.rd, 0); | 570 | xmove_fd(gzipDataPipe.rd, 0); |
555 | xmove_fd(tar_fd, 1); | 571 | xmove_fd(tar_fd, 1); |
556 | /* exec gzip/bzip2 program/applet */ | 572 | /* exec gzip/bzip2 program/applet */ |
@@ -562,7 +578,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) | |||
562 | /* parent */ | 578 | /* parent */ |
563 | xmove_fd(gzipDataPipe.wr, tar_fd); | 579 | xmove_fd(gzipDataPipe.wr, tar_fd); |
564 | close(gzipDataPipe.rd); | 580 | close(gzipDataPipe.rd); |
565 | #if WAIT_FOR_CHILD | 581 | # if WAIT_FOR_CHILD |
566 | close(gzipStatusPipe.wr); | 582 | close(gzipStatusPipe.wr); |
567 | while (1) { | 583 | while (1) { |
568 | char buf; | 584 | char buf; |
@@ -574,7 +590,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) | |||
574 | continue; /* try it again */ | 590 | continue; /* try it again */ |
575 | } | 591 | } |
576 | close(gzipStatusPipe.rd); | 592 | close(gzipStatusPipe.rd); |
577 | #endif | 593 | # endif |
578 | if (vfork_exec_errno) { | 594 | if (vfork_exec_errno) { |
579 | errno = vfork_exec_errno; | 595 | errno = vfork_exec_errno; |
580 | bb_perror_msg_and_die("can't execute '%s'", zip_exec); | 596 | bb_perror_msg_and_die("can't execute '%s'", zip_exec); |
@@ -597,7 +613,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, | |||
597 | 613 | ||
598 | /* Store the stat info for the tarball's file, so | 614 | /* Store the stat info for the tarball's file, so |
599 | * can avoid including the tarball into itself.... */ | 615 | * can avoid including the tarball into itself.... */ |
600 | if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) | 616 | if (fstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf) < 0) |
601 | bb_perror_msg_and_die("can't stat tar file"); | 617 | bb_perror_msg_and_die("can't stat tar file"); |
602 | 618 | ||
603 | #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 | 619 | #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 |
@@ -675,7 +691,7 @@ static llist_t *append_file_list_to_list(llist_t *list) | |||
675 | return newlist; | 691 | return newlist; |
676 | } | 692 | } |
677 | #else | 693 | #else |
678 | #define append_file_list_to_list(x) 0 | 694 | # define append_file_list_to_list(x) 0 |
679 | #endif | 695 | #endif |
680 | 696 | ||
681 | #if ENABLE_FEATURE_SEAMLESS_Z | 697 | #if ENABLE_FEATURE_SEAMLESS_Z |
@@ -700,7 +716,7 @@ static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle) | |||
700 | return EXIT_FAILURE; | 716 | return EXIT_FAILURE; |
701 | } | 717 | } |
702 | #else | 718 | #else |
703 | #define get_header_tar_Z NULL | 719 | # define get_header_tar_Z NULL |
704 | #endif | 720 | #endif |
705 | 721 | ||
706 | #ifdef CHECK_FOR_CHILD_EXITCODE | 722 | #ifdef CHECK_FOR_CHILD_EXITCODE |
diff --git a/libbb/make_directory.c b/libbb/make_directory.c index a4ad59975..4486eb1ed 100644 --- a/libbb/make_directory.c +++ b/libbb/make_directory.c | |||
@@ -28,53 +28,76 @@ | |||
28 | 28 | ||
29 | int FAST_FUNC bb_make_directory(char *path, long mode, int flags) | 29 | int FAST_FUNC bb_make_directory(char *path, long mode, int flags) |
30 | { | 30 | { |
31 | mode_t mask; | 31 | mode_t cur_mask; |
32 | mode_t org_mask; | ||
32 | const char *fail_msg; | 33 | const char *fail_msg; |
33 | char *s = path; | 34 | char *s; |
34 | char c; | 35 | char c; |
35 | struct stat st; | 36 | struct stat st; |
36 | 37 | ||
37 | mask = umask(0); | 38 | /* Happens on bb_make_directory(dirname("no_slashes"),...) */ |
38 | umask(mask & ~0300); /* Ensure intermediate dirs are wx */ | 39 | if (LONE_CHAR(path, '.')) |
40 | return 0; | ||
39 | 41 | ||
42 | org_mask = cur_mask = (mode_t)-1L; | ||
43 | s = path; | ||
40 | while (1) { | 44 | while (1) { |
41 | c = '\0'; | 45 | c = '\0'; |
42 | 46 | ||
43 | if (flags & FILEUTILS_RECUR) { /* Get the parent. */ | 47 | if (flags & FILEUTILS_RECUR) { /* Get the parent */ |
44 | /* Bypass leading non-'/'s and then subsequent '/'s. */ | 48 | /* Bypass leading non-'/'s and then subsequent '/'s */ |
45 | while (*s) { | 49 | while (*s) { |
46 | if (*s == '/') { | 50 | if (*s == '/') { |
47 | do { | 51 | do { |
48 | ++s; | 52 | ++s; |
49 | } while (*s == '/'); | 53 | } while (*s == '/'); |
50 | c = *s; /* Save the current char */ | 54 | c = *s; /* Save the current char */ |
51 | *s = '\0'; /* and replace it with nul. */ | 55 | *s = '\0'; /* and replace it with nul */ |
52 | break; | 56 | break; |
53 | } | 57 | } |
54 | ++s; | 58 | ++s; |
55 | } | 59 | } |
56 | } | 60 | } |
57 | 61 | ||
58 | if (!c) /* Last component uses orig umask */ | 62 | if (c != '\0') { |
59 | umask(mask); | 63 | /* Intermediate dirs: must have wx for user */ |
64 | if (cur_mask == (mode_t)-1L) { /* wasn't done yet? */ | ||
65 | mode_t new_mask; | ||
66 | org_mask = umask(0); | ||
67 | cur_mask = 0; | ||
68 | /* Clear u=wx in umask - this ensures | ||
69 | * they won't be cleared on mkdir */ | ||
70 | new_mask = (org_mask & ~(mode_t)0300); | ||
71 | //bb_error_msg("org_mask:%o cur_mask:%o", org_mask, new_mask); | ||
72 | if (new_mask != cur_mask) { | ||
73 | cur_mask = new_mask; | ||
74 | umask(new_mask); | ||
75 | } | ||
76 | } | ||
77 | } else { | ||
78 | /* Last component: uses original umask */ | ||
79 | //bb_error_msg("1 org_mask:%o", org_mask); | ||
80 | if (org_mask != cur_mask) { | ||
81 | cur_mask = org_mask; | ||
82 | umask(org_mask); | ||
83 | } | ||
84 | } | ||
60 | 85 | ||
61 | if (mkdir(path, 0777) < 0) { | 86 | if (mkdir(path, 0777) < 0) { |
62 | /* If we failed for any other reason than the directory | 87 | /* If we failed for any other reason than the directory |
63 | * already exists, output a diagnostic and return -1. */ | 88 | * already exists, output a diagnostic and return -1 */ |
64 | if (errno != EEXIST | 89 | if (errno != EEXIST |
65 | || !(flags & FILEUTILS_RECUR) | 90 | || !(flags & FILEUTILS_RECUR) |
66 | || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode)) | 91 | || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode)) |
67 | ) { | 92 | ) { |
68 | fail_msg = "create"; | 93 | fail_msg = "create"; |
69 | umask(mask); | ||
70 | break; | 94 | break; |
71 | } | 95 | } |
72 | /* Since the directory exists, don't attempt to change | 96 | /* Since the directory exists, don't attempt to change |
73 | * permissions if it was the full target. Note that | 97 | * permissions if it was the full target. Note that |
74 | * this is not an error condition. */ | 98 | * this is not an error condition. */ |
75 | if (!c) { | 99 | if (!c) { |
76 | umask(mask); | 100 | goto ret0; |
77 | return 0; | ||
78 | } | 101 | } |
79 | } | 102 | } |
80 | 103 | ||
@@ -86,13 +109,21 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) | |||
86 | fail_msg = "set permissions of"; | 109 | fail_msg = "set permissions of"; |
87 | break; | 110 | break; |
88 | } | 111 | } |
89 | return 0; | 112 | goto ret0; |
90 | } | 113 | } |
91 | 114 | ||
92 | /* Remove any inserted nul from the path (recursive mode). */ | 115 | /* Remove any inserted nul from the path (recursive mode) */ |
93 | *s = c; | 116 | *s = c; |
94 | } /* while (1) */ | 117 | } /* while (1) */ |
95 | 118 | ||
96 | bb_perror_msg("can't %s directory '%s'", fail_msg, path); | 119 | bb_perror_msg("can't %s directory '%s'", fail_msg, path); |
97 | return -1; | 120 | flags = -1; |
121 | goto ret; | ||
122 | ret0: | ||
123 | flags = 0; | ||
124 | ret: | ||
125 | //bb_error_msg("2 org_mask:%o", org_mask); | ||
126 | if (org_mask != cur_mask) | ||
127 | umask(org_mask); | ||
128 | return flags; | ||
98 | } | 129 | } |