Kernel - Added 'Flags' param to VFS Read/Write/FindDir
[tpg/acess2.git] / KernelLand / Modules / Filesystems / FAT / nodecache.c
1 /*
2  * Acess2 FAT12/16/32 Driver
3  * - By John Hodge (thePowersGang)
4  *
5  * nodecache.c
6  * - FAT-Specific node caching
7  */
8 #include <acess.h>
9 #include <vfs.h>
10 #include "common.h"
11
12 // === PROTOTYPES ===
13 extern tVFS_Node        *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node);
14
15 // === CODE ===
16 tTime FAT_int_GetAcessTimestamp(Uint16 Date, Uint16 Time, Uint8 MS)
17 {
18         return MS * 10 + timestamp(
19                 // Seconds         Minutes              Hours
20                 (Time & 0x1F) * 2, (Time >> 5) & 0x3F, (Time >> 11) & 0x1F,
21                 // Day             Month                    Year
22                 (Date & 0x1F) - 1, ((Date >> 5) & 0xF) - 1, 1980 + ((Date >> 9) & 0xFF)
23                 );
24 }
25
26 void FAT_int_GetFATTimestamp(tTime AcessTimestamp, Uint16 *Date, Uint16 *Time, Uint8 *MS)
27 {
28          int    y, m, d;
29          int    h, min, s, ms;
30         format_date(AcessTimestamp, &y, &m, &d, &h, &min, &s, &ms);
31         if(Date)
32                 *Date = (d + 1) | ((m + 1) << 5) | ((y - 1980) << 9);
33         if(Time)
34                 *Time = (s / 2) | (min << 5) | (h << 11);
35         if(MS)
36                 *MS = (ms / 10) + (s & 1) * 100;
37 }
38
39 /**
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
43  */
44 tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry)
45 {
46         tVFS_Node       node;
47         tVFS_Node       *ret;
48         tFAT_VolInfo    *disk = Parent->ImplPtr;
49
50         ENTER("pParent pEntry", Parent, Entry);
51         LOG("disk = %p", disk);
52         
53         if( (ret = FAT_int_GetNode(disk, Entry->cluster | (Entry->clusterHi<<16))) )
54         {
55                 if( (ret->Inode >> 32) != 0 )
56                 {
57                         LEAVE('p', ret);
58                         return ret;
59                 }
60         }
61         else
62         {
63                 ret = &node;
64                 memset(ret, 0, sizeof(tVFS_Node));
65         }
66         
67         // Set Other Data
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);
71         ret->ImplInt = 0;
72         // Disk Pointer
73         ret->ImplPtr = disk;
74         ret->Size = Entry->size;
75         LOG("Entry->size = %i", Entry->size);
76         // root:root
77         ret->UID = 0;   ret->GID = 0;
78         ret->NumACLs = 1;
79         
80         ret->Flags = 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
86         }
87         else {
88                 ret->ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX
89         }
90         
91         // Create timestamps
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);
95         
96         // Set pointers
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;      
100                 ret->Size = -1;
101         }
102         else {
103                 ret->Type = &gFAT_FileType;
104         }
105
106         // Cache node only if we're not updating a cache
107         if( ret == &node ) {
108                 ret = FAT_int_CacheNode(disk, &node);
109         }
110         
111         LEAVE('p', ret);
112         return ret;
113 }
114
115 tVFS_Node *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster)
116 {
117         if( Cluster == Disk->rootOffset )
118                 return &Disk->rootNode;
119         
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?
123         
124         Mutex_Acquire(&Disk->lNodeCache);
125         tFAT_CachedNode *cnode, *prev = NULL;
126
127         for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next)
128         {
129                 if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
130                         cnode->Node.ReferenceCount ++;
131                         Mutex_Release(&Disk->lNodeCache);
132                         return &cnode->Node;
133                 }
134         }       
135
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;
143
144         if( prev )
145                 prev->Next = cnode;
146         else
147                 Disk->NodeCache = cnode;
148
149         Mutex_Release(&Disk->lNodeCache);
150         return &cnode->Node;
151 }
152
153 tVFS_Node *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster)
154 {
155         if( Cluster == Disk->rootOffset )
156                 return &Disk->rootNode;
157         Mutex_Acquire(&Disk->lNodeCache);
158         tFAT_CachedNode *cnode;
159
160         for(cnode = Disk->NodeCache; cnode; cnode = cnode->Next)
161         {
162                 if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
163                         cnode->Node.ReferenceCount ++;
164                         Mutex_Release(&Disk->lNodeCache);
165                         return &cnode->Node;
166                 }
167         }
168
169         Mutex_Release(&Disk->lNodeCache);
170         return NULL;
171 }
172
173 tVFS_Node *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node)
174 {
175         tFAT_CachedNode *cnode, *prev = NULL;
176         Mutex_Acquire(&Disk->lNodeCache);
177         
178         for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
179         {
180                 if( cnode->Node.Inode == Node->Inode ) {
181                         cnode->Node.ReferenceCount ++;
182                         Mutex_Release(&Disk->lNodeCache);
183                         return &cnode->Node;
184                 }
185         }
186         
187         cnode = malloc(sizeof(tFAT_CachedNode));
188         cnode->Next = NULL;
189         memcpy(&cnode->Node, Node, sizeof(tVFS_Node));
190         cnode->Node.ReferenceCount = 1;
191         
192         if( prev )
193                 prev->Next = cnode;
194         else
195                 Disk->NodeCache = cnode;
196         
197         Mutex_Release(&Disk->lNodeCache);
198         return &cnode->Node;
199 }
200
201 int FAT_int_DerefNode(tVFS_Node *Node)
202 {
203         tFAT_VolInfo    *Disk = Node->ImplPtr;
204         tFAT_CachedNode *cnode, *prev = NULL;
205          int    bFreed = 0;
206
207         if( Node == &Disk->rootNode )
208                 return 0;
209
210         Mutex_Acquire(&Disk->lNodeCache);
211         Node->ReferenceCount --;
212         for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
213         {
214                 if(Node == &cnode->Node) {
215                         if(prev)
216                                 prev->Next = cnode->Next;
217                         else
218                                 Disk->NodeCache = cnode->Next;
219                         break;
220                 }
221         }
222         if(Node->ReferenceCount == 0 && cnode) {
223                 // Already out of the list :)
224                 if(cnode->Node.Data)
225                         free(cnode->Node.Data);
226                 VFS_CleanupNode(&cnode->Node);
227                 free(cnode);
228                 bFreed = 1;
229         }
230         Mutex_Release(&Disk->lNodeCache);
231         if( !cnode ) {
232                 // Not here?
233                 return -1;
234         }
235         
236         return bFreed;
237 }
238
239 void FAT_int_ClearNodeCache(tFAT_VolInfo *Disk)
240 {
241         // TODO: In theory when this is called, all handles will be closed
242 }

UCC git Repository :: git.ucc.asn.au