summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_descrip.c48
-rw-r--r--sys/kern/vfs_init.c3
-rw-r--r--sys/kern/vfs_lookup.c47
3 files changed, 90 insertions, 8 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index a2dd667..d4c9885 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -149,6 +149,7 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write)
{
char *kbuf = NULL;
ssize_t n;
+ uint32_t seal;
struct filedesc *filedes;
struct sio_txn sio;
scret_t retval = 0;
@@ -159,8 +160,17 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write)
}
filedes = fd_get(fd);
- kbuf = dynalloc(count);
+ seal = filedes->flags;
+ /* Check the seal */
+ if (write && !ISSET(seal, O_ALLOW_WR)) {
+ return -EPERM;
+ }
+ if (!write && ISSET(seal, O_WRONLY)) {
+ return -EPERM;
+ }
+
+ kbuf = dynalloc(count);
if (kbuf == NULL) {
retval = -ENOMEM;
goto done;
@@ -229,6 +239,29 @@ done:
return retval;
}
+static int
+fd_do_create(const char *path, struct nameidata *ndp)
+{
+ struct vop_create_args cargs;
+ struct vnode *dirvp = ndp->vp;
+ const struct vops *vops = dirvp->vops;
+ int error;
+
+ if (vops->create == NULL) {
+ return -EINVAL;
+ }
+
+ cargs.path = path;
+ cargs.ppath = ndp->path;
+ cargs.dirvp = dirvp;
+ cargs.vpp = &ndp->vp;
+ if ((error = vops->create(&cargs)) < 0) {
+ return error;
+ }
+
+ return 0;
+}
+
int
fd_read(unsigned int fd, void *buf, size_t count)
{
@@ -247,18 +280,17 @@ fd_write(unsigned int fd, void *buf, size_t count)
*
* @pathname: Path of file to open.
* @flags: Flags to use.
- *
- * TODO: Use of flags.
*/
int
fd_open(const char *pathname, int flags)
{
int error;
+ const struct vops *vops;
struct filedesc *filedes;
struct nameidata nd;
nd.path = pathname;
- nd.flags = 0;
+ nd.flags = ISSET(flags, O_CREAT) ? NAMEI_WANTPARENT : 0;
if ((error = namei(&nd)) < 0) {
return error;
@@ -269,6 +301,14 @@ fd_open(const char *pathname, int flags)
return error;
}
+ vops = nd.vp->vops;
+ if (ISSET(flags, O_CREAT) && vops->create != NULL) {
+ error = fd_do_create(pathname, &nd);
+ }
+ if (error < 0) {
+ return error;
+ }
+
filedes->vp = nd.vp;
filedes->flags = flags;
return filedes->fdno;
diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c
index 8c1bc74..bc7f8b0 100644
--- a/sys/kern/vfs_init.c
+++ b/sys/kern/vfs_init.c
@@ -37,7 +37,8 @@ struct vnode *g_root_vnode = NULL;
static struct fs_info fs_list[] = {
{MOUNT_RAMFS, &g_initramfs_vfsops, 0, 0},
{MOUNT_DEVFS, &g_devfs_vfsops, 0, 0},
- {MOUNT_CTLFS, &g_ctlfs_vfsops, 0, 0}
+ {MOUNT_CTLFS, &g_ctlfs_vfsops, 0, 0},
+ {MOUNT_TMPFS, &g_tmpfs_vfsops, 0, 0}
};
void
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index d04b812..d88c447 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -29,6 +29,7 @@
#include <sys/namei.h>
#include <sys/vnode.h>
+#include <sys/param.h>
#include <sys/mount.h>
#include <sys/errno.h>
#include <vm/dynalloc.h>
@@ -118,20 +119,60 @@ vfs_get_fname_at(const char *path, size_t idx)
}
/*
+ * Count the number of components that exist within
+ * a path minus the delimiter as well as any redundant
+ * delimiters.
+ *
+ * @path: Path to count
+ */
+static uint8_t
+namei_num_cnp(const char *path)
+{
+ const char *p = path;
+ uint8_t count = 0;
+
+ while (*p != '\0') {
+ /* Skip redundant delimiters */
+ if (p[0] == '/' && p[1] == '/') {
+ ++p;
+ continue;
+ }
+
+ if (*p == '/') {
+ ++count;
+ }
+ ++p;
+ }
+
+ /* Don't count leading slash */
+ if (*(p - 1) == '/') {
+ --count;
+ }
+
+ return count;
+}
+
+/*
* Search for a path within a mountpoint.
*
* @mp: Mountpoint to search in.
* @path: Path to search for.
+ * @ndp: Namei data pointer
*/
static struct vnode *
-namei_mp_search(struct mount *mp, const char *path)
+namei_mp_search(struct mount *mp, const char *path, struct nameidata *ndp)
{
struct vop_lookup_args lookup_args;
struct vnode *vp = mp->vp;
+ uint8_t n_cnp = 0;
char *name;
int status;
- for (size_t i = 1;; ++i) {
+ n_cnp = namei_num_cnp(path);
+ if (ISSET(ndp->flags, NAMEI_WANTPARENT)) {
+ --n_cnp;
+ }
+ for (size_t i = 1; i < n_cnp; ++i) {
name = vfs_get_fname_at(path, i);
if (name == NULL)
break;
@@ -212,7 +253,7 @@ namei(struct nameidata *ndp)
/* If the name matches, search within */
if (strcmp(mp->name, name) == 0)
- vp = namei_mp_search(mp, path);
+ vp = namei_mp_search(mp, path, ndp);
/* Did we find it at this mountpoint? */
if (vp != NULL) {