2 * Acess2 FAT12/16/32 Driver
3 * - By John Hodge (thePowersGang)
6 * - FAT-Specific node caching
13 extern tVFS_Node *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node);
16 tTime FAT_int_GetAcessTimestamp(Uint16 Date, Uint16 Time, Uint8 MS)
18 return MS * 10 + timestamp(
19 // Seconds Minutes Hours
20 (Time & 0x1F) * 2, (Time >> 5) & 0x3F, (Time >> 11) & 0x1F,
22 (Date & 0x1F) - 1, ((Date >> 5) & 0xF) - 1, 1980 + ((Date >> 9) & 0xFF)
26 void FAT_int_GetFATTimestamp(tTime AcessTimestamp, Uint16 *Date, Uint16 *Time, Uint8 *MS)
30 format_date(AcessTimestamp, &y, &m, &d, &h, &min, &s, &ms);
32 *Date = (d + 1) | ((m + 1) << 5) | ((y - 1980) << 9);
34 *Time = (s / 2) | (min << 5) | (h << 11);
36 *MS = (ms / 10) + (s & 1) * 100;
40 * \brief Creates a tVFS_Node structure for a given file entry
41 * \param Parent Parent directory VFS node
42 * \param Entry File table entry for the new node
44 tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry)
48 tFAT_VolInfo *disk = Parent->ImplPtr;
50 ENTER("pParent pEntry", Parent, Entry);
51 LOG("disk = %p", disk);
53 if( (ret = FAT_int_GetNode(disk, Entry->cluster | (Entry->clusterHi<<16))) )
55 if( (ret->Inode >> 32) != 0 )
64 memset(ret, 0, sizeof(tVFS_Node));
68 // 0-27: Cluster, 32-59: Parent Cluster
69 ret->Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);
70 LOG("node.Inode = %llx", ret->Inode);
74 ret->Size = Entry->size;
75 LOG("Entry->size = %i", Entry->size);
77 ret->UID = 0; ret->GID = 0;
81 if(Entry->attrib & ATTR_DIRECTORY)
82 ret->Flags |= VFS_FFLAG_DIRECTORY;
83 if(Entry->attrib & ATTR_READONLY) {
84 ret->Flags |= VFS_FFLAG_READONLY;
85 ret->ACLs = &gVFS_ACL_EveryoneRX; // R-XR-XR-X
88 ret->ACLs = &gVFS_ACL_EveryoneRWX; // RWXRWXRWX
92 ret->CTime = FAT_int_GetAcessTimestamp(Entry->cdate, Entry->ctime, Entry->ctimems);
93 ret->MTime = FAT_int_GetAcessTimestamp(Entry->mdate, Entry->mtime, 0);
94 ret->ATime = FAT_int_GetAcessTimestamp(Entry->adate, 0, 0);
97 if(ret->Flags & VFS_FFLAG_DIRECTORY) {
98 //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);
99 ret->Type = &gFAT_DirType;
103 ret->Type = &gFAT_FileType;
106 // Cache node only if we're not updating a cache
108 ret = FAT_int_CacheNode(disk, &node);
115 tVFS_Node *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster)
117 if( Cluster == Disk->rootOffset )
118 return &Disk->rootNode;
120 // If the directory isn't in the cache, what do?
121 // - we want to lock it such that we don't collide, but don't want to put crap data in the cache
122 // - Put a temp node in with a flag that indicates it's incomplete?
124 Mutex_Acquire(&Disk->lNodeCache);
125 tFAT_CachedNode *cnode, *prev = NULL;
127 for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next)
129 if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
130 cnode->Node.ReferenceCount ++;
131 Mutex_Release(&Disk->lNodeCache);
136 // Create a temporary node?
137 cnode = calloc( sizeof(tFAT_CachedNode), 1 );
138 cnode->Node.Inode = Cluster;
139 cnode->Node.ReferenceCount = 1;
140 cnode->Node.ImplPtr = Disk;
141 cnode->Node.Type = &gFAT_DirType;
142 cnode->Node.Size = -1;
147 Disk->NodeCache = cnode;
149 Mutex_Release(&Disk->lNodeCache);
153 tVFS_Node *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster)
155 if( Cluster == Disk->rootOffset )
156 return &Disk->rootNode;
157 Mutex_Acquire(&Disk->lNodeCache);
158 tFAT_CachedNode *cnode;
160 for(cnode = Disk->NodeCache; cnode; cnode = cnode->Next)
162 if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
163 cnode->Node.ReferenceCount ++;
164 Mutex_Release(&Disk->lNodeCache);
169 Mutex_Release(&Disk->lNodeCache);
173 tVFS_Node *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node)
175 tFAT_CachedNode *cnode, *prev = NULL;
176 Mutex_Acquire(&Disk->lNodeCache);
178 for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
180 if( cnode->Node.Inode == Node->Inode ) {
181 cnode->Node.ReferenceCount ++;
182 Mutex_Release(&Disk->lNodeCache);
187 cnode = malloc(sizeof(tFAT_CachedNode));
189 memcpy(&cnode->Node, Node, sizeof(tVFS_Node));
190 cnode->Node.ReferenceCount = 1;
195 Disk->NodeCache = cnode;
197 Mutex_Release(&Disk->lNodeCache);
201 int FAT_int_DerefNode(tVFS_Node *Node)
203 tFAT_VolInfo *Disk = Node->ImplPtr;
204 tFAT_CachedNode *cnode, *prev = NULL;
207 if( Node == &Disk->rootNode )
210 Mutex_Acquire(&Disk->lNodeCache);
211 Node->ReferenceCount --;
212 for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
214 if(Node == &cnode->Node) {
216 prev->Next = cnode->Next;
218 Disk->NodeCache = cnode->Next;
222 if(Node->ReferenceCount == 0 && cnode) {
223 // Already out of the list :)
225 free(cnode->Node.Data);
226 VFS_CleanupNode(&cnode->Node);
230 Mutex_Release(&Disk->lNodeCache);
239 void FAT_int_ClearNodeCache(tFAT_VolInfo *Disk)
241 // TODO: In theory when this is called, all handles will be closed