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_int_Unmount(tVFS_Mount *Mount);
19 void VFS_UpdateMountFile(void);
22 tRWLock glVFS_MountList;
23 tVFS_Mount *gVFS_Mounts;
24 tVFS_Mount *gVFS_RootMount = NULL;
25 Uint32 giVFS_NextMountIdent = 1;
29 * \brief Mount a device
30 * \param Device Device string to mount
31 * \param MountPoint Destination for the mount
32 * \param Filesystem Filesystem to use for the mount
33 * \param Options Options to be passed to the filesystem
34 * \return -1 on Invalid FS, -2 on No Mem, 0 on success
36 * Mounts the filesystem on \a Device at \a MountPoint using the driver
37 * \a Filesystem. The options in the string \a Options is passed to the
40 int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options)
42 tVFS_Mount *mnt, *parent_mnt;
44 int deviceLen = strlen(Device);
45 int mountLen = strlen(MountPoint);
46 int argLen = strlen(Options);
49 if( Filesystem && Filesystem[0] )
51 fs = VFS_GetFSByName(Filesystem);
53 Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
59 int fd = VFS_Open(Device, VFS_OPENFLAG_READ);
61 Log_Warning("VFS", "VFS_Mount - Unable to open '%s' for autodetect", Device);
65 tVFS_Driver *bestfs = NULL;
67 for( fs = gVFS_Drivers; fs; fs = fs->Next )
69 if(!fs->Detect) continue ;
70 rank = fs->Detect(fd);
72 if(!bestfs || rank > bestrank) {
78 if( bestfs == NULL ) {
79 Log_Warning("VFS", "VFS_Mount - Filesystem autodetection failed");
86 // Validate the mountpoint target
87 // - Only if / is mounted
90 tVFS_Node *mpnode = VFS_ParsePath(MountPoint, NULL, &parent_mnt);
92 Log_Warning("VFS", "VFS_Mount - Mountpoint '%s' does not exist", MountPoint);
95 if( mpnode->Type->Close )
96 mpnode->Type->Close(mpnode);
97 if( parent_mnt->RootNode == mpnode ) {
98 Log_Warning("VFS", "VFS_Mount - Attempt to mount over '%s' (%s)",
99 MountPoint, parent_mnt->MountPoint);
104 // Create mount information
105 mnt = malloc( sizeof(tVFS_Mount)+deviceLen+1+mountLen+1+argLen+1 );
107 parent_mnt->OpenHandleCount --;
111 // HACK: Forces VFS_ParsePath to fall back on root
112 if(mountLen == 1 && MountPoint[0] == '/')
113 mnt->MountPointLen = 0;
115 mnt->MountPointLen = mountLen;
118 mnt->Filesystem = fs;
119 mnt->OpenHandleCount = 0;
121 mnt->Device = &mnt->StrData[0];
122 memcpy( mnt->Device, Device, deviceLen+1 );
124 mnt->MountPoint = &mnt->StrData[deviceLen+1];
125 memcpy( mnt->MountPoint, MountPoint, mountLen+1 );
127 mnt->Options = &mnt->StrData[deviceLen+1+mountLen+1];
128 memcpy( mnt->Options, Options, argLen+1 );
130 // Parse options string
131 char *str = mnt->Options;
135 } while( (str = strchr(str, ',')) );
137 char *args[nArg + 1];
142 str = strchr(str, ',');
145 args[nArg] = 0; // NULL terminal
148 mnt->RootNode = fs->InitDevice(Device, (const char **)args);
151 parent_mnt->OpenHandleCount --;
155 // Repair the options string
157 args[nArg][-1] = ',';
159 mnt->Identifier = giVFS_NextMountIdent++;
161 // Ensure identifiers don't repeat
162 // - Only a problem if there have been 4 billion mounts
163 while( giVFS_NextMountIdent == 0 || VFS_GetMountByIdent(giVFS_NextMountIdent) )
164 giVFS_NextMountIdent ++;
168 if(!gVFS_RootMount) gVFS_RootMount = mnt;
171 RWLock_AcquireWrite( &glVFS_MountList );
176 for( tmp = gVFS_Mounts; tmp->Next; tmp = tmp->Next );
183 RWLock_Release( &glVFS_MountList );
185 Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, fs->Name);
187 VFS_UpdateMountFile();
192 void VFS_int_Unmount(tVFS_Mount *Mount)
194 // Decrease the open handle count for the mountpoint filesystem.
195 if( Mount != gVFS_RootMount )
198 for( mpmnt = gVFS_Mounts; mpmnt; mpmnt = mpmnt->Next )
200 if( strncmp(mpmnt->MountPoint, Mount->MountPoint, mpmnt->MountPointLen) != 0 )
202 if( Mount->MountPoint[ mpmnt->MountPointLen ] != '/' )
207 mpmnt->OpenHandleCount -= 1;
210 Log_Notice("VFS", "Mountpoint '%s' has no parent", Mount->MountPoint);
214 if( Mount->Filesystem->Unmount )
215 Mount->Filesystem->Unmount( Mount->RootNode );
216 LOG("%p (%s) unmounted", Mount, Mount->MountPoint);
220 int VFS_Unmount(const char *Mountpoint)
222 tVFS_Mount *mount, *prev = NULL;
223 RWLock_AcquireWrite( &glVFS_MountList );
224 for( mount = gVFS_Mounts; mount; prev = mount, mount = mount->Next )
226 if( strcmp(Mountpoint, mount->MountPoint) == 0 ) {
227 if( mount->OpenHandleCount ) {
228 LOG("Mountpoint busy");
229 RWLock_Release(&glVFS_MountList);
233 prev->Next = mount->Next;
235 gVFS_Mounts = mount->Next;
239 RWLock_Release( &glVFS_MountList );
241 LOG("Mountpoint not found");
245 VFS_int_Unmount(mount);
247 VFS_UpdateMountFile();
252 int VFS_UnmountAll(void)
255 tVFS_Mount *mount, *prev = NULL, *next;
257 RWLock_AcquireWrite( &glVFS_MountList );
258 // If we've unmounted the final filesystem, all good
259 if( gVFS_Mounts == NULL) {
260 RWLock_Release( &glVFS_MountList );
264 for( mount = gVFS_Mounts; mount; prev = mount, mount = next )
267 // Can't unmount stuff with open handles
268 if( mount->OpenHandleCount > 0 ) {
269 LOG("%p (%s) has open handles (%i of them)",
270 mount, mount->MountPoint, mount->OpenHandleCount);
275 prev->Next = mount->Next;
277 gVFS_Mounts = mount->Next;
279 VFS_int_Unmount(mount);
283 RWLock_Release( &glVFS_MountList );
285 VFS_UpdateMountFile();
291 * \brief Gets a mount point given the identifier
293 tVFS_Mount *VFS_GetMountByIdent(Uint32 MountID)
297 RWLock_AcquireRead(&glVFS_MountList);
298 for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
300 if(mnt->Identifier == MountID)
304 mnt->OpenHandleCount ++;
305 RWLock_Release(&glVFS_MountList);
310 * \brief Updates the mount file buffer
312 * Updates the ProcFS mounts file buffer to match the current mounts list.
314 void VFS_UpdateMountFile(void)
321 // <device>\t<location>\t<type>\t<options>\n
323 RWLock_AcquireRead( &glVFS_MountList );
324 for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
326 len += 4 + strlen(mnt->Device) + strlen(mnt->MountPoint)
327 + strlen(mnt->Filesystem->Name) + strlen(mnt->Options);
329 RWLock_Release( &glVFS_MountList );
331 buf = malloc( len + 1 );
333 RWLock_AcquireRead( &glVFS_MountList );
334 for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
336 strcpy( &buf[len], mnt->Device );
337 len += strlen(mnt->Device);
340 strcpy( &buf[len], mnt->MountPoint );
341 len += strlen(mnt->MountPoint);
344 strcpy( &buf[len], mnt->Filesystem->Name );
345 len += strlen(mnt->Filesystem->Name);
348 strcpy( &buf[len], mnt->Options );
349 len += strlen(mnt->Options);
352 RWLock_Release( &glVFS_MountList );
355 SysFS_UpdateFile( giVFS_MountFileID, buf, len );
356 if( gsVFS_MountFile ) free( gsVFS_MountFile );
357 gsVFS_MountFile = buf;