home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume4 / xmodem / copy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  5.9 KB  |  378 lines

  1. #
  2. #include <stdio.h>
  3. #include <sys/types.h>
  4. #include <sys/dir.h>
  5. #include <sys/stat.h>
  6. #include <signal.h>
  7. #include <pwd.h>
  8. #include <grp.h>
  9.  
  10.  
  11. /*
  12. **    copy - copy a  subtree to a new directory
  13. **    preserving ownership and dates (access and modification only)
  14. **
  15. **    Keith Thompson    - Feb 7, 1981
  16. **    revised        - May 1, 1981    (added options)
  17. **
  18. **    Options:    (can only be used by superuser)
  19. **
  20. **        -o login_name    make all files owned by 'login_name'
  21. **        -u login_name    make all user ownership 'login_name'
  22. **        -g group_name    make all group ownership 'group_name'
  23. */
  24.  
  25. #define BSIZE 4096
  26.  
  27. #define DEST (argc-1)
  28. #define SRC  (argc-2)
  29.  
  30. #define EXISTS 0
  31. #define READABLE 4
  32. #define WRITEABLE 2
  33. #define EXECUTABLE 1
  34.  
  35. #define MODE 0666
  36. #define READ 0
  37.  
  38. #define strncat strcatn
  39. extern char *strcat();
  40. extern char *strcpy();
  41.  
  42. int superuser;
  43. int user;
  44. int group;
  45.  
  46. main(argc,argv)
  47. int argc;
  48. char **argv;
  49. {
  50.     register i,j,badarg;
  51.     register struct passwd *pw;
  52.     extern struct passwd *getpwnam();
  53.  
  54.     signal(SIGINT,SIG_IGN);
  55.     signal(SIGHUP,SIG_IGN);
  56.     signal(SIGQUIT,SIG_IGN);
  57.     signal(SIGTERM,SIG_IGN);
  58.     signal(SIGPIPE,SIG_IGN);
  59.  
  60.     user = getuid();
  61.     superuser = user == 0;
  62.     group = superuser ? 0 : getgid();
  63.  
  64.     badarg = 0;
  65.  
  66.     if(argc < 3) {
  67.         fprintf(stderr,"usage: %s [ options ] src_dir dst_dir\n",
  68.                 argv[0]);
  69.         exit(2);
  70.     }
  71.  
  72.     if(superuser) for(i=1 ; i<SRC; i = j) {
  73.         register char *ptr;
  74.  
  75.         ptr = argv[i];
  76.         j = i+1;
  77.         if(j >= SRC) {
  78.             fprintf(stderr,"Invalid argument: %s\n",argv[i]);
  79.             badarg++;
  80.             break;
  81.         }
  82.  
  83.         if(*ptr++ != '-') {
  84.             fprintf(stderr,"Invalid argument: %s\n",argv[i]);
  85.             badarg++;
  86.             continue;
  87.         }
  88.  
  89.         pw = getpwnam(argv[j]);
  90.         j++;
  91.  
  92.         switch(*ptr) {
  93.  
  94.         case 'o':
  95.             user = pw->pw_uid;
  96.             group = pw->pw_gid;
  97.             break;
  98.  
  99.         case 'u':
  100.             user = pw->pw_uid;
  101.             break;
  102.  
  103.         case 'g':
  104.             group = pw->pw_gid;
  105.             break;
  106.  
  107.         default:
  108.             fprintf(stderr,"Bad option: %c\n",*(ptr-1));
  109.             badarg++;
  110.         }
  111.     }
  112.  
  113.     if(badarg) exit(4);
  114.  
  115.  
  116.     if(!access(argv[DEST],EXISTS)) {
  117.         fprintf(stderr,"%s already exists\n",argv[DEST]);
  118.         exit(2);
  119.     }
  120.  
  121.     if(access(argv[SRC],READABLE)) {
  122.         fprintf(stderr,"%s not readable\n",argv[SRC]);
  123.         exit(2);
  124.     }
  125.  
  126.  
  127.     copy(argv[SRC],argv[DEST]);
  128. }
  129.  
  130. copy(src,dst)
  131. char *src,*dst;
  132. {
  133.     struct direct dirbuf;
  134.     union {
  135.         char *c;
  136.         struct direct *d;
  137.     } u_dir;
  138.     struct stat statbuf;
  139.     struct stat srcstat;
  140.     char src_file[256],dst_file[256];
  141.     int src_fd;
  142.  
  143.     u_dir.d = &dirbuf;
  144.  
  145.     if(stat(src,&srcstat)) {
  146.         perror(src);
  147.         exit(4);
  148.     }
  149.  
  150.     if((srcstat.st_mode&S_IFMT) != S_IFDIR) {
  151.         fprintf(stderr,"copy: %s is not a directory\n",src);
  152.         exit(4);
  153.     }
  154.  
  155.     /*
  156.     **    src exists and is readable
  157.     **    now make the target directory
  158.     */
  159.  
  160.     if(mkdir(dst)) {
  161.         exit(4);
  162.     }
  163.  
  164.     change(dst, &srcstat);
  165.  
  166.     if((src_fd = open(src,0)) < 0) {
  167.         perror(src);
  168.         exit(4);
  169.     }
  170.  
  171.     while(read(src_fd,u_dir.c,sizeof(dirbuf)) == sizeof(dirbuf)) {
  172.  
  173.         /*
  174.         **    test to see if the directory slot is in use
  175.         */
  176.  
  177.         if(!dirbuf.d_ino)  {
  178.             continue;
  179.         }
  180.  
  181.         /*
  182.         **    skip "." & "..", mkdir takes care of them
  183.         */
  184.  
  185.         if(!strcmp(".",dirbuf.d_name)
  186.         || !strcmp("..",dirbuf.d_name)) {
  187.             continue;
  188.         }
  189.  
  190.         /*
  191.         **    we have a file or directory to copy now
  192.         */
  193.  
  194.         mkname(src_file,src,dirbuf.d_name);
  195.         mkname(dst_file,dst,dirbuf.d_name);
  196.  
  197.         if(stat(src_file,&statbuf)) {
  198.             perror(src_file);
  199.             exit(4);
  200.         }
  201.  
  202.         if(!superuser && access(src_file,READABLE)) {
  203.             fprintf(stdout,"copy: no access %s\n",src_file);
  204.             continue;
  205.         }
  206.  
  207.         /*
  208.         **    do the copy depending on the file type
  209.         **
  210.         **    directory:    recursively copy the subtree
  211.         **    regular:    copy the file
  212.         **    special:    make a new node (super user only)
  213.         */
  214.  
  215.         switch((statbuf.st_mode)&S_IFMT) {
  216.  
  217.         case S_IFDIR:
  218.             copy(src_file,dst_file);
  219.             break;
  220.  
  221.         case S_IFCHR:
  222.         case S_IFBLK:
  223.             if(!superuser) break;
  224.  
  225.             fprintf(stdout,"making special file %s\n",dst_file);
  226.  
  227.             if(mknod(dst_file,(int) statbuf.st_mode,
  228.                 statbuf.st_rdev)) {
  229.             }
  230.             change(dst_file, &statbuf);
  231.             utime(dst_file,&(statbuf.st_atime));
  232.             if(chmod(dst_file,(int) statbuf.st_mode)) {
  233.                 perror(dst_file);
  234.                 exit(4);
  235.             }
  236.             break;
  237.  
  238.         case S_IFREG:
  239.             filecopy(src_file,dst_file);
  240.             change(dst_file, &statbuf);
  241.             utime(dst_file,&(statbuf.st_atime));
  242.             if(chmod(dst_file,(int) statbuf.st_mode)) {
  243.                 perror(dst_file);
  244.                 exit(4);
  245.             }
  246.             break;
  247.  
  248.         default:
  249.             fprintf(stderr,"bad file type: %s\n",src_file);
  250.         }
  251.  
  252.     }
  253.     utime(dst,&(srcstat.st_atime));
  254.     if(chmod(dst,(int) srcstat.st_mode)) {
  255.         perror(dst_file);
  256.         exit(4);
  257.     }
  258.  
  259.     close(src_fd);
  260. }
  261.  
  262.  
  263. mkname(dst,str1,str2)
  264. char *dst,*str1,*str2;
  265. {
  266.     dst[0] = '\0';
  267.     strcat(dst,str1);
  268.     strcat(dst,"/");
  269.     strncat(dst,str2,14);
  270.  
  271. }
  272.  
  273. filecopy(src,dst)
  274. char *src,*dst;
  275. {
  276.     register int src_fd,dst_fd;
  277.     char block[BSIZE];
  278.     register int size;
  279.  
  280.     if((src_fd = open(src,READ)) < 0) {
  281.         perror(src);
  282.         exit(4);
  283.     }
  284.  
  285.     if((dst_fd = creat(dst,MODE)) < 0) {
  286.         perror(dst);
  287.         exit(4);
  288.     }
  289.  
  290.     while((size = read(src_fd,block,BSIZE)) > 0) {
  291.         if(write(dst_fd,block,size) != size) {
  292.             perror(dst);
  293.             exit(4);
  294.         }
  295.     }
  296.  
  297.     if(size < 0) {
  298.         perror(src);
  299.         exit(4);
  300.     }
  301.  
  302.     if(close(src_fd)) {
  303.         perror(src);
  304.         exit(4);
  305.     }
  306.     if(close(dst_fd)) {
  307.         perror(src);
  308.         exit(4);
  309.     }
  310.  
  311. }
  312.  
  313. change(file,status)
  314. char *file;
  315. struct stat *status;
  316. {
  317.     int u,g;
  318.  
  319.     u = user;
  320.     g = group;
  321.  
  322.     if(superuser) {
  323.         if(!user) {
  324.             u = status->st_uid;
  325.         }
  326.         if(!group) {
  327.             g = status->st_gid;
  328.         }
  329.     }
  330.     if(chown(file, u, g)) {
  331.         perror(file);
  332.         exit(4);
  333.     }
  334. }
  335.  
  336.  
  337. mkdir(d)
  338. register char *d;
  339. {
  340.     char pname[128], dname[128];
  341.     register i, slash = 0;
  342.  
  343.     pname[0] = '\0';
  344.     for(i = 0; d[i]; ++i)
  345.         if(d[i] == '/')
  346.             slash = i + 1;
  347.     if(slash)
  348.         strncpy(pname, d, slash);
  349.     strcpy(pname+slash, ".");
  350.     if (access(pname, WRITEABLE)) {
  351.         fprintf(stderr,"mkdir: cannot access %s\n", pname);
  352.         return(-1);
  353.     }
  354.  
  355.     if ((mknod(d, 040777, 0)) < 0) {
  356.         fprintf(stderr,"mkdir: cannot make directory %s\n", d);
  357.         return(-1);
  358.     }
  359.     strcpy(dname, d);
  360.     strcat(dname, "/.");
  361.  
  362.     if((link(d, dname)) < 0) {
  363.         fprintf(stderr, "mkdir: cannot link %s\n", dname);
  364.         unlink(d);
  365.         return(-1);
  366.     }
  367.     strcat(dname, ".");
  368.     if((link(pname, dname)) < 0) {
  369.         fprintf(stderr, "mkdir: cannot link %s\n",dname);
  370.         dname[strlen(dname)] = '\0';
  371.         unlink(dname);
  372.         unlink(d);
  373.         return(-1);
  374.     }
  375.  
  376.     return(0);
  377. }
  378.