3 * Ext2 Driver Version 1
7 * \brief Second Extended Filesystem Driver
8 * \todo Implement file full write support
12 #include "ext2_common.h"
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);
21 tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
25 * \brief Reads a directory entry
26 * \param Node Directory node
27 * \param Pos Position of desired element
29 char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
32 char namebuf[EXT2_NAME_LEN+1];
34 Uint64 Base; // Block's Base Address
35 int block = 0, ofs = 0;
37 tExt2_Disk *disk = Node->ImplPtr;
40 ENTER("pNode iPos", Node, Pos);
42 // Read directory's inode
43 //Ext2_int_GetInode(Node, &inode);
44 Ext2_int_ReadInode(disk, Node->Inode, &inode);
47 LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
51 // - Do this ourselves as it is a simple operation
52 Base = inode.i_block[0] * disk->BlockSize;
54 while(Pos -- && size > 0)
56 VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
57 ofs += dirent.rec_len;
58 size -= dirent.rec_len;
61 if(ofs >= disk->BlockSize) {
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);
68 Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
72 // Check for the end of the list
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
87 // Ignore . and .. (these are done in the VFS)
88 if( (namebuf[0] == '.' && namebuf[1] == '\0')
89 || (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) {
91 return VFS_SKIP; // Skip
96 return strdup(namebuf);
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
105 tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename)
107 tExt2_Disk *disk = Node->ImplPtr;
109 char namebuf[EXT2_NAME_LEN+1];
111 Uint64 Base; // Block's Base Address
112 int block = 0, ofs = 0;
116 // Read directory's inode
117 Ext2_int_ReadInode(disk, Node->Inode, &inode);
121 // - Do this ourselves as it is a simple operation
122 Base = inode.i_block[0] * disk->BlockSize;
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;
137 // Check for end of block
138 if(ofs >= disk->BlockSize) {
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);
145 Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
153 * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
154 * \brief Create a new node
156 int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
162 inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode);
164 memset(&inode, 0, sizeof(tExt2_Inode));
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;
175 inode.i_uid = Threads_GetUID();
176 inode.i_gid = Threads_GetGID();
179 inode.i_atime = now() / 1000;
181 child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum);
182 return Ext2_Link(Parent, child, Name);
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
195 int Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, char *Name)
200 // ---- INTERNAL FUNCTIONS ----
202 * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
203 * \brief Create a new VFS Node
205 tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
211 if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
214 if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )
219 retNode.Inode = InodeID;
220 retNode.ImplPtr = Disk;
223 retNode.Size = inode.i_size;
225 // Set Access Permissions
226 retNode.UID = inode.i_uid;
227 retNode.GID = inode.i_gid;
229 retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
231 // Set Function Pointers
232 retNode.Read = Ext2_Read;
233 retNode.Write = Ext2_Write;
234 retNode.Close = Ext2_CloseFile;
236 switch(inode.i_mode & EXT2_S_IFMT)
240 retNode.Flags = VFS_FFLAG_SYMLINK;
245 retNode.Size |= (Uint64)inode.i_dir_acl << 32;
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;
256 // Unknown, Write protect and hide it to be safe
258 retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN;
263 retNode.ATime = inode.i_atime * 1000;
264 retNode.MTime = inode.i_mtime * 1000;
265 retNode.CTime = inode.i_ctime * 1000;
267 // Save in node cache and return saved node
268 return Inode_CacheNode(Disk->CacheID, &retNode);