mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 11:22:45 +00:00 
			
		
		
		
	Implement sys$chdir() and teach sh+ls to cd around and browse different dirs.
This commit is contained in:
		
							parent
							
								
									ac738b03d6
								
							
						
					
					
						commit
						2749e7f1c2
					
				
					 16 changed files with 147 additions and 33 deletions
				
			
		|  | @ -110,6 +110,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) | |||
|         return 0; | ||||
|     case Syscall::GetArguments: | ||||
|         return current->sys$get_arguments((int*)arg1, (char***)arg2); | ||||
|     case Syscall::PosixChdir: | ||||
|         return current->sys$chdir((const char*)arg1); | ||||
|     default: | ||||
|         kprintf("int0x80: Unknown function %x requested {%x, %x, %x}\n", function, arg1, arg2, arg3); | ||||
|         break; | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ enum Function { | |||
|     PosixGettimeofday = 0x2000, | ||||
|     PosixGethostname = 0x2001, | ||||
|     GetArguments = 0x2002, | ||||
|     PosixChdir = 0x2003, | ||||
| }; | ||||
| 
 | ||||
| void initialize(); | ||||
|  |  | |||
|  | @ -205,7 +205,14 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren | |||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     auto handle = VirtualFileSystem::the().open(path); | ||||
|     RetainPtr<VirtualFileSystem::Node> cwd; | ||||
|     { | ||||
|         InterruptDisabler disabler; | ||||
|         if (auto* parentTask = Task::fromPID(parentPID)) | ||||
|             cwd = parentTask->m_cwd.copyRef(); | ||||
|     } | ||||
| 
 | ||||
|     auto handle = VirtualFileSystem::the().open(path, cwd.ptr()); | ||||
|     if (!handle) { | ||||
|         error = -ENOENT; // FIXME: Get a more detailed error from VFS.
 | ||||
|         return nullptr; | ||||
|  | @ -327,9 +334,9 @@ Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring) | |||
| 
 | ||||
|     auto* parentTask = Task::fromPID(parentPID); | ||||
|     if (parentTask) | ||||
|         m_cwd = parentTask->m_cwd; | ||||
|         m_cwd = parentTask->m_cwd.copyRef(); | ||||
|     else | ||||
|         m_cwd = "/"; | ||||
|         m_cwd = nullptr; | ||||
| 
 | ||||
|     m_nextRegion = LinearAddress(0x600000); | ||||
| 
 | ||||
|  | @ -712,22 +719,29 @@ int Task::sys$close(int fd) | |||
| 
 | ||||
| int Task::sys$lstat(const char* path, void* statbuf) | ||||
| { | ||||
|     auto handle = VirtualFileSystem::the().open(move(path)); | ||||
|     auto handle = VirtualFileSystem::the().open(move(path), m_cwd.ptr()); | ||||
|     if (!handle) | ||||
|         return -1; | ||||
|     handle->stat((Unix::stat*)statbuf); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int Task::sys$chdir(const char* path) | ||||
| { | ||||
|     auto handle = VirtualFileSystem::the().open(path, m_cwd.ptr()); | ||||
|     if (!handle) | ||||
|         return -ENOENT; // FIXME: More detailed error.
 | ||||
|     if (!handle->isDirectory()) | ||||
|         return -ENOTDIR; | ||||
|     m_cwd = handle->vnode(); | ||||
|     kprintf("m_cwd <- %p (%u)\n", m_cwd.ptr(), handle->vnode()->inode.index()); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int Task::sys$getcwd(char* buffer, size_t size) | ||||
| { | ||||
|     if (size < m_cwd.length() + 1) { | ||||
|         // FIXME: return -ERANGE;
 | ||||
|         return -1; | ||||
|     } | ||||
|     memcpy(buffer, m_cwd.characters(), m_cwd.length()); | ||||
|     buffer[m_cwd.length()] = '\0'; | ||||
|     return 0; | ||||
|     // FIXME: Implement!
 | ||||
|     return -ENOTIMPL; | ||||
| } | ||||
| 
 | ||||
| int Task::sys$open(const char* path, size_t pathLength) | ||||
|  | @ -744,7 +758,7 @@ int Task::sys$open(const char* path, size_t pathLength) | |||
| 
 | ||||
| FileHandle* Task::openFile(String&& path) | ||||
| { | ||||
|     auto handle = VirtualFileSystem::the().open(move(path)); | ||||
|     auto handle = VirtualFileSystem::the().open(move(path), m_cwd.ptr()); | ||||
|     if (!handle) { | ||||
| #ifdef DEBUG_IO | ||||
|         kprintf("vfs::open() failed\n"); | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include "TSS.h" | ||||
| #include <AK/Vector.h> | ||||
| #include "i386.h" | ||||
| #include <VirtualFileSystem/VirtualFileSystem.h> | ||||
| 
 | ||||
| //#define TASK_SANITY_CHECKS
 | ||||
| 
 | ||||
|  | @ -98,6 +99,7 @@ public: | |||
|     int sys$munmap(void*, size_t size); | ||||
|     int sys$get_dir_entries(int fd, void*, size_t); | ||||
|     int sys$getcwd(char*, size_t); | ||||
|     int sys$chdir(const char*); | ||||
|     int sys$sleep(unsigned seconds); | ||||
|     int sys$gettimeofday(timeval*); | ||||
|     int sys$gethostname(char* name, size_t length); | ||||
|  | @ -150,7 +152,7 @@ private: | |||
|     pid_t m_waitee { -1 }; | ||||
|     int m_fdBlockedOnRead { -1 }; | ||||
| 
 | ||||
|     String m_cwd; | ||||
|     RetainPtr<VirtualFileSystem::Node> m_cwd; | ||||
| 
 | ||||
|     struct Region { | ||||
|         Region(LinearAddress, size_t, RetainPtr<Zone>&&, String&&); | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							|  | @ -37,3 +37,5 @@ | |||
| #define ENAMETOOLONG 36 // Name too long
 | ||||
| 
 | ||||
| #define EOVERFLOW 75    // Value too large for defined data type
 | ||||
| 
 | ||||
| #define ENOTIMPL 999    // Not implemented
 | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ dirent* readdir(DIR* dirp) | |||
|         dirp->nextptr = dirp->buffer; | ||||
|     } | ||||
| 
 | ||||
|     if (dirp->nextptr > (dirp->buffer + dirp->buffer_size)) | ||||
|     if (dirp->nextptr >= (dirp->buffer + dirp->buffer_size)) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     auto* sys_ent = (sys_dirent*)dirp->nextptr; | ||||
|  |  | |||
|  | @ -69,6 +69,7 @@ const char* strerror(int errnum) | |||
|     case ERANGE: return "Math result not representable"; | ||||
|     case ENAMETOOLONG: return "Name too long"; | ||||
|     case EOVERFLOW: return "Value too large for data type"; | ||||
|     case ENOTIMPL: return "Not implemented"; | ||||
|     } | ||||
|     printf("strerror() missing string for errnum=%d\n", errnum); | ||||
|     return "Unknown error"; | ||||
|  |  | |||
|  | @ -51,6 +51,12 @@ int lstat(const char* path, stat* statbuf) | |||
|     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||
| } | ||||
| 
 | ||||
| int chdir(const char* path) | ||||
| { | ||||
|     int rc = Syscall::invoke(Syscall::PosixChdir, (dword)path); | ||||
|     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||
| } | ||||
| 
 | ||||
| char* getcwd(char* buffer, size_t size) | ||||
| { | ||||
|     int rc = Syscall::invoke(Syscall::PosixGetcwd, (dword)buffer, (dword)size); | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ int open(const char* path); | |||
| ssize_t read(int fd, void* buf, size_t count); | ||||
| int close(int fd); | ||||
| pid_t waitpid(pid_t); | ||||
| int chdir(const char* path); | ||||
| char* getcwd(char* buffer, size_t size); | ||||
| int lstat(const char* path, stat* statbuf); | ||||
| int sleep(unsigned seconds); | ||||
|  |  | |||
|  | @ -4,14 +4,14 @@ | |||
| 
 | ||||
| int main(int c, char** v) | ||||
| { | ||||
|     DIR* dirp = opendir("/"); | ||||
|     DIR* dirp = opendir("."); | ||||
|     if (!dirp) { | ||||
|         printf("opendir failed :(\n"); | ||||
|         return 1; | ||||
|     } | ||||
|     char pathbuf[256]; | ||||
|     while (auto* de = readdir(dirp)) { | ||||
|         sprintf(pathbuf, "/%s", de->d_name); | ||||
|         sprintf(pathbuf, "%s", de->d_name); | ||||
|         stat st; | ||||
|         int rc = lstat(pathbuf, &st); | ||||
|         if (rc == -1) { | ||||
|  |  | |||
|  | @ -3,6 +3,9 @@ | |||
| #include <LibC/process.h> | ||||
| #include <LibC/errno.h> | ||||
| #include <LibC/string.h> | ||||
| #include <LibC/stdlib.h> | ||||
| 
 | ||||
| char* g_cwd = nullptr; | ||||
| 
 | ||||
| static void prompt() | ||||
| { | ||||
|  | @ -12,12 +15,63 @@ static void prompt() | |||
|         printf("$ "); | ||||
| } | ||||
| 
 | ||||
| static int sh_pwd(int, const char**) | ||||
| { | ||||
|     printf("cwd: %s\n", g_cwd); | ||||
| } | ||||
| 
 | ||||
| static int sh_cd(int argc, const char** argv) | ||||
| { | ||||
|     if (argc == 1) { | ||||
|         printf("usage: cd <path>\n"); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     char pathbuf[128]; | ||||
|     if (argv[1][1] == '/') | ||||
|         memcpy(pathbuf, argv[1], strlen(argv[1])); | ||||
|     else | ||||
|         sprintf(pathbuf, "%s/%s", g_cwd, argv[1]); | ||||
|     struct stat st; | ||||
|     int rc = lstat(pathbuf, &st); | ||||
|     if (rc < 0) { | ||||
|         printf("lstat(%s) failed: %s\n", pathbuf, strerror(errno)); | ||||
|         return 1; | ||||
|     } | ||||
|     if (!S_ISDIR(st.st_mode)) { | ||||
|         printf("Not a directory: %s\n", pathbuf); | ||||
|         return 1; | ||||
|     } | ||||
|     rc = chdir(pathbuf); | ||||
|     if (rc < 0) { | ||||
|         printf("chdir(%s) failed: %s\n", pathbuf, strerror(errno)); | ||||
|         return 1; | ||||
|     } | ||||
|     memcpy(g_cwd, pathbuf, strlen(pathbuf)); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static bool handle_builtin(int argc, const char** argv, int& retval) | ||||
| { | ||||
|     if (argc == 0) | ||||
|         return false; | ||||
|     if (!strcmp(argv[0], "cd")) { | ||||
|         retval = sh_cd(argc, argv); | ||||
|         return true; | ||||
|     } | ||||
|     if (!strcmp(argv[0], "pwd")) { | ||||
|         retval = sh_pwd(argc, argv); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static int runcmd(char* cmd) | ||||
| { | ||||
|     if (cmd[0] == 0) | ||||
|         return 0; | ||||
|     char buf[128]; | ||||
|     sprintf(buf, "/bin/%s", cmd); | ||||
|     memcpy(buf, cmd, 128); | ||||
| 
 | ||||
|     const char* argv[32]; | ||||
|     size_t argi = 1; | ||||
|  | @ -30,16 +84,27 @@ static int runcmd(char* cmd) | |||
|         } | ||||
|     } | ||||
|     argv[argi + 1] = nullptr; | ||||
|     int ret = spawn(argv[0], argv); | ||||
| 
 | ||||
|     int retval = 0; | ||||
|     if (handle_builtin(argi, argv, retval)) { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     const char* search_path = "/bin"; | ||||
| 
 | ||||
|     char pathbuf[128]; | ||||
|     sprintf(pathbuf, "%s/%s", search_path, argv[0]); | ||||
|     int ret = spawn(pathbuf, argv); | ||||
|     if (ret == -1) { | ||||
|         printf("spawn failed: %s (%s)\n", cmd, strerror(errno)); | ||||
|         return 1; | ||||
|     } | ||||
|     // FIXME: waitpid should give us the spawned process's exit status
 | ||||
|     waitpid(ret); | ||||
|     return 0; | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
| int main(int c, char** v) | ||||
| int main(int, char**) | ||||
| { | ||||
|     char linebuf[128]; | ||||
|     int linedx = 0; | ||||
|  | @ -50,6 +115,9 @@ int main(int c, char** v) | |||
|         printf("failed to open /dev/keyboard :(\n"); | ||||
|         return 1; | ||||
|     } | ||||
|     g_cwd = (char*)malloc(1024); | ||||
|     g_cwd[0] = '/'; | ||||
|     g_cwd[1] = '\0'; | ||||
|     prompt(); | ||||
|     for (;;) { | ||||
|         char keybuf[16]; | ||||
|  |  | |||
|  | @ -128,6 +128,11 @@ ByteBuffer FileHandle::readEntireFile() | |||
|     return m_vnode->fileSystem()->readEntireInode(m_vnode->inode); | ||||
| } | ||||
| 
 | ||||
| bool FileHandle::isDirectory() const | ||||
| { | ||||
|     return m_vnode->metadata().isDirectory(); | ||||
| } | ||||
| 
 | ||||
| ssize_t FileHandle::get_dir_entries(byte* buffer, size_t size) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
|  |  | |||
|  | @ -20,6 +20,10 @@ public: | |||
| 
 | ||||
|     String absolutePath() const; | ||||
| 
 | ||||
|     bool isDirectory() const; | ||||
| 
 | ||||
|     VirtualFileSystem::Node* vnode() { return m_vnode.ptr(); } | ||||
| 
 | ||||
| #ifdef SERENITY | ||||
|     int fd() const { return m_fd; } | ||||
|     void setFD(int fd) { m_fd = fd; } | ||||
|  |  | |||
|  | @ -168,9 +168,9 @@ void VirtualFileSystem::freeNode(Node* node) | |||
|     m_nodeFreeList.append(move(node)); | ||||
| } | ||||
| 
 | ||||
| bool VirtualFileSystem::isDirectory(const String& path) | ||||
| bool VirtualFileSystem::isDirectory(const String& path, Node* base) | ||||
| { | ||||
|     auto inode = resolvePath(path); | ||||
|     auto inode = resolvePath(path, base); | ||||
|     if (!inode.isValid()) | ||||
|         return false; | ||||
| 
 | ||||
|  | @ -355,11 +355,11 @@ bool VirtualFileSystem::touch(const String& path) | |||
|     return inode.fileSystem()->setModificationTime(inode, ktime(nullptr)); | ||||
| } | ||||
| 
 | ||||
| OwnPtr<FileHandle> VirtualFileSystem::open(const String& path) | ||||
| OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, Node* base) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|     auto inode = resolvePath(path); | ||||
|     auto inode = resolvePath(path, base); | ||||
|     if (!inode.isValid()) | ||||
|         return nullptr; | ||||
|     auto vnode = getOrCreateNode(inode); | ||||
|  | @ -368,7 +368,7 @@ OwnPtr<FileHandle> VirtualFileSystem::open(const String& path) | |||
|     return make<FileHandle>(move(vnode)); | ||||
| } | ||||
| 
 | ||||
| OwnPtr<FileHandle> VirtualFileSystem::create(const String& path) | ||||
| OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, Node* base) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|  | @ -378,7 +378,7 @@ OwnPtr<FileHandle> VirtualFileSystem::create(const String& path) | |||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path) | ||||
| OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path, Node* base) | ||||
| { | ||||
|     Locker locker(VirtualFileSystem::lock()); | ||||
| 
 | ||||
|  | @ -398,10 +398,18 @@ InodeIdentifier VirtualFileSystem::resolveSymbolicLink(const String& basePath, I | |||
|     return resolvePath(buf); | ||||
| } | ||||
| 
 | ||||
| InodeIdentifier VirtualFileSystem::resolvePath(const String& path) | ||||
| InodeIdentifier VirtualFileSystem::resolvePath(const String& path, Node* base) | ||||
| { | ||||
|     if (path.isEmpty()) | ||||
|         return { }; | ||||
| 
 | ||||
|     auto parts = path.split('/'); | ||||
|     InodeIdentifier inode = m_rootNode->inode; | ||||
|     InodeIdentifier inode; | ||||
| 
 | ||||
|     if (path[0] == '/') | ||||
|         inode = m_rootNode->inode; | ||||
|     else | ||||
|         inode = base ? base->inode : m_rootNode->inode; | ||||
| 
 | ||||
|     for (unsigned i = 0; i < parts.size(); ++i) { | ||||
|         auto& part = parts[i]; | ||||
|  |  | |||
|  | @ -51,7 +51,7 @@ public: | |||
|     VirtualFileSystem(); | ||||
|     ~VirtualFileSystem(); | ||||
| 
 | ||||
|     bool isDirectory(const String& path); | ||||
|     bool isDirectory(const String& path, Node* base = nullptr); | ||||
|     void listDirectory(const String& path); | ||||
|     void listDirectoryRecursively(const String& path); | ||||
| 
 | ||||
|  | @ -64,9 +64,9 @@ public: | |||
|     bool mountRoot(RetainPtr<FileSystem>&&); | ||||
|     bool mount(RetainPtr<FileSystem>&&, const String& path); | ||||
| 
 | ||||
|     OwnPtr<FileHandle> open(const String& path); | ||||
|     OwnPtr<FileHandle> create(const String& path); | ||||
|     OwnPtr<FileHandle> mkdir(const String& path); | ||||
|     OwnPtr<FileHandle> open(const String& path, Node* base = nullptr); | ||||
|     OwnPtr<FileHandle> create(const String& path, Node* base = nullptr); | ||||
|     OwnPtr<FileHandle> mkdir(const String& path, Node* base = nullptr); | ||||
| 
 | ||||
|     bool isRoot(InodeIdentifier) const; | ||||
| 
 | ||||
|  | @ -79,7 +79,7 @@ private: | |||
| 
 | ||||
|     void enumerateDirectoryInode(InodeIdentifier, Function<bool(const FileSystem::DirectoryEntry&)>); | ||||
|     String absolutePath(InodeIdentifier); | ||||
|     InodeIdentifier resolvePath(const String& path); | ||||
|     InodeIdentifier resolvePath(const String& path, Node* base = nullptr); | ||||
|     InodeIdentifier resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode); | ||||
| 
 | ||||
|     RetainPtr<Node> allocateNode(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling