home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / ARCHIVERS / lha208src.lzh / LHA / SRC / ln.c < prev    next >
C/C++ Source or Header  |  1994-02-14  |  17KB  |  550 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. /*
  19.  * Version 1.1
  20.  *
  21.  * Modified by Mike Haaland
  22.  *
  23.  * December 8, 1992 Tuesday 9:55:17 am          - MSH
  24.  * 
  25.  * o added sector size checking for OSK 2.4
  26.  * o added closing path to raw disk after successful link
  27.  * o Added FROM_DISK || FROM_DRIVER as methods of checking sector size
  28.  * o Added TESTING define for debuggin info
  29.  *
  30.  */
  31.  
  32. #include <stdio.h>
  33. #include <ctype.h>
  34. #include <modes.h>
  35. #include <direct.h>
  36. #include <errno.h>
  37. #include <sgstat.h>
  38.  
  39. struct sgbuf sgopts;
  40.  
  41. extern char *rindex();
  42. extern int  open();
  43. extern int  close();
  44. extern int  read();
  45. extern int  write();
  46. extern int  lseek();
  47. extern int  access();
  48. extern int  getuid();
  49. extern int  strcmp();
  50. extern char *strcpy();
  51. extern char *strcat();
  52. extern char *_prgname();
  53. extern int  _gs_devn();
  54. extern int  _ss_lock();
  55. extern long _gs_pos();
  56.  
  57. static int  dncmp();        /* directory name comparison    */
  58. static int  do_link();        /* does all the real work        */
  59.  
  60. /* keys for the do_link subroutine */
  61. #define DO_LINK        0
  62. #define DO_RENAME    1
  63. #define TO_DIR        128        /* orred with one of the above    */
  64.  
  65. /*
  66.  * Define one of the following ONLY
  67.  *
  68.  * FROM_DISK   - will read LSN0 for the sector size info, byte 0x68
  69.  *               works on ALL OSK systems that I've encountered.
  70.  * FROM_DRIVER - uses the path descriptor sg_ssize field
  71.  *               BEWARE: some OSK 2.3 drivers LIE and say 512 bytes
  72.  *                       when the disk actually uses 256 byte sectors!!!
  73.  * MSH
  74.  */
  75.  
  76. #define FROM_DISK
  77.  
  78. /* Get sector size info from driver - Hazelwoods HD Driver lies on the TC70
  79. #define FROM_DRIVER
  80. */
  81.  
  82. #ifndef LINK
  83. main(argc, argv)
  84. int argc;
  85. char **argv;
  86. {
  87.     register int i;
  88.     char *todir = NULL;
  89.     int skip, what;
  90.  
  91.     for(i = 1; i < argc; i++) {
  92.         if(argv[i][0]=='-') {
  93.             switch(argv[i][1]) {
  94.             case '?':
  95.                 usage();
  96.                 exit(0);
  97.             case 'w':
  98.                 if(todir==NULL && argv[i][2]=='=') {
  99.                     todir = &argv[i][3];
  100.                     skip = i;
  101.                     continue;
  102.                 }
  103.                 /*FALLTHROUGH*/
  104.             default:
  105.                 usage();
  106.                 exit(1);
  107.             }
  108.         }
  109.     }
  110.     what = strcmp(argv[0],"ln")==0 ? DO_LINK : DO_RENAME;
  111.     if(todir==NULL) {
  112.         if(argc != 3) {
  113.             usage();
  114.             exit(1);
  115.         }
  116.         exit(do_link(argv[1], argv[2], what) < 0);
  117.     }
  118.     what |= TO_DIR;
  119.     for(i=1; i < argc; i++) {
  120.         if(i!=skip) {
  121.             if(do_link(argv[i], todir, what) < 0) exit(1);
  122.         }
  123.     }
  124.     exit(0);
  125. }
  126.  
  127. usage() {
  128.     register char *prg = _prgname();
  129.  
  130.     fprintf(stderr,"Usage: %s -?\n",prg);
  131.     fprintf(stderr,"       %s <from> <to>\n",prg);
  132.     fprintf(stderr,"       %s -w=<todir> <from> [<from>]...\n", prg);
  133. }
  134.  
  135.  
  136. #define problem(x)    fprintf x
  137. #else
  138. #define problem(x)    /* ignore */
  139.  
  140. link(old, new)
  141. register char *old, *new;
  142. {
  143.     return do_link(old, new, DO_LINK);
  144. }
  145.  
  146. rename(old, new)
  147. register char *old, *new;
  148. {
  149.     return do_link(old, new, DO_RENAME);
  150. }
  151. #endif
  152.  
  153. static int do_link(old, new, action)
  154. char *old, *new;
  155. int action;
  156. {
  157.     char *olddir, *oldname, *newdir, *newname;
  158.     int olddirp, newdirp;
  159.     char olddevn[32], newdevn[32+2];
  160.     struct dirent de;
  161.     unsigned char fdl;
  162.     int disk;
  163.     long empty_slot;
  164.     long newdir_addr;
  165.     long entrydir_addr;
  166.     long fdladdr;
  167.     int same;
  168.     int i;
  169.     int sector_size;
  170.     long old_slot;
  171.     char namebuf[256];
  172.     char nn[128];
  173.     char ssz;
  174.     int uid;
  175.  
  176.     if((oldname = rindex(old, '/')) == NULL) {
  177.         olddir = ".";
  178.         oldname = old;
  179.     } 
  180.     else {
  181.         olddir = namebuf;
  182.         strncpy(namebuf, old, oldname - old);
  183.         namebuf[oldname - old] = '\0';
  184.         oldname++;
  185.     }
  186.     if(action & TO_DIR) {
  187.         newdir = new;
  188.         newname = oldname;
  189.         action &= ~TO_DIR;
  190.     } 
  191.     else {
  192.         if((newname = rindex(new, '/')) == NULL) {
  193.             newdir = ".";
  194.             newname = new;
  195.         } 
  196.         else {
  197.             newdir = namebuf;
  198.             if(olddir==namebuf) newdir += oldname - old;
  199.             strncpy(newdir, new, newname - new);
  200.             newdir[newname - new] = '\0';
  201.             newname++;
  202.         }
  203.     }
  204.     if(_prsnam(newname) <= 0) {
  205.         problem((stderr, "%s: Invalid file name \"%s\"\n", _prgname(), newname));
  206.         return -1;
  207.     }
  208.     if((olddirp = open(olddir, S_IREAD | S_IWRITE | S_IFDIR)) < 0) {
  209.         problem((stderr, "%s: Can't open old directory \"%s\"\n", _prgname(),
  210.         olddir));
  211.         return -1;
  212.     }
  213.     if((newdirp = open(newdir, S_IREAD | S_IWRITE | S_IFDIR)) < 0) {
  214.         problem((stderr, "%s: Can't open new directory \"%s\"\n", _prgname(),
  215.         newdir));
  216.         close(olddirp);
  217.         return -1;
  218.     }
  219.     _gs_devn(olddirp, olddevn);
  220.     _gs_devn(newdirp, newdevn);
  221.     if(strcmp(olddevn, newdevn) != 0) {
  222.         problem((stderr, "%s: Not on same device \"%s\" \"%s\"\n",
  223.         _prgname(), olddir, newdir));
  224.         errno = E_DIFFER;
  225.         close(olddirp);
  226.         close(newdirp);
  227.         return -1;
  228.     }
  229.     if((lseek(newdirp, (long)sizeof de, 0) < 0)                /* skip .. */
  230.         || (read(newdirp, (char *)&de, sizeof de) != sizeof de)) {    /* read . */
  231.         problem((stderr, "%s: Problem reading \"%s\"\n", _prgname(), newdir));
  232.         close(olddirp);
  233.         close(newdirp);
  234.         return -1;
  235.     }
  236.     newdir_addr = de.dir_addr;
  237.     if((lseek(olddirp, (long)sizeof de, 0) < 0)                /* skip .. */
  238.         || (read(olddirp, (char *)&de, sizeof de) != sizeof de)) {    /* read . */
  239.         problem((stderr, "%s: Problem reading \"%s\"\n", _prgname(), olddir));
  240.         close(olddirp);
  241.         close(newdirp);
  242.         return -1;
  243.     }
  244.     if((same = (de.dir_addr == newdir_addr)) != 0) {
  245.         /* link to same directory, scan only once */
  246.         close(olddirp);
  247.         olddirp = newdirp;
  248.         /* rename to same name allowed, but not link */
  249.         if(action == DO_LINK && dncmp(oldname, newname) == 0) {
  250.             problem((stderr, "%s: Can't link to same name \"%s\" \"%s\"\n",
  251.             _prgname(), oldname, newname));
  252.             errno = E_CEF;
  253.             close(newdirp);
  254.             return -1;
  255.         }
  256.         if(_ss_lock(newdirp, 0xfffffffff) < 0) {
  257.             problem((stderr, "%s: Could not lock directory \"%s\"\n",
  258.             _prgname(), newdir));
  259.             close(newdirp);
  260.             return -1;
  261.         }
  262.     }
  263.     empty_slot = 0;
  264.     for(;;) {
  265.         if(read(olddirp, (char *)&de, sizeof de) != sizeof de) {
  266.             problem((stderr, "%s: Could not find \"%s\" in \"%s\"\n",
  267.             _prgname(), oldname, olddir));
  268.             errno = E_PNNF;
  269.             if(!same) close(olddirp);
  270.             close(newdirp);
  271.             return -1;
  272.         }
  273.         if(dncmp(de.dir_name, oldname) == 0) break;    /* found it */
  274.         if(same) {
  275.             if(dncmp(de.dir_name, newname) == 0) {
  276.                 problem((stderr, "%s: Already exists \"%s/%s\"\n",
  277.                 _prgname(), newdir, newname));
  278.                 errno = E_CEF;
  279.                 close(newdirp);
  280.                 return -1;
  281.             }
  282.             if(empty_slot == 0 && de.dir_name[0] == '\0')
  283.                 empty_slot = _gs_pos(olddirp);
  284.         }
  285.     }
  286.     if(action != DO_LINK) old_slot = _gs_pos(olddirp);
  287.     entrydir_addr = de.dir_addr;
  288.     if(!same) {
  289.         if(_ss_lock(newdirp, 0xffffffff) < 0) {
  290.             problem((stderr, "%s: Can't lock directory \"%s\"\n", _prgname(),
  291.             newdir));
  292.             close(olddirp);
  293.             close(newdirp);
  294.             return -1;
  295.         }
  296.     }
  297.     if(action != DO_LINK && same) empty_slot = old_slot;
  298.     while(read(newdirp, (char *)&de, sizeof de) == sizeof de) {
  299.         if(dncmp(de.dir_name, newname) == 0) {
  300.             problem((stderr, "%s: Already exists \"%s/%s\"\n", _prgname(),
  301.             newdir, newname));
  302.             errno = E_CEF;
  303.             if(!same) close(olddirp);
  304.             close(newdirp);
  305.             return -1;
  306.         }
  307.         if(empty_slot == 0 && de.dir_name[0] == '\0') {
  308.             empty_slot = _gs_pos(newdirp);
  309.         }
  310.     }
  311.     strcpy(de.dir_name, newname);
  312.     i = strlen(de.dir_name);
  313.     de.dir_name[i-1] |= 0x80;
  314.     while(i < sizeof de.dir_name) de.dir_name[i++] = '\0';
  315.     de.dir_addr = entrydir_addr;
  316.     if(empty_slot != 0) {
  317.         if(lseek(newdirp, empty_slot - sizeof de, 0) < 0) {
  318.             problem((stderr, "%s: Can't position in \"%s\"\n", _prgname(),
  319.             newdir));
  320.             close(disk);
  321.             if(!same) close(olddirp);
  322.             close(newdirp);
  323.             return -1;
  324.         }
  325.     }
  326.     if(action == DO_LINK) {        /* link: increase the link count */
  327.         /* Sector size info for OSK 2.4 added 12/07/1992 by MSH */
  328. #ifdef FROM_DRIVER
  329.         if (_gs_opt(newdirp,&sgopts) == -1) {
  330.             problem((stderr, "%s: Can't get device sector size info.\n",
  331.             _prgname()));
  332.             close(olddirp);
  333.             close(newdirp);
  334.             return -1;
  335.         }
  336.         sector_size = sgopts.sg_ssize;
  337.         
  338.         if (sector_size == 0) 
  339.            sector_size = 256;
  340. #endif
  341.         uid = getuid();
  342.         if (uid)
  343.             setuid(0);
  344.         newdevn[0] = '/';            /* form /<device>@ string */
  345.         strcat(strcpy(newdevn+1, olddevn), "@");
  346. #ifdef TESTING
  347.         fprintf(stderr,"Opening '%s' for link\n",newdevn);
  348. #endif
  349.         if((disk = open(newdevn, S_IREAD | S_IWRITE)) < 0) {
  350.             problem((stderr, "%s: Can't open \"%s\"\n", _prgname(), newdevn));
  351.             if(!same) close(olddirp);
  352.             close(newdirp);
  353.             setuid(uid);
  354.             return -1;
  355.         }
  356. #ifdef FROM_MEDIA
  357.         /* Sector size info for OSK 2.4 added 12/07/1992 by MSH */
  358.         /* seek to byte 0x68 - LSNSize - media logical sector size */
  359.         if (lseek(disk,0x68,0) != 0x68) {
  360.             problem((stderr,"%s: Can't seek to LSN0 on \"%s\"\n",_prgname(),newdevn));
  361.             if(!same) close(olddirp);
  362.             close(newdirp);
  363.             setuid(uid);
  364.             return -1;
  365.         }
  366.         /* Read LSNSize byte */    
  367.         if(read(disk, &ssz, sizeof ssz) != sizeof ssz) {
  368.             problem((stderr, "%s: Can't get sector size of \"%s\"\n", _prgname(), newdevn));
  369.             close(disk);
  370.             if(!same) close(olddirp);
  371.             setuid(uid);
  372.             close(newdirp);
  373.             return -1;
  374.         }
  375.         /* If it's 0 sector size is 256 bytes - Pre-OSK 2.4 */
  376.         if (ssz == 0)
  377.             ssz = 1;
  378.         /* value * 256 == sector size in bytes */
  379.         sector_size = ssz * 256;
  380. #endif /* FROM_MEDIA */
  381. #ifdef TESTING
  382.         fprintf(stderr,"Media sector size %d bytes\n",sector_size);
  383. #endif
  384.         if((fdladdr = lseek(disk, (entrydir_addr * sector_size) +
  385.             ((char *)(&(((struct fildes *)0)->fd_link)) - (char *)0),
  386.             0)) < 0) {
  387.             problem((stderr, "%s: Can't seek to sector 0x%x on \"%s\"\n",
  388.             _prgname(), entrydir_addr, newdevn));
  389.             close(disk);
  390.             if(!same) close(olddirp);
  391.             setuid(uid);
  392.             close(newdirp);
  393.             return -1;
  394.         }
  395. #ifdef TESTING
  396.         fprintf(stderr,"Linkbyte addr (%d) for file '%s'\n",fdladdr,old);
  397. #endif
  398.         if(read(disk, (char *)&fdl, sizeof fdl) != sizeof fdl) {
  399.             problem((stderr, "%s: Can't read \"%s\"\n", _prgname(), newdevn));
  400.             close(disk);
  401.             if(!same) close(olddirp);
  402.             setuid(uid);
  403.             close(newdirp);
  404.             return -1;
  405.         }
  406. #ifdef TESTING
  407.         fprintf(stderr,"Linkbyte = (%d) for file '%s'\n",fdl,old);
  408. #endif
  409.         if(fdl == 0) {
  410.             problem((stderr, "%s: Bad file descriptor \"%s/%s\"\n", _prgname(),
  411.             olddir, oldname));
  412.             errno = E_BMHP;        /* no appropriate error number */
  413.             close(disk);
  414.             if(!same) close(olddirp);
  415.             setuid(uid);
  416.             close(newdirp);
  417.             return -1;
  418.         }
  419.         if(++fdl == 0) {
  420.             problem((stderr, "%s: Too many links \"%s/%s\"\n", _prgname(),
  421.             olddir, oldname));
  422.             errno = E_BMHP;        /* no appropriate error number */
  423.             close(disk);
  424.             if(!same) close(olddirp);
  425.             setuid(uid);
  426.             close(newdirp);
  427.             return -1;
  428.         }
  429. #ifdef TESTING
  430.         fprintf(stderr,"Inc. Linkbyte = (%d) to link '%s'\n",fdl,new);
  431. #endif
  432.         if(lseek(disk, fdladdr, 0) != fdladdr) {
  433.             problem((stderr, "%s: Can't lseek on \"%s\"\n", _prgname(),
  434.             newdevn));
  435.             close(disk);
  436.             if(!same) close(olddirp);
  437.             setuid(uid);
  438.             close(newdirp);
  439.             return -1;
  440.         }
  441. #ifdef TESTING
  442.         fprintf(stderr,"ReSeek to (%d) to link '%s'\n",fdladdr,new);
  443. #endif
  444.         if(write(disk, &fdl, sizeof fdl) < 0) {
  445.             problem((stderr, "%s: Can't write to \"%s\"\n", _prgname(),
  446.             newdevn));
  447.             close(disk);
  448.             if(!same) close(olddirp);
  449.             setuid(uid);
  450.             close(newdirp);
  451.             return -1;
  452.         }
  453.         /* This wasn't here!!! - might have been my link problem, yes? */
  454.         close(disk);
  455. #ifdef TESTING
  456.         fprintf(stderr,"Success %s linked to %s - (%d) links\n",old,new,fdl);
  457. #endif
  458.         setuid(uid);
  459.     } 
  460.     else {
  461.         strcpy(nn, newdir);
  462.         strcat(nn, "/");
  463.         strcat(nn, newname);
  464.         /* Don't let non-superuser move directories, it is dangerous!
  465.             * (artificial restriction)
  466.             */
  467.         if(!same && access(nn, 0) != 0 && getuid() != 0) {
  468.             problem((stderr, "%s: Directory moving can only be done by superuser\n",
  469.             _prgname()));
  470.             errno = E_FNA;
  471.             close(olddirp);
  472.             close(newdirp);
  473.             return -1;
  474.         }
  475.     }
  476.     if(write(newdirp, (char *)&de, sizeof de) < 0) {
  477.         problem((stderr, "%s: Can't write to \"%s\"\n", _prgname(), newdir));
  478.         if(action==DO_LINK) close(disk);
  479.         if(!same) close(olddirp);
  480.         close(newdirp);
  481.         return -1;
  482.     }
  483.     if(action != DO_LINK && !same) {        /* rename: delete old name */
  484.         if((disk = open(nn, S_IREAD | S_IWRITE | S_IFDIR)) >= 0) {
  485.             /* change .. when moving directory */
  486.             if(lseek(disk, (long)sizeof de.dir_name, 0) < 0) {
  487.                 problem((stderr, "%s: can't position in \"%s\"\n",
  488.                 _prgname(), nn));
  489.                 close(disk);
  490.                 close(olddirp);
  491.                 close(newdirp);
  492.                 return -1;
  493.             }
  494.             if(write(disk, (char *)&newdir_addr, sizeof newdir_addr) < 0) {
  495.                 problem((stderr, "%s: Can't write to \"%s\"\n",
  496.                 _prgname(), nn));
  497.                 close(disk);
  498.                 close(olddirp);
  499.                 close(newdirp);
  500.                 return -1;
  501.             }
  502.             close(disk);
  503.         }
  504.         fdl = '\0';
  505.         if(lseek(olddirp, old_slot - sizeof de, 0) < 0) {
  506.             problem((stderr, "%s: can't position in \"%s\"\n", _prgname(),
  507.             olddir));
  508.             close(olddirp);
  509.             close(newdirp);
  510.             return -1;
  511.         }
  512.         if(write(olddirp, (char *)&fdl, sizeof fdl) < 0) {
  513.             problem((stderr, "%s: can't write to \"%s\"\n", _prgname(),
  514.             olddir));
  515.             close(olddirp);
  516.             close(newdirp);
  517.             return -1;
  518.         }
  519.     }
  520.     if(action == DO_LINK) close(disk);
  521.     if(!same) close(olddirp);
  522.     close(newdirp);
  523.     return 0;
  524. }
  525.  
  526. /* Compares two os9 file names, case independant.
  527.  * The first argument may be terminated by setting the msb of
  528.  * the last character or NUL terminated, the second must be NUL
  529.  * termintated.     Returns zero on same, non-zero on different.
  530.  */
  531. static int dncmp(cp1, cp2)
  532. register char *cp1, *cp2;
  533. {
  534.     register int c1, c2;
  535.  
  536.     while((c1 = *cp1++) != 0) {
  537.         if(c1 & 0x80) {
  538.             c1 &= 0x7f;
  539.             return ((c1 != (c2 = *cp2++)) &&
  540.                 (isupper(c1) ? (tolower(c1) != c2) :
  541.             (!isupper(c2) || (tolower(c2) != c1)))) || *cp2;
  542.         }
  543.         if((c1 != (c2 = *cp2++)) && (isupper(c1) ? (tolower(c1) != c2) :
  544.         (!isupper(c2) || (tolower(c2) != c1)))) return 1;
  545.     }
  546.     return *cp2;
  547. }
  548.  
  549.  
  550.