- if (inScan != 0) {
- /* If we're scanning then we need to test for duplicates
- * NB This does not need to be efficient since it should only ever
- * happen when the power fails during a write, then only one
- * chunk should ever be affected.
- *
- * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
- * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
- */
-
- if (existingChunk > 0) {
- /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
- * thus we have to do a FindChunkInFile to get the real chunk id.
- *
- * We have a duplicate now we need to decide which one to use:
- *
- * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
- * Forward scanning YAFFS2: The new one is what we use, dump the old one.
- * YAFFS1: Get both sets of tags and compare serial numbers.
- */
-
- if (inScan > 0) {
- /* Only do this for forward scanning */
- yaffs_ReadChunkWithTagsFromNAND(dev,
- chunkInNAND,
- NULL, &newTags);
-
- /* Do a proper find */
- existingChunk =
- yaffs_FindChunkInFile(in, chunkInInode,
- &existingTags);
- }
-
- if (existingChunk <= 0) {
- /*Hoosterman - how did this happen? */
-
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy: existing chunk < 0 in scan"
- TENDSTR)));
-
- }
-
- /* NB The deleted flags should be false, otherwise the chunks will
- * not be loaded during a scan
- */
-
- if(inScan > 0) {
- newSerial = newTags.serialNumber;
- existingSerial = existingTags.serialNumber;
- }
-
- if ((inScan > 0) &&
- (in->myDev->isYaffs2 ||
- existingChunk <= 0 ||
- ((existingSerial + 1) & 3) == newSerial)) {
- /* Forward scanning.
- * Use new
- * Delete the old one and drop through to update the tnode
- */
- yaffs_DeleteChunk(dev, existingChunk, 1,
- __LINE__);
- } else {
- /* Backward scanning or we want to use the existing one
- * Use existing.
- * Delete the new one and return early so that the tnode isn't changed
- */
- yaffs_DeleteChunk(dev, chunkInNAND, 1,
- __LINE__);
- return YAFFS_OK;
- }
- }
-
- }
-
- if (existingChunk == 0) {
- in->nDataChunks++;
- }
-
- yaffs_PutLevel0Tnode(dev,tn,chunkInInode,chunkInNAND);
-
- return YAFFS_OK;
-}
-
-static int yaffs_ReadChunkDataFromObject(yaffs_Object * in, int chunkInInode,
- __u8 * buffer)
-{
- int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
-
- if (chunkInNAND >= 0) {
- return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
- buffer,NULL);
- } else {
- T(YAFFS_TRACE_NANDACCESS,
- (TSTR("Chunk %d not found zero instead" TENDSTR),
- chunkInNAND));
- /* get sane (zero) data if you read a hole */
- memset(buffer, 0, in->myDev->nDataBytesPerChunk);
- return 0;
- }
-
-}
-
-void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn)
-{
- int block;
- int page;
- yaffs_ExtendedTags tags;
- yaffs_BlockInfo *bi;
-
- if (chunkId <= 0)
- return;
-
-
- dev->nDeletions++;
- block = chunkId / dev->nChunksPerBlock;
- page = chunkId % dev->nChunksPerBlock;
-
-
- if(!yaffs_CheckChunkBit(dev,block,page))
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Deleting invalid chunk %d"TENDSTR),
- chunkId));
-
- bi = yaffs_GetBlockInfo(dev, block);
-
- T(YAFFS_TRACE_DELETION,
- (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
-
- if (markNAND &&
- bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
-
- yaffs_InitialiseTags(&tags);
-
- tags.chunkDeleted = 1;
-
- yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
- yaffs_HandleUpdateChunk(dev, chunkId, &tags);
- } else {
- dev->nUnmarkedDeletions++;
- }
-
- /* Pull out of the management area.
- * If the whole block became dirty, this will kick off an erasure.
- */
- if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
- bi->blockState == YAFFS_BLOCK_STATE_FULL ||
- bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
- bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
- dev->nFreeChunks++;
-
- yaffs_ClearChunkBit(dev, block, page);
-
- bi->pagesInUse--;
-
- if (bi->pagesInUse == 0 &&
- !bi->hasShrinkHeader &&
- bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
- bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
- yaffs_BlockBecameDirty(dev, block);
- }
-
- } else {
- /* T(("Bad news deleting chunk %d\n",chunkId)); */
- }
-
-}
-
-static int yaffs_WriteChunkDataToObject(yaffs_Object * in, int chunkInInode,
- const __u8 * buffer, int nBytes,
- int useReserve)
-{
- /* Find old chunk Need to do this to get serial number
- * Write new one and patch into tree.
- * Invalidate old tags.
- */
-
- int prevChunkId;
- yaffs_ExtendedTags prevTags;
-
- int newChunkId;
- yaffs_ExtendedTags newTags;
-
- yaffs_Device *dev = in->myDev;
-
- yaffs_CheckGarbageCollection(dev);
-
- /* Get the previous chunk at this location in the file if it exists */
- prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
-
- /* Set up new tags */
- yaffs_InitialiseTags(&newTags);
-
- newTags.chunkId = chunkInInode;
- newTags.objectId = in->objectId;
- newTags.serialNumber =
- (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
- newTags.byteCount = nBytes;
-
- if(nBytes < 1 || nBytes > dev->totalBytesPerChunk){
- T(YAFFS_TRACE_ERROR,
- (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
- while(1){}
- }
-
-
-
- newChunkId =
- yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
- useReserve);
-
- if (newChunkId >= 0) {
- yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
-
- if (prevChunkId >= 0) {
- yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
-
- }
-
- yaffs_CheckFileSanity(in);
- }
- return newChunkId;
-
-}
-
-/* UpdateObjectHeader updates the header on NAND for an object.
- * If name is not NULL, then that new name is used.
- */
-int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, int force,
- int isShrink, int shadows)
-{
-
- yaffs_BlockInfo *bi;
-
- yaffs_Device *dev = in->myDev;
-
- int prevChunkId;
- int retVal = 0;
- int result = 0;
-
- int newChunkId;
- yaffs_ExtendedTags newTags;
- yaffs_ExtendedTags oldTags;
-
- __u8 *buffer = NULL;
- YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
-
- yaffs_ObjectHeader *oh = NULL;
-
- yaffs_strcpy(oldName,_Y("silly old name"));
-
-
- if (!in->fake ||
- in == dev->rootDir || /* The rootDir should also be saved */
- force) {
-
- yaffs_CheckGarbageCollection(dev);
- yaffs_CheckObjectDetailsLoaded(in);
-
- buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
- oh = (yaffs_ObjectHeader *) buffer;
-
- prevChunkId = in->hdrChunk;
-
- if (prevChunkId > 0) {
- result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
- buffer, &oldTags);
-
- yaffs_VerifyObjectHeader(in,oh,&oldTags,0);
-
- memcpy(oldName, oh->name, sizeof(oh->name));
- }
-
- memset(buffer, 0xFF, dev->nDataBytesPerChunk);
-
- oh->type = in->variantType;
- oh->yst_mode = in->yst_mode;
- oh->shadowsObject = oh->inbandShadowsObject = shadows;
-
-#ifdef CONFIG_YAFFS_WINCE
- oh->win_atime[0] = in->win_atime[0];
- oh->win_ctime[0] = in->win_ctime[0];
- oh->win_mtime[0] = in->win_mtime[0];
- oh->win_atime[1] = in->win_atime[1];
- oh->win_ctime[1] = in->win_ctime[1];
- oh->win_mtime[1] = in->win_mtime[1];
-#else
- oh->yst_uid = in->yst_uid;
- oh->yst_gid = in->yst_gid;
- oh->yst_atime = in->yst_atime;
- oh->yst_mtime = in->yst_mtime;
- oh->yst_ctime = in->yst_ctime;
- oh->yst_rdev = in->yst_rdev;
-#endif
- if (in->parent) {
- oh->parentObjectId = in->parent->objectId;
- } else {
- oh->parentObjectId = 0;
- }
-
- if (name && *name) {
- memset(oh->name, 0, sizeof(oh->name));
- yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
- } else if (prevChunkId>=0) {
- memcpy(oh->name, oldName, sizeof(oh->name));
- } else {
- memset(oh->name, 0, sizeof(oh->name));
- }
-
- oh->isShrink = isShrink;
-
- switch (in->variantType) {
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- /* Should not happen */
- break;
- case YAFFS_OBJECT_TYPE_FILE:
- oh->fileSize =
- (oh->parentObjectId == YAFFS_OBJECTID_DELETED
- || oh->parentObjectId ==
- YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
- fileVariant.fileSize;
- break;
- case YAFFS_OBJECT_TYPE_HARDLINK:
- oh->equivalentObjectId =
- in->variant.hardLinkVariant.equivalentObjectId;
- break;
- case YAFFS_OBJECT_TYPE_SPECIAL:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- yaffs_strncpy(oh->alias,
- in->variant.symLinkVariant.alias,
- YAFFS_MAX_ALIAS_LENGTH);
- oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
- break;
- }
-
- /* Tags */
- yaffs_InitialiseTags(&newTags);
- in->serial++;
- newTags.chunkId = 0;
- newTags.objectId = in->objectId;
- newTags.serialNumber = in->serial;
-
- /* Add extra info for file header */
-
- newTags.extraHeaderInfoAvailable = 1;
- newTags.extraParentObjectId = oh->parentObjectId;
- newTags.extraFileLength = oh->fileSize;
- newTags.extraIsShrinkHeader = oh->isShrink;
- newTags.extraEquivalentObjectId = oh->equivalentObjectId;
- newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
- newTags.extraObjectType = in->variantType;
-
- yaffs_VerifyObjectHeader(in,oh,&newTags,1);
-
- /* Create new chunk in NAND */
- newChunkId =
- yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
- (prevChunkId >= 0) ? 1 : 0);
-
- if (newChunkId >= 0) {
-
- in->hdrChunk = newChunkId;
-
- if (prevChunkId >= 0) {
- yaffs_DeleteChunk(dev, prevChunkId, 1,
- __LINE__);
- }
-
- if(!yaffs_ObjectHasCachedWriteData(in))
- in->dirty = 0;
-
- /* If this was a shrink, then mark the block that the chunk lives on */
- if (isShrink) {
- bi = yaffs_GetBlockInfo(in->myDev,
- newChunkId /in->myDev-> nChunksPerBlock);
- bi->hasShrinkHeader = 1;
- }
-
- }
-
- retVal = newChunkId;
-
- }
-
- if (buffer)
- yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
-
- return retVal;
-}
-
-/*------------------------ Short Operations Cache ----------------------------------------
- * In many situations where there is no high level buffering (eg WinCE) a lot of
- * reads might be short sequential reads, and a lot of writes may be short
- * sequential writes. eg. scanning/writing a jpeg file.
- * In these cases, a short read/write cache can provide a huge perfomance benefit
- * with dumb-as-a-rock code.
- * In Linux, the page cache provides read buffering aand the short op cache provides write
- * buffering.
- *
- * There are a limited number (~10) of cache chunks per device so that we don't
- * need a very intelligent search.
- */
-
-static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
-{
- yaffs_Device *dev = obj->myDev;
- int i;
- yaffs_ChunkCache *cache;
- int nCaches = obj->myDev->nShortOpCaches;
-
- for(i = 0; i < nCaches; i++){
- cache = &dev->srCache[i];
- if (cache->object == obj &&
- cache->dirty)
- return 1;
- }
-
- return 0;
-}
-
-
-static void yaffs_FlushFilesChunkCache(yaffs_Object * obj)
-{
- yaffs_Device *dev = obj->myDev;
- int lowest = -99; /* Stop compiler whining. */
- int i;
- yaffs_ChunkCache *cache;
- int chunkWritten = 0;
- int nCaches = obj->myDev->nShortOpCaches;
-
- if (nCaches > 0) {
- do {
- cache = NULL;
-
- /* Find the dirty cache for this object with the lowest chunk id. */
- for (i = 0; i < nCaches; i++) {
- if (dev->srCache[i].object == obj &&
- dev->srCache[i].dirty) {
- if (!cache
- || dev->srCache[i].chunkId <
- lowest) {
- cache = &dev->srCache[i];
- lowest = cache->chunkId;
- }
- }
- }
-
- if (cache && !cache->locked) {
- /* Write it out and free it up */
-
- chunkWritten =
- yaffs_WriteChunkDataToObject(cache->object,
- cache->chunkId,
- cache->data,
- cache->nBytes,
- 1);
- cache->dirty = 0;
- cache->object = NULL;
- }
-
- } while (cache && chunkWritten > 0);
-
- if (cache) {
- /* Hoosterman, disk full while writing cache out. */
- T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
-
- }
- }
-
-}
-
-/*yaffs_FlushEntireDeviceCache(dev)
- *
- *
- */
-
-void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
-{
- yaffs_Object *obj;
- int nCaches = dev->nShortOpCaches;
- int i;
-
- /* Find a dirty object in the cache and flush it...
- * until there are no further dirty objects.
- */
- do {
- obj = NULL;
- for( i = 0; i < nCaches && !obj; i++) {
- if (dev->srCache[i].object &&
- dev->srCache[i].dirty)
- obj = dev->srCache[i].object;
-
- }
- if(obj)
- yaffs_FlushFilesChunkCache(obj);
-
- } while(obj);
-
-}
-
-
-/* Grab us a cache chunk for use.
- * First look for an empty one.
- * Then look for the least recently used non-dirty one.
- * Then look for the least recently used dirty one...., flush and look again.
- */
-static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device * dev)
-{
- int i;
-
- if (dev->nShortOpCaches > 0) {
- for (i = 0; i < dev->nShortOpCaches; i++) {
- if (!dev->srCache[i].object)
- return &dev->srCache[i];
- }
- }
-
- return NULL;
-}
-
-static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev)
-{
- yaffs_ChunkCache *cache;
- yaffs_Object *theObj;
- int usage;
- int i;
- int pushout;
-
- if (dev->nShortOpCaches > 0) {
- /* Try find a non-dirty one... */
-
- cache = yaffs_GrabChunkCacheWorker(dev);
-
- if (!cache) {
- /* They were all dirty, find the last recently used object and flush
- * its cache, then find again.
- * NB what's here is not very accurate, we actually flush the object
- * the last recently used page.
- */
-
- /* With locking we can't assume we can use entry zero */
-
- theObj = NULL;
- usage = -1;
- cache = NULL;
- pushout = -1;
-
- for (i = 0; i < dev->nShortOpCaches; i++) {
- if (dev->srCache[i].object &&
- !dev->srCache[i].locked &&
- (dev->srCache[i].lastUse < usage || !cache))
- {
- usage = dev->srCache[i].lastUse;
- theObj = dev->srCache[i].object;
- cache = &dev->srCache[i];
- pushout = i;
- }
- }
-
- if (!cache || cache->dirty) {
- /* Flush and try again */
- yaffs_FlushFilesChunkCache(theObj);
- cache = yaffs_GrabChunkCacheWorker(dev);
- }
-
- }
- return cache;
- } else
- return NULL;
-
-}
-
-/* Find a cached chunk */
-static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object * obj,
- int chunkId)
-{
- yaffs_Device *dev = obj->myDev;
- int i;
- if (dev->nShortOpCaches > 0) {
- for (i = 0; i < dev->nShortOpCaches; i++) {
- if (dev->srCache[i].object == obj &&
- dev->srCache[i].chunkId == chunkId) {
- dev->cacheHits++;
-
- return &dev->srCache[i];
- }
- }
- }
- return NULL;
-}
-
-/* Mark the chunk for the least recently used algorithym */
-static void yaffs_UseChunkCache(yaffs_Device * dev, yaffs_ChunkCache * cache,
- int isAWrite)
-{
-
- if (dev->nShortOpCaches > 0) {
- if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
- /* Reset the cache usages */
- int i;
- for (i = 1; i < dev->nShortOpCaches; i++) {
- dev->srCache[i].lastUse = 0;
- }
- dev->srLastUse = 0;
- }
-
- dev->srLastUse++;
-
- cache->lastUse = dev->srLastUse;
-
- if (isAWrite) {
- cache->dirty = 1;
- }
- }
-}
-
-/* Invalidate a single cache page.
- * Do this when a whole page gets written,
- * ie the short cache for this page is no longer valid.
- */
-static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId)
-{
- if (object->myDev->nShortOpCaches > 0) {
- yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
-
- if (cache) {
- cache->object = NULL;
- }
- }
-}
-
-/* Invalidate all the cache pages associated with this object
- * Do this whenever ther file is deleted or resized.
- */
-static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in)
-{
- int i;
- yaffs_Device *dev = in->myDev;
-
- if (dev->nShortOpCaches > 0) {
- /* Invalidate it. */
- for (i = 0; i < dev->nShortOpCaches; i++) {
- if (dev->srCache[i].object == in) {
- dev->srCache[i].object = NULL;
- }
- }
- }
-}
-
-/*--------------------- Checkpointing --------------------*/
-
-
-static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head)
-{
- yaffs_CheckpointValidity cp;
-
- memset(&cp,0,sizeof(cp));
-
- cp.structType = sizeof(cp);
- cp.magic = YAFFS_MAGIC;
- cp.version = YAFFS_CHECKPOINT_VERSION;
- cp.head = (head) ? 1 : 0;
-
- return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))?
- 1 : 0;
-}
-
-static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
-{
- yaffs_CheckpointValidity cp;
- int ok;
-
- ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
-
- if(ok)
- ok = (cp.structType == sizeof(cp)) &&
- (cp.magic == YAFFS_MAGIC) &&
- (cp.version == YAFFS_CHECKPOINT_VERSION) &&
- (cp.head == ((head) ? 1 : 0));
- return ok ? 1 : 0;
-}
-
-static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
- yaffs_Device *dev)
-{
- cp->nErasedBlocks = dev->nErasedBlocks;
- cp->allocationBlock = dev->allocationBlock;
- cp->allocationPage = dev->allocationPage;
- cp->nFreeChunks = dev->nFreeChunks;
-
- cp->nDeletedFiles = dev->nDeletedFiles;
- cp->nUnlinkedFiles = dev->nUnlinkedFiles;
- cp->nBackgroundDeletions = dev->nBackgroundDeletions;
- cp->sequenceNumber = dev->sequenceNumber;
- cp->oldestDirtySequence = dev->oldestDirtySequence;
-
-}
-
-static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
- yaffs_CheckpointDevice *cp)
-{
- dev->nErasedBlocks = cp->nErasedBlocks;
- dev->allocationBlock = cp->allocationBlock;
- dev->allocationPage = cp->allocationPage;
- dev->nFreeChunks = cp->nFreeChunks;
-
- dev->nDeletedFiles = cp->nDeletedFiles;
- dev->nUnlinkedFiles = cp->nUnlinkedFiles;
- dev->nBackgroundDeletions = cp->nBackgroundDeletions;
- dev->sequenceNumber = cp->sequenceNumber;
- dev->oldestDirtySequence = cp->oldestDirtySequence;
-}
-
-
-static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
-{
- yaffs_CheckpointDevice cp;
- __u32 nBytes;
- __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
-
- int ok;
-
- /* Write device runtime values*/
- yaffs_DeviceToCheckpointDevice(&cp,dev);
- cp.structType = sizeof(cp);
-
- ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
-
- /* Write block info */
- if(ok) {
- nBytes = nBlocks * sizeof(yaffs_BlockInfo);
- ok = (yaffs_CheckpointWrite(dev,dev->blockInfo,nBytes) == nBytes);
- }
-
- /* Write chunk bits */
- if(ok) {
- nBytes = nBlocks * dev->chunkBitmapStride;
- ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes);
- }
- return ok ? 1 : 0;
-
-}
-
-static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
-{
- yaffs_CheckpointDevice cp;
- __u32 nBytes;
- __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
-
- int ok;
-
- ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
- if(!ok)
- return 0;
-
- if(cp.structType != sizeof(cp))
- return 0;
-
-
- yaffs_CheckpointDeviceToDevice(dev,&cp);
-
- nBytes = nBlocks * sizeof(yaffs_BlockInfo);
-
- ok = (yaffs_CheckpointRead(dev,dev->blockInfo,nBytes) == nBytes);
-
- if(!ok)
- return 0;
- nBytes = nBlocks * dev->chunkBitmapStride;
-
- ok = (yaffs_CheckpointRead(dev,dev->chunkBits,nBytes) == nBytes);
-
- return ok ? 1 : 0;
-}
-
-static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
- yaffs_Object *obj)
-{
-
- cp->objectId = obj->objectId;
- cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
- cp->hdrChunk = obj->hdrChunk;
- cp->variantType = obj->variantType;
- cp->deleted = obj->deleted;
- cp->softDeleted = obj->softDeleted;
- cp->unlinked = obj->unlinked;
- cp->fake = obj->fake;
- cp->renameAllowed = obj->renameAllowed;
- cp->unlinkAllowed = obj->unlinkAllowed;
- cp->serial = obj->serial;
- cp->nDataChunks = obj->nDataChunks;
-
- if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
- cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
- else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
- cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
-}
-
-static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp)
-{
-
- yaffs_Object *parent;
-
- obj->objectId = cp->objectId;
-
- if(cp->parentId)
- parent = yaffs_FindOrCreateObjectByNumber(
- obj->myDev,
- cp->parentId,
- YAFFS_OBJECT_TYPE_DIRECTORY);
- else
- parent = NULL;
-
- if(parent)
- yaffs_AddObjectToDirectory(parent, obj);
-
- obj->hdrChunk = cp->hdrChunk;
- obj->variantType = cp->variantType;
- obj->deleted = cp->deleted;
- obj->softDeleted = cp->softDeleted;
- obj->unlinked = cp->unlinked;
- obj->fake = cp->fake;
- obj->renameAllowed = cp->renameAllowed;
- obj->unlinkAllowed = cp->unlinkAllowed;
- obj->serial = cp->serial;
- obj->nDataChunks = cp->nDataChunks;
-
- if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
- obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
- else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
- obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
-
- if(obj->hdrChunk > 0)
- obj->lazyLoaded = 1;
-}
-
-
-
-static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn,
- __u32 level, int chunkOffset)
-{
- int i;
- yaffs_Device *dev = in->myDev;
- int ok = 1;
- int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
- if(tnodeSize < sizeof(yaffs_Tnode))
- tnodeSize = sizeof(yaffs_Tnode);
-
-
- if (tn) {
- if (level > 0) {
-
- for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){
- if (tn->internal[i]) {
- ok = yaffs_CheckpointTnodeWorker(in,
- tn->internal[i],
- level - 1,
- (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
- }
- }
- } else if (level == 0) {
- __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
- ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset));
- if(ok)
- ok = (yaffs_CheckpointWrite(dev,tn,tnodeSize) == tnodeSize);
- }
- }
-
- return ok;
-
-}
-
-static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
-{
- __u32 endMarker = ~0;
- int ok = 1;
-
- if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){
- ok = yaffs_CheckpointTnodeWorker(obj,
- obj->variant.fileVariant.top,
- obj->variant.fileVariant.topLevel,
- 0);
- if(ok)
- ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) ==
- sizeof(endMarker));
- }
-
- return ok ? 1 : 0;
-}
-
-static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
-{
- __u32 baseChunk;
- int ok = 1;
- yaffs_Device *dev = obj->myDev;
- yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
- yaffs_Tnode *tn;
- int nread = 0;
- int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
- if(tnodeSize < sizeof(yaffs_Tnode))
- tnodeSize = sizeof(yaffs_Tnode);
-
- ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk));
-
- while(ok && (~baseChunk)){
- nread++;
- /* Read level 0 tnode */
-
-
- tn = yaffs_GetTnodeRaw(dev);
- if(tn)
- ok = (yaffs_CheckpointRead(dev,tn,tnodeSize) == tnodeSize);
- else
- ok = 0;
-
- if(tn && ok){
- ok = yaffs_AddOrFindLevel0Tnode(dev,
- fileStructPtr,
- baseChunk,
- tn) ? 1 : 0;
-
- }
-
- if(ok)
- ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk));
-
- }
-
- T(YAFFS_TRACE_CHECKPOINT,(
- TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
- nread,baseChunk,ok));
-
- return ok ? 1 : 0;
-}
-
-
-static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
-{
- yaffs_Object *obj;
- yaffs_CheckpointObject cp;
- int i;
- int ok = 1;
- struct ylist_head *lh;
-
-
- /* Iterate through the objects in each hash entry,
- * dumping them to the checkpointing stream.
- */
-
- for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){
- ylist_for_each(lh, &dev->objectBucket[i].list) {
- if (lh) {
- obj = ylist_entry(lh, yaffs_Object, hashLink);
- if (!obj->deferedFree) {
- yaffs_ObjectToCheckpointObject(&cp,obj);
- cp.structType = sizeof(cp);
-
- T(YAFFS_TRACE_CHECKPOINT,(
- TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
- cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk,(unsigned) obj));
-
- ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
-
- if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){
- ok = yaffs_WriteCheckpointTnodes(obj);
- }
- }
- }
- }
- }
-
- /* Dump end of list */
- memset(&cp,0xFF,sizeof(yaffs_CheckpointObject));
- cp.structType = sizeof(cp);
-
- if(ok)
- ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
-
- return ok ? 1 : 0;
-}
-
-static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
-{
- yaffs_Object *obj;
- yaffs_CheckpointObject cp;
- int ok = 1;
- int done = 0;
- yaffs_Object *hardList = NULL;
-
- while(ok && !done) {
- ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
- if(cp.structType != sizeof(cp)) {
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("struct size %d instead of %d ok %d"TENDSTR),
- cp.structType,sizeof(cp),ok));
- ok = 0;
- }
-
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
- cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk));
-
- if(ok && cp.objectId == ~0)
- done = 1;
- else if(ok){
- obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType);
- if(obj) {
- yaffs_CheckpointObjectToObject(obj,&cp);
- if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
- ok = yaffs_ReadCheckpointTnodes(obj);
- } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
- obj->hardLinks.next =
- (struct ylist_head *)
- hardList;
- hardList = obj;
- }
-
- }
- }
- }
-
- if(ok)
- yaffs_HardlinkFixup(dev,hardList);
-
- return ok ? 1 : 0;
-}
-
-static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
-{
- __u32 checkpointSum;
- int ok;
-
- yaffs_GetCheckpointSum(dev,&checkpointSum);
-
- ok = (yaffs_CheckpointWrite(dev,&checkpointSum,sizeof(checkpointSum)) == sizeof(checkpointSum));
-
- if(!ok)
- return 0;
-
- return 1;
-}
-
-static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
-{
- __u32 checkpointSum0;
- __u32 checkpointSum1;
- int ok;
-
- yaffs_GetCheckpointSum(dev,&checkpointSum0);
-
- ok = (yaffs_CheckpointRead(dev,&checkpointSum1,sizeof(checkpointSum1)) == sizeof(checkpointSum1));
-
- if(!ok)
- return 0;
-
- if(checkpointSum0 != checkpointSum1)
- return 0;
-
- return 1;
-}
-
-
-static int yaffs_WriteCheckpointData(yaffs_Device *dev)
-{
-
- int ok = 1;
-
- if(dev->skipCheckpointWrite || !dev->isYaffs2){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint write" TENDSTR)));
- ok = 0;
- }
-
- if(ok)
- ok = yaffs_CheckpointOpen(dev,1);
-
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR)));
- ok = yaffs_WriteCheckpointValidityMarker(dev,1);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint device" TENDSTR)));
- ok = yaffs_WriteCheckpointDevice(dev);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR)));
- ok = yaffs_WriteCheckpointObjects(dev);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR)));
- ok = yaffs_WriteCheckpointValidityMarker(dev,0);
- }
-
- if(ok){
- ok = yaffs_WriteCheckpointSum(dev);
- }
-
-
- if(!yaffs_CheckpointClose(dev))
- ok = 0;
-
- if(ok)
- dev->isCheckpointed = 1;
- else
- dev->isCheckpointed = 0;
-
- return dev->isCheckpointed;
-}
-
-static int yaffs_ReadCheckpointData(yaffs_Device *dev)
-{
- int ok = 1;
-
- if(dev->skipCheckpointRead || !dev->isYaffs2){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint read" TENDSTR)));
- ok = 0;
- }
-
- if(ok)
- ok = yaffs_CheckpointOpen(dev,0); /* open for read */
-
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR)));
- ok = yaffs_ReadCheckpointValidityMarker(dev,1);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint device" TENDSTR)));
- ok = yaffs_ReadCheckpointDevice(dev);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR)));
- ok = yaffs_ReadCheckpointObjects(dev);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR)));
- ok = yaffs_ReadCheckpointValidityMarker(dev,0);
- }
-
- if(ok){
- ok = yaffs_ReadCheckpointSum(dev);
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint checksum %d" TENDSTR),ok));
- }
-
- if(!yaffs_CheckpointClose(dev))
- ok = 0;
-
- if(ok)
- dev->isCheckpointed = 1;
- else
- dev->isCheckpointed = 0;
-
- return ok ? 1 : 0;
-
-}
-
-static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
-{
- if(dev->isCheckpointed ||
- dev->blocksInCheckpoint > 0){
- dev->isCheckpointed = 0;
- yaffs_CheckpointInvalidateStream(dev);
- if(dev->superBlock && dev->markSuperBlockDirty)
- dev->markSuperBlockDirty(dev->superBlock);
- }
-}
-
-
-int yaffs_CheckpointSave(yaffs_Device *dev)
-{
-
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
-
- yaffs_VerifyObjects(dev);
- yaffs_VerifyBlocks(dev);
- yaffs_VerifyFreeChunks(dev);
-
- if(!dev->isCheckpointed) {
- yaffs_InvalidateCheckpoint(dev);
- yaffs_WriteCheckpointData(dev);
- }
-
- T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
-
- return dev->isCheckpointed;
-}
-
-int yaffs_CheckpointRestore(yaffs_Device *dev)
-{
- int retval;
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
-
- retval = yaffs_ReadCheckpointData(dev);
-
- if(dev->isCheckpointed){
- yaffs_VerifyObjects(dev);
- yaffs_VerifyBlocks(dev);
- yaffs_VerifyFreeChunks(dev);
- }
-
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
-
- return retval;
-}
-
-/*--------------------- File read/write ------------------------
- * Read and write have very similar structures.
- * In general the read/write has three parts to it
- * An incomplete chunk to start with (if the read/write is not chunk-aligned)
- * Some complete chunks
- * An incomplete chunk to end off with
- *
- * Curve-balls: the first chunk might also be the last chunk.
- */
-
-int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset,
- int nBytes)
-{
-
- int chunk;
- __u32 start;
- int nToCopy;
- int n = nBytes;
- int nDone = 0;
- yaffs_ChunkCache *cache;
-
- yaffs_Device *dev;
-
- dev = in->myDev;
-
- while (n > 0) {
- //chunk = offset / dev->nDataBytesPerChunk + 1;
- //start = offset % dev->nDataBytesPerChunk;
- yaffs_AddrToChunk(dev,offset,&chunk,&start);
- chunk++;
-
- /* OK now check for the curveball where the start and end are in
- * the same chunk.
- */
- if ((start + n) < dev->nDataBytesPerChunk) {
- nToCopy = n;
- } else {
- nToCopy = dev->nDataBytesPerChunk - start;
- }
-
- cache = yaffs_FindChunkCache(in, chunk);
-
- /* If the chunk is already in the cache or it is less than a whole chunk
- * or we're using inband tags then use the cache (if there is caching)
- * else bypass the cache.
- */
- if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
- if (dev->nShortOpCaches > 0) {
-
- /* If we can't find the data in the cache, then load it up. */
-
- if (!cache) {
- cache = yaffs_GrabChunkCache(in->myDev);
- cache->object = in;
- cache->chunkId = chunk;
- cache->dirty = 0;
- cache->locked = 0;
- yaffs_ReadChunkDataFromObject(in, chunk,
- cache->
- data);
- cache->nBytes = 0;
- }
-
- yaffs_UseChunkCache(dev, cache, 0);
-
- cache->locked = 1;
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(buffer, &cache->data[start], nToCopy);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- cache->locked = 0;
- } else {
- /* Read into the local buffer then copy..*/
-
- __u8 *localBuffer =
- yaffs_GetTempBuffer(dev, __LINE__);
- yaffs_ReadChunkDataFromObject(in, chunk,
- localBuffer);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(buffer, &localBuffer[start], nToCopy);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- yaffs_ReleaseTempBuffer(dev, localBuffer,
- __LINE__);
- }
-
- } else {
-#ifdef CONFIG_YAFFS_WINCE
- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
-
- /* Under WinCE can't do direct transfer. Need to use a local buffer.
- * This is because we otherwise screw up WinCE's memory mapper
- */
- yaffs_ReadChunkDataFromObject(in, chunk, localBuffer);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(buffer, localBuffer, dev->nDataBytesPerChunk);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
-#endif
-
-#else
- /* A full chunk. Read directly into the supplied buffer. */
- yaffs_ReadChunkDataFromObject(in, chunk, buffer);
-#endif
- }
-
- n -= nToCopy;
- offset += nToCopy;
- buffer += nToCopy;
- nDone += nToCopy;
-
- }
-
- return nDone;
-}
-
-int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset,
- int nBytes, int writeThrough)
-{
-
- int chunk;
- __u32 start;
- int nToCopy;
- int n = nBytes;
- int nDone = 0;
- int nToWriteBack;
- int startOfWrite = offset;
- int chunkWritten = 0;
- __u32 nBytesRead;
- __u32 chunkStart;
-
- yaffs_Device *dev;
-
- dev = in->myDev;
-
- while (n > 0 && chunkWritten >= 0) {
- //chunk = offset / dev->nDataBytesPerChunk + 1;
- //start = offset % dev->nDataBytesPerChunk;
- yaffs_AddrToChunk(dev,offset,&chunk,&start);
-
- if(chunk * dev->nDataBytesPerChunk + start != offset ||
- start >= dev->nDataBytesPerChunk){
- T(YAFFS_TRACE_ERROR,(TSTR("AddrToChunk of offset %d gives chunk %d start %d"TENDSTR),
- (int)offset, chunk,start));
- }
- chunk++;
-
- /* OK now check for the curveball where the start and end are in
- * the same chunk.
- */
-
- if ((start + n) < dev->nDataBytesPerChunk) {
- nToCopy = n;
-
- /* Now folks, to calculate how many bytes to write back....
- * If we're overwriting and not writing to then end of file then
- * we need to write back as much as was there before.
- */
-
- chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
-
- if(chunkStart > in->variant.fileVariant.fileSize)
- nBytesRead = 0; /* Past end of file */
- else
- nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
-
- if (nBytesRead > dev->nDataBytesPerChunk) {
- nBytesRead = dev->nDataBytesPerChunk;
- }
-
- nToWriteBack =
- (nBytesRead >
- (start + n)) ? nBytesRead : (start + n);
-
- if(nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
- YBUG();
-
- } else {
- nToCopy = dev->nDataBytesPerChunk - start;
- nToWriteBack = dev->nDataBytesPerChunk;
- }
-
- if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
- /* An incomplete start or end chunk (or maybe both start and end chunk),
- * or we're using inband tags, so we want to use the cache buffers.
- */
- if (dev->nShortOpCaches > 0) {
- yaffs_ChunkCache *cache;
- /* If we can't find the data in the cache, then load the cache */
- cache = yaffs_FindChunkCache(in, chunk);
-
- if (!cache
- && yaffs_CheckSpaceForAllocation(in->
- myDev)) {
- cache = yaffs_GrabChunkCache(in->myDev);
- cache->object = in;
- cache->chunkId = chunk;
- cache->dirty = 0;
- cache->locked = 0;
- yaffs_ReadChunkDataFromObject(in, chunk,
- cache->
- data);
- }
- else if(cache &&
- !cache->dirty &&
- !yaffs_CheckSpaceForAllocation(in->myDev)){
- /* Drop the cache if it was a read cache item and
- * no space check has been made for it.
- */
- cache = NULL;
- }
-
- if (cache) {
- yaffs_UseChunkCache(dev, cache, 1);
- cache->locked = 1;
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
-
- memcpy(&cache->data[start], buffer,
- nToCopy);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- cache->locked = 0;
- cache->nBytes = nToWriteBack;
-
- if (writeThrough) {
- chunkWritten =
- yaffs_WriteChunkDataToObject
- (cache->object,
- cache->chunkId,
- cache->data, cache->nBytes,
- 1);
- cache->dirty = 0;
- }
-
- } else {
- chunkWritten = -1; /* fail the write */
- }
- } else {
- /* An incomplete start or end chunk (or maybe both start and end chunk)
- * Read into the local buffer then copy, then copy over and write back.
- */
-
- __u8 *localBuffer =
- yaffs_GetTempBuffer(dev, __LINE__);
-
- yaffs_ReadChunkDataFromObject(in, chunk,
- localBuffer);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
-
- memcpy(&localBuffer[start], buffer, nToCopy);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- chunkWritten =
- yaffs_WriteChunkDataToObject(in, chunk,
- localBuffer,
- nToWriteBack,
- 0);
-
- yaffs_ReleaseTempBuffer(dev, localBuffer,
- __LINE__);
-
- }
-
- } else {
- /* A full chunk. Write directly from the supplied buffer. */
-
-#ifdef CONFIG_YAFFS_WINCE
- /* Under WinCE can't do direct transfer. Need to use a local buffer.
- * This is because we otherwise screw up WinCE's memory mapper
- */
- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(localBuffer, buffer, dev->nDataBytesPerChunk);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- chunkWritten =
- yaffs_WriteChunkDataToObject(in, chunk, localBuffer,
- dev->nDataBytesPerChunk,
- 0);
- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
-#else
-
- chunkWritten =
- yaffs_WriteChunkDataToObject(in, chunk, buffer,
- dev->nDataBytesPerChunk,
- 0);
-#endif
- /* Since we've overwritten the cached data, we better invalidate it. */
- yaffs_InvalidateChunkCache(in, chunk);
- }
-
- if (chunkWritten >= 0) {
- n -= nToCopy;
- offset += nToCopy;
- buffer += nToCopy;
- nDone += nToCopy;
- }
-
- }
-
- /* Update file object */
-
- if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) {
- in->variant.fileVariant.fileSize = (startOfWrite + nDone);
- }
-
- in->dirty = 1;
-
- return nDone;
-}
-
-
-/* ---------------------- File resizing stuff ------------------ */
-
-static void yaffs_PruneResizedChunks(yaffs_Object * in, int newSize)
-{
-
- yaffs_Device *dev = in->myDev;
- int oldFileSize = in->variant.fileVariant.fileSize;
-
- int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
-
- int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
- dev->nDataBytesPerChunk;
- int i;
- int chunkId;
-
- /* Delete backwards so that we don't end up with holes if
- * power is lost part-way through the operation.
- */
- for (i = lastDel; i >= startDel; i--) {
- /* NB this could be optimised somewhat,
- * eg. could retrieve the tags and write them without
- * using yaffs_DeleteChunk
- */
-
- chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
- if (chunkId > 0) {
- if (chunkId <
- (dev->internalStartBlock * dev->nChunksPerBlock)
- || chunkId >=
- ((dev->internalEndBlock +
- 1) * dev->nChunksPerBlock)) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("Found daft chunkId %d for %d" TENDSTR),
- chunkId, i));
- } else {
- in->nDataChunks--;
- yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
- }
- }
- }