// oldtest.cpp - TEST PROGRAM TO EXTRACT FILES FROM OLD FILE SYSTEM TAPES // // MODULE INDEX // NAME CONTENTS // LongToBigEnd Convert long to big endian // GetBlkNo Get block number // CreateFile Create file // main Main line // // MAINTENANCE HISTORY // DATE PROGRAMMER AND DETAILS // 09-11-02 JS Original // //----------------------------------------------------------------------------- #include // Standard input/output #include // String manipulation #include // Standard library #include // Error codes //----------------------------------------------------------------------------- // DEFINITIONS #define BLKSIZE 1024 // Tape block size #define FILENAMELEN 16 // File name length #define FSTDIRBLKNO 1 // First directory block number #define LSTDIRBLKNO 31 // Last directory block number #define DIRRECPERBLK (BLKSIZE/sizeof(DirRec)) // Directory records per block #define MAXDIRREC ((LSTDIRBLKNO - FSTDIRBLKNO + 1) * DIRRECPERBLK) // Maximum directory records #define BLKNOPERBLK (BLKSIZE/sizeof(BigEnd)) // Block numbers per block #define MAXDATABLK (1 + BLKNOPERBLK + BLKNOPERBLK*BLKNOPERBLK) // Maximum data blocks #define MAXPNTBLK (1 + BLKNOPERBLK) // Maximum pointer blocks #define FILESYSSIZE (256*1024) // File system size in blocks #define TOTDATABLK (FILESYSSIZE-LSTDIRBLKNO-1) // Total number of data blocks #define TAPENAME "TAPEFILESYS" // Tape device file name //----------------------------------------------------------------------------- // BIG ENDIAN NUMBER struct BigEnd { unsigned char bigEnd3; // Highest order byte unsigned char bigEnd2; unsigned char bigEnd1; unsigned char bigEnd0; // Lowest order byte }; //----------------------------------------------------------------------------- // DIRECTORY RECORD struct DirRec { char dirFileName[FILENAMELEN]; // File name BigEnd dirFileSize; // File size BigEnd dirFirstBlkNo; // First block number BigEnd dirPntBlkNo; // Pointer block number BigEnd dirPntPntBlkNo; // Pointer to pointer block numbers }; //----------------------------------------------------------------------------- // DIRECTORY BLOCK struct DirBlk { DirRec dirRecArr[DIRRECPERBLK]; // Directory record array }; //----------------------------------------------------------------------------- // POINTER BLOCK struct PntBlk { BigEnd pntBlkNoArr[BLKNOPERBLK]; // Block number array }; //----------------------------------------------------------------------------- // GLOBAL DATA DirRec dirRecArr[MAXDIRREC]; // Directory records unsigned long freeBlkNoArr[TOTDATABLK]; // Free block number array unsigned long freeBlkNoCnt; // Free block number count //----------------------------------------------------------------------------- // CONVERT LONG TO BIG ENDIAN BigEnd LongToBigEnd ( unsigned long l) // Long value { BigEnd bigEnd; // Big endian value bigEnd.bigEnd0 = (unsigned char) (l & 0xff); bigEnd.bigEnd1 = (unsigned char) ((l >> 8) & 0xff); bigEnd.bigEnd2 = (unsigned char) ((l >> 16) & 0xff); bigEnd.bigEnd3 = (unsigned char) ((l >> 24) & 0xff); return bigEnd; } //----------------------------------------------------------------------------- // GET BLOCK NUMBER unsigned long GetBlkNo () { if (freeBlkNoCnt == 0) { fprintf (stderr, "Error: no free blocks\n"); exit (1); } return freeBlkNoArr[--freeBlkNoCnt]; } //----------------------------------------------------------------------------- // CREATE FILE void CreateFile ( FILE *tapeFp, // Tape file pointer DirRec *dirRec, // Directory record char *fileName, // File name unsigned long fileSize) // File size { unsigned long dataBlkNoArr[MAXDATABLK]; // Data block numbers unsigned long dataBlkCnt; // Data block count size_t lastDataBlkLen; // Last data block length unsigned long pntBlkNoArr[MAXPNTBLK]; // Pointer block numbers unsigned long pntBlkCnt; // Pointer block count unsigned long pntPntBlkNo; // Pointer-pointer block number unsigned long pntPntBlkCnt; // Pointer-pointer block count unsigned long i, j; // General purpose indices unsigned char blkBuf[BLKSIZE]; // Block buffer size_t blkLen; // Block length FILE *refFp; // Reference file pointer char refName[FILENAMELEN+10]; // Reference file name unsigned long blkNo; // Block number PntBlk pntBlk; // Pointer block // Load the file parameters dataBlkCnt = (fileSize + BLKSIZE - 1) / BLKSIZE; lastDataBlkLen = (size_t) (fileSize % BLKSIZE); for (i = 0; i < dataBlkCnt; i++) dataBlkNoArr[i] = GetBlkNo(); pntBlkCnt = (dataBlkCnt - 1 + BLKNOPERBLK - 1) / BLKNOPERBLK; for (i = 0; i < pntBlkCnt; i++) pntBlkNoArr[i] = GetBlkNo(); pntPntBlkCnt = (pntBlkCnt - 1 + BLKNOPERBLK - 1) / BLKNOPERBLK; if (pntPntBlkCnt > 0) pntPntBlkNo = GetBlkNo(); // Create the reference file strcpy (refName, fileName); strcat (refName, ".ref"); if ((refFp = fopen (refName, "w")) == NULL) { fprintf (stderr, "Error: cannot create %s: %s\n", refName, strerror(errno)); exit (1); } // Write the data blocks for (i = 0; i < dataBlkCnt; i++) { blkLen = i != dataBlkCnt-1 ? BLKSIZE : lastDataBlkLen; for (j = 0; j < BLKSIZE; j++) blkBuf[j] = (unsigned char)(lrand48() % 256); if (fwrite (blkBuf, blkLen, 1, refFp) != 1) { fprintf (stderr, "Error: cannot write %s: %s\n", refName, strerror(errno)); exit (1); } blkNo = dataBlkNoArr[i]; if (fseek (tapeFp, blkNo*BLKSIZE, SEEK_SET) != 0) { fprintf (stderr, "Error: cannot seek %s %lu: %s\n", TAPENAME, blkNo*BLKSIZE, strerror(errno)); exit (1); } if (fwrite (blkBuf, BLKSIZE, 1, tapeFp) != 1) { fprintf (stderr, "Error: cannot write %s: %s\n", TAPENAME, strerror(errno)); exit (1); } } // Close the reference file fclose (refFp); // Write the pointer blocks for (i = 0; i < pntBlkCnt; i++) { memset (&pntBlk, 0, sizeof(pntBlk)); for ( j = 0; j < BLKNOPERBLK && 1+i*BLKNOPERBLK+j < dataBlkCnt; j ++ ) { pntBlk.pntBlkNoArr[j] = LongToBigEnd ( dataBlkNoArr[1+i*BLKNOPERBLK+j] ); } blkNo = pntBlkNoArr[i]; if (fseek (tapeFp, blkNo*BLKSIZE, SEEK_SET) != 0) { fprintf (stderr, "Error: cannot seek %s %lu: %s\n", TAPENAME, blkNo*BLKSIZE, strerror(errno)); exit (1); } if (fwrite (&pntBlk, BLKSIZE, 1, tapeFp) != 1) { fprintf (stderr, "Error: cannot write %s: %s\n", TAPENAME, strerror(errno)); exit (1); } } // Write the pointer-pointer block if (pntPntBlkCnt > 0) { memset (&pntBlk, 0, sizeof(pntBlk)); for (j = 0; j < pntBlkCnt-1; j ++) pntBlk.pntBlkNoArr[j] = LongToBigEnd(pntBlkNoArr[j+1]); blkNo = pntPntBlkNo; if (fseek (tapeFp, blkNo*BLKSIZE, SEEK_SET) != 0) { fprintf (stderr, "Error: cannot seek %s %lu: %s\n", TAPENAME, blkNo*BLKSIZE, strerror(errno)); exit (1); } if (fwrite (&pntBlk, BLKSIZE, 1, tapeFp) != 1) { fprintf (stderr, "Error: cannot write %s: %s\n", TAPENAME, strerror(errno)); exit (1); } } // Return the directory record memset (dirRec, 0, sizeof(*dirRec)); memcpy (dirRec->dirFileName, fileName, sizeof(dirRec->dirFileName)); dirRec->dirFileSize = LongToBigEnd (fileSize); if (fileSize > 0) dirRec->dirFirstBlkNo = LongToBigEnd (dataBlkNoArr[0]); if (pntBlkCnt > 0) dirRec->dirPntBlkNo = LongToBigEnd (pntBlkNoArr[0]); if (pntPntBlkCnt > 0) dirRec->dirPntPntBlkNo = LongToBigEnd (pntPntBlkNo); } //----------------------------------------------------------------------------- // MAIN LINE int main () { unsigned long i, j, k; // General purpose indices unsigned long blkNo; // Block number size_t fileNameLen; // File name length char fileName[FILENAMELEN+1]; // File name unsigned long fileSize; // File size FILE *tapeFp; // Tape file pointer DirBlk dirBlk; // Directory block char refName[FILENAMELEN+10]; // Reference file name char cmdBuf[256]; // Command buffer // Initialise and shuffle the free block number array freeBlkNoCnt = TOTDATABLK; for (i = 0; i < freeBlkNoCnt; i++) freeBlkNoArr[i] = i + LSTDIRBLKNO+1; for (i = 0; i < freeBlkNoCnt; i++) { j = lrand48() % freeBlkNoCnt; if (j != i) { blkNo = freeBlkNoArr[j]; freeBlkNoArr[j] = freeBlkNoArr[i]; freeBlkNoArr[i] = blkNo; } } // Create the tape file system file if ((tapeFp = fopen (TAPENAME, "w")) == NULL) { fprintf (stderr, "Error: cannot create %s: %s\n", TAPENAME, strerror(errno)); exit (1); } // Create the files memset (dirRecArr, 0, sizeof(dirRecArr)); for (i = 0; i < MAXDIRREC; i++) { // Only load one in forty directory entries if (lrand48() % 40 == 7) { // Generate a unique file name do { fileNameLen = (size_t) (9 + lrand48() % (FILENAMELEN-8)); strcpy (fileName, "TAPEFILE"); for (k = 8; k < fileNameLen; k++) fileName[k] = (char)('0'+lrand48()%10); fileName[fileNameLen] = '\0'; for ( j = 0; j < i && strncmp ( dirRecArr[j].dirFileName, fileName, FILENAMELEN ) != 0; j ++ ); } while (j < i); // Generate the file parameters fileSize = lrand48() % (1024*1024); // Create the file CreateFile (tapeFp, dirRecArr+i, fileName, fileSize); } } // Create the directory for (blkNo = FSTDIRBLKNO; blkNo <= LSTDIRBLKNO; blkNo++) { for (j = 0; j < DIRRECPERBLK; j++) { dirBlk.dirRecArr[j] = dirRecArr[ (blkNo-FSTDIRBLKNO) * DIRRECPERBLK + j ]; } if (fseek (tapeFp, blkNo*BLKSIZE, SEEK_SET) != 0) { fprintf (stderr, "Error: cannot seek %s %lu: %s\n", TAPENAME, blkNo*BLKSIZE, strerror(errno)); exit (1); } if (fwrite (&dirBlk, BLKSIZE, 1, tapeFp) != 1) { fprintf (stderr, "Error: cannot write %s: %s\n", TAPENAME, strerror(errno)); exit (1); } } // Close the tape file fclose (tapeFp); // Use the extraction program to extract each tape file // and check that the correct data is retrieved. for (i = 0; i < MAXDIRREC; i++) { if (dirRecArr[i].dirFileName[0] != '\0') { memcpy (fileName,dirRecArr[i].dirFileName,FILENAMELEN); fileName[FILENAMELEN] = '\0'; strcpy (refName, fileName); strcat (refName, ".ref"); sprintf (cmdBuf, "oldtape %s %s", TAPENAME, fileName); if (system (cmdBuf) != 0) { fprintf (stderr, "Error: '%s' failed\n", cmdBuf); exit (1); } sprintf (cmdBuf, "cmp %s %s", fileName, refName); if (system (cmdBuf) != 0) { fprintf (stderr, "Error: '%s' failed\n", cmdBuf); exit (1); } } } // Exit gracefully return 0; }