home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / directry / mv / mv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  10.5 KB  |  372 lines

  1. /*
  2.   8-Sep-86 16:13:41-PDT,10586;000000000000
  3.   Return-Path: <pwu@unix.macc.wisc.edu>
  4.   Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:11:55 PDT
  5.   Received: by unix.macc.wisc.edu;
  6.             id AA04974; 4.12/5; Mon, 8 Sep 86 17:31:56 cdt
  7.   Date: Mon, 8 Sep 86 17:31:56 cdt
  8.   From: Peter Wu <pwu@unix.macc.wisc.edu>
  9.   Message-Id: <8609082231.AA04974@unix.macc.wisc.edu>
  10.   To: info-ibmpc-request@mosis
  11.   Subject: mv.c
  12. */
  13.  
  14. /* move subdirectories
  15. ** Written by Peter Wu; July 86.
  16. ** compile with cc mv /ze
  17. */
  18. #define LINT_ARGS
  19.  
  20. #define ALLOC 26        /* starting cluster number in directory entry */
  21. #define PLEN 200        /* max path len */
  22.  
  23. #include <dos.h>
  24. #include "dta.h"
  25. #include "peek.h"
  26. #include <conio.h>
  27.  
  28. unsigned char func32h();
  29. unsigned short findir();
  30. unsigned short clus2sec();
  31. char *readsec();
  32. char lastc(char *);
  33.  
  34. /* external var */
  35. extern int
  36.   num_sec,  /* number of sectors buffered */
  37.   brk_st;  /* orginal break status */
  38.  
  39. /* source & dest must be normalized
  40. ** mydta1 contains dta of source
  41. */
  42. mvdir(mydta1,source,dest)  /* move subdirectory */
  43. union dtbuf mydta1;
  44. char *source, *dest;
  45. {
  46.   unsigned short sector1, sector2, offset1, offset2, clus1, clus2,
  47.                 d1, d2, status, *p1, *p2, ds1, ds2, bps, parent, drv;
  48.   char *secbuf1, *secbuf2, *secbuf3, cpath[PLEN];
  49.   union dtbuf mydta2;
  50.  
  51.   /* make sure source is not a root directory */
  52.   if (lastc(source) == '\\') {
  53.     cputs("move root directory? You're joking!\n\015");
  54.     exit(1);
  55.   }
  56.  
  57.   /* make sure source is not predesessor of destination */
  58.   if (apreb(source, dest)) {
  59.     /* this will create a directory loop if allowed to go on or
  60.     ** it's a redundant rename to itself (e.g. mv \ha\. \)
  61.     */
  62.     cputs("not moved to avoid loop or redundancy\n\015");
  63.     return -1;
  64.   }
  65.  
  66.   /* see if source is a predesessor of current directory */
  67.   drv = toupper(source[0]) - '@';
  68.   current(drv,cpath);
  69.   if ( apreb(source,cpath) ) {
  70.     cputs("not moved to preserve current directory\n\015");
  71.     return -2;
  72.   }
  73.  
  74.   /* there should be a way to test if source is a predesessor of
  75.   ** a 'subst' drive's current directory
  76.   */
  77.  
  78.   bset(0);  /* do not allow user to break during this portion */
  79.  
  80.   status = mkdir(dest);
  81.   if (status) {
  82.     cputs("can't; file exists already/disk write protected\n\015");
  83.     exit(1);
  84.   }
  85.  
  86.   status = ffmf(dest, A_DIR, &mydta2);
  87.   if (status) {
  88.     cputs("error on ffmf after mkdir\n\015");
  89.     error("mvdir", 0);
  90.   }
  91.  
  92.   num_sec = 0;  /* clear sector buffers */
  93.  
  94.   sector1 = findir(mydta1, &offset1, &d1, &secbuf1);
  95.   if (sector1 < 0) {
  96.     cputs("cannot find source directory\n\015");
  97.     error("mvdir", 0);
  98.   }
  99.  
  100.   sector2 = findir(mydta2, &offset2, &d2, &secbuf2);
  101.   if (sector2 < 0) {
  102.     cputs("cannot get info on destination directory\n\015");
  103.     error("mvdir", 0);
  104.   }
  105.  
  106.   if (d1 != d2) {  /* this should have been detected earlier */
  107.     cputs("source and destination has to be on the same drive\n\015");
  108.     exit(1);
  109.   }
  110.  
  111.   /* now switch the starting cluster of the two directories */
  112.   p1 =  (unsigned short *) (secbuf1 + offset1 + ALLOC);
  113.   p2 =  (unsigned short *) (secbuf2 + offset2 + ALLOC);
  114.   clus1 = *p1;
  115.   clus2 = *p2;
  116. #ifdef debug
  117.   printf("clus1=%4x  clus2=%4x\n", clus1, clus2);
  118. #endif
  119.   *p1 = clus2;
  120.   *p2 = clus1;
  121.  
  122.   status = flirt(d1-1, sector1);  /* mark sector dirty */
  123.   if (status) {
  124.     cputs("error in flirt\n\015");
  125.     error("mvdir", 0);
  126.   }
  127.  
  128.   status = flirt(d1-1, sector2);  /* mark sectors as dirty */
  129.   if (status) {
  130.     cputs("error in flirt\n\015");
  131.     error("mvdir", 0);
  132.   }
  133.  
  134.   /* now we must find the cluster# of the parent directory of the
  135.   ** destination directory (slot number two in clus2) so we can put
  136.   ** it in the source directory (which will become the new destination
  137.   ** directory.
  138.   */
  139.   ds1 = clus2sec(d1, clus1, &bps);  /* sector# of cluster 1 */
  140.   ds2 = clus2sec(d1, clus2, &bps);  /* sector# of cluster 2 */
  141.   secbuf3 = readsec(d1-1,ds2);
  142.   if (secbuf3 == (char *) 0) {
  143.     cputs("error in calling readsec\n\015");
  144.     error("mvdir", 0);
  145.   }
  146.  
  147.   parent = * (unsigned short *) (secbuf3 + 32 + ALLOC);
  148. #ifdef debug
  149.   printf("parent is %4x\n", parent );
  150. #endif
  151.  
  152.   /* now write this into source dir */
  153.  
  154.   secbuf3 = readsec(d1-1,ds1);
  155.   if (secbuf3 == (char *) 0) {
  156.     cputs("error in calling readsec\n\015");
  157.     error("mvdir", 0);
  158.   }
  159.  
  160.   *(unsigned short *) (secbuf3 + 32 + ALLOC) = parent;
  161.   status = flirt(d1-1,ds1);
  162.   if (status) {
  163.     cputs("error in flirt\n\015");
  164.     error("mvdir", 0);
  165.   }
  166.  
  167.   /* now write back all three (or less) modified sectors */
  168.   status = writesec(d1-1,ds1);  /* the cluster containing parent pointer */
  169.   if (status) {  /* what could cause this to happen? */
  170.     cputs("error in writing first modified sector\n\015");
  171.     error("mvdir", 1);
  172.   }
  173.  
  174.   status = writesec(d1-1,sector2);
  175.   if (status) {  /* it's impossible for this to happen */
  176.     cputs("error in writing second modified sector\n\015");
  177.     error("mvdir", 1);
  178.   }
  179.  
  180.   status = writesec(d1-1,sector1);
  181.   if (status) {  /* this is also impossible */
  182.     cputs("error in writing third modified sector\n\015");
  183.     error("mvdir", 1);
  184.   }
  185.  
  186.   bdos(0xd,0,0);  /* reset disk - neccessary for rmdir to work since DOS'
  187.                   ** buffer now contains invalid information (it didn't
  188.                   ** know that the disk was modified).
  189.                   */
  190.   status = rmdir(source);  /* this dir should be empty now */
  191.   if (status) {
  192.     putn(
  193. "Oops!\n\015",
  194. "cannot remove old directory \"", source, "\"\n\015",
  195. "Maybe one of your `subst' disk is using this directory. If this is\n\015",
  196. "the case, remove the subst disk and then remove this directory.\n\015", 0);
  197.     exit(1);
  198.   }
  199.  
  200.   bset(brk_st);  /* restore break status */
  201.   return 0;  /* no error */
  202. }
  203.  
  204. unsigned short findir(mydta, offsetp, drv, secbuf)
  205. char **secbuf;
  206. unsigned short *offsetp;
  207. unsigned int *drv;
  208. union dtbuf mydta;
  209. {
  210.   unsigned int status, i, j, offset, sector, cluster, tmp, bps;
  211.   union REGS inregs, outregs;
  212.   struct SREGS segregs;
  213.   char c, dir[13];  /* directory entry formatted like X.Y not "X       Y  " */
  214.  
  215.   if (mydta.dos.attr != A_DIR) {  /* guard against programmer's error */
  216.     putn(mydta.dos.fn, " is not a directory\n\015",0);
  217.     error("findir", 0);
  218.   }
  219.  
  220.   /* now find the cluster where the searched directory is */
  221.   cluster = mydta.dos.clusl + (mydta.dos.clush << 8);
  222.  
  223.   /* now convert the cluster number to sector number */
  224.   sector = clus2sec(mydta.dos.drv_no, cluster, &bps);
  225.  
  226.   /* calculate directory entry offset in the sector */
  227.   offset = ((mydta.dos.sloth << 8) + mydta.dos.slotl) * 32;
  228.  
  229.   sector += offset / bps;  /* normalize sector & offset */
  230.   offset %= bps;
  231.  
  232. #ifdef debug
  233.   printf("dir at sector %d\n", sector);
  234. #endif
  235.  
  236.   *secbuf = readsec(mydta.dos.drv_no - 1, sector);
  237.   if (*secbuf == (char *) 0) {
  238.     cputs("error in calling readsec\n\015");
  239.     error("findir", 0);
  240.   }
  241.  
  242. #ifdef debug
  243.   printf("First 11 bytes in sector: %11.11s\n", *secbuf+offset);
  244.   printf("Fn returned by ffmf: %11.11s\n", mydta.fn);
  245. #endif
  246.  
  247.   /* redundant check to see if we have the correct directory entry */
  248.   /* first format the directory entry name in this form "*.*" instead of
  249.   ** "???????????"
  250.   */
  251.   i=0;
  252.   c = (*secbuf)[offset];
  253.   while ((c != ' ') && (i < 8)) {  /* copy the first 8 characters */
  254.     dir[i] = c;
  255.     i++;
  256.     c = (*secbuf)[offset+i];
  257.   }
  258.  
  259.   j = 8;
  260.   c = (*secbuf)[offset+j];
  261.   if (c != ' ') {  /* sub-dir name has extension */
  262.     /* now add '.' and copy the extension */
  263.     dir[i] = '.';
  264.     i++;
  265.     while ((c != ' ') && (j < 11)) {
  266.       dir[i] = c;
  267.       i++;
  268.       j++;
  269.       c = (*secbuf)[offset + j];
  270.     }
  271.   }
  272.   dir[i] = '\0';  /* terminate string */
  273. #ifdef debug
  274.   printf("formatted directory entry string: %s\n", dir);
  275. #endif
  276.  
  277.   if (strcmp(mydta.dos.fn, dir) == 0) {
  278. #ifdef debug
  279.     printf("Directory entry found!\n");
  280. #endif
  281.   } else {
  282.     cputs("cannot find directory entry\n\015");
  283.     error("findir", 0);
  284.   }
  285.  
  286.   /* redundant check to make sure file size of directory is zero */
  287.   if (*(unsigned long *)(*secbuf+offset+28) != 0L) {
  288.     cputs("found directory with size > 0\n\015");
  289.     error("findir", 0);
  290.   }
  291.  
  292.   *offsetp = offset;
  293.   *drv = mydta.dos.drv_no;
  294.   return sector;
  295. }
  296.  
  297. unsigned short clus2sec(drv, clus_no, pbps)  /* convert cluster to sector */
  298. unsigned short clus_no, *pbps, drv;
  299. {
  300.   unsigned char status;
  301.   static unsigned short spc=0, ss, bps, tabseg, taboff;
  302.   unsigned short sector;
  303.  
  304.   if (spc == 0) {  /* first time function is called */
  305.     status = func32h(drv, &tabseg, &taboff);  /* See PC Tech Journal */
  306.     if (status == 0xff) {
  307.       cputs("func32h: invalid drive: "); putch(drv+'A'); cputs("\n\015");
  308.       error("clus2sec", 0);
  309.     }
  310.  
  311.     spc = peekb(tabseg,taboff+4)+1;  /* sector per cluster */
  312.     ss =  peekw(tabseg,taboff+11);  /* starting data sector */
  313.     bps = peekw(tabseg,taboff+2);  /* bytes per sector */
  314.  
  315. #ifdef debug
  316.     printf("drive #: %d\n", drv);
  317.     printf("sectors per cluster: %d\n", spc);
  318.     printf("# allocation units: %d\n",  peekw(tabseg,taboff+13)-1 );
  319.     printf("sector size: %d\n", bps);
  320.     printf("starting sector: %d\n", ss);
  321. #endif
  322.   }
  323.   *pbps = bps;  /* return this value */
  324.  
  325.   if (clus_no == 0) {
  326. #ifdef debug
  327.     printf("parent directory is root! - special case\n");
  328. #endif
  329.     sector = peekw(tabseg,taboff+16);  /* first sector of root directory */
  330.   } else {
  331.     sector = (clus_no - 2) * spc + ss;  /* see DOS Tech. Ref */
  332.   }
  333.  
  334.   return sector;
  335. }
  336.  
  337. /* apreb test to see if patha is equal to or is a predessesor of pathb
  338. ** This is used to test whether moving a directory would result
  339. ** in a directory loop condition and also whether the source
  340. ** directory is a predessor of the current path (can't delete
  341. ** source directory in this case, so don't move)
  342. **
  343. ** patha and pathb must be normalized paths
  344. ** E.g.
  345. **         apreb("A:\DEF", "A:\DEF")    is true
  346. **         apreb("A:\DEF", "A:\DEF\GHI")   is also true
  347. **         apreb("A:\DEF", "A:\DEFG")    is false
  348. */
  349. apreb(patha, pathb)
  350. char *patha, *pathb;
  351. {
  352.   int i, lena, lenb;
  353.   char c;
  354.  
  355.   lena = strlen(patha);
  356.   lenb = strlen(pathb);
  357.   if (lena > lenb) {  /* if patha is longer, it can't be a predessesor */
  358.     return 0;
  359.   }
  360.  
  361.   c = pathb[lena];  /* if patha is a predessesor, c should be '\\' or '\0' */
  362.   if ((c != '\\') && (c != '\0')) {
  363.     return 0;
  364.   }
  365.  
  366.   if (strncmp(patha, pathb, lena)) {  /* not equal */
  367.     return 0;
  368.   }
  369.  
  370.   return 1;
  371. }
  372.