cpdir.c revision 168046
190075Sobrien/*- 290075Sobrien * Copyright (C) 1996 390075Sobrien * David L. Nugent. All rights reserved. 490075Sobrien * 590075Sobrien * Redistribution and use in source and binary forms, with or without 690075Sobrien * modification, are permitted provided that the following conditions 790075Sobrien * are met: 890075Sobrien * 1. Redistributions of source code must retain the above copyright 990075Sobrien * notice, this list of conditions and the following disclaimer. 1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1190075Sobrien * notice, this list of conditions and the following disclaimer in the 1290075Sobrien * documentation and/or other materials provided with the distribution. 1390075Sobrien * 1490075Sobrien * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 1590075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1690075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1790075Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 1890075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1990075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2090075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2190075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2290075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2390075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2490075Sobrien * SUCH DAMAGE. 2590075Sobrien */ 2690075Sobrien 2790075Sobrien#ifndef lint 2890075Sobrienstatic const char rcsid[] = 2990075Sobrien "$FreeBSD: head/usr.sbin/pw/cpdir.c 168046 2007-03-30 13:18:52Z le $"; 3090075Sobrien#endif /* not lint */ 3190075Sobrien 3290075Sobrien#include <err.h> 3390075Sobrien#include <errno.h> 3490075Sobrien#include <fcntl.h> 3590075Sobrien#include <stdio.h> 3690075Sobrien#include <string.h> 3790075Sobrien#include <stdlib.h> 3890075Sobrien#include <unistd.h> 3990075Sobrien#include <sys/types.h> 4090075Sobrien#include <sys/stat.h> 4190075Sobrien#include <sys/param.h> 4290075Sobrien#include <dirent.h> 4390075Sobrien 4490075Sobrien#include "pwupd.h" 4590075Sobrien 4690075Sobrienvoid 4790075Sobriencopymkdir(char const * dir, char const * skel, mode_t mode, uid_t uid, gid_t gid) 4890075Sobrien{ 4990075Sobrien char src[MAXPATHLEN]; 5090075Sobrien char dst[MAXPATHLEN]; 5190075Sobrien char lnk[MAXPATHLEN]; 5290075Sobrien int len; 5390075Sobrien 5490075Sobrien if (mkdir(dir, mode) != 0 && errno != EEXIST) { 5590075Sobrien warn("mkdir(%s)", dir); 5690075Sobrien } else { 5790075Sobrien int infd, outfd; 5890075Sobrien struct stat st; 5990075Sobrien 6090075Sobrien static char counter = 0; 6190075Sobrien static char *copybuf = NULL; 6290075Sobrien 6390075Sobrien ++counter; 6490075Sobrien chown(dir, uid, gid); 6590075Sobrien if (skel != NULL && *skel != '\0') { 6690075Sobrien DIR *d = opendir(skel); 6790075Sobrien 6890075Sobrien if (d != NULL) { 6990075Sobrien struct dirent *e; 7090075Sobrien 7190075Sobrien while ((e = readdir(d)) != NULL) { 7290075Sobrien char *p = e->d_name; 7390075Sobrien 7490075Sobrien if (snprintf(src, sizeof(src), "%s/%s", skel, p) >= (int)sizeof(src)) 7590075Sobrien warn("warning: pathname too long '%s/%s' (skel not copied)", skel, p); 7690075Sobrien else if (lstat(src, &st) == 0) { 7790075Sobrien if (strncmp(p, "dot.", 4) == 0) /* Conversion */ 7890075Sobrien p += 3; 7990075Sobrien if (snprintf(dst, sizeof(dst), "%s/%s", dir, p) >= (int)sizeof(dst)) 8090075Sobrien warn("warning: path too long '%s/%s' (skel file skipped)", dir, p); 8190075Sobrien else { 8290075Sobrien if (S_ISDIR(st.st_mode)) { /* Recurse for this */ 8390075Sobrien if (strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0) 8490075Sobrien copymkdir(dst, src, (st.st_mode & 0777), uid, gid); 85 chflags(dst, st.st_flags); /* propogate flags */ 86 } else if (S_ISLNK(st.st_mode) && (len = readlink(src, lnk, sizeof(lnk))) != -1) { 87 lnk[len] = '\0'; 88 symlink(lnk, dst); 89 lchown(dst, uid, gid); 90 /* 91 * Note: don't propogate special attributes 92 * but do propogate file flags 93 */ 94 } else if (S_ISREG(st.st_mode) && (outfd = open(dst, O_RDWR | O_CREAT | O_EXCL, st.st_mode)) != -1) { 95 if ((infd = open(src, O_RDONLY)) == -1) { 96 close(outfd); 97 remove(dst); 98 } else { 99 int b; 100 101 /* 102 * Allocate our copy buffer if we need to 103 */ 104 if (copybuf == NULL) 105 copybuf = malloc(4096); 106 while ((b = read(infd, copybuf, 4096)) > 0) 107 write(outfd, copybuf, b); 108 close(infd); 109 /* 110 * Propogate special filesystem flags 111 */ 112 fchown(outfd, uid, gid); 113 fchflags(outfd, st.st_flags); 114 close(outfd); 115 chown(dst, uid, gid); 116 } 117 } 118 } 119 } 120 } 121 closedir(d); 122 } 123 } 124 if (--counter == 0 && copybuf != NULL) { 125 free(copybuf); 126 copybuf = NULL; 127 } 128 } 129} 130 131