cpdir.c (6a068746777241722b2b32c5d0bc443a2a64d80b) | cpdir.c (65730d9349cc2fac547af1613bd5a019ff5663c8) |
---|---|
1/*- 2 * Copyright (C) 1996 3 * David L. Nugent. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 31 unchanged lines hidden (view full) --- 40#include <sys/stat.h> 41#include <sys/param.h> 42#include <dirent.h> 43 44#include "pw.h" 45#include "pwupd.h" 46 47void | 1/*- 2 * Copyright (C) 1996 3 * David L. Nugent. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 31 unchanged lines hidden (view full) --- 40#include <sys/stat.h> 41#include <sys/param.h> 42#include <dirent.h> 43 44#include "pw.h" 45#include "pwupd.h" 46 47void |
48copymkdir(char const * dir, char const * skel, mode_t mode, uid_t uid, gid_t gid) | 48copymkdir(int rootfd, char const * dir, int skelfd, mode_t mode, uid_t uid, 49 gid_t gid, int flags) |
49{ | 50{ |
50 char src[MAXPATHLEN]; 51 char dst[MAXPATHLEN]; 52 char lnk[MAXPATHLEN]; 53 int len; | 51 char *p, lnk[MAXPATHLEN], copybuf[4096]; 52 int len, homefd, srcfd, destfd; 53 ssize_t sz; 54 struct stat st; 55 struct dirent *e; 56 DIR *d; |
54 | 57 |
55 if (mkdir(dir, mode) != 0 && errno != EEXIST) { | 58 if (*dir == '/') 59 dir++; 60 61 if (mkdirat(rootfd, dir, mode) != 0 && errno != EEXIST) { |
56 warn("mkdir(%s)", dir); | 62 warn("mkdir(%s)", dir); |
57 } else { 58 int infd, outfd; 59 struct stat st; | 63 return; 64 } 65 fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW); 66 if (flags > 0) 67 chflagsat(rootfd, dir, flags, AT_SYMLINK_NOFOLLOW); |
60 | 68 |
61 static char counter = 0; 62 static char *copybuf = NULL; | 69 if (skelfd == -1) 70 return; |
63 | 71 |
64 ++counter; 65 chown(dir, uid, gid); 66 if (skel != NULL && *skel != '\0') { 67 DIR *d = opendir(skel); | 72 homefd = openat(rootfd, dir, O_DIRECTORY); 73 if ((d = fdopendir(skelfd)) == NULL) { 74 close(skelfd); 75 close(homefd); 76 return; 77 } |
68 | 78 |
69 if (d != NULL) { 70 struct dirent *e; | 79 while ((e = readdir(d)) != NULL) { 80 if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) 81 continue; |
71 | 82 |
72 while ((e = readdir(d)) != NULL) { 73 char *p = e->d_name; | 83 p = e->d_name; 84 if (fstatat(skelfd, p, &st, AT_SYMLINK_NOFOLLOW) == -1) 85 continue; |
74 | 86 |
75 if (snprintf(src, sizeof(src), "%s/%s", skel, p) >= (int)sizeof(src)) 76 warn("warning: pathname too long '%s/%s' (skel not copied)", skel, p); 77 else if (lstat(src, &st) == 0) { 78 if (strncmp(p, "dot.", 4) == 0) /* Conversion */ 79 p += 3; 80 if (snprintf(dst, sizeof(dst), "%s/%s", dir, p) >= (int)sizeof(dst)) 81 warn("warning: path too long '%s/%s' (skel file skipped)", dir, p); 82 else { 83 if (S_ISDIR(st.st_mode)) { /* Recurse for this */ 84 if (strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0) 85 copymkdir(dst, src, st.st_mode & _DEF_DIRMODE, uid, gid); 86 chflags(dst, st.st_flags); /* propagate flags */ 87 } else if (S_ISLNK(st.st_mode) && (len = readlink(src, lnk, sizeof(lnk) - 1)) != -1) { 88 lnk[len] = '\0'; 89 symlink(lnk, dst); 90 lchown(dst, uid, gid); 91 /* 92 * Note: don't propagate special attributes 93 * but do propagate file flags 94 */ 95 } else if (S_ISREG(st.st_mode) && (outfd = open(dst, O_RDWR | O_CREAT | O_EXCL, st.st_mode)) != -1) { 96 if ((infd = open(src, O_RDONLY)) == -1) { 97 close(outfd); 98 remove(dst); 99 } else { 100 int b; | 87 if (strncmp(p, "dot.", 4) == 0) /* Conversion */ 88 p += 3; |
101 | 89 |
102 /* 103 * Allocate our copy buffer if we need to 104 */ 105 if (copybuf == NULL) 106 copybuf = malloc(4096); 107 while ((b = read(infd, copybuf, 4096)) > 0) 108 write(outfd, copybuf, b); 109 close(infd); 110 /* 111 * Propagate special filesystem flags 112 */ 113 fchown(outfd, uid, gid); 114 fchflags(outfd, st.st_flags); 115 close(outfd); 116 chown(dst, uid, gid); 117 } 118 } 119 } 120 } 121 } 122 closedir(d); 123 } | 90 if (S_ISDIR(st.st_mode)) { 91 copymkdir(homefd, p, openat(skelfd, e->d_name, O_DIRECTORY), 92 st.st_mode & _DEF_DIRMODE, uid, gid, st.st_flags); 93 continue; |
124 } | 94 } |
125 if (--counter == 0 && copybuf != NULL) { 126 free(copybuf); 127 copybuf = NULL; | 95 96 if (S_ISLNK(st.st_mode) && 97 (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) -1)) 98 != -1) { 99 lnk[len] = '\0'; 100 symlinkat(lnk, homefd, p); 101 fchownat(homefd, p, uid, gid, AT_SYMLINK_NOFOLLOW); 102 continue; |
128 } | 103 } |
104 105 if (!S_ISREG(st.st_mode)) 106 continue; 107 108 if ((srcfd = openat(skelfd, e->d_name, O_RDONLY)) == -1) 109 continue; 110 destfd = openat(homefd, p, O_RDWR | O_CREAT | O_EXCL, 111 st.st_mode); 112 if (destfd == -1) { 113 close(srcfd); 114 continue; 115 } 116 117 while ((sz = read(srcfd, copybuf, sizeof(copybuf))) > 0) 118 write(destfd, copybuf, sz); 119 120 close(srcfd); 121 /* 122 * Propagate special filesystem flags 123 */ 124 fchown(destfd, uid, gid); 125 fchflags(destfd, st.st_flags); 126 close(destfd); |
|
129 } | 127 } |
128 closedir(d); |
|
130} | 129} |
131 | |