From d4590cefa1424d21c9d28787ea09ca3f09f39a3a Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 21 Nov 2011 12:19:57 +0100 Subject: [PATCH] Added chdir(2), getcwd(2), which mxsh and ls now uses. --- libmaxsi/c/hsrc/unistd.h | 4 +- libmaxsi/hsrc/error.h | 2 + libmaxsi/io.cpp | 12 ++++ sortix/directory.cpp | 120 +++++++++++++++++++++++++++++++++++++++ sortix/directory.h | 1 + sortix/filesystem.cpp | 26 ++++----- sortix/process.cpp | 5 ++ sortix/process.h | 3 +- sortix/syscallnum.h | 4 +- utils/ls.cpp | 7 ++- utils/mxsh.cpp | 20 ++++++- 11 files changed, 182 insertions(+), 22 deletions(-) diff --git a/libmaxsi/c/hsrc/unistd.h b/libmaxsi/c/hsrc/unistd.h index bf96f74a..832927f6 100644 --- a/libmaxsi/c/hsrc/unistd.h +++ b/libmaxsi/c/hsrc/unistd.h @@ -78,7 +78,6 @@ __BEGIN_DECLS #ifndef SORTIX_UNIMPLEMENTED int access(const char*, int); unsigned alarm(unsigned); -int chdir(const char*); int chown(const char*, uid_t, gid_t); size_t confstr(int, char*, size_t); char* crypt(const char*, const char*); @@ -100,7 +99,6 @@ int fexecve(int, char* const [], char* const []); long fpathconf(int, int); int fsync(int); int ftruncate(int, off_t); -char* getcwd(char*, size_t); gid_t getegid(void); uid_t geteuid(void); gid_t getgid(void); @@ -157,10 +155,12 @@ extern char* optarg; extern int opterr, optind, optopt; #endif +int chdir(const char*); int close(int); int dup(int); void _exit(int); pid_t fork(void); +char* getcwd(char*, size_t); pid_t getpid(void); pid_t getppid(void); int pipe(int [2]); diff --git a/libmaxsi/hsrc/error.h b/libmaxsi/hsrc/error.h index b006c314..92101dab 100644 --- a/libmaxsi/hsrc/error.h +++ b/libmaxsi/hsrc/error.h @@ -55,6 +55,8 @@ namespace Maxsi const int EROFS = 20; const int EINVAL = 21; const int ENOTDIR = 22; + const int ENOMEM = 23; + const int ERANGE = 24; extern int _errornumber; diff --git a/libmaxsi/io.cpp b/libmaxsi/io.cpp index 9c511841..4b1c8a1b 100644 --- a/libmaxsi/io.cpp +++ b/libmaxsi/io.cpp @@ -38,6 +38,8 @@ namespace Maxsi DEFN_SYSCALL1(int, SysDup, 22, int); DEFN_SYSCALL3(int, SysOpen, 23, const char*, int, mode_t); DEFN_SYSCALL3(int, SysReadDirEnts, 24, int, struct sortix_dirent*, size_t); + DEFN_SYSCALL1(int, SysChDir, 25, const char*); + DEFN_SYSCALL2(char*, SysGetCWD, 26, char*, size_t); size_t Print(const char* Message) { @@ -102,6 +104,16 @@ namespace Maxsi { return SysReadDirEnts(fd, dirent, size); } + + extern "C" int chdir(const char* path) + { + return SysChDir(path); + } + + extern "C" char* getcwd(char* buf, size_t size) + { + return SysGetCWD(buf, size); + } #endif } diff --git a/sortix/directory.cpp b/sortix/directory.cpp index 085fcc70..3ce2f3cd 100644 --- a/sortix/directory.cpp +++ b/sortix/directory.cpp @@ -30,6 +30,8 @@ #include "process.h" #include "device.h" #include "directory.h" +#include "filesystem.h" +#include "mount.h" using namespace Maxsi; @@ -84,9 +86,127 @@ namespace Sortix } } + int SysChDir(const char* path) + { + // Calculate the absolute new path. + Process* process = CurrentProcess(); + const char* wd = process->workingdir; + char* abs = MakeAbsolute(wd, path); + if ( !abs ) { Error::Set(Error::ENOMEM); return -1; } + size_t abslen = String::Length(abs); + if ( 1 < abslen && abs[abslen-1] == '/' ) + { + abs[abslen-1] = '\0'; + } + + // Lookup the path and see if it is a directory. + size_t pathoffset = 0; + DevFileSystem* fs = Mount::WhichFileSystem(abs, &pathoffset); + if ( !fs ) { delete[] abs; Error::Set(Error::EINVAL); return -1; } + Device* dev = fs->Open(abs + pathoffset, O_SEARCH | O_DIRECTORY, 0); + if ( !dev ) { Error::Set(Error::ENOTDIR); return -1; } + dev->Unref(); + + // Alright, the path passed. + delete[] process->workingdir; // Works if it was NULL. + process->workingdir = abs; + + return 0; + } + + char* SysGetCWD(char* buf, size_t size) + { + // Calculate the absolute new path. + Process* process = CurrentProcess(); + const char* wd = process->workingdir; + if ( !wd ) { wd = "/"; } + size_t wdsize = String::Length(wd) + 1; + if ( size < wdsize ) { Error::Set(Error::ERANGE); return NULL; } + String::Copy(buf, wd); + return buf; + } + void Init() { Syscall::Register(SYSCALL_READDIRENTS, (void*) SysReadDirEnts); + Syscall::Register(SYSCALL_CHDIR, (void*) SysChDir); + Syscall::Register(SYSCALL_GETCWD, (void*) SysGetCWD); + } + + // Allocate a byte too much, in case you want to add a trailing slash. + char* MakeAbsolute(const char* wd, const char* rel) + { + // If given no wd, then interpret from the root. + if ( !wd ) { wd = "/"; } + + // The resulting size won't ever be larger than this. + size_t wdlen = String::Length(wd); + size_t resultsize = wdlen + String::Length(rel) + 2; + char* result = new char[resultsize + 1]; + if ( !result ) { return NULL; } + + // Detect if rel is relative to / or to wd, and then continue the + // interpretation from that point. + size_t offset; + if ( *rel == '/' ) { result[0] = '/'; offset = 1; rel++; } + else { String::Copy(result, wd); offset = wdlen; } + + // Make sure the working directory ends with a slash. + if ( result[offset-1] != '/' ) { result[offset++] = '/'; } + + bool leadingdots = true; + size_t dots = 0; + int c = 1; + while ( c ) // Exit after handling \0 + { + c = *rel++; + + // Don't insert double //'s into the final path. + if ( c == '/' && result[offset-1] == '/' ) { continue; } + + // / or \0 means that we should interpret . and .. + if ( c == '/' || c == '\0' ) + { + // If ., just remove the dot and ignore the slash. + if ( leadingdots && dots == 1 ) + { + result[--offset] = '\0'; + dots = 0; + continue; + } + + // If .., remove .. and one element of the path. + if ( leadingdots && dots == 2 ) + { + offset -= 2; // Remove .. + offset -= 1; // Remove the trailing slash + while ( offset ) + { + if ( result[--offset] == '/' ) { break; } + } + result[offset++] = '/'; // Need to re-insert a slash. + result[offset] = '\0'; + dots = 0; + continue; + } + + // Reset the dot count after a slash. + dots = 0; + } + + // The newest path element consisted solely of dots. + leadingdots = ( c == '/' || c == '.' ); + + // Count the number of leading dots in the path element. + if ( c == '.' && leadingdots ) { dots++; } + + // Insert the character into the result. + result[offset++] = c; + } + + // TODO: To avoid wasting space, should we String::Clone(result)? + + return result; } } } diff --git a/sortix/directory.h b/sortix/directory.h index dd381a3d..8f0bd6a3 100644 --- a/sortix/directory.h +++ b/sortix/directory.h @@ -57,6 +57,7 @@ namespace Sortix namespace Directory { void Init(); + char* MakeAbsolute(const char* wd, const char* rel); } } diff --git a/sortix/filesystem.cpp b/sortix/filesystem.cpp index b0f3c7a2..81feaa8d 100644 --- a/sortix/filesystem.cpp +++ b/sortix/filesystem.cpp @@ -23,11 +23,13 @@ ******************************************************************************/ #include "platform.h" +#include #include #include #include "syscall.h" #include "process.h" #include "filesystem.h" +#include "directory.h" #include "mount.h" using namespace Maxsi; @@ -38,22 +40,16 @@ namespace Sortix { Device* Open(const char* path, int flags, mode_t mode) { - const char* workingdir = "/"; - char* fullpath = NULL; - if ( *path != '/' ) - { - size_t len = String::Length(workingdir) + String::Length(path); - fullpath = new char[len+1]; - if ( !fullpath ) { return NULL; } - String::Copy(fullpath, workingdir); - String::Cat(fullpath, path); - path = fullpath; - } + Process* process = CurrentProcess(); + const char* wd = process->workingdir; + char* abs = Directory::MakeAbsolute(wd, path); + if ( !abs ) { Error::Set(Error::ENOMEM); return NULL; } + size_t pathoffset = 0; - DevFileSystem* fs = Mount::WhichFileSystem(path, &pathoffset); - if ( !fs ) { delete[] fullpath; return NULL; } - Device* result = fs->Open(path + pathoffset, flags, mode); - delete[] fullpath; + DevFileSystem* fs = Mount::WhichFileSystem(abs, &pathoffset); + if ( !fs ) { delete[] abs; return NULL; } + Device* result = fs->Open(abs + pathoffset, flags, mode); + delete[] abs; return result; } diff --git a/sortix/process.cpp b/sortix/process.cpp index 05b7397f..7f6148c5 100644 --- a/sortix/process.cpp +++ b/sortix/process.cpp @@ -96,6 +96,7 @@ namespace Sortix firstchild = NULL; zombiechild = NULL; firstthread = NULL; + workingdir = NULL; mmapfrom = 0x80000000UL; exitstatus = -1; pid = AllocatePID(); @@ -110,6 +111,8 @@ namespace Sortix // Avoid memory leaks. ASSERT(segments == NULL); + + delete[] workingdir; // TODO: Delete address space! } @@ -193,6 +196,8 @@ namespace Sortix // Copy variables. clone->mmapfrom = mmapfrom; + if ( workingdir ) { clone->workingdir = String::Clone(workingdir); } + else { clone->workingdir = NULL; } // Now that the cloned process is fully created, we need to signal to // its threads that they should insert themselves into the scheduler. diff --git a/sortix/process.h b/sortix/process.h index ee4145ba..19facd6b 100644 --- a/sortix/process.h +++ b/sortix/process.h @@ -67,8 +67,7 @@ namespace Sortix public: addr_t addrspace; int exitstatus; - - public: + char* workingdir; pid_t pid; public: diff --git a/sortix/syscallnum.h b/sortix/syscallnum.h index 61f92f2f..ee0c8641 100644 --- a/sortix/syscallnum.h +++ b/sortix/syscallnum.h @@ -50,7 +50,9 @@ #define SYSCALL_DUP 22 #define SYSCALL_OPEN 23 #define SYSCALL_READDIRENTS 24 -#define SYSCALL_MAX_NUM 25 /* index of highest constant + 1 */ +#define SYSCALL_CHDIR 25 +#define SYSCALL_GETCWD 26 +#define SYSCALL_MAX_NUM 27 /* index of highest constant + 1 */ #endif diff --git a/utils/ls.cpp b/utils/ls.cpp index 2f3ac068..459bcbc0 100644 --- a/utils/ls.cpp +++ b/utils/ls.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,11 @@ int ls(const char* path) int main(int argc, char* argv[]) { - const char* path = "/"; + const size_t CWD_SIZE = 512; + char cwd[CWD_SIZE]; + const char* path = getcwd(cwd, CWD_SIZE); + if ( !path ) { path = "."; } + if ( 1 < argc ) { path = argv[1]; } return ls(path); diff --git a/utils/mxsh.cpp b/utils/mxsh.cpp index dfbd474e..f495a18d 100644 --- a/utils/mxsh.cpp +++ b/utils/mxsh.cpp @@ -14,7 +14,12 @@ int status = 0; void command() { - printf("root@sortix / # "); + const size_t CWD_SIZE = 512; + char cwd[CWD_SIZE]; + const char* wd = getcwd(cwd, CWD_SIZE); + if ( !wd ) { wd = "?"; } + + printf("root@sortix %s # ", wd); const size_t commandsize = 128; char command[commandsize + 1]; @@ -81,6 +86,19 @@ void command() exit(atoi(status)); } + if ( strcmp(argv[0], "cd") == 0 ) + { + status = 0; + const char* newdir = "/"; + if ( 1 < argc ) { newdir = argv[1]; } + if ( chdir(newdir) ) + { + printf("cd: %s: cannot change directory\n", newdir); + status = 1; + } + return; + } + pid_t child = fork(); if ( child < 0 ) { printf("fork failed\n"); return; } if ( child != 0 )