C   20

fcp

Guest on 21st September 2022 01:43:41 PM

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <sys/param.h>
  4.  
  5. #include <unistd.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <fts.h>
  9. #include <fcntl.h>
  10. #include <err.h>
  11.  
  12. #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
  13. #include <sys/mman.h>
  14. #endif
  15.  
  16. #include "uthash.h"
  17.  
  18. char **dests;
  19. int nbdests;
  20.  
  21. #define HASH_FIND_INO(head,ino,out) \
  22.         HASH_FIND(hh,head,ino,sizeof(ino_t),out)
  23. #define HASH_ADD_INO(head,ino,add) \
  24.         HASH_ADD(hh,head,ino,sizeof(ino_t),add)
  25.  
  26. struct hardlinks {
  27.         ino_t inode;
  28.         char path[MAXPATHLEN];
  29.         UT_hash_handle hh;
  30. };
  31.  
  32. static void
  33. setattrs(struct stat *st, char *path)
  34. {
  35.         static struct timeval tv[2];
  36.  
  37.         TIMESPEC_TO_TIMEVAL(&tv[0], &st->st_atim);
  38.         TIMESPEC_TO_TIMEVAL(&tv[1], &st->st_mtim);
  39.  
  40.         lutimes(path, tv);
  41.         lchown(path, st->st_uid, st->st_gid);
  42. }
  43.  
  44. void
  45. copy_file(FTSENT *f, char *p)
  46. {
  47.         char buf[BUFSIZ];
  48.         char *bufp;
  49.         int ffd, r, w, wr, i;
  50.         int *tfds;
  51.         char dpath[MAXPATHLEN];
  52. #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
  53.         char *p;
  54. #endif
  55.  
  56.         ffd = open(f->fts_path, O_RDONLY, 0);
  57.         if (ffd == -1) {
  58.                 warn("%s", f->fts_path);
  59.                 return;
  60.         }
  61.  
  62.         tfds = malloc(nbdests * sizeof(int));
  63.  
  64.         for (i = 0; i < nbdests; i++) {
  65.                 snprintf(dpath, sizeof(dpath), "%s/%s", dests[i], f->fts_path + strlen(p));
  66.                 tfds[i] = open(dpath, O_WRONLY|O_TRUNC|O_CREAT, f->fts_statp->st_mode);
  67.                 if (tfds[i] == -1) {
  68.                         warn("%s", dpath);
  69.                         continue;
  70.                 }
  71.         }
  72. #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
  73.         if (f->fts_statp->st_size > 0 && f->fts_statp->st_size <= 8 * 1024 * 1024 &&
  74.             (p = mmap(NULL, (size_t)f->fts_statp->st_size, PROT_READ, MAP_SHARED, ffd, (off_t)0)) != MAP_FAILED) {
  75.                 for (i = 0; i < nbdests; i++) {
  76.                         for (bufp = p, wr < f->fts_statp->st_size; ; bufp += w, wr -= w) {
  77.                                 w = write(tfds[i], bufp, wr);
  78.                                 if (w <= 0)
  79.                                         break;
  80.                                 if (w >= wr)
  81.                                         break;
  82.                         }
  83.                 }
  84.         } else
  85. #endif
  86.         {
  87.                 while ((r = read(ffd, buf, BUFSIZ)) > 0) {
  88.                         for (i = 0; i < nbdests; i++) {
  89.                                 if (tfds[i] == -1)
  90.                                         continue;
  91.  
  92.                                 for (bufp = buf, w = 0, wr = r; ; bufp += w, wr -= r) {
  93.                                         w = write(tfds[i], bufp, wr);
  94.                                         if (w <= 0)
  95.                                                 break;
  96.                                         if (w >= wr)
  97.                                                 break;
  98.                                 }
  99.                         }
  100.                 }
  101.         }
  102.  
  103.         for (i = 0; i < nbdests; i++) {
  104.                 if (tfds[i] == -1)
  105.                         continue;
  106.                 snprintf(dpath, sizeof(dpath), "%s/%s", dests[i], f->fts_path + strlen(p));
  107.                 setattrs(f->fts_statp, dpath);
  108.                 close(tfds[i]);
  109.         }
  110.         free(tfds);
  111. }
  112.  
  113. int
  114. main(int argc, char **argv)
  115. {
  116.         FTS *ftsp;
  117.         FTSENT *curr;
  118.         char *path[2];
  119.         char dpath[MAXPATHLEN];
  120.         char slink[MAXPATHLEN];
  121.         int i, len;
  122.         struct hardlinks *hl = NULL;
  123.         struct hardlinks *h;
  124.  
  125.         if (argc < 3)
  126.                 err(EXIT_FAILURE, "usage()");
  127.  
  128.         path[0] = argv[1];
  129.         path[1] = NULL;
  130.  
  131.         dests = argv + 2;
  132.         nbdests = argc - 2;
  133.  
  134.         if ((ftsp = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, NULL)) == NULL)
  135.                 err(EXIT_FAILURE, "fts_open");
  136.  
  137.        
  138.         while ((curr = fts_read(ftsp)) != NULL) {
  139.                 if (curr->fts_level == FTS_ROOTLEVEL)
  140.                         continue;
  141.  
  142.                 switch (curr->fts_info) {
  143.                 case FTS_NS:
  144.                 case FTS_DNR:
  145.                 case FTS_ERR:
  146.                         warnx("%s: %s", curr->fts_path, strerror(curr->fts_errno));
  147.                         continue;
  148.                 case FTS_DC:
  149.                         warnx("%s: directory causes a cycle", curr->fts_path);
  150.                         continue;
  151.                 case FTS_D:
  152.                         for (i = 0; i < nbdests; i++) {
  153.                                 snprintf(dpath, sizeof(dpath), "%s/%s", dests[i], curr->fts_path + strlen(path[0]));
  154.                                 mkdir(dpath, curr->fts_statp->st_mode);
  155.                                 setattrs(curr->fts_statp, dpath);
  156.                         }
  157.                         break;
  158.                 case FTS_SL:
  159.                         len = readlink(curr->fts_path, slink, sizeof(slink) -1);
  160.                         slink[len] = '\0';
  161.                         for (i = 0; i < nbdests; i++) {
  162.                                 snprintf(dpath, sizeof(dpath), "%s/%s", dests[i], curr->fts_path + strlen(path[0]));
  163.                                 symlink(slink, dpath);
  164.                                 setattrs(curr->fts_statp, dpath);
  165.                         }
  166.                         break;
  167.                 case FTS_F:
  168.                         HASH_FIND_INO(hl, &curr->fts_statp->st_ino, h);
  169.                         if (h != NULL) {
  170.                                 for (i = 0; i < nbdests; i++) {
  171.                                         snprintf(slink, sizeof(slink), "%s/%s", dests[i], h->path);
  172.                                         snprintf(dpath, sizeof(dpath), "%s/%s", dests[i], curr->fts_path + strlen(path[0]));
  173.                                         link(slink, dpath);
  174.                                         setattrs(curr->fts_statp, dpath);
  175.                                 }
  176.                                 continue;
  177.                         }
  178.  
  179.                         h = malloc(sizeof(struct hardlinks));                  
  180.                         h->inode = curr->fts_statp->st_ino;
  181.                         strlcpy(h->path, curr->fts_path + strlen(path[0]), sizeof(h->path));
  182.                         HASH_ADD_INO(hl, inode, h);
  183.                         /* copy file */
  184.                         copy_file(curr, path[0]);
  185.                         break;
  186.                 default:
  187.                         break;
  188.                 }
  189.  
  190.         }
  191. }

Raw Paste


Login or Register to edit or fork this paste. It's free.