Hello,
On Wed, 26 Aug 2026 14:06:04 Samuel Thibault wrote:
> > > > diff --git a/storeio/pager.c b/storeio/pager.c
> > > > index 11bf469..7df1a79 100644
> > > > --- a/storeio/pager.c
> > > > +++ b/storeio/pager.c
> > > > @@ -27,6 +27,7 @@
> > > > #include <error.h>
> > > > #include <sys/mman.h>
> > > > #include <stdio.h>
> > > > +#include <string.h>
> > > >
> > > > #include "dev.h"
> > > >
> > > > @@ -51,6 +52,11 @@ pager_read_page (struct user_pager_info *upi,
> > > > /* Read a partial page if necessary to avoid reading off
the end.
> > */
> > > > want = store->size - page;
> > > >
> > > > + void *new_buf = mmap (0, want, PROT_READ|PROT_WRITE,
MAP_ANON, 0, 0);
> > > > + if (new_buf == MAP_FAILED)
> > > > + return EIO;
> > > > +
> > > > + *((void **) buf) = new_buf;
> > > > err = dev_read (dev, page, want, (void **)buf, &read);
> > >
> > > Mmm, why always allocating? It's better to allocate lazily in
case the
> > > read can be directly be fed by raw_read i.e. store_read, and avoid
> > > a copy. That means keeping ensure_buf() etc., did you have a reason
> > > to remove it? You can make pager_read_page set buf to NULL, and let
> > > dev_read cope with that case, and otherwise try to use the provided
> > > buffer (netfs_attempt_read case).
> >
> > I think we can allocate memory in the pager_read_page function if
it hasn't
> > already been allocated.
>
> My point is that it would miss the opportunity to let functions further
> down do the allocation. In the current dev_read, when we call raw_read
> and there call store_read, it's store_read that can allocate it, which
> itself can delegate the allocation to the read method of the class etc.
> possibly up to a function that is happier to be able to provide an
> already-allocated buffer, rather than having to copy data into the
> buffer allocated by pager_read_page.
>
> > This way, dev_read will behave consistently.
>
> The buffer-return semantic explained above is a usual thing in the Hurd
> and avoids various copies.
Maybe it's better to leave dev_read and pager_read_page as is? The build
succeeds, and the Hurd starts and runs.
Thanks,
--
Mikhail Karpov
From 9d4e5452ff0b227499397540a192a878c47b0edb Mon Sep 17 00:00:00 2001
From: Mikhail Karpov <[email protected]>
Date: Thu, 27 Aug 2026 10:40:11 +0700
Subject: [PATCH] Migrating storeio from trivfs to netfs
---
storeio/Makefile | 13 +-
storeio/dev.c | 71 +--
storeio/dev.h | 107 ++--
storeio/io.c | 385 ---------------
storeio/open.c | 127 -----
storeio/open.h | 68 ---
storeio/pager.c | 12 +-
storeio/part.c | 162 +++++++
storeio/storeio.c | 1187 +++++++++++++++++++++++++++++++++++----------
9 files changed, 1214 insertions(+), 918 deletions(-)
delete mode 100644 storeio/io.c
delete mode 100644 storeio/open.c
delete mode 100644 storeio/open.h
create mode 100644 storeio/part.c
diff --git a/storeio/Makefile b/storeio/Makefile
index 5d9aeb4d..616dbc67 100644
--- a/storeio/Makefile
+++ b/storeio/Makefile
@@ -1,6 +1,7 @@
# Makefile for storeio
-#
-# Copyright (C) 1995, 1996, 1997, 2000, 2012 Free Software Foundation, Inc.
+#
+# Copyright (C) 1995, 1996, 1997, 2000, 2012, 2026 Free Software
+# Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -19,12 +20,14 @@
dir := storeio
makemode := server
+#CFLAGS += -DDEBUG
+
target = storeio storeio.static
-SRCS = dev.c storeio.c open.c pager.c io.c
+SRCS = dev.c storeio.c pager.c $(and $(PARTED_LIBS),part.c)
OBJS = $(SRCS:.c=.o)
-HURDLIBS = trivfs pager fshelp iohelp store ports ihash shouldbeinlibc
-LDLIBS = -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
+HURDLIBS = netfs pager fshelp iohelp store ports ihash shouldbeinlibc
+LDLIBS = -lpthread $(PARTED_LIBS) $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
include ../Makeconf
diff --git a/storeio/dev.c b/storeio/dev.c
index c87400c0..63ef2ce1 100644
--- a/storeio/dev.c
+++ b/storeio/dev.c
@@ -1,6 +1,6 @@
/* store `device' I/O
- Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2008
+ Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2008, 2026
Free Software Foundation, Inc.
Written by Miles Bader <[email protected]>
@@ -140,48 +140,33 @@ dev_buf_rw (struct dev *dev, size_t buf_offs, size_t *io_offs, size_t *len,
return 0;
}
}
-
-/* Called with DEV->lock held. Try to open the store underlying DEV. */
+
+/* Called with DEV->lock held. Initialize the DEV struct. */
error_t
-dev_open (struct dev *dev)
+dev_open_from_store (struct dev *dev, struct store *store)
{
- error_t err;
- const int flags = ((dev->readonly ? STORE_READONLY : 0)
- | (dev->no_fileio ? STORE_NO_FILEIO : 0));
-
- assert_backtrace (dev->store == 0);
-
- if (dev->store_name == 0)
- {
- /* This means we had no store arguments.
- We are to operate on our underlying node. */
- err = store_create (storeio_fsys->underlying, flags, 0, &dev->store);
- }
- else
- /* Open based on the previously parsed store arguments. */
- err = store_parsed_open (dev->store_name, flags, &dev->store);
- if (err)
- return err;
-
/* Inactivate the store, it will be activated at first access.
We ignore possible EINVAL here . XXX Pass STORE_INACTIVE to
store_create/store_parsed_open instead when libstore is fixed
to support this. */
+ dev->store = store;
store_set_flags (dev->store, STORE_INACTIVE);
- if (! dev->store->block_size)
+ if (!dev->store->block_size)
dev->buf = NULL;
else
dev->buf = mmap (0, dev->store->block_size, PROT_READ|PROT_WRITE,
- MAP_ANON, 0, 0);
+ MAP_ANON, 0, 0);
+
if (dev->buf == MAP_FAILED)
{
+ error_t err = errno;
store_free (dev->store);
dev->store = 0;
- return ENOMEM;
+ return err;
}
- if (!dev->inhibit_cache)
+ if (!storeio_stat.inhibit_cache)
{
dev->buf_offs = -1;
pthread_rwlock_init (&dev->io_lock, NULL);
@@ -192,6 +177,32 @@ dev_open (struct dev *dev)
return 0;
}
+
+/* Try to open the store underlying DEV. */
+error_t
+dev_open (struct dev *dev, struct store_parsed *store_name)
+{
+ error_t err;
+ const int flags = ((storeio_stat.readonly ? STORE_READONLY : 0)
+ | (storeio_stat.no_fileio ? STORE_NO_FILEIO : 0));
+
+ assert_backtrace (dev->store == 0);
+
+ struct store *store;
+ if (store_name == 0)
+ {
+ /* This means we had no store arguments.
+ We are to operate on our underlying node. */
+ err = store_create (underlying_node, flags, 0, &store);
+ }
+ else
+ /* Open based on the previously parsed store arguments. */
+ err = store_parsed_open (store_name, flags, &store);
+ if (err)
+ return err;
+
+ return dev_open_from_store (dev, store);
+}
/* Shut down the store underlying DEV and free any resources it consumes.
DEV itself remains intact so that dev_open can be called again.
@@ -201,7 +212,7 @@ dev_close (struct dev *dev)
{
assert_backtrace (dev->store);
- if (!dev->inhibit_cache)
+ if (!storeio_stat.inhibit_cache)
{
if (dev->pager != NULL)
pager_shutdown (dev->pager);
@@ -222,7 +233,7 @@ dev_sync(struct dev *dev, int wait)
{
error_t err;
- if (dev->inhibit_cache)
+ if (storeio_stat.inhibit_cache)
return 0;
/* Sync any paged backing store. */
@@ -359,7 +370,7 @@ dev_write (struct dev *dev, off_t offs, const void *buf, size_t len,
buf + io_offs, len, amount);
}
- if (dev->inhibit_cache)
+ if (storeio_stat.inhibit_cache)
{
/* Under --no-cache, we permit only whole-block writes.
Note that in this case we handle non-power-of-two block sizes. */
@@ -452,7 +463,7 @@ dev_read (struct dev *dev, off_t offs, size_t whole_amount,
return 0;
}
- if (dev->inhibit_cache)
+ if (storeio_stat.inhibit_cache)
{
/* Under --no-cache, we permit only whole-block reads.
Note that in this case we handle non-power-of-two block sizes.
diff --git a/storeio/dev.h b/storeio/dev.h
index eda7a93d..beeb1fe6 100644
--- a/storeio/dev.h
+++ b/storeio/dev.h
@@ -1,6 +1,6 @@
/* store `device' I/O
- Copyright (C) 1995,96,97,99,2000,2001 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,99,2000,2001,2026 Free Software Foundation, Inc.
Written by Miles Bader <[email protected]>
This program is free software; you can redistribute it and/or
@@ -23,47 +23,26 @@
#include <mach.h>
#include <device/device.h>
#include <pthread.h>
-#include <hurd/store.h>
-#include <hurd/trivfs.h>
+#include <hurd/netfs.h>
+#include <stdio.h>
+#include <unistd.h>
-extern struct trivfs_control *storeio_fsys;
+extern mach_port_t underlying_node;
/* Information about backend store, which we presumptively call a "device". */
struct dev
{
- /* The argument specification that we use to open the store. */
- struct store_parsed *store_name;
-
/* The device to which we're doing io. This is null when the
device is closed, in which case we will open from `store_name'. */
struct store *store;
- int readonly; /* Nonzero if user gave --readonly flag. */
- int enforced; /* Nonzero if user gave --enforced flag. */
- int no_fileio; /* Nonzero if user gave --no-fileio flag. */
- dev_t rdev; /* A unixy device number for st_rdev. */
-
- /* The current owner of the open device. For terminals, this affects
- controlling terminal behavior (see term_become_ctty). For all objects
- this affects old-style async IO. Negative values represent pgrps. This
- has nothing to do with the owner of a file (as returned by io_stat, and
- as used for various permission checks by filesystems). An owner of 0
- indicates that there is no owner. */
- pid_t owner;
-
/* The number of active opens. */
int nperopens;
- /* This lock protects `store', `owner' and `nperopens'. The other
- members never change after creation, except for those locked by
- io_lock (below). */
+ /* This lock protects `store' and 'nperopens'. The other members never
+ change after creation, except for those locked by io_lock (below). */
pthread_mutex_t lock;
- /* Nonzero iff the --no-cache flag was given.
- If this is set, the remaining members are not used at all
- and don't need to be initialized or cleaned up. */
- int inhibit_cache;
-
/* A bitmask corresponding to the part of an offset that lies within a
device block. */
unsigned block_mask;
@@ -84,14 +63,54 @@ struct dev
pthread_mutex_t pager_lock;
};
+struct netnode
+{
+ struct dev *dev;
+ char *name;
+ struct node **entries;
+
+ /* If the storage is a disk, this is the number of partitions on it. */
+ size_t entries_num;
+};
+
+struct storeio_stat
+{
+ /* The argument specification that we use to open the store. */
+ struct store_parsed *store_name;
+ volatile struct mapped_time_value *current_time;
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+ int readonly; /* Nonzero if user gave --readonly flag. */
+ int enforced; /* Nonzero if user gave --enforced flag. */
+ int no_fileio; /* Nonzero if user gave --no-fileio flag. */
+ dev_t rdev; /* A unixy device number for st_rdev. */
+
+ /* Nonzero iff the --no-cache flag was given.
+ If this is set, the remaining members are not used at all
+ and don't need to be initialized or cleaned up. */
+ int inhibit_cache;
+};
+
+extern struct storeio_stat storeio_stat;
+
+error_t create_node (struct node **node, char *name, struct node *dir);
+error_t check_dev (struct node *node, struct store *store, int flags);
+error_t create_partitions (void);
+
static inline int
dev_is_readonly (const struct dev *dev)
{
- return dev->readonly || (dev->store && (dev->store->flags & STORE_READONLY));
+ return storeio_stat.readonly || (dev->store && (dev->store->flags
+ & STORE_READONLY));
}
-/* Called with DEV->lock held. Try to open the store underlying DEV. */
-error_t dev_open (struct dev *dev);
+/* Called with DEV->lock held. Initialize the DEV struct. */
+error_t dev_open_from_store (struct dev *dev, struct store *store);
+
+/* Try to open the store underlying DEV. */
+error_t dev_open (struct dev *dev, struct store_parsed *store_name);
/* Shut down the store underlying DEV and free any resources it consumes.
DEV itself remains intact so that dev_open can be called again.
@@ -103,10 +122,10 @@ void dev_close (struct dev *dev);
error_t dev_get_memory_object(struct dev *dev, vm_prot_t prot,
memory_object_t *memobj);
-/* Try to stop all paging activity on DEV, returning true if we were
- successful. If NOSYNC is true, then we won't write back any (kernel)
- cached pages to the device. */
-int dev_stop_paging (struct dev *dev, int nosync);
+/* Try to stop all paging activity, returning true if we were successful.
+ If NOSYNC is true, then we won't write back any (kernel) cached pages to
+ the device. */
+int dev_stop_paging (int nosync);
/* Try and write out any pending writes to DEV. If WAIT is true, will wait
for any paging activity to cease. */
@@ -124,4 +143,22 @@ error_t dev_write (struct dev *dev, off_t offs, const void *buf, size_t len,
error_t dev_read (struct dev *dev, off_t offs, size_t amount,
void **buf, size_t *len);
+#ifdef DEBUG
+extern FILE *debug_file;
+extern pthread_mutex_t debug_lock;
+# define debug(format, ...) \
+ do \
+ { \
+ if (debug_file) \
+ { \
+ pthread_mutex_lock (&debug_lock); \
+ fprintf (debug_file, format, ## __VA_ARGS__); \
+ pthread_mutex_unlock (&debug_lock); \
+ } \
+ } \
+ while (0)
+#else
+# define debug(format, ...) do {} while (0)
+#endif
+
#endif /* !__DEV_H__ */
diff --git a/storeio/io.c b/storeio/io.c
deleted file mode 100644
index dca997ef..00000000
--- a/storeio/io.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/* The hurd io interface to storeio
-
- Copyright (C) 1995,96,97,99,2000,02 Free Software Foundation, Inc.
- Written by Miles Bader <[email protected]>
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <hurd/trivfs.h>
-#include <stdio.h>
-#include <fcntl.h>
-
-#include "open.h"
-#include "dev.h"
-#include "libtrivfs/trivfs_fs_S.h"
-#include "libtrivfs/trivfs_io_S.h"
-
-/* Return objects mapping the data underlying this memory object. If
- the object can be read then memobjrd will be provided; if the
- object can be written then memobjwr will be provided. For objects
- where read data and write data are the same, these objects will be
- equal, otherwise they will be disjoint. Servers are permitted to
- implement io_map but not io_map_cntl. Some objects do not provide
- mapping; they will set none of the ports and return an error. Such
- objects can still be accessed by io_read and io_write. */
-kern_return_t
-trivfs_S_io_map (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- memory_object_t *rd_obj, mach_msg_type_name_t *rd_type,
- memory_object_t *wr_obj, mach_msg_type_name_t *wr_type)
-{
- if (! cred)
- return EOPNOTSUPP;
- else if (! (cred->po->openmodes & (O_READ|O_WRITE)))
- return EBADF;
- else
- {
- mach_port_t memobj;
- int flags = cred->po->openmodes;
- vm_prot_t prot =
- ((flags & O_READ) ? VM_PROT_READ : 0)
- | ((flags & O_WRITE) ? VM_PROT_WRITE : 0);
- struct open *open = (struct open *)cred->po->hook;
- error_t err = dev_get_memory_object (open->dev, prot, &memobj);
-
- if (!err)
- {
- if (flags & O_READ)
- *rd_obj = memobj;
- else
- *rd_obj = MACH_PORT_NULL;
- if (flags & O_WRITE)
- *wr_obj = memobj;
- else
- *wr_obj = MACH_PORT_NULL;
-
- if ((flags & (O_READ|O_WRITE)) == (O_READ|O_WRITE)
- && memobj != MACH_PORT_NULL)
- mach_port_mod_refs (mach_task_self (), memobj,
- MACH_PORT_RIGHT_SEND, 1);
- }
-
- *rd_type = *wr_type = MACH_MSG_TYPE_MOVE_SEND;
-
- return err;
- }
-}
-
-/* Read data from an IO object. If offset if -1, read from the object
- maintained file pointer. If the object is not seekable, offset is
- ignored. The amount desired to be read is in AMOUNT. */
-kern_return_t
-trivfs_S_io_read (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- data_t *data, mach_msg_type_name_t *data_len,
- off_t offs, vm_size_t amount)
-{
- error_t err;
- size_t data_size = *data_len;
-
- if (! cred)
- return EOPNOTSUPP;
- else if (! (cred->po->openmodes & O_READ))
- return EBADF;
-
- err = open_read ((struct open *)cred->po->hook,
- offs, amount, (void **)data, &data_size);
- if (err)
- return err;
- *data_len = data_size;
- return 0;
-}
-
-/* Tell how much data can be read from the object without blocking for
- a "long time" (this should be the same meaning of "long time" used
- by the nonblocking flag. */
-kern_return_t
-trivfs_S_io_readable (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- vm_size_t *amount)
-{
- if (! cred)
- return EOPNOTSUPP;
- else if (! (cred->po->openmodes & O_READ))
- return EBADF;
- else
- {
- struct open *open = (struct open *)cred->po->hook;
- *amount = open->dev->store->size - open->offs;
- return 0;
- }
-}
-
-/* Write data to an IO object. If offset is -1, write at the object
- maintained file pointer. If the object is not seekable, offset is
- ignored. The amount successfully written is returned in amount. A
- given user should not have more than one outstanding io_write on an
- object at a time; servers implement congestion control by delaying
- responses to io_write. Servers may drop data (returning ENOBUFS)
- if they recevie more than one write when not prepared for it. */
-kern_return_t
-trivfs_S_io_write (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- const_data_t data, mach_msg_type_number_t data_len,
- off_t offs, vm_size_t *amount)
-{
- if (! cred)
- return EOPNOTSUPP;
- else if (! (cred->po->openmodes & O_WRITE))
- return EBADF;
- else
- return open_write ((struct open *)cred->po->hook,
- offs, data, data_len, amount);
-}
-
-/* Change current read/write offset */
-kern_return_t
-trivfs_S_io_seek (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- off_t offs, int whence, off_t *new_offs)
-{
- if (! cred)
- return EOPNOTSUPP;
- else
- return open_seek ((struct open *)cred->po->hook, offs, whence, new_offs);
-}
-
-/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
- Block until one of the indicated types of i/o can be done "quickly", and
- return the types that are then available. */
-kern_return_t
-trivfs_S_io_select (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- int *type)
-{
- if (! cred)
- return EOPNOTSUPP;
- *type &= ~SELECT_URG;
- return 0;
-}
-
-kern_return_t
-trivfs_S_io_select_timeout (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- struct timespec ts,
- int *type)
-{
- return trivfs_S_io_select (cred, reply, reply_type, type);
-}
-
-/* Truncate file. */
-kern_return_t
-trivfs_S_file_set_size (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- off_t size)
-{
- if (! cred)
- return EOPNOTSUPP;
- else if (size < 0)
- return EINVAL;
- else
- return 0;
-}
-
-/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
- O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
- will tell you which of O_READ, O_WRITE, and O_EXEC the object can
- be used for. The O_ASYNC bit affects icky async I/O; good async
- I/O is done through io_async which is orthogonal to these calls. */
-
-kern_return_t
-trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- int *bits)
-{
- if (! cred)
- return EOPNOTSUPP;
- else
- {
- *bits = cred->po->openmodes;
- return 0;
- }
-}
-
-kern_return_t
-trivfs_S_io_set_all_openmodes (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int mode)
-{
- if (! cred)
- return EOPNOTSUPP;
- else
- return 0;
-}
-
-kern_return_t
-trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int bits)
-{
- if (! cred)
- return EOPNOTSUPP;
- else
- return 0;
-}
-
-kern_return_t
-trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int bits)
-{
- if (! cred)
- return EOPNOTSUPP;
- else
- return 0;
-}
-
-/* Get/set the owner of the IO object. For terminals, this affects
- controlling terminal behavior (see term_become_ctty). For all
- objects this affects old-style async IO. Negative values represent
- pgrps. This has nothing to do with the owner of a file (as
- returned by io_stat, and as used for various permission checks by
- filesystems). An owner of 0 indicates that there is no owner. */
-kern_return_t
-trivfs_S_io_get_owner (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- pid_t *owner)
-{
- if (! cred)
- return EOPNOTSUPP;
- else
- {
- struct open *open = (struct open *)cred->po->hook;
- *owner = open->dev->owner; /* atomic word fetch */
- return 0;
- }
-}
-
-kern_return_t
-trivfs_S_io_mod_owner (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- pid_t owner)
-{
- if (! cred)
- return EOPNOTSUPP;
- else
- {
- struct open *open = (struct open *)cred->po->hook;
- open->dev->owner = owner; /* atomic word store */
- return 0;
- }
-}
-
-/* File syncing operations; these all do the same thing, sync the underlying
- device. */
-
-kern_return_t
-trivfs_S_file_sync (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- int wait, int omit_metadata)
-{
- if (cred)
- return dev_sync (((struct open *)cred->po->hook)->dev, wait);
- else
- return EOPNOTSUPP;
-}
-
-kern_return_t
-trivfs_S_file_syncfs (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- int wait, int dochildren)
-{
- if (cred)
- return dev_sync (((struct open *)cred->po->hook)->dev, wait);
- else
- return EOPNOTSUPP;
-}
-
-kern_return_t
-trivfs_S_file_get_storage_info (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- mach_port_t **ports,
- mach_msg_type_name_t *ports_type,
- mach_msg_type_number_t *num_ports,
- int **ints, mach_msg_type_number_t *num_ints,
- off_t **offsets,
- mach_msg_type_number_t *num_offsets,
- data_t *data, mach_msg_type_number_t *data_len)
-{
- *ports_type = MACH_MSG_TYPE_COPY_SEND;
-
- if (! cred || ! cred->po->hook)
- return EOPNOTSUPP;
- else
- {
- error_t err;
- struct dev *dev = ((struct open *)cred->po->hook)->dev;
- struct store *store = dev->store;
-
- if (dev->enforced && !(store->flags & STORE_ENFORCED))
- {
- /* The --enforced switch tells us not to let anyone
- get at the device, no matter how trustable they are. */
- size_t name_len = (store->name ? strlen (store->name) + 1 : 0);
- int i;
- *num_ports = 0;
- i = 0;
- (*ints)[i++] = STORAGE_OTHER;
- (*ints)[i++] = store->flags;
- (*ints)[i++] = store->block_size;
- (*ints)[i++] = 1; /* num_runs */
- (*ints)[i++] = name_len;
- (*ints)[i++] = 0; /* misc_len */
- *num_ints = i;
- i = 0;
- (*offsets)[i++] = 0;
- (*offsets)[i++] = store->size;
- *num_offsets = i;
- if (store->name)
- memcpy (*data, store->name, name_len);
- *data_len = name_len;
- return 0;
- }
-
- if (!cred->isroot
- && !store_is_securely_returnable (store, cred->po->openmodes))
- {
- struct store *clone;
- err = store_clone (store, &clone);
- if (! err)
- {
- err = store_set_flags (clone, STORE_INACTIVE);
- if (err == EINVAL)
- err = EACCES;
- else
- err = store_return (clone,
- ports, num_ports, ints, num_ints,
- offsets, num_offsets, data, data_len);
- store_free (clone);
- }
- }
- else
- err = store_return (store,
- ports, num_ports, ints, num_ints,
- offsets, num_offsets, data, data_len);
-
- return err;
- }
-}
diff --git a/storeio/open.c b/storeio/open.c
deleted file mode 100644
index 74902520..00000000
--- a/storeio/open.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Per-open information for storeio
-
- Copyright (C) 1995, 1996, 2006 Free Software Foundation, Inc.
-
- Written by Miles Bader <[email protected]>
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <hurd.h>
-#include <stdio.h>
-
-#include "open.h"
-#include "dev.h"
-
-/* Returns a new per-open structure for the device DEV in OPEN. If an error
- occurs, the error-code is returned, otherwise 0. */
-error_t
-open_create (struct dev *dev, struct open **open)
-{
- *open = malloc (sizeof (struct open));
- if (*open == NULL)
- return ENOMEM;
-
- (*open)->dev = dev;
- (*open)->offs = 0;
- pthread_mutex_init (&(*open)->lock, NULL);
-
- return 0;
-}
-
-/* Free OPEN and any resources it holds. */
-void
-open_free (struct open *open)
-{
- free (open);
-}
-
-/* Writes up to LEN bytes from BUF to OPEN's device at device offset OFFS
- (which may be ignored if the device doesn't support random access),
- and returns the number of bytes written in AMOUNT. If no error occurs,
- zero is returned, otherwise the error code is returned. */
-error_t
-open_write (struct open *open, off_t offs, const void *buf, size_t len,
- vm_size_t *amount)
-{
- error_t err;
- if (offs < 0)
- /* Use OPEN's offset. */
- {
- pthread_mutex_lock (&open->lock);
- err = dev_write (open->dev, open->offs, buf, len, amount);
- if (! err)
- open->offs += *amount;
- pthread_mutex_unlock (&open->lock);
- }
- else
- err = dev_write (open->dev, offs, buf, len, amount);
- return err;
-}
-
-/* Reads up to AMOUNT bytes from the device into BUF and LEN using the
- standard mach out-array convention. If no error occurs, zero is returned,
- otherwise the error code is returned. */
-error_t
-open_read (struct open *open, off_t offs, vm_size_t amount,
- void **buf, vm_size_t *len)
-{
- error_t err;
- if (offs < 0)
- /* Use OPEN's offset. */
- {
- pthread_mutex_lock (&open->lock);
- err = dev_read (open->dev, open->offs, amount, buf, len);
- if (! err)
- open->offs += *len;
- pthread_mutex_unlock (&open->lock);
- }
- else
- err = dev_read (open->dev, offs, amount, buf, len);
- return err;
-}
-
-/* Set OPEN's location to OFFS, interpreted according to WHENCE as by seek.
- The new absolute location is returned in NEW_OFFS (and may not be the same
- as OFFS). If no error occurs, zero is returned, otherwise the error code
- is returned. */
-error_t
-open_seek (struct open *open, off_t offs, int whence, off_t *new_offs)
-{
- error_t err = 0;
-
- pthread_mutex_lock (&open->lock);
-
- switch (whence)
- {
- case SEEK_CUR:
- offs += open->offs;
- goto check;
- case SEEK_END:
- offs += open->dev->store->size;
- case SEEK_SET:
- check:
- if (offs >= 0)
- {
- *new_offs = open->offs = offs;
- break;
- }
- default:
- err = EINVAL;
- }
-
- pthread_mutex_unlock (&open->lock);
-
- return err;
-}
diff --git a/storeio/open.h b/storeio/open.h
deleted file mode 100644
index ad2678ff..00000000
--- a/storeio/open.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* Per-open information for storeio
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <[email protected]>
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#ifndef __OPEN_H__
-#define __OPEN_H__
-
-#include "dev.h"
-
-/* ---------------------------------------------------------------- */
-
-/* A structure describing a particular i/o stream on this device. */
-struct open
-{
- /* The device that this an open on. */
- struct dev *dev;
-
- /* The per-open offset used for I/O operations that don't specify an
- explicit offset. */
- off_t offs;
-
- /* A lock used to control write access to OFFS. */
- pthread_mutex_t lock;
-};
-
-/* Returns a new per-open structure for the device DEV in OPEN. If an error
- occurs, the error-code is returned, otherwise 0. */
-error_t open_create (struct dev *dev, struct open **open);
-
-/* Free OPEN and any resources it holds. */
-void open_free (struct open *open);
-
-/* Writes up to LEN bytes from BUF to OPEN's device at device offset OFFS
- (which may be ignored if the device doesn't support random access),
- and returns the number of bytes written in AMOUNT. If no error occurs,
- zero is returned, otherwise the error code is returned. */
-error_t open_write (struct open *open, off_t offs, const void *buf, size_t len,
- vm_size_t *amount);
-
-/* Reads up to AMOUNT bytes from the device into BUF and BUF_LEN using the
- standard mach out-array convention. If no error occurs, zero is returned,
- otherwise the error code is returned. */
-error_t open_read (struct open *open, off_t offs, vm_size_t amount,
- void **buf, vm_size_t *buf_len);
-
-/* Set OPEN's location to OFFS, interpreted according to WHENCE as by seek.
- The new absolute location is returned in NEW_OFFS (and may not be the same
- as OFFS). If no error occurs, zero is returned, otherwise the error code
- is returned. */
-error_t open_seek (struct open *open, off_t offs, int whence, off_t *new_offs);
-
-#endif /* !__OPEN_H__ */
diff --git a/storeio/pager.c b/storeio/pager.c
index 11bf4692..10bdd1c3 100644
--- a/storeio/pager.c
+++ b/storeio/pager.c
@@ -20,6 +20,7 @@
#include <hurd.h>
#include <hurd/pager.h>
+#include <hurd/store.h>
#include <assert-backtrace.h>
#include <strings.h>
#include <unistd.h>
@@ -27,6 +28,7 @@
#include <error.h>
#include <sys/mman.h>
#include <stdio.h>
+#include <string.h>
#include "dev.h"
@@ -174,11 +176,11 @@ pager_dropweak (struct user_pager_info *upi __attribute__ ((unused)))
{
}
-/* Try to stop all paging activity on DEV, returning true if we were
- successful. If NOSYNC is true, then we won't write back any (kernel)
- cached pages to the device. */
+/* Try to stop all paging activity, returning true if we were successful.
+ If NOSYNC is true, then we won't write back any (kernel) cached pages to
+ the device. */
int
-dev_stop_paging (struct dev *dev, int nosync)
+dev_stop_paging (int nosync)
{
size_t num_pagers = (pager_port_bucket ?
ports_count_bucket (pager_port_bucket) : 0);
@@ -223,7 +225,7 @@ dev_get_memory_object (struct dev *dev, vm_prot_t prot, memory_object_t *memobj)
{
error_t err = store_map (dev->store, prot, memobj);
- if (err == EOPNOTSUPP && !dev->inhibit_cache)
+ if (err == EOPNOTSUPP && !storeio_stat.inhibit_cache)
{
int created = 0;
diff --git a/storeio/part.c b/storeio/part.c
new file mode 100644
index 00000000..5c9c6a20
--- /dev/null
+++ b/storeio/part.c
@@ -0,0 +1,162 @@
+/* Partition storeio backend
+ Copyright (C) 2026 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <parted/parted.h>
+#include <hurd/store.h>
+
+#include "dev.h"
+
+/* Initialize a PedDevice using SOURCE. The SOURCE will NOT be destroyed;
+ the caller created it, it is the caller's responsilbility to free it
+ after it calls ped_device_destroy. SOURCE is not registered in Parted's
+ list of devices. */
+PedDevice* ped_device_new_from_store (struct store *source);
+
+static int
+set_last_partition_num (struct store *store)
+{
+ debug ("last_partition_num (store: %p):\n", store);
+ int last_partition_num = 0;
+ ped_exception_fetch_all ();
+ PedDevice *device = ped_device_new_from_store (store);
+ if (!device || !ped_device_open (device))
+ {
+ debug ("!device || !ped_device_open (device)\n");
+ goto err_ped_exception_leave_all;
+ }
+
+ PedDisk *disk = ped_disk_new (device);
+ if (!disk)
+ {
+ debug ("!disk\n");
+ goto err_ped_device_close;
+ }
+
+ if (strcmp (disk->type->name, "loop") == 0)
+ {
+ debug ("strcmp (disk->type->name, \"loop\") == 0\n");
+ goto err_ped_disk_destroy;
+ }
+
+ last_partition_num = ped_disk_get_last_partition_num (disk);
+ if (last_partition_num < 0)
+ {
+ debug ("last_partition_num < 0\n");
+ last_partition_num = 0;
+ }
+
+ err_ped_disk_destroy:
+ ped_disk_destroy (disk);
+
+ err_ped_device_close:
+ if (!ped_device_close (device))
+ debug ("!ped_device_close (device)\n");
+
+ err_ped_exception_leave_all:
+ ped_exception_leave_all ();
+
+ debug ("set_last_partition_num return: %d\n", last_partition_num);
+ return last_partition_num;
+}
+
+static inline char *
+create_node_name (const size_t num)
+{
+ char *buffer;
+ error_t err = asprintf (&buffer, "%zu", num);
+ if (err == -1)
+ return NULL;
+
+ return buffer;
+}
+
+error_t
+create_partitions (void)
+{
+ debug ("create_partitions:\n");
+ struct node *dir = netfs_root_node;
+ size_t last_partition_num =
+ (size_t) set_last_partition_num (dir->nn->dev->store);
+ if (last_partition_num == 0)
+ {
+ debug ("last_partition_num == 0\n");
+ debug ("create_partitions return: ENOTDIR\n");
+ return ENOTDIR;
+ }
+
+ error_t err;
+ dir->nn->entries_num = last_partition_num;
+ dir->nn->entries = malloc (last_partition_num * sizeof (struct node *));
+ if (!dir->nn->entries)
+ {
+ err = errno;
+ debug ("!dir->nn->entries\n");
+ debug ("create_partitions return: %d\n", err);
+ return err;
+ }
+
+ const int flags = ((storeio_stat.readonly ? STORE_READONLY : 0)
+ | (storeio_stat.no_fileio ? STORE_NO_FILEIO : 0));
+
+ struct store *source, *store;
+ struct node **part;
+ char *node_name;
+ for (size_t i = 1; i <= last_partition_num; ++i)
+ {
+ err = store_parsed_open (storeio_stat.store_name, flags, &source);
+ if (err)
+ {
+ debug ("store_parsed_open return err: %d\n", err);
+ break;
+ }
+
+ err = store_part_create (source, i, flags, &store);
+ if (err)
+ {
+ debug ("store_part_create return err: %d\n", err);
+ break;
+ }
+
+ part = &dir->nn->entries[i - 1];
+ node_name = create_node_name (i);
+ if (!node_name)
+ {
+ err = errno;
+ debug ("!node_name\n");
+ break;
+ }
+
+ err = create_node (part, node_name, dir);
+ if (err)
+ {
+ debug ("create_node return err: %d\n", err);
+ break;
+ }
+
+ err = check_dev (*part, store, flags);
+ if (err)
+ {
+ debug ("dev_init_from_store return err: %d\n", err);
+ break;
+ }
+ }
+
+ debug ("create_partitions return: %d\n", err);
+ return err;
+}
diff --git a/storeio/storeio.c b/storeio/storeio.c
index 4e8a9628..7fe93ad3 100644
--- a/storeio/storeio.c
+++ b/storeio/storeio.c
@@ -1,6 +1,6 @@
/* A translator for doing I/O to stores
- Copyright (C) 1995,96,97,98,99,2000,01,02 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2000,01,02,26 Free Software Foundation, Inc.
Written by Miles Bader <[email protected]>
This program is free software; you can redistribute it and/or
@@ -18,23 +18,28 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
+#include <stdlib.h>
#include <error.h>
#include <assert-backtrace.h>
#include <fcntl.h>
#include <argp.h>
#include <argz.h>
#include <sys/sysmacros.h>
+#include <sys/mman.h>
#include <stdbool.h>
+#include <dirent.h>
#include <hurd.h>
#include <hurd/ports.h>
-#include <hurd/trivfs.h>
+#include <hurd/store.h>
#include <version.h>
-#include "open.h"
#include "dev.h"
-#include "libtrivfs/trivfs_fsys_S.h"
-
+#include "libnetfs/fs_S.h"
+#include "libnetfs/io_S.h"
+#include "libnetfs/fsys_S.h"
+#include "libnetfs/fsys_reply_U.h"
+
static struct argp_option options[] =
{
{"readonly", 'r', 0, 0,"Disallow writing"},
@@ -43,8 +48,10 @@ static struct argp_option options[] =
{"no-file-io", 'F', 0, 0,"Never perform io via plain file io RPCs"},
{"no-fileio", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
{"enforced", 'e', 0, 0,"Never reveal underlying devices, even to root"},
- {"debug", 'd', "PATH", 0,
- "Launch a standalone translator, for debug purposes"},
+#ifdef DEBUG
+ {"debug", 'd', "FILE", 0, "Enable debug and write debug statements to"
+ " FILE. The FILE must be located outside the translator directory."},
+#endif
{"rdev", 'n', "ID", 0,
"The stat rdev number for this node; may be either a"
" single integer, or of the form MAJOR,MINOR"},
@@ -54,31 +61,225 @@ static const char doc[] = "Translator for devices and other stores";
const char *argp_program_version = STANDARD_HURD_VERSION (storeio);
-static bool debug=false;
-static char *debug_fname=NULL;
+char *netfs_server_name = "storeio";
+char *netfs_server_version = HURD_VERSION;
+int netfs_maxsymlinks = 0; /* arbitrary */
+
+char *debug_file_name = NULL;
+FILE *debug_file;
+pthread_mutex_t debug_lock;
-/* Desired store parameters specified by the user. */
-struct storeio_argp_params
+error_t
+create_node (struct node **node, char *name, struct node *dir)
{
- struct store_argp_params store_params; /* Filled in by store_argp parser. */
- struct dev *dev; /* We fill in its flag members. */
-};
+ error_t err;
+ struct netnode *netnode = malloc (sizeof (struct netnode));
+ if (!netnode)
+ {
+ err = errno;
+ goto return_error;
+ }
+
+ struct node *new_node = netfs_make_node (netnode);
+ if (!new_node)
+ {
+ err = errno;
+ goto free_netnode;
+ }
+
+ static ino_t id = 1;
+ io_statbuf_t statbuf = {
+ .st_fstype = FSTYPE_MISC,
+ .st_fsid = storeio_stat.pid,
+ .st_dev = storeio_stat.pid,
+ .st_rdev = storeio_stat.pid,
+ .st_uid = storeio_stat.uid,
+ .st_author = storeio_stat.uid,
+ .st_gid = storeio_stat.gid,
+ .st_mode = storeio_stat.mode,
+ .st_ino = id++,
+ .st_nlink = 1,
+ .st_blksize = 0,
+ .st_size = 0,
+ .st_blocks = 1,
+ .st_gen = 0
+ };
+ new_node->nn_stat = statbuf;
+ new_node->next = NULL;
+ new_node->prevp = NULL;
+
+ struct dev *dev = malloc (sizeof (struct dev));
+ if (!dev)
+ {
+ err = errno;
+ goto free_new_node;
+ }
+
+ memset (dev, 0, sizeof (struct dev));
+ pthread_mutex_init (&dev->lock, NULL);
+ new_node->nn->dev = dev;
+ new_node->nn->name = name;
+ new_node->nn->entries = NULL;
+ new_node->nn->entries_num = 0;
+
+ if (dir)
+ netfs_nref (dir);
+
+ fshelp_touch (&new_node->nn_stat, TOUCH_ATIME|TOUCH_CTIME|TOUCH_MTIME,
+ storeio_stat.current_time);
+
+ *node = new_node;
+
+ debug ("create_node (name: %s, dir: %p):\n", name, dir);
+ debug ("*node: %p\n", *node);
+ debug ("create_node return: 0");
+ return 0;
+
+ free_new_node:
+ free (new_node);
+
+ free_netnode:
+ free (netnode);
+
+ return_error:
+ *node = NULL;
+
+ debug ("create_node (name: %s, dir: %p):\n", name, dir);
+ debug ("*node: %p\n", *node);
+ debug ("create_node return: %d", err);
+ return err;
+}
+
+static inline void
+change_node_mode (struct node *node)
+{
+ node->nn_stat.st_mode &= S_IFMT;
+
+ if (storeio_stat.inhibit_cache)
+ {
+ node->nn_stat.st_mode |= S_IFCHR;
+ return;
+ }
+
+ if (node->nn->dev->store && node->nn->dev->store->block_size == 1)
+ node->nn_stat.st_mode |= S_IFCHR;
+ else
+ node->nn_stat.st_mode |= S_IFBLK;
+}
+
+error_t
+check_dev (struct node *node, struct store *store, int flags)
+{
+ if (dev_is_readonly (node->nn->dev) && (flags & O_WRITE))
+ {
+ debug ("check_dev (node: %p, store: %p, flags: %d):\n",
+ node, store, flags);
+ debug ("dev_is_readonly (node->nn->dev) && (flags & O_WRITE)\n");
+ debug ("check_dev return: EROFS\n");
+ return EROFS;
+ }
+
+ struct dev *dev = node->nn->dev;
+ pthread_mutex_lock (&dev->lock);
+ if (!dev->store)
+ {
+ error_t err;
+
+ if (store)
+ err = dev_open_from_store (dev, store);
+ else
+ err = dev_open (dev, storeio_stat.store_name);
+
+ if (err)
+ {
+ pthread_mutex_unlock (&dev->lock);
+
+ debug ("check_dev (node: %p, store: %p, flags: %d):\n", node,
+ store, flags);
+ if ((flags & (O_READ | O_WRITE)) == 0)
+ {
+ debug ("dev open err: %d, but we are not opening the file for"
+ " reading or writing, just ignore the error and exit"
+ " the function. XXX\n", err);
+ debug ("check_dev return: 0\n");
+ return 0;
+ }
+
+ debug ("dev open return err: %d\n", err);
+ debug ("check_dev return: %d\n", err);
+ return err;
+ }
+
+ node->nn_stat.st_size = dev->store->size;
+
+ if (dev->store->block_size > 1)
+ node->nn_stat.st_blksize = dev->store->block_size;
+
+ if (node != netfs_root_node)
+ change_node_mode (node);
+ }
+ pthread_mutex_unlock (&dev->lock);
+
+ return 0;
+}
+
+error_t __attribute__ ((weak))
+create_partitions (void)
+{
+ return ENOTDIR;
+}
+
+static error_t
+create_storeio (void)
+{
+ debug ("create_storeio:\n");
+ error_t err = maptime_map (1, 0, &storeio_stat.current_time);
+ if (err)
+ {
+ err = maptime_map (0, 0, &storeio_stat.current_time);
+ if (err)
+ return err;
+ }
+
+ storeio_stat.pid = getpid ();
+ storeio_stat.uid = getuid ();
+ storeio_stat.gid = getgid ();
+
+ storeio_stat.mode = storeio_stat.readonly ? 0444 : 0644;
+
+ err = create_node (&netfs_root_node, NULL, NULL);
+ if (err)
+ {
+ debug ("create_node return err: %d\n", err);
+ debug ("create_storeio return: %d\n", err);
+ return err;
+ }
+
+ netfs_root_node->nn_stat.st_nlink = 2;
+
+ debug ("create_storeio return: 0\n");
+ return 0;
+}
+
+struct storeio_stat storeio_stat;
/* Parse a single option. */
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
- struct storeio_argp_params *params = state->input;
+ struct store_argp_params *store_params = state->input;
switch (key)
{
+ case 'r': storeio_stat.readonly = 1; break;
+ case 'w': storeio_stat.readonly = 0; break;
- case 'r': params->dev->readonly = 1; break;
- case 'w': params->dev->readonly = 0; break;
-
- case 'c': params->dev->inhibit_cache = 1; break;
- case 'e': params->dev->enforced = 1; break;
- case 'F': params->dev->no_fileio = 1; break;
+ case 'c': storeio_stat.inhibit_cache = 1; break;
+ case 'e': storeio_stat.enforced = 1; break;
+ case 'F': storeio_stat.no_fileio = 1; break;
+#ifdef DEBUG
+ case 'd': debug_file_name = arg; break;
+#endif
case 'n':
{
@@ -99,31 +300,22 @@ parse_opt (int key, char *arg, struct argp_state *state)
return EINVAL;
}
- params->dev->rdev = rdev;
- }
- break;
-
- case 'd':
- {
- debug=true;
- char *new = strdup (arg);
- if (new == NULL)
- return ENOMEM;
- debug_fname = new;
+ storeio_stat.rdev = rdev;
}
break;
case ARGP_KEY_INIT:
/* Now store_argp's parser will get to initialize its state.
The default_type member is our input parameter to it. */
- memset (¶ms->store_params, 0, sizeof params->store_params);
- params->store_params.default_type = "device";
- params->store_params.store_optional = 1;
- state->child_inputs[0] = ¶ms->store_params;
+ memset (&storeio_stat, 0, sizeof (struct storeio_stat));
+ memset (store_params, 0, sizeof (struct store_argp_params));
+ store_params->default_type = "device";
+ store_params->store_optional = 1;
+ state->child_inputs[0] = store_params;
break;
case ARGP_KEY_SUCCESS:
- params->dev->store_name = params->store_params.result;
+ storeio_stat.store_name = store_params->result;
break;
default:
@@ -134,321 +326,790 @@ parse_opt (int key, char *arg, struct argp_state *state)
static const struct argp_child argp_kids[] = { { &store_argp }, {0} };
static const struct argp argp = { options, parse_opt, 0, doc, argp_kids };
-
-struct trivfs_control *storeio_fsys;
+
+mach_port_t underlying_node;
int
main (int argc, char *argv[])
{
- error_t err;
+ struct store_argp_params store_params;
+ argp_parse (&argp, argc, argv, 0, 0, &store_params);
+
mach_port_t bootstrap;
- struct dev device;
- struct storeio_argp_params params;
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (2, 0, "Must be started as a translator");
- memset (&device, 0, sizeof device);
- pthread_mutex_init (&device.lock, NULL);
+ netfs_init ();
- params.dev = &device;
- argp_parse (&argp, argc, argv, 0, 0, ¶ms);
+ underlying_node = netfs_startup (bootstrap, O_READ);
+ io_statbuf_t underlying_stat;
- if (debug)
+ error_t err = io_stat (underlying_node, &underlying_stat);
+ if (err)
+ error (1, err, "Cannot stat underlying node");
+
+#ifdef DEBUG
+ if (debug_file_name)
{
- if (!debug_fname)
- error (3, EINVAL, "missing translated node");
- err = trivfs_startup_debug (debug_fname, 0, 0, 0, 0, &storeio_fsys);
- if (err)
- error (3, err, "trivfs_startup_debug failed");
+ debug_file = fopen (debug_file_name, "a");
+ setbuf (debug_file, NULL);
+ pthread_mutex_init (&debug_lock, NULL);
}
- else
- {
- task_get_bootstrap_port (mach_task_self (), &bootstrap);
- if (bootstrap == MACH_PORT_NULL)
- error (2, 0, "Must be started as a translator");
+#endif
- /* Reply to our parent */
- err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &storeio_fsys);
- if (err)
- error (3, err, "trivfs_startup");
- }
+ debug ("\n---------------start main---------------\n");
- storeio_fsys->hook = &device;
+ err = create_storeio ();
+ if (err)
+ error (1, err, "Cannot creare storeio");
+
+ netfs_root_node->nn_stat = underlying_stat;
+ netfs_root_node->nn_stat.st_mode =
+ S_IFDIR | (underlying_stat.st_mode & ~S_IFMT & ~S_ITRANS);
+ debug ("netfs_root_node->nn_stat.st_mode: %d\n",
+ netfs_root_node->nn_stat.st_mode);
/* Launch. */
- ports_manage_port_operations_multithread (storeio_fsys->pi.bucket,
- trivfs_demuxer,
- 30*1000, 5*60*1000, 0);
+ debug ("netfs_server_loop()...\n");
+ netfs_server_loop ();
return 0;
}
-
+
error_t
-trivfs_append_args (struct trivfs_control *trivfs_control,
- char **argz, size_t *argz_len)
+netfs_append_args (char **argz, size_t *argz_len)
{
- struct dev *const dev = trivfs_control->hook;
error_t err = 0;
- if (dev->rdev != (dev_t) 0)
+ if (storeio_stat.rdev != (dev_t) 0)
{
char buf[40];
- snprintf (buf, sizeof buf, "--rdev=%d,%d",
- gnu_dev_major (dev->rdev), gnu_dev_minor (dev->rdev));
+ snprintf (buf, sizeof (buf), "--rdev=%d,%d",
+ gnu_dev_major (storeio_stat.rdev),
+ gnu_dev_minor (storeio_stat.rdev));
+
err = argz_add (argz, argz_len, buf);
}
- if (!err && dev->inhibit_cache)
+ if (!err && storeio_stat.inhibit_cache)
err = argz_add (argz, argz_len, "--no-cache");
- if (!err && dev->enforced)
+ if (!err && storeio_stat.enforced)
err = argz_add (argz, argz_len, "--enforced");
- if (!err && dev->no_fileio)
+ if (!err && storeio_stat.no_fileio)
err = argz_add (argz, argz_len, "--no-file-io");
- if (! err)
+ if (!err)
err = argz_add (argz, argz_len,
- dev->readonly ? "--readonly" : "--writable");
+ storeio_stat.readonly ? "--readonly" : "--writable");
- if (! err)
- err = store_parsed_append_args (dev->store_name, argz, argz_len);
+ if (!err)
+ err = store_parsed_append_args (storeio_stat.store_name, argz, argz_len);
return err;
}
-
-/* Called whenever a new lookup is done of our node. The only reason we
- set this hook is to duplicate the check done normally done against
- trivfs_allow_open in trivfs_S_fsys_getroot, but looking at the
- per-device state. This gets checked again in check_open_hook, but this
- hook runs before a little but more overhead gets incurred. In the
- success case, we just return EAGAIN to have trivfs_S_fsys_getroot
- continue with its generic processing. */
-static error_t
-getroot_hook (struct trivfs_control *cntl,
- mach_port_t reply_port,
- mach_msg_type_name_t reply_port_type,
- mach_port_t dotdot,
- const uid_t *uids, mach_msg_type_number_t nuids, const uid_t *gids, mach_msg_type_number_t ngids,
- int flags,
- retry_type *do_retry, char *retry_name,
- mach_port_t *node, mach_msg_type_name_t *node_type)
-{
- struct dev *const dev = cntl->hook;
- return (dev_is_readonly (dev) && (flags & O_WRITE)) ? EROFS : EAGAIN;
-}
-
-/* Called whenever someone tries to open our node (even for a stat). We
- delay opening the kernel device until this point, as we can usefully
- return errors from here. */
+
static error_t
-check_open_hook (struct trivfs_control *trivfs_control,
- struct iouser *user,
- int flags)
+node_open_create (struct peropen *po)
{
- struct dev *const dev = trivfs_control->hook;
error_t err = 0;
+ struct dev *dev = po->np->nn->dev;
+ if (dev->store)
+ {
+ pthread_mutex_lock (&dev->lock);
+ if (dev->nperopens++ == 0)
+ err = store_clear_flags (dev->store, STORE_INACTIVE);
+ pthread_mutex_unlock (&dev->lock);
+ }
- if (!err && dev_is_readonly (dev) && (flags & O_WRITE))
- return EROFS;
+ return err;
+}
+
+error_t (*netfs_peropen_create_hook) (struct peropen *po) = node_open_create;
+static void
+node_open_destroy (struct peropen *po)
+{
+ struct dev *dev = po->np->nn->dev;
pthread_mutex_lock (&dev->lock);
- if (dev->store == NULL)
+ if (--dev->nperopens == 0)
+ store_clear_flags (dev->store, STORE_INACTIVE);
+ pthread_mutex_unlock (&dev->lock);
+}
+
+void (*netfs_peropen_destroy_hook) (struct peropen *po) = node_open_destroy;
+
+inline static void
+devs_lock (void)
+{
+ pthread_mutex_lock (&netfs_root_node->nn->dev->lock);
+ for (size_t i = 0; i < netfs_root_node->nn->entries_num; ++i)
+ pthread_mutex_lock (&netfs_root_node->nn->entries[i]->nn->dev->lock);
+}
+
+inline static void
+devs_unlock (void)
+{
+ pthread_mutex_unlock (&netfs_root_node->nn->dev->lock);
+ for (size_t i = 0; i < netfs_root_node->nn->entries_num; ++i)
+ pthread_mutex_unlock (&netfs_root_node->nn->entries[i]->nn->dev->lock);
+}
+
+kern_return_t
+netfs_S_fsys_goaway (struct netfs_control *pt,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int flags)
+{
+ debug ("netfs_S_fsys_goaway enter\n");
+ if (!pt)
{
- /* Try and open the store. */
- err = dev_open (dev);
- if (err && (flags & (O_READ|O_WRITE)) == 0)
- /* If we're not opening for read or write, then just ignore the
- error, as this allows stat to work correctly. XXX */
- err = 0;
+ debug ("!pt");
+ debug ("netfs_S_fsys_goaway return: EOPNOTSUPP\n");
+ return EOPNOTSUPP;
+ }
+
+ if ((flags & FSYS_GOAWAY_UNLINK)
+ && S_ISDIR (netfs_root_node->nn_stat.st_mode))
+ {
+ debug ("(flags & FSYS_GOAWAY_UNLINK) && S_ISDIR"
+ " (netfs_root_node->nn_stat.st_mode\n");
+ debug ("netfs_S_fsys_goaway return: EBUSY\n");
+ return EBUSY;
+ }
+
+ devs_lock ();
+
+ int force = flags & FSYS_GOAWAY_FORCE;
+ error_t err = ports_inhibit_class_rpcs (netfs_protid_class);
+ if (err == EINTR || (err && !force))
+ {
+ debug ("err == EINTR || (err && !force)\n");
+ devs_unlock ();
+ debug ("netfs_S_fsys_goaway return: %d\n", err);
+ return err;
+ }
+
+ int nosync = flags & FSYS_GOAWAY_NOSYNC;
+ if (force && nosync)
+ {
+ debug ("force && nosync\n");
+ exit (0);
+ }
+
+ if (!force && ports_count_class (netfs_protid_class) > 0)
+ {
+ debug ("!force && ports_count_class (netfs_protid_class) > 0\n");
+ ports_enable_class (netfs_protid_class);
+ ports_resume_class_rpcs (netfs_protid_class);
+ devs_unlock ();
+ debug ("netfs_S_fsys_goaway return: EBUSY\n");
+ return EBUSY;
+ }
+
+ if (!nosync)
+ {
+ debug ("!nosync\n");
+ err = netfs_attempt_syncfs (0, flags);
}
- pthread_mutex_unlock (&dev->lock);
+ if (!err && (dev_stop_paging (nosync) || force))
+ {
+ debug ("!err && (dev_stop_paging (nosync) || force)\n");
+ if (!nosync)
+ {
+ debug ("!nosync\n");
+ dev_close (netfs_root_node->nn->dev);
+ for (size_t i = 0; i < netfs_root_node->nn->entries_num; ++i)
+ dev_close (netfs_root_node->nn->entries[i]->nn->dev);
+ }
+ }
+
+ if (!err)
+ {
+ debug ("!err\n");
+ fsys_goaway_reply (reply, reply_type, 0);
+ debug ("netfs_S_fsys_goaway exit (0)\n");
+ exit (0);
+ }
+
+ debug ("netfs_S_fsys_goaway return: %d\n", err);
return err;
}
-static error_t
-open_hook (struct trivfs_peropen *peropen)
+error_t
+netfs_validate_stat (struct node *np, struct iouser *cred)
+{
+ if (np->nn->dev->store)
+ {
+ np->nn_stat.st_size = np->nn->dev->store->size;
+ np->nn_stat.st_blksize = np->nn->dev->store->block_size;
+ }
+ else
+ {
+ np->nn_stat.st_size = 0;
+ np->nn_stat.st_blksize = 0;
+ }
+
+ return 0;
+}
+
+error_t
+netfs_attempt_chown (struct iouser *cred, struct node *np, uid_t uid,
+ uid_t gid)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_chauthor (struct iouser *cred, struct node *np, uid_t author)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_chmod (struct iouser *cred, struct node *np, mode_t mode)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_mksymlink (struct iouser *cred, struct node *np,
+ const char *name)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_mkdev (struct iouser *cred, struct node *np, mode_t type,
+ dev_t indexes)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_utimes (struct iouser *cred, struct node *np,
+ struct timespec *atime, struct timespec *mtime)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_set_size (struct iouser *cred, struct node *np, loff_t size)
+{
+ return 0;
+}
+
+error_t
+netfs_attempt_statfs (struct iouser *cred, struct node *np,
+ fsys_statfsbuf_t *st)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_sync (struct iouser *cred, struct node *np, int wait)
+{
+ error_t err = dev_sync (np->nn->dev, wait);
+ if (err)
+ {
+ debug ("netfs_attempt_sync (cred: %p, np: %p, wait: %d):\n",
+ cred, np, wait);
+ debug ("netfs_attempt_sync return: %d\n", err);
+ }
+
+ return err;
+}
+
+error_t
+netfs_attempt_syncfs (struct iouser *cred, int wait)
+{
+ error_t err = dev_sync (netfs_root_node->nn->dev, wait);
+ if (err)
+ {
+ debug ("netfs_attempt_syncfs (cred: %p, wait: %d):\n", cred, wait);
+ debug ("dev_sync (netfs_root_node->nn->dev) return err: %d\n", err);
+ debug ("netfs_attempt_syncfs return: %d\n", err);
+ return err;
+ }
+
+ for (size_t i = 0; i < netfs_root_node->nn->entries_num; ++i)
+ {
+ err = dev_sync (netfs_root_node->nn->entries[i]->nn->dev, wait);
+ if (err)
+ {
+ debug ("netfs_attempt_syncfs (cred: %p, wait: %d):\n", cred, wait);
+ debug ("dev_sync (netfs_root_node->nn->entries[%zu]->nn->dev)"
+ " return err: %d\n", i, err);
+ debug ("netfs_attempt_syncfs return: %d\n", err);
+ break;
+ }
+ }
+
+ return err;
+}
+
+error_t
+netfs_attempt_lookup (struct iouser *user, struct node *dir,
+ const char *name, struct node **np)
+{
+ if (!dir->nn->entries)
+ {
+ if (dir != netfs_root_node)
+ {
+ debug ("netfs_attempt_lookup (user: %p, dir: %p, name: %s):\n",
+ user, dir, name);
+ debug ("!dir->nn->entries\n");
+ debug ("dir != netfs_root_node\n");
+ *np = NULL;
+ pthread_mutex_unlock (&dir->lock);
+ debug ("netfs_attempt_lookup return: ENOTDIR\n");
+ return ENOTDIR;
+ }
+
+ error_t err = create_partitions ();
+ if (err)
+ {
+ debug ("netfs_attempt_lookup (user: %p, dir: %p, name: %s):\n",
+ user, dir, name);
+ debug ("!dir->nn->entries\n");
+ debug ("create_partitions return err: %d\n", err);
+ *np = NULL;
+ pthread_mutex_unlock (&dir->lock);
+ debug ("netfs_attempt_lookup return: %d\n", err);
+ return err;
+ }
+ }
+ pthread_mutex_unlock (&dir->lock);
+
+ if (*name == '\0' || strcmp (name, ".") == 0)
+ {
+ *np = dir;
+ pthread_mutex_lock (&dir->lock);
+ netfs_nref (*np);
+ pthread_mutex_unlock (&dir->lock);
+ pthread_mutex_lock (&(*np)->lock);
+ return 0;
+ }
+
+ struct node *current_node = NULL;
+ struct node *iter;
+ for (size_t i = 0; i < dir->nn->entries_num; ++i)
+ {
+ iter = dir->nn->entries[i];
+
+ if (strcmp (name, iter->nn->name) == 0)
+ {
+ current_node = iter;
+ break;
+ }
+ }
+
+ if (current_node)
+ {
+ *np = current_node;
+ pthread_mutex_lock (&dir->lock);
+ netfs_nref (*np);
+ pthread_mutex_unlock (&dir->lock);
+ pthread_mutex_lock (&(*np)->lock);
+ return 0;
+ }
+
+ *np = NULL;
+ debug ("netfs_attempt_lookup (user: %p, dir: %p, name: %s):\n",
+ user, dir, name);
+ debug ("netfs_attempt_lookup return: ENOENT\n");
+ return ENOENT;
+}
+
+error_t
+netfs_attempt_unlink (struct iouser *user, struct node *dir, const char *name)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_rename (struct iouser *user, struct node *fromdir,
+ const char *fromname, struct node *todir,
+ const char *toname, int excl)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_mkdir (struct iouser *user, struct node *dir, const char *name,
+ mode_t mode)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_rmdir (struct iouser *user, struct node *dir, const char *name)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_link (struct iouser *user, struct node *dir, struct node *file,
+ const char *name, int excl)
+{
+ return EOPNOTSUPP;
+}
+
+/* We don't use this function, but we need to unlock the dir. */
+error_t
+netfs_attempt_mkfile (struct iouser *user, struct node *dir, mode_t mode,
+ struct node **np)
+{
+ pthread_mutex_unlock (&dir->lock);
+ return EOPNOTSUPP;
+}
+
+/* We don't use this function, but we need to unlock the dir and clear np. */
+error_t
+netfs_attempt_create_file (struct iouser *user, struct node *dir,
+ const char *name, mode_t mode, struct node **np)
+{
+ *np = NULL;
+ pthread_mutex_unlock (&dir->lock);
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_check_open_permissions (struct iouser *user, struct node *np,
+ int flags, int newnode)
{
error_t err = 0;
- struct dev *const dev = peropen->cntl->hook;
- if (dev->store)
+ if (!err && flags & O_READ)
{
- pthread_mutex_lock (&dev->lock);
- if (dev->nperopens++ == 0)
- err = store_clear_flags (dev->store, STORE_INACTIVE);
- pthread_mutex_unlock (&dev->lock);
- if (!err)
- err = open_create (dev, (struct open **)&peropen->hook);
+ err = fshelp_access (&np->nn_stat, S_IREAD, user);
+ if (err)
+ {
+ debug ("netfs_check_open_permissions (user: %p, np: %p, flags: %d,"
+ " newnode: %d):\n", user, np, flags, newnode);
+ debug ("fshelp_access with S_IREAD return err: %d\n", err);
+ }
+ }
+
+ if (!err && flags & O_WRITE)
+ {
+ err = fshelp_access (&np->nn_stat, S_IWRITE, user);
+ if (err)
+ {
+ debug ("netfs_check_open_permissions (user: %p, np: %p, flags: %d,"
+ " newnode: %d):\n", user, np, flags, newnode);
+ debug ("fshelp_access with S_IWRITE return err: %d\n", err);
+ }
}
+
+ if (!err && flags & O_EXEC)
+ {
+ err = fshelp_access (&np->nn_stat, S_IEXEC, user);
+ if (err)
+ {
+ debug ("netfs_check_open_permissions (user: %p, np: %p, flags: %d,"
+ " newnode: %d):\n", user, np, flags, newnode);
+ debug ("fshelp_access with S_IEXEC return err: %d\n", err);
+ }
+ }
+
+ if (!err)
+ if (!np->nn->dev->store)
+ {
+ err = check_dev (np, NULL, flags);
+ if (err)
+ {
+ debug ("netfs_check_open_permissions (user: %p, np: %p,"
+ " flags: %d, newnode: %d):\n", user, np, flags, newnode);
+ debug ("check_dev return err: %d\n", err);
+ }
+ }
+
+ if (err)
+ debug ("netfs_check_open_permissions return: %d\n", err);
+
return err;
}
-static void
-close_hook (struct trivfs_peropen *peropen)
+error_t
+netfs_attempt_read (struct iouser *cred, struct node *np, loff_t offset,
+ size_t *len, void *data)
{
- struct dev *const dev = peropen->cntl->hook;
+ void *our_data = data;
+ error_t err = dev_read (np->nn->dev, offset, *len, &our_data, len);
+ if (err)
+ return err;
- if (peropen->hook)
+ if (our_data != data)
{
- pthread_mutex_lock (&dev->lock);
- if (--dev->nperopens == 0)
- store_set_flags (dev->store, STORE_INACTIVE);
- pthread_mutex_unlock (&dev->lock);
- open_free (peropen->hook);
+ memcpy (data, our_data, *len);
+ munmap (our_data, *len);
}
+
+ return 0;
+}
+
+error_t
+netfs_attempt_write (struct iouser *cred, struct node *np, loff_t offset,
+ size_t *len, const void *data)
+{
+ return dev_write (np->nn->dev, offset, data, *len, len);
}
-
-/* ---------------------------------------------------------------- */
-/* Trivfs hooks */
-int trivfs_fstype = FSTYPE_DEV;
-int trivfs_fsid = 0;
+error_t
+netfs_report_access (struct iouser *cred, struct node *np, int *types)
+{
+ return EOPNOTSUPP;
+}
-int trivfs_support_read = 1;
-int trivfs_support_write = 1;
-int trivfs_support_exec = 0;
+mach_port_t
+netfs_get_filemap (struct node *np, vm_prot_t prot)
+{
+ mach_port_t memobj;
+ errno = dev_get_memory_object (np->nn->dev, prot, &memobj);
+ if (errno)
+ {
+ debug ("netfs_get_filemap (np: %p, vm_prot_t: %d):\n", np, prot);
+ memobj = MACH_PORT_NULL;
+ debug ("dev_get_memory_object return err: %d\n", errno);
+ }
-int trivfs_allow_open = O_READ | O_WRITE;
+ return memobj;
+}
+
+struct iouser *
+netfs_make_user (uid_t *uids, int nuids, uid_t *gids, int ngids)
+{
+ return NULL;
+}
void
-trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+netfs_node_norefs (struct node *np)
{
- struct dev *const dev = cred->po->cntl->hook;
- struct open *open = cred->po->hook;
+ return;
+}
- st->st_mode &= ~S_IFMT;
+/* Returned directory entries are aligned to blocks this many bytes long.
+ Must be a power of two. */
+#define DIRENT_ALIGN 4
+#define DIRENT_NAME_OFFS offsetof (struct dirent, d_name)
- if (open)
- /* An open device. */
- {
- struct store *store = open->dev->store;
- store_offset_t size = store->size;
+/* Length is structure before the name + the name + '\0', all
+ padded to a four-byte alignment. */
+#define DIRENT_LEN(name_len) \
+ ((DIRENT_NAME_OFFS + (name_len) + 1 + (DIRENT_ALIGN - 1)) \
+ & ~(DIRENT_ALIGN - 1))
- if (store->block_size > 1)
- st->st_blksize = store->block_size;
+static inline int
+bump_size (size_t *size, int *count, const char *name, const int nentries,
+ const vm_size_t buffsize)
+{
+ if (nentries == -1 || *count < nentries)
+ {
+ size_t new_size = *size + DIRENT_LEN (strlen (name));
+ if (buffsize > 0 && new_size > buffsize)
+ return 0;
- st->st_size = size;
- st->st_mode |= ((dev->inhibit_cache || store->block_size == 1)
- ? S_IFCHR : S_IFBLK);
+ *size = new_size;
+ *count += 1;
+ return 1;
}
- else
- /* Try and do things without an open device... */
+
+ return 0;
+}
+
+static inline int
+add_dir_entry (char **data, const char *name, const ino_t fileno,
+ const int type, int *count, const int nentries, size_t *size)
+{
+ if (nentries == -1 || *count < nentries)
{
- st->st_blksize = 0;
- st->st_size = 0;
+ size_t namlen = strlen (name);
+ size_t sz = DIRENT_LEN (namlen);
- st->st_mode |= dev->inhibit_cache ? S_IFCHR : S_IFBLK;
+ if (sz > *size)
+ return 0;
+
+ *size -= sz;
+
+ struct dirent hdr;
+ hdr.d_fileno = fileno;
+ hdr.d_reclen = sz;
+ hdr.d_type = type;
+ hdr.d_namlen = namlen;
+
+ memcpy (*data, &hdr, DIRENT_NAME_OFFS);
+ strcpy (*data + DIRENT_NAME_OFFS, name);
+
+ *data += sz;
+ *count += 1;
+
+ return 1;
}
- st->st_rdev = dev->rdev;
- if (dev_is_readonly (dev))
- st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ return 0;
}
error_t
-trivfs_goaway (struct trivfs_control *fsys, int flags)
+netfs_get_dirents (struct iouser *cred, struct node *dir, int entry,
+ int nentries, char **data, mach_msg_type_number_t *datacnt,
+ vm_size_t bufsize, int *amt)
{
- struct dev *const device = fsys->hook;
- error_t err;
- int force = (flags & FSYS_GOAWAY_FORCE);
- int nosync = (flags & FSYS_GOAWAY_NOSYNC);
- struct port_class *root_port_class = fsys->protid_class;
+ if (!dir->nn->entries)
+ {
+ if (dir != netfs_root_node)
+ return ENOTDIR;
+
+ error_t err = create_partitions ();
+ if (err)
+ return err;
+ }
- pthread_mutex_lock (&device->lock);
+ if (dir->nn->entries_num + 2 <= entry)
+ {
+ *datacnt = 0;
+ *amt = 0;
+ *data = NULL;
+ return 0;
+ }
- if (device->store == NULL)
- /* The device is not actually open.
- XXX note that exitting here nukes non-io users, like someone
- in the middle of a stat who will get SIGLOST or something. */
- exit (0);
+ int count = 0;
+ size_t size = 0;
- /* Wait until all pending rpcs are done. */
- err = ports_inhibit_class_rpcs (root_port_class);
- if (err == EINTR || (err && !force))
+ if (entry == 0)
+ bump_size (&size, &count, ".", nentries, bufsize);
+ if (entry <= 1)
+ bump_size (&size, &count, "..", nentries, bufsize);
+
+ struct node *current_node;
+ for (size_t i = 0; i < dir->nn->entries_num; ++i)
{
- pthread_mutex_unlock (&device->lock);
- return err;
+ current_node = dir->nn->entries[i];
+ if (!bump_size (&size, &count, current_node->nn->name, nentries,
+ bufsize))
+ break;
}
- if (force && nosync)
- /* Exit with extreme prejudice. */
- exit (0);
-
- if (!force && ports_count_class (root_port_class) > 0)
- /* Still users, so don't exit. */
- goto busy;
-
- if (! nosync)
- /* Sync the device here, if necessary, so that closing it won't result in
- any I/O (which could get hung up trying to use one of our pagers). */
- dev_sync (device, 1);
-
- /* devpager_shutdown may sync the pagers as side-effect (if NOSYNC is 0),
- so we put that first in this test. */
- if (dev_stop_paging (device, nosync) || force)
- /* Bye-bye. */
- {
- if (! nosync)
- /* If NOSYNC is true, we don't close DEV, as that could cause data to
- be written back. */
- dev_close (device);
- exit (0);
+ void *new_data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (new_data == MAP_FAILED)
+ return errno;
+
+ *data = (char *) new_data;
+ *datacnt = size;
+ *amt = count;
+
+ count = 0;
+ char *ptr_data = *data;
+
+ if (entry == 0)
+ add_dir_entry (&ptr_data, ".", dir->nn_stat.st_ino, DT_DIR, &count,
+ nentries, &size);
+
+ if (entry <= 1)
+ add_dir_entry (&ptr_data, "..", 2, DT_DIR, &count, nentries, &size);
+
+ int dirent_type;
+ for (size_t i = 0; i < dir->nn->entries_num; ++i)
+ {
+ current_node = dir->nn->entries[i];
+ if (current_node->nn->dev->store->block_size == 1)
+ dirent_type = DT_CHR;
+ else
+ dirent_type = DT_BLK;
+
+ if (!add_dir_entry (&ptr_data, current_node->nn->name,
+ current_node->nn_stat.st_ino, dirent_type, &count,
+ nentries, &size))
+ break;
}
- busy:
- /* Allow normal operations to proceed. */
- ports_enable_class (root_port_class);
- ports_resume_class_rpcs (root_port_class);
- pthread_mutex_unlock (&device->lock);
-
- /* Complain that there are still users. */
- return EBUSY;
-}
-
-/* If this variable is set, it is called by trivfs_S_fsys_getroot before any
- other processing takes place; if the return value is EAGAIN, normal trivfs
- getroot processing continues, otherwise the rpc returns with that return
- value. */
-error_t (*trivfs_getroot_hook) (struct trivfs_control *cntl,
- mach_port_t reply_port,
- mach_msg_type_name_t reply_port_type,
- mach_port_t dotdot,
- const uid_t *uids, mach_msg_type_number_t nuids, const uid_t *gids, mach_msg_type_number_t ngids,
- int flags,
- retry_type *do_retry, char *retry_name,
- mach_port_t *node, mach_msg_type_name_t *node_type)
- = getroot_hook;
-
-/* If this variable is set, it is called every time an open happens.
- USER and FLAGS are from the open; CNTL identifies the
- node being opened. This call need not check permissions on the underlying
- node. If the open call should block, then return EWOULDBLOCK. Other
- errors are immediately reflected to the user. If O_NONBLOCK
- is not set in FLAGS and EWOULDBLOCK is returned, then call
- trivfs_complete_open when all pending open requests for this
- file can complete. */
-error_t (*trivfs_check_open_hook)(struct trivfs_control *trivfs_control,
- struct iouser *user,
- int flags)
- = check_open_hook;
-
-/* If this variable is set, it is called every time a new peropen
- structure is created and initialized. */
-error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
-
-/* If this variable is set, it is called every time a peropen structure
- is about to be destroyed. */
-void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
-
-/* Sync this filesystem. */
-kern_return_t
-trivfs_S_fsys_syncfs (struct trivfs_control *cntl,
- mach_port_t reply, mach_msg_type_name_t replytype,
- int wait, int dochildren)
+ return 0;
+}
+
+static inline int
+is_privileged (const struct idvec *uids)
{
- struct dev *dev = cntl->hook;
- if (dev)
- return dev_sync (dev, wait);
+ return idvec_contains (uids, 0) || idvec_contains (uids, getuid ());
+}
+
+error_t
+netfs_file_get_storage_info (struct iouser *cred, struct node *np,
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints,
+ mach_msg_type_number_t *num_ints,
+ off_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data,
+ mach_msg_type_number_t *data_len)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ *ports_type = MACH_MSG_TYPE_COPY_SEND;
+ struct dev *dev = np->nn->dev;
+ struct store *store = dev->store;
+ if (storeio_stat.enforced && !(store->flags & STORE_ENFORCED))
+ {
+ /* The --enforced switch tells us not to let anyone
+ get at the device, no matter how trustable they are. */
+ size_t name_len = (store->name ? strlen (store->name) + 1 : 0);
+ *num_ports = 0;
+ int i = 0;
+ (*ints)[i++] = STORAGE_OTHER;
+ (*ints)[i++] = store->flags;
+ (*ints)[i++] = store->block_size;
+ (*ints)[i++] = 1; /* num_runs */
+ (*ints)[i++] = name_len;
+ (*ints)[i++] = 0; /* misc_len */
+ *num_ints = i;
+ i = 0;
+ (*offsets)[i++] = 0;
+ (*offsets)[i++] = store->size;
+ *num_offsets = i;
+ if (store->name)
+ memcpy (*data, store->name, name_len);
+ *data_len = name_len;
+ return 0;
+ }
+
+ error_t err;
+ if (!is_privileged (cred->uids)
+ && !store_is_securely_returnable (store, np->nn_stat.st_mode))
+ {
+ struct store *clone;
+ err = store_clone (store, &clone);
+ if (err)
+ return err;
+
+ err = store_set_flags (clone, STORE_INACTIVE);
+ if (err == EINVAL)
+ err = EACCES;
+ else
+ err = store_return (clone, ports, num_ports, ints, num_ints,
+ offsets, num_offsets, data, data_len);
+
+ store_free (clone);
+ }
else
- return 0;
+ err = store_return (store, ports, num_ports, ints, num_ints,
+ offsets, num_offsets, data, data_len);
+
+ return err;
}
--
2.43.0