X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FFilesystems%2FFAT%2Ffat.c;h=1411902ad2ef4bdb6fbe32a9c9c8fdca199a7a6b;hb=0dd55a90dfc0073f9432635a621c3ec6d2d9bca9;hp=f7dd8c527eb595296eb4e475d914d2757c0b99ed;hpb=0ea39901119279ee9bb9cf8270b2a0d65cb7460f;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/Filesystems/FAT/fat.c b/KernelLand/Modules/Filesystems/FAT/fat.c index f7dd8c52..1411902a 100644 --- a/KernelLand/Modules/Filesystems/FAT/fat.c +++ b/KernelLand/Modules/Filesystems/FAT/fat.c @@ -27,14 +27,15 @@ // === PROTOTYPES === // --- Driver Core int FAT_Install(char **Arguments); + int FAT_Detect(int FD); tVFS_Node *FAT_InitDevice(const char *device, const char **options); void FAT_Unmount(tVFS_Node *Node); // --- Helpers int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster); // --- File IO -size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer); +size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags); #if SUPPORT_WRITE -size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer); +size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags); #endif void FAT_CloseFile(tVFS_Node *node); @@ -46,7 +47,13 @@ void FAT_CloseFile(tVFS_Node *node); MODULE_DEFINE(0, VER2(0,80) /*v0.80*/, VFAT, FAT_Install, NULL, NULL); tFAT_VolInfo gFAT_Disks[8]; int giFAT_PartCount = 0; -tVFS_Driver gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, FAT_GetNodeFromINode, NULL}; +tVFS_Driver gFAT_FSInfo = { + .Name = "fat", + .Detect = FAT_Detect, + .InitDevice = FAT_InitDevice, + .Unmount = FAT_Unmount, + .GetNodeFromINode = FAT_GetNodeFromINode +}; tVFS_NodeType gFAT_DirType = { .TypeName = "FAT-Dir", .ReadDir = FAT_ReadDir, @@ -78,6 +85,26 @@ int FAT_Install(char **Arguments) return MODULE_ERR_OK; } +/** + * \brief Detect if a file is a FAT device + */ +int FAT_Detect(int FD) +{ + fat_bootsect bs; + + if( VFS_ReadAt(FD, 0, 512, &bs) != 512) { + return 0; + } + + if(bs.bps == 0 || bs.spc == 0) + return 0; + + Log_Debug("FAT", "_Detect: Media type = %02x", bs.mediaDesc); + if( bs.mediaDesc < 0xF0 ) + return 0; + + return 1; +} /** * \brief Reads the boot sector of a disk and prepares the structures for it */ @@ -105,6 +132,7 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options) if(bs->bps == 0 || bs->spc == 0) { Log_Notice("FAT", "Error in FAT Boot Sector (zero BPS/SPC)"); + VFS_Close(diskInfo->fileHandle); return NULL; } @@ -172,8 +200,10 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options) // Compute Root directory offset if(diskInfo->type == FAT32) diskInfo->rootOffset = bs->spec.fat32.rootClust; - else + else { + diskInfo->RootSector = FATSz * bs->fatCount; diskInfo->rootOffset = (FATSz * bs->fatCount) / bs->spc; + } diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors; @@ -185,6 +215,7 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options) diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount); if(diskInfo->FATCache == NULL) { Log_Warning("FAT", "Heap Exhausted"); + VFS_Cose(diskInfo->fileHandle); return NULL; } Ofs = bs->resvSectCount*512; @@ -296,31 +327,43 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu cluster = base_cluster = Node->Inode & 0xFFFFFFF; // Cluster ID // LOG("base cluster = 0x%07x", cluster); - - // Do Cluster Skip + + // Handle root directory // - Pre FAT32 had a reserved area for the root. - if( disk->type == FAT32 || cluster != disk->rootOffset ) + if( disk->type != FAT32 && Node == &disk->rootNode ) { - skip = Offset / disk->BytesPerCluster; - LOG("skip = %i", skip); - // Skip previous clusters - for(; skip-- ; ) - { - if(Cluster) *Cluster = cluster; - cluster = FAT_int_GetFatValue(disk, cluster); - // Check for end of cluster chain - if(cluster == 0xFFFFFFFF) { LEAVE('i', 1); return 1;} + Uint32 root_byte_count = disk->bootsect.files_in_root * 32 ; + if( Offset >= root_byte_count ) { + LOG("FAT12/16 root out of range (%i >= %i)", Offset, root_byte_count); + LEAVE('i', 1); + return 1; } - if(Cluster) *Cluster = cluster; + LOG("FAT12/16 root"); + + // Calculate address + addr = (disk->bootsect.resvSectCount + disk->RootSector) * disk->bootsect.bps; + addr += Offset; + + LOG("addr = %llx", addr); + *Addr = addr; + LEAVE('i', 0); + return 0; } - else { - // TODO: Bounds checking on root -// LOG("Root cluster count %i", disk->bootsect.files_in_root*32/disk->BytesPerCluster); - // Increment by clusters in offset - cluster += Offset / disk->BytesPerCluster; + + // Do Cluster Skip + skip = Offset / disk->BytesPerCluster; + LOG("skip = %i", skip); + // Skip previous clusters + for(; skip-- ; ) + { + if(Cluster) *Cluster = cluster; + cluster = FAT_int_GetFatValue(disk, cluster); + // Check for end of cluster chain + if(cluster == GETFATVALUE_EOC) { LEAVE('i', 1); return 1; } } + if(Cluster) *Cluster = cluster; -// LOG("cluster = 0x%07x", cluster); + LOG("cluster = 0x%07x", cluster); // Bounds Checking (Used to spot corruption) if(cluster > disk->ClusterCount + 2) @@ -332,15 +375,8 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu } // Compute Offsets - // - Pre FAT32 cluster base (in sectors) - if( base_cluster == disk->rootOffset && disk->type != FAT32 ) { - addr = disk->bootsect.resvSectCount * disk->bootsect.bps; - addr += cluster * disk->BytesPerCluster; - } - else { - addr = disk->firstDataSect * disk->bootsect.bps; - addr += (cluster - 2) * disk->BytesPerCluster; - } + addr = disk->firstDataSect * disk->bootsect.bps; + addr += (cluster - 2) * disk->BytesPerCluster; // In-cluster offset addr += Offset % disk->BytesPerCluster; @@ -357,7 +393,7 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu /** * \brief Reads data from a specified file */ -size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer) +size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) { int preSkip, count; Uint64 final_bytes; @@ -392,13 +428,15 @@ size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer) for(i = preSkip; i--; ) { cluster = FAT_int_GetFatValue(disk, cluster); - if(cluster == -1) { + if(cluster == GETFATVALUE_EOC) { Log_Warning("FAT", "Offset is past end of cluster chain mark"); LEAVE('i', 0); return 0; } } + // TODO: Handle (Flags & VFS_IOFLAG_NOBLOCK) + // Reading from within one cluster if((int)Offset + (int)Length <= bpc) { @@ -418,7 +456,7 @@ size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer) LOG("pos = %i, Reading the rest of the clusters"); // Get next cluster in the chain cluster = FAT_int_GetFatValue(disk, cluster); - if(cluster == -1) { + if(cluster == GETFATVALUE_EOC) { Log_Warning("FAT", "Read past End of Cluster Chain (Align)"); LEAVE('X', pos); return pos; @@ -436,7 +474,7 @@ size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer) // Read the rest of the cluster data for( ; count; count -- ) { - if(cluster == -1) { + if(cluster == GETFATVALUE_EOC) { Log_Warning("FAT", "Read past End of Cluster Chain (Bulk)"); LEAVE('X', pos); return pos; @@ -476,23 +514,28 @@ size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer) * \param Length Size of data to write * \param Buffer Data source */ -size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer) +size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags) { tFAT_VolInfo *disk = Node->ImplPtr; char tmpBuf[disk->BytesPerCluster]; int remLength = Length; Uint32 cluster, tmpCluster; int bNewCluster = 0; + off_t original_offset = Offset; if(Offset > Node->Size) return 0; + // TODO: Handle (Flags & VFS_IOFLAG_NOBLOCK) + + ENTER("pNode Xoffset xlength pbuffer", Node, Offset, Length, Buffer); // Seek Clusters cluster = Node->Inode & 0xFFFFFFFF; while( Offset > disk->BytesPerCluster ) { cluster = FAT_int_GetFatValue( disk, cluster ); - if(cluster == -1) { + if(cluster == GETFATVALUE_EOC) { Log_Warning("FAT", "EOC Unexpectedly Reached"); + LEAVE('i', 0); return 0; } Offset -= disk->BytesPerCluster; @@ -500,7 +543,10 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffe if( Offset == disk->BytesPerCluster ) { Uint32 tmp = FAT_int_AllocateCluster(disk, cluster); - if(!tmp) return 0; + if(!tmp) { + LEAVE('i', 0); + return 0; + } cluster = tmp; Offset -= disk->BytesPerCluster; } @@ -509,17 +555,20 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffe { char tmpBuf[disk->BytesPerCluster]; + LOG("Read-Modify-Write single"); + // Read-Modify-Write FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf ); memcpy( tmpBuf + Offset, Buffer, Length ); FAT_int_WriteCluster( disk, cluster, tmpBuf ); - - return Length; + goto return_full; } // Clean up changes within a cluster if( Offset ) { + LOG("Read-Modify-Write first"); + // Read-Modify-Write FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf ); memcpy( tmpBuf + Offset, Buffer, disk->BytesPerCluster - Offset ); @@ -530,11 +579,10 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffe // Get next cluster (allocating if needed) tmpCluster = FAT_int_GetFatValue(disk, cluster); - if(tmpCluster == -1) { + if(tmpCluster == GETFATVALUE_EOC) { tmpCluster = FAT_int_AllocateCluster(disk, cluster); - if( tmpCluster == 0 ) { - return Length - remLength; - } + if( tmpCluster == 0 ) + goto ret_incomplete; } cluster = tmpCluster; } @@ -543,28 +591,47 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffe { FAT_int_WriteCluster( disk, cluster, Buffer ); Buffer += disk->BytesPerCluster; + remLength -= disk->BytesPerCluster; // Get next cluster (allocating if needed) tmpCluster = FAT_int_GetFatValue(disk, cluster); - if(tmpCluster == -1) { + if(tmpCluster == GETFATVALUE_EOC) { bNewCluster = 1; tmpCluster = FAT_int_AllocateCluster(disk, cluster); - if( tmpCluster == 0 ) { - return Length - remLength; - } + if( tmpCluster == 0 ) + goto ret_incomplete; } cluster = tmpCluster; } // Finish off - if( bNewCluster ) - memset(tmpBuf, 0, disk->BytesPerCluster); - else - FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf ); - memcpy( tmpBuf, Buffer, remLength ); - FAT_int_WriteCluster( disk, cluster, tmpBuf ); - free( tmpBuf ); - + if( remLength ) + { + if( bNewCluster ) + memset(tmpBuf, 0, disk->BytesPerCluster); + else + FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf ); + memcpy( tmpBuf, Buffer, remLength ); + FAT_int_WriteCluster( disk, cluster, tmpBuf ); + } + +return_full: + if( original_offset + Length > Node->Size ) { + Node->Size = original_offset + Length; + LOG("Updated size to %x", Node->Size); + Node->ImplInt |= FAT_FLAG_DIRTY; + } + + LEAVE('i', Length); + return Length; +ret_incomplete: + LOG("Write incomplete"); + Length -= remLength; + if( original_offset + Length > Node->Size ) { + Node->Size = original_offset + Length; + Node->ImplInt |= FAT_FLAG_DIRTY; + } + LEAVE('i', Length); return Length; } #endif @@ -577,7 +644,9 @@ void FAT_CloseFile(tVFS_Node *Node) { tFAT_VolInfo *disk = Node->ImplPtr; if(Node == NULL) return ; - + + ENTER("pNode", Node); + #if SUPPORT_WRITE // Update the node if it's dirty (don't bother if it's marked for // deletion) @@ -589,6 +658,7 @@ void FAT_CloseFile(tVFS_Node *Node) dirnode = FAT_int_CreateIncompleteDirNode(disk, Node->Inode >> 32); if( !dirnode ) { Log_Error("FAT", "Can't get node for directory cluster #0x%x", Node->Inode>>32); + LEAVE('-'); return ; } @@ -619,4 +689,5 @@ void FAT_CloseFile(tVFS_Node *Node) } } #endif + LEAVE('-'); }