Hello,
On Thu, 6 Aug 2026 01:22:31 Samuel Thibault wrote:
> No, I didn't mean PedDeviceType, but really PedDiskType, in the PedDisk
> structure:
>
> PedDisk *disk = ped_disk_new (device);
>
> Then disk->type->name tells you the name of the partition type, which
> can be "msdos", "gpt", and probably "loop" when there is no actual
> partition table (last detector as last dummy resort).
Yes, that helped. Now storeio only creates partition directories when they
exist. Well, they can also be passed to the ext2fs translator in two ways:
settrans -c ext /hurd/ext2fs -T typed file:/root/storeio/2
settranc -c ext /hurd/ext2fs -T typed part:2:file:/root/storeio
> *All* I'm saying is that instead of defining netfs_S_io_read, you can
> probably simply define netfs_attempt_read, something like:
>
> error_t
> netfs_attempt_read (struct iouser * cred, struct node * node,
> off_t offset, size_t * len, void *data)
> {
> return dev_read(node->nn->dev, offset, *len, &data, len);
> }
>
>
> Way less duplicated code to maintain. libstore
>
>
> And similarly for netfs_S_io_write.
>
> And netfs_S_io_map can probably be implemented by just providing
> netfs_get_filemap.
>
> And netfs_S_io_readable can probably be implemented by making
> netfs_validate_stat actually fill np->nn_stat so libnetfs'
> implementation of netfs_S_io_readable will just work already.
Yes, I managed to remove the duplicate code, and now everything looks
neater.
I also moved the netfs_file_get_storage_info function to storeio.c so we can
delete the io.c file. Just passing &data to dev_read results in an error, so
sometimes copying the value via memcpy (I assume libstore can sometimes
somehow change the data pointer itself).
Thanks,
--
Mikhail Karpov
From b738b85509e9a89ac7a8cbb6060606171acbcd9e Mon Sep 17 00:00:00 2001
From: Mikhail Karpov <[email protected]>
Date: Sun, 9 Aug 2026 17:42:54 +0700
Subject: [PATCH] Migrating storeio from trivfs to netfs
---
Makefile | 6 +-
libnetfs/Makefile | 2 +-
libnetfs/init-init.c | 4 +-
libnetfs/make-peropen.c | 9 +
libnetfs/netfs.h | 8 +
libnetfs/priv.c | 26 +
libnetfs/release-peropen.c | 8 +
storeio/Makefile | 13 +-
storeio/dev.c | 118 ++--
storeio/dev.h | 97 ++-
storeio/io.c | 385 -----------
storeio/open.c | 127 ----
storeio/open.h | 68 --
storeio/pager.c | 25 +-
storeio/storeio.c | 1335 +++++++++++++++++++++++++++++-------
15 files changed, 1273 insertions(+), 958 deletions(-)
create mode 100644 libnetfs/priv.c
delete mode 100644 storeio/io.c
delete mode 100644 storeio/open.c
delete mode 100644 storeio/open.h
diff --git a/Makefile b/Makefile
index c51e8c1..9d2968e 100644
--- a/Makefile
+++ b/Makefile
@@ -37,7 +37,7 @@ lib-subdirs = libshouldbeinlibc libihash libiohelp libports \
# Hurd programs
prog-subdirs = auth proc exec term \
ext2fs isofs tmpfs fatfs \
- storeio pflocal pfinet defpager mach-defpager \
+ pflocal pfinet defpager mach-defpager \
login daemons boot console \
hostmux usermux ftpfs trans \
console-client utils sutils libfshelp-tests \
@@ -70,6 +70,10 @@ ifeq ($(HAVE_LIBACPICA),yes)
prog-subdirs += acpi
endif
+ifneq ($(PARTED_LIBS),)
+prog-subdirs += storeio
+endif
+
# Other directories
other-subdirs = hurd doc config release include
diff --git a/libnetfs/Makefile b/libnetfs/Makefile
index 24606ff..8f947a3 100644
--- a/libnetfs/Makefile
+++ b/libnetfs/Makefile
@@ -53,7 +53,7 @@ OTHERSRCS= drop-node.c init-init.c make-node.c make-peropen.c make-protid.c \
runtime-argp.c std-runtime-argp.c std-startup-argp.c \
append-std-options.c trans-callback.c set-get-trans.c \
nref.c nrele.c nput.c file-get-storage-info-default.c dead-name.c \
- get-source.c
+ get-source.c priv.c
SRCS= $(OTHERSRCS) $(FSSRCS) $(IOSRCS) $(FSYSSRCS) $(IFSOCKSRCS)
diff --git a/libnetfs/init-init.c b/libnetfs/init-init.c
index 19ed0d3..f64c7bb 100644
--- a/libnetfs/init-init.c
+++ b/libnetfs/init-init.c
@@ -38,9 +38,9 @@ void
netfs_init (void)
{
error_t err;
- err = maptime_map (0, 0, &netfs_mtime);
+ err = maptime_map (1, 0, &netfs_mtime);
if (err)
- err = maptime_map (1, 0, &netfs_mtime);
+ err = maptime_map (0, 0, &netfs_mtime);
if (err)
error (2, err, "mapping time");
diff --git a/libnetfs/make-peropen.c b/libnetfs/make-peropen.c
index 3b12788..9bb4892 100644
--- a/libnetfs/make-peropen.c
+++ b/libnetfs/make-peropen.c
@@ -43,6 +43,15 @@ netfs_make_peropen (struct node *np, int flags, struct peropen *context)
po->np = np;
po->path = NULL;
+ if (netfs_peropen_create_hook)
+ err = (*netfs_peropen_create_hook) (po);
+ if (err)
+ {
+ fshelp_rlock_po_fini (&po->lock_status);
+ free (po);
+ return NULL;
+ }
+
if (context)
{
if (context->path)
diff --git a/libnetfs/netfs.h b/libnetfs/netfs.h
index 6fc53ce..1f1d5c2 100644
--- a/libnetfs/netfs.h
+++ b/libnetfs/netfs.h
@@ -113,6 +113,14 @@ extern char *netfs_server_name;
version number. */
extern char *netfs_server_version;
+/* If this variable is set, it is called internally every time a new peropen
+ structure is created and initialized. */
+extern error_t (*netfs_peropen_create_hook) (struct peropen *po);
+
+/* If this variable is set, it is called internally every time a peropen
+ structure is about to be destroyed. */
+extern void (*netfs_peropen_destroy_hook) (struct peropen *po);
+
/* The user must define this function. Make sure that NP->nn_stat is
filled with the most current information. CRED identifies the user
responsible for the operation. NP is locked. */
diff --git a/libnetfs/priv.c b/libnetfs/priv.c
new file mode 100644
index 0000000..4a46606
--- /dev/null
+++ b/libnetfs/priv.c
@@ -0,0 +1,26 @@
+/* Default values for weak variables
+ 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 "netfs.h"
+
+error_t (*netfs_peropen_create_hook) (struct peropen *po)
+ __attribute__ ((weak));
+
+void (*netfs_peropen_destroy_hook) (struct peropen *po)
+ __attribute__ ((weak));
diff --git a/libnetfs/release-peropen.c b/libnetfs/release-peropen.c
index 43f4cba..3dfca36 100644
--- a/libnetfs/release-peropen.c
+++ b/libnetfs/release-peropen.c
@@ -26,6 +26,14 @@ netfs_release_peropen (struct peropen *po)
if (refcount_deref (&po->refcnt) > 0)
return;
+ if (netfs_peropen_destroy_hook)
+ {
+ refcount_unsafe_ref (&po->refcnt);
+ (*netfs_peropen_destroy_hook) (po);
+ if (refcount_deref (&po->refcnt) > 0)
+ return;
+ }
+
pthread_mutex_lock (&po->np->lock);
if (po->root_parent)
mach_port_deallocate (mach_task_self (), po->root_parent);
diff --git a/storeio/Makefile b/storeio/Makefile
index 5d9aeb4..15632d0 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
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 = -lparted -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
include ../Makeconf
diff --git a/storeio/dev.c b/storeio/dev.c
index c87400c..97b36cd 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]>
@@ -22,7 +22,6 @@
#include <assert-backtrace.h>
#include <string.h>
#include <hurd/pager.h>
-#include <hurd/store.h>
#include <sys/mman.h>
#include "dev.h"
@@ -140,48 +139,31 @@ 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. */
+
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)
{
store_free (dev->store);
dev->store = 0;
- return ENOMEM;
+ return errno;
}
- if (!dev->inhibit_cache)
+ if (!storeio_stat.inhibit_cache)
{
dev->buf_offs = -1;
pthread_rwlock_init (&dev->io_lock, NULL);
@@ -192,6 +174,32 @@ dev_open (struct dev *dev)
return 0;
}
+
+/* Called with DEV->lock held. 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 +209,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 +230,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 +367,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. */
@@ -390,27 +398,10 @@ error_t
dev_read (struct dev *dev, off_t offs, size_t whole_amount,
void **buf, size_t *len)
{
- error_t err;
- int allocated_buf = 0;
- error_t ensure_buf (void)
- {
- if (*len < whole_amount)
- {
- void *new = mmap (0, whole_amount, PROT_READ|PROT_WRITE,
- MAP_ANON, 0, 0);
- if (new == (void *) -1)
- return errno;
- *buf = new;
- allocated_buf = 1;
- }
- return 0;
- }
error_t buf_read (size_t buf_offs, size_t io_offs, size_t len)
{
- error_t err = ensure_buf ();
- if (! err)
- memcpy (*buf + io_offs, dev->buf + buf_offs, len);
- return err;
+ memcpy (*buf + io_offs, dev->buf + buf_offs, len);
+ return 0;
}
error_t raw_read (off_t offs, size_t io_offs, size_t len, size_t *amount)
{
@@ -424,22 +415,15 @@ dev_read (struct dev *dev, off_t offs, size_t whole_amount,
a buffer big enough to hold everything, in case we have to
coalesce multiple reads into a single return buffer. */
{
- error_t err = ensure_buf ();
+ void *_req_buf = *buf + io_offs, *req_buf = _req_buf;
+ size_t req_len = len;
+ error_t err = store_read (store, addr, len, &req_buf, &req_len);
if (! err)
{
- void *_req_buf = *buf + io_offs, *req_buf = _req_buf;
- size_t req_len = len;
- err = store_read (store, addr, len, &req_buf, &req_len);
- if (! err)
- {
- if (req_buf != _req_buf)
- /* Copy from wherever the read put it. */
- {
- memcpy (_req_buf, req_buf, req_len);
- munmap (req_buf, req_len);
- }
- *amount = req_len;
- }
+ if (req_buf != _req_buf)
+ /* Copy from wherever the read put it. */
+ memcpy (_req_buf, req_buf, req_len);
+ *amount = req_len;
}
return err;
}
@@ -452,7 +436,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.
@@ -476,9 +460,5 @@ dev_read (struct dev *dev, off_t offs, size_t whole_amount,
whole_amount, buf, len);
}
- err = dev_rw (dev, offs, whole_amount, len, buf_read, raw_read);
- if (err && allocated_buf)
- munmap (*buf, whole_amount);
-
- return err;
+ return dev_rw (dev, offs, whole_amount, len, buf_read, raw_read);
}
diff --git a/storeio/dev.h b/storeio/dev.h
index eda7a93..2252f60 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
@@ -24,46 +24,25 @@
#include <device/device.h>
#include <pthread.h>
#include <hurd/store.h>
-#include <hurd/trivfs.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,48 @@ struct dev
pthread_mutex_t pager_lock;
};
+struct netnode
+{
+ struct dev *dev;
+ struct opens *opens;
+ char *name;
+ struct node **entries;
+ size_t entries_size;
+};
+
+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;
+
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));
}
+error_t dev_open_from_store (struct dev *dev, struct store *store);
+
/* Called with DEV->lock held. Try to open the store underlying DEV. */
-error_t dev_open (struct dev *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 +116,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 +137,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 dca997e..0000000
--- 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 7490252..0000000
--- 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 ad2678f..0000000
--- 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 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);
if (!err && want < vm_page_size)
@@ -61,9 +67,12 @@ pager_read_page (struct user_pager_info *upi,
*writelock = (store->flags & STORE_READONLY);
if (err || read < want)
- return EIO;
- else
- return 0;
+ {
+ munmap (*((void **) buf), want);
+ return EIO;
+ }
+
+ return 0;
}
/* For pager PAGER, synchronously write one page from BUF to offset PAGE.
@@ -174,11 +183,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 +232,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/storeio.c b/storeio/storeio.c
index 4e8a962..3e79e12 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 <parted/parted.h>
+#include <dirent.h>
#include <hurd.h>
#include <hurd/ports.h>
-#include <hurd/trivfs.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,136 @@ 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
+static 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. */
-};
+ debug ("create_node (name: %s, dir: %p):\n", name, dir);
+ struct netnode *netnode = malloc (sizeof (struct netnode));
+ if (!netnode)
+ {
+ debug ("!netnode\n");
+ debug ("create_node return: ENOMEM\n");
+ return ENOMEM;
+ }
+
+ struct node *new_node = netfs_make_node (netnode);
+ if (!new_node)
+ {
+ debug ("!new_node\n");
+ free (netnode);
+ debug ("create_node return: ENOMEM\n");
+ return ENOMEM;
+ }
+
+ 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)
+ {
+ debug ("!dev\n");
+ free (netnode);
+ free (new_node);
+ debug ("create_node return: ENOMEM\n");
+ return ENOMEM;
+ }
+
+ 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_size = 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 ("new_node: %p, name: %s\n", new_node, new_node->nn->name);
+ debug ("create_node return: 0\n");
+ return 0;
+}
+
+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 +211,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 +237,1035 @@ 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)
+
+static inline void
+change_node_mode (struct node *node)
{
- struct dev *const dev = trivfs_control->hook;
- error_t err = 0;
+ 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;
+}
- if (!err && dev_is_readonly (dev) && (flags & O_WRITE))
- return EROFS;
+static 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 == NULL)
+ if (!dev->store)
{
- /* 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;
+ 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 err;
+ return 0;
}
static error_t
-open_hook (struct trivfs_peropen *peropen)
+node_open_create (struct peropen *po)
{
error_t err = 0;
- struct dev *const dev = peropen->cntl->hook;
-
+ 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);
+ err = store_clear_flags (dev->store, STORE_INACTIVE);
pthread_mutex_unlock (&dev->lock);
- if (!err)
- err = open_create (dev, (struct open **)&peropen->hook);
}
+
return err;
}
+error_t (*netfs_peropen_create_hook) (struct peropen *po) = node_open_create;
+
static void
-close_hook (struct trivfs_peropen *peropen)
+node_open_destroy (struct peropen *po)
+{
+ struct dev *dev = po->np->nn->dev;
+ pthread_mutex_lock (&dev->lock);
+ 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_size; ++i)
+ pthread_mutex_lock (&netfs_root_node->nn->entries[i]->nn->dev->lock);
+}
+
+inline static void
+devs_unlock (void)
{
- struct dev *const dev = peropen->cntl->hook;
+ pthread_mutex_unlock (&netfs_root_node->nn->dev->lock);
+ for (size_t i = 0; i < netfs_root_node->nn->entries_size; ++i)
+ pthread_mutex_unlock (&netfs_root_node->nn->entries[i]->nn->dev->lock);
+}
- if (peropen->hook)
+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)
{
- 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);
+ debug ("!pt");
+ debug ("netfs_S_fsys_goaway return: EOPNOTSUPP\n");
+ return EOPNOTSUPP;
}
-}
-
-/* ---------------------------------------------------------------- */
-/* Trivfs hooks */
-int trivfs_fstype = FSTYPE_DEV;
-int trivfs_fsid = 0;
+ 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;
+ }
-int trivfs_support_read = 1;
-int trivfs_support_write = 1;
-int trivfs_support_exec = 0;
+ devs_lock ();
-int trivfs_allow_open = O_READ | O_WRITE;
+ 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;
+ }
-void
-trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
-{
- struct dev *const dev = cred->po->cntl->hook;
- struct open *open = cred->po->hook;
+ int nosync = flags & FSYS_GOAWAY_NOSYNC;
+ if (force && nosync)
+ {
+ debug ("force && nosync\n");
+ exit (0);
+ }
- st->st_mode &= ~S_IFMT;
+ 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 (open)
- /* An open device. */
+ if (!nosync)
{
- struct store *store = open->dev->store;
- store_offset_t size = store->size;
+ debug ("!nosync\n");
+ err = netfs_attempt_syncfs (0, flags);
+ }
- if (store->block_size > 1)
- st->st_blksize = store->block_size;
+ 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_size; ++i)
+ dev_close (netfs_root_node->nn->entries[i]->nn->dev);
+ }
+ }
- st->st_size = size;
- st->st_mode |= ((dev->inhibit_cache || store->block_size == 1)
- ? S_IFCHR : S_IFBLK);
+ 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;
+}
+
+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
- /* Try and do things without an open device... */
{
- st->st_blksize = 0;
- st->st_size = 0;
+ np->nn_stat.st_size = 0;
+ np->nn_stat.st_blksize = 0;
+ }
+
+ return 0;
+}
- st->st_mode |= dev->inhibit_cache ? S_IFCHR : S_IFBLK;
+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);
}
- st->st_rdev = dev->rdev;
- if (dev_is_readonly (dev))
- st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ return err;
}
error_t
-trivfs_goaway (struct trivfs_control *fsys, int flags)
+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_size; ++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[%d]->nn->dev)"
+ " return err: %d\n", i, err);
+ debug ("netfs_attempt_syncfs return: %d\n", err);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/* 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)
{
- struct dev *const device = fsys->hook;
+ char buffer[20];
+ snprintf (buffer, sizeof (buffer), "%zu", num);
+
+ return strdup (buffer);
+}
+
+static 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;
+ }
+
+ dir->nn->entries_size = last_partition_num;
+ dir->nn->entries = malloc (last_partition_num * sizeof (struct node *));
+ if (!dir->nn->entries)
+ {
+ debug ("!dir->nn->entries\n");
+ debug ("create_partitions return: ENOMEM\n");
+ return ENOMEM;
+ }
+
+ 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;
error_t err;
- int force = (flags & FSYS_GOAWAY_FORCE);
- int nosync = (flags & FSYS_GOAWAY_NOSYNC);
- struct port_class *root_port_class = fsys->protid_class;
+ 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;
+ }
- pthread_mutex_lock (&device->lock);
+ 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)
+ {
+ debug ("!node_name\n");
+ err = ENOMEM;
+ break;
+ }
+
+ err = create_node (part, create_node_name (i), dir);
+ if (err)
+ {
+ debug ("create_node return err: %d\n", err);
+ break;
+ }
- 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);
+ err = check_dev (*part, store, flags);
+ if (err)
+ {
+ debug ("dev_init_from_store return err: %d\n", err);
+ break;
+ }
+ }
- /* Wait until all pending rpcs are done. */
- err = ports_inhibit_class_rpcs (root_port_class);
- if (err == EINTR || (err && !force))
+ debug ("create_partitions return: %d\n", err);
+ return err;
+}
+
+error_t
+netfs_attempt_lookup (struct iouser *user, struct node *dir,
+ const char *name, struct node **np)
+{
+ if (!dir->nn->entries)
{
- pthread_mutex_unlock (&device->lock);
+ 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);
+ return 0;
+ }
+
+ struct node *current_node = NULL;
+ struct node *iter;
+ for (size_t i = 0; i < dir->nn->entries_size; ++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);
+ 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;
+
+ if (!err && flags & O_READ)
+ {
+ 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;
+}
+
+error_t
+netfs_attempt_read (struct iouser *cred, struct node *np, loff_t offset,
+ size_t *len, void *data)
+{
+ void *our_data = data;
+ error_t err = dev_read (np->nn->dev, offset, *len, &our_data, len);
+ if (err)
+ {
+ debug ("netfs_attempt_read (np: %p, offset: %lld, *len: %zu,"
+ " data: %p):\n", np, offset, *len, data);
+ debug ("dev_read return err: %d\n", err);
+ debug ("netfs_attempt_read return: %d\n", err);
return err;
}
- 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);
+ if (our_data != data)
+ {
+ memcpy (data, our_data, *len);
+ munmap (our_data, *len);
}
- 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;
+}
+
+error_t
+netfs_attempt_write (struct iouser *cred, struct node *np, loff_t offset,
+ size_t *len, const void *data)
+{
+ error_t err = dev_write (np->nn->dev, offset, data, *len, len);
+ if (err)
+ {
+ debug ("netfs_attempt_write (np: %p, offset: %lld, *len: %zu,"
+ " data: %p):\n", np, offset, *len, data);
+ debug ("dev_write return err: %d\n", err);
+ debug ("netfs_attempt_write return: %d\n", err);
+ }
+
+ return err;
+}
+
+error_t
+netfs_report_access (struct iouser *cred, struct node *np, int *types)
+{
+ return EOPNOTSUPP;
+}
+
+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);
+ }
+
+ return memobj;
+}
+
+struct iouser *
+netfs_make_user (uid_t *uids, int nuids, uid_t *gids, int ngids)
+{
+ return NULL;
+}
+
+void
+netfs_node_norefs (struct node *np)
+{
+ return;
+}
+
+/* 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)
+
+/* 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))
+
+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;
+
+ *size = new_size;
+ *count += 1;
+ return 1;
+ }
+
+ 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)
+ {
+ size_t namlen = strlen (name);
+ size_t sz = DIRENT_LEN (namlen);
+
+ 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;
+ }
+
+ return 0;
+}
+
+error_t
+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)
+{
+ if (!dir->nn->entries)
+ {
+ if (dir != netfs_root_node)
+ {
+ debug ("netfs_get_dirents (cred: %p, dir: %p, entry: %d,"
+ " nentries: %d, datacnt: %u, bufsize: %u, amt: %d)\n",
+ cred, dir, entry, nentries, *datacnt, bufsize, *amt);
+ debug ("!dir->nn->entries\n");
+ debug ("dir != netfs_root_node\n");
+ debug ("netfs_get_dirents return: ENOTDIR\n");
+ return ENOTDIR;
+ }
+
+ error_t err = create_partitions ();
+ if (err)
+ {
+ debug ("netfs_get_dirents (cred: %p, dir: %p, entry: %d,"
+ " nentries: %d, datacnt: %u, bufsize: %u, amt: %d)\n",
+ cred, dir, entry, nentries, *datacnt, bufsize, *amt);
+ debug ("!dir->nn->entries\n");
+ debug ("create_partitions return err: %d\n", err);
+ debug ("netfs_get_dirents return: %d\n", err);
+ return err;
+ }
+ }
+
+ if (dir->nn->entries_size + 2 <= entry)
+ {
+ *datacnt = 0;
+ *amt = 0;
+ *data = NULL;
+ return 0;
+ }
+
+ int count = 0;
+ size_t size = 0;
+
+ 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_size; ++i)
+ {
+ current_node = dir->nn->entries[i];
+ if (!bump_size (&size, &count, current_node->nn->name, nentries,
+ bufsize))
+ break;
+ }
+
+ void *new_data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (new_data == MAP_FAILED)
+ {
+ debug ("netfs_get_dirents (cred: %p, dir: %p, entry: %d,"
+ " nentries: %d, datacnt: %u, bufsize: %u, amt: %d)\n",
+ cred, dir, entry, nentries, *datacnt, bufsize, *amt);
+ debug ("new_data == MAP_FAILED\n");
+ debug ("netfs_get_dirents return: %d\n", errno);
+ 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_size; ++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;
+ }
+
+ return 0;
+}
+
+static inline int
+is_privileged (const struct idvec *uids)
+{
+ 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)
{
- struct dev *dev = cntl->hook;
- if (dev)
- return dev_sync (dev, wait);
+ 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