X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;ds=sidebyside;f=src%2Fextract.c;h=9d47c58bcd8b1fdc04799bcc1cf7e1c54fcc3f91;hb=196caec187f27a3c3e4a68eee6bb388d79dac960;hp=a9fcb6969c2758d5d8b7cac32acf1eb72f4c692a;hpb=9cb6f5c46626aa0a8b6ce89b949fe3d9aad3feee;p=chaz%2Ftar diff --git a/src/extract.c b/src/extract.c index a9fcb69..9d47c58 100644 --- a/src/extract.c +++ b/src/extract.c @@ -1,5 +1,5 @@ /* Extract files from a tar archive. - Copyright (C) 1988, 92,93,94,96,97,98, 1999 Free Software Foundation, Inc. + Copyright 1988, 92,93,94,96,97,98, 1999 Free Software Foundation, Inc. Written by John Gilmore, on 1985-11-19. This program is free software; you can redistribute it and/or modify it @@ -18,9 +18,6 @@ #include "system.h" -#include -time_t time (); - #if HAVE_UTIME_H # include #else @@ -33,20 +30,10 @@ struct utimbuf #include "common.h" -static time_t now; /* current time */ static int we_are_root; /* true if our effective uid == 0 */ static mode_t newdir_umask; /* umask when creating new directories */ static mode_t current_umask; /* current umask (which is set to 0 if -p) */ -#if 0 -/* "Scratch" space to store the information about a sparse file before - writing the info into the header or extended header. */ -struct sp_array *sparsearray; - -/* Number of elts storable in the sparsearray. */ -int sp_array_size = 10; -#endif - struct delayed_set_stat { struct delayed_set_stat *next; @@ -63,15 +50,16 @@ static struct delayed_set_stat *delayed_set_stat_head; void extr_init (void) { - now = time ((time_t *) 0); we_are_root = geteuid () == 0; + same_permissions_option += we_are_root; + same_owner_option += we_are_root; /* Option -p clears the kernel umask, so it does not affect proper restoration of file permissions. New intermediate directories will comply with umask at start of program. */ newdir_umask = umask (0); - if (same_permissions_option) + if (0 < same_permissions_option) current_umask = 0; else { @@ -103,7 +91,7 @@ set_mode (char *file_name, struct stat *stat_info) normal, we merely skip the chmod. This works because we did umask (0) when -p, so umask will have left the specified mode alone. */ - if ((we_are_root || same_permissions_option) + if (0 < same_permissions_option && ((!keep_old_files_option && !unlink_first_option) || (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX)))) if (chmod (file_name, ~current_umask & stat_info->st_mode) < 0) @@ -144,7 +132,7 @@ set_stat (char *file_name, struct stat *stat_info, int symlink_flag) if (incremental_option) utimbuf.actime = stat_info->st_atime; else - utimbuf.actime = now; + utimbuf.actime = start_time; utimbuf.modtime = stat_info->st_mtime; @@ -165,10 +153,8 @@ set_stat (char *file_name, struct stat *stat_info, int symlink_flag) extract as the original owner. Or else, if we are running as a user, leave the owner and group as they are, so we extract as that user. */ - if (we_are_root || same_owner_option) + if (0 < same_owner_option) { -#if HAVE_LCHOWN - /* When lchown exists, it should be used to change the attributes of the symbolic link itself. In this case, a mere chown would change the attributes of the file the symbolic link is pointing to, and @@ -176,11 +162,13 @@ set_stat (char *file_name, struct stat *stat_info, int symlink_flag) if (symlink_flag) { +#if HAVE_LCHOWN if (lchown (file_name, stat_info->st_uid, stat_info->st_gid) < 0) ERROR ((0, errno, _("%s: Cannot lchown to uid %lu gid %lu"), file_name, (unsigned long) stat_info->st_uid, (unsigned long) stat_info->st_gid)); +#endif } else { @@ -189,28 +177,13 @@ set_stat (char *file_name, struct stat *stat_info, int symlink_flag) file_name, (unsigned long) stat_info->st_uid, (unsigned long) stat_info->st_gid)); - } - -#else /* not HAVE_LCHOWN */ - - if (!symlink_flag) - - if (chown (file_name, stat_info->st_uid, stat_info->st_gid) < 0) - ERROR ((0, errno, _("%s: Cannot chown to uid %lu gid %lu"), - file_name, - (unsigned long) stat_info->st_uid, - (unsigned long) stat_info->st_gid)); -#endif/* not HAVE_LCHOWN */ - - if (!symlink_flag) - - /* On a few systems, and in particular, those allowing to give files - away, changing the owner or group destroys the suid or sgid bits. - So let's attempt setting these bits once more. */ - - if (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX)) - set_mode (file_name, stat_info); + /* On a few systems, and in particular, those allowing to give files + away, changing the owner or group destroys the suid or sgid bits. + So let's attempt setting these bits once more. */ + if (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX)) + set_mode (file_name, stat_info); + } } } @@ -229,7 +202,7 @@ make_directories (char *file_name) int status; for (cursor = strchr (file_name, '/'); - cursor != NULL; + cursor; cursor = strchr (cursor + 1, '/')) { /* Avoid mkdir of empty string, if leading or double '/'. */ @@ -247,16 +220,6 @@ make_directories (char *file_name) if (status == 0) { - /* Fix ownership. */ - - if (we_are_root) - if (chown (file_name, current_stat.st_uid, current_stat.st_gid) < 0) - ERROR ((0, errno, - _("%s: Cannot change owner to uid %lu, gid %lu"), - file_name, - (unsigned long) current_stat.st_uid, - (unsigned long) current_stat.st_gid)); - print_for_mkdir (file_name, cursor - file_name, ~newdir_umask & MODE_RWX); did_something = 1; @@ -280,7 +243,7 @@ make_directories (char *file_name) break; } - errno = saved_errno; /* FIXME: errno should be read-only */ + errno = saved_errno; return did_something; /* tell them to retry if we made one */ } @@ -352,7 +315,7 @@ extract_sparse_file (int fd, off_t *sizeleft, off_t totalsize, char *name) while (*sizeleft > 0) { union block *data_block = find_next_block (); - if (data_block == NULL) + if (! data_block) { ERROR ((0, 0, _("Unexpected EOF on archive file"))); return; @@ -375,6 +338,11 @@ extract_sparse_file (int fd, off_t *sizeleft, off_t totalsize, char *name) *sizeleft -= count; set_next_block_after (data_block); data_block = find_next_block (); + if (! data_block) + { + ERROR ((0, 0, _("Unexpected EOF on archive file"))); + return; + } } count = full_write (fd, data_block->buffer, written); @@ -447,15 +415,14 @@ extract_archive (void) skipcrud = 0; while (!absolute_names_option && CURRENT_FILE_NAME[0] == '/') { - static int warned_once = 0; + static int warned_once; - skipcrud++; /* force relative path */ if (!warned_once) { warned_once = 1; - WARN ((0, 0, _("\ -Removing leading `/' from absolute path names in the archive"))); + WARN ((0, 0, _("Removing leading `/' from archive names"))); } + skipcrud++; /* force relative path */ } /* Take a safety backup of a previously existing file. */ @@ -492,15 +459,14 @@ Removing leading `/' from absolute path names in the archive"))); case GNUTYPE_SPARSE: sp_array_size = 10; - sparsearray = (struct sp_array *) + sparsearray = xmalloc (sp_array_size * sizeof (struct sp_array)); for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++) { - sparsearray[counter].offset = - OFF_FROM_OCT (current_header->oldgnu_header.sp[counter].offset); - sparsearray[counter].numbytes = - SIZE_FROM_OCT (current_header->oldgnu_header.sp[counter].numbytes); + struct sparse const *s = ¤t_header->oldgnu_header.sp[counter]; + sparsearray[counter].offset = OFF_FROM_HEADER (s->offset); + sparsearray[counter].numbytes = SIZE_FROM_HEADER (s->numbytes); if (!sparsearray[counter].numbytes) break; } @@ -516,26 +482,30 @@ Removing leading `/' from absolute path names in the archive"))); while (1) { exhdr = find_next_block (); + if (! exhdr) + { + ERROR ((0, 0, _("Unexpected EOF on archive file"))); + return; + } for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++) { + struct sparse const *s = &exhdr->sparse_header.sp[counter]; if (counter + ind > sp_array_size - 1) { /* Realloc the scratch area since we've run out of room. */ sp_array_size *= 2; - sparsearray = (struct sp_array *) + sparsearray = xrealloc (sparsearray, - sp_array_size * (sizeof (struct sp_array))); + sp_array_size * sizeof (struct sp_array)); } - /* Compare to 0, or use !(int)..., for Pyramid's dumb - compiler. */ - if (exhdr->sparse_header.sp[counter].numbytes == 0) + if (s->numbytes[0] == 0) break; sparsearray[counter + ind].offset = - OFF_FROM_OCT (exhdr->sparse_header.sp[counter].offset); + OFF_FROM_HEADER (s->offset); sparsearray[counter + ind].numbytes = - SIZE_FROM_OCT (exhdr->sparse_header.sp[counter].numbytes); + SIZE_FROM_HEADER (s->numbytes); } if (!exhdr->sparse_header.isextended) break; @@ -564,8 +534,8 @@ Removing leading `/' from absolute path names in the archive"))); again_file: openflag = (keep_old_files_option || unlink_first_option ? - O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL : - O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC) + O_WRONLY | O_BINARY | O_NONBLOCK | O_CREAT | O_EXCL : + O_WRONLY | O_BINARY | O_NONBLOCK | O_CREAT | O_TRUNC) | ((typeflag == GNUTYPE_SPARSE) ? 0 : O_APPEND); /* JK - The last | is a kludge to solve the problem the O_APPEND @@ -606,7 +576,7 @@ Removing leading `/' from absolute path names in the archive"))); #else /* not O_CTG */ if (typeflag == CONTTYPE) { - static int conttype_diagnosed = 0; + static int conttype_diagnosed; if (!conttype_diagnosed) { @@ -646,7 +616,7 @@ Removing leading `/' from absolute path names in the archive"))); REAL interesting unless we do this. */ name_length_bis = strlen (CURRENT_FILE_NAME) + 1; - name = (char *) xmalloc (name_length_bis); + name = xmalloc (name_length_bis); memcpy (name, CURRENT_FILE_NAME, name_length_bis); size = current_stat.st_size; extract_sparse_file (fd, &size, current_stat.st_size, name); @@ -668,7 +638,7 @@ Removing leading `/' from absolute path names in the archive"))); worked. */ data_block = find_next_block (); - if (data_block == NULL) + if (! data_block) { ERROR ((0, 0, _("Unexpected EOF on archive file"))); break; /* FIXME: What happens, then? */ @@ -678,7 +648,7 @@ Removing leading `/' from absolute path names in the archive"))); if (written > size) written = size; - errno = 0; /* FIXME: errno should be read-only */ + errno = 0; sstatus = full_write (fd, data_block->buffer, written); set_next_block_after ((union block *) @@ -702,7 +672,7 @@ Removing leading `/' from absolute path names in the archive"))); } if (multi_volume_option) - assign_string (&save_name, NULL); + assign_string (&save_name, 0); /* If writing to stdout, don't try to do anything to the filename; it doesn't exist, or we don't want to touch it anyway. */ @@ -754,13 +724,13 @@ Removing leading `/' from absolute path names in the archive"))); #else { - static int warned_once = 0; + static int warned_once; if (!warned_once) { warned_once = 1; - WARN ((0, 0, _("\ -Attempting extraction of symbolic links as hard links"))); + WARN ((0, 0, + _("Attempting extraction of symbolic links as hard links"))); } } /* Fall through. */ @@ -916,7 +886,7 @@ Attempting extraction of symbolic links as hard links"))); if (stat (CURRENT_FILE_NAME, &st1) == 0 && S_ISDIR (st1.st_mode)) goto check_perms; - errno = saved_errno; /* FIXME: errno should be read-only */ + errno = saved_errno; } if (maybe_recoverable (CURRENT_FILE_NAME)) @@ -947,7 +917,7 @@ Attempting extraction of symbolic links as hard links"))); } #if !MSDOS - /* MSDOS does not associate timestamps with directories. In this + /* MSDOS does not associate time stamps with directories. In this case, no need to try delaying their restoration. */ if (touch_option) @@ -960,8 +930,7 @@ Attempting extraction of symbolic links as hard links"))); else { - data = ((struct delayed_set_stat *) - xmalloc (sizeof (struct delayed_set_stat))); + data = xmalloc (sizeof (struct delayed_set_stat)); data->file_name = xstrdup (CURRENT_FILE_NAME); data->stat_info = current_stat; data->next = delayed_set_stat_head; @@ -980,8 +949,8 @@ Attempting extraction of symbolic links as hard links"))); break; case GNUTYPE_MULTIVOL: - ERROR ((0, 0, _("\ -Cannot extract `%s' -- file is continued from another volume"), + ERROR ((0, 0, + _("Cannot extract `%s' -- file is continued from another volume"), current_file_name)); skip_file (current_stat.st_size); if (backup_option) @@ -1015,7 +984,7 @@ apply_delayed_set_stat (void) { struct delayed_set_stat *data; - while (delayed_set_stat_head != NULL) + while (delayed_set_stat_head) { data = delayed_set_stat_head; delayed_set_stat_head = delayed_set_stat_head->next;