kbd: use a better get_key method
[thunix.git] / fs / namei.c
blob929b3b8fe65f7ef1e36f442b303eb20c6cb4189e
1 #include <stdio.h>
2 #include <string.h>
3 #include <malloc.h>
4 #include <thunix.h>
5 #include <fs.h>
6 #include <err.h>
8 /*
9 * Looking for an inode with the given path
11 * returns NULL for -ENOENT, ERROR for errors happend
12 * and inode for finding responding file or directory.
14 struct inode * namei(const char *name, uint32_t flag)
16 struct inode *inode;
17 struct inode *parent;
18 char part[256];
19 char *p;
21 FS_DEBUG("trying to open path: %s\n", name);
22 if (*name == '/') {
23 inode = root_fs()->root;
24 if (IS_ERR(inode))
25 panic("namei: Read root inode error!\n");
26 while (*name == '/')
27 name++;
28 } else {
29 inode = root_fs()->pwd;
30 FS_DEBUG("pwd->inode: %d\n", inode->i_ino);
32 parent = inode;
34 while (*name) {
35 p = part;
36 while (*name && *name != '/') {
37 if (p >= part + MAX_NAME_LEN)
38 return ERR_PTR(-ENAMETOOLONG);
39 *p++ = *name++;
41 *p = '\0';
42 while (*name && *name == '/')
43 name++;
44 if (!*name && (flag & LOOKUP_PARENT))
45 return parent;
46 FS_DEBUG("Looking for part: %s, parent->inode: %d\n", part, parent->i_ino);
47 inode = iget(part, parent);
48 if (IS_ERR_OR_NULL(inode))
49 break;
51 free_inode(parent);
52 parent = inode;
53 if (!*name)
54 break;
57 if (PTR_ERR(inode) == -ENOENT && flag & LOOKUP_CREATE) {
58 inode = parent->i_op->mknod(parent, part, TFS_FILE);
59 free_inode(parent);
60 if (IS_ERR(inode))
61 return ERR_CAST(inode);
62 if (inode->i_op->iwrite(inode)) {
63 free_inode(inode);
64 return ERR_PTR(-EIO);
68 return inode;
72 * Lookup the parent inode
74 * NOTE: the parent should be directory!
76 struct inode *namei_parent(const char *pathname)
78 struct inode *dir = namei(pathname, LOOKUP_PARENT);
80 if (!IS_ERR_OR_NULL(dir))
81 return dir ? ERR_CAST(dir) : ERR_PTR(-ENOENT);
83 if (!IS_DIR(dir)) {
84 free_inode(dir);
85 return ERR_PTR(-ENOTDIR);
88 return dir;
92 int sys_mkdir(const char *pathname)
94 int err;
95 struct inode *dir = namei_parent(pathname);
97 if (IS_ERR(dir))
98 return PTR_ERR(dir);
100 err = -ENOSYS;
101 if (dir->i_op && dir->i_op->mkdir)
102 err = dir->i_op->mkdir(dir, get_base_name(pathname));
104 free_inode(dir);
105 return err;
108 int sys_rmdir(const char *pathname)
110 struct inode *dir = namei_parent(pathname);
111 int err;
113 if (IS_ERR(dir))
114 return PTR_ERR(dir);
116 err = -ENOSYS;
117 if (dir->i_op && dir->i_op->rmdir)
118 err = dir->i_op->rmdir(dir, get_base_name(pathname));
120 free_inode(dir);
121 return err;
124 int sys_chdir(const char *pathname)
126 struct inode * inode;
127 char *cwd;
129 while (*pathname && *pathname == '.' && *(pathname + 1) == '/')
130 pathname += 2;
131 /* If we are changing to current dir, then just do nothing */
132 if (*pathname == '.' && !*(pathname + 1))
133 return 0;
135 inode = namei(pathname, 0);
136 if (IS_ERR_OR_NULL(inode))
137 return inode ? PTR_ERR(inode) : -ENOENT;
138 if (!IS_DIR(inode)) {
139 free_inode(inode);
140 return -ENOTDIR;
143 free_inode(root_fs()->pwd);
144 root_fs()->pwd = inode;
146 cwd = root_fs()->cwd;
147 if (*pathname == '/') {
148 strcpy(cwd, pathname);
149 } else if (strcmp(pathname, "..") == 0) {
150 char *p = strrchr(cwd, '/');
152 /* At least we have a '/' char */
153 if (!p)
154 return -EINVAL;
156 if (p == cwd)
157 *(p + 1) = '\0';
158 else
159 *p = '\0';
160 } else {
161 strcat(cwd, pathname);
164 return 0;
168 * The sys call to get the current directory
170 int sys_getcwd(char *buf, int size)
172 int len = strlen(root_fs()->cwd);
174 if (size <= 0)
175 return -EINVAL;
176 if (len > size)
177 return -ERANGE;
178 strcpy(buf, root_fs()->cwd);
179 return len;
182 int sys_unlink(const char *pathname)
184 struct inode *dir = namei_parent(pathname);
185 int err;
187 if (IS_ERR(dir))
188 return PTR_ERR(dir);
190 err = -ENOSYS;
191 if (dir->i_op && dir->i_op->unlink)
192 err = dir->i_op->unlink(dir, get_base_name(pathname));
194 free_inode(dir);
195 return err;