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

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