📄 wrudf-cmnd.c
字号:
/* wrudf-cmnd.c * * PURPOSE * High level wrudf command functions * * CONTACTS * E-mail regarding this program to * e.fennema@dataweb.nl * * COPYRIGHT * This file is distributed under the terms of the GNU General Public * License (GPL). Copies of the GPL can be obtained from: * ftp://prep.ai.mit.edu/pub/gnu/GPL * * (C) 2001 Enno Fennema * * HISTORY * 16 Aug 01 ef Created. */#include <stddef.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <string.h>#include <unistd.h>#include <dirent.h>#include <sys/stat.h>#include "wrudf.h"int deleteDirectory(Directory *dir, struct fileIdentDesc *fid);Directory *makeDir(Directory *dir, char* name);int questionOverwrite(Directory *dir, struct fileIdentDesc *fid, char* name);int directoryIsEmpty(Directory *dir);char *hdWorkingDir;/* copyFile() * Write File Entry immediately followed by data * A verify error on CDR causes a further packet with * the new FE followed by copies of the defective blocks only */intcopyFile(Directory *dir, char* inName, char*newName, struct stat *fileStat) { int fd, i, blkno; uint32_t nBytes, blkInPkt; uint32_t maxVarPktSize; // in bytes struct fileIdentDesc *fid; struct fileEntry *fe; uint8_t p[2048]; fd = open(inName, O_RDONLY); if( fd == 0 ) { printf("'%s' does not exist\n", cmndv[i]); return CMND_FAILED; } printf("Copy file %s\n", inName); fid = findFileIdentDesc(dir, newName); if( fid && questionOverwrite(dir, fid, newName) ) return CMND_OK; fid = makeFileIdentDesc(newName); // could reuse FID if overwrite allowed fe = makeFileEntry(); fe->uid = fileStat->st_uid; fe->gid = fileStat->st_gid; if( fileStat->st_mode & S_IRUSR ) fe->permissions |= FE_PERM_U_READ; if( fileStat->st_mode & S_IWUSR ) fe->permissions |= FE_PERM_U_WRITE | FE_PERM_U_DELETE | FE_PERM_U_CHATTR;; if( fileStat->st_mode & S_IXUSR ) fe->permissions |= FE_PERM_U_EXEC; if( fileStat->st_mode & S_IRGRP ) fe->permissions |= FE_PERM_G_READ; if( fileStat->st_mode & S_IWGRP ) fe->permissions |= FE_PERM_G_WRITE | FE_PERM_G_DELETE | FE_PERM_G_CHATTR; if( fileStat->st_mode & S_IXGRP ) fe->permissions |= FE_PERM_G_EXEC; if( fileStat->st_mode & S_IROTH ) fe->permissions |= FE_PERM_O_READ; if( fileStat->st_mode & S_IWOTH ) fe->permissions |= FE_PERM_O_WRITE | FE_PERM_O_DELETE | FE_PERM_O_CHATTR;; if( fileStat->st_mode & S_IXOTH ) fe->permissions |= FE_PERM_O_EXEC; if( fileStat->st_mode & S_ISUID ) fe->icbTag.flags |= ICBTAG_FLAG_SETUID; if( fileStat->st_mode & S_ISGID ) fe->icbTag.flags |= ICBTAG_FLAG_SETGID; fe->informationLength = fileStat->st_size; updateTimestamp(fileStat->st_atime, 0); fe->accessTime = timeStamp; updateTimestamp(fileStat->st_mtime, 0); fe->modificationTime = timeStamp; updateTimestamp(fileStat->st_ctime, 0); fe->attrTime = timeStamp; /* check whether embedding of data is possible */ fe->logicalBlocksRecorded = ((fileStat->st_size + 2047) & ~2047) >> 11; if( medium == CDR ) { /* File data written in physical space but fileEntry in virtual space * so must use long allocation descriptors * * Variable packet length restricted by drive buffer size. * Must break up long file over several var packets. * Only 116 long_ad's fit in fileEntry without going to extended alloc descs */ long_ad *ad; uint32_t loc; maxVarPktSize = getMaxVarPktSize(); if( fe->informationLength / maxVarPktSize > 116 ) { printf("Cannot handle files longer than %d\n", 116 * maxVarPktSize); return CMND_FAILED; } fe->icbTag.flags |= ICBTAG_FLAG_AD_LONG; /* +1 as the fileEntry itself occupies block NWA */ loc = getNWA() + 1 - pd->partitionStartingLocation; nBytes = (uint32_t) fe->informationLength ; for( ad = (long_ad*)(fe->allocDescs + fe->lengthExtendedAttr); nBytes > 0; ad++ ) { if( nBytes > maxVarPktSize ) { ad->extLength = maxVarPktSize; nBytes -= maxVarPktSize; } else { ad->extLength = nBytes; nBytes = 0; } ad->extLocation.logicalBlockNum = loc; ad->extLocation.partitionReferenceNum = pd->partitionNumber; *(uint32_t*)&((struct allocDescImpUse*)(ad->impUse))->impUse = (uint32_t) fe->uniqueID; loc += ((ad->extLength + 2047) >> 11) + 7; } if( ((ad-1)->extLength & 2047) == 0 ) { memset(ad, 0, sizeof(long_ad)); *(uint32_t*)&((struct allocDescImpUse*)(ad->impUse))->impUse = (uint32_t) fe->uniqueID; ad++; } fe->lengthAllocDescs = (uint8_t*)ad - (fe->allocDescs + fe->lengthExtendedAttr); fe->descTag.descCRCLength = sizeof(struct fileEntry) + fe->lengthExtendedAttr + fe->lengthAllocDescs - sizeof(tag); fe->descTag.tagLocation = newVATentry(); for( ;; ) { /* retry loop for verify failure */ int blknoFE, skipped, retries; long_ad *extent; setChecksum(fe); skipped = 0; retries = 0; lseek(fd, 0, SEEK_SET); /* write FE */ blknoFE = vat[fe->descTag.tagLocation] = writeCDR(fe) - pd->partitionStartingLocation; fid->icb.extLocation.logicalBlockNum = fe->descTag.tagLocation; fid->icb.extLocation.partitionReferenceNum = virtualPartitionNum; /* write file data */ extent = (long_ad*)(fe->allocDescs + fe->lengthExtendedAttr); for( blkInPkt = nBytes = 0; nBytes < fe->informationLength; extent++ ) { blkno = extent->extLocation.logicalBlockNum; if( blkno < blknoFE ) { nBytes += extent->extLength; skipped = 1; continue; } for( i = 0; i < extent->extLength; blkno++, i += 2048 ) { memset(p, 0, 2048); if( skipped ) { lseek(fd, nBytes, SEEK_SET); skipped = 0; } nBytes += read(fd, p, 2048); writeCDR(p); if( ++blkInPkt == (maxVarPktSize >> 11) ) { syncCDR(); blkInPkt = 0; } } } syncCDR(); if( verifyCDR(fe) == 0 ) // verify the file data break; if( retries++ > 3 ) { printf("Retry count 3 exceeded\n"); break; } } } else { short_ad *extent, extentFE[2]; if( getExtents(2048, extentFE ) != 16 ) { /* extent for File Entry */ printf("No space for File Entry\n"); return CMND_FAILED; } fe->descTag.tagLocation = extentFE[0].extPosition; // must mark allocated; otherwise allocated for a second time before being written markBlock(ALLOC, fe->descTag.tagLocation); fe->lengthAllocDescs = /* extents for the file data */ getExtents(fe->informationLength, (short_ad*)(fe->allocDescs + fe->lengthExtendedAttr)); if( !fe->lengthAllocDescs ) { printf("No space for file\n"); return CMND_FAILED; } /* write FE */ fe->descTag.descCRCLength = sizeof(struct fileEntry) + fe->lengthExtendedAttr + fe->lengthAllocDescs - sizeof(tag); setChecksum(fe); writeBlock(fe->descTag.tagLocation, pd->partitionNumber, fe); fid->icb.extLocation.logicalBlockNum = fe->descTag.tagLocation; fid->icb.extLocation.partitionReferenceNum = pd->partitionNumber; /* write file data */ extent = (short_ad*)(fe->allocDescs + fe->lengthExtendedAttr); for( nBytes = 0; nBytes < fe->informationLength; extent++ ) { blkno = extent->extPosition; for( i = 0; i < extent->extLength; blkno++, i += 2048 ) { memset(p, 0, 2048); nBytes += read(fd, p, 2048); writeBlock(blkno, pd->partitionNumber, p); } } } if( devicetype == DISK_IMAGE && medium == CDR ) writeHDlink(); *(uint32_t*)(&( (struct allocDescImpUse*)fid->icb.impUse)->impUse) = (uint32_t) fe->uniqueID; insertFileIdentDesc(dir, fid); ((struct logicalVolIntegrityDescImpUse*) (lvid->impUse + 2 * sizeof(uint32_t) * lvid->numOfPartitions))->numFiles++; close(fd); free(fe); free(fid); return CMND_OK;}intcopyDirectory(Directory *dir, char* name) { DIR *srcDir; Directory *workDir; struct dirent *dirEnt; struct stat dirEntStat; struct fileIdentDesc *fid; if( !(srcDir = opendir(name)) ) { printf("Open dir '%s': %m\n", name); return CMND_FAILED; } chdir(name); printf("Now in %s\n", getcwd(NULL, 0)); workDir = dir; while( (dirEnt = readdir(srcDir)) ) { if( !strcmp(dirEnt->d_name, ".") || !strcmp(dirEnt->d_name, "..") ) continue; lstat(dirEnt->d_name, &dirEntStat); // do not follow links if( S_ISDIR(dirEntStat.st_mode) ) { if( !(options & OPT_RECURSIVE) ) { printf("Not recursive. Ignoring '%s' directory\n", dirEnt->d_name); continue; } fid = findFileIdentDesc(dir, dirEnt->d_name); if( fid && !(fid->fileCharacteristics & FID_FILE_CHAR_DIRECTORY ) ) { printf("'%s' exists but is not a directory\n", dirEnt->d_name); continue; } if( fid && (fid->fileCharacteristics & FID_FILE_CHAR_DELETED) ) { removeFID(dir, fid); fid = NULL; } if( !fid ) workDir = makeDir(dir, dirEnt->d_name); else workDir = readDirectory(dir, &fid->icb, dirEnt->d_name); copyDirectory(workDir, dirEnt->d_name); } else { if( S_ISREG(dirEntStat.st_mode) ) copyFile(workDir, dirEnt->d_name, dirEnt->d_name, &dirEntStat); } } chdir(".."); closedir(srcDir); return CMND_OK;}/* deleteDirectory() * * Recursing into subdirectories. * If anywhere no permission, query deletion but proceed if 'yes' * Returns 0 if fid freed, 1 if fid not empty */int deleteDirectory(Directory *dir, struct fileIdentDesc* fid) { int i, rv, notEmpty; char *name; struct fileIdentDesc *childFid; Directory *childDir; rv = 0; if( fid->fileCharacteristics & FID_FILE_CHAR_DELETED ) return CMND_OK; if( (fid->fileCharacteristics & FID_FILE_CHAR_DIRECTORY) == 0 ) return deleteFID(dir, fid); /* delete regular files */ name = malloc(fid->lengthFileIdent + 1); strncpy(name, fid->fileIdent + fid->lengthOfImpUse, fid->lengthFileIdent); readDirectory(dir, &fid->icb, name); childDir = dir->child; /* check permission */ notEmpty = 0; for( i = 0; i < childDir->fe.informationLength; i += ((sizeof(struct fileIdentDesc) + childFid->lengthOfImpUse + childFid->lengthFileIdent + 3) & ~3) ) { childFid = (struct fileIdentDesc*)(childDir->data + i); if( childFid->fileCharacteristics & (FID_FILE_CHAR_DELETED | FID_FILE_CHAR_PARENT) ) continue; if( childFid->fileCharacteristics & FID_FILE_CHAR_DIRECTORY ) deleteDirectory( childDir, childFid); else deleteFID(childDir, childFid); } if( directoryIsEmpty(childDir) ) { rv |= deleteFID(dir, fid); } else { childDir->dirDirty = 1; updateDirectory(childDir); rv = notEmpty; } free(name); return rv;}/* readDirectory() * All fileIdentDesc's are put into the data area of the Directory structure.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -