1 #include <stdio.h> 2 #include <stdbool.h> 3 #include <string.h> 4 #include <dprintf.h> 5 #include <fcntl.h> 6 #include "fs.h" 7 #include "cache.h" 8 9 /* 10 * Convert a relative pathname to an absolute pathname 11 * In the future this might also resolve symlinks... 12 */ 13 void pm_realpath(com32sys_t *regs) 14 { 15 const char *src = MK_PTR(regs->ds, regs->esi.w[0]); 16 char *dst = MK_PTR(regs->es, regs->edi.w[0]); 17 18 realpath(dst, src, FILENAME_MAX); 19 } 20 21 static size_t copy_string(char *buf, size_t ix, size_t bufsize, const char *src) 22 { 23 char c; 24 25 while ((c = *src++)) { 26 if (ix+1 < bufsize) 27 buf[ix] = c; 28 ix++; 29 } 30 31 if (ix < bufsize) 32 buf[ix] = '\0'; 33 34 return ix; 35 } 36 37 static size_t generic_inode_to_path(struct inode *inode, char *dst, size_t bufsize) 38 { 39 size_t s = 0; 40 41 dprintf("inode %p name %s\n", inode, inode->name); 42 43 if (inode->parent) { 44 if (!inode->name) /* Only the root should have no name */ 45 return -1; 46 47 s = generic_inode_to_path(inode->parent, dst, bufsize); 48 if (s == (size_t)-1) 49 return s; /* Error! */ 50 51 s = copy_string(dst, s, bufsize, "/"); 52 s = copy_string(dst, s, bufsize, inode->name); 53 } 54 55 return s; 56 } 57 58 __export size_t realpath(char *dst, const char *src, size_t bufsize) 59 { 60 int rv; 61 struct file *file; 62 size_t s; 63 64 dprintf("realpath: input: %s\n", src); 65 66 if (this_fs->fs_ops->realpath) { 67 s = this_fs->fs_ops->realpath(this_fs, dst, src, bufsize); 68 } else { 69 rv = searchdir(src, O_RDONLY); 70 if (rv < 0) { 71 dprintf("realpath: searchpath failure\n"); 72 return -1; 73 } 74 75 file = handle_to_file(rv); 76 s = generic_inode_to_path(file->inode, dst, bufsize); 77 if (s == 0) 78 s = copy_string(dst, 0, bufsize, "/"); 79 80 _close_file(file); 81 } 82 83 dprintf("realpath: output: %s\n", dst); 84 return s; 85 } 86 87 __export int chdir(const char *src) 88 { 89 int rv; 90 struct file *file; 91 char cwd_buf[CURRENTDIR_MAX]; 92 size_t s; 93 94 dprintf("chdir: from %s (inode %p) add %s\n", 95 this_fs->cwd_name, this_fs->cwd, src); 96 97 if (this_fs->fs_ops->chdir) 98 return this_fs->fs_ops->chdir(this_fs, src); 99 100 /* Otherwise it is a "conventional filesystem" */ 101 rv = searchdir(src, O_RDONLY|O_DIRECTORY); 102 if (rv < 0) 103 return rv; 104 105 file = handle_to_file(rv); 106 if (file->inode->mode != DT_DIR) { 107 _close_file(file); 108 return -1; 109 } 110 111 put_inode(this_fs->cwd); 112 this_fs->cwd = get_inode(file->inode); 113 _close_file(file); 114 115 /* Save the current working directory */ 116 s = generic_inode_to_path(this_fs->cwd, cwd_buf, CURRENTDIR_MAX-1); 117 118 /* Make sure the cwd_name ends in a slash, it's supposed to be a prefix */ 119 if (s < 1 || cwd_buf[s-1] != '/') 120 cwd_buf[s++] = '/'; 121 122 if (s >= CURRENTDIR_MAX) 123 s = CURRENTDIR_MAX - 1; 124 125 cwd_buf[s++] = '\0'; 126 memcpy(this_fs->cwd_name, cwd_buf, s); 127 128 dprintf("chdir: final %s (inode %p)\n", 129 this_fs->cwd_name, this_fs->cwd); 130 131 return 0; 132 } 133