AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
link.c
Go to the documentation of this file.
1
5
6#include <core/system.h>
7#include <fs/vfs.h>
8#include <aquila/fcntl.h>
9
24int vfs_link(const char *oldpath, struct uio *ouio, const char *newpath, struct uio *nuio)
25{
26 int ret = 0;
27 struct vnode *vnode = NULL, *dir = NULL, *odir = NULL;
28 char *name = NULL;
29 struct uio *uio = nuio;
30
31 if ((ret = vfs_lookup_dir(oldpath, ouio, &vnode, &odir)))
32 return ret;
33
34 if (S_ISDIR(vnode->mode)) {
35 ret = -EPERM;
36 goto done;
37 }
38
39 if ((ret = vfs_lookup_parent(newpath, nuio, &dir, &name))) {
40 if (ret == -EBUSY)
41 ret = -EEXIST;
42 goto done;
43 }
44
45 /* both must be in the same mounted filesystem */
46 if (vfs_mount_root_of(odir) != vfs_mount_root_of(dir)) {
47 ret = -EXDEV;
48 goto done;
49 }
50
51 if ((ret = vfs_access(dir, uio, VFS_W | VFS_X)))
52 goto done;
53
54 ret = vfs_vlink(dir, name, vnode, uio);
55
56done:
57 if (dir) vfs_close(dir);
58 vfs_close(odir);
60 kfree(name);
61 return ret;
62}
63
72int vfs_symlink(const char *target, const char *path, struct uio *uio)
73{
74 int ret = 0;
75 struct vnode *vnode = NULL;
76 size_t len = strlen(target);
77
78 if (!len)
79 return -ENOENT;
80
81 if ((ret = vfs_mknod(path, S_IFLNK | 0777, 0, uio, &vnode)))
82 return ret;
83
84 ssize_t written = vfs_write(vnode, 0, len, (void *) target);
86
87 if (written != (ssize_t) len) {
88 vfs_unlink(path, uio);
89 return written < 0 ? written : -EIO;
90 }
91
92 return 0;
93}
94
105ssize_t vfs_readlink(const char *path, struct uio *uio, char *buf, size_t size)
106{
107 struct vnode *vnode = NULL;
108 struct uio link_uio = *uio;
109 link_uio.flags |= O_NOFOLLOW;
110
111 ssize_t ret = vfs_lookup(path, &link_uio, &vnode);
112
113 if (ret)
114 return ret;
115
116 if (S_ISLNK(vnode->mode))
117 ret = vfs_read(vnode, 0, MIN(size, vnode->size), buf);
118 else
119 ret = -EINVAL;
120
122 return ret;
123}
124
127static int entry_get(struct vnode *dir, const char *name, struct vnode **ref)
128{
129 struct dirent dirent;
130 int ret = vfs_finddir(dir, name, &dirent);
131
132 *ref = NULL;
133
134 if (ret == -ENOENT)
135 return 0;
136
137 return ret ? ret : vfs_vget(dir, dirent.d_ino, ref);
138}
139
154int vfs_rename(const char *oldpath, struct uio *ouio, const char *newpath, struct uio *nuio)
155{
156 int ret = 0;
157 struct vnode *odir = NULL, *ndir = NULL, *ovnode = NULL, *nvnode = NULL;
158 char *oname = NULL, *nname = NULL;
159 struct uio *uio = ouio;
160
161 if ((ret = vfs_lookup_parent(oldpath, ouio, &odir, &oname)))
162 goto done;
163
164 if ((ret = vfs_lookup_parent(newpath, nuio, &ndir, &nname)))
165 goto done;
166
167 if ((ret = vfs_access(odir, uio, VFS_W | VFS_X)) ||
168 (ret = vfs_access(ndir, uio, VFS_W | VFS_X)))
169 goto done;
170
171 if ((ret = entry_get(odir, oname, &ovnode)))
172 goto done;
173
174 if (!ovnode) {
175 ret = -ENOENT;
176 goto done;
177 }
178
179 if ((ret = entry_get(ndir, nname, &nvnode)))
180 goto done;
181
182 /* renaming a file to itself (or to another link to it) does nothing */
183 if (ovnode == nvnode || (odir == ndir && !strcmp(oname, nname)))
184 goto done;
185
186 /* both must be in the same mounted filesystem */
187 if (vfs_mount_root_of(odir) != vfs_mount_root_of(ndir)) {
188 ret = -EXDEV;
189 goto done;
190 }
191
192 /* a directory can't be moved into itself */
193 if (S_ISDIR(ovnode->mode) && vfs_under(ndir, ovnode)) {
194 ret = -EINVAL;
195 goto done;
196 }
197
198 if (nvnode) {
199 if (S_ISDIR(ovnode->mode) && !S_ISDIR(nvnode->mode)) {
200 ret = -ENOTDIR;
201 goto done;
202 }
203
204 if (!S_ISDIR(ovnode->mode) && S_ISDIR(nvnode->mode)) {
205 ret = -EISDIR;
206 goto done;
207 }
208
209 if (S_ISDIR(nvnode->mode) && !vfs_dir_empty(nvnode)) {
210 ret = -ENOTEMPTY;
211 goto done;
212 }
213 }
214
215 /* the filesystem replaces an entry at the new name */
216 ret = vfs_vrename(odir, oname, ndir, nname, uio);
217
218done:
219 if (nvnode) vfs_close(nvnode);
220 if (ovnode) vfs_close(ovnode);
221 if (ndir) vfs_close(ndir);
222 if (odir) vfs_close(odir);
223
224 kfree(oname);
225 kfree(nname);
226 return ret;
227}
int vfs_close(struct vnode *vnode)
Drops a reference to a vnode.
Definition close.c:18
#define MIN(a, b)
Definition system.h:11
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
int vfs_lookup_dir(const char *path, struct uio *uio, struct vnode **ref, struct vnode **dir)
Finds the vnode a path names, as vfs_lookup() does, and the directory it was found in.
Definition lookup.c:381
int vfs_lookup_parent(const char *path, struct uio *uio, struct vnode **dir, char **name)
Finds the directory of a path's last component, and the component's name, to make or remove an entry ...
Definition lookup.c:414
struct vnode * vfs_mount_root_of(struct vnode *vnode)
Finds the root of the mounted filesystem a vnode is in.
Definition lookup.c:452
int vfs_under(struct vnode *vnode, struct vnode *dir)
Says whether a vnode is a directory or under it, in the same filesystem: rename() can't move a direct...
Definition lookup.c:473
int vfs_lookup(const char *path, struct uio *uio, struct vnode **ref)
Finds the vnode a path names.
Definition lookup.c:349
int vfs_mknod(const char *path, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)
Makes a node at a path.
Definition mknod.c:21
ssize_t vfs_read(struct vnode *vnode, off_t off, size_t size, void *buf)
Reads from a vnode into a kernel buffer.
Definition read.c:52
int vfs_finddir(struct vnode *dir, const char *name, struct dirent *dirent)
Finds the entry of a directory that has a name.
Definition readdir.c:46
int vfs_dir_empty(struct vnode *dir)
Says whether a directory is empty, so that it can be removed.
Definition readdir.c:69
#define NULL
Definition stddef.h:27
Who does a filesystem operation: where its paths start, and its credentials and umask.
Definition vfs.h:60
uint32_t flags
Definition vfs.h:66
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
size_t size
Definition vfs.h:115
mode_t mode
Definition vfs.h:118
long int ssize_t
Definition types.h:12
int vfs_access(struct vnode *vnode, struct uio *uio, int mode)
Checks whether a user may access a vnode in a way: the owner's permissions apply to its owner,...
Definition vfs.c:114
#define VFS_W
Definition vfs.h:296
#define VFS_X
Definition vfs.h:297
int vfs_vget(struct vnode *super, ino_t ino, struct vnode **ref)
Gets the vnode of an inode, by its number.
Definition vops.c:176
int vfs_vlink(struct vnode *dir, const char *fn, struct vnode *vnode, struct uio *uio)
Adds a name for an existing file (a hard link) to a directory of the same filesystem.
Definition vops.c:103
int vfs_vrename(struct vnode *odir, const char *ofn, struct vnode *ndir, const char *nfn, struct uio *uio)
Renames an entry, possibly to another directory of the same filesystem.
Definition vops.c:132
ssize_t vfs_write(struct vnode *vnode, off_t off, size_t size, void *buf)
Writes to a vnode from a kernel buffer.
Definition write.c:60