diff options
author | Miles Bader <miles@gnu.org> | 1997-02-21 21:55:41 +0000 |
---|---|---|
committer | Miles Bader <miles@gnu.org> | 1997-02-21 21:55:41 +0000 |
commit | a6d04a211c6f48bc23aea892c8b9544a22401714 (patch) | |
tree | b671d487e4359ba8eacbe6f625bc0f27fa2e67d2 /trans | |
parent | 37e138a0b010037798144653c56c7e151bd40554 (diff) |
Initial checkin.
Diffstat (limited to 'trans')
-rw-r--r-- | trans/firmlink.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/trans/firmlink.c b/trans/firmlink.c new file mode 100644 index 00000000..effae3d4 --- /dev/null +++ b/trans/firmlink.c @@ -0,0 +1,271 @@ +/* A translator for `firmlinks' + + Copyright (C) 1997 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + 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 <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include <argp.h> +#include <error.h> + +#include <hurd/trivfs.h> + +#include <version.h> + +const char *argp_program_version = STANDARD_HURD_VERSION (firmlink); + +static const struct argp_option options[] = +{ + { "invisible", 'i', 0, 0, "Don't resemble a symlink" }, + { 0 } +}; + +static const char args_doc[] = "TARGET"; +static const char doc[] = "A translator for firmlinks" +"\vA firmlink is sort of half-way between a symbolic link and a hard link;" +"\n" +"\nLike a symbolic link, it is `by name', and contains no actual reference to" +" the target. However, the lookup returns a node which will redirect parent" +" lookups so that attempts to find the cwd that go through the link will" +" reflect the link name, not the target name. The target referenced by the" +" firmlink is looked up in the namespace of the translator, not the client."; + +/* Link parameters. */ +static char *target = 0; /* What we translate too. */ +static int invisible = 0; /* Return a link node to O_NOLINK opens? */ + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + if (key == 'i') + invisible = 1; + else if (key == ARGP_KEY_ARG && state->arg_num == 0) + target = arg; + else if (key == ARGP_KEY_ARG || key == ARGP_KEY_NO_ARGS) + argp_usage (state); + else + return ARGP_ERR_UNKNOWN; + return 0; +} + +static struct argp argp = { 0, parse_opt, args_doc, doc }; + +void +main (int argc, char **argv) +{ + error_t err; + mach_port_t bootstrap; + struct trivfs_control *fsys; + + /* Parse our options... */ + argp_parse (&argp, argc, argv, 0, 0, 0); + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + if (bootstrap == MACH_PORT_NULL) + error (1, 0, "Must be started as a translator"); + + /* Reply to our parent */ + err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys); + if (err) + error (2, err, "Contacting parent"); + + /* Launch. */ + ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer, 0); + + exit (0); +} + +static error_t +firmlink (mach_port_t parent, const char *target_name, int flags, + mach_port_t *link) +{ + error_t err; + file_t authed_link; + file_t target = file_name_lookup (target_name, flags & ~O_CREAT, 0); + + if (target == MACH_PORT_NULL) + return errno; + + err = file_reparent (target, parent, &authed_link); + mach_port_deallocate (mach_task_self (), target); + mach_port_deallocate (mach_task_self (), parent); + + if (! err) + { + err = io_restrict_auth (authed_link, link, 0, 0, 0, 0); + mach_port_deallocate (mach_task_self (), authed_link); + } + + return err; +} + +/* Trivfs hooks */ + +int trivfs_fstype = FSTYPE_MISC; +int trivfs_fsid = 0; + +int trivfs_support_read = 1; +int trivfs_support_write = 0; +int trivfs_support_exec = 0; + +int trivfs_allow_open = O_READ; + +static error_t +getroot (struct trivfs_control *cntl, + mach_port_t reply_port, mach_msg_type_name_t reply_port_type, + mach_port_t dotdot, + uid_t *uids, u_int nuids, uid_t *gids, u_int ngids, + int flags, + retry_type *do_retry, char *retry_name, + mach_port_t *node, mach_msg_type_name_t *node_type) +{ + error_t err; + + if ((flags & O_NOLINK) && !invisible) + /* Cons up our own node. */ + return EAGAIN; + + err = firmlink (dotdot, target, flags, node); + if (!err) + { + *node_type = MACH_MSG_TYPE_MOVE_SEND; + *do_retry = FS_RETRY_REAUTH; + retry_name[0] = '\0'; + } + + return err; +} + +/* 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) () = getroot; + +void +trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) +{ + st->st_size = strlen (target); + st->st_blocks = 0; + st->st_mode &= ~S_IFMT; + st->st_mode |= S_IFLNK; +} + +error_t +trivfs_goaway (struct trivfs_control *cntl, int flags) +{ + error_t err; + int force = (flags & FSYS_GOAWAY_FORCE); + struct port_bucket *bucket = ((struct port_info *)cntl)->bucket; + + err = ports_inhibit_bucket_rpcs (bucket); + if (err == EINTR || (err && !force)) + return err; + + if (ports_count_class (cntl->protid_class) > 0 && !force) + /* Still some opens, and we're not being forced to go away, so don't. */ + { + ports_enable_class (cntl->protid_class); + ports_resume_bucket_rpcs (bucket); + return EBUSY; + } + + exit (0); +} + +/* We store the file offset in po->hook (ick!) */ + +/* 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 AMT. */ +error_t +trivfs_S_io_read (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + vm_address_t *data, mach_msg_type_number_t *data_len, + off_t offs, mach_msg_type_number_t amount) +{ + error_t err = 0; + + if (! cred) + err = EOPNOTSUPP; + else if (! (cred->po->openmodes & O_READ)) + err = EBADF; + else + { + off_t max = strlen (target); + off_t start = offs >= 0 ? offs : (off_t)cred->po->hook; + if (start < 0) + return EINVAL; + if (start + amount > max) + amount = max - start; + if (amount > *data_len) + err = vm_allocate (mach_task_self (), data, amount, 1); + if (!err && amount > 0) + { + memcpy ((char *)(*data + start), target, amount); + if (offs < 0) + cred->po->hook = (void *)(start + amount); /* Update PO offset. */ + } + *data_len = amount; + } + + return err; +} + +/* 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. */ +error_t +trivfs_S_io_readable (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + mach_msg_type_number_t *amount) +{ + if (! cred) + return EOPNOTSUPP; + else if (! (cred->po->openmodes & O_READ)) + return EBADF; + else if ((off_t)cred->po->hook < 0) + return EINVAL; + else + *amount = strlen (target) - (off_t)cred->po->hook; + return 0; +} + +/* Change current read/write offset */ +error_t +trivfs_S_io_seek (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + off_t offset, int whence, off_t *new_offset) +{ + return EOPNOTSUPP; +} + +/* 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. ID_TAG is returned as passed; it + is just for the convenience of the user in matching up reply messages with + specific requests sent. */ +error_t +trivfs_S_io_select (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + int *type, int *tag) +{ + return EOPNOTSUPP; +} |