- 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;
- }
- }
- }
-}
-
-/*--------------------- 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, __u32 offset,
- int nBytes)
-{
-
- int chunk;
- int start;
- int nToCopy;
- int n = nBytes;
- int nDone = 0;
- yaffs_ChunkCache *cache;
-
- yaffs_Device *dev;
-
- dev = in->myDev;
-
- while (n > 0) {
- chunk = offset / dev->nBytesPerChunk + 1; /* The first chunk is 1 */
- start = offset % dev->nBytesPerChunk;
-
- /* OK now check for the curveball where the start and end are in
- * the same chunk.
- */
- if ((start + n) < dev->nBytesPerChunk) {
- nToCopy = n;
- } else {
- nToCopy = dev->nBytesPerChunk - start;
- }
-
- cache = yaffs_FindChunkCache(in, chunk);
-
- /* If the chunk is already in the cache or it is less than a whole chunk
- * then use the cache (if there is caching)
- * else bypass the cache.
- */
- if (cache || nToCopy != dev->nBytesPerChunk) {
- 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->nBytesPerChunk);
-
-#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, __u32 offset,
- int nBytes, int writeThrough)
-{
-
- int chunk;
- int start;
- int nToCopy;
- int n = nBytes;
- int nDone = 0;
- int nToWriteBack;
- int startOfWrite = offset;
- int chunkWritten = 0;
- int nBytesRead;
-
- yaffs_Device *dev;
-
- dev = in->myDev;
-
- while (n > 0 && chunkWritten >= 0) {
- chunk = offset / dev->nBytesPerChunk + 1;
- start = offset % dev->nBytesPerChunk;
-
- /* OK now check for the curveball where the start and end are in
- * the same chunk.
- */
-
- if ((start + n) < dev->nBytesPerChunk) {
- 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.
- */
-
- nBytesRead =
- in->variant.fileVariant.fileSize -
- ((chunk - 1) * dev->nBytesPerChunk);
-
- if (nBytesRead > dev->nBytesPerChunk) {
- nBytesRead = dev->nBytesPerChunk;
- }
-
- nToWriteBack =
- (nBytesRead >
- (start + n)) ? nBytesRead : (start + n);
-
- } else {
- nToCopy = dev->nBytesPerChunk - start;
- nToWriteBack = dev->nBytesPerChunk;
- }
-
- if (nToCopy != dev->nBytesPerChunk) {
- /* An incomplete start or end chunk (or maybe both start and end chunk) */
- 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);
- }
-
- 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 {
-
-#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->nBytesPerChunk);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- chunkWritten =
- yaffs_WriteChunkDataToObject(in, chunk, localBuffer,
- dev->nBytesPerChunk,
- 0);
- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
-#else
- /* A full chunk. Write directly from the supplied buffer. */
- chunkWritten =
- yaffs_WriteChunkDataToObject(in, chunk, buffer,
- dev->nBytesPerChunk,
- 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->nBytesPerChunk;
-
- int startDel = 1 + (newSize + dev->nBytesPerChunk - 1) /
- dev->nBytesPerChunk;
- 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__);
- }
- }
- }
-
-}
-
-int yaffs_ResizeFile(yaffs_Object * in, int newSize)
-{
-
- int oldFileSize = in->variant.fileVariant.fileSize;
- int sizeOfPartialChunk;
- yaffs_Device *dev = in->myDev;
-
- sizeOfPartialChunk = newSize % dev->nBytesPerChunk;
-
- yaffs_FlushFilesChunkCache(in);
- yaffs_InvalidateWholeChunkCache(in);
-
- yaffs_CheckGarbageCollection(dev);
-
- if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
- return yaffs_GetFileSize(in);
- }
-
- if (newSize == oldFileSize) {
- return oldFileSize;
- }
-
- if (newSize < oldFileSize) {
-
- yaffs_PruneResizedChunks(in, newSize);
-
- if (sizeOfPartialChunk != 0) {
- int lastChunk = 1 + newSize / dev->nBytesPerChunk;
- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
-
- /* Got to read and rewrite the last chunk with its new size and zero pad */
- yaffs_ReadChunkDataFromObject(in, lastChunk,
- localBuffer);
-
- memset(localBuffer + sizeOfPartialChunk, 0,
- dev->nBytesPerChunk - sizeOfPartialChunk);
-
- yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
- sizeOfPartialChunk, 1);
-
- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
- }
-
- in->variant.fileVariant.fileSize = newSize;
-
- yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
- }
- /* Write a new object header.
- * show we've shrunk the file, if need be
- * Do this only if the file is not in the deleted directories.
- */
- if (in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
- in->parent->objectId != YAFFS_OBJECTID_DELETED) {
- yaffs_UpdateObjectHeader(in, NULL, 0,
- (newSize < oldFileSize) ? 1 : 0, 0);
- }
-
- return newSize;
-}
-
-loff_t yaffs_GetFileSize(yaffs_Object * obj)
-{
- obj = yaffs_GetEquivalentObject(obj);
-
- switch (obj->variantType) {
- case YAFFS_OBJECT_TYPE_FILE:
- return obj->variant.fileVariant.fileSize;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- return yaffs_strlen(obj->variant.symLinkVariant.alias);
- default:
- return 0;
- }
-}
-
-
-
-int yaffs_FlushFile(yaffs_Object * in, int updateTime)
-{
- int retVal;
- if (in->dirty) {
- yaffs_FlushFilesChunkCache(in);
- if (updateTime) {
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_WinFileTimeNow(in->win_mtime);
-#else
-
- in->yst_mtime = Y_CURRENT_TIME;
-
-#endif
- }
-
- retVal =
- (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
- 0) ? YAFFS_OK : YAFFS_FAIL;
- } else {
- retVal = YAFFS_OK;
- }
-
- return retVal;
-
-}
-
-static int yaffs_DoGenericObjectDeletion(yaffs_Object * in)
-{
-
- /* First off, invalidate the file's data in the cache, without flushing. */
- yaffs_InvalidateWholeChunkCache(in);
-
- if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
- /* Move to the unlinked directory so we have a record that it was deleted. */
- yaffs_ChangeObjectName(in, in->myDev->deletedDir, NULL, 0, 0);
-
- }
-
- yaffs_RemoveObjectFromDirectory(in);
- yaffs_DeleteChunk(in->myDev, in->chunkId, 1, __LINE__);
- in->chunkId = -1;
-
- yaffs_FreeObject(in);
- return YAFFS_OK;
-
-}
-
-/* yaffs_DeleteFile deletes the whole file data
- * and the inode associated with the file.
- * It does not delete the links associated with the file.
- */
-static int yaffs_UnlinkFile(yaffs_Object * in)
-{
-
- int retVal;
- int immediateDeletion = 0;
-
- if (1) {
-#ifdef __KERNEL__
- if (!in->myInode) {
- immediateDeletion = 1;
-
- }
-#else
- if (in->inUse <= 0) {
- immediateDeletion = 1;
-
- }
-#endif
- if (immediateDeletion) {
- retVal =
- yaffs_ChangeObjectName(in, in->myDev->deletedDir,
- NULL, 0, 0);
- T(YAFFS_TRACE_TRACING,
- (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
- in->objectId));
- in->deleted = 1;
- in->myDev->nDeletedFiles++;
- if (0 && in->myDev->isYaffs2) {
- yaffs_ResizeFile(in, 0);
- }
- yaffs_SoftDeleteFile(in);
- } else {
- retVal =
- yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
- NULL, 0, 0);
- }
-
- }
- return retVal;
-}
-
-int yaffs_DeleteFile(yaffs_Object * in)
-{
- int retVal = YAFFS_OK;
-
- if (in->nDataChunks > 0) {
- /* Use soft deletion if there is data in the file */
- if (!in->unlinked) {
- retVal = yaffs_UnlinkFile(in);
- }
- if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
- in->deleted = 1;
- in->myDev->nDeletedFiles++;
- yaffs_SoftDeleteFile(in);
- }
- return in->deleted ? YAFFS_OK : YAFFS_FAIL;
- } else {
- /* The file has no data chunks so we toss it immediately */
- yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
- in->variant.fileVariant.top = NULL;
- yaffs_DoGenericObjectDeletion(in);
-
- return YAFFS_OK;
- }
-}
-
-static int yaffs_DeleteDirectory(yaffs_Object * in)