diff options
-rw-r--r-- | hostmux/ChangeLog | 0 | ||||
-rw-r--r-- | hostmux/Makefile | 31 | ||||
-rw-r--r-- | hostmux/hostmux-xinl.c | 24 | ||||
-rw-r--r-- | hostmux/hostmux.c | 118 | ||||
-rw-r--r-- | hostmux/hostmux.h | 122 | ||||
-rw-r--r-- | hostmux/leaf.c | 187 | ||||
-rw-r--r-- | hostmux/mux.c | 401 | ||||
-rw-r--r-- | hostmux/node.c | 117 | ||||
-rw-r--r-- | hostmux/stubs.c | 143 |
9 files changed, 1143 insertions, 0 deletions
diff --git a/hostmux/ChangeLog b/hostmux/ChangeLog new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/hostmux/ChangeLog diff --git a/hostmux/Makefile b/hostmux/Makefile new file mode 100644 index 00000000..390277ef --- /dev/null +++ b/hostmux/Makefile @@ -0,0 +1,31 @@ +# Makefile for hostmux +# +# Copyright (C) 1997 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 +# 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. + +dir := hostmux +makemode := server + +target = hostmux + +SRCS = hostmux.c mux.c leaf.c node.c stubs.c +LCLHDRS = hostmux.h + +MIGSTUBS = ioServer.o socketServer.o +OBJS = $(SRCS:.c=.o) +HURDLIBS = netfs fshelp iohelp ports threads ihash shouldbeinlibc + +include ../Makeconf diff --git a/hostmux/hostmux-xinl.c b/hostmux/hostmux-xinl.c new file mode 100644 index 00000000..2f79f96b --- /dev/null +++ b/hostmux/hostmux-xinl.c @@ -0,0 +1,24 @@ +/* Real definitions for extern inline functions in hostmux.h + + Copyright (C) 1997 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.ai.mit.edu> + 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. */ + +#define HOSTMUX_EI +#undef __OPTIMIZE__ +#define __OPTIMIZE__ +#include "hostmux.h" diff --git a/hostmux/hostmux.c b/hostmux/hostmux.c new file mode 100644 index 00000000..d3127a46 --- /dev/null +++ b/hostmux/hostmux.c @@ -0,0 +1,118 @@ +/* Multiplexing filesystems by host + + Copyright (C) 1997 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.ai.mit.edu> + 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 <unistd.h> +#include <argp.h> +#include <argz.h> +#include <error.h> +#include <sys/time.h> + +#include "hostmux.h" + +int netfs_maxsymlinks = 25; + +volatile struct mapped_time_value *hostmux_mapped_time; + +/* Startup options. */ +static const struct argp_option options[] = +{ + { "host-pattern", 'H', "PAT", OPTION_ARG_OPTIONAL, + "The string to replace in the translator specification with the hostname;" + " if empty, or doesn't occur, the hostname is appended as additional" + " argument instead (default `${host}')" }, + { 0 } +}; +static const char args_doc[] = "TRANSLATOR [ARG...]"; +static const char doc[] = + "A translator for invoking host-specific translators" + "\vThis translator appears like a directory in which hostnames can be" + " looked up, and will start TRANSLATOR to service each resulting node."; + +/* NFS client main program */ +int +main (int argc, char **argv) +{ + error_t err; + struct stat ul_stat; + mach_port_t bootstrap; + struct hostmux mux = { host_pat: "${host}", next_fileno: 10 }; + struct netnode root_nn = { mux: &mux }; + + error_t parse_opt (int key, char *arg, struct argp_state *state) + { + switch (key) + { + case 'H': + mux.host_pat = arg; break; + case ARGP_KEY_NO_ARGS: + argp_usage (state); + case ARGP_KEY_ARGS: + /* Steal the entire tail of arg vector for our own use. */ + return argz_create (state->argv + state->next, + &mux.trans_template, &mux.trans_template_len); + default: + return ARGP_ERR_UNKNOWN; + } + return 0; + } + struct argp argp = { options, parse_opt, args_doc, doc }; + + /* Parse our command line arguments. */ + argp_parse (&argp, argc, argv, 0, 0, 0); + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + netfs_init (); + + /* Create the root node (some attributes initialized below). */ + netfs_root_node = netfs_make_node (&root_nn); + if (! netfs_root_node) + error (5, ENOMEM, "Cannot create root node"); + + err = maptime_map (0, 0, &hostmux_mapped_time); + if (err) + error (6, err, "Cannot map time"); + + /* Handshake with the party trying to start the translator. */ + mux.underlying = netfs_startup (bootstrap, 0); + + /* We inherit various attributes from the node underlying this translator. */ + err = io_stat (mux.underlying, &ul_stat); + if (err) + error (7, err, "Cannot stat underlying node"); + + /* MUX.stat_template contains some fields that are inherited by all nodes + we create. */ + mux.stat_template.st_uid = ul_stat.st_uid; + mux.stat_template.st_gid = ul_stat.st_gid; + mux.stat_template.st_author = ul_stat.st_author; + mux.stat_template.st_fsid = getpid (); + mux.stat_template.st_nlink = 1; + mux.stat_template.st_fstype = FSTYPE_MISC; + + /* Initialize the root node's stat information. */ + netfs_root_node->nn_stat = mux.stat_template; + netfs_root_node->nn_stat.st_ino = 2; + netfs_root_node->nn_stat.st_mode = + S_IFDIR | (ul_stat.st_mode & ~S_IFMT & ~S_ITRANS); + touch (netfs_root_node, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME); + + for (;;) /* ?? */ + netfs_server_loop (); +} diff --git a/hostmux/hostmux.h b/hostmux/hostmux.h new file mode 100644 index 00000000..54c11738 --- /dev/null +++ b/hostmux/hostmux.h @@ -0,0 +1,122 @@ +/* Multiplexing filesystems by host + + Copyright (C) 1997 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.ai.mit.edu> + 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. */ + +#ifndef __HOSTMUX_H__ +#define __HOSTMUX_H__ + +#include <hurd/netfs.h> +#include <rwlock.h> +#include <maptime.h> + +/* Handy source of time. */ +volatile struct mapped_time_value *hostmux_mapped_time; + +/* The state associated with a host multiplexer translator. */ +struct hostmux +{ + /* The host hodes in this mux. */ + struct hostmux_name *names; + struct rwlock names_lock; + + /* The next inode number we'll use; protected by NAMES_LOCK. */ + ino_t next_fileno; + + /* A template argz, which is used to start each host-specific translator + with the host name appropriately added. */ + char *trans_template; + size_t trans_template_len; + + /* What string to replace in TRANS_TEMPLATE with the name of the host; if + 0, or it doesn't occur, the host name is appended as an additional + argument. */ + char *host_pat; + + /* Constant fields for host stat entries. */ + struct stat stat_template; + + /* The file that this translator is sitting on top of; we inherit various + characteristics from it. */ + file_t underlying; +}; + +/* The name of a recently looked up host entry. */ +struct hostmux_name +{ + const char *name; /* Looked up name (may be a number). */ + const char *canon; /* The canonical (fq) host name. */ + + /* A filesystem node associated with NAME. If NAME = CANON, then this will + refer to a node with a translator for that host, otherwise, the node + will be a symbolic link to the canonical name. */ + struct node *node; + + ino_t fileno; /* The inode number for this entry. */ + + struct hostmux_name *next; +}; + +/* The fs specific storage that libnetfs associates with each filesystem + node. */ +struct netnode +{ + /* The mux this node belongs to (the node can either be the mux root, or + one of the hosts served by it). */ + struct hostmux *mux; + + /* For mux nodes, 0, and for leaf nodes, the name under which the node was + looked up. */ + struct hostmux_name *name; +}; + +/* Timestamps to change. */ +#define TOUCH_ATIME 0x1 +#define TOUCH_MTIME 0x2 +#define TOUCH_CTIME 0x4 + +#ifndef HOSTMUX_EI +# define HOSTMUX_EI extern inline +#endif + +/* Change the stat times of NODE as indicated by WHAT (from the set TOUCH_*) + to the current time. */ +HOSTMUX_EI void touch (struct node *node, unsigned what) +{ + struct timeval tv; + + maptime_read (hostmux_mapped_time, &tv); + + if (what & TOUCH_ATIME) + { + netfs_root_node->nn_stat.st_atime = tv.tv_sec; + netfs_root_node->nn_stat.st_atime_usec = tv.tv_usec; + } + if (what & TOUCH_CTIME) + { + netfs_root_node->nn_stat.st_ctime = tv.tv_sec; + netfs_root_node->nn_stat.st_ctime_usec = tv.tv_usec; + } + if (what & TOUCH_MTIME) + { + netfs_root_node->nn_stat.st_mtime = tv.tv_sec; + netfs_root_node->nn_stat.st_mtime_usec = tv.tv_usec; + } +} + +#endif /* __HOSTMUX_H__ */ diff --git a/hostmux/leaf.c b/hostmux/leaf.c new file mode 100644 index 00000000..d17a4bce --- /dev/null +++ b/hostmux/leaf.c @@ -0,0 +1,187 @@ +/* Hostmux leaf node functions + + Copyright (C) 1997 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.ai.mit.edu> + 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 <string.h> +#include <argz.h> + +#include "hostmux.h" + +/* Read the contents of NODE (a symlink), for USER, into BUF. */ +error_t +netfs_attempt_readlink (struct iouser *user, struct node *node, char *buf) +{ + assert (node->nn->name); + memcpy (buf, node->nn->name->canon, node->nn_stat.st_size); + touch (node, TOUCH_ATIME); + return 0; +} + +/* Append BUF, of length BUF_LEN to *TO, of length *TO_LEN, reallocating and + updating *TO & *TO_LEN appropriately. If an allocation error occurs, + *TO's old value is freed, and *TO is set to 0. */ +static void +str_append (char **to, size_t *to_len, const char *buf, const size_t buf_len) +{ + size_t new_len = *to_len + buf_len; + char *new_to = realloc (*to, new_len + 1); + + if (new_to) + { + memcpy (new_to + *to_len, buf, buf_len); + new_to[new_len] = '\0'; + *to = new_to; + *to_len = new_len; + } + else + { + free (*to); + *to = 0; + } +} + +/* For locked node NODE with S_IPTRANS set in its mode, look up the name of + its translator. Store the name into newly malloced storage, and return it + in *ARGZ; set *ARGZ_LEN to the total length. + + For hostmux, this creates a new translator string by instantiating the + global translator template. */ +error_t +netfs_get_translator (struct node *node, char **argz, size_t *argz_len) +{ + if (! node->nn->name) + return EINVAL; + else + { + error_t err = 0; + char *arg = 0; + int did_replace = 0; + struct hostmux *mux = node->nn->mux; + char *template = mux->trans_template; + size_t template_len = mux->trans_template_len; + char *host_pat = mux->host_pat; + const char *host = node->nn->name->canon; + size_t host_len = strlen (host); + + *argz = 0; /* Initialize return value. */ + *argz_len = 0; + + if (host_pat) + { + size_t host_pat_len = strlen (host_pat); + + while (!err && (arg = argz_next (template, template_len, arg))) + { + char *match = strstr (arg, host_pat); + if (match) + { + char *from = match + host_pat_len; + size_t to_len = match - arg; + char *to = strndup (arg, to_len); + + while (to && from) + { + str_append (&to, &to_len, host, host_len); + if (to) + { + match = strstr (from, host_pat); + if (match) + { + str_append (&to, &to_len, from, match - from); + from = match + host_pat_len; + } + else + { + str_append (&to, &to_len, from, strlen (from)); + from = 0; + } + } + } + + if (to) + { + err = argz_add (argz, argz_len, to); + free (to); + } + else + err = ENOMEM; + + did_replace = 1; + } + else + err = argz_add (argz, argz_len, arg); + } + } + else + err = argz_append (argz, argz_len, template, template_len); + + if (!err && !did_replace) + err = argz_add (argz, argz_len, host); + + if (err && *argz_len > 0) + free (*argz); + + return err; + } +} + +/* Create a new leaf node in MUX, with a name NAME, and return the new node + with a single reference in NODE. */ +error_t +create_host_node (struct hostmux *mux, struct hostmux_name *name, + struct node **node) +{ + struct node *new; + struct netnode *nn = malloc (sizeof (struct netnode)); + + if (! nn) + return ENOMEM; + + nn->mux = mux; + nn->name = name; + + new = netfs_make_node (nn); + if (! new) + { + free (nn); + return ENOMEM; + } + + new->nn_stat = mux->stat_template; + new->nn_stat.st_ino = name->fileno; + + if (strcmp (name->name, name->canon) == 0) + /* The real name of the host, make a real node. */ + { + new->nn_stat.st_mode = (S_IFREG | S_IPTRANS | 0666); + new->nn_stat.st_size = 0; + } + else + /* An alias for this host, make a symlink instead. */ + { + new->nn_stat.st_mode = (S_IFLNK | 0666); + new->nn_stat.st_size = strlen (name->canon); + } + + name->node = new; + + *node = new; + + return 0; +} diff --git a/hostmux/mux.c b/hostmux/mux.c new file mode 100644 index 00000000..cba29126 --- /dev/null +++ b/hostmux/mux.c @@ -0,0 +1,401 @@ +/* Root hostmux node + + Copyright (C) 1997 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.ai.mit.edu> + 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 <stddef.h> +#include <string.h> +#include <dirent.h> +#include <netdb.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#include "hostmux.h" + +error_t create_host_node (struct hostmux *mux, struct hostmux_name *name, + struct node **node); + +/* 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 error_t lookup_host (struct hostmux *mux, const char *host, + struct node **node); /* fwd decl */ + +/* [root] Directory operations. */ + +/* Lookup NAME in DIR for USER; set *NODE to the found name upon return. If + the name was not found, then return ENOENT. On any error, clear *NODE. + (*NODE, if found, should be locked, this call should unlock DIR no matter + what.) */ +error_t +netfs_attempt_lookup (struct iouser *user, struct node *dir, + char *name, struct node **node) +{ + error_t err; + + if (dir->nn->name) + err = ENOTDIR; + else + err = lookup_host (dir->nn->mux, name, node); + + touch (dir, TOUCH_ATIME); + + mutex_unlock (&dir->lock); + + if (! err) + mutex_lock (&(*node)->lock); + + return err; +} + +/* Implement the netfs_get_directs callback as described in + <hurd/netfs.h>. */ +error_t +netfs_get_dirents (struct iouser *cred, struct node *dir, + int first_entry, int num_entries, char **data, + mach_msg_type_number_t *data_len, + vm_size_t max_data_len, int *data_entries) +{ + error_t err; + int count; + size_t size = 0; /* Total size of our return block. */ + struct hostmux_name *first_name, *nm; + + if (dir->nn->name) + return ENOTDIR; + + rwlock_reader_lock (&dir->nn->mux->names_lock); + + /* Find the first entry. */ + for (first_name = dir->nn->mux->names; + first_name && first_entry > 0; + first_name = first_name->next) + if (first_name->node) + first_entry--; + + /* See how much space we need for the result. */ + for (nm = first_name, count = 0; + nm && (num_entries == -1 || count < num_entries); + nm = nm->next) + if (nm->node) + { + size_t new_size = size + DIRENT_LEN (strlen (nm->name)); + if (new_size > max_data_len) + break; + size = new_size; + count++; + } + + /* Allocate it. */ + err = vm_allocate (mach_task_self (), (vm_address_t *) data, size, 1); + if (! err) + /* Copy out the result. */ + { + char *p = *data; + + *data_len = size; + *data_entries = count; + + /* See how much space we need for the result. */ + for (nm = first_name, count = 0; + nm && (num_entries == -1 || count < num_entries); + nm = nm->next) + if (nm->node) + { + struct dirent hdr; + size_t name_len = strlen (nm->name); + size_t sz = DIRENT_LEN (name_len); + + if (sz > size) + break; + else + size -= sz; + + hdr.d_fileno = nm->fileno; + hdr.d_reclen = sz; + hdr.d_type = + (strcmp (nm->canon, nm->name) == 0 ? DT_REG : DT_LNK); + hdr.d_namlen = name_len; + + memcpy (p, &hdr, DIRENT_NAME_OFFS); + strcpy (p + DIRENT_NAME_OFFS, nm->name); + p += sz; + + count++; + } + + } + + rwlock_reader_unlock (&dir->nn->mux->names_lock); + + touch (dir, TOUCH_ATIME); + + return err; +} + +/* Host lookup. */ + +/* Free storage allocated consumed by the host mux name NM, but not the node + it points to. */ +static void +free_name (struct hostmux_name *nm) +{ + free ((char *)nm->name); + if (nm->name != nm->canon) + free ((char *)nm->canon); + free (nm); +} + +/* See if there's an existing entry for the name HOST, and if so, return its + node in NODE with an additional references. True is returned iff the + lookup succeeds. If PURGE is true, then any nodes with a null node are + removed. */ +static int +lookup_cached (struct hostmux *mux, const char *host, int purge, + struct node **node) +{ + struct hostmux_name *nm = mux->names, **prevl = &mux->names; + + while (nm) + { + struct hostmux_name *next = nm->next; + + if (strcasecmp (host, nm->name) == 0) + { + spin_lock (&netfs_node_refcnt_lock); + if (nm->node) + nm->node->references++; + spin_unlock (&netfs_node_refcnt_lock); + + if (nm->node) + { + *node = nm->node; + return 1; + } + } + + if (purge && !nm->node) + { + *prevl = nm->next; + free_name (nm); + } + else + prevl = &nm->next; + + nm = next; + } + + return 0; +} + +/* See if there's an existing entry for the name HOST, and if so, return its + node in NODE, with an additional reference, otherwise, create a new node + for the host HE as referred to by HOST, and return that instead, with a + single reference. The type of node created is either a translator node, + if HOST refers to the official name of the host, or a symlink node to the + official name, if it doesn't. */ +static error_t +lookup_hostent (struct hostmux *mux, const char *host, struct hostent *he, + struct node **node) +{ + error_t err; + struct hostmux_name *nm = malloc (sizeof (struct hostmux_name)); + + if (! nm) + return ENOMEM; + + nm->name = strdup (host); + if (strcmp (host, he->h_name) == 0) + nm->canon = nm->name; + else + nm->canon = strdup (he->h_name); + + err = create_host_node (mux, nm, node); + if (err) + { + free_name (nm); + return err; + } + + rwlock_writer_lock (&mux->names_lock); + if (lookup_cached (mux, host, 1, node)) + /* An entry for HOST has already been created between the time we last + looked and now (which is possible because we didn't lock MUX). + Just throw away our version and return the one already in the cache. */ + { + rwlock_writer_unlock (&mux->names_lock); + nm->node->nn->name = 0; /* Avoid touching the mux name list. */ + netfs_nrele (nm->node); /* Free the tentative new node. */ + free_name (nm); /* And the name it was under. */ + } + else + /* Enter NM into MUX's list of names, and return the new node. */ + { + nm->fileno = mux->next_fileno++; /* Now that we hold the lock... */ + nm->next = mux->names; + mux->names = nm; + rwlock_writer_unlock (&mux->names_lock); + } + + return 0; +} + +/* Lookup the host HOST in MUX, and return the resulting node in NODE, with + an additional reference, or an error. */ +static error_t +lookup_host (struct hostmux *mux, const char *host, struct node **node) +{ + int was_cached; + int h_err; + struct hostent _he, *he; + struct in_addr inet_addr; + char hostent_data[2048]; /* XXX what size should this be???? */ + + rwlock_reader_lock (&mux->names_lock); + was_cached = lookup_cached (mux, host, 0, node); + rwlock_reader_unlock (&mux->names_lock); + + if (was_cached) + return 0; + else if (inet_aton (host, &inet_addr)) + { + if (gethostbyaddr_r ((char *)&inet_addr, sizeof inet_addr, AF_INET, + &_he, hostent_data, sizeof hostent_data, + &he, &h_err) == 0) + return lookup_hostent (mux, host, he, node); + else + return ENOENT; + } + else if (gethostbyname_r (host, &_he, hostent_data, sizeof hostent_data, + &he, &h_err) == 0) + return lookup_hostent (mux, host, he, node); + else + return ENOENT; +} + +/* This should sync the entire remote filesystem. If WAIT is set, return + only after sync is completely finished. */ +error_t +netfs_attempt_syncfs (struct iouser *cred, int wait) +{ + return 0; +} + +/* This should attempt a chmod call for the user specified by CRED on node + NODE, to change the owner to UID and the group to GID. */ +error_t +netfs_attempt_chown (struct iouser *cred, struct node *node, uid_t uid, uid_t gid) +{ + if (node->nn->name) + return EOPNOTSUPP; + else + { + struct hostmux *mux = node->nn->mux; + error_t err = file_chown (mux->underlying, uid, gid); + + if (! err) + { + struct hostmux_name *nm; + + /* Change NODE's owner. */ + mux->stat_template.st_uid = uid; + mux->stat_template.st_gid = gid; + node->nn_stat.st_uid = uid; + node->nn_stat.st_gid = gid; + + /* Change the owner of each leaf node. */ + rwlock_reader_lock (&mux->names_lock); + for (nm = mux->names; nm; nm = nm->next) + if (nm->node) + { + nm->node->nn_stat.st_uid = uid; + nm->node->nn_stat.st_gid = gid; + } + rwlock_reader_unlock (&mux->names_lock); + + touch (node, TOUCH_CTIME); + } + + return err; + } +} + +/* This should attempt a chauthor call for the user specified by CRED on node + NODE, to change the author to AUTHOR. */ +error_t +netfs_attempt_chauthor (struct iouser *cred, struct node *node, uid_t author) +{ + if (node->nn->name) + return EOPNOTSUPP; + else + { + struct hostmux *mux = node->nn->mux; + error_t err = file_chauthor (mux->underlying, author); + + if (! err) + { + struct hostmux_name *nm; + + /* Change NODE's owner. */ + mux->stat_template.st_author = author; + node->nn_stat.st_author = author; + + /* Change the owner of each leaf node. */ + rwlock_reader_lock (&mux->names_lock); + for (nm = mux->names; nm; nm = nm->next) + if (nm->node) + nm->node->nn_stat.st_author = author; + rwlock_reader_unlock (&mux->names_lock); + + touch (node, TOUCH_CTIME); + } + + return err; + } +} + +/* This should attempt a chmod call for the user specified by CRED on node + NODE, to change the mode to MODE. Unlike the normal Unix and Hurd meaning + of chmod, this function is also used to attempt to change files into other + types. If such a transition is attempted which is impossible, then return + EOPNOTSUPP. */ +error_t +netfs_attempt_chmod (struct iouser *cred, struct node *node, mode_t mode) +{ + mode &= ~S_ITRANS; + if (node->nn->name || ((mode & S_IFMT) != (node->nn_stat.st_mode & S_IFMT))) + return EOPNOTSUPP; + else + { + error_t err = file_chmod (node->nn->mux->underlying, mode & ~S_IFMT); + if (! err) + { + node->nn_stat.st_mode = mode; + touch (node, TOUCH_CTIME); + } + return err; + } +} diff --git a/hostmux/node.c b/hostmux/node.c new file mode 100644 index 00000000..3d808afe --- /dev/null +++ b/hostmux/node.c @@ -0,0 +1,117 @@ +/* General fs node functions + + Copyright (C) 1997 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.ai.mit.edu> + 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 <fcntl.h> + +#include "hostmux.h" + +/* Node maintenance. */ + +/* Node NP is all done; free all its associated storage. */ +void +netfs_node_norefs (struct node *node) +{ + if (node->nn->name) + /* Remove our name's pointer to us; the name itself will eventually be + freed by another party. */ + node->nn->name->node = 0; + free (node->nn); + free (node); +} + +/* Attempt to create a file named NAME in DIR for USER with MODE. Set *NODE + to the new node upon return. On any error, clear *NODE. *NODE should be + locked on success; no matter what, unlock DIR before returning. */ +error_t +netfs_attempt_create_file (struct iouser *user, struct node *dir, + char *name, mode_t mode, struct node **node) +{ + *node = 0; + mutex_unlock (&dir->lock); + return EOPNOTSUPP; +} + +/* Node NODE is being opened by USER, with FLAGS. NEWNODE is nonzero if we + just created this node. Return an error if we should not permit the open + to complete because of a permission restriction. */ +error_t +netfs_check_open_permissions (struct iouser *user, struct node *node, + int flags, int newnode) +{ + error_t err = 0; + if (flags & O_READ) + err = fshelp_access (&node->nn_stat, S_IREAD, user); + if (!err && (flags & O_WRITE)) + err = fshelp_access (&node->nn_stat, S_IWRITE, user); + if (!err && (flags & O_EXEC)) + err = fshelp_access (&node->nn_stat, S_IEXEC, user); + return err; +} + +/* This should attempt a utimes call for the user specified by CRED on node + NODE, to change the atime to ATIME and the mtime to MTIME. */ +error_t +netfs_attempt_utimes (struct iouser *cred, struct node *node, + struct timespec *atime, struct timespec *mtime) +{ + error_t err = fshelp_isowner (&node->nn_stat, cred); + if (! err) + { + node->nn_stat.st_mtime = mtime->tv_sec; + node->nn_stat.st_mtime_usec = mtime->tv_nsec / 1000; + node->nn_stat.st_atime = atime->tv_sec; + node->nn_stat.st_atime_usec = atime->tv_nsec / 1000; + touch (node, TOUCH_CTIME); + } + return err; +} + +/* Return the valid access types (bitwise OR of O_READ, O_WRITE, and O_EXEC) + in *TYPES for file NODE and user CRED. */ +error_t +netfs_report_access (struct iouser *cred, struct node *node, int *types) +{ + *types = 0; + if (fshelp_access (&node->nn_stat, S_IREAD, cred) == 0) + *types |= O_READ; + if (fshelp_access (&node->nn_stat, S_IWRITE, cred) == 0) + *types |= O_WRITE; + if (fshelp_access (&node->nn_stat, S_IEXEC, cred) == 0) + *types |= O_EXEC; + return 0; +} + +/* Trivial definitions. */ + +/* Make sure that NP->nn_stat is filled with current information. CRED + identifies the user responsible for the operation. */ +error_t +netfs_validate_stat (struct node *node, struct iouser *cred) +{ + return 0; +} + +/* This should sync the file NODE completely to disk, for the user CRED. If + WAIT is set, return only after sync is completely finished. */ +error_t +netfs_attempt_sync (struct iouser *cred, struct node *node, int wait) +{ + return 0; +} diff --git a/hostmux/stubs.c b/hostmux/stubs.c new file mode 100644 index 00000000..d9402877 --- /dev/null +++ b/hostmux/stubs.c @@ -0,0 +1,143 @@ +/* Stub routines for hostmux + + Copyright (C) 1997 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.ai.mit.edu> + 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 <hurd/netfs.h> + +/* Attempt to turn NODE (user CRED) into a symlink with target NAME. */ +error_t +netfs_attempt_mksymlink (struct iouser *cred, struct node *node, char *name) +{ + return EOPNOTSUPP; +} + +/* Attempt to turn NODE (user CRED) into a device. TYPE is either S_IFBLK or + S_IFCHR. */ +error_t +netfs_attempt_mkdev (struct iouser *cred, struct node *node, + mode_t type, dev_t indexes) +{ + return EOPNOTSUPP; +} + +/* Attempt to set the passive translator record for FILE to ARGZ (of length + ARGZLEN) for user CRED. */ +error_t +netfs_set_translator (struct iouser *cred, struct node *node, + char *argz, size_t argzlen) +{ + return EOPNOTSUPP; +} + +/* This should attempt a chflags call for the user specified by CRED on node + NODE, to change the flags to FLAGS. */ +error_t +netfs_attempt_chflags (struct iouser *cred, struct node *node, int flags) +{ + return EOPNOTSUPP; +} + +/* This should attempt to set the size of the file NODE (for user CRED) to + SIZE bytes long. */ +error_t +netfs_attempt_set_size (struct iouser *cred, struct node *node, off_t size) +{ + return EOPNOTSUPP; +} + +/* This should attempt to fetch filesystem status information for the remote + filesystem, for the user CRED. */ +error_t +netfs_attempt_statfs (struct iouser *cred, struct node *node, + struct statfs *st) +{ + return EOPNOTSUPP; +} + +/* Delete NAME in DIR for USER. */ +error_t +netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name) +{ + return EOPNOTSUPP; +} + +/* Note that in this one call, neither of the specific nodes are locked. */ +error_t +netfs_attempt_rename (struct iouser *user, struct node *fromdir, + char *fromname, struct node *todir, + char *toname, int excl) +{ + return EOPNOTSUPP; +} + +/* Attempt to create a new directory named NAME in DIR for USER with mode + MODE. */ +error_t +netfs_attempt_mkdir (struct iouser *user, struct node *dir, + char *name, mode_t mode) +{ + return EOPNOTSUPP; +} + +/* Attempt to remove directory named NAME in DIR for USER. */ +error_t +netfs_attempt_rmdir (struct iouser *user, + struct node *dir, char *name) +{ + return EOPNOTSUPP; +} + +/* Create a link in DIR with name NAME to FILE for USER. Note that neither + DIR nor FILE are locked. If EXCL is set, do not delete the target, but + return EEXIST if NAME is already found in DIR. */ +error_t +netfs_attempt_link (struct iouser *user, struct node *dir, + struct node *file, char *name, int excl) +{ + return EOPNOTSUPP; +} + +/* Attempt to create an anonymous file related to DIR for USER with MODE. + Set *NODE to the returned file upon success. No matter what, unlock DIR. */ +error_t +netfs_attempt_mkfile (struct iouser *user, struct node *dir, + mode_t mode, struct node **node) +{ + return EOPNOTSUPP; +} + +/* Read from the file NODE for user CRED starting at OFFSET and continuing for + up to *LEN bytes. Put the data at DATA. Set *LEN to the amount + successfully read upon return. */ +error_t +netfs_attempt_read (struct iouser *cred, struct node *node, + off_t offset, size_t *len, void *data) +{ + return EOPNOTSUPP; +} + +/* Write to the file NODE for user CRED starting at OFSET and continuing for up + to *LEN bytes from DATA. Set *LEN to the amount seccessfully written upon + return. */ +error_t +netfs_attempt_write (struct iouser *cred, struct node *node, + off_t offset, size_t *len, void *data) +{ + return EOPNOTSUPP; +} |