diff options
Diffstat (limited to 'libstore/file.c')
-rw-r--r-- | libstore/file.c | 284 |
1 files changed, 207 insertions, 77 deletions
diff --git a/libstore/file.c b/libstore/file.c index 44cb7b9d..49f1c3fb 100644 --- a/libstore/file.c +++ b/libstore/file.c @@ -1,9 +1,7 @@ -/* Mach file store backend - - Copyright (C) 1995, 1996 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> +/* File store backend + Copyright (C) 1995,96,97,98,2001, 2002 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.org> This file is part of the GNU Hurd. The GNU Hurd is free software; you can redistribute it and/or @@ -18,7 +16,7 @@ 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. */ + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include <stdio.h> #include <string.h> @@ -29,94 +27,225 @@ #include "store.h" +/* Return 0 if STORE's range is enforced by the filesystem, otherwise an + error. */ +static error_t +enforced (struct store *store) +{ + if (store->num_runs != 1 || store->runs[0].start != 0) + /* Can't enforce non-contiguous ranges, or one not starting at 0. */ + return EINVAL; + else + { + /* See if the the current (one) range is that the kernel is enforcing. */ + struct stat st; + error_t err = io_stat (store->port, &st); + + if (!err + && store->runs[0].length != (st.st_size >> store->log2_block_size)) + /* The single run is not the whole file. */ + err = EINVAL; + + return err; + } +} + static error_t file_read (struct store *store, - off_t addr, size_t index, mach_msg_type_number_t amount, - char **buf, mach_msg_type_number_t *len) + store_offset_t addr, size_t index, size_t amount, void **buf, + size_t *len) { size_t bsize = store->block_size; - error_t err = io_read (store->port, buf, len, addr * bsize, amount); - char rep_buf[20]; - if (err) - strcpy (rep_buf, "-"); - else if (*len > sizeof rep_buf - 3) - sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), *buf); - else - sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), *buf); - fprintf (stderr, "; file_read (%ld, %d, %d) [%d] => %s, %s, %d\n", - addr, index, amount, store->block_size, err ? strerror (err) : "-", - rep_buf, err ? 0 : *len); - return err; + return io_read (store->port, (char **)buf, len, addr * bsize, amount); } static error_t file_write (struct store *store, - off_t addr, size_t index, char *buf, mach_msg_type_number_t len, - mach_msg_type_number_t *amount) + store_offset_t addr, size_t index, const void *buf, size_t len, + size_t *amount) { size_t bsize = store->block_size; - char rep_buf[20]; - if (len > sizeof rep_buf - 3) - sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), buf); - else - sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), buf); - fprintf (stderr, "; file_write (%ld, %d, %s, %d)\n", - addr, index, rep_buf, len); return io_write (store->port, buf, len, addr * bsize, amount); } static error_t -file_decode (struct store_enc *enc, struct store_class *classes, +file_store_set_size (struct store *store, size_t newsize) +{ + error_t err; + + if (enforced (store) != 0) + /* Bail out if there is more than a single run. */ + return EOPNOTSUPP; + + err = file_set_size (store->port, newsize); + + if (!err) + { + /* Update STORE's size and run. */ + store->size = newsize; + store->runs[0].length = newsize >> store->log2_block_size; + } + + return err; +} + +static error_t +file_decode (struct store_enc *enc, const struct store_class *const *classes, struct store **store) { return store_std_leaf_decode (enc, _store_file_create, store); } -static struct store_class -file_class = +static error_t +file_open (const char *name, int flags, + const struct store_class *const *classes, + struct store **store) { - STORAGE_HURD_FILE, "file", file_read, file_write, - store_std_leaf_allocate_encoding, store_std_leaf_encode, file_decode -}; -_STORE_STD_CLASS (file_class); + return store_file_open (name, flags, store); +} static error_t -file_byte_read (struct store *store, - off_t addr, size_t index, mach_msg_type_number_t amount, - char **buf, mach_msg_type_number_t *len) +fiopen (const char *name, file_t *file, int *mod_flags) +{ + if (*mod_flags & STORE_HARD_READONLY) + *file = file_name_lookup (name, O_RDONLY, 0); + else + { + *file = file_name_lookup (name, O_RDWR, 0); + if (*file == MACH_PORT_NULL + && (errno == EACCES || errno == EROFS)) + { + *file = file_name_lookup (name, O_RDONLY, 0); + if (*file != MACH_PORT_NULL) + *mod_flags |= STORE_HARD_READONLY; + } + else if (*file != MACH_PORT_NULL) + *mod_flags &= ~STORE_HARD_READONLY; + } + return *file == MACH_PORT_NULL ? errno : 0; +} + +static void +ficlose (struct store *store) +{ + mach_port_deallocate (mach_task_self (), store->port); + store->port = MACH_PORT_NULL; +} + + + +static error_t +file_set_flags (struct store *store, int flags) { - error_t err = io_read (store->port, buf, len, addr, amount); - char rep_buf[20]; + if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0) + /* Trying to set flags we don't support. */ + return EINVAL; + + if (! ((store->flags | flags) & STORE_INACTIVE)) + /* Currently active and staying that way, so we must be trying to set the + STORE_ENFORCED flag. */ + { + error_t err = enforced (store); + if (err) + return err; + } + + if (flags & STORE_INACTIVE) + ficlose (store); + + store->flags |= flags; /* When inactive, anything goes. */ + + return 0; +} + +static error_t +file_clear_flags (struct store *store, int flags) +{ + error_t err = 0; + if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0) + err = EINVAL; + if (!err && (flags & STORE_INACTIVE)) + err = store->name + ? fiopen (store->name, &store->port, &store->flags) + : ENOENT; + if (! err) + store->flags &= ~flags; + return err; +} + +static error_t +file_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj) +{ + error_t err; + mach_port_t rd_memobj, wr_memobj; + int ro = (store->flags & STORE_HARD_READONLY); + + if (store->num_runs != 1 || store->runs[0].start != 0) + return EOPNOTSUPP; + + if ((prot & VM_PROT_WRITE) && ro) + return EACCES; + + err = io_map (store->port, &rd_memobj, &wr_memobj); if (err) - strcpy (rep_buf, "-"); - else if (*len > sizeof rep_buf - 3) - sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), *buf); + return err; + + *memobj = rd_memobj; + + if (ro && wr_memobj == MACH_PORT_NULL) + return 0; + else if (rd_memobj == wr_memobj) + { + if (rd_memobj != MACH_PORT_NULL) + mach_port_mod_refs (mach_task_self (), rd_memobj, + MACH_PORT_RIGHT_SEND, -1); + } else - sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), *buf); - fprintf (stderr, "; file_byte_read (%ld, %d, %d) => %s, %s, %d\n", - addr, index, amount, err ? strerror (err) : "-", - rep_buf, err ? 0 : *len); + { + if (rd_memobj != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), rd_memobj); + if (wr_memobj != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), wr_memobj); + err = EOPNOTSUPP; + } + return err; } +const struct store_class +store_file_class = +{ + STORAGE_HURD_FILE, "file", file_read, file_write, file_store_set_size, + store_std_leaf_allocate_encoding, store_std_leaf_encode, file_decode, + file_set_flags, file_clear_flags, 0, 0, 0, file_open, 0, file_map +}; +STORE_STD_CLASS (file); + +static error_t +file_byte_read (struct store *store, + store_offset_t addr, size_t index, size_t amount, + void **buf, size_t *len) +{ + return io_read (store->port, (char **)buf, len, addr, amount); +} + static error_t file_byte_write (struct store *store, - off_t addr, size_t index, - char *buf, mach_msg_type_number_t len, - mach_msg_type_number_t *amount) + store_offset_t addr, size_t index, + const void *buf, size_t len, + size_t *amount) { - char rep_buf[20]; - if (len > sizeof rep_buf - 3) - sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), buf); - else - sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), buf); - fprintf (stderr, "; file_byte_write (%ld, %d, %s, %d)\n", - addr, index, rep_buf, len); return io_write (store->port, buf, len, addr, amount); } -static struct store_class -file_byte_class = {STORAGE_HURD_FILE, "file", file_byte_read, file_byte_write}; +struct store_class +store_file_byte_class = +{ + STORAGE_HURD_FILE, "file", file_byte_read, file_byte_write, + file_store_set_size, + store_std_leaf_allocate_encoding, store_std_leaf_encode, file_decode, + file_set_flags, file_clear_flags, 0, 0, 0, file_open, 0, file_map +}; /* Return a new store in STORE referring to the mach file FILE. Consumes the send right FILE. */ @@ -145,29 +274,30 @@ _store_file_create (file_t file, int flags, size_t block_size, struct store **store) { if (block_size == 1) - *store = _make_store (&file_byte_class, file, flags, 1, runs, num_runs, 0); - else if ((block_size & (block_size - 1)) == 0) - *store = - _make_store (&file_class, file, flags, block_size, runs, num_runs, 0); + return _store_create (&store_file_byte_class, + file, flags, 1, runs, num_runs, 0, store); else - return EINVAL; /* block size not a power of two */ - return *store ? 0 : ENOMEM; + return _store_create (&store_file_class, + file, flags, block_size, runs, num_runs, 0, store); } /* Open the file NAME, and return the corresponding store in STORE. */ error_t store_file_open (const char *name, int flags, struct store **store) { - error_t err; - int open_flags = (flags & STORE_HARD_READONLY) ? O_RDONLY : O_RDWR; - file_t node = file_name_lookup (name, open_flags, 0); - - if (node == MACH_PORT_NULL) - return errno; - - err = store_file_create (node, flags, store); - if (err) - mach_port_deallocate (mach_task_self (), node); - + file_t file; + error_t err = fiopen (name, &file, &flags); + if (! err) + { + err = store_file_create (file, flags, store); + if (! err) + { + err = store_set_name (*store, name); + if (err) + store_free (*store); + } + if (err) + mach_port_deallocate (mach_task_self (), file); + } return err; } |