Example #1
0
/* If disk is not readonly and the noatime option is not enabled, set
   NP->dn_set_atime.  */
void
diskfs_set_node_atime (struct node *np)
{
  if (!_diskfs_noatime && !diskfs_check_readonly ())
    np->dn_set_atime = 1;
}
/* Return in FILE & FILE_TYPE the file in FSYS corresponding to the NFS file
   handle HANDLE & HANDLE_LEN.  */
error_t
diskfs_S_fsys_getfile (mach_port_t fsys,
		       mach_port_t reply, mach_msg_type_name_t reply_type,
		       uid_t *uids, mach_msg_type_number_t nuids,
		       gid_t *gids, mach_msg_type_number_t ngids,
		       char *handle, mach_msg_type_number_t handle_len,
		       mach_port_t *file, mach_msg_type_name_t *file_type)
{
  int flags;
  error_t err;
  struct node *node;
  const union diskfs_fhandle *f;
  struct protid *new_cred;
  struct peropen *new_po;
  struct iouser *user;
  struct port_info *pt =
    ports_lookup_port (diskfs_port_bucket, fsys, diskfs_control_class);

  if (!pt)
    return EOPNOTSUPP;

  if (handle_len != sizeof *f)
    {
      ports_port_deref (pt);
      return EINVAL;
    }

  f = (const union diskfs_fhandle *) handle;

  err = diskfs_cached_lookup (f->data.cache_id, &node);
  if (err)
    {
      ports_port_deref (pt);
      return err;
    }

  if (node->dn_stat.st_gen != f->data.gen)
    {
      diskfs_nput (node);
      ports_port_deref (pt);
      return ESTALE;
    }

  err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids);
  if (err)
    {
      diskfs_nput (node);
      ports_port_deref (pt);
      return err;
    }

  flags = 0;
  if (! fshelp_access (&node->dn_stat, S_IREAD, user))
    flags |= O_READ;
  if (! fshelp_access (&node->dn_stat, S_IEXEC, user))
    flags |= O_EXEC;
  if (! fshelp_access (&node->dn_stat, S_IWRITE, user)
      && ! S_ISDIR (node->dn_stat.st_mode)
      && ! diskfs_check_readonly ())
    flags |= O_WRITE;

  err = diskfs_make_peropen (node, flags, 0, &new_po);
  if (! err)
    {
      err = diskfs_create_protid (new_po, user, &new_cred);
      if (err)
	diskfs_release_peropen (new_po);
    }

  iohelp_free_iouser (user);

  diskfs_nput (node);
  ports_port_deref (pt);

  if (! err)
    {
      *file = ports_get_right (new_cred);
      *file_type = MACH_MSG_TYPE_MAKE_SEND;
    }

  return err;
}
Example #3
0
/* Implement dir_unlink as described in <hurd/fs.defs>. */
kern_return_t
diskfs_S_dir_unlink (struct protid *dircred,
		     char *name)
{
  struct node *dnp;
  struct node *np;
  struct dirstat *ds = alloca (diskfs_dirstat_size);
  error_t err;
  mach_port_t control = MACH_PORT_NULL;

  if (!dircred)
    return EOPNOTSUPP;

  dnp = dircred->po->np;
  if (diskfs_check_readonly ())
    return EROFS;

  pthread_mutex_lock (&dnp->lock);

  err = diskfs_lookup (dnp, name, REMOVE, &np, ds, dircred);
  if (err == EAGAIN)
    err = EPERM;	/* 1003.1-1996 5.5.1.4 */
  if (err)
    {
      diskfs_drop_dirstat (dnp, ds);
      pthread_mutex_unlock (&dnp->lock);
      return err;
    }

  /* This isn't the BSD behavior, but it is Posix compliant and saves
     us on several race conditions.*/
  if (S_ISDIR(np->dn_stat.st_mode))
    {
      if (np == dnp)		/* gotta catch '.' */
	diskfs_nrele (np);
      else
	diskfs_nput (np);
      diskfs_drop_dirstat (dnp, ds);
      pthread_mutex_unlock (&dnp->lock);
      return EPERM;		/* 1003.1-1996 5.5.1.4 */
    }

  err = diskfs_dirremove (dnp, np, name, ds);
  if (diskfs_synchronous)
    diskfs_node_update (dnp, 1);
  if (err)
    {
      diskfs_nput (np);
      pthread_mutex_unlock (&dnp->lock);
      return err;
    }

  np->dn_stat.st_nlink--;
  np->dn_set_ctime = 1;
  if (diskfs_synchronous)
    diskfs_node_update (np, 1);

  if (np->dn_stat.st_nlink == 0)
    fshelp_fetch_control (&np->transbox, &control);

  /* This check is necessary because we might get here on an error while
     checking the mode on something which happens to be `.'. */
  if (np == dnp)
    diskfs_nrele (np);
  else
    diskfs_nput (np);
  pthread_mutex_unlock (&dnp->lock);

  if (control)
    {
      fsys_goaway (control, FSYS_GOAWAY_UNLINK);
      mach_port_deallocate (mach_task_self (), control);
    }

  return err;
}
Example #4
0
/* Implement dir_rename as described in <hurd/fs.defs>. */
kern_return_t
diskfs_S_dir_rename (struct protid *fromcred,
		     char *fromname,
		     struct protid *tocred,
		     char *toname,
		     int excl)
{
  struct node *fdp, *tdp, *fnp, *tnp, *tmpnp;
  error_t err;
  struct dirstat *ds = alloca (diskfs_dirstat_size);
  
  if (!fromcred)
    return EOPNOTSUPP;

  /* Verify that tocred really is a port to us. */
  if (! tocred)
    return EXDEV;

  if (!strcmp (fromname, ".") || !strcmp (fromname, "..")
   || !strcmp (toname,   ".") || !strcmp (toname,   ".."))
    return EINVAL;

  if (tocred->po->shadow_root != fromcred->po->shadow_root)
    /* Same translator, but in different shadow trees.  */
    return EXDEV;

  if (diskfs_check_readonly ())
    return EROFS;

  fdp = fromcred->po->np;
  tdp = tocred->po->np;

 try_again:
  /* Acquire the source; hold a reference to it.  This 
     will prevent anyone from deleting it before we create
     the new link. */
  mutex_lock (&fdp->lock);
  err = diskfs_lookup (fdp, fromname, LOOKUP, &fnp, 0, fromcred);
  mutex_unlock (&fdp->lock);
  if (err == EAGAIN)
    err = EINVAL;
  if (err)
    return err;

  if (S_ISDIR (fnp->dn_stat.st_mode))
    {
      mutex_unlock (&fnp->lock);
      if (!mutex_try_lock (&renamedirlock))
	{
	  diskfs_nrele (fnp);
	  mutex_lock (&renamedirlock);
	  goto try_again;
	}
      err = diskfs_rename_dir (fdp, fnp, fromname, tdp, toname, fromcred,
			       tocred);
      if (diskfs_synchronous)
	{
	  mutex_lock (&fdp->lock);
	  diskfs_file_update (fdp, 1);
	  mutex_unlock (&fdp->lock);
	  
	  mutex_lock (&fnp->lock);
	  diskfs_file_update (fnp, 1);
	  mutex_unlock (&fnp->lock);

	  mutex_lock (&tdp->lock);
	  diskfs_file_update (tdp, 1);
	  mutex_unlock (&tdp->lock);
	}
      
      diskfs_nrele (fnp);
      mutex_unlock (&renamedirlock);
      if (!err)
	/* MiG won't do this for us, which it ought to. */
	mach_port_deallocate (mach_task_self (), tocred->pi.port_right);
      return err;
    }

  mutex_unlock (&fnp->lock);

  /* We now hold no locks */

  /* Link the node into the new directory. */
  mutex_lock (&tdp->lock);
  
  err = diskfs_lookup (tdp, toname, RENAME, &tnp, ds, tocred);
  if (err == EAGAIN)
    err = EINVAL;
  else if (!err && excl)
    {
      err = EEXIST;
      diskfs_nput (tnp);
    }
  if (err && err != ENOENT)
    {
      diskfs_drop_dirstat (tdp, ds);
      diskfs_nrele (fnp);
      mutex_unlock (&tdp->lock);
      return err;
    }

  /* rename("foo", "link-to-foo") is guaranteed to return 0 and
     do nothing by Posix. */
  if (tnp == fnp)
    {
      diskfs_drop_dirstat (tdp, ds);
      diskfs_nrele (fnp);
      diskfs_nput (tnp);
      mutex_unlock (&tdp->lock);
      mach_port_deallocate (mach_task_self (), tocred->pi.port_right);
      return 0;
    }

  /* rename("foo", dir) should fail. */
  if (tnp && S_ISDIR (tnp->dn_stat.st_mode))
    {
      diskfs_drop_dirstat (tdp, ds);
      diskfs_nrele (fnp);
      diskfs_nput (tnp);
      mutex_unlock (&tdp->lock);
      return EISDIR;
    }

  mutex_lock (&fnp->lock);

  /* Increment the link count for the upcoming link */
  if (fnp->dn_stat.st_nlink == diskfs_link_max - 1)
    {
      diskfs_drop_dirstat (tdp, ds);
      diskfs_nput (fnp);
      if (tnp)
        diskfs_nput (tnp);
      mutex_unlock (&tdp->lock);
      return EMLINK;
    }
  fnp->dn_stat.st_nlink++;
  fnp->dn_set_ctime = 1;
  diskfs_node_update (fnp, 1);

  if (tnp)
    {
      err = diskfs_dirrewrite (tdp, tnp, fnp, toname, ds);
      if (!err)
	{
	  tnp->dn_stat.st_nlink--;
	  tnp->dn_set_ctime = 1;
	  if (diskfs_synchronous)
	    diskfs_node_update (tnp, 1);
	}
      diskfs_nput (tnp);
    }
  else
    err = diskfs_direnter (tdp, toname, fnp, ds, tocred);

  if (diskfs_synchronous)
    diskfs_node_update (tdp, 1);

  mutex_unlock (&tdp->lock);
  mutex_unlock (&fnp->lock);
  if (err)
    {
      diskfs_nrele (fnp);
      return err;
    }

  /* We now hold no locks */

  /* Now we remove the source.  Unfortunately, we haven't held 
     fdp locked (nor could we), so someone else might have already
     removed it. */
  mutex_lock (&fdp->lock);
  err = diskfs_lookup (fdp, fromname, REMOVE, &tmpnp, ds, fromcred);
  if (err)
    {
      diskfs_drop_dirstat (tdp, ds);
      mutex_unlock (&fdp->lock);
      diskfs_nrele (fnp);
      return err;
    }

  if (tmpnp != fnp)
    {
      /* This is no longer the node being renamed, so just return. */
      diskfs_drop_dirstat (tdp, ds);
      diskfs_nput (tmpnp);
      diskfs_nrele (fnp);
      mutex_unlock (&fdp->lock);
      mach_port_deallocate (mach_task_self (), tocred->pi.port_right);
      return 0;
    }
  
  diskfs_nrele (tmpnp);

  err = diskfs_dirremove (fdp, fnp, fromname, ds);
  if (diskfs_synchronous)
    diskfs_node_update (fdp, 1);

  fnp->dn_stat.st_nlink--;
  fnp->dn_set_ctime = 1;
  
  if (diskfs_synchronous)
    diskfs_node_update (fnp, 1);
  
  diskfs_nput (fnp);
  mutex_unlock (&fdp->lock);
  if (!err)
    mach_port_deallocate (mach_task_self (), tocred->pi.port_right);

  return err;
}
Example #5
0
/* The user must define this function if she wants to use the node
   cache.  Read stat information out of the on-disk node.  */
error_t
diskfs_user_read_node (struct node *np, struct lookup_context *ctx)
{
  error_t err;
  struct stat *st = &np->dn_stat;
  struct disknode *dn = diskfs_node_disknode (np);
  struct ext2_inode *di;
  struct ext2_inode_info *info = &dn->info;

  ext2_debug ("(%llu)", np->cache_id);

  err = diskfs_catch_exception ();
  if (err)
    return err;

  di = dino_ref (np->cache_id);

  st->st_fstype = FSTYPE_EXT2FS;
  st->st_fsid = getpid ();	/* This call is very cheap.  */
  st->st_ino = np->cache_id;
  st->st_blksize = vm_page_size * 2;

  st->st_nlink = di->i_links_count;
  st->st_size = di->i_size;
  st->st_gen = di->i_generation;

  st->st_atim.tv_sec = di->i_atime;
#ifdef not_yet
  /* ``struct ext2_inode'' doesn't do better than sec. precision yet.  */
#else
  st->st_atim.tv_nsec = 0;
#endif
  st->st_mtim.tv_sec = di->i_mtime;
#ifdef not_yet
  /* ``struct ext2_inode'' doesn't do better than sec. precision yet.  */
#else
  st->st_mtim.tv_nsec = 0;
#endif
  st->st_ctim.tv_sec = di->i_ctime;
#ifdef not_yet
  /* ``struct ext2_inode'' doesn't do better than sec. precision yet.  */
#else
  st->st_ctim.tv_nsec = 0;
#endif

  st->st_blocks = di->i_blocks;

  st->st_flags = 0;
  if (di->i_flags & EXT2_APPEND_FL)
    st->st_flags |= UF_APPEND;
  if (di->i_flags & EXT2_NODUMP_FL)
    st->st_flags |= UF_NODUMP;
  if (di->i_flags & EXT2_IMMUTABLE_FL)
    st->st_flags |= UF_IMMUTABLE;

  if (sblock->s_creator_os == EXT2_OS_HURD)
    {
      st->st_mode = di->i_mode | (di->i_mode_high << 16);
      st->st_mode &= ~S_ITRANS;
      if (di->i_translator)
	st->st_mode |= S_IPTRANS;

      st->st_uid = di->i_uid | (di->i_uid_high << 16);
      st->st_gid = di->i_gid | (di->i_gid_high << 16);

      st->st_author = di->i_author;
      if (st->st_author == -1)
	st->st_author = st->st_uid;
    }
  else
    {
      st->st_mode = di->i_mode & ~S_ITRANS;
      st->st_uid = di->i_uid;
      st->st_gid = di->i_gid;
      st->st_author = st->st_uid;
      np->author_tracks_uid = 1;
    }

  /* Setup the ext2fs auxiliary inode info.  */
  info->i_dtime = di->i_dtime;
  info->i_flags = di->i_flags;
  info->i_faddr = di->i_faddr;
  info->i_frag_no = di->i_frag;
  info->i_frag_size = di->i_fsize;
  info->i_osync = 0;
  info->i_file_acl = di->i_file_acl;
  if (S_ISDIR (st->st_mode))
    info->i_dir_acl = di->i_dir_acl;
  else
    {
      info->i_dir_acl = 0;
      info->i_high_size = di->i_size_high;
      if (info->i_high_size)	/* XXX */
	{
	  dino_deref (di);
	  ext2_warning ("cannot handle large file inode %Ld", np->cache_id);
	  diskfs_end_catch_exception ();
	  return EFBIG;
	}
    }
  info->i_block_group = inode_group_num (np->cache_id);
  info->i_next_alloc_block = 0;
  info->i_next_alloc_goal = 0;
  info->i_prealloc_count = 0;

  /* Set to a conservative value.  */
  dn->last_page_partially_writable = 0;

  if (S_ISCHR (st->st_mode) || S_ISBLK (st->st_mode))
    st->st_rdev = di->i_block[0];
  else
    {
      memcpy (info->i_data, di->i_block,
	      EXT2_N_BLOCKS * sizeof info->i_data[0]);
      st->st_rdev = 0;
    }
  dn->info_i_translator = di->i_translator;

  dino_deref (di);
  diskfs_end_catch_exception ();

  if (S_ISREG (st->st_mode) || S_ISDIR (st->st_mode)
      || (S_ISLNK (st->st_mode) && st->st_blocks))
    {
      unsigned offset;

      np->allocsize = np->dn_stat.st_size;

      /* Round up to a block multiple.  */
      offset = np->allocsize & ((1 << log2_block_size) - 1);
      if (offset > 0)
	np->allocsize += block_size - offset;
    }
  else
    /* Allocsize should be zero for anything except directories, files, and
       long symlinks.  These are the only things allowed to have any blocks
       allocated as well, although st_size may be zero for any type (cases
       where st_blocks=0 and st_size>0 include fast symlinks, and, under
       linux, some devices).  */
    np->allocsize = 0;

  if (!diskfs_check_readonly () && !np->dn_stat.st_gen)
    {
      pthread_spin_lock (&generation_lock);
      if (++next_generation < diskfs_mtime->seconds)
	next_generation = diskfs_mtime->seconds;
      np->dn_stat.st_gen = next_generation;
      pthread_spin_unlock (&generation_lock);
      np->dn_set_ctime = 1;
    }

  return 0;
}