]> git.cameronkatri.com Git - pw-darwin.git/blobdiff - pw/cpdir.c
Remove useless assignement of linelen
[pw-darwin.git] / pw / cpdir.c
index 5f1773c9beba427ce666e565829e6d2be7f352e6..334f789bb75edf368d619062f8859b0f83d672bc 100644 (file)
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- *     $Id: cpdir.c,v 1.1.1.2 1996/12/09 23:55:15 joerg Exp $
  */
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
 #include <dirent.h>
-#include <unistd.h>
-#include <sys/param.h>
+#include <err.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
 
+#include "pw.h"
 #include "pwupd.h"
 
 void
-copymkdir(char const * dir, char const * skel, mode_t mode, uid_t uid, gid_t gid)
+copymkdir(int rootfd, char const * dir, int skelfd, mode_t mode, uid_t uid,
+    gid_t gid, int flags)
 {
-       int             rc = 0;
-       char            src[MAXPATHLEN];
-       char            dst[MAXPATHLEN];
-
-       if (mkdir(dir, mode) != 0 && errno != EEXIST) {
-               sprintf(src, "mkdir(%s)", dir);
-               perror(src);
-       } else {
-               int             infd, outfd;
-               struct stat     st;
-
-               static char     counter = 0;
-               static char    *copybuf = NULL;
-
-               ++counter;
-               chown(dir, uid, gid);
-               if (skel == NULL || *skel == '\0')
-                       rc = 1;
-               else {
-                       DIR            *d = opendir(skel);
-
-                       if (d != NULL) {
-                               struct dirent  *e;
-
-                               while ((e = readdir(d)) != NULL) {
-                                       char           *p = e->d_name;
-
-                                       sprintf(src, "%s/%s", skel, p);
-                                       if (stat(src, &st) == 0) {
-                                               if (strncmp(p, "dot.", 4) == 0) /* Conversion */
-                                                       p += 3;
-                                               sprintf(dst, "%s/%s", dir, p);
-                                               if (S_ISDIR(st.st_mode)) {      /* Recurse for this */
-                                                       if (strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0)
-                                                               copymkdir(dst, src, (st.st_mode & 0777), uid, gid);
-                                                       /*
-                                                        * Note: don't propogate 'special' attributes
-                                                        */
-                                               } else if (S_ISREG(st.st_mode) && (outfd = open(dst, O_RDWR | O_CREAT | O_EXCL, st.st_mode)) != -1) {
-                                                       if ((infd = open(src, O_RDONLY)) == -1) {
-                                                               close(outfd);
-                                                               remove(dst);
-                                                       } else {
-                                                               int             b;
-
-                                                               /*
-                                                                * Allocate our copy buffer if we need to
-                                                                */
-                                                               if (copybuf == NULL)
-                                                                       copybuf = malloc(4096);
-                                                               while ((b = read(infd, copybuf, 4096)) > 0)
-                                                                       write(outfd, copybuf, b);
-                                                               close(infd);
-                                                               close(outfd);
-                                                               chown(dst, uid, gid);
-                                                       }
-                                               }
-                                       }
-                               }
-                               closedir(d);
-                       }
+       char            *p, lnk[MAXPATHLEN], copybuf[4096];
+       int             len, homefd, srcfd, destfd;
+       ssize_t         sz;
+       struct stat     st;
+       struct dirent  *e;
+       DIR             *d;
+
+       if (*dir == '/')
+               dir++;
+
+       if (mkdirat(rootfd, dir, mode) != 0 && errno != EEXIST) {
+               warn("mkdir(%s)", dir);
+               return;
+       }
+       fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW);
+       if (flags > 0)
+               chflagsat(rootfd, dir, flags, AT_SYMLINK_NOFOLLOW);
+
+       if (skelfd == -1)
+               return;
+
+       homefd = openat(rootfd, dir, O_DIRECTORY);
+       if ((d = fdopendir(skelfd)) == NULL) {
+               close(skelfd);
+               close(homefd);
+               return;
+       }
+
+       while ((e = readdir(d)) != NULL) {
+               if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0)
+                       continue;
+
+               p = e->d_name;
+               if (fstatat(skelfd, p, &st, AT_SYMLINK_NOFOLLOW) == -1)
+                       continue;
+
+               if (strncmp(p, "dot.", 4) == 0) /* Conversion */
+                       p += 3;
+
+               if (S_ISDIR(st.st_mode)) {
+                       copymkdir(homefd, p, openat(skelfd, e->d_name, O_DIRECTORY),
+                           st.st_mode & _DEF_DIRMODE, uid, gid, st.st_flags);
+                       continue;
+               }
+
+               if (S_ISLNK(st.st_mode) &&
+                   (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) -1))
+                   != -1) {
+                       lnk[len] = '\0';
+                       symlinkat(lnk, homefd, p);
+                       fchownat(homefd, p, uid, gid, AT_SYMLINK_NOFOLLOW);
+                       continue;
                }
-               if (--counter == 0 && copybuf != NULL) {
-                       free(copybuf);
-                       copybuf = NULL;
+
+               if (!S_ISREG(st.st_mode))
+                       continue;
+
+               if ((srcfd = openat(skelfd, e->d_name, O_RDONLY)) == -1)
+                       continue;
+               destfd = openat(homefd, p, O_RDWR | O_CREAT | O_EXCL,
+                   st.st_mode);
+               if (destfd == -1) {
+                       close(srcfd);
+                       continue;
                }
+
+               while ((sz = read(srcfd, copybuf, sizeof(copybuf))) > 0)
+                       write(destfd, copybuf, sz);
+
+               close(srcfd);
+               /*
+                * Propagate special filesystem flags
+                */
+               fchown(destfd, uid, gid);
+               fchflags(destfd, st.st_flags);
+               close(destfd);
        }
+       closedir(d);
 }
-