X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fmisc.c;h=734dc4eded7adcac4f7a29d84111a0d49306cfb4;hb=4ac671c49ba5df93c2f386bc8d7dbe50f4671a57;hp=763c661e9ca704d6193633baaa3020628d217110;hpb=14efeb9f956e38d7beaf3fbedb04d3f3bb9ece3a;p=chaz%2Ftar diff --git a/src/misc.c b/src/misc.c index 763c661..734dc4e 100644 --- a/src/misc.c +++ b/src/misc.c @@ -37,8 +37,7 @@ void assign_string (char **string, const char *value) { - if (*string) - free (*string); + free (*string); *string = value ? xstrdup (value) : 0; } @@ -106,7 +105,7 @@ quote_copy_string (const char *string) completes the unquoting anyway. This is used for reading the saved directory file in incremental - dumps. It is used for decoding old `N' records (demangling names). + dumps. It is used for decoding old 'N' records (demangling names). But also, it is used for decoding file arguments, would they come from the shell or a -T file, and for decoding the --exclude argument. */ @@ -617,6 +616,57 @@ deref_stat (char const *name, struct stat *buf) return fstatat (chdir_fd, name, buf, fstatat_flags); } +/* Read from FD into the buffer BUF with COUNT bytes. Attempt to fill + BUF. Wait until input is available; this matters because files are + opened O_NONBLOCK for security reasons, and on some file systems + this can cause read to fail with errno == EAGAIN. Return the + actual number of bytes read, zero for EOF, or + SAFE_READ_ERROR upon error. */ +size_t +blocking_read (int fd, void *buf, size_t count) +{ + size_t bytes = safe_read (fd, buf, count); + +#if defined F_SETFL && O_NONBLOCK + if (bytes == SAFE_READ_ERROR && errno == EAGAIN) + { + int flags = fcntl (fd, F_GETFL); + if (0 <= flags && flags & O_NONBLOCK + && fcntl (fd, F_SETFL, flags & ~O_NONBLOCK) != -1) + bytes = safe_read (fd, buf, count); + } +#endif + + return bytes; +} + +/* Write to FD from the buffer BUF with COUNT bytes. Do a full write. + Wait until an output buffer is available; this matters because + files are opened O_NONBLOCK for security reasons, and on some file + systems this can cause write to fail with errno == EAGAIN. Return + the actual number of bytes written, setting errno if that is less + than COUNT. */ +size_t +blocking_write (int fd, void const *buf, size_t count) +{ + size_t bytes = full_write (fd, buf, count); + +#if defined F_SETFL && O_NONBLOCK + if (bytes < count && errno == EAGAIN) + { + int flags = fcntl (fd, F_GETFL); + if (0 <= flags && flags & O_NONBLOCK + && fcntl (fd, F_SETFL, flags & ~O_NONBLOCK) != -1) + { + char const *buffer = buf; + bytes += full_write (fd, buffer + bytes, count - bytes); + } + } +#endif + + return bytes; +} + /* Set FD's (i.e., assuming the working directory is PARENTFD, FILE's) access time to ATIME. */ int @@ -663,7 +713,7 @@ static int wdcache[CHDIR_CACHE_SIZE]; static size_t wdcache_count; int -chdir_count () +chdir_count (void) { if (wd_count == 0) return wd_count; @@ -728,7 +778,6 @@ chdir_do (int i) { if (chdir_current != i) { - static size_t counter; struct wd *curr = &wd[i]; int fd = curr->fd; @@ -736,7 +785,8 @@ chdir_do (int i) { if (! IS_ABSOLUTE_FILE_NAME (curr->name)) chdir_do (i - 1); - fd = openat (chdir_fd, curr->name, open_searchdir_flags); + fd = openat (chdir_fd, curr->name, + open_searchdir_flags & ~ O_NOFOLLOW); if (fd < 0) open_fatal (curr->name); @@ -764,11 +814,11 @@ chdir_do (int i) int prev = wdcache[0]; for (ci = 1; prev != i; ci++) { - int curr = wdcache[ci]; + int cur = wdcache[ci]; wdcache[ci] = prev; - if (curr == i) + if (cur == i) break; - prev = curr; + prev = cur; } wdcache[0] = i; } @@ -856,21 +906,6 @@ file_removed_diag (const char *name, bool top_level, diagfn (name); } -void -dir_removed_diag (const char *name, bool top_level, - void (*diagfn) (char const *name)) -{ - if (!top_level && errno == ENOENT) - { - WARNOPT (WARN_FILE_REMOVED, - (0, 0, _("%s: Directory removed before we read it"), - quotearg_colon (name))); - set_exit_status (TAREXIT_DIFFERS); - } - else - diagfn (name); -} - void write_fatal_details (char const *name, ssize_t status, size_t size) { @@ -927,7 +962,7 @@ page_aligned_alloc (void **ptr, size_t size) struct namebuf { - char *buffer; /* directory, `/', and directory member */ + char *buffer; /* directory, '/', and directory member */ size_t buffer_size; /* allocated size of name_buffer */ size_t dir_length; /* length of directory part in buffer */ };