Kernel/VFS - Fixed mount reference counting and shutdown cleanup
[tpg/acess2.git] / KernelLand / Kernel / vfs / dir.c
1 /*
2  * Acess2 VFS
3  * - Directory Management Functions
4  */
5 #define SANITY  1
6 #define DEBUG   0
7 #include <acess.h>
8 #include <vfs.h>
9 #include <vfs_int.h>
10
11 // === IMPORTS ===
12 extern tVFS_Mount       *gRootMount;
13
14 // === PROTOTYPES ===
15 #if 0
16  int    VFS_MkDir(const char *Path);
17  int    VFS_MkNod(const char *Path, Uint Flags);
18  int    VFS_Symlink(const char *Name, const char *Link);
19 #endif
20
21 // === CODE ===
22 /**
23  * \fn int VFS_MkDir(char *Path)
24  * \brief Create a new node
25  * \param Path  Path of directory to create
26  */
27 int VFS_MkDir(const char *Path)
28 {
29         return VFS_MkNod(Path, VFS_FFLAG_DIRECTORY);
30 }
31
32 /**
33  * \fn int VFS_MkNod(char *Path, Uint Flags)
34  * \brief Create a new node in a directory
35  * \param Path  Path of new node
36  * \param Flags Flags to apply to the node
37  */
38 int VFS_MkNod(const char *Path, Uint Flags)
39 {
40         tVFS_Mount      *mountpt;
41         char    *absPath, *name;
42          int    pos = 0, oldpos = 0;
43          int    next = 0;
44         tVFS_Node       *parent;
45         tVFS_Node       *ret;
46         
47         ENTER("sPath xFlags", Path, Flags);
48         
49         absPath = VFS_GetAbsPath(Path);
50         LOG("absPath = '%s'", absPath);
51         
52         while( (next = strpos(&absPath[pos+1], '/')) != -1 ) {
53                 LOG("next = %i", next);
54                 pos += next+1;
55                 LOG("pos = %i", pos);
56                 oldpos = pos;
57         }
58         absPath[oldpos] = '\0'; // Mutilate path
59         name = &absPath[oldpos+1];
60         
61         LOG("absPath = '%s', name = '%s'", absPath, name);
62         
63         // Check for root
64         if(absPath[0] == '\0')
65                 parent = VFS_ParsePath("/", NULL, &mountpt);
66         else
67                 parent = VFS_ParsePath(absPath, NULL, &mountpt);
68         
69         LOG("parent = %p", parent);
70         
71         if(!parent) {
72                 errno = ENOENT;
73                 goto _error;
74         }
75
76         // Permissions Check
77         if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
78                 errno = EACCES;
79                 goto _error;
80         }
81         
82         LOG("parent = %p", parent);
83         
84         if(!parent->Type || !parent->Type->MkNod) {
85                 Log_Warning("VFS", "VFS_MkNod - Directory has no MkNod method");
86                 errno = ENOTDIR;
87                 goto _error;
88         }
89         
90         // Create node
91         ret = parent->Type->MkNod(parent, name, Flags);
92         _CloseNode(ret);
93         
94         // Free allocated string
95         free(absPath);
96         
97         // Free Parent
98         ASSERT(mountpt->OpenHandleCount>0);
99         mountpt->OpenHandleCount --;
100         _CloseNode(parent);
101
102         // Return whatever the driver said      
103         LEAVE('i', ret==NULL);
104         return ret==NULL;
105
106 _error:
107         _CloseNode(parent);
108         ASSERT(mountpt->OpenHandleCount>0);
109         mountpt->OpenHandleCount --;
110         free(absPath);
111         LEAVE('i', -1);
112         return -1;
113 }
114
115 /**
116  * \fn int VFS_Symlink(const char *Name, const char *Link)
117  * \brief Creates a symlink called \a Name to \a Link
118  * \param Name  Name of symbolic link
119  * \param Link  Destination of symbolic link
120  */
121 int VFS_Symlink(const char *Name, const char *Link)
122 {
123         char    *realLink;
124          int    fp;
125         
126         ENTER("sName sLink", Name, Link);
127         
128         // Get absolue path name
129         realLink = VFS_GetAbsPath( Link );
130         if(!realLink) {
131                 Log_Warning("VFS", "Path '%s' is badly formed", Link);
132                 errno = EINVAL;
133                 LEAVE('i', -1);
134                 return -1;
135         }
136
137         LOG("realLink = '%s'", realLink);
138
139         // Make node
140         if( VFS_MkNod(Name, VFS_FFLAG_SYMLINK) != 0 ) {
141                 Log_Warning("VFS", "Unable to create link node '%s'", Name);
142                 free(realLink);
143                 // errno is set by VFS_MkNod
144                 LEAVE('i', -2);
145                 return -2;      // Make link node
146         }
147         
148         // Write link address
149         fp = VFS_Open(Name, VFS_OPENFLAG_WRITE|VFS_OPENFLAG_NOLINK);
150         if( fp == -1 ) {
151                 Log_Warning("VFS", "Unable to open newly created symlink '%s'", Name);
152                 free(realLink);
153                 LEAVE('i', -3);
154                 return -3;
155         }
156         VFS_Write(fp, strlen(realLink), realLink);
157         VFS_Close(fp);
158         
159         free(realLink);
160         
161         LEAVE('i', 1);
162         return 1;
163 }
164
165 /**
166  * \fn int VFS_ReadDir(int FD, char *Dest)
167  * \brief Read from a directory
168  */
169 int VFS_ReadDir(int FD, char *Dest)
170 {
171         tVFS_Handle     *h = VFS_GetHandle(FD);
172          int    rv;
173         
174         //ENTER("ph pDest", h, Dest);
175         
176         if(!h || !h->Node->Type || !h->Node->Type->ReadDir) {
177                 //LEAVE('i', 0);
178                 return 0;
179         }
180         
181         if(h->Node->Size != (Uint64)-1 && h->Position >= h->Node->Size) {
182                 //LEAVE('i', 0);
183                 return 0;
184         }
185         
186         do {
187                 rv = h->Node->Type->ReadDir(h->Node, h->Position, Dest);
188                 if(rv > 0)
189                         h->Position += rv;
190                 else
191                         h->Position ++;
192         } while(rv > 0);
193         
194         if(rv < 0) {
195                 //LEAVE('i', 0);
196                 return 0;
197         }
198         
199         //LEAVE('i', 1);
200         return 1;
201 }

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