X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftar;a=blobdiff_plain;f=src%2Fcreate.c;h=24920db37b967b99ea803d1418c7cb02141100cd;hp=5e2171b561917a74c2bde424a9eb7e0648c970a0;hb=45ccda119355a1087450039a250359c1d0de0d08;hpb=8da503cad6e883b30c05749149084d24319063b4 diff --git a/src/create.c b/src/create.c index 5e2171b..24920db 100644 --- a/src/create.c +++ b/src/create.c @@ -1,23 +1,24 @@ /* Create a tar archive. - Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, - 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. + Copyright 1985, 1992-1994, 1996-1997, 1999-2001, 2003-2007, + 2009-2010, 2012-2014 Free Software Foundation, Inc. - Written by John Gilmore, on 1985-08-25. + This file is part of GNU tar. - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 3, or (at your option) any later - version. + GNU tar is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - Public License for more details. + GNU tar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by John Gilmore, on 1985-08-25. */ #include @@ -511,12 +512,11 @@ start_private_header (const char *name, size_t size, time_t t) tar_name_copy_str (header->header.name, name, NAME_FIELD_SIZE); OFF_TO_CHARS (size, header->header.size); - TIME_TO_CHARS (t, header->header.mtime); + TIME_TO_CHARS (t < 0 ? 0 : min (t, MAX_OCTAL_VAL (header->header.mtime)), + header->header.mtime); MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode); - UID_TO_CHARS (getuid (), header->header.uid); - GID_TO_CHARS (getgid (), header->header.gid); - MAJOR_TO_CHARS (0, header->header.devmajor); - MINOR_TO_CHARS (0, header->header.devminor); + UID_TO_CHARS (0, header->header.uid); + GID_TO_CHARS (0, header->header.gid); strncpy (header->header.magic, TMAGIC, TMAGLEN); strncpy (header->header.version, TVERSION, TVERSLEN); return header; @@ -534,11 +534,6 @@ write_short_name (struct tar_stat_info *st) return header; } -#define FILL(field,byte) do { \ - memset(field, byte, sizeof(field)-1); \ - (field)[sizeof(field)-1] = 0; \ -} while (0) - /* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */ static void write_gnu_long_link (struct tar_stat_info *st, const char *p, char type) @@ -548,13 +543,7 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type) union block *header; char *tmpname; - header = start_private_header ("././@LongLink", size, time (NULL)); - FILL (header->header.mtime, '0'); - FILL (header->header.mode, '0'); - FILL (header->header.uid, '0'); - FILL (header->header.gid, '0'); - FILL (header->header.devmajor, 0); - FILL (header->header.devminor, 0); + header = start_private_header ("././@LongLink", size, 0); uid_to_uname (0, &tmpname); UNAME_TO_CHARS (tmpname, header->header.uname); free (tmpname); @@ -562,7 +551,8 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type) GNAME_TO_CHARS (tmpname, header->header.gname); free (tmpname); - strcpy (header->header.magic, OLDGNU_MAGIC); + strcpy (header->buffer + offsetof (struct posix_header, magic), + OLDGNU_MAGIC); header->header.typeflag = type; finish_header (st, header, -1); @@ -710,7 +700,7 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header) { type = XGLTYPE; p = xheader_ghdr_name (); - time (&t); + t = start_time.tv_sec; } else { @@ -784,9 +774,9 @@ start_header (struct tar_stat_info *st) . . . . . . . . . 9 = Omron UNIOS-B 4.3BSD 1.60Beta . = works - # = ``impossible file type'' + # = "impossible file type" - The following mask for old archive removes the `#'s in column 4 + The following mask for old archive removes the '#'s in column 4 above, thus making GNU tar both a universal donor and a universal acceptor for Paul's test. */ @@ -899,7 +889,8 @@ start_header (struct tar_stat_info *st) case OLDGNU_FORMAT: case GNU_FORMAT: /*FIXME?*/ /* Overwrite header->header.magic and header.version in one blow. */ - strcpy (header->header.magic, OLDGNU_MAGIC); + strcpy (header->buffer + offsetof (struct posix_header, magic), + OLDGNU_MAGIC); break; case POSIX_FORMAT: @@ -918,8 +909,15 @@ start_header (struct tar_stat_info *st) } else { - uid_to_uname (st->stat.st_uid, &st->uname); - gid_to_gname (st->stat.st_gid, &st->gname); + if (owner_name_option) + st->uname = xstrdup (owner_name_option); + else + uid_to_uname (st->stat.st_uid, &st->uname); + + if (group_name_option) + st->gname = xstrdup (group_name_option); + else + gid_to_gname (st->stat.st_gid, &st->gname); if (archive_format == POSIX_FORMAT && (strlen (st->uname) > UNAME_FIELD_SIZE @@ -934,6 +932,30 @@ start_header (struct tar_stat_info *st) GNAME_TO_CHARS (st->gname, header->header.gname); } + if (archive_format == POSIX_FORMAT) + { + if (acls_option > 0) + { + if (st->acls_a_ptr) + xheader_store ("SCHILY.acl.access", st, NULL); + if (st->acls_d_ptr) + xheader_store ("SCHILY.acl.default", st, NULL); + } + if ((selinux_context_option > 0) && st->cntx_name) + xheader_store ("RHT.security.selinux", st, NULL); + if (xattrs_option > 0) + { + size_t scan_xattr = 0; + struct xattr_array *xattr_map = st->xattr_map; + + while (scan_xattr < st->xattr_map_size) + { + xheader_store (xattr_map[scan_xattr].xkey, st, &scan_xattr); + ++scan_xattr; + } + } + } + return header; } @@ -1042,7 +1064,7 @@ dump_regular_file (int fd, struct tar_stat_info *st) memset (blk->buffer + size_left, 0, BLOCKSIZE - count); } - count = (fd <= 0) ? bufsize : safe_read (fd, blk->buffer, bufsize); + count = (fd <= 0) ? bufsize : blocking_read (fd, blk->buffer, bufsize); if (count == SAFE_READ_ERROR) { read_diag_details (st->orig_file_name, @@ -1263,49 +1285,10 @@ open_failure_recover (struct tar_stat_info const *dir) char * get_directory_entries (struct tar_stat_info *st) { - DIR *dirstream; - while (! (dirstream = fdopendir (st->fd)) && open_failure_recover (st)) - continue; - - if (! dirstream) - return 0; - else - { - char *entries = streamsavedir (dirstream); - int streamsavedir_errno = errno; - - int fd = dirfd (dirstream); - if (fd < 0) - { - /* The dirent.h implementation doesn't use file descriptors - for directory streams, so open the directory again. */ - char const *name = st->orig_file_name; - if (closedir (dirstream) != 0) - close_diag (name); - dirstream = 0; - fd = subfile_open (st->parent, - st->parent ? last_component (name) : name, - open_searchdir_flags); - if (fd < 0) - fd = - errno; - else - { - struct stat dirst; - if (! (fstat (fd, &dirst) == 0 - && st->stat.st_ino == dirst.st_ino - && st->stat.st_dev == dirst.st_dev)) - { - close (fd); - fd = - IMPOSTOR_ERRNO; - } - } - } - - st->fd = fd; - st->dirstream = dirstream; - errno = streamsavedir_errno; - return entries; - } + while (! (st->dirstream = fdopendir (st->fd))) + if (! open_failure_recover (st)) + return 0; + return streamsavedir (st->dirstream); } /* Dump the directory ST. Return true if successful, false (emitting @@ -1384,7 +1367,8 @@ create_archive (void) { if (! st.orig_file_name) { - int fd = open (p->name, open_searchdir_flags); + int fd = openat (chdir_fd, p->name, + open_searchdir_flags); if (fd < 0) { open_diag (p->name); @@ -1588,7 +1572,7 @@ subfile_open (struct tar_stat_info const *dir, char const *file, int flags) gettext (""); } - while ((fd = openat (dir ? dir->fd : AT_FDCWD, file, flags)) < 0 + while ((fd = openat (dir ? dir->fd : chdir_fd, file, flags)) < 0 && open_failure_recover (dir)) continue; return fd; @@ -1619,7 +1603,8 @@ restore_parent_fd (struct tar_stat_info const *st) if (parentfd < 0) { - int origfd = open (parent->orig_file_name, open_searchdir_flags); + int origfd = openat (chdir_fd, parent->orig_file_name, + open_searchdir_flags); if (0 <= origfd) { if (fstat (parentfd, &parentstat) == 0 @@ -1649,13 +1634,12 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) char type; off_t original_size; struct timespec original_ctime; - struct timespec restore_times[2]; off_t block_ordinal = -1; int fd = 0; bool is_dir; struct tar_stat_info const *parent = st->parent; bool top_level = ! parent; - int parentfd = top_level ? AT_FDCWD : parent->fd; + int parentfd = top_level ? chdir_fd : parent->fd; void (*diag) (char const *) = 0; if (interactive_option && !confirm ("add", p)) @@ -1693,8 +1677,8 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) } st->archive_file_size = original_size = st->stat.st_size; - st->atime = restore_times[0] = get_stat_atime (&st->stat); - st->mtime = restore_times[1] = get_stat_mtime (&st->stat); + st->atime = get_stat_atime (&st->stat); + st->mtime = get_stat_mtime (&st->stat); st->ctime = original_ctime = get_stat_ctime (&st->stat); #ifdef S_ISHIDDEN @@ -1714,9 +1698,9 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) put in the archive. This check is omitted if incremental_option is set *and* the - requested file is not explicitely listed in the command line. */ + requested file is not explicitly listed in the command line. */ - if (!(incremental_option && !is_individual_file (p)) + if (! (incremental_option && ! top_level) && !S_ISDIR (st->stat.st_mode) && OLDER_TAR_STAT_TIME (*st, m) && (!after_date_option || OLDER_TAR_STAT_TIME (*st, c))) @@ -1747,6 +1731,10 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) bool ok; struct stat final_stat; + xattrs_acls_get (parentfd, name, st, 0, !is_dir); + xattrs_selinux_get (parentfd, name, st, fd); + xattrs_xattrs_get (parentfd, name, st, fd); + if (is_dir) { const char *tag_file_name; @@ -1763,7 +1751,7 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) ok = dump_dir (st); fd = st->fd; - parentfd = top_level ? AT_FDCWD : parent->fd; + parentfd = top_level ? chdir_fd : parent->fd; } else { @@ -1833,7 +1821,8 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) set_exit_status (TAREXIT_DIFFERS); } else if (atime_preserve_option == replace_atime_preserve - && set_file_atime (fd, p, restore_times) != 0) + && fd && (is_dir || original_size != 0) + && set_file_atime (fd, parentfd, name, st->atime) != 0) utime_error (p); } @@ -1864,6 +1853,9 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size) write_long_link (st); + xattrs_selinux_get (parentfd, name, st, 0); + xattrs_xattrs_get (parentfd, name, st, 0); + block_ordinal = current_block_ordinal (); st->stat.st_size = 0; /* force 0 size on symlink */ header = start_header (st); @@ -1882,11 +1874,26 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) } #endif else if (S_ISCHR (st->stat.st_mode)) - type = CHRTYPE; + { + type = CHRTYPE; + xattrs_acls_get (parentfd, name, st, 0, true); + xattrs_selinux_get (parentfd, name, st, 0); + xattrs_xattrs_get (parentfd, name, st, 0); + } else if (S_ISBLK (st->stat.st_mode)) - type = BLKTYPE; + { + type = BLKTYPE; + xattrs_acls_get (parentfd, name, st, 0, true); + xattrs_selinux_get (parentfd, name, st, 0); + xattrs_xattrs_get (parentfd, name, st, 0); + } else if (S_ISFIFO (st->stat.st_mode)) - type = FIFOTYPE; + { + type = FIFOTYPE; + xattrs_acls_get (parentfd, name, st, 0, true); + xattrs_selinux_get (parentfd, name, st, 0); + xattrs_xattrs_get (parentfd, name, st, 0); + } else if (S_ISSOCK (st->stat.st_mode)) { WARNOPT (WARN_FILE_IGNORED,