📄 extract.c
字号:
/* if (head->header.linkflag == LF_SPARSE) {
off_t pos;
pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
printf("%d at %d\n", (int) pos, sparse_ind);
written = sparsearray[sparse_ind++].numbytes;
} else*/
written = endofrecs()->charptr - data;
if (written > size)
written = size;
errno = 0;
check = write(fd, data, written);
/*
* The following is in violation of strict
* typing, since the arg to userec
* should be a struct rec *. FIXME.
*/
userec((union record *)(data + written - 1));
if (check == written) continue;
/*
* Error in writing to file.
* Print it, skip to next file in archive.
*/
if(check<0)
msg_perror("couldn't write to file %s",skipcrud+head->header.name);
else
msg("could only write %d of %d bytes to file %s",written,check,skipcrud+head->header.name);
skip_file((long)(size - written));
break; /* Still do the close, mod time, chmod, etc */
}
if(f_multivol)
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 */
if(f_exstdout)
break;
/* if (head->header.isextended) {
register union record *exhdr;
register int i;
for (i = 0; i < 21; i++) {
long offset;
if (!exhdr->ext_hdr.sp[i].numbytes)
break;
offset = from_oct(1+12,
exhdr->ext_hdr.sp[i].offset);
written = from_oct(1+12,
exhdr->ext_hdr.sp[i].numbytes);
lseek(fd, offset, 0);
check = write(fd, data, written);
if (check == written) continue;
}
}*/
check = close(fd);
if (check < 0) {
msg_perror("Error while closing %s",skipcrud+head->header.name);
}
set_filestat:
/*
* If we are root, set the owner and group of the extracted
* file. This does what is wanted both on real Unix and on
* System V. If we are running as a user, we extract as that
* user; if running as root, we extract as the original owner.
*/
if (we_are_root || f_do_chown) {
if (chown(skipcrud+head->header.name, hstat.st_uid,
hstat.st_gid) < 0) {
msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.name,hstat.st_uid,hstat.st_gid);
}
}
/*
* Set the modified time of the file.
*
* Note that we set the accessed time to "now", which
* is really "the time we started extracting files".
* unless f_gnudump is used, in which case .st_atime is used
*/
if (!f_modified) {
/* fixme if f_gnudump should set ctime too, but how? */
if(f_gnudump)
acc_upd_times[0]=hstat.st_atime;
else acc_upd_times[0] = now; /* Accessed now */
acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
if (utime(skipcrud+head->header.name,
acc_upd_times) < 0) {
msg_perror("couldn't change access and modification times of %s",skipcrud+head->header.name);
}
}
/* We do the utime before the chmod because some versions of
utime are broken and trash the modes of the file. Since
we then change the mode anyway, we don't care. . . */
/*
* If '-k' is not set, open() or creat() could have saved
* the permission bits from a previously created file,
* ignoring the ones we specified.
* Even if -k is set, if the file has abnormal
* mode bits, we must chmod since writing or chown() has
* probably reset them.
*
* If -k is set, we know *we* created this file, so the mode
* bits were set by our open(). If the file is "normal", we
* skip the chmod. This works because we did umask(0) if -p
* is set, so umask will have left the specified mode alone.
*/
if ((!f_keep)
|| (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
if (chmod(skipcrud+head->header.name,
notumask & (int)hstat.st_mode) < 0) {
msg_perror("cannot change mode of file %s to %ld",skipcrud+head->header.name,notumask & (int)hstat.st_mode);
}
}
quit:
break;
case LF_LINK:
again_link:
{
struct stat st1,st2;
check = link (head->header.linkname,
skipcrud+head->header.name);
if (check == 0)
break;
if (make_dirs(skipcrud+head->header.name))
goto again_link;
if(f_gnudump && errno==EEXIST)
break;
if( stat(head->header.linkname, &st1) == 0
&& stat(skipcrud+head->header.name, &st2)==0
&& st1.st_dev==st2.st_dev
&& st1.st_ino==st2.st_ino)
break;
msg_perror("Could not link %s to %s",
skipcrud+head->header.name,head->header.linkname);
}
break;
#ifdef S_IFLNK
case LF_SYMLINK:
again_symlink:
check = symlink(head->header.linkname,
skipcrud+head->header.name);
/* FIXME, don't worry uid, gid, etc... */
if (check == 0)
break;
if (make_dirs(skipcrud+head->header.name))
goto again_symlink;
msg_perror("Could not create symlink to %s",head->header.linkname);
break;
#endif
#ifdef S_IFCHR
case LF_CHR:
hstat.st_mode |= S_IFCHR;
goto make_node;
#endif
#ifdef S_IFBLK
case LF_BLK:
hstat.st_mode |= S_IFBLK;
goto make_node;
#endif
#ifdef S_IFIFO
/* If local system doesn't support FIFOs, use default case */
case LF_FIFO:
hstat.st_mode |= S_IFIFO;
hstat.st_rdev = 0; /* FIXME, do we need this? */
goto make_node;
#endif
make_node:
check = mknod(skipcrud+head->header.name,
(int) hstat.st_mode, (int) hstat.st_rdev);
if (check != 0) {
if (make_dirs(skipcrud+head->header.name))
goto make_node;
msg_perror("Could not make %s",skipcrud+head->header.name);
break;
};
goto set_filestat;
case LF_DIR:
case LF_DUMPDIR:
namelen = strlen(skipcrud+head->header.name)-1;
really_dir:
/* Check for trailing /, and zap as many as we find. */
while (namelen && head->header.name[skipcrud+namelen] == '/')
head->header.name[skipcrud+namelen--] = '\0';
if(f_gnudump) { /* Read the entry and delete files
that aren't listed in the archive */
gnu_restore(skipcrud);
} else if(head->header.linkflag==LF_DUMPDIR)
skip_file((long)(hstat.st_size));
again_dir:
check = mkdir(skipcrud+head->header.name,
(we_are_root ? 0 : 0300) | (int)hstat.st_mode);
if (check != 0) {
struct stat st1;
if (make_dirs(skipcrud+head->header.name))
goto again_dir;
/* If we're trying to create '.', let it be. */
if (head->header.name[skipcrud+namelen] == '.' &&
(namelen==0 ||
head->header.name[skipcrud+namelen-1]=='/'))
goto check_perms;
if( errno==EEXIST
&& stat(skipcrud+head->header.name,&st1)==0
&& (st1.st_mode&S_IFMT)==S_IFDIR)
break;
msg_perror("Could not create directory %s",skipcrud+head->header.name);
break;
}
check_perms:
if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) {
hstat.st_mode |= 0300;
msg("Added write and execute permission to directory %s",
skipcrud+head->header.name);
}
goto set_filestat;
/* FIXME, Remember timestamps for after files created? */
/* FIXME, change mode after files created (if was R/O dir) */
case LF_VOLHDR:
if(f_verbose) {
printf("Reading %s\n",head->header.name);
}
break;
case LF_NAMES:
extract_mangle(head);
break;
case LF_MULTIVOL:
msg("Can't extract '%s'--file is continued from another volume\n",head->header.name);
skip_file((long)hstat.st_size);
break;
}
/* We don't need to save it any longer. */
saverec((union record **) 0); /* Unsave it */
}
/*
* After a file/link/symlink/dir creation has failed, see if
* it's because some required directory was not present, and if
* so, create all required dirs.
*/
int
make_dirs(pathname)
char *pathname;
{
char *p; /* Points into path */
int madeone = 0; /* Did we do anything yet? */
int save_errno = errno; /* Remember caller's errno */
int check;
if (errno != ENOENT)
return 0; /* Not our problem */
for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
/* Avoid mkdir of empty string, if leading or double '/' */
if (p == pathname || p[-1] == '/')
continue;
/* Avoid mkdir where last part of path is '.' */
if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
continue;
*p = 0; /* Truncate the path there */
check = mkdir (pathname, 0777); /* Try to create it as a dir */
if (check == 0) {
/* Fix ownership */
if (we_are_root) {
if (chown(pathname, hstat.st_uid,
hstat.st_gid) < 0) {
msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
}
}
pr_mkdir(pathname, p-pathname, notumask&0777);
madeone++; /* Remember if we made one */
*p = '/';
continue;
}
*p = '/';
if (errno == EEXIST) /* Directory already exists */
continue;
/*
* Some other error in the mkdir. We return to the caller.
*/
break;
}
errno = save_errno; /* Restore caller's errno */
return madeone; /* Tell them to retry if we made one */
}
extract_sparse_file(fd, sizeleft, totalsize, name)
int fd;
long *sizeleft,
totalsize;
char *name;
{
register char *data;
union record *datarec;
int sparse_ind = 0;
int written,
count;
/* assuming sizeleft is initially totalsize */
while (*sizeleft > 0) {
datarec = findrec();
if (datarec == NULL) {
msg("Unexpected EOF on archive file");
return;
}
lseek(fd, sparsearray[sparse_ind].offset, 0);
written = sparsearray[sparse_ind++].numbytes;
while (written > RECORDSIZE) {
count = write(fd, datarec->charptr, RECORDSIZE);
if (count < 0)
msg_perror("couldn't write to file %s", name);
written -= count;
*sizeleft -= count;
userec(datarec);
datarec = findrec();
}
count = write(fd, datarec->charptr, written);
if (count < 0) {
msg_perror("couldn't write to file %s", name);
} else if (count != written) {
msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name);
skip_file((long) (*sizeleft));
}
written -= count;
*sizeleft -= count;
userec(datarec);
}
free(sparsearray);
/* if (end_nulls) {
register int i;
printf("%d\n", (int) end_nulls);
for (i = 0; i < end_nulls; i++)
write(fd, "\000", 1);
}*/
userec(datarec);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -