2 * Acess Micro - VFS Server version 1
11 extern int giVFS_MountFileID;
12 extern char *gsVFS_MountFile;
16 int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
18 void VFS_UpdateMountFile(void);
21 tRWLock glVFS_MountList;
22 tVFS_Mount *gVFS_Mounts;
23 tVFS_Mount *gVFS_RootMount = NULL;
24 Uint32 giVFS_NextMountIdent = 1;
28 * \brief Mount a device
29 * \param Device Device string to mount
30 * \param MountPoint Destination for the mount
31 * \param Filesystem Filesystem to use for the mount
32 * \param Options Options to be passed to the filesystem
33 * \return -1 on Invalid FS, -2 on No Mem, 0 on success
35 * Mounts the filesystem on \a Device at \a MountPoint using the driver
36 * \a Filesystem. The options in the string \a Options is passed to the
39 int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options)
41 tVFS_Mount *mnt, *parent_mnt;
43 int deviceLen = strlen(Device);
44 int mountLen = strlen(MountPoint);
45 int argLen = strlen(Options);
48 fs = VFS_GetFSByName(Filesystem);
50 Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
54 // Create mount information
55 mnt = malloc( sizeof(tVFS_Mount)+deviceLen+1+mountLen+1+argLen+1 );
60 // Validate the mountpoint target
61 // - Only if / is mounted
64 tVFS_Node *mpnode = VFS_ParsePath(MountPoint, NULL, &parent_mnt);
66 Log_Warning("VFS", "VFS_Mount - Mountpoint '%s' does not exist", MountPoint);
69 if( mpnode->Type->Close )
70 mpnode->Type->Close(mpnode);
71 if( parent_mnt->RootNode == mpnode ) {
72 Log_Warning("VFS", "VFS_Mount - Attempt to mount over '%s' (%s)",
73 MountPoint, parent_mnt->MountPoint);
78 // HACK: Forces VFS_ParsePath to fall back on root
79 if(mountLen == 1 && MountPoint[0] == '/')
80 mnt->MountPointLen = 0;
82 mnt->MountPointLen = mountLen;
86 mnt->OpenHandleCount = 0;
88 mnt->Device = &mnt->StrData[0];
89 memcpy( mnt->Device, Device, deviceLen+1 );
91 mnt->MountPoint = &mnt->StrData[deviceLen+1];
92 memcpy( mnt->MountPoint, MountPoint, mountLen+1 );
94 mnt->Options = &mnt->StrData[deviceLen+1+mountLen+1];
95 memcpy( mnt->Options, Options, argLen+1 );
97 // Parse options string
98 char *str = mnt->Options;
102 } while( (str = strchr(str, ',')) );
104 char *args[nArg + 1];
109 str = strchr(str, ',');
112 args[nArg] = 0; // NULL terminal
115 mnt->RootNode = fs->InitDevice(Device, (const char **)args);
118 parent_mnt->OpenHandleCount --;
122 // Repair the options string
124 args[nArg][-1] = ',';
126 mnt->Identifier = giVFS_NextMountIdent++;
128 // Ensure identifiers don't repeat
129 // - Only a problem if there have been 4 billion mounts
130 while( giVFS_NextMountIdent == 0 || VFS_GetMountByIdent(giVFS_NextMountIdent) )
131 giVFS_NextMountIdent ++;
135 if(!gVFS_RootMount) gVFS_RootMount = mnt;
138 RWLock_AcquireWrite( &glVFS_MountList );
143 for( tmp = gVFS_Mounts; tmp->Next; tmp = tmp->Next );
150 RWLock_Release( &glVFS_MountList );
152 Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
154 VFS_UpdateMountFile();
159 int VFS_Unmount(const char *Mountpoint)
161 tVFS_Mount *mount, *prev = NULL;
162 RWLock_AcquireWrite( &glVFS_MountList );
163 for( mount = gVFS_Mounts; mount; prev = mount, mount = mount->Next )
165 if( strcmp(Mountpoint, mount->MountPoint) == 0 ) {
166 if( mount->OpenHandleCount ) {
167 LOG("Mountpoint busy");
168 RWLock_Release(&glVFS_MountList);
172 prev->Next = mount->Next;
174 gVFS_Mounts = mount->Next;
178 RWLock_Release( &glVFS_MountList );
180 LOG("Mountpoint not found");
184 Log_Warning("VFS", "TODO: Impliment unmount");
186 // Decrease the open handle count for the mountpoint filesystem.
188 tVFS_Node *mpnode = VFS_ParsePath(mount->MountPoint, NULL, &mpmnt);
191 mpmnt->OpenHandleCount -= 2; // -1 for _ParsePath here, -1 for in _Mount
194 mount->Filesystem->Unmount( mount->RootNode );
200 int VFS_UnmountAll(void)
203 tVFS_Mount *mount, *prev = NULL, *next;
205 RWLock_AcquireWrite( &glVFS_MountList );
206 // If we've unmounted the final filesystem, all good
207 if( gVFS_Mounts == NULL) {
208 RWLock_Release( &glVFS_MountList );
212 for( mount = gVFS_Mounts; mount; prev = mount, mount = next )
215 // Can't unmount stuff with open handles
216 if( mount->OpenHandleCount > 0 ) {
217 LOG("%p (%s) has open handles (%i of them)",
218 mount, mount->MountPoint, mount->OpenHandleCount);
223 prev->Next = mount->Next;
225 gVFS_Mounts = mount->Next;
227 if( mount->Filesystem->Unmount ) {
228 mount->Filesystem->Unmount( mount->RootNode );
231 Log_Error("VFS", "%s (%s) does not have an unmount method, not calling it",
232 mount->MountPoint, mount->Filesystem->Name);
238 RWLock_Release( &glVFS_MountList );
244 * \brief Gets a mount point given the identifier
246 tVFS_Mount *VFS_GetMountByIdent(Uint32 MountID)
250 RWLock_AcquireRead(&glVFS_MountList);
251 for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
253 if(mnt->Identifier == MountID)
257 mnt->OpenHandleCount ++;
258 RWLock_Release(&glVFS_MountList);
263 * \brief Updates the mount file buffer
265 * Updates the ProcFS mounts file buffer to match the current mounts list.
267 void VFS_UpdateMountFile(void)
274 // <device>\t<location>\t<type>\t<options>\n
276 RWLock_AcquireRead( &glVFS_MountList );
277 for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
279 len += 4 + strlen(mnt->Device) + strlen(mnt->MountPoint)
280 + strlen(mnt->Filesystem->Name) + strlen(mnt->Options);
282 RWLock_Release( &glVFS_MountList );
284 buf = malloc( len + 1 );
286 RWLock_AcquireRead( &glVFS_MountList );
287 for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
289 strcpy( &buf[len], mnt->Device );
290 len += strlen(mnt->Device);
293 strcpy( &buf[len], mnt->MountPoint );
294 len += strlen(mnt->MountPoint);
297 strcpy( &buf[len], mnt->Filesystem->Name );
298 len += strlen(mnt->Filesystem->Name);
301 strcpy( &buf[len], mnt->Options );
302 len += strlen(mnt->Options);
305 RWLock_Release( &glVFS_MountList );
308 SysFS_UpdateFile( giVFS_MountFileID, buf, len );
309 if( gsVFS_MountFile ) free( gsVFS_MountFile );
310 gsVFS_MountFile = buf;