More work on Ext2 write (and fixed an error made earlier)
[tpg/acess2.git] / Modules / Filesystems / Ext2 / dir.c
1 /*
2  * Acess OS
3  * Ext2 Driver Version 1
4  */
5 /**
6  * \file dir.c
7  * \brief Second Extended Filesystem Driver
8  * \todo Implement file full write support
9  */
10 #define DEBUG   1
11 #define VERBOSE 0
12 #include "ext2_common.h"
13
14
15 // === PROTOTYPES ===
16 char    *Ext2_ReadDir(tVFS_Node *Node, int Pos);
17 tVFS_Node       *Ext2_FindDir(tVFS_Node *Node, char *FileName);
18  int    Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
19  int    Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, char *Name);
20 // --- Helpers ---
21 tVFS_Node       *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
22
23 // === CODE ===
24 /**
25  * \brief Reads a directory entry
26  * \param Node  Directory node
27  * \param Pos   Position of desired element
28  */
29 char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
30 {
31         tExt2_Inode     inode;
32         char    namebuf[EXT2_NAME_LEN+1];
33         tExt2_DirEnt    dirent;
34         Uint64  Base;   // Block's Base Address
35          int    block = 0, ofs = 0;
36          int    entNum = 0;
37         tExt2_Disk      *disk = Node->ImplPtr;
38         Uint    size;
39         
40         ENTER("pNode iPos", Node, Pos);
41         
42         // Read directory's inode
43         //Ext2_int_GetInode(Node, &inode);
44         Ext2_int_ReadInode(disk, Node->Inode, &inode);
45         size = inode.i_size;
46         
47         LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
48         
49         // Find Entry
50         // Get First Block
51         // - Do this ourselves as it is a simple operation
52         Base = inode.i_block[0] * disk->BlockSize;
53         // Scan directory
54         while(Pos -- && size > 0)
55         {
56                 VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
57                 ofs += dirent.rec_len;
58                 size -= dirent.rec_len;
59                 entNum ++;
60                 
61                 if(ofs >= disk->BlockSize) {
62                         block ++;
63                         if( ofs > disk->BlockSize ) {
64                                 Log_Warning("EXT2", "Directory Entry %i of inode %i extends over a block boundary, ignoring",
65                                         entNum-1, Node->Inode);
66                         }
67                         ofs = 0;
68                         Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
69                 }
70         }
71         
72         // Check for the end of the list
73         if(size <= 0) {
74                 LEAVE('n');
75                 return NULL;
76         }
77         
78         // Read Entry
79         VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );
80         //LOG("dirent.inode = %i", dirent.inode);
81         //LOG("dirent.rec_len = %i", dirent.rec_len);
82         //LOG("dirent.name_len = %i", dirent.name_len);
83         VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
84         namebuf[ dirent.name_len ] = '\0';      // Cap off string
85         
86         
87         // Ignore . and .. (these are done in the VFS)
88         if( (namebuf[0] == '.' && namebuf[1] == '\0')
89         ||  (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) {
90                 LEAVE('p', VFS_SKIP);
91                 return VFS_SKIP;        // Skip
92         }
93         
94         LEAVE('s', namebuf);
95         // Create new node
96         return strdup(namebuf);
97 }
98
99 /**
100  * \brief Gets information about a file
101  * \param Node  Parent Node
102  * \param Filename      Name of wanted file
103  * \return VFS Node of file
104  */
105 tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename)
106 {
107         tExt2_Disk      *disk = Node->ImplPtr;
108         tExt2_Inode     inode;
109         char    namebuf[EXT2_NAME_LEN+1];
110         tExt2_DirEnt    dirent;
111         Uint64  Base;   // Block's Base Address
112          int    block = 0, ofs = 0;
113          int    entNum = 0;
114         Uint    size;
115         
116         // Read directory's inode
117         Ext2_int_ReadInode(disk, Node->Inode, &inode);
118         size = inode.i_size;
119         
120         // Get First Block
121         // - Do this ourselves as it is a simple operation
122         Base = inode.i_block[0] * disk->BlockSize;
123         // Find File
124         while(size > 0)
125         {
126                 VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
127                 VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
128                 namebuf[ dirent.name_len ] = '\0';      // Cap off string
129                 // If it matches, create a node and return it
130                 if(strcmp(namebuf, Filename) == 0)
131                         return Ext2_int_CreateNode( disk, dirent.inode );
132                 // Increment pointers
133                 ofs += dirent.rec_len;
134                 size -= dirent.rec_len;
135                 entNum ++;
136                 
137                 // Check for end of block
138                 if(ofs >= disk->BlockSize) {
139                         block ++;
140                         if( ofs > disk->BlockSize ) {
141                                 Log_Warning("EXT2", "Directory Entry %i of inode %i extends over a block boundary, ignoring",
142                                         entNum-1, Node->Inode);
143                         }
144                         ofs = 0;
145                         Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
146                 }
147         }
148         
149         return NULL;
150 }
151
152 /**
153  * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
154  * \brief Create a new node
155  */
156 int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
157 {
158         #if 0
159         tVFS_Node       *child;
160         Uint64  inodeNum;
161         tExt2_Inode     inode;
162         inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode);
163         
164         memset(&inode, 0, sizeof(tExt2_Inode));
165         
166         // File type
167         inode.i_mode = 0664;
168         if( Flags & VFS_FFLAG_READONLY )
169                 inode.i_mode &= ~0222;
170         if( Flags & VFS_FFLAG_SYMLINK )
171                 inode.i_mode |= EXT2_S_IFLNK;
172         else if( Flags & VFS_FFLAG_DIRECTORY )
173                 inode.i_mode |= EXT2_S_IFDIR | 0111;
174         
175         inode.i_uid = Threads_GetUID();
176         inode.i_gid = Threads_GetGID();
177         inode.i_ctime =
178                 inode.i_mtime =
179                 inode.i_atime = now() / 1000;
180         
181         child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum);
182         return Ext2_Link(Parent, child, Name);
183         #else
184         return 1;
185         #endif
186 }
187
188 /**
189  * \brief Links an existing node to a new name
190  * \param Parent        Parent (directory) node
191  * \param Node  Node to link
192  * \param Name  New name for the node
193  * \return Boolean Failure - See ::tVFS_Node.Link for info
194  */
195 int Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, char *Name)
196 {
197         return 1;
198 }
199
200 // ---- INTERNAL FUNCTIONS ----
201 /**
202  * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
203  * \brief Create a new VFS Node
204  */
205 tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
206 {
207         tExt2_Inode     inode;
208         tVFS_Node       retNode;
209         tVFS_Node       *tmpNode;
210         
211         if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
212                 return NULL;
213         
214         if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )
215                 return tmpNode;
216         
217         
218         // Set identifiers
219         retNode.Inode = InodeID;
220         retNode.ImplPtr = Disk;
221         
222         // Set file length
223         retNode.Size = inode.i_size;
224         
225         // Set Access Permissions
226         retNode.UID = inode.i_uid;
227         retNode.GID = inode.i_gid;
228         retNode.NumACLs = 3;
229         retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
230         
231         //  Set Function Pointers
232         retNode.Read = Ext2_Read;
233         retNode.Write = Ext2_Write;
234         retNode.Close = Ext2_CloseFile;
235         
236         switch(inode.i_mode & EXT2_S_IFMT)
237         {
238         // Symbolic Link
239         case EXT2_S_IFLNK:
240                 retNode.Flags = VFS_FFLAG_SYMLINK;
241                 break;
242         // Regular File
243         case EXT2_S_IFREG:
244                 retNode.Flags = 0;
245                 retNode.Size |= (Uint64)inode.i_dir_acl << 32;
246                 break;
247         // Directory
248         case EXT2_S_IFDIR:
249                 retNode.ReadDir = Ext2_ReadDir;
250                 retNode.FindDir = Ext2_FindDir;
251                 retNode.MkNod = Ext2_MkNod;
252                 //retNode.Relink = Ext2_Relink;
253                 retNode.Link = Ext2_Link;
254                 retNode.Flags = VFS_FFLAG_DIRECTORY;
255                 break;
256         // Unknown, Write protect and hide it to be safe 
257         default:
258                 retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN;
259                 break;
260         }
261         
262         // Set Timestamps
263         retNode.ATime = inode.i_atime * 1000;
264         retNode.MTime = inode.i_mtime * 1000;
265         retNode.CTime = inode.i_ctime * 1000;
266         
267         // Save in node cache and return saved node
268         return Inode_CacheNode(Disk->CacheID, &retNode);
269 }

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