home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / ARCHIVERS / lhasrc.lzh / ln.c < prev    next >
C/C++ Source or Header  |  1992-05-13  |  13KB  |  430 lines

  1. /* Ln: create a hard link to a file (os9/68k)
  2.  * by Robert A. Larson (blarson@skat.usc.edu)
  3.  * This is placed in the public domain for all to enjoy.
  4.  *
  5.  ****** USE AT YOUR OWN RISK *****
  6.  *
  7.  * 01/14/89    Version 1.0
  8.  *
  9.  * Warning: this does potentialy dangerous writing to directories
  10.  * and to the raw disk.  Although some attempt is made to lock out
  11.  * other users from interfearing, I'm not sure the locking works.
  12.  * Moving or links to directories should be used with EXTREME caution
  13.  * if at all.  Note that moving a directory can make a directory tree
  14.  * inaccessable, and 'deldir'ing a linked directory will delete its
  15.  * contents and change the remaining links to normal files.
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <ctype.h>
  20. #include <modes.h>
  21. #include <direct.h>
  22. #include <errno.h>
  23.  
  24. extern char *rindex();
  25. extern int open(), close(), read(), write(), lseek();
  26. extern int access(), getuid(), strcmp();
  27. extern char *strcpy(), *strcat();
  28. extern char *_prgname();
  29. extern int _gs_devn(), _ss_lock();
  30. extern long _gs_pos();
  31.  
  32. static int dncmp();        /* directory name comparison    */
  33. static int do_link();      /* does all the real work    */
  34.  
  35. /* keys for the do_link subroutine */
  36. #define DO_LINK     0
  37. #define DO_RENAME   1
  38. #define TO_DIR      128    /* orred with one of the above    */
  39.  
  40. #define link link
  41.  
  42. #ifndef link
  43. main(argc, argv)
  44. int argc;
  45. char **argv;
  46. {
  47.     register int i;
  48.     char *todir = NULL;
  49.     int skip, what;
  50.  
  51.     for(i = 1; i < argc; i++) {
  52.         if(argv[i][0]=='-') {
  53.             switch(argv[i][1]) {
  54.             case '?':
  55.                 usage();
  56.                 exit(0);
  57.             case 'w':
  58.                 if(todir==NULL && argv[i][2]=='=') {
  59.                     todir = &argv[i][3];
  60.                     skip = i;
  61.                     continue;
  62.                 }
  63.                 /*FALLTHROUGH*/
  64.             default:
  65.                 usage();
  66.                 exit(1);
  67.             }
  68.         }
  69.     }
  70.     what = strcmp(argv[0],"ln")==0 ? DO_LINK : DO_RENAME;
  71.     if(todir==NULL) {
  72.         if(argc != 3) {
  73.             usage();
  74.             exit(1);
  75.         }
  76.         exit(do_link(argv[1], argv[2], what) < 0);
  77.     }
  78.     what |= TO_DIR;
  79.     for(i=1; i < argc; i++) {
  80.         if(i!=skip) {
  81.             if(do_link(argv[i], todir, what) < 0) exit(1);
  82.         }
  83.     }
  84.     exit(0);
  85. }
  86.  
  87. usage() {
  88.     register char *prg = _prgname();
  89.  
  90.     fprintf(stderr,
  91.     "Usage: %s -?\n       %s <from> <to>\n       %s -w=<todir> <from> [<from>]...\n",
  92.     prg, prg, prg);
  93. }
  94.  
  95. #define problem(x)    fprintf x
  96. #else
  97. #define problem(x)    /* ignore */
  98.  
  99. link(old, new)
  100. register char *old, *new;
  101. {
  102.     return do_link(old, new, DO_LINK);
  103. }
  104.  
  105. rename(old, new)
  106. register char *old, *new;
  107. {
  108.     return do_link(old, new, DO_RENAME);
  109. }
  110. #endif
  111.  
  112. do_link(old, new, action)
  113. char *old, *new;
  114. int action;
  115. {
  116.     char *olddir, *oldname, *newdir, *newname;
  117.     int olddirp, newdirp;
  118.     char olddevn[32], newdevn[32+2];
  119.     struct dirent de;
  120.     unsigned char fdl;
  121.     int disk;
  122.     long empty_slot;
  123.     long newdir_addr;
  124.     long entrydir_addr;
  125.     int same;
  126.     int i;
  127.     long old_slot;
  128.     char namebuf[256];
  129.     char nn[128];
  130.  
  131.     if((oldname = rindex(old, '/')) == NULL) {
  132.         olddir = ".";
  133.         oldname = old;
  134.     } 
  135.     else {
  136.         olddir = namebuf;
  137.         strncpy(namebuf, old, oldname - old);
  138.         namebuf[oldname - old] = '\0';
  139.         oldname++;
  140.     }
  141.     if(action & TO_DIR) {
  142.         newdir = new;
  143.         newname = oldname;
  144.         action &= ~TO_DIR;
  145.     } 
  146.     else {
  147.         if((newname = rindex(new, '/')) == NULL) {
  148.             newdir = ".";
  149.             newname = new;
  150.         } 
  151.         else {
  152.             newdir = namebuf;
  153.             if(olddir==namebuf) newdir += oldname - old;
  154.             strncpy(newdir, new, newname - new);
  155.             newdir[newname - new] = '\0';
  156.             newname++;
  157.         }
  158.     }
  159.     if(_prsnam(newname) <= 0) {
  160.         problem((stderr, "%s: Invalid file name \"%s\"\n", _prgname(), newname));
  161.         return -1;
  162.     }
  163.     if((olddirp = open(olddir, S_IREAD | S_IWRITE | S_IFDIR)) < 0) {
  164.         problem((stderr, "%s: Can't open old directory \"%s\"\n", _prgname(),
  165.         olddir));
  166.         return -1;
  167.     }
  168.     if((newdirp = open(newdir, S_IREAD | S_IWRITE | S_IFDIR)) < 0) {
  169.         problem((stderr, "%s: Can't open new directory \"%s\"\n", _prgname(),
  170.         newdir));
  171.         close(olddirp);
  172.         return -1;
  173.     }
  174.     _gs_devn(olddirp, olddevn);
  175.     _gs_devn(newdirp, newdevn);
  176.     if(strcmp(olddevn, newdevn) != 0) {
  177.         problem((stderr, "%s: Not on same device \"%s\" \"%s\"\n",
  178.         _prgname(), olddir, newdir));
  179.         errno = E_DIFFER;
  180.         close(olddirp);
  181.         close(newdirp);
  182.         return -1;
  183.     }
  184.     if((lseek(newdirp, (long)sizeof de, 0) < 0)                /* skip .. */
  185.         || (read(newdirp, (char *)&de, sizeof de) != sizeof de)) {    /* read . */
  186.         problem((stderr, "%s: Problem reading \"%s\"\n", _prgname(), newdir));
  187.         close(olddirp);
  188.         close(newdirp);
  189.         return -1;
  190.     }
  191.     newdir_addr = de.dir_addr;
  192.     if((lseek(olddirp, (long)sizeof de, 0) < 0)                /* skip .. */
  193.         || (read(olddirp, (char *)&de, sizeof de) != sizeof de)) {    /* read . */
  194.         problem((stderr, "%s: Problem reading \"%s\"\n", _prgname(), olddir));
  195.         close(olddirp);
  196.         close(newdirp);
  197.         return -1;
  198.     }
  199.     if((same = (de.dir_addr == newdir_addr)) != 0) {
  200.         /* link to same directory, scan only once */
  201.         close(olddirp);
  202.         olddirp = newdirp;
  203.         /* rename to same name allowed, but not link */
  204.         if(action == DO_LINK && dncmp(oldname, newname) == 0) {
  205.             problem((stderr, "%s: Can't link to same name \"%s\" \"%s\"\n",
  206.             _prgname(), oldname, newname));
  207.             errno = E_CEF;
  208.             close(newdirp);
  209.             return -1;
  210.         }
  211.         if(_ss_lock(newdirp, 0xfffffffff) < 0) {
  212.             problem((stderr, "%s: Could not lock directory \"%s\"\n",
  213.             _prgname(), newdir));
  214.             close(newdirp);
  215.             return -1;
  216.         }
  217.     }
  218.     empty_slot = 0;
  219.     for(;;) {
  220.         if(read(olddirp, (char *)&de, sizeof de) != sizeof de) {
  221.             problem((stderr, "%s: Could not find \"%s\" in \"%s\"\n",
  222.             _prgname(), oldname, olddir));
  223.             errno = E_PNNF;
  224.             if(!same) close(olddirp);
  225.             close(newdirp);
  226.             return -1;
  227.         }
  228.         if(dncmp(de.dir_name, oldname) == 0) break;    /* found it */
  229.         if(same) {
  230.             if(dncmp(de.dir_name, newname) == 0) {
  231.                 problem((stderr, "%s: Already exists \"%s/%s\"\n",
  232.                 _prgname(), newdir, newname));
  233.                 errno = E_CEF;
  234.                 close(newdirp);
  235.                 return -1;
  236.             }
  237.             if(empty_slot == 0 && de.dir_name[0] == '\0')
  238.                 empty_slot = _gs_pos(olddirp);
  239.         }
  240.     }
  241.     if(action != DO_LINK) old_slot = _gs_pos(olddirp);
  242.     entrydir_addr = de.dir_addr;
  243.     if(!same) {
  244.         if(_ss_lock(newdirp, 0xffffffff) < 0) {
  245.             problem((stderr, "%s: Can't lock directory \"%s\"\n", _prgname(),
  246.             newdir));
  247.             close(olddirp);
  248.             close(newdirp);
  249.             return -1;
  250.         }
  251.     }
  252.     if(action != DO_LINK && same) empty_slot = old_slot;
  253.     while(read(newdirp, (char *)&de, sizeof de) == sizeof de) {
  254.         if(dncmp(de.dir_name, newname) == 0) {
  255.             problem((stderr, "%s: Already exists \"%s/%s\"\n", _prgname(),
  256.             newdir, newname));
  257.             errno = E_CEF;
  258.             if(!same) close(olddirp);
  259.             close(newdirp);
  260.             return -1;
  261.         }
  262.         if(empty_slot == 0 && de.dir_name[0] == '\0') {
  263.             empty_slot = _gs_pos(newdirp);
  264.         }
  265.     }
  266.     strcpy(de.dir_name, newname);
  267.     i = strlen(de.dir_name);
  268.     de.dir_name[i-1] |= 0x80;
  269.     while(i < sizeof de.dir_name) de.dir_name[i++] = '\0';
  270.     de.dir_addr = entrydir_addr;
  271.     if(empty_slot != 0) {
  272.         if(lseek(newdirp, empty_slot - sizeof de, 0) < 0) {
  273.             problem((stderr, "%s: Can't position in \"%s\"\n", _prgname(),
  274.             newdir));
  275.             close(disk);
  276.             if(!same) close(olddirp);
  277.             close(newdirp);
  278.             return -1;
  279.         }
  280.     }
  281.     if(action == DO_LINK) {        /* link: increase the link count */
  282.         newdevn[0] = '/';            /* form /<device>@ string */
  283.         strcat(strcpy(newdevn+1, olddevn), "@");
  284.         if((disk = open(newdevn, S_IREAD | S_IWRITE)) < 0) {
  285.             problem((stderr, "%s: Can't open \"%s\"\n", _prgname(), newdevn));
  286.             if(!same) close(olddirp);
  287.             close(newdirp);
  288.             return -1;
  289.         }
  290.         if(lseek(disk, (entrydir_addr<<8) +
  291.             ((char *)(&(((struct fildes *)0)->fd_link)) - (char *)0),
  292.             0) < 0) {
  293.             problem((stderr, "%s: Can't seek to sector 0x%x on \"%s\"\n",
  294.             _prgname(), entrydir_addr, newdevn));
  295.             close(disk);
  296.             if(!same) close(olddirp);
  297.             close(newdirp);
  298.             return -1;
  299.         }
  300.         if(read(disk, (char *)&fdl, sizeof fdl) != sizeof fdl) {
  301.             problem((stderr, "%s: Can't read \"%s\"\n", _prgname(), newdevn));
  302.             close(disk);
  303.             if(!same) close(olddirp);
  304.             close(newdirp);
  305.             return -1;
  306.         }
  307.         if(fdl == 0) {
  308.             problem((stderr, "%s: Bad file descriptor \"%s/%s\"\n", _prgname(),
  309.             olddir, oldname));
  310.             errno = E_BMHP;        /* no appropriate error number */
  311.             close(disk);
  312.             if(!same) close(olddirp);
  313.             close(newdirp);
  314.             return -1;
  315.         }
  316.         if(++fdl == 0) {
  317.             problem((stderr, "%s: Too many links \"%s/%s\"\n", _prgname(),
  318.             olddir, oldname));
  319.             errno = E_BMHP;        /* no appropriate error number */
  320.             close(disk);
  321.             if(!same) close(olddirp);
  322.             close(newdirp);
  323.             return -1;
  324.         }
  325.         if(lseek(disk, -(long)sizeof fdl, 1) < 0) {
  326.             problem((stderr, "%s: Can't lseek on \"%s\"\n", _prgname(),
  327.             newdevn));
  328.             close(disk);
  329.             if(!same) close(olddirp);
  330.             close(newdirp);
  331.             return -1;
  332.         }
  333.         if(write(disk, (char *)&fdl, sizeof fdl) < 0) {
  334.             problem((stderr, "%s: Can't write to \"%s\"\n", _prgname(),
  335.             newdevn));
  336.             close(disk);
  337.             if(!same) close(olddirp);
  338.             close(newdirp);
  339.             return -1;
  340.         }
  341.     } 
  342.     else {
  343.         strcpy(nn, newdir);
  344.         strcat(nn, "/");
  345.         strcat(nn, newname);
  346.         /* Don't let non-superuser move directories, it is dangerous!
  347.          * (artificial restriction)
  348.          */
  349.         if(!same && access(nn, 0) != 0 && getuid() != 0) {
  350.             problem((stderr, "%s: Directory moving can only be done by superuser\n",
  351.             _prgname()));
  352.             errno = E_FNA;
  353.             close(olddirp);
  354.             close(newdirp);
  355.             return -1;
  356.         }
  357.     }
  358.     if(write(newdirp, (char *)&de, sizeof de) < 0) {
  359.         problem((stderr, "%s: Can't write to \"%s\"\n", _prgname(), newdir));
  360.         if(action==DO_LINK) close(disk);
  361.         if(!same) close(olddirp);
  362.         close(newdirp);
  363.         return -1;
  364.     }
  365.     if(action != DO_LINK && !same) {        /* rename: delete old name */
  366.         if((disk = open(nn, S_IREAD | S_IWRITE | S_IFDIR)) >= 0) {
  367.             /* change .. when moving directory */
  368.             if(lseek(disk, (long)sizeof de.dir_name, 0) < 0) {
  369.                 problem((stderr, "%s: can't position in \"%s\"\n",
  370.                 _prgname(), nn));
  371.                 close(disk);
  372.                 close(olddirp);
  373.                 close(newdirp);
  374.                 return -1;
  375.             }
  376.             if(write(disk, (char *)&newdir_addr, sizeof newdir_addr) < 0) {
  377.                 problem((stderr, "%s: Can't write to \"%s\"\n",
  378.                 _prgname(), nn));
  379.                 close(disk);
  380.                 close(olddirp);
  381.                 close(newdirp);
  382.                 return -1;
  383.             }
  384.             close(disk);
  385.         }
  386.         fdl = '\0';
  387.         if(lseek(olddirp, old_slot - sizeof de, 0) < 0) {
  388.             problem((stderr, "%s: can't position in \"%s\"\n", _prgname(),
  389.             olddir));
  390.             close(olddirp);
  391.             close(newdirp);
  392.             return -1;
  393.         }
  394.         if(write(olddirp, (char *)&fdl, sizeof fdl) < 0) {
  395.             problem((stderr, "%s: can't write to \"%s\"\n", _prgname(),
  396.             olddir));
  397.             close(olddirp);
  398.             close(newdirp);
  399.             return -1;
  400.         }
  401.     }
  402.     if(action == DO_LINK) close(disk);
  403.     if(!same) close(olddirp);
  404.     close(newdirp);
  405.     return 0;
  406. }
  407.  
  408. /* Compares two os9 file names, case independant.
  409.  * The first argument may be terminated by setting the msb of
  410.  * the last character or NUL terminated, the second must be NUL
  411.  * termintated.  Returns zero on same, non-zero on different.
  412.  */
  413. static int dncmp(cp1, cp2)
  414. register char *cp1, *cp2;
  415. {
  416.     register int c1, c2;
  417.  
  418.     while((c1 = *cp1++) != 0) {
  419.         if(c1 & 0x80) {
  420.             c1 &= 0x7f;
  421.             return ((c1 != (c2 = *cp2++)) &&
  422.                 (isupper(c1) ? (tolower(c1) != c2) :
  423.             (!isupper(c2) || (tolower(c2) != c1)))) || *cp2;
  424.         }
  425.         if((c1 != (c2 = *cp2++)) && (isupper(c1) ? (tolower(c1) != c2) :
  426.         (!isupper(c2) || (tolower(c2) != c1)))) return 1;
  427.     }
  428.     return *cp2;
  429. }
  430.