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