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

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