* AcessMicro VFS
* - Open, Close and ChDir
*/
+#define DEBUG 0
#include <common.h>
#include "vfs.h"
#include "vfs_int.h"
#include "vfs_ext.h"
-#define DEBUG 0
-
-#if DEBUG
-#else
-# undef ENTER
-# undef LOG
-# undef LEAVE
-# define ENTER(...)
-# define LOG(...)
-# define LEAVE(...)
-#endif
-
// === CONSTANTS ===
#define OPEN_MOUNT_ROOT 1
#define MAX_KERNEL_FILES 128
+#define MAX_PATH_SLASHES 256
// === IMPORTS ===
extern tVFS_Node gVFS_MemRoot;
{
char *ret;
int pathLen = strlen(Path);
- int read, write;
- int pos, slashNum=0, baseLen;
- Uint slashOffsets[256];
+ char *pathComps[MAX_PATH_SLASHES];
+ char *tmpStr;
+ int iPos = 0;
+ int iPos2 = 0;
char *cwd = CFGPTR(CFG_VFS_CWD);
int cwdLen;
+
ENTER("sPath", Path);
// Memory File
if(Path[0] == '$') {
ret = malloc(strlen(Path)+1);
+ if(!ret) {
+ Warning("VFS_GetAbsPath - malloc() returned NULL");
+ return NULL;
+ }
strcpy(ret, Path);
LEAVE('p', ret);
return ret;
// Check if the path is already absolute
if(Path[0] == '/') {
ret = malloc(pathLen + 1);
+ if(!ret) {
+ Warning("VFS_GetAbsPath - malloc() returned NULL");
+ return NULL;
+ }
strcpy(ret, Path);
- baseLen = 1;
} else {
- cwdLen = strlen(cwd);
+ if(cwd == NULL) {
+ cwd = "/";
+ cwdLen = 1;
+ }
+ else {
+ cwdLen = strlen(cwd);
+ }
// Prepend the current directory
- ret = malloc(cwdLen+pathLen+1);
+ ret = malloc( cwdLen + 1 + pathLen + 1 );
strcpy(ret, cwd);
- strcpy(&ret[cwdLen], Path);
-
- // Pre-fill the slash positions
- pos = 0;
- while( (pos = strpos( &ret[pos+1], '/' )) != -1 )
- slashOffsets[slashNum++] = pos;
-
- baseLen = cwdLen;
+ ret[cwdLen] = '/';
+ strcpy(&ret[cwdLen+1], Path);
+ //Log("ret = '%s'\n", ret);
}
- // Remove . and ..
- read = write = baseLen; // Cwd has already been parsed
- for(; read < baseLen+pathLen; read = pos+1)
+ // Parse Path
+ pathComps[iPos++] = tmpStr = ret+1;
+ while(*tmpStr)
{
- pos = strpos( &ret[read], '/' );
- // If we are in the last section, force a break at the end of the itteration
- if(pos == -1) pos = baseLen+pathLen;
- else pos += read; // Else, Adjust to absolute
-
- // Check Length
- if(pos - read <= 2)
+ if(*tmpStr++ == '/')
{
- // Current Dir "."
- if(strncmp(&ret[read], ".", pos-read) == 0) continue;
- // Parent ".."
- if(strncmp(&ret[read], "..", pos-read) == 0)
- {
- // If there is no higher, silently ignore
- if(!slashNum) continue;
- // Reverse write pointer
- write = slashOffsets[ slashNum-- ];
- continue;
+ pathComps[iPos++] = tmpStr;
+ if(iPos == MAX_PATH_SLASHES) {
+ LOG("Path '%s' has too many elements", Path);
+ free(ret);
+ LEAVE('n');
+ return NULL;
}
}
-
-
- // Only copy if the positions differ
- if(read != write) {
- memcpy( &ret[write], &ret[read], pos-read+1 );
+ }
+ pathComps[iPos] = NULL;
+
+ // Cleanup
+ iPos2 = iPos = 0;
+ while(pathComps[iPos])
+ {
+ tmpStr = pathComps[iPos];
+ // Always Increment iPos
+ iPos++;
+ // ..
+ if(tmpStr[0] == '.' && tmpStr[1] == '.' && (tmpStr[2] == '/' || tmpStr[2] == '\0') )
+ {
+ if(iPos2 != 0)
+ iPos2 --;
+ continue;
}
- write = pos+1;
- if(slashNum < 256)
- slashOffsets[ slashNum++ ] = pos;
- else {
- LOG("Path '%s' has too many elements", Path);
- free(ret);
- LEAVE('n');
- return NULL;
+ // .
+ if(tmpStr[0] == '.' && (tmpStr[1] == '/' || tmpStr[1] == '\0') )
+ {
+ continue;
+ }
+ // Empty
+ if(tmpStr[0] == '/' || tmpStr[0] == '\0')
+ {
+ continue;
}
+
+ // Set New Position
+ pathComps[iPos2] = tmpStr;
+ iPos2++;
+ }
+ pathComps[iPos2] = NULL;
+
+ // Build New Path
+ iPos2 = 1; iPos = 0;
+ ret[0] = '/';
+ while(pathComps[iPos])
+ {
+ tmpStr = pathComps[iPos];
+ while(*tmpStr && *tmpStr != '/')
+ {
+ ret[iPos2++] = *tmpStr;
+ tmpStr++;
+ }
+ ret[iPos2++] = '/';
+ iPos++;
}
+ if(iPos2 > 1)
+ ret[iPos2-1] = 0;
+ else
+ ret[iPos2] = 0;
- // `ret` should now be the absolute path
LEAVE('s', ret);
+ //Log("VFS_GetAbsPath: RETURN '%s'", ret);
return ret;
}
}
// Check if there is anything mounted
- if(!gMounts) return NULL;
+ if(!gMounts) {
+ Warning("WTF! There's nothing mounted?");
+ return NULL;
+ }
// Find Mountpoint
for(mnt = gMounts;
// Sanity Check
/*if(!longestMount) {
- Log("VFS_GetTruePath - ERROR: No Root Node\n");
+ Log("VFS_ParsePath - ERROR: No Root Node\n");
return NULL;
}*/
free(*TruePath);
*TruePath = NULL;
}
+ //Log("Permissions fail on '%s'", Path);
LEAVE('n');
return NULL;
}
*TruePath = NULL;
}
Path[nextSlash] = '/';
+ //Log("FindDir fail on '%s'", Path);
LEAVE('n');
return NULL;
}
free(*TruePath);
*TruePath = NULL;
}
+ //Log("Child fail on '%s' ('%s)", Path, &Path[ofs]);
Path[nextSlash] = '/';
LEAVE('n');
return NULL;
// Error Check
if(!curNode) {
+ Log("Symlink fail '%s'", tmp);
free(tmp); // Free temp string
LEAVE('n');
return NULL;
// Check if file was found
if(!tmpNode) {
LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
+ Log("Child fail '%s' ('%s')", Path, &Path[ofs]);
if(TruePath) free(*TruePath);
if(curNode->Close) curNode->Close(curNode);
LEAVE('n');
if( !(Mode & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
{
if( !node->Read ) {
- LOG("No read method on symlink");
+ Warning("No read method on symlink");
LEAVE('i', -1);
return -1;
}
}
if(!node) {
+ LOG("Cannot find node");
LEAVE('i', -1);
return -1;
}
// Permissions Check
if( !VFS_CheckACL(node, i) ) {
node->Close( node );
+ Log("VFS_Open: Permissions Failed");
LEAVE('i', -1);
return -1;
}
}
}
+ Log("VFS_Open: Out of handles");
LEAVE('i', -1);
return -1;
}
h->Node = NULL;
}
+/**
+ * \fn int VFS_ChDir(char *New)
+ * \brief Change current working directory
+ */
+int VFS_ChDir(char *New)
+{
+ char *buf;
+ int fd;
+ tVFS_Handle *h;
+
+ // Create Absolute
+ buf = VFS_GetAbsPath(New);
+ if(buf == NULL) {
+ Log("VFS_ChDir: Path expansion failed");
+ return -1;
+ }
+
+ // Check if path exists
+ fd = VFS_Open(buf, VFS_OPENFLAG_EXEC);
+ if(fd == -1) {
+ Log("VFS_ChDir: Path is invalid");
+ return -1;
+ }
+
+ // Get node so we can check for directory
+ h = VFS_GetHandle(fd);
+ if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
+ Log("VFS_ChDir: Path is not a directory");
+ VFS_Close(fd);
+ return -1;
+ }
+
+ // Close file
+ VFS_Close(fd);
+
+ // Free old working directory
+ if( CFGPTR(CFG_VFS_CWD) )
+ free( CFGPTR(CFG_VFS_CWD) );
+ // Set new
+ CFGPTR(CFG_VFS_CWD) = buf;
+
+ Log("Updated CWD to '%s'", buf);
+
+ return 1;
+}
+
/**
* \fn tVFS_Handle *VFS_GetHandle(int FD)
* \brief Gets a pointer to the handle information structure
*/
tVFS_Handle *VFS_GetHandle(int FD)
{
+ tVFS_Handle *h;
+
if(FD < 0) return NULL;
if(FD & VFS_KERNEL_FLAG) {
FD &= (VFS_KERNEL_FLAG - 1);
if(FD >= MAX_KERNEL_FILES) return NULL;
- return &gaKernelHandles[ FD ];
+ h = &gaKernelHandles[ FD ];
} else {
if(FD >= CFGINT(CFG_VFS_MAXFILES)) return NULL;
- return &gaUserHandles[ FD ];
+ h = &gaUserHandles[ FD ];
}
+
+ if(h->Node == NULL) return NULL;
+ return h;
}