127 lines
2.6 KiB
C
127 lines
2.6 KiB
C
|
#include <defs.h>
|
||
|
#include <string.h>
|
||
|
#include <vfs.h>
|
||
|
#include <inode.h>
|
||
|
#include <iobuf.h>
|
||
|
#include <stat.h>
|
||
|
#include <proc.h>
|
||
|
#include <error.h>
|
||
|
#include <assert.h>
|
||
|
|
||
|
/*
|
||
|
* get_cwd_nolock - retrieve current process's working directory. without lock protect
|
||
|
*/
|
||
|
static struct inode *
|
||
|
get_cwd_nolock(void) {
|
||
|
return current->filesp->pwd;
|
||
|
}
|
||
|
/*
|
||
|
* set_cwd_nolock - set current working directory.
|
||
|
*/
|
||
|
static void
|
||
|
set_cwd_nolock(struct inode *pwd) {
|
||
|
current->filesp->pwd = pwd;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* lock_cfs - lock the fs related process on current process
|
||
|
*/
|
||
|
static void
|
||
|
lock_cfs(void) {
|
||
|
lock_files(current->filesp);
|
||
|
}
|
||
|
/*
|
||
|
* unlock_cfs - unlock the fs related process on current process
|
||
|
*/
|
||
|
static void
|
||
|
unlock_cfs(void) {
|
||
|
unlock_files(current->filesp);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* vfs_get_curdir - Get current directory as a inode.
|
||
|
*/
|
||
|
int
|
||
|
vfs_get_curdir(struct inode **dir_store) {
|
||
|
struct inode *node;
|
||
|
if ((node = get_cwd_nolock()) != NULL) {
|
||
|
vop_ref_inc(node);
|
||
|
*dir_store = node;
|
||
|
return 0;
|
||
|
}
|
||
|
return -E_NOENT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* vfs_set_curdir - Set current directory as a inode.
|
||
|
* The passed inode must in fact be a directory.
|
||
|
*/
|
||
|
int
|
||
|
vfs_set_curdir(struct inode *dir) {
|
||
|
int ret = 0;
|
||
|
lock_cfs();
|
||
|
struct inode *old_dir;
|
||
|
if ((old_dir = get_cwd_nolock()) != dir) {
|
||
|
if (dir != NULL) {
|
||
|
uint32_t type;
|
||
|
if ((ret = vop_gettype(dir, &type)) != 0) {
|
||
|
goto out;
|
||
|
}
|
||
|
if (!S_ISDIR(type)) {
|
||
|
ret = -E_NOTDIR;
|
||
|
goto out;
|
||
|
}
|
||
|
vop_ref_inc(dir);
|
||
|
}
|
||
|
set_cwd_nolock(dir);
|
||
|
if (old_dir != NULL) {
|
||
|
vop_ref_dec(old_dir);
|
||
|
}
|
||
|
}
|
||
|
out:
|
||
|
unlock_cfs();
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* vfs_chdir - Set current directory, as a pathname. Use vfs_lookup to translate
|
||
|
* it to a inode.
|
||
|
*/
|
||
|
int
|
||
|
vfs_chdir(char *path) {
|
||
|
int ret;
|
||
|
struct inode *node;
|
||
|
if ((ret = vfs_lookup(path, &node)) == 0) {
|
||
|
ret = vfs_set_curdir(node);
|
||
|
vop_ref_dec(node);
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
/*
|
||
|
* vfs_getcwd - retrieve current working directory(cwd).
|
||
|
*/
|
||
|
int
|
||
|
vfs_getcwd(struct iobuf *iob) {
|
||
|
int ret;
|
||
|
struct inode *node;
|
||
|
if ((ret = vfs_get_curdir(&node)) != 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
assert(node->in_fs != NULL);
|
||
|
|
||
|
const char *devname = vfs_get_devname(node->in_fs);
|
||
|
if ((ret = iobuf_move(iob, (char *)devname, strlen(devname), 1, NULL)) != 0) {
|
||
|
goto out;
|
||
|
}
|
||
|
char colon = ':';
|
||
|
if ((ret = iobuf_move(iob, &colon, sizeof(colon), 1, NULL)) != 0) {
|
||
|
goto out;
|
||
|
}
|
||
|
ret = vop_namefile(node, iob);
|
||
|
|
||
|
out:
|
||
|
vop_ref_dec(node);
|
||
|
return ret;
|
||
|
}
|
||
|
|