DiskTool - Added LVM support
[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                 LEAVE('p', ret);
55                 return ret;
56         }
57
58         memset(&node, 0, sizeof(tVFS_Node));
59         
60         // Set Other Data
61         // 0-27: Cluster, 32-59: Parent Cluster
62         node.Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);
63         LOG("node.Inode = %llx", node.Inode);
64         node.ImplInt = 0;
65         // Disk Pointer
66         node.ImplPtr = disk;
67         node.Size = Entry->size;
68         LOG("Entry->size = %i", Entry->size);
69         // root:root
70         node.UID = 0;   node.GID = 0;
71         node.NumACLs = 1;
72         
73         node.Flags = 0;
74         if(Entry->attrib & ATTR_DIRECTORY)      node.Flags |= VFS_FFLAG_DIRECTORY;
75         if(Entry->attrib & ATTR_READONLY) {
76                 node.Flags |= VFS_FFLAG_READONLY;
77                 node.ACLs = &gVFS_ACL_EveryoneRX;       // R-XR-XR-X
78         }
79         else {
80                 node.ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX
81         }
82         
83         // Create timestamps
84         node.CTime = FAT_int_GetAcessTimestamp(Entry->cdate, Entry->ctime, Entry->ctimems);
85         node.MTime = FAT_int_GetAcessTimestamp(Entry->mdate, Entry->mtime, 0);
86         node.ATime = FAT_int_GetAcessTimestamp(Entry->adate, 0, 0);
87         
88         // Set pointers
89         if(node.Flags & VFS_FFLAG_DIRECTORY) {
90                 //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);
91                 node.Type = &gFAT_DirType;      
92                 node.Size = -1;
93         }
94         else {
95                 node.Type = &gFAT_FileType;
96         }
97
98         // TODO: Cache node     
99         ret = FAT_int_CacheNode(disk, &node);
100         LEAVE('p', ret);
101         return ret;
102 }
103
104 tVFS_Node *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster)
105 {
106         if( Cluster == Disk->rootOffset )
107                 return &Disk->rootNode;
108         
109         // If the directory isn't in the cache, what do?
110         // - we want to lock it such that we don't collide, but don't want to put crap data in the cache
111         // - Put a temp node in with a flag that indicates it's incomplete?
112         
113         Mutex_Acquire(&Disk->lNodeCache);
114         tFAT_CachedNode *cnode;
115
116         for(cnode = Disk->NodeCache; cnode; cnode = cnode->Next)
117         {
118                 if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
119                         cnode->Node.ReferenceCount ++;
120                         Mutex_Release(&Disk->lNodeCache);
121                         return &cnode->Node;
122                 }
123         }       
124
125         // Create a temporary node?
126         Log_Warning("FAT", "TODO: Impliment FAT_int_CreateIncompleteDirNode()");
127
128         Mutex_Release(&Disk->lNodeCache);
129         return NULL;
130 }
131
132 tVFS_Node *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster)
133 {
134         if( Cluster == Disk->rootOffset )
135                 return &Disk->rootNode;
136         Mutex_Acquire(&Disk->lNodeCache);
137         tFAT_CachedNode *cnode;
138
139         for(cnode = Disk->NodeCache; cnode; cnode = cnode->Next)
140         {
141                 if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
142                         cnode->Node.ReferenceCount ++;
143                         Mutex_Release(&Disk->lNodeCache);
144                         return &cnode->Node;
145                 }
146         }       
147
148         Mutex_Release(&Disk->lNodeCache);
149         return NULL;
150 }
151
152 tVFS_Node *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node)
153 {
154         tFAT_CachedNode *cnode, *prev = NULL;
155         Mutex_Acquire(&Disk->lNodeCache);
156         
157         for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
158         {
159                 if( cnode->Node.Inode == Node->Inode ) {
160                         cnode->Node.ReferenceCount ++;
161                         Mutex_Release(&Disk->lNodeCache);
162                         return &cnode->Node;
163                 }
164         }
165         
166         cnode = malloc(sizeof(tFAT_CachedNode));
167         cnode->Next = NULL;
168         memcpy(&cnode->Node, Node, sizeof(tVFS_Node));
169         cnode->Node.ReferenceCount = 1;
170         
171         if( prev )
172                 prev->Next = cnode;
173         else
174                 Disk->NodeCache = cnode;
175         
176         Mutex_Release(&Disk->lNodeCache);
177         return &cnode->Node;
178 }
179
180 int FAT_int_DerefNode(tVFS_Node *Node)
181 {
182         tFAT_VolInfo    *Disk = Node->ImplPtr;
183         tFAT_CachedNode *cnode, *prev = NULL;
184          int    bFreed = 0;
185
186         if( Node == &Disk->rootNode )
187                 return 0;
188
189         Mutex_Acquire(&Disk->lNodeCache);
190         Node->ReferenceCount --;
191         for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
192         {
193                 if(Node == &cnode->Node) {
194                         if(prev)
195                                 prev->Next = cnode->Next;
196                         else
197                                 Disk->NodeCache = cnode->Next;
198                         break;
199                 }
200         }
201         if(Node->ReferenceCount == 0 && cnode) {
202                 // Already out of the list :)
203                 free(cnode->Node.Data);
204                 free(cnode);
205                 bFreed = 1;
206         }
207         Mutex_Release(&Disk->lNodeCache);
208         if( !cnode ) {
209                 // Not here?
210                 return -1;
211         }
212         
213         return bFreed;
214 }
215
216 void FAT_int_ClearNodeCache(tFAT_VolInfo *Disk)
217 {
218         // TODO: In theory when this is called, all handles will be closed
219 }

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