cpdir.c revision 286201
120253Sjoerg/*- 220302Sjoerg * Copyright (C) 1996 320302Sjoerg * David L. Nugent. All rights reserved. 420253Sjoerg * 520253Sjoerg * Redistribution and use in source and binary forms, with or without 620253Sjoerg * modification, are permitted provided that the following conditions 720253Sjoerg * are met: 820253Sjoerg * 1. Redistributions of source code must retain the above copyright 920302Sjoerg * notice, this list of conditions and the following disclaimer. 1020253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1120253Sjoerg * notice, this list of conditions and the following disclaimer in the 1220253Sjoerg * documentation and/or other materials provided with the distribution. 1320253Sjoerg * 1420302Sjoerg * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 1520253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1620253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1720302Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 1820253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1920253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2020253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2120253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2220253Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2320253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2420253Sjoerg * SUCH DAMAGE. 2520253Sjoerg */ 2620253Sjoerg 2730259Scharnier#ifndef lint 2830259Scharnierstatic const char rcsid[] = 2950479Speter "$FreeBSD: head/usr.sbin/pw/cpdir.c 286201 2015-08-02 13:22:46Z bapt $"; 3030259Scharnier#endif /* not lint */ 3130259Scharnier 32286201Sbapt#include <dirent.h> 3330259Scharnier#include <err.h> 3430259Scharnier#include <errno.h> 3530259Scharnier#include <fcntl.h> 3620253Sjoerg#include <string.h> 3730259Scharnier#include <unistd.h> 3820253Sjoerg 39219408Sjkim#include "pw.h" 4020253Sjoerg#include "pwupd.h" 4120253Sjoerg 4220253Sjoergvoid 43285430Sbaptcopymkdir(int rootfd, char const * dir, int skelfd, mode_t mode, uid_t uid, 44285430Sbapt gid_t gid, int flags) 4520253Sjoerg{ 46285430Sbapt char *p, lnk[MAXPATHLEN], copybuf[4096]; 47285430Sbapt int len, homefd, srcfd, destfd; 48285430Sbapt ssize_t sz; 49285430Sbapt struct stat st; 50285430Sbapt struct dirent *e; 51285430Sbapt DIR *d; 5220253Sjoerg 53285430Sbapt if (*dir == '/') 54285430Sbapt dir++; 55285430Sbapt 56285430Sbapt if (mkdirat(rootfd, dir, mode) != 0 && errno != EEXIST) { 5730259Scharnier warn("mkdir(%s)", dir); 58285430Sbapt return; 59285430Sbapt } 60285430Sbapt fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW); 61285430Sbapt if (flags > 0) 62285430Sbapt chflagsat(rootfd, dir, flags, AT_SYMLINK_NOFOLLOW); 6320253Sjoerg 64285430Sbapt if (skelfd == -1) 65285430Sbapt return; 6620253Sjoerg 67285430Sbapt homefd = openat(rootfd, dir, O_DIRECTORY); 68285430Sbapt if ((d = fdopendir(skelfd)) == NULL) { 69285430Sbapt close(skelfd); 70285430Sbapt close(homefd); 71285430Sbapt return; 72285430Sbapt } 7320253Sjoerg 74285430Sbapt while ((e = readdir(d)) != NULL) { 75285430Sbapt if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) 76285430Sbapt continue; 7720253Sjoerg 78285430Sbapt p = e->d_name; 79285430Sbapt if (fstatat(skelfd, p, &st, AT_SYMLINK_NOFOLLOW) == -1) 80285430Sbapt continue; 8120253Sjoerg 82285430Sbapt if (strncmp(p, "dot.", 4) == 0) /* Conversion */ 83285430Sbapt p += 3; 8420253Sjoerg 85285430Sbapt if (S_ISDIR(st.st_mode)) { 86285430Sbapt copymkdir(homefd, p, openat(skelfd, e->d_name, O_DIRECTORY), 87285430Sbapt st.st_mode & _DEF_DIRMODE, uid, gid, st.st_flags); 88285430Sbapt continue; 8920253Sjoerg } 90285430Sbapt 91285430Sbapt if (S_ISLNK(st.st_mode) && 92285430Sbapt (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) -1)) 93285430Sbapt != -1) { 94285430Sbapt lnk[len] = '\0'; 95285430Sbapt symlinkat(lnk, homefd, p); 96285430Sbapt fchownat(homefd, p, uid, gid, AT_SYMLINK_NOFOLLOW); 97285430Sbapt continue; 9820253Sjoerg } 99285430Sbapt 100285430Sbapt if (!S_ISREG(st.st_mode)) 101285430Sbapt continue; 102285430Sbapt 103285430Sbapt if ((srcfd = openat(skelfd, e->d_name, O_RDONLY)) == -1) 104285430Sbapt continue; 105285430Sbapt destfd = openat(homefd, p, O_RDWR | O_CREAT | O_EXCL, 106285430Sbapt st.st_mode); 107285430Sbapt if (destfd == -1) { 108285430Sbapt close(srcfd); 109285430Sbapt continue; 110285430Sbapt } 111285430Sbapt 112285430Sbapt while ((sz = read(srcfd, copybuf, sizeof(copybuf))) > 0) 113285430Sbapt write(destfd, copybuf, sz); 114285430Sbapt 115285430Sbapt close(srcfd); 116285430Sbapt /* 117285430Sbapt * Propagate special filesystem flags 118285430Sbapt */ 119285430Sbapt fchown(destfd, uid, gid); 120285430Sbapt fchflags(destfd, st.st_flags); 121285430Sbapt close(destfd); 12220253Sjoerg } 123285430Sbapt closedir(d); 12420253Sjoerg} 125