skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

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 }