home *** CD-ROM | disk | FTP | other *** search
- /*
- 8-Sep-86 16:13:41-PDT,10586;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:11:55 PDT
- Received: by unix.macc.wisc.edu;
- id AA04974; 4.12/5; Mon, 8 Sep 86 17:31:56 cdt
- Date: Mon, 8 Sep 86 17:31:56 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082231.AA04974@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: mv.c
- */
-
- /* move subdirectories
- ** Written by Peter Wu; July 86.
- ** compile with cc mv /ze
- */
- #define LINT_ARGS
-
- #define ALLOC 26 /* starting cluster number in directory entry */
- #define PLEN 200 /* max path len */
-
- #include <dos.h>
- #include "dta.h"
- #include "peek.h"
- #include <conio.h>
-
- unsigned char func32h();
- unsigned short findir();
- unsigned short clus2sec();
- char *readsec();
- char lastc(char *);
-
- /* external var */
- extern int
- num_sec, /* number of sectors buffered */
- brk_st; /* orginal break status */
-
- /* source & dest must be normalized
- ** mydta1 contains dta of source
- */
- mvdir(mydta1,source,dest) /* move subdirectory */
- union dtbuf mydta1;
- char *source, *dest;
- {
- unsigned short sector1, sector2, offset1, offset2, clus1, clus2,
- d1, d2, status, *p1, *p2, ds1, ds2, bps, parent, drv;
- char *secbuf1, *secbuf2, *secbuf3, cpath[PLEN];
- union dtbuf mydta2;
-
- /* make sure source is not a root directory */
- if (lastc(source) == '\\') {
- cputs("move root directory? You're joking!\n\015");
- exit(1);
- }
-
- /* make sure source is not predesessor of destination */
- if (apreb(source, dest)) {
- /* this will create a directory loop if allowed to go on or
- ** it's a redundant rename to itself (e.g. mv \ha\. \)
- */
- cputs("not moved to avoid loop or redundancy\n\015");
- return -1;
- }
-
- /* see if source is a predesessor of current directory */
- drv = toupper(source[0]) - '@';
- current(drv,cpath);
- if ( apreb(source,cpath) ) {
- cputs("not moved to preserve current directory\n\015");
- return -2;
- }
-
- /* there should be a way to test if source is a predesessor of
- ** a 'subst' drive's current directory
- */
-
- bset(0); /* do not allow user to break during this portion */
-
- status = mkdir(dest);
- if (status) {
- cputs("can't; file exists already/disk write protected\n\015");
- exit(1);
- }
-
- status = ffmf(dest, A_DIR, &mydta2);
- if (status) {
- cputs("error on ffmf after mkdir\n\015");
- error("mvdir", 0);
- }
-
- num_sec = 0; /* clear sector buffers */
-
- sector1 = findir(mydta1, &offset1, &d1, &secbuf1);
- if (sector1 < 0) {
- cputs("cannot find source directory\n\015");
- error("mvdir", 0);
- }
-
- sector2 = findir(mydta2, &offset2, &d2, &secbuf2);
- if (sector2 < 0) {
- cputs("cannot get info on destination directory\n\015");
- error("mvdir", 0);
- }
-
- if (d1 != d2) { /* this should have been detected earlier */
- cputs("source and destination has to be on the same drive\n\015");
- exit(1);
- }
-
- /* now switch the starting cluster of the two directories */
- p1 = (unsigned short *) (secbuf1 + offset1 + ALLOC);
- p2 = (unsigned short *) (secbuf2 + offset2 + ALLOC);
- clus1 = *p1;
- clus2 = *p2;
- #ifdef debug
- printf("clus1=%4x clus2=%4x\n", clus1, clus2);
- #endif
- *p1 = clus2;
- *p2 = clus1;
-
- status = flirt(d1-1, sector1); /* mark sector dirty */
- if (status) {
- cputs("error in flirt\n\015");
- error("mvdir", 0);
- }
-
- status = flirt(d1-1, sector2); /* mark sectors as dirty */
- if (status) {
- cputs("error in flirt\n\015");
- error("mvdir", 0);
- }
-
- /* now we must find the cluster# of the parent directory of the
- ** destination directory (slot number two in clus2) so we can put
- ** it in the source directory (which will become the new destination
- ** directory.
- */
- ds1 = clus2sec(d1, clus1, &bps); /* sector# of cluster 1 */
- ds2 = clus2sec(d1, clus2, &bps); /* sector# of cluster 2 */
- secbuf3 = readsec(d1-1,ds2);
- if (secbuf3 == (char *) 0) {
- cputs("error in calling readsec\n\015");
- error("mvdir", 0);
- }
-
- parent = * (unsigned short *) (secbuf3 + 32 + ALLOC);
- #ifdef debug
- printf("parent is %4x\n", parent );
- #endif
-
- /* now write this into source dir */
-
- secbuf3 = readsec(d1-1,ds1);
- if (secbuf3 == (char *) 0) {
- cputs("error in calling readsec\n\015");
- error("mvdir", 0);
- }
-
- *(unsigned short *) (secbuf3 + 32 + ALLOC) = parent;
- status = flirt(d1-1,ds1);
- if (status) {
- cputs("error in flirt\n\015");
- error("mvdir", 0);
- }
-
- /* now write back all three (or less) modified sectors */
- status = writesec(d1-1,ds1); /* the cluster containing parent pointer */
- if (status) { /* what could cause this to happen? */
- cputs("error in writing first modified sector\n\015");
- error("mvdir", 1);
- }
-
- status = writesec(d1-1,sector2);
- if (status) { /* it's impossible for this to happen */
- cputs("error in writing second modified sector\n\015");
- error("mvdir", 1);
- }
-
- status = writesec(d1-1,sector1);
- if (status) { /* this is also impossible */
- cputs("error in writing third modified sector\n\015");
- error("mvdir", 1);
- }
-
- bdos(0xd,0,0); /* reset disk - neccessary for rmdir to work since DOS'
- ** buffer now contains invalid information (it didn't
- ** know that the disk was modified).
- */
- status = rmdir(source); /* this dir should be empty now */
- if (status) {
- putn(
- "Oops!\n\015",
- "cannot remove old directory \"", source, "\"\n\015",
- "Maybe one of your `subst' disk is using this directory. If this is\n\015",
- "the case, remove the subst disk and then remove this directory.\n\015", 0);
- exit(1);
- }
-
- bset(brk_st); /* restore break status */
- return 0; /* no error */
- }
-
- unsigned short findir(mydta, offsetp, drv, secbuf)
- char **secbuf;
- unsigned short *offsetp;
- unsigned int *drv;
- union dtbuf mydta;
- {
- unsigned int status, i, j, offset, sector, cluster, tmp, bps;
- union REGS inregs, outregs;
- struct SREGS segregs;
- char c, dir[13]; /* directory entry formatted like X.Y not "X Y " */
-
- if (mydta.dos.attr != A_DIR) { /* guard against programmer's error */
- putn(mydta.dos.fn, " is not a directory\n\015",0);
- error("findir", 0);
- }
-
- /* now find the cluster where the searched directory is */
- cluster = mydta.dos.clusl + (mydta.dos.clush << 8);
-
- /* now convert the cluster number to sector number */
- sector = clus2sec(mydta.dos.drv_no, cluster, &bps);
-
- /* calculate directory entry offset in the sector */
- offset = ((mydta.dos.sloth << 8) + mydta.dos.slotl) * 32;
-
- sector += offset / bps; /* normalize sector & offset */
- offset %= bps;
-
- #ifdef debug
- printf("dir at sector %d\n", sector);
- #endif
-
- *secbuf = readsec(mydta.dos.drv_no - 1, sector);
- if (*secbuf == (char *) 0) {
- cputs("error in calling readsec\n\015");
- error("findir", 0);
- }
-
- #ifdef debug
- printf("First 11 bytes in sector: %11.11s\n", *secbuf+offset);
- printf("Fn returned by ffmf: %11.11s\n", mydta.fn);
- #endif
-
- /* redundant check to see if we have the correct directory entry */
- /* first format the directory entry name in this form "*.*" instead of
- ** "???????????"
- */
- i=0;
- c = (*secbuf)[offset];
- while ((c != ' ') && (i < 8)) { /* copy the first 8 characters */
- dir[i] = c;
- i++;
- c = (*secbuf)[offset+i];
- }
-
- j = 8;
- c = (*secbuf)[offset+j];
- if (c != ' ') { /* sub-dir name has extension */
- /* now add '.' and copy the extension */
- dir[i] = '.';
- i++;
- while ((c != ' ') && (j < 11)) {
- dir[i] = c;
- i++;
- j++;
- c = (*secbuf)[offset + j];
- }
- }
- dir[i] = '\0'; /* terminate string */
- #ifdef debug
- printf("formatted directory entry string: %s\n", dir);
- #endif
-
- if (strcmp(mydta.dos.fn, dir) == 0) {
- #ifdef debug
- printf("Directory entry found!\n");
- #endif
- } else {
- cputs("cannot find directory entry\n\015");
- error("findir", 0);
- }
-
- /* redundant check to make sure file size of directory is zero */
- if (*(unsigned long *)(*secbuf+offset+28) != 0L) {
- cputs("found directory with size > 0\n\015");
- error("findir", 0);
- }
-
- *offsetp = offset;
- *drv = mydta.dos.drv_no;
- return sector;
- }
-
- unsigned short clus2sec(drv, clus_no, pbps) /* convert cluster to sector */
- unsigned short clus_no, *pbps, drv;
- {
- unsigned char status;
- static unsigned short spc=0, ss, bps, tabseg, taboff;
- unsigned short sector;
-
- if (spc == 0) { /* first time function is called */
- status = func32h(drv, &tabseg, &taboff); /* See PC Tech Journal */
- if (status == 0xff) {
- cputs("func32h: invalid drive: "); putch(drv+'A'); cputs("\n\015");
- error("clus2sec", 0);
- }
-
- spc = peekb(tabseg,taboff+4)+1; /* sector per cluster */
- ss = peekw(tabseg,taboff+11); /* starting data sector */
- bps = peekw(tabseg,taboff+2); /* bytes per sector */
-
- #ifdef debug
- printf("drive #: %d\n", drv);
- printf("sectors per cluster: %d\n", spc);
- printf("# allocation units: %d\n", peekw(tabseg,taboff+13)-1 );
- printf("sector size: %d\n", bps);
- printf("starting sector: %d\n", ss);
- #endif
- }
- *pbps = bps; /* return this value */
-
- if (clus_no == 0) {
- #ifdef debug
- printf("parent directory is root! - special case\n");
- #endif
- sector = peekw(tabseg,taboff+16); /* first sector of root directory */
- } else {
- sector = (clus_no - 2) * spc + ss; /* see DOS Tech. Ref */
- }
-
- return sector;
- }
-
- /* apreb test to see if patha is equal to or is a predessesor of pathb
- ** This is used to test whether moving a directory would result
- ** in a directory loop condition and also whether the source
- ** directory is a predessor of the current path (can't delete
- ** source directory in this case, so don't move)
- **
- ** patha and pathb must be normalized paths
- ** E.g.
- ** apreb("A:\DEF", "A:\DEF") is true
- ** apreb("A:\DEF", "A:\DEF\GHI") is also true
- ** apreb("A:\DEF", "A:\DEFG") is false
- */
- apreb(patha, pathb)
- char *patha, *pathb;
- {
- int i, lena, lenb;
- char c;
-
- lena = strlen(patha);
- lenb = strlen(pathb);
- if (lena > lenb) { /* if patha is longer, it can't be a predessesor */
- return 0;
- }
-
- c = pathb[lena]; /* if patha is a predessesor, c should be '\\' or '\0' */
- if ((c != '\\') && (c != '\0')) {
- return 0;
- }
-
- if (strncmp(patha, pathb, lena)) { /* not equal */
- return 0;
- }
-
- return 1;
- }