From 0ea39901119279ee9bb9cf8270b2a0d65cb7460f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 12 Jul 2012 16:50:09 +0800 Subject: [PATCH] Modules/FAT - Implimentation of FAT_Link, validity unknown but it compiles --- KernelLand/Modules/Filesystems/FAT/common.h | 2 +- KernelLand/Modules/Filesystems/FAT/dir.c | 271 ++++++++++++++++-- KernelLand/Modules/Filesystems/FAT/fat.c | 33 ++- KernelLand/Modules/Filesystems/FAT/fatio.c | 43 ++- .../Modules/Filesystems/FAT/nodecache.c | 17 +- 5 files changed, 310 insertions(+), 56 deletions(-) diff --git a/KernelLand/Modules/Filesystems/FAT/common.h b/KernelLand/Modules/Filesystems/FAT/common.h index 340fff08..5f8539c5 100644 --- a/KernelLand/Modules/Filesystems/FAT/common.h +++ b/KernelLand/Modules/Filesystems/FAT/common.h @@ -91,7 +91,7 @@ extern int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint extern tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry); extern tVFS_Node *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster); extern tVFS_Node *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster); -extern void FAT_int_DerefNode(tVFS_Node *Node); +extern int FAT_int_DerefNode(tVFS_Node *Node); extern void FAT_int_ClearNodeCache(tFAT_VolInfo *Disk); // --- FAT Access --- diff --git a/KernelLand/Modules/Filesystems/FAT/dir.c b/KernelLand/Modules/Filesystems/FAT/dir.c index f639a0b6..3154b17c 100644 --- a/KernelLand/Modules/Filesystems/FAT/dir.c +++ b/KernelLand/Modules/Filesystems/FAT/dir.c @@ -114,6 +114,7 @@ int FAT_int_CompareUTF16_UTF8(const Uint16 *Str16, const char *Str8) Uint32 cp8, cp16; if( Str16[pos16] & 0x8000 ) { // Do something! + cp16 = 0; } else { cp16 = Str16[pos16]; @@ -154,7 +155,7 @@ int FAT_int_ConvertUTF16_to_UTF8(Uint8 *Dest, const Uint16 *Source) int FAT_int_ConvertUTF8_to_UTF16(Uint16 *Dest, const Uint8 *Source) { int len = 0; - for( ; *Source; Source ++ ) + while( *Source ) { Uint32 cp; int cpl; @@ -211,6 +212,8 @@ int FAT_int_GetEntryByName(tVFS_Node *DirNode, const char *Name, fat_filetable * int lfnId = -1; #endif + ENTER("pDirNode sName pEntry", DirNode, Name, Entry); + for( int i = 0; ; i++ ) { if((i & 0xF) == 0) { @@ -363,6 +366,37 @@ int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer) } #if SUPPORT_WRITE +/** + * \brief Write a sector to the disk + * \param Node Directory node to write + * \param Sector Sector number in the directory to write + * \param Buffer Source data + */ +int FAT_int_WriteDirSector(tVFS_Node *Node, int Sector, const fat_filetable *Buffer) +{ + Uint64 addr; + tFAT_VolInfo *disk = Node->ImplPtr; + + ENTER("pNode iSector pEntry", Node, Sector, Buffer); + + // Parse address + if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL)) + { + LEAVE('i', 1); + return 1; + } + + // Read Sector + if(VFS_WriteAt(disk->fileHandle, addr, 512, Buffer) != 512) + { + LEAVE('i', 1); + return 1; + } + + LEAVE('i', 0); + return 0; +} + /** * \brief Writes an entry to the disk * \todo Support expanding a directory @@ -396,8 +430,8 @@ int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry) LOG("addr = 0x%llx", addr); - // Read Sector - VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry); // Read Dir Data + // Wriet data to disk + VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry); LEAVE('i', 0); return 0; @@ -677,6 +711,8 @@ int FAT_Mknod(tVFS_Node *DirNode, const char *Name, Uint Flags) int rv; fat_filetable ft; memset(&ft, 0, sizeof(ft)); + + ENTER("pDirNode sName xFlags", DirNode, Name, Flags); // Allocate a cluster Uint32 cluster = FAT_int_AllocateCluster(disk, -1); @@ -699,10 +735,10 @@ int FAT_Mknod(tVFS_Node *DirNode, const char *Name, Uint Flags) // Call link if( (rv = FAT_Link(DirNode, Name, newnode)) ) { - newnode->Flags |= FAT_FLAG_DELETE; + newnode->ImplInt |= FAT_FLAG_DELETE; } - LOG("rv = %i", rv); FAT_CloseFile(newnode); + LEAVE('i', rv); return rv; } @@ -715,7 +751,11 @@ static inline int is_valid_83_char(char ch) return 1; if( 'A' <= ch && ch <= 'Z' ) return 1; - return 0; + if( 'a' <= ch && ch <= 'z' ) + return 0; + if( strchr(";+=[]',\"*\\<>/?:| ", ch) ) + return 0; + return 1; } /** @@ -724,6 +764,10 @@ static inline int is_valid_83_char(char ch) int FAT_int_IsValid83Filename(const char *Name) { int i, j; + + if( !Name[0] || Name[0] == '.' ) + return 0; + // Check filename portion for( i = 0; Name[i] && i < 8; i ++ ) { @@ -760,37 +804,224 @@ int FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *NewNode) Uint16 lfn[256]; fat_filetable ft; int nLFNEnt = 0; + const int eps = 512 / sizeof(fat_filetable); + fat_filetable fileinfo[eps]; + + Mutex_Acquire( &DirNode->Lock ); + + // -- Ensure duplicates aren't created -- + if( FAT_int_GetEntryByName(DirNode, NewName, &ft) >= 0 ) { + Mutex_Release( &DirNode->Lock ); + return EEXIST; + } // -- Create filetable entry -- int bNeedsLFN = !FAT_int_IsValid83Filename(NewName); if( bNeedsLFN ) { int lfnlen = FAT_int_ConvertUTF8_to_UTF16(lfn, (const Uint8*)NewName); + lfn[lfnlen] = 0; nLFNEnt = DivUp(lfnlen, 13); - // Create mangled filetable entry - // - Requires checking for duplicates - Log_Warning("FAT", "FAT_Link - LFN Mangling unimplimented"); + // Create a base mangled filetable entry + int i, j = 0; + while(NewName[j] == '.') j ++; // Eat leading dots + for( i = 0; i < 6 && NewName[j] && NewName[j] != '.'; i ++, j ++ ) + { + if( !isalpha(NewName[j]) && !is_valid_83_char(NewName[j]) ) + ft.name[i] = '_'; + else + ft.name[i] = toupper(NewName[j]); + } + ft.name[i++] = '~'; + ft.name[i++] = '0'; + while(i < 8) ft.name[i++] = ' '; + while(NewName[j] && NewName[j] != '.') j ++; + for( ; i < 8+3 && NewName[j]; i ++, j ++ ) + { + if( NewName[j] == '.' ) + i --; + else if( !is_valid_83_char(NewName[j]) ) + ft.name[i] = '_'; + else + ft.name[i] = toupper(NewName[j]); + } + while(i < 8+3) ft.name[i++] = ' '; + + // - Ensure there isn't a duplicate short-name + int bIsDuplicate = 1; + while( bIsDuplicate ) + { + bIsDuplicate = 0; // Assume none + + // Scan directory + for( int id = 0; ; id ++ ) + { + if( id % eps == 0 ) + { + if(FAT_int_ReadDirSector(DirNode, id/eps, fileinfo)) + break; // end of cluster chain + } + + // End of file list + if( fileinfo[id%eps].name[0] == '\0' ) break; + // Empty entry + if( fileinfo[id%eps].name[0] == '\xE5' ) continue; + // LFN entry + if( fileinfo[id%eps].attrib == ATTR_LFN ) continue; + + // Is this a duplicate? + if( memcmp(ft.name, fileinfo[id%eps].name, 8+3) == 0 ) { + bIsDuplicate = 1; + break; + } + + // No - move a long + } + + // If a duplicate was found, increment the suffix + if( bIsDuplicate ) + { + if( ft.name[7] == '9' ) { + // TODO: Expand into ~00 + Log_Error("FAT", "TODO: Use two digit LFN suffixes"); + Mutex_Release(&DirNode->Lock); + return ENOTIMPL; + } + + ft.name[7] += 1; + } + } } else { // Create pure filetable entry - Log_Warning("FAT", "FAT_Link - Filename translation unimplimented"); + int i; + // - Copy filename + for( i = 0; i < 8 && *NewName && *NewName != '.'; i ++, NewName++ ) + ft.name[i] = *NewName; + // - Pad with spaces + for( ; i < 8; i ++ ) + ft.name[i] = ' '; + // - Eat '.' + if(*NewName) + NewName ++; + // - Copy extension + for( ; i < 8+3 && *NewName; i ++, NewName++ ) + ft.name[i] = *NewName; + // - Pad with spaces + for( ; i < 8+3; i ++ ) + ft.name[i] = ' '; } - - ft.size = NewNode->Size; - // -- Add entry to the directory -- - Mutex_Acquire( &DirNode->Lock ); + ft.attrib = 0; + if(NewNode->Flags & VFS_FFLAG_DIRECTORY ) + ft.attrib |= ATTR_DIRECTORY; + // TODO: Fill in creation/modifcation times + ft.clusterHi = LittleEndian16((NewNode->Inode >> 16) & 0xFFFF); + ft.cluster = LittleEndian16(NewNode->Inode & 0xFFFF); + ft.size = LittleEndian32(NewNode->Size); + + LOG("ft.name = '%.11s'", ft.name); + // -- Add entry to the directory -- // Locate a range of nLFNEnt + 1 free entries - // - If there are none, defragment the directory? - // - Else, expand the directory - // - and if that fails, return an error - Log_Warning("FAT", "FAT_Link - Free entry scanning unimplimented"); + int end_id = -1; + int range_first = 0, range_last = -1; + for( int id = 0; ; id ++ ) + { + if( id % eps == 0 ) + { + if(FAT_int_ReadDirSector(DirNode, id/eps, fileinfo)) + break; // end of cluster chain + } + + // End of file list, break out + if( fileinfo[id%eps].name[0] == '\0' ) { + if( id - range_first == nLFNEnt ) + range_last = id; + end_id = id; + break; + } + + // If an entry is occupied, clear the range + if( fileinfo[id%eps].name[0] != '\xE5' ) { + range_first = id + 1; + continue ; + } + + // Free entry, check if we have enough + if( id - range_first == nLFNEnt ) { + range_last = id; + break; + } + // Check the next one + } + if( range_last == -1 ) + { + // - If there are none, defragment the directory? + + // - Else, expand the directory + if( end_id == -1 ) { + // End of cluster chain + } + else { + // Just end of block + } + // - and if that fails, return an error + Log_Warning("FAT", "TODO: Impliment directory expansion / defragmenting"); + Mutex_Release(&DirNode->Lock); + return ENOTIMPL; + } + + // Insert entries + if( range_first % eps != 0 ) + FAT_int_ReadDirSector(DirNode, range_first/eps, fileinfo); + for( int id = range_first; id <= range_last; id ++ ) + { + if( id % eps == 0 ) { + if( id != range_first ) + FAT_int_WriteDirSector(DirNode, (id-1)/eps, fileinfo); + FAT_int_ReadDirSector(DirNode, id/eps, fileinfo); + } + + if( id == range_last ) { + // Actual entry + memcpy(fileinfo + id % eps, &ft, sizeof(fat_filetable)); + } + else { + // Long filename + int lfnid = (nLFNEnt - (id - range_first)); + int ofs = (lfnid-1) * 13; + int i=0, j=0; + fat_longfilename *lfnent = (void*)( fileinfo + id%eps ); + + lfnent->id = 0x40 | lfnid; + lfnent->attrib = ATTR_LFN; + lfnent->type = 0; + lfnent->firstCluster = 0; + lfnent->checksum = 0; // ??? + + for( i = 0; i < 13; i ++ ) + { + Uint16 wd; + if( (wd = lfn[ofs+j]) ) j ++; + wd = LittleEndian16(wd); + if(i < 5) + lfnent->name1[i ] = wd; + else if( i < 5+6 ) + lfnent->name2[i-5 ] = wd; + else + lfnent->name3[i-5-6] = wd; + } + + lfnent->checksum = 0; // ??? + } + } + FAT_int_WriteDirSector(DirNode, range_last/eps, fileinfo); Mutex_Release( &DirNode->Lock ); - return ENOTIMPL; + return 0; } /** @@ -820,7 +1051,7 @@ int FAT_Unlink(tVFS_Node *Node, const char *OldName) // TODO: If it has a LFN, remove that too // Delete from the directory - ft.name[0] = '\xE9'; + ft.name[0] = '\xE5'; FAT_int_WriteDirEntry(Node, id, &ft); // Close child diff --git a/KernelLand/Modules/Filesystems/FAT/fat.c b/KernelLand/Modules/Filesystems/FAT/fat.c index 07066975..f7dd8c52 100644 --- a/KernelLand/Modules/Filesystems/FAT/fat.c +++ b/KernelLand/Modules/Filesystems/FAT/fat.c @@ -17,7 +17,7 @@ * \todo Implement changing of the parent directory when a file is written to * \todo Implement file creation / deletion */ -#define DEBUG 1 +#define DEBUG 0 #define VERBOSE 1 #include @@ -43,7 +43,7 @@ void FAT_CloseFile(tVFS_Node *node); int giFAT_MaxCachedClusters = 1024*512/4; // === SEMI-GLOBALS === -MODULE_DEFINE(0, VER2(1,1) /*v1.01*/, VFAT, FAT_Install, NULL, NULL); +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}; @@ -295,7 +295,7 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu ENTER("pNode XOffset", Node, Offset); cluster = base_cluster = Node->Inode & 0xFFFFFFF; // Cluster ID - LOG("base cluster = 0x%07x", cluster); +// LOG("base cluster = 0x%07x", cluster); // Do Cluster Skip // - Pre FAT32 had a reserved area for the root. @@ -315,12 +315,12 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu } else { // TODO: Bounds checking on root - LOG("Root cluster count %i", disk->bootsect.files_in_root*32/disk->BytesPerCluster); +// LOG("Root cluster count %i", disk->bootsect.files_in_root*32/disk->BytesPerCluster); // Increment by clusters in offset cluster += Offset / disk->BytesPerCluster; } - LOG("cluster = 0x%07x", cluster); +// LOG("cluster = 0x%07x", cluster); // Bounds Checking (Used to spot corruption) if(cluster > disk->ClusterCount + 2) @@ -602,22 +602,21 @@ void FAT_CloseFile(tVFS_Node *Node) Node->ImplInt &= ~FAT_FLAG_DIRTY; } #endif + + Uint32 cluster = Node->Inode; + Uint32 implint = Node->ImplInt; - // TODO: Make this more thread safe somehow, probably by moving the - // Inode_UncacheNode higher up and saving the cluster value somewhere - if( Node->ReferenceCount == 1 ) - { - #if SUPPORT_WRITE + #if SUPPORT_WRITE + if( FAT_int_DerefNode(Node) == 1 ) + { + LOG("implint = %x", implint); // Delete File - if( Node->ImplInt & FAT_FLAG_DELETE ) { + if( implint & FAT_FLAG_DELETE ) { + Log_Debug("FAT", "Deallocating chain stating at 0x%07x", cluster); // Since the node is marked, we only need to remove it's data - Uint32 cluster = Node->Inode & 0xFFFFFFFF; while( cluster != -1 ) - cluster = FAT_int_FreeCluster(Node->ImplPtr, cluster); + cluster = FAT_int_FreeCluster(disk, cluster); } - #endif } - - FAT_int_DerefNode(Node); - return ; + #endif } diff --git a/KernelLand/Modules/Filesystems/FAT/fatio.c b/KernelLand/Modules/Filesystems/FAT/fatio.c index 43bd6226..ab49b30b 100644 --- a/KernelLand/Modules/Filesystems/FAT/fatio.c +++ b/KernelLand/Modules/Filesystems/FAT/fatio.c @@ -58,20 +58,22 @@ Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster) */ Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous) { - Uint32 ret = -1, eoc; - - switch(Disk->type) - { - case FAT12: eoc = EOC_FAT12; break; - case FAT16: eoc = EOC_FAT16; break; - case FAT32: eoc = EOC_FAT32; break; - default: return 0; - } + Uint32 ret = -1; #if CACHE_FAT if( Disk->ClusterCount <= giFAT_MaxCachedClusters ) { int bFoundCluster = 0; + Uint32 eoc; + + switch(Disk->type) + { + case FAT12: eoc = EOC_FAT12; break; + case FAT16: eoc = EOC_FAT16; break; + case FAT32: eoc = EOC_FAT32; break; + default: return 0; + } + Mutex_Acquire(&Disk->lFAT); if( Previous != -1 ) { @@ -201,6 +203,13 @@ Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous) Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster) { Uint32 ret; + + if( Cluster < 2 || Cluster > Disk->ClusterCount ) // oops? + { + Log_Notice("FAT", "Cluster 0x%x is out of range (2 ... 0x%x)", + Cluster, Disk->ClusterCount-1); + return -1; + } Mutex_Acquire(&Disk->lFAT); #if CACHE_FAT @@ -213,40 +222,50 @@ Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster) else { #endif - Uint32 val; + Uint32 val = 0; Uint32 ofs = Disk->bootsect.resvSectCount*512; switch(Disk->type) { case FAT12: VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val); + val = LittleEndian32(val); if( Cluster & 1 ) { - ret = val & 0xFFF0000; + ret = (val >> 12) & 0xFFF; val &= 0xFFF; } else { ret = val & 0xFFF; val &= 0xFFF000; } + val = LittleEndian32(val); VFS_WriteAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val); break; case FAT16: VFS_ReadAt(Disk->fileHandle, ofs+Cluster*2, 2, &ret); + ret = LittleEndian16(ret); val = 0; VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val); break; case FAT32: VFS_ReadAt(Disk->fileHandle, ofs+Cluster*4, 4, &ret); + ret = LittleEndian32(ret); val = 0; - VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val); + VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 4, &val); break; } #if CACHE_FAT } #endif Mutex_Release(&Disk->lFAT); + LOG("ret = %07x, eoc = %07x", ret, EOC_FAT12); + if(ret == 0) { + Log_Notice("FAT", "Cluster 0x%x was already free", Cluster); + return -1; + } if(Disk->type == FAT12 && ret == EOC_FAT12) ret = -1; if(Disk->type == FAT16 && ret == EOC_FAT16) ret = -1; if(Disk->type == FAT32 && ret == EOC_FAT32) ret = -1; + LOG("ret = %07x", ret); return ret; } #endif diff --git a/KernelLand/Modules/Filesystems/FAT/nodecache.c b/KernelLand/Modules/Filesystems/FAT/nodecache.c index e181e98e..c862dca5 100644 --- a/KernelLand/Modules/Filesystems/FAT/nodecache.c +++ b/KernelLand/Modules/Filesystems/FAT/nodecache.c @@ -155,13 +155,14 @@ tVFS_Node *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node) return &cnode->Node; } -void FAT_int_DerefNode(tVFS_Node *Node) +int FAT_int_DerefNode(tVFS_Node *Node) { tFAT_VolInfo *Disk = Node->ImplPtr; tFAT_CachedNode *cnode, *prev = NULL; + int bFreed = 0; if( Node == &Disk->rootNode ) - return ; + return 0; Mutex_Acquire(&Disk->lNodeCache); Node->ReferenceCount --; @@ -175,15 +176,19 @@ void FAT_int_DerefNode(tVFS_Node *Node) break; } } + if(Node->ReferenceCount == 0 && cnode) { + // Already out of the list :) + free(cnode->Node.Data); + free(cnode); + bFreed = 1; + } Mutex_Release(&Disk->lNodeCache); if( !cnode ) { // Not here? - return ; + return -1; } - // Already out of the list :) - free(cnode->Node.Data); - free(cnode); + return bFreed; } void FAT_int_ClearNodeCache(tFAT_VolInfo *Disk) -- 2.20.1