/* * adfDelFromCache * * delete one cache entry from its block. don't do 'records garbage collecting' */ RETCODE adfDelFromCache(struct Volume *vol, struct bEntryBlock *parent, SECTNUM headerKey) { struct bDirCacheBlock dirc; SECTNUM nSect, prevSect; struct CacheEntry caEntry; int offset, oldOffset, n; BOOL found; int entryLen; int i; RETCODE rc = RC_OK; prevSect = -1; nSect = parent->extension; found = FALSE; do { adfReadDirCBlock(vol, nSect, &dirc); offset = 0; n = 0; while(n < dirc.recordsNb && !found) { oldOffset = offset; adfGetCacheEntry(&dirc, &offset, &caEntry); found = (caEntry.header==headerKey); if (found) { entryLen = offset-oldOffset; if (dirc.recordsNb>1 || prevSect==-1) { if (n<dirc.recordsNb-1) { /* not the last of the block : switch the following records */ for(i=oldOffset; i<(488-entryLen); i++) dirc.records[i] = dirc.records[i+entryLen]; /* and clear the following bytes */ for(i=488-entryLen; i<488; i++) dirc.records[i] = 0; } else { /* the last record of this cache block */ for(i=oldOffset; i<offset; i++) dirc.records[i] = 0; } dirc.recordsNb--; if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK) return -1; } else { /* dirc.recordsNb ==1 or == 0 , prevSect!=-1 : * the only record in this dirc block and a previous dirc block exists */ adfSetBlockFree(vol, dirc.headerKey); adfReadDirCBlock(vol, prevSect, &dirc); dirc.nextDirC = 0L; adfWriteDirCBlock(vol, prevSect, &dirc); adfUpdateBitmap(vol); } } n++; } prevSect = nSect; nSect = dirc.nextDirC; }while(nSect!=0 && !found); if (!found) (*adfEnv.wFct)("adfUpdateCache : entry not found"); return rc; }
/* * adfRemoveEntry * */ RETCODE adfRemoveEntry(struct Volume *vol, SECTNUM pSect, char *name) { struct bEntryBlock parent, previous, entry; SECTNUM nSect2, nSect; int hashVal; BOOL intl; char buf[200]; if (adfReadEntryBlock( vol, pSect, &parent )!=RC_OK) return RC_ERROR; nSect = adfNameToEntryBlk(vol, parent.hashTable, name, &entry, &nSect2); if (nSect==-1) { sprintf(buf, "adfRemoveEntry : entry '%s' not found", name); (*adfEnv.wFct)(buf); return RC_ERROR; } /* if it is a directory, is it empty ? */ if ( entry.secType==ST_DIR && !isDirEmpty((struct bDirBlock*)&entry) ) { sprintf(buf, "adfRemoveEntry : directory '%s' not empty", name); (*adfEnv.wFct)(buf); return RC_ERROR; } /* printf("name=%s nSect2=%ld\n",name, nSect2);*/ /* in parent hashTable */ if (nSect2==0) { intl = isINTL(vol->dosType) || isDIRCACHE(vol->dosType); hashVal = adfGetHashValue( (unsigned char*)name, intl ); /*printf("hashTable=%d nexthash=%d\n",parent.hashTable[hashVal], entry.nextSameHash);*/ parent.hashTable[hashVal] = entry.nextSameHash; if (adfWriteEntryBlock(vol, pSect, &parent)!=RC_OK) return RC_ERROR; } /* in linked list */ else { if (adfReadEntryBlock(vol, nSect2, &previous)!=RC_OK) return RC_ERROR; previous.nextSameHash = entry.nextSameHash; if (adfWriteEntryBlock(vol, nSect2, &previous)!=RC_OK) return RC_ERROR; } if (entry.secType==ST_FILE) { adfFreeFileBlocks(vol, (struct bFileHeaderBlock*)&entry); if (adfEnv.useNotify) (*adfEnv.notifyFct)(pSect,ST_FILE); } else if (entry.secType==ST_DIR) { adfSetBlockFree(vol, nSect); /* free dir cache block : the directory must be empty, so there's only one cache block */ if (isDIRCACHE(vol->dosType)) adfSetBlockFree(vol, entry.extension); if (adfEnv.useNotify) (*adfEnv.notifyFct)(pSect,ST_DIR); } else { sprintf(buf, "adfRemoveEntry : secType %d not supported", entry.secType); (*adfEnv.wFct)(buf); return RC_ERROR; } if (isDIRCACHE(vol->dosType)) adfDelFromCache(vol, &parent, entry.headerKey); adfUpdateBitmap(vol); return RC_OK; }
/* * adfUpdateCache * */ RETCODE adfUpdateCache(struct Volume *vol, struct bEntryBlock *parent, struct bEntryBlock *entry, BOOL entryLenChg) { struct bDirCacheBlock dirc; SECTNUM nSect; struct CacheEntry caEntry, newEntry; int offset, oldOffset, n; BOOL found; int i, oLen, nLen; int sLen; /* shift length */ nLen = adfEntry2CacheEntry(entry, &newEntry); nSect = parent->extension; found = FALSE; do { /*printf("dirc=%ld\n",nSect);*/ if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK) return RC_ERROR; offset = 0; n = 0; /* search entry to update with its header_key */ while(n < dirc.recordsNb && !found) { oldOffset = offset; /* offset is updated */ adfGetCacheEntry(&dirc, &offset, &caEntry); oLen = offset-oldOffset; sLen = oLen-nLen; /*printf("olen=%d nlen=%d\n",oLen,nLen);*/ found = (caEntry.header==newEntry.header); if (found) { if (!entryLenChg || oLen==nLen) { /* same length : remplace the old values */ adfPutCacheEntry(&dirc, &oldOffset, &newEntry); /*if (entryLenChg) puts("oLen==nLen");*/ if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK) return RC_ERROR; } else if (oLen>nLen) { /*puts("oLen>nLen");*/ /* the new record is shorter, write it, * then shift down the following records */ adfPutCacheEntry(&dirc, &oldOffset, &newEntry); for(i=oldOffset+nLen; i<(488-sLen); i++) dirc.records[i] = dirc.records[i+sLen]; /* then clear the following bytes */ for(i=488-sLen; i<488; i++) dirc.records[i] = (char)0; if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK) return RC_ERROR; } else { /* the new record is larger */ /*puts("oLen<nLen");*/ adfDelFromCache(vol,parent,entry->headerKey); adfAddInCache(vol,parent,entry); /*puts("oLen<nLen end");*/ } } n++; } nSect = dirc.nextDirC; }while(nSect!=0 && !found); if (found) { if (adfUpdateBitmap(vol)!=RC_OK) return RC_ERROR; } else (*adfEnv.wFct)("adfUpdateCache : entry not found"); return RC_OK; }
/* * adfCreateVol * * */ struct Volume* adfCreateVol( struct Device* dev, int32_t start, int32_t len, char* volName, int volType,struct DateTime * voldate ) { struct bBootBlock boot; struct bRootBlock root; /* struct bDirCacheBlock dirc;*/ SECTNUM blkList[2]; struct Volume* vol; int nlen; if (adfEnv.useProgressBar) (*adfEnv.progressBar)(0); vol=(struct Volume*)calloc(1,sizeof(struct Volume)); if (!vol) { (*adfEnv.eFct)("adfCreateVol : malloc vol"); return NULL; } vol->dev = dev; vol->firstBlock = (dev->heads * dev->sectors)*start; vol->lastBlock = (vol->firstBlock + (dev->heads * dev->sectors)*len)-1; vol->rootBlock = (vol->lastBlock - vol->firstBlock+1)/2; /*printf("first=%ld last=%ld root=%ld\n",vol->firstBlock, vol->lastBlock, vol->rootBlock); */ vol->curDirPtr = vol->rootBlock; vol->readOnly = dev->readOnly; vol->mounted = TRUE; nlen = min( MAXNAMELEN, strlen(volName) ); vol->volName = (char*)calloc(1,nlen+1); if (!vol->volName) { (*adfEnv.eFct)("adfCreateVol : malloc"); free(vol); return NULL; } memcpy(vol->volName, volName, nlen); vol->volName[nlen]='\0'; if (adfEnv.useProgressBar) (*adfEnv.progressBar)(25); memset(&boot, 0, 1024); boot.dosType[3] = volType; /*printf("first=%d last=%d\n", vol->firstBlock, vol->lastBlock); printf("name=%s root=%d\n", vol->volName, vol->rootBlock); */ if (adfWriteBootBlock(vol, &boot)!=RC_OK) { free(vol->volName); free(vol); return NULL; } if (adfEnv.useProgressBar) (*adfEnv.progressBar)(20); if (adfCreateBitmap( vol )!=RC_OK) { free(vol->volName); free(vol); return NULL; } if (adfEnv.useProgressBar) (*adfEnv.progressBar)(40); /*for(i=0; i<127; i++) printf("%3d %x, ",i,vol->bitmapTable[0]->map[i]); */ if ( isDIRCACHE(volType) ) adfGetFreeBlocks( vol, 2, blkList ); else adfGetFreeBlocks( vol, 1, blkList ); /*printf("[0]=%d [1]=%d\n",blkList[0],blkList[1]);*/ memset(&root, 0, LOGICAL_BLOCK_SIZE); if (strlen(volName)>MAXNAMELEN) volName[MAXNAMELEN]='\0'; root.nameLen = (char)strlen(volName); memcpy(root.diskName,volName,root.nameLen); if(voldate) { adfTime2AmigaTime(*voldate,&(root.coDays),&(root.coMins),&(root.coTicks)); } else { adfTime2AmigaTime(adfGiveCurrentTime(),&(root.coDays),&(root.coMins),&(root.coTicks)); } /* dircache block */ if ( isDIRCACHE(volType) ) { root.extension = 0L; root.secType = ST_ROOT; /* needed by adfCreateEmptyCache() */ adfCreateEmptyCache(vol, (struct bEntryBlock*)&root, blkList[1]); } if (adfEnv.useProgressBar) (*adfEnv.progressBar)(60); if (adfWriteRootBlock(vol, blkList[0], &root)!=RC_OK) { free(vol->volName); free(vol); return NULL; } /* fills root->bmPages[] and writes filled bitmapExtBlocks */ if (adfWriteNewBitmap(vol)!=RC_OK) return NULL; if (adfEnv.useProgressBar) (*adfEnv.progressBar)(80); if (adfUpdateBitmap(vol)!=RC_OK) return NULL; if (adfEnv.useProgressBar) (*adfEnv.progressBar)(100); /*printf("free blocks %ld\n",adfCountFreeBlocks(vol));*/ /* will be managed by adfMount() later */ adfFreeBitmap(vol); vol->mounted = FALSE; return(vol); }