hiercopy_internal.c (2300B)
1 /* ISC license. */ 2 3 #include <string.h> 4 #include <unistd.h> 5 #include <sys/stat.h> 6 #include <errno.h> 7 8 #include <skalibs/stralloc.h> 9 #include <skalibs/direntry.h> 10 #include <skalibs/fcntl.h> 11 #include <skalibs/djbunix.h> 12 13 static int dircopy (char const *src, char const *dst, mode_t mode, stralloc *tmp, unsigned int options) 14 { 15 size_t tmpbase = tmp->len ; 16 size_t maxlen = 0 ; 17 if (sals(src, tmp, &maxlen) == -1) return 0 ; 18 19 if (mkdir(dst, S_IRWXU) < 0) 20 { 21 struct stat st ; 22 if (errno != EEXIST) goto err ; 23 if (stat(dst, &st) < 0) goto err ; 24 if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR ; goto err ; } 25 } 26 { 27 size_t srclen = strlen(src) ; 28 size_t dstlen = strlen(dst) ; 29 size_t i = tmpbase ; 30 char srcbuf[srclen + maxlen + 2] ; 31 char dstbuf[dstlen + maxlen + 2] ; 32 memcpy(srcbuf, src, srclen) ; 33 memcpy(dstbuf, dst, dstlen) ; 34 srcbuf[srclen] = '/' ; 35 dstbuf[dstlen] = '/' ; 36 while (i < tmp->len) 37 { 38 size_t n = strlen(tmp->s + i) + 1 ; 39 memcpy(srcbuf + srclen + 1, tmp->s + i, n) ; 40 memcpy(dstbuf + dstlen + 1, tmp->s + i, n) ; 41 i += n ; 42 hiercopy_internal(srcbuf, dstbuf, tmp, 0) ; 43 } 44 } 45 if (chmod(dst, mode) < 0 && !(options & 1)) goto err ; 46 tmp->len = tmpbase ; 47 return 1 ; 48 err: 49 tmp->len = tmpbase ; 50 return 0 ; 51 } 52 53 int hiercopy_internal (char const *src, char const *dst, stralloc *tmp, unsigned int options) 54 { 55 struct stat st ; 56 if (lstat(src, &st) < 0) return 0 ; 57 if (S_ISREG(st.st_mode)) 58 { 59 if (!filecopy_unsafe(src, dst, st.st_mode)) return 0 ; 60 } 61 else if (S_ISDIR(st.st_mode)) 62 { 63 if (!dircopy(src, dst, st.st_mode, tmp, options)) return 0 ; 64 } 65 else if (S_ISFIFO(st.st_mode)) 66 { 67 if (mkfifo(dst, st.st_mode) < 0) return 0 ; 68 } 69 else if (S_ISLNK(st.st_mode)) 70 { 71 size_t tmpbase = tmp->len ; 72 if (sareadlink(tmp, src) < 0) return 0 ; 73 if (!stralloc_0(tmp) || symlink(tmp->s + tmpbase, dst) < 0) 74 { 75 tmp->len = tmpbase ; 76 return 0 ; 77 } 78 tmp->len = tmpbase ; 79 } 80 else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || S_ISSOCK(st.st_mode)) 81 { 82 if (mknod(dst, st.st_mode, st.st_rdev) < 0) return 0 ; 83 } 84 else return (errno = ENOTSUP, 0) ; 85 lchown(dst, st.st_uid, st.st_gid) ; 86 if (!S_ISLNK(st.st_mode)) chmod(dst, st.st_mode) ; 87 return 1 ; 88 }