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

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