#include #include #include #include #include #include #include #include #include "dosstruc.h" /*--- Function Prototypes ---*/ int SearchFirst(struct ExtFcb * Fcb); int AbortProgram(void); int isdevice(int handle); void ReadRoot(void); void ReadSub(void); void WriteRoot(void); void WriteSub(void); long Alu2Sec(struct DpbStruct * Dpb, unsigned Alu); char *strrspn(char *s1, char *s2); void PutQueue(struct ClusterQueue * Q, unsigned Cluster); unsigned NextCl(int Is12Bit, unsigned Cluster); void FreeCluster(int Is12Bit, unsigned Val, unsigned Cluster); /*--- End of Prototypes ---*/ /* * SORTDIR is the main routine of CSAP. It is a recursive routine that will * walk the directory hierarchy, sorting all directories that it finds. It * uses the quick sort or quicker sort algorithm provided by most C runtime * libraries to perform the actual sort. It uses DOS Int 25H and 26H, * Absolute Disk Read and Absolute Disk Write, to read the directories into * memory for sorting and to write out the sorted directories. It depends * upon information about the physical characteristics of the disk provided * by GETDPB. */ extern struct absr32m a32; extern char a32sw; extern char ZeroSwt; extern int ZCount; void SortDir (void) { extern char Disk, Parent[67], Element[13]; extern char Line[80], Level, RSwt, VerSwt, Packed, TruncateSwt; extern int Lim, j, l; extern int OutSectors, OutClusters, BytesPerCluster, ECount; extern int TruncSectors, TruncClusters; extern int *CluArray; extern unsigned NumSec; extern unsigned DirStart; extern long MinMem; extern struct DpbStruct Dpb; extern struct DirEntry *DirBuff; extern struct ClusterEntry *p, *t; extern struct ExtFcb Fcb; extern struct ExtendedEntry Dir; extern struct ClusterQueue CluQ; char *strrspn(); char **DirVector, *r; int strincmp(); int i, k, DirCount, Root; long Mem; BytesPerCluster = (Dpb.ClusterSize + 1) * Dpb.SectorSize; if (strlen(Element) != 0) { /* Sorting a sub-directory */ Root = 0; bdosptr(0x3B, Parent, 0); /* Set Current Directory */ if ((Parent[strlen(Parent) - 1] != '\\') && (Parent[strlen(Parent) - 1] != '/')) strcat(Parent, "\\"); setdta((char *) &Dir); parsfnm(Element, (struct fcb *) & Fcb.DriveId, 0); Fcb.FcbHdr.Header = 0xFF; Fcb.DriveId = Disk - '@'; Fcb.FcbHdr.Attrib = 0xFF; if (SearchFirst(&Fcb) != 0) { fprintf(stderr, "Not found: %s%s\n", Parent, Element); AbortProgram(); } } else Root = 1; /* Sorting the Root directory */ printf("Sorting: %s%s", Parent, Element); if (!isdevice(1)) fprintf(stderr, "Sorting: %s%s", Parent, Element); /* Read directory to be sorted into memory */ if (Root) ReadRoot(); else ReadSub(); /* Count sub-directories, skipping "current" and "parent" entries */ for (DirCount = 0, i = 0; i < Lim / sizeof(struct DirEntry); i++) { if (DirBuff[i].Name[0] == 0) break; if ((DirBuff[i].Attribute & 0x10) && (DirBuff[i].Name[0] != '.') && (DirBuff[i].Name[0] != 0xE5)) DirCount++; } if (ZeroSwt) k = Lim / sizeof(struct DirEntry)-1; else k = i; if (DirCount != 0) { if ((DirVector = malloc(DirCount * sizeof(DirVector))) == NULL) { fprintf(stderr, "Insufficient memory (2).\n"); return; } } j = 0; if (Root) { /* * If sorting Root - skip 1st two files if "System" & * "Hidden" */ if (i > 1) { if (DirBuff[j].Attribute & 0x06) { j++; i--; if (DirBuff[j].Attribute & 0x06) { j++; i--; } } } } else { /* * If sorting subdirectory - skip 1st two entries, "current" * and "parent" */ j += 2; i -= 2; } if (i == 0) { printf(" Empty.\n"); r = &Parent[strlen(Parent) - 1]; if (r[-1] == ':') r++; *r = 0x00; if (TruncateSwt) { OutClusters = 1; WriteSub(); } return; } /* If VerSwt ON - request operator confirmation BEFORE sorting */ if (VerSwt != 0) { if (isdevice(1)) { printf(" Sort (Y or N)? "); fflush(stdout); } else { fprintf(stderr, " Sort (Y or N)? "); fflush(stderr); } if (toupper(getche()) != 'Y') { if (!isdevice(1)) fprintf(stderr, "n"); printf("\n"); return; } } if (!isdevice(1)) fprintf(stderr, "\n"); printf("\n"); /* Sort directory */ qsort(&DirBuff[j], i, sizeof(struct DirEntry), strincmp); ECount = 0; ZCount = 0; /* * If Packed OFF, remove "erased" entries from directory (mark them * "unused") */ if (Packed) { for (i = k; i >= 0; i--) { if ((DirBuff[i].Name[0] != 0xE5) && (DirBuff[i].Name[0] != 0x00)) break; if (DirBuff[i].Name[0] == 0xE5) { memset(DirBuff[i].Name, '\0', sizeof(DirBuff[i])); ++ECount; } } i = k; } /* * If Zero ON, zero all "unused" entries from directory */ if (ZeroSwt) { for (i = k; i >= 0; i--) { if (DirBuff[i].Name[0] != 0x00) break; if (memcmp(DirBuff[i].Name,DirBuff[i].Name+1,sizeof(DirBuff[i])-1)) { memset(DirBuff[i].Name, '\0', sizeof(DirBuff[i])); ++ZCount; } } i = k; } if (TruncateSwt) { for (i = k; i > 0; --i) { if (DirBuff[i-1].Name[0] != 0x00) break; } } /* * Compute the number of directory sectors to write out - don't write * sectors that don't contain active entries unless ZeroSwt ON */ if (ZeroSwt) OutSectors = ((k * 32) + Dpb.SectorSize - 1) / Dpb.SectorSize; else OutSectors = ((i * 32) + Dpb.SectorSize - 1) / Dpb.SectorSize; OutClusters = (OutSectors + Dpb.ClusterSize) >> Dpb.ClusterShift; /* * Compute the number of directory sectors/clusters after which may be * truncated. May be different if ZeroSwt ON */ TruncSectors = ((i * 32) + Dpb.SectorSize - 1) / Dpb.SectorSize; TruncClusters = (TruncSectors + Dpb.ClusterSize) >> Dpb.ClusterShift; /* * Build list of subdirectories - skipping "current" and "parent" * entries */ for (l = 0, i = 0; DirBuff[i].Name[0]; i++) { if ((DirBuff[i].Attribute & 0x10) && (DirBuff[i].Name[0] != '.')) { for (k = 0, j = 0; j < 8; ++j) { if (DirBuff[i].Name[j] == ' ') break; else Line[k++] = DirBuff[i].Name[j]; } if (DirBuff[i].Ext[0] != ' ') { Line[k++] = '.'; for (j = 0; j < 3; ++j) { if (DirBuff[i].Ext[j] == ' ') break; else Line[k++] = DirBuff[i].Ext[j]; } } Line[k++] = '\0'; if ((DirVector[l] = malloc(k)) == NULL) { fprintf(stderr, "Insufficient memory.\n"); return; } strcpy(DirVector[l++], Line); } } /* Write out sorted directory */ if (Root) { WriteRoot(); if (RSwt) printf(" Location: %04XH-%04XH\n", DirStart, DirStart + NumSec - 1); } else { WriteSub(); if (RSwt) { printf(" Location:"); for (i = 0; i < CluQ.Count; ++i) { if (i == 0) printf(" %04XH", Alu2Sec(&Dpb, CluArray[i])); if ((i > 0) && (CluArray[i] != CluArray[i - 1] + 1)) { printf("-%04XH %04XH", Alu2Sec(&Dpb, CluArray[i - 1] + 1) - 1, Alu2Sec(&Dpb, CluArray[i]) ); } } printf("-%04XH\n", Alu2Sec(&Dpb, CluArray[i - 1] + 1) - 1); } } if (RSwt) { printf(" %d Erased entries removed\n", ECount); printf(" %d Unused entries Zeroed\n", ZCount); } Mem = coreleft(); if (MinMem < Mem) MinMem = Mem; /* Release dynamically acquired space for this directory */ free(DirBuff); for (p = CluQ.Head; p != NULL; p = t) { t = p->Next; free(p); } free(CluArray); /* * If Recursive sort - build Parent and Element for sub directories & * sort */ if (!Level) { strcat(Parent, Element); for (i = 0; i < DirCount; i++) { strcpy(Element, DirVector[i]); SortDir(); } r = strrspn(Parent, "\\/"); if (r[-1] == ':') r++; *r = 0x00; } } void ReadSub (void) { extern unsigned Cluster; extern unsigned LastCluster; extern struct ExtendedEntry Dir; extern struct ClusterQueue CluQ; extern int Is12Bit, *CluArray, BytesPerCluster, Lim; extern char Disk; extern struct DirEntry *DirBuff; extern struct DpbStruct Dpb; int i; struct ClusterEntry *p; void PutQueue(); unsigned NextCl(); Cluster = Dir.Body.FirstCluster; CluQ.Head = CluQ.Current = NULL; CluQ.Count = 0; while (Cluster < LastCluster) { PutQueue(&CluQ, Cluster); Cluster = NextCl(Is12Bit, Cluster); } if ((CluArray = malloc(CluQ.Count * sizeof(int))) == NULL) { fprintf(stderr, "Insufficient memory (3).\n"); return; } for (i = 0, p = CluQ.Head; p != NULL; i++, p = p->Next) { CluArray[i] = p->Cluster; } Lim = CluQ.Count * BytesPerCluster; if ((DirBuff = malloc(Lim)) == NULL) { fprintf(stderr, "Insufficient memory for directory buffer.\n"); return; } for (i = 0; i < CluQ.Count; i++) { if (a32sw | absread(Disk - 'A', Dpb.ClusterSize + 1, Alu2Sec(&Dpb, CluArray[i]), (char *) &DirBuff[(i * BytesPerCluster) / 32])) { #if 1 a32.nsect = Dpb.ClusterSize + 1; a32.sector = Alu2Sec(&Dpb,CluArray[i]); a32.xferad = (unsigned char *) &DirBuff[(i * BytesPerCluster) / 32]; a32sw=1; if (absread(Disk - 'A', -1, 0, &a32) != 0) { /* EWS */ #endif fprintf(stderr, "Error reading directory.\n"); exit(1); } #if 1 } #endif } } void WriteSub (void) { extern char TruncateSwt; extern char FatDirty; extern struct ClusterQueue CluQ; extern char Disk; extern struct DpbStruct Dpb; extern int Is12Bit, *CluArray, BytesPerCluster; extern int OutClusters; extern int TruncClusters; extern struct DirEntry *DirBuff; int i; for (i = 0; i < OutClusters; i++) { if (a32sw | abswrite(Disk - 'A', Dpb.ClusterSize + 1, Alu2Sec(&Dpb, CluArray[i]), (char *) &DirBuff[(i * BytesPerCluster) / 32])) { #if 1 a32.nsect = Dpb.ClusterSize + 1; a32.sector = Alu2Sec(&Dpb,CluArray[i]); a32.xferad = (unsigned char *) &DirBuff[(i * BytesPerCluster) / 32]; a32sw=1; if (abswrite(Disk - 'A', -1, 0, &a32) != 0) { /* EWS */ #endif fprintf(stderr, "Error writing directory.\n"); exit(1); } #if 1 } #endif } if ((TruncateSwt) && ((i=TruncClusters) < CluQ.Count)) { FatDirty |= 1; FreeCluster(Is12Bit, 0xFFFF, CluArray[i - 1]); for (; i < CluQ.Count; ++i) FreeCluster(Is12Bit, 0, CluArray[i]); } } void ReadRoot (void) { extern struct DpbStruct Dpb; extern unsigned NumSec; extern unsigned DirStart; extern struct DirEntry *DirBuff; extern int *CluArray, Lim; extern char Disk; int Error; Lim = Dpb.MaxEntries * 32; NumSec = (Lim + Dpb.SectorSize - 1) / Dpb.SectorSize; if ((DirBuff = malloc(Lim)) == NULL) { fprintf(stderr, "Insufficient memory for cluster buffer.\n"); return; } if ((CluArray = malloc(sizeof(int))) == NULL) { fprintf(stderr, "Insufficient memory (4).\n"); return; } CluArray[0] = 0; if (a32sw | (Error = absread(Disk - 'A', NumSec, DirStart, (char *) DirBuff))) { #if 1 a32.nsect = NumSec; a32.sector = DirStart; a32.xferad = (unsigned char *) DirBuff; a32sw=1; if ((Error = absread(Disk - 'A', -1, 0, &a32)) != 0) { /* EWS */ #endif fprintf(stderr, "Error reading root: %04X.\n", Error); exit(1); } #if 1 } #endif } void WriteRoot (void) { extern char Disk; extern unsigned NumSec; extern unsigned DirStart; extern struct DpbStruct Dpb; extern struct DirEntry *DirBuff; if (a32sw | abswrite(Disk - 'A', NumSec, DirStart, (char *) DirBuff)) { #if 1 a32.nsect = NumSec; a32.sector = DirStart; a32.xferad = (unsigned char *) DirBuff; a32sw=1; if (abswrite(Disk - 'A', -1, 0, &a32) != 0) { /* EWS */ #endif fprintf(stderr, "Error writing Root.\n"); exit(1); } #if 1 } #endif }