diff options
Diffstat (limited to 'ufs/inode.c')
-rw-r--r-- | ufs/inode.c | 335 |
1 files changed, 156 insertions, 179 deletions
diff --git a/ufs/inode.c b/ufs/inode.c index 640e6b6f..77a45edb 100644 --- a/ufs/inode.c +++ b/ufs/inode.c @@ -1,5 +1,7 @@ /* Inode management routines - Copyright (C) 1994, 1995, 1996 Free Software Foundation + + Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2007 + 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 @@ -20,6 +22,8 @@ #include <unistd.h> #include <stdio.h> #include <netinet/in.h> +#include <fcntl.h> +#include <hurd/store.h> #define INOHSZ 512 #if ((INOHSZ&(INOHSZ-1)) == 0) @@ -42,10 +46,10 @@ inode_init () nodehash[n] = 0; } -/* Fetch inode INUM, set *NPP to the node structure; +/* Fetch inode INUM, set *NPP to the node structure; gain one user reference and lock the node. */ -error_t -diskfs_cached_lookup (int inum, struct node **npp) +error_t +diskfs_cached_lookup (ino_t inum, struct node **npp) { struct disknode *dn; struct node *np; @@ -68,6 +72,7 @@ diskfs_cached_lookup (int inum, struct node **npp) dn->number = inum; dn->dirents = 0; + dn->dir_idx = 0; rwlock_init (&dn->allocptrlock); dn->dirty = 0; @@ -85,7 +90,7 @@ diskfs_cached_lookup (int inum, struct node **npp) spin_unlock (&diskfs_node_refcnt_lock); err = read_disknode (np); - + if (!diskfs_check_readonly () && !np->dn_stat.st_gen) { spin_lock (&gennumberlock); @@ -95,7 +100,7 @@ diskfs_cached_lookup (int inum, struct node **npp) spin_unlock (&gennumberlock); np->dn_set_ctime = 1; } - + if (err) return err; else @@ -111,13 +116,13 @@ struct node * ifind (ino_t inum) { struct node *np; - + spin_lock (&diskfs_node_refcnt_lock); for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) { if (np->dn->number != inum) continue; - + assert (np->references); spin_unlock (&diskfs_node_refcnt_lock); return np; @@ -127,7 +132,7 @@ ifind (ino_t inum) /* The last reference to a node has gone away; drop it from the hash table and clean all state in the dn structure. */ -void +void diskfs_node_norefs (struct node *np) { *np->dn->hprevp = np->dn->hnext; @@ -155,7 +160,7 @@ diskfs_lost_hardrefs (struct node *np) #ifdef notanymore struct port_info *pi; struct pager *p; - + /* Check and see if there is a pager which has only one reference (ours). If so, then drop that reference, breaking the cycle. The complexity in this routine @@ -167,17 +172,17 @@ diskfs_lost_hardrefs (struct node *np) pi = (struct port_info *) np->dn->fileinfo->p; if (pi->refcnt == 1) { - + /* The only way to get a new reference to the pager in this state is to call diskfs_get_filemap; this can't happen as long as we hold NP locked. So we can safely unlock _libports_portrefcntlock for the following call. */ spin_unlock (&_libports_portrefcntlock); - + /* Right now the node is locked with no hard refs; - this is an anomolous situation. Before messing with - the reference count on the file pager, we have to + this is an anomalous situation. Before messing with + the reference count on the file pager, we have to give ourselves a reference back so that we are really allowed to hold the lock. Then we can do the unreference. */ @@ -209,53 +214,41 @@ diskfs_new_hardrefs (struct node *np) static error_t read_disknode (struct node *np) { - static int fsid, fsidset; struct stat *st = &np->dn_stat; struct dinode *di = dino (np->dn->number); error_t err; - + err = diskfs_catch_exception (); if (err) return err; - np->istranslated = !! di->di_trans; - - if (!fsidset) - { - fsid = getpid (); - fsidset = 1; - } - st->st_fstype = FSTYPE_UFS; - st->st_fsid = fsid; + st->st_fsid = getpid (); /* This call is very cheap. */ st->st_ino = np->dn->number; st->st_gen = read_disk_entry (di->di_gen); st->st_rdev = read_disk_entry(di->di_rdev); - st->st_mode = (read_disk_entry (di->di_model) - | (read_disk_entry (di->di_modeh) << 16)); + st->st_mode = (((read_disk_entry (di->di_model) + | (read_disk_entry (di->di_modeh) << 16)) + & ~S_ITRANS) + | (di->di_trans ? S_IPTRANS : 0)); st->st_nlink = read_disk_entry (di->di_nlink); st->st_size = read_disk_entry (di->di_size); -#ifdef notyet - st->st_atimespec = di->di_atime; - st->st_mtimespec = di->di_mtime; - st->st_ctimespec = di->di_ctime; -#else - st->st_atime = read_disk_entry (di->di_atime.tv_sec); - st->st_atime_usec = read_disk_entry (di->di_atime.tv_nsec) / 1000; - st->st_mtime = read_disk_entry (di->di_mtime.tv_sec); - st->st_mtime_usec = read_disk_entry (di->di_mtime.tv_nsec) / 1000; - st->st_ctime = read_disk_entry (di->di_ctime.tv_sec); - st->st_ctime_usec = read_disk_entry (di->di_ctime.tv_nsec) / 1000; -#endif + st->st_atim.tv_sec = read_disk_entry (di->di_atime.tv_sec); + st->st_atim.tv_nsec = read_disk_entry (di->di_atime.tv_nsec); + st->st_mtim.tv_sec = read_disk_entry (di->di_mtime.tv_sec); + st->st_mtim.tv_nsec = read_disk_entry (di->di_mtime.tv_nsec); + st->st_ctim.tv_sec = read_disk_entry (di->di_ctime.tv_sec); + st->st_ctim.tv_nsec = read_disk_entry (di->di_ctime.tv_nsec); st->st_blksize = sblock->fs_bsize; st->st_blocks = read_disk_entry (di->di_blocks); st->st_flags = read_disk_entry (di->di_flags); - + if (sblock->fs_inodefmt < FS_44INODEFMT) { st->st_uid = read_disk_entry (di->di_ouid); st->st_gid = read_disk_entry (di->di_ogid); - st->st_author = 0; + st->st_author = st->st_uid; + np->author_tracks_uid = 1; } else { @@ -270,8 +263,8 @@ read_disknode (struct node *np) if (!S_ISBLK (st->st_mode) && !S_ISCHR (st->st_mode)) st->st_rdev = 0; - if (S_ISLNK (st->st_mode) - && direct_symlink_extension + if (S_ISLNK (st->st_mode) + && direct_symlink_extension && st->st_size < sblock->fs_maxsymlinklen) np->allocsize = 0; else @@ -297,14 +290,25 @@ error_t diskfs_node_reload (struct node *node) return 0; } +/* Return 0 if NP's author can be changed to AUTHOR; otherwise return an + error code. */ +error_t +diskfs_validate_author_change (struct node *np, uid_t author) +{ + if (compat_mode == COMPAT_GNU) + return 0; + else + /* For non-hurd filesystems, the author & owner are the same. */ + return (author == np->dn_stat.st_uid) ? 0 : EINVAL; +} + static void write_node (struct node *np) { struct stat *st = &np->dn_stat; struct dinode *di = dino (np->dn->number); error_t err; - - assert (!np->dn_set_ctime && !np->dn_set_atime && !np->dn_set_mtime); + if (np->dn_stat_dirty) { assert (!diskfs_readonly); @@ -312,9 +316,9 @@ write_node (struct node *np) err = diskfs_catch_exception (); if (err) return; - + write_disk_entry (di->di_gen, st->st_gen); - + if (S_ISBLK (st->st_mode) || S_ISCHR (st->st_mode)) write_disk_entry (di->di_rdev, st->st_rdev); @@ -323,12 +327,13 @@ write_node (struct node *np) if (compat_mode == COMPAT_GNU) { - write_disk_entry (di->di_model, st->st_mode & 0xffff); - write_disk_entry (di->di_modeh, (st->st_mode >> 16) & 0xffff); + mode_t mode = st->st_mode & ~S_ITRANS; + write_disk_entry (di->di_model, mode & 0xffff); + write_disk_entry (di->di_modeh, (mode >> 16) & 0xffff); } - else + else { - write_disk_entry (di->di_model, st->st_mode & 0xffff); + write_disk_entry (di->di_model, st->st_mode & 0xffff & ~S_ITRANS); di->di_modeh = 0; } @@ -337,7 +342,7 @@ write_node (struct node *np) write_disk_entry (di->di_uid, st->st_uid); write_disk_entry (di->di_gid, st->st_gid); } - + if (sblock->fs_inodefmt < FS_44INODEFMT) { write_disk_entry (di->di_ouid, st->st_uid & 0xffff); @@ -348,49 +353,43 @@ write_node (struct node *np) write_disk_entry (di->di_nlink, st->st_nlink); write_disk_entry (di->di_size, st->st_size); -#ifdef notyet - di->di_atime = st->st_atimespec; - di->di_mtime = st->st_mtimespec; - di->di_ctime = st->st_ctimespec; -#else - write_disk_entry (di->di_atime.tv_sec, st->st_atime); - write_disk_entry (di->di_atime.tv_nsec, st->st_atime_usec * 1000); - write_disk_entry (di->di_mtime.tv_sec, st->st_mtime); - write_disk_entry (di->di_mtime.tv_nsec, st->st_mtime_usec * 1000); - write_disk_entry (di->di_ctime.tv_sec, st->st_ctime); - write_disk_entry (di->di_ctime.tv_nsec, st->st_ctime_usec * 1000); -#endif + write_disk_entry (di->di_atime.tv_sec, st->st_atim.tv_sec); + write_disk_entry (di->di_atime.tv_nsec, st->st_atim.tv_nsec); + write_disk_entry (di->di_mtime.tv_sec, st->st_mtim.tv_sec); + write_disk_entry (di->di_mtime.tv_nsec, st->st_mtim.tv_nsec); + write_disk_entry (di->di_ctime.tv_sec, st->st_ctim.tv_sec); + write_disk_entry (di->di_ctime.tv_nsec, st->st_ctim.tv_nsec); write_disk_entry (di->di_blocks, st->st_blocks); write_disk_entry (di->di_flags, st->st_flags); - + diskfs_end_catch_exception (); np->dn_stat_dirty = 0; record_poke (di, sizeof (struct dinode)); } -} +} /* See if we should create a symlink by writing it directly into the block pointer array. Returning EINVAL tells diskfs to do it the usual way. */ static error_t -create_symlink_hook (struct node *np, char *target) +create_symlink_hook (struct node *np, const char *target) { int len = strlen (target); error_t err; struct dinode *di; - + if (!direct_symlink_extension) return EINVAL; - + assert (compat_mode != COMPAT_BSD42); if (len >= sblock->fs_maxsymlinklen) return EINVAL; - + err = diskfs_catch_exception (); if (err) return err; - + di = dino (np->dn->number); bcopy (target, di->di_shortlink, len); np->dn_stat.st_size = len; @@ -401,29 +400,28 @@ create_symlink_hook (struct node *np, char *target) diskfs_end_catch_exception (); return 0; } -error_t (*diskfs_create_symlink_hook)(struct node *, char *) +error_t (*diskfs_create_symlink_hook)(struct node *, const char *) = create_symlink_hook; /* Check if this symlink is stored directly in the block pointer array. Returning EINVAL tells diskfs to do it the usual way. */ -static error_t +static error_t read_symlink_hook (struct node *np, char *buf) { error_t err; - - if (!direct_symlink_extension + + if (!direct_symlink_extension || np->dn_stat.st_size >= sblock->fs_maxsymlinklen) return EINVAL; err = diskfs_catch_exception (); if (err) return err; - + bcopy ((dino (np->dn->number))->di_shortlink, buf, np->dn_stat.st_size); - if (! diskfs_check_readonly ()) - np->dn_set_atime = 1; + diskfs_set_node_atime (np); diskfs_end_catch_exception (); return 0; @@ -439,7 +437,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) struct item *i; error_t err; int n; - + /* Acquire a reference on all the nodes in the hash table and enter them into a list on the stack. */ spin_lock (&diskfs_node_refcnt_lock); @@ -479,10 +477,10 @@ write_all_disknodes () write_node (np); return 0; } - + diskfs_node_iterate (helper); } - + void diskfs_write_disknode (struct node *np, int wait) { @@ -497,23 +495,27 @@ error_t diskfs_set_statfs (struct statfs *st) { st->f_type = FSTYPE_UFS; - st->f_bsize = sblock->fs_bsize; - st->f_blocks = sblock->fs_dsize * sblock->fs_frag; + st->f_bsize = sblock->fs_fsize; + st->f_blocks = sblock->fs_dsize; st->f_bfree = (sblock->fs_cstotal.cs_nbfree * sblock->fs_frag + sblock->fs_cstotal.cs_nffree); st->f_bavail = ((sblock->fs_dsize * (100 - sblock->fs_minfree) / 100) - (sblock->fs_dsize - st->f_bfree)); + if (st->f_bfree < ((sblock->fs_dsize * (100 - sblock->fs_minfree) / 100))) + st->f_bavail = 0; st->f_files = sblock->fs_ncg * sblock->fs_ipg - 2; /* not 0 or 1 */ st->f_ffree = sblock->fs_cstotal.cs_nifree; st->f_fsid = getpid (); st->f_namelen = 0; + st->f_favail = st->f_ffree; + st->f_frsize = sblock->fs_fsize; return 0; } /* Implement the diskfs_set_translator callback from the diskfs library; see <hurd/diskfs.h> for the interface description. */ error_t -diskfs_set_translator (struct node *np, char *name, u_int namelen, +diskfs_set_translator (struct node *np, const char *name, u_int namelen, struct protid *cred) { daddr_t blkno; @@ -530,10 +532,10 @@ diskfs_set_translator (struct node *np, char *name, u_int namelen, err = diskfs_catch_exception (); if (err) return err; - + di = dino (np->dn->number); blkno = read_disk_entry (di->di_trans); - + if (namelen && !blkno) { /* Allocate block for translator */ @@ -554,10 +556,10 @@ diskfs_set_translator (struct node *np, char *name, u_int namelen, di->di_trans = 0; record_poke (di, sizeof (struct dinode)); np->dn_stat.st_blocks -= btodb (sblock->fs_bsize); - np->istranslated = 0; + np->dn_stat.st_mode &= ~S_IPTRANS; np->dn_set_ctime = 1; } - + if (namelen) { bcopy (&namelen, buf, sizeof (u_int)); @@ -566,10 +568,10 @@ diskfs_set_translator (struct node *np, char *name, u_int namelen, bcopy (buf, disk_image + fsaddr (sblock, blkno), sblock->fs_bsize); sync_disk_blocks (blkno, sblock->fs_bsize, 1); - np->istranslated = 1; + np->dn_stat.st_mode |= S_IPTRANS; np->dn_set_ctime = 1; } - + diskfs_end_catch_exception (); return err; } @@ -582,7 +584,7 @@ diskfs_get_translator (struct node *np, char **namep, u_int *namelen) error_t err; daddr_t blkno; u_int datalen; - void *transloc; + const void *transloc; err = diskfs_catch_exception (); if (err) @@ -591,10 +593,17 @@ diskfs_get_translator (struct node *np, char **namep, u_int *namelen) blkno = read_disk_entry ((dino (np->dn->number))->di_trans); assert (blkno); transloc = disk_image + fsaddr (sblock, blkno); - + datalen = *(u_int *)transloc; - *namep = malloc (datalen); - bcopy (transloc + sizeof (u_int), *namep, datalen); + if (datalen > sblock->fs_bsize - sizeof (u_int)) + err = EFTYPE; + else + { + *namep = malloc (datalen); + if (*namep == NULL) + err = ENOMEM; + memcpy (*namep, transloc + sizeof (u_int), datalen); + } diskfs_end_catch_exception (); @@ -619,108 +628,76 @@ diskfs_shutdown_soft_ports () offset into inode block holding inode (4 bytes) */ error_t diskfs_S_file_get_storage_info (struct protid *cred, - int *class, - off_t **addresses, - u_int *naddresses, - size_t *block_size, - char *storage_name, - mach_port_t *storage_port, - mach_msg_type_name_t *storage_port_type, - char **storage_data, - u_int *storage_data_len, - int *flags) + 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) { error_t err; struct node *np; - int i; - struct dinode *di; - void *cp; - + struct store *file_store; + struct store_run runs[NDADDR]; + size_t num_runs = 0; + + if (! cred) + return EOPNOTSUPP; + np = cred->po->np; mutex_lock (&np->lock); - + /* See if this file fits in the direct block pointers. If not, punt for now. (Reading indir blocks is a pain, and I'm postponing pain.) XXX */ - if (np->allocsize > NDADDR * sblock->fs_bsize) { mutex_unlock (&np->lock); return EINVAL; } - - if (*naddresses < NDADDR * 2) - vm_allocate (mach_task_self (), (vm_address_t *) addresses, - sizeof (int) * NDADDR * 2, 1); - else - bzero (addresses, *naddresses * 2 * sizeof (int)); - *naddresses = NDADDR * 2; - - if (*storage_data_len < 4 * sizeof (int)) - vm_allocate (mach_task_self (), (vm_address_t *) storage_data, - sizeof (int) * 4, 1); - *storage_data_len = 4 * sizeof (int); - di = dino (np->dn->number); - err = diskfs_catch_exception (); - if (err) - { - mutex_unlock (&np->lock); - return err; - } - - /* Copy the block pointers */ + if (! err) + if (!direct_symlink_extension + || np->dn_stat.st_size >= sblock->fs_maxsymlinklen + || !S_ISLNK (np->dn_stat.st_mode)) + /* Copy the block pointers */ + { + int i; + struct store_run *run = runs; + struct dinode *di = dino (np->dn->number); + + for (i = 0; i < NDADDR; i++) + { + store_offset_t start = fsbtodb (sblock, read_disk_entry (di->di_db[i])); + store_offset_t length = + (((i + 1) * sblock->fs_bsize > np->allocsize) + ? np->allocsize - i * sblock->fs_bsize + : sblock->fs_bsize); + start <<= log2_dev_blocks_per_dev_bsize; + length <<= log2_dev_blocks_per_dev_bsize; + if (num_runs == 0 || run->start + run->length != start) + *run++ = (struct store_run){ start, length }; + else + run->length += length; + } + } + diskfs_end_catch_exception (); - if (!direct_symlink_extension - || np->dn_stat.st_size >= sblock->fs_maxsymlinklen - || !S_ISLNK (np->dn_stat.st_mode)) + mutex_unlock (&np->lock); + + if (! err) + err = store_clone (store, &file_store); + if (! err) { - for (i = 0; i < NDADDR; i++) - { - (*addresses)[2 * i] = fsbtodb (sblock, - read_disk_entry (di->di_db[i])); - if ((i + 1) * sblock->fs_bsize > np->allocsize) - (*addresses)[2 * i + 1] = np->allocsize - i * sblock->fs_bsize; - else - (*addresses)[2 * i + 1] = sblock->fs_bsize; - } + err = store_remap (file_store, runs, num_runs, &file_store); + if (! err) + err = store_return (file_store, ports, num_ports, ints, num_ints, + offsets, num_offsets, data, data_len); + store_free (file_store); } + *ports_type = MACH_MSG_TYPE_COPY_SEND; - /* Fill in the aux data */ - cp = *storage_data; - - *(int *)cp = htonl (np->dn->number); - cp += sizeof (int); - - *(int *)cp = htonl (di->di_trans); - cp += sizeof (int); - - *(int *)cp = htonl (fsbtodb (sblock, ino_to_fsba (sblock, np->dn->number))); - cp += sizeof (int); - - *(int *)cp = htonl (ino_to_fsbo (sblock, np->dn->number) - * sizeof (struct dinode)); - - - diskfs_end_catch_exception (); - - *class = STORAGE_DEVICE; - *flags = 0; - *block_size = DEV_BSIZE; - - if (diskfs_device_name) - strcpy (storage_name, diskfs_device_name); - - if (diskfs_isuid (0, cred)) - *storage_port = diskfs_device; - else - *storage_port = MACH_PORT_NULL; - *storage_port_type = MACH_MSG_TYPE_COPY_SEND; - - mutex_unlock (&np->lock); - - return 0; + return err; } - - |