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 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 */ }
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; }