Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/pw/cpdir.c
| Show All 34 Lines | |||||
| #include "pw.h" | #include "pw.h" | ||||
| void | void | ||||
| copymkdir(int rootfd, char const *dir, int skelfd, mode_t mode, uid_t uid, | copymkdir(int rootfd, char const *dir, int skelfd, mode_t mode, uid_t uid, | ||||
| gid_t gid, int flags) | gid_t gid, int flags) | ||||
| { | { | ||||
| char *p, lnk[MAXPATHLEN]; | char *p, lnk[MAXPATHLEN]; | ||||
| int len, homefd, srcfd, destfd; | int len, srcfd, destfd; | ||||
| ssize_t sz; | ssize_t sz; | ||||
| struct stat st; | struct stat st; | ||||
| struct dirent *e; | struct dirent *e; | ||||
| DIR *d; | DIR *d; | ||||
| mode_t pumask; | |||||
| if (*dir == '/') | if (*dir == '/') | ||||
| dir++; | dir++; | ||||
| pumask = umask(0); | |||||
| umask(pumask); | |||||
| if (mkdirat(rootfd, dir, mode) != 0) { | if (mkdirat(rootfd, dir, mode) != 0) { | ||||
| mode_t pumask; | |||||
| if (errno != EEXIST) { | if (errno != EEXIST) { | ||||
| warn("mkdir(%s)", dir); | warn("mkdir(%s)", dir); | ||||
| return; | return; | ||||
| } | } | ||||
| pumask = umask(0); | |||||
| umask(pumask); | |||||
| if (fchmodat(rootfd, dir, mode & ~pumask, | if (fchmodat(rootfd, dir, mode & ~pumask, | ||||
| AT_SYMLINK_NOFOLLOW) == -1) | AT_SYMLINK_NOFOLLOW) == -1) | ||||
| warn("chmod(%s)", dir); | warn("chmod(%s)", dir); | ||||
| } | } | ||||
| if (fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW) == -1) | if (fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW) == -1) | ||||
| warn("chown(%s)", dir); | warn("chown(%s)", dir); | ||||
| if (flags > 0 && chflagsat(rootfd, dir, flags, | if (flags > 0 && chflagsat(rootfd, dir, flags, | ||||
| AT_SYMLINK_NOFOLLOW) == -1) | AT_SYMLINK_NOFOLLOW) == -1) | ||||
| warn("chflags(%s)", dir); | warn("chflags(%s)", dir); | ||||
| metalog_emit(dir, (mode | S_IFDIR) & ~pumask, uid, gid, flags); | |||||
| if (skelfd == -1) | if (skelfd == -1) | ||||
| return; | return; | ||||
| homefd = openat(rootfd, dir, O_DIRECTORY); | |||||
| if ((d = fdopendir(skelfd)) == NULL) { | if ((d = fdopendir(skelfd)) == NULL) { | ||||
| close(skelfd); | close(skelfd); | ||||
| close(homefd); | |||||
| return; | return; | ||||
| } | } | ||||
| while ((e = readdir(d)) != NULL) { | while ((e = readdir(d)) != NULL) { | ||||
| char path[MAXPATHLEN]; | |||||
| if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) | if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) | ||||
| continue; | continue; | ||||
| p = e->d_name; | p = e->d_name; | ||||
| if (fstatat(skelfd, p, &st, AT_SYMLINK_NOFOLLOW) == -1) | if (fstatat(skelfd, p, &st, AT_SYMLINK_NOFOLLOW) == -1) | ||||
| continue; | continue; | ||||
| if (strncmp(p, "dot.", 4) == 0) /* Conversion */ | if (strncmp(p, "dot.", 4) == 0) /* Conversion */ | ||||
| p += 3; | p += 3; | ||||
| (void)snprintf(path, sizeof(path), "%s/%s", dir, p); | |||||
| if (S_ISDIR(st.st_mode)) { | if (S_ISDIR(st.st_mode)) { | ||||
| copymkdir(homefd, p, openat(skelfd, e->d_name, O_DIRECTORY), | int fd; | ||||
| st.st_mode & _DEF_DIRMODE, uid, gid, st.st_flags); | |||||
| fd = openat(skelfd, e->d_name, O_DIRECTORY); | |||||
| if (fd == -1) { | |||||
| warn("openat(%s)", e->d_name); | |||||
| continue; | continue; | ||||
| } | } | ||||
| copymkdir(rootfd, path, fd, st.st_mode & _DEF_DIRMODE, | |||||
| uid, gid, st.st_flags); | |||||
| continue; | |||||
| } | |||||
| if (S_ISLNK(st.st_mode) && | if (S_ISLNK(st.st_mode) && | ||||
| (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) -1)) | (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) - 1)) | ||||
| != -1) { | != -1) { | ||||
| lnk[len] = '\0'; | lnk[len] = '\0'; | ||||
| symlinkat(lnk, homefd, p); | if (symlinkat(lnk, rootfd, path) != 0) | ||||
| fchownat(homefd, p, uid, gid, AT_SYMLINK_NOFOLLOW); | warn("symlink(%s)", path); | ||||
| else if (fchownat(rootfd, path, uid, gid, | |||||
| AT_SYMLINK_NOFOLLOW) != 0) | |||||
| warn("chown(%s)", path); | |||||
| metalog_emit_symlink(path, lnk, st.st_mode & ~pumask, | |||||
| uid, gid); | |||||
| continue; | continue; | ||||
| } | } | ||||
| if (!S_ISREG(st.st_mode)) | if (!S_ISREG(st.st_mode)) | ||||
| continue; | continue; | ||||
| if ((srcfd = openat(skelfd, e->d_name, O_RDONLY)) == -1) | if ((srcfd = openat(skelfd, e->d_name, O_RDONLY)) == -1) | ||||
| continue; | continue; | ||||
| destfd = openat(homefd, p, O_RDWR | O_CREAT | O_EXCL, | destfd = openat(rootfd, path, O_RDWR | O_CREAT | O_EXCL, | ||||
| st.st_mode); | st.st_mode); | ||||
| if (destfd == -1) { | if (destfd == -1) { | ||||
| close(srcfd); | close(srcfd); | ||||
| continue; | continue; | ||||
| } | } | ||||
| do { | do { | ||||
| sz = copy_file_range(srcfd, NULL, destfd, NULL, | sz = copy_file_range(srcfd, NULL, destfd, NULL, | ||||
| SSIZE_MAX, 0); | SSIZE_MAX, 0); | ||||
| } while (sz > 0); | } while (sz > 0); | ||||
| if (sz < 0) | if (sz < 0) | ||||
| warn("copy_file_range"); | warn("copy_file_range"); | ||||
| close(srcfd); | close(srcfd); | ||||
| /* | /* | ||||
| * Propagate special filesystem flags | * Propagate special filesystem flags | ||||
| */ | */ | ||||
| if (fchown(destfd, uid, gid) != 0) | if (fchown(destfd, uid, gid) != 0) | ||||
| warn("chown(%s)", p); | warn("chown(%s)", p); | ||||
| if (fchflags(destfd, st.st_flags) != 0) | if (fchflags(destfd, st.st_flags) != 0) | ||||
| warn("chflags(%s)", p); | warn("chflags(%s)", p); | ||||
| metalog_emit(path, st.st_mode & ~pumask, uid, gid, st.st_flags); | |||||
| close(destfd); | close(destfd); | ||||
| } | } | ||||
| closedir(d); | closedir(d); | ||||
| } | } | ||||