void proc_dir(void) { DIRDATA *dblk; long cnt; if (dirp == NULL) return; /* * read backwards through the file and process each directory */ cnt = dircnt; while (--cnt >= 0) { /* * frc_mode set, make sure we set the file modes even if * the user didn't ask for it (see file_subs.c for more info) */ dblk = &dirp[cnt]; if (pmode || dblk->frc_mode) set_pmode(dblk->name, dblk->mode); if (patime || pmtime) set_ftime(dblk->name, dblk->mtime, dblk->atime, 0); free(dblk->name); } free(dirp); dirp = NULL; dircnt = 0; }
void file_close(ARCHD *arcn, int fd) { int res = 0; if (fd < 0) return; if (close(fd) < 0) syswarn(0, errno, "Unable to close file descriptor on %s", arcn->name); /* * set owner/groups first as this may strip off mode bits we want * then set file permission modes. Then set file access and * modification times. */ if (pids) res = set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid); /* * IMPORTANT SECURITY NOTE: * if not preserving mode or we cannot set uid/gid, then PROHIBIT * set uid/gid bits */ if (!pmode || res) arcn->sb.st_mode &= ~(SETBITS); if (pmode) set_pmode(arcn->name, arcn->sb.st_mode); if (patime || pmtime) set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0); }
void proc_dir(void) { char name[PAXPATHLEN+1]; DIRDATA dblk; u_long cnt; if (dirfd < 0) return; /* * read backwards through the file and process each directory */ for (cnt = 0; cnt < dircnt; ++cnt) { /* * read the trailer, then the file name, if this fails * just give up. */ if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0) break; if (read(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk)) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break; if (read(dirfd, name, dblk.nlen) != dblk.nlen) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break; /* * frc_mode set, make sure we set the file modes even if * the user didn't ask for it (see file_subs.c for more info) */ if (pmode || dblk.frc_mode) set_pmode(name, dblk.mode); if (patime || pmtime) set_ftime(name, dblk.mtime, dblk.atime, 0); } close(dirfd); dirfd = -1; if (cnt != dircnt) paxwarn(1,"Unable to set mode and times for created directories"); return; }
void rdfile_close(ARCHD *arcn, int *fd) { /* * make sure the file is open */ if (*fd < 0) return; (void)close(*fd); *fd = -1; if (!tflag) return; /* * user wants last access time reset */ set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1); }
void atdir_end(void) { ATDIR *pt; int i; if (atab == NULL) return; /* * for each non-empty hash table entry reset all the directories * chained there. */ for (i = 0; i < A_TAB_SZ; ++i) { if ((pt = atab[i]) == NULL) continue; /* * remember to force the times, set_ftime() looks at pmtime * and patime, which only applies to things CREATED by pax, * not read by pax. Read time reset is controlled by -t. */ for (; pt != NULL; pt = pt->fow) set_ftime(pt->name, pt->mtime, pt->atime, 1, 0); } }
void proc_dir(void) { #ifdef DIRS_USE_FILE char name[PAXPATHLEN+1]; DIRDATA dblk; u_long cnt; if (dirfd < 0) return; /* * read backwards through the file and process each directory */ for (cnt = 0; cnt < dircnt; ++cnt) { /* * read the trailer, then the file name, if this fails * just give up. */ if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0) break; if (xread(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk)) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break; if (xread(dirfd, name, dblk.nlen) != dblk.nlen) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break; /* * frc_mode set, make sure we set the file modes even if * the user didn't ask for it (see file_subs.c for more info) */ if (pmode || dblk.frc_mode) set_pmode(name, dblk.mode); if (patime || pmtime) set_ftime(name, dblk.mtime, dblk.atime, 0, 0); if (pfflags) set_chflags(name, dblk.fflags); } (void)close(dirfd); dirfd = -1; if (cnt != dircnt) tty_warn(1, "Unable to set mode and times for created directories"); return; #else DIRDATA *dblk; for (dblk = dirdata_head; dblk != NULL; dblk = dirdata_head) { dirdata_head = dblk->next; /* * frc_mode set, make sure we set the file modes even if * the user didn't ask for it (see file_subs.c for more info) */ if (pmode || dblk->frc_mode) set_pmode(dblk->name, dblk->mode); if (patime || pmtime) set_ftime(dblk->name, dblk->mtime, dblk->atime, 0, 0); if (pfflags) set_chflags(dblk->name, dblk->fflags); free(dblk->name); free(dblk); } #endif /* DIRS_USE_FILE */ }
int next_file(ARCHD *arcn) { int cnt; time_t atime; time_t mtime; /* * ftree_sel() might have set the ftree_skip flag if the user has the * -n option and a file was selected from this file arg tree. (-n says * only one member is matched for each pattern) ftree_skip being 1 * forces us to go to the next arg now. */ if (ftree_skip) { /* * clear and go to next arg */ ftree_skip = 0; if (ftree_arg() < 0) return(-1); } /* * loop until we get a valid file to process */ for (;;) { if ((ftent = fts_read(ftsp)) == NULL) { if (errno) syswarn(1, errno, "next_file"); /* * out of files in this tree, go to next arg, if none * we are done */ if (ftree_arg() < 0) return(-1); continue; } /* * handle each type of fts_read() flag */ switch (ftent->fts_info) { case FTS_D: case FTS_DEFAULT: case FTS_F: case FTS_SL: case FTS_SLNONE: /* * these are all ok */ break; case FTS_DP: /* * already saw this directory. If the user wants file * access times reset, we use this to restore the * access time for this directory since this is the * last time we will see it in this file subtree * remember to force the time (this is -t on a read * directory, not a created directory). */ if (!tflag || (get_atdir(ftent->fts_statp->st_dev, ftent->fts_statp->st_ino, &mtime, &atime) < 0)) continue; set_ftime(ftent->fts_path, mtime, atime, 1); continue; case FTS_DC: /* * fts claims a file system cycle */ paxwarn(1,"File system cycle found at %s",ftent->fts_path); continue; case FTS_DNR: syswarn(1, ftent->fts_errno, "Unable to read directory %s", ftent->fts_path); continue; case FTS_ERR: syswarn(1, ftent->fts_errno, "File system traversal error"); continue; case FTS_NS: case FTS_NSOK: syswarn(1, ftent->fts_errno, "Unable to access %s", ftent->fts_path); continue; } /* * ok got a file tree node to process. copy info into arcn * structure (initialize as required) */ arcn->skip = 0; arcn->pad = 0; arcn->ln_nlen = 0; arcn->ln_name[0] = '\0'; memcpy(&arcn->sb, ftent->fts_statp, sizeof(arcn->sb)); /* * file type based set up and copy into the arcn struct * SIDE NOTE: * we try to reset the access time on all files and directories * we may read when the -t flag is specified. files are reset * when we close them after copying. we reset the directories * when we are done with their file tree (we also clean up at * end in case we cut short a file tree traversal). However * there is no way to reset access times on symlinks. */ switch (S_IFMT & arcn->sb.st_mode) { case S_IFDIR: arcn->type = PAX_DIR; if (!tflag) break; add_atdir(ftent->fts_path, arcn->sb.st_dev, arcn->sb.st_ino, arcn->sb.st_mtime, arcn->sb.st_atime); break; case S_IFCHR: arcn->type = PAX_CHR; break; case S_IFBLK: arcn->type = PAX_BLK; break; case S_IFREG: /* * only regular files with have data to store on the * archive. all others will store a zero length skip. * the skip field is used by pax for actual data it has * to read (or skip over). */ arcn->type = PAX_REG; arcn->skip = arcn->sb.st_size; break; case S_IFLNK: arcn->type = PAX_SLK; /* * have to read the symlink path from the file */ if ((cnt = readlink(ftent->fts_path, arcn->ln_name, PAXPATHLEN)) < 0) { syswarn(1, errno, "Unable to read symlink %s", ftent->fts_path); continue; } /* * set link name length, watch out readlink does not * always NUL terminate the link path */ arcn->ln_name[cnt] = '\0'; arcn->ln_nlen = cnt; break; case S_IFSOCK: /* * under BSD storing a socket is senseless but we will * let the format specific write function make the * decision of what to do with it. */ arcn->type = PAX_SCK; break; case S_IFIFO: arcn->type = PAX_FIF; break; } break; } /* * copy file name, set file name length */ arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name)); if (arcn->nlen >= sizeof(arcn->name)) arcn->nlen = sizeof(arcn->name) - 1; /* XXX truncate? */ arcn->org_name = ftent->fts_path; return(0); }
int next_file(ARCHD *arcn) { #ifndef SMALL static char curdir[PAXPATHLEN+2], curpath[PAXPATHLEN+2]; static int curdirlen; struct stat statbuf; FTSENT Mftent; #endif /* SMALL */ int cnt; time_t atime, mtime; char *curlink; #define MFTENT_DUMMY_DEV UINT_MAX curlink = NULL; #ifndef SMALL /* * if parsing an mtree(8) specfile, build up `dummy' ftsent * from specfile info, and jump below to complete setup of arcn. */ if (Mflag) { int skipoptional; next_ftnode: skipoptional = 0; if (ftnode == NULL) /* tree is empty */ return (-1); /* get current name */ if (snprintf(curpath, sizeof(curpath), "%s%s%s", curdir, curdirlen ? "/" : "", ftnode->name) >= sizeof(curpath)) { tty_warn(1, "line %lu: %s: %s", (u_long)ftnode->lineno, curdir, strerror(ENAMETOOLONG)); return (-1); } ftnode->flags |= F_VISIT; /* mark node visited */ /* construct dummy FTSENT */ Mftent.fts_path = curpath; Mftent.fts_statp = &statbuf; Mftent.fts_pointer = ftnode; ftent = &Mftent; /* look for existing file */ if (lstat(Mftent.fts_path, &statbuf) == -1) { if (ftnode->flags & F_OPT) skipoptional = 1; /* missing: fake up stat info */ memset(&statbuf, 0, sizeof(statbuf)); statbuf.st_dev = MFTENT_DUMMY_DEV; statbuf.st_ino = ftnode->lineno; statbuf.st_size = 0; #define NODETEST(t, m) \ if (!(t)) { \ tty_warn(1, "line %lu: %s: %s not specified", \ (u_long)ftnode->lineno, \ ftent->fts_path, m); \ return -1; \ } statbuf.st_mode = nodetoino(ftnode->type); NODETEST(ftnode->flags & F_TYPE, "type"); NODETEST(ftnode->flags & F_MODE, "mode"); if (!(ftnode->flags & F_TIME)) statbuf.st_mtime = starttime; NODETEST(ftnode->flags & (F_GID | F_GNAME), "group"); NODETEST(ftnode->flags & (F_UID | F_UNAME), "user"); if (ftnode->type == F_BLOCK || ftnode->type == F_CHAR) NODETEST(ftnode->flags & F_DEV, "device number"); if (ftnode->type == F_LINK) NODETEST(ftnode->flags & F_SLINK, "symlink"); /* don't require F_FLAGS or F_SIZE */ #undef NODETEST } else { if (ftnode->flags & F_TYPE && nodetoino(ftnode->type) != (statbuf.st_mode & S_IFMT)) { tty_warn(1, "line %lu: %s: type mismatch: specfile %s, tree %s", (u_long)ftnode->lineno, ftent->fts_path, inotype(nodetoino(ftnode->type)), inotype(statbuf.st_mode)); return -1; } if (ftnode->type == F_DIR && (ftnode->flags & F_OPT)) skipoptional = 1; } /* * override settings with those from specfile */ if (ftnode->flags & F_MODE) { statbuf.st_mode &= ~ALLPERMS; statbuf.st_mode |= (ftnode->st_mode & ALLPERMS); } if (ftnode->flags & (F_GID | F_GNAME)) statbuf.st_gid = ftnode->st_gid; if (ftnode->flags & (F_UID | F_UNAME)) statbuf.st_uid = ftnode->st_uid; #if HAVE_STRUCT_STAT_ST_FLAGS if (ftnode->flags & F_FLAGS) statbuf.st_flags = ftnode->st_flags; #endif if (ftnode->flags & F_TIME) #if BSD4_4 && !HAVE_NBTOOL_CONFIG_H statbuf.st_mtimespec = ftnode->st_mtimespec; #else statbuf.st_mtime = ftnode->st_mtimespec.tv_sec; #endif if (ftnode->flags & F_DEV) statbuf.st_rdev = ftnode->st_rdev; if (ftnode->flags & F_SLINK) curlink = ftnode->slink; /* ignore F_SIZE */ /* * find next node */ if (ftnode->type == F_DIR && ftnode->child != NULL) { /* directory with unseen child */ ftnode = ftnode->child; curdirlen = strlcpy(curdir, curpath, sizeof(curdir)); } else do { if (ftnode->next != NULL) { /* next node at current level */ ftnode = ftnode->next; } else { /* move back to parent */ /* reset time only on first cd.. */ if (Mftent.fts_pointer == ftnode && tflag && (get_atdir(MFTENT_DUMMY_DEV, ftnode->lineno, &mtime, &atime) == 0)) { set_ftime(ftent->fts_path, mtime, atime, 1, 0); } ftnode = ftnode->parent; if (ftnode->parent == ftnode) ftnode = NULL; else { curdirlen -= strlen(ftnode->name) + 1; curdir[curdirlen] = '\0'; } } } while (ftnode != NULL && ftnode->flags & F_VISIT); if (skipoptional) /* skip optional entries */ goto next_ftnode; goto got_ftent; } #endif /* SMALL */ /* * ftree_sel() might have set the ftree_skip flag if the user has the * -n option and a file was selected from this file arg tree. (-n says * only one member is matched for each pattern) ftree_skip being 1 * forces us to go to the next arg now. */ if (ftree_skip) { /* * clear and go to next arg */ ftree_skip = 0; if (ftree_arg() < 0) return -1; } if (ftsp == NULL) return -1; /* * loop until we get a valid file to process */ for(;;) { if ((ftent = fts_read(ftsp)) == NULL) { /* * out of files in this tree, go to next arg, if none * we are done */ if (ftree_arg() < 0) return -1; continue; } /* * handle each type of fts_read() flag */ switch(ftent->fts_info) { case FTS_D: case FTS_DEFAULT: case FTS_F: case FTS_SL: case FTS_SLNONE: /* * these are all ok */ break; case FTS_DP: /* * already saw this directory. If the user wants file * access times reset, we use this to restore the * access time for this directory since this is the * last time we will see it in this file subtree * remember to force the time (this is -t on a read * directory, not a created directory). */ if (!tflag || (get_atdir( ftent->fts_statp->st_dev, ftent->fts_statp->st_ino, &mtime, &atime) < 0)) continue; set_ftime(ftent->fts_path, mtime, atime, 1, 0); continue; case FTS_DC: /* * fts claims a file system cycle */ tty_warn(1,"File system cycle found at %s", ftent->fts_path); continue; case FTS_DNR: syswarn(1, FTS_ERRNO(ftent), "Unable to read directory %s", ftent->fts_path); continue; case FTS_ERR: syswarn(1, FTS_ERRNO(ftent), "File system traversal error"); continue; case FTS_NS: case FTS_NSOK: syswarn(1, FTS_ERRNO(ftent), "Unable to access %s", ftent->fts_path); continue; } #ifndef SMALL got_ftent: #endif /* SMALL */ /* * ok got a file tree node to process. copy info into arcn * structure (initialize as required) */ arcn->skip = 0; arcn->pad = 0; arcn->ln_nlen = 0; arcn->ln_name[0] = '\0'; arcn->sb = *(ftent->fts_statp); /* * file type based set up and copy into the arcn struct * SIDE NOTE: * we try to reset the access time on all files and directories * we may read when the -t flag is specified. files are reset * when we close them after copying. we reset the directories * when we are done with their file tree (we also clean up at * end in case we cut short a file tree traversal). However * there is no way to reset access times on symlinks. */ switch(S_IFMT & arcn->sb.st_mode) { case S_IFDIR: arcn->type = PAX_DIR; if (!tflag) break; add_atdir(ftent->fts_path, arcn->sb.st_dev, arcn->sb.st_ino, arcn->sb.st_mtime, arcn->sb.st_atime); break; case S_IFCHR: arcn->type = PAX_CHR; break; case S_IFBLK: arcn->type = PAX_BLK; break; case S_IFREG: /* * only regular files with have data to store on the * archive. all others will store a zero length skip. * the skip field is used by pax for actual data it has * to read (or skip over). */ arcn->type = PAX_REG; arcn->skip = arcn->sb.st_size; break; case S_IFLNK: arcn->type = PAX_SLK; if (curlink != NULL) { cnt = strlcpy(arcn->ln_name, curlink, sizeof(arcn->ln_name)); /* * have to read the symlink path from the file */ } else if ((cnt = readlink(ftent->fts_path, arcn->ln_name, sizeof(arcn->ln_name) - 1)) < 0) { syswarn(1, errno, "Unable to read symlink %s", ftent->fts_path); continue; } /* * set link name length, watch out readlink does not * always null terminate the link path */ arcn->ln_name[cnt] = '\0'; arcn->ln_nlen = cnt; break; #ifdef S_IFSOCK case S_IFSOCK: /* * under BSD storing a socket is senseless but we will * let the format specific write function make the * decision of what to do with it. */ arcn->type = PAX_SCK; break; #endif case S_IFIFO: arcn->type = PAX_FIF; break; } break; } /* * copy file name, set file name length */ arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name)); arcn->org_name = arcn->fts_name; strlcpy(arcn->fts_name, ftent->fts_path, sizeof arcn->fts_name); if (strcmp(NM_CPIO, argv0) == 0) { /* * cpio does *not* descend directories listed in the * arguments, unlike pax/tar, so needs special handling * here. failure to do so results in massive amounts * of duplicated files in the output. We kill fts after * the first name is extracted, what a waste. */ ftcur->refcnt = 1; (void)ftree_arg(); } return 0; }
int node_creat(ARCHD *arcn) { int res; int ign = 0; int oerrno; int pass = 0; mode_t file_mode; struct stat sb; /* * create node based on type, if that fails try to unlink the node and * try again. finally check the path and try again. As noted in the * file and link creation routines, this method seems to exhibit the * best performance in general use workloads. */ file_mode = arcn->sb.st_mode & FILEBITS; for (;;) { switch(arcn->type) { case PAX_DIR: res = mkdir(arcn->name, file_mode); if (ign) res = 0; break; case PAX_CHR: file_mode |= S_IFCHR; res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); break; case PAX_BLK: file_mode |= S_IFBLK; res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); break; case PAX_FIF: res = mkfifo(arcn->name, file_mode); break; case PAX_SCK: /* * Skip sockets, operation has no meaning under BSD */ paxwarn(0, "%s skipped. Sockets cannot be copied or extracted", arcn->name); return(-1); case PAX_SLK: res = symlink(arcn->ln_name, arcn->name); break; case PAX_CTG: case PAX_HLK: case PAX_HRG: case PAX_REG: default: /* * we should never get here */ paxwarn(0, "%s has an unknown file type, skipping", arcn->name); return(-1); } /* * if we were able to create the node break out of the loop, * otherwise try to unlink the node and try again. if that * fails check the full path and try a final time. */ if (res == 0) break; /* * we failed to make the node */ oerrno = errno; if ((ign = unlnk_exist(arcn->name, arcn->type)) < 0) return(-1); if (++pass <= 1) continue; if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { syswarn(1, oerrno, "Could not create: %s", arcn->name); return(-1); } } /* * we were able to create the node. set uid/gid, modes and times */ if (pids) res = ((arcn->type == PAX_SLK) ? set_lids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid) : set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid)); else res = 0; /* * symlinks are done now. */ if (arcn->type == PAX_SLK) return(0); /* * IMPORTANT SECURITY NOTE: * if not preserving mode or we cannot set uid/gid, then PROHIBIT any * set uid/gid bits */ if (!pmode || res) arcn->sb.st_mode &= ~(SETBITS); if (pmode) set_pmode(arcn->name, arcn->sb.st_mode); if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) { /* * Dirs must be processed again at end of extract to set times * and modes to agree with those stored in the archive. However * to allow extract to continue, we may have to also set owner * rights. This allows nodes in the archive that are children * of this directory to be extracted without failure. Both time * and modes will be fixed after the entire archive is read and * before pax exits. */ if (access(arcn->name, R_OK | W_OK | X_OK) < 0) { if (lstat(arcn->name, &sb) < 0) { syswarn(0, errno,"Could not access %s (stat)", arcn->name); set_pmode(arcn->name,file_mode | S_IRWXU); } else { /* * We have to add rights to the dir, so we make * sure to restore the mode. The mode must be * restored AS CREATED and not as stored if * pmode is not set. */ set_pmode(arcn->name, ((sb.st_mode & FILEBITS) | S_IRWXU)); if (!pmode) arcn->sb.st_mode = sb.st_mode; } /* * we have to force the mode to what was set here, * since we changed it from the default as created. */ add_dir(arcn->name, arcn->nlen, &(arcn->sb), 1); } else if (pmode || patime || pmtime) add_dir(arcn->name, arcn->nlen, &(arcn->sb), 0); } if (patime || pmtime) set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0); return(0); }
int node_creat(ARCHD *arcn) { int res; int ign = 0; int oerrno; int pass = 0; mode_t file_mode; struct stat sb; char target[MAXPATHLEN]; char *nm = arcn->name; int len; /* * create node based on type, if that fails try to unlink the node and * try again. finally check the path and try again. As noted in the * file and link creation routines, this method seems to exhibit the * best performance in general use workloads. */ file_mode = arcn->sb.st_mode & FILEBITS(arcn->type == PAX_DIR); for (;;) { switch (arcn->type) { case PAX_DIR: /* * If -h (or -L) was given in tar-mode, follow the * potential symlink chain before trying to create the * directory. */ if (strcmp(NM_TAR, argv0) == 0 && Lflag) { while (lstat(nm, &sb) == 0 && S_ISLNK(sb.st_mode)) { len = readlink(nm, target, sizeof target - 1); if (len == -1) { syswarn(0, errno, "cannot follow symlink %s " "in chain for %s", nm, arcn->name); res = -1; goto badlink; } target[len] = '\0'; nm = target; } } res = domkdir(nm, file_mode); badlink: if (ign) res = 0; break; case PAX_CHR: file_mode |= S_IFCHR; res = mknod(nm, file_mode, arcn->sb.st_rdev); break; case PAX_BLK: file_mode |= S_IFBLK; res = mknod(nm, file_mode, arcn->sb.st_rdev); break; case PAX_FIF: res = mkfifo(nm, file_mode); break; case PAX_SCK: /* * Skip sockets, operation has no meaning under BSD */ tty_warn(0, "%s skipped. Sockets cannot be copied or extracted", nm); return (-1); case PAX_SLK: res = symlink(arcn->ln_name, nm); break; case PAX_CTG: case PAX_HLK: case PAX_HRG: case PAX_REG: default: /* * we should never get here */ tty_warn(0, "%s has an unknown file type, skipping", nm); return (-1); } /* * if we were able to create the node break out of the loop, * otherwise try to unlink the node and try again. if that * fails check the full path and try a final time. */ if (res == 0) break; /* * we failed to make the node */ oerrno = errno; switch (pass++) { case 0: if ((ign = unlnk_exist(nm, arcn->type)) < 0) return (-1); continue; case 1: if (nodirs || chk_path(nm, arcn->sb.st_uid, arcn->sb.st_gid) < 0) { syswarn(1, oerrno, "Cannot create %s", nm); return (-1); } continue; } /* * it must be a file that exists but we can't create or * remove, but we must avoid the infinite loop. */ break; } /* * we were able to create the node. set uid/gid, modes and times */ if (pids) res = set_ids(nm, arcn->sb.st_uid, arcn->sb.st_gid); else res = 0; /* * IMPORTANT SECURITY NOTE: * if not preserving mode or we cannot set uid/gid, then PROHIBIT any * set uid/gid bits */ if (!pmode || res) arcn->sb.st_mode &= ~SETBITS(arcn->type == PAX_DIR); if (pmode) set_pmode(arcn->name, arcn->sb.st_mode); if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) { /* * Dirs must be processed again at end of extract to set times * and modes to agree with those stored in the archive. However * to allow extract to continue, we may have to also set owner * rights. This allows nodes in the archive that are children * of this directory to be extracted without failure. Both time * and modes will be fixed after the entire archive is read and * before pax exits. */ if (access(nm, R_OK | W_OK | X_OK) < 0) { if (lstat(nm, &sb) < 0) { syswarn(0, errno,"Cannot access %s (stat)", arcn->name); set_pmode(nm,file_mode | S_IRWXU); } else { /* * We have to add rights to the dir, so we make * sure to restore the mode. The mode must be * restored AS CREATED and not as stored if * pmode is not set. */ set_pmode(nm, ((sb.st_mode & FILEBITS(arcn->type == PAX_DIR)) | S_IRWXU)); if (!pmode) arcn->sb.st_mode = sb.st_mode; } /* * we have to force the mode to what was set here, * since we changed it from the default as created. */ add_dir(nm, arcn->nlen, &(arcn->sb), 1); } else if (pmode || patime || pmtime) add_dir(nm, arcn->nlen, &(arcn->sb), 0); } if (patime || pmtime) set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0, (arcn->type == PAX_SLK) ? 1 : 0); #if HAVE_STRUCT_STAT_ST_FLAGS if (pfflags && arcn->type != PAX_SLK) set_chflags(arcn->name, arcn->sb.st_flags); #endif return 0; }
void file_close(ARCHD *arcn, int fd) { char *tmp_name; int res; if (fd < 0) return; tmp_name = (arcn->tmp_name != NULL) ? arcn->tmp_name : arcn->name; if (close(fd) < 0) syswarn(0, errno, "Cannot close file descriptor on %s", tmp_name); /* * set owner/groups first as this may strip off mode bits we want * then set file permission modes. Then set file access and * modification times. */ if (pids) res = set_ids(tmp_name, arcn->sb.st_uid, arcn->sb.st_gid); else res = 0; /* * IMPORTANT SECURITY NOTE: * if not preserving mode or we cannot set uid/gid, then PROHIBIT * set uid/gid bits but restore the file modes (since mkstemp doesn't). */ if (!pmode || res) arcn->sb.st_mode &= ~SETBITS(0); if (pmode) set_pmode(tmp_name, arcn->sb.st_mode); else set_pmode(tmp_name, apply_umask((arcn->sb.st_mode & FILEBITS(0)))); if (patime || pmtime) set_ftime(tmp_name, arcn->sb.st_mtime, arcn->sb.st_atime, 0, 0); /* Did we write directly to the target file? */ if (arcn->tmp_name == NULL) return; /* * Finally, now the temp file is fully instantiated rename it to * the desired file name. */ if (rename(tmp_name, arcn->name) < 0) { syswarn(0, errno, "Cannot rename %s to %s", tmp_name, arcn->name); (void)unlink(tmp_name); } #if HAVE_STRUCT_STAT_ST_FLAGS if (pfflags && arcn->type != PAX_SLK) set_chflags(arcn->name, arcn->sb.st_flags); #endif free(arcn->tmp_name); arcn->tmp_name = NULL; xtmp_name = NULL; }