Exemplo n.º 1
0
/*===========================================================================*
 *				do_chdir				     *
 *===========================================================================*/
PUBLIC int do_chdir()
{
/* Change directory.  This function is  also called by MM to simulate a chdir
 * in order to do EXEC, etc.  It also changes the root directory, the uids and
 * gids, and the umask. 
 */

  int r;
  register struct fproc *rfp;

  if (who == MM_PROC_NR) {
	rfp = &fproc[slot1];
	put_inode(fp->fp_rootdir);
	dup_inode(fp->fp_rootdir = rfp->fp_rootdir);
	put_inode(fp->fp_workdir);
	dup_inode(fp->fp_workdir = rfp->fp_workdir);

	/* MM uses access() to check permissions.  To make this work, pretend
	 * that the user's real ids are the same as the user's effective ids.
	 * FS calls other than access() do not use the real ids, so are not
	 * affected.
	 */
	fp->fp_realuid =
	fp->fp_effuid = rfp->fp_effuid;
	fp->fp_realgid =
	fp->fp_effgid = rfp->fp_effgid;
	fp->fp_umask = rfp->fp_umask;
	return(OK);
  }

  /* Perform the chdir(name) system call. */
  r = change(&fp->fp_workdir, name, name_length);
  return(r);
}
Exemplo n.º 2
0
/*===========================================================================*
 *				do_fchdir				     *
 *===========================================================================*/
PUBLIC int do_fchdir()
{
	/* Change directory on already-opened fd. */
	struct filp *rfilp;

	/* Is the file descriptor valid? */
	if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
	dup_inode(rfilp->filp_ino);
	return change_into(&fp->fp_workdir, rfilp->filp_ino);
}
Exemplo n.º 3
0
/*===========================================================================*
 *				do_pipe					     *
 *===========================================================================*/
PUBLIC int do_pipe()
{
/* Perform the pipe(fil_des) system call. */

  register struct fproc *rfp;
  register struct inode *rip;
  int r;
  struct filp *fil_ptr0, *fil_ptr1;
  int fil_des[2];		/* reply goes here */

  /* Acquire two file descriptors. */
  rfp = fp;
  if ( (r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r);
  rfp->fp_filp[fil_des[0]] = fil_ptr0;
  fil_ptr0->filp_count = 1;
  if ( (r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
	rfp->fp_filp[fil_des[0]] = NIL_FILP;
	fil_ptr0->filp_count = 0;
	return(r);
  }
  rfp->fp_filp[fil_des[1]] = fil_ptr1;
  fil_ptr1->filp_count = 1;

  /* Make the inode on the pipe device. */
  if ( (rip = alloc_inode(root_dev, I_REGULAR) ) == NIL_INODE) {
	rfp->fp_filp[fil_des[0]] = NIL_FILP;
	fil_ptr0->filp_count = 0;
	rfp->fp_filp[fil_des[1]] = NIL_FILP;
	fil_ptr1->filp_count = 0;
	return(err_code);
  }

  if (read_only(rip) != OK) 
  	panic(__FILE__,"pipe device is read only", NO_NUM);
 
  rip->i_pipe = I_PIPE;
  rip->i_mode &= ~I_REGULAR;
  rip->i_mode |= I_NAMED_PIPE;	/* pipes and FIFOs have this bit set */
  fil_ptr0->filp_ino = rip;
  fil_ptr0->filp_flags = O_RDONLY;
  dup_inode(rip);		/* for double usage */
  fil_ptr1->filp_ino = rip;
  fil_ptr1->filp_flags = O_WRONLY;
  rw_inode(rip, WRITING);	/* mark inode as allocated */
  m_out.reply_i1 = fil_des[0];
  m_out.reply_i2 = fil_des[1];
  rip->i_update = ATIME | CTIME | MTIME;
  return(OK);
}
Exemplo n.º 4
0
struct inode* get_inode(ino_t i)
{
	struct inode *i_node;
	struct dir_extent *extent;

	if (i == 0)
		return NULL;

	/* Try to get inode from cache. */
	i_node = find_inode(i);
	if (i_node != NULL) {
		dup_inode(i_node);
		return i_node;
	}

	/*
	 * Inode wasn't in cache, try to load it.
	 * FIXME: a fake extent of one logical block is created for
	 * read_inode(). Reading a inode this way could be problematic if
	 * additional extents are stored behind the block boundary.
	 */
	i_node = alloc_inode();
	extent = alloc_extent();
	extent->location = i / v_pri.logical_block_size_l;
	extent->length = 1;

	if (read_inode(i_node, extent, i % v_pri.logical_block_size_l,
	    NULL) != OK) {
		free_extent(extent);
		put_inode(i_node);
		return NULL;
	}

	free_extent(extent);
	return i_node;
}
Exemplo n.º 5
0
/*===========================================================================*
 *				do_rename				     *
 *===========================================================================*/
PUBLIC int do_rename()
{
/* Perform the rename(name1, name2) system call. */

  struct inode *old_dirp, *old_ip;	/* ptrs to old dir, file inodes */
  struct inode *new_dirp, *new_ip;	/* ptrs to new dir, file inodes */
  struct inode *new_superdirp, *next_new_superdirp;
  int r = OK;				/* error flag; initially no error */
  int odir, ndir;			/* TRUE iff {old|new} file is dir */
  int same_pdir;			/* TRUE iff parent dirs are the same */
  char old_name[NAME_MAX], new_name[NAME_MAX];
  ino_t numb;
  int r1;
  
  /* See if 'name1' (existing file) exists.  Get dir and file inodes. */
  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
  if ( (old_dirp = last_dir(user_path, old_name))==NIL_INODE) return(err_code);

  if ( (old_ip = advance(old_dirp, old_name)) == NIL_INODE) r = err_code;

  /* See if 'name2' (new name) exists.  Get dir and file inodes. */
  if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code;
  if ( (new_dirp = last_dir(user_path, new_name)) == NIL_INODE) r = err_code;
  new_ip = advance(new_dirp, new_name);	/* not required to exist */

  if (old_ip != NIL_INODE)
	odir = ((old_ip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE iff dir */

  /* If it is ok, check for a variety of possible errors. */
  if (r == OK) {
	same_pdir = (old_dirp == new_dirp);

	/* The old inode must not be a superdirectory of the new last dir. */
	if (odir && !same_pdir) {
		dup_inode(new_superdirp = new_dirp);
		while (TRUE) {		/* may hang in a file system loop */
			if (new_superdirp == old_ip) {
				r = EINVAL;
				break;
			}
			next_new_superdirp = advance(new_superdirp, dot2);
			put_inode(new_superdirp);
			if (next_new_superdirp == new_superdirp)
				break;	/* back at system root directory */
			new_superdirp = next_new_superdirp;
			if (new_superdirp == NIL_INODE) {
				/* Missing ".." entry.  Assume the worst. */
				r = EINVAL;
				break;
			}
		} 	
		put_inode(new_superdirp);
	}	

	/* The old or new name must not be . or .. */
	if (strcmp(old_name, ".")==0 || strcmp(old_name, "..")==0 ||
	    strcmp(new_name, ".")==0 || strcmp(new_name, "..")==0) r = EINVAL;

	/* Both parent directories must be on the same device. */
	if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV;

	/* Parent dirs must be writable, searchable and on a writable device */
	if ((r1 = forbidden(old_dirp, W_BIT | X_BIT)) != OK ||
	    (r1 = forbidden(new_dirp, W_BIT | X_BIT)) != OK) r = r1;

	/* Some tests apply only if the new path exists. */
	if (new_ip == NIL_INODE) {
		/* don't rename a file with a file system mounted on it. */
		if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV;
		if (odir && new_dirp->i_nlinks >=
		    (new_dirp->i_sp->s_version == V1 ? CHAR_MAX : SHRT_MAX) &&
		    !same_pdir && r == OK) r = EMLINK;
	} else {
		if (old_ip == new_ip) r = SAME; /* old=new */

		/* has the old file or new file a file system mounted on it? */
		if (old_ip->i_dev != new_ip->i_dev) r = EXDEV;

		ndir = ((new_ip->i_mode & I_TYPE) == I_DIRECTORY); /* dir ? */
		if (odir == TRUE && ndir == FALSE) r = ENOTDIR;
		if (odir == FALSE && ndir == TRUE) r = EISDIR;
	}
  }

  /* If a process has another root directory than the system root, we might
   * "accidently" be moving it's working directory to a place where it's
   * root directory isn't a super directory of it anymore. This can make
   * the function chroot useless. If chroot will be used often we should
   * probably check for it here.
   */

  /* The rename will probably work. Only two things can go wrong now:
   * 1. being unable to remove the new file. (when new file already exists)
   * 2. being unable to make the new directory entry. (new file doesn't exists)
   *     [directory has to grow by one block and cannot because the disk
   *      is completely full].
   */
  if (r == OK) {
	if (new_ip != NIL_INODE) {
		  /* There is already an entry for 'new'. Try to remove it. */
		if (odir) 
			r = remove_dir(new_dirp, new_ip, new_name);
		else 
			r = unlink_file(new_dirp, new_ip, new_name);
	}
	/* if r is OK, the rename will succeed, while there is now an
	 * unused entry in the new parent directory.
	 */
  }

  if (r == OK) {
	/* If the new name will be in the same parent directory as the old one,
	 * first remove the old name to free an entry for the new name,
	 * otherwise first try to create the new name entry to make sure
	 * the rename will succeed.
	 */
	numb = old_ip->i_num;		/* inode number of old file */

  	if (same_pdir) {
		r = search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
						/* shouldn't go wrong. */
		if (r==OK) (void) search_dir(old_dirp, new_name, &numb, ENTER);
	} else {
		r = search_dir(new_dirp, new_name, &numb, ENTER);
		if (r == OK)
		    (void) search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
	}
  }
  /* If r is OK, the ctime and mtime of old_dirp and new_dirp have been marked
   * for update in search_dir.
   */

  if (r == OK && odir && !same_pdir) {
	/* Update the .. entry in the directory (still points to old_dirp). */
	numb = new_dirp->i_num;
	(void) unlink_file(old_ip, NIL_INODE, dot2);
	if (search_dir(old_ip, dot2, &numb, ENTER) == OK) {
		/* New link created. */
		new_dirp->i_nlinks++;
		new_dirp->i_dirt = DIRTY;
	}
  }
	
  /* Release the inodes. */
  put_inode(old_dirp);
  put_inode(old_ip);
  put_inode(new_dirp);
  put_inode(new_ip);
  return(r == SAME ? OK : r);
}
Exemplo n.º 6
0
/*===========================================================================*
 *				do_mount				     *
 *===========================================================================*/
PUBLIC int do_mount()
{
/* Perform the mount(name, mfile, rd_only) system call. */

  register struct inode *rip, *root_ip;
  struct super_block *xp, *sp;
  dev_t dev;
  mode_t bits;
  int rdir, mdir;		/* TRUE iff {root|mount} file is dir */
  int i, r, found;
  struct fproc *tfp;

  /* Only the super-user may do MOUNT. */
  if (!super_user) return(EPERM);

  /* If 'name' is not for a block special file, return error. */
  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
  if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code);

  /* Scan super block table to see if dev already mounted & find a free slot.*/
  sp = NIL_SUPER;
  found = FALSE;
  for (xp = &super_block[0]; xp < &super_block[NR_SUPERS]; xp++) {
	if (xp->s_dev == dev)
	{
		/* is it mounted already? */
		found = TRUE;
		sp= xp;
		break;
	}
	if (xp->s_dev == NO_DEV) sp = xp;	/* record free slot */
  }
  if (found)
  {
	printf(
"do_mount: s_imount = 0x%x (%x, %d), s_isup = 0x%x (%x, %d), fp_rootdir = 0x%x\n",
		xp->s_imount, xp->s_imount->i_dev, xp->s_imount->i_num,
		xp->s_isup, xp->s_isup->i_dev, xp->s_isup->i_num,
		fproc[FS_PROC_NR].fp_rootdir);
	/* It is possible that we have an old root lying around that 
	 * needs to be remounted.
	 */
	if (xp->s_imount != xp->s_isup ||
		xp->s_isup == fproc[FS_PROC_NR].fp_rootdir)
	{
		/* Normally, s_imount refers to the mount point. For a root
		 * filesystem, s_imount is equal to the root inode. We assume
		 * that the root of FS is always the real root. If the two
		 * inodes are different or if the root of FS is equal two the
		 * root of the filesystem we found, we found a filesystem that
		 * is in use.
		 */
		return(EBUSY);	/* already mounted */
	}

	if (root_dev == xp->s_dev)
	{
		panic("fs", "inconsistency remounting old root",
			NO_NUM);
	}

	/* Now get the inode of the file to be mounted on. */
	if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
		return(err_code);
	}

	if ( (rip = eat_path(user_path)) == NIL_INODE) {
		return(err_code);
	}

	r = OK;

	/* It may not be special. */
	bits = rip->i_mode & I_TYPE;
	if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL)
		r = ENOTDIR;

	/* Get the root inode of the mounted file system. */
	root_ip= sp->s_isup;

	/* File types of 'rip' and 'root_ip' may not conflict. */
	if (r == OK) {
		mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY); 
						/* TRUE iff dir */
		rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY);
		if (!mdir && rdir) r = EISDIR;
	}

	/* If error, return the mount point. */
	if (r != OK) {
		put_inode(rip);
		return(r);
	}

	/* Nothing else can go wrong.  Perform the mount. */
	rip->i_mount = I_MOUNT;	/* this bit says the inode is
				 * mounted on
				 */
	put_inode(sp->s_imount);
	sp->s_imount = rip;
	sp->s_rd_only = m_in.rd_only;
	allow_newroot= 0;		/* The root is now fixed */
	return(OK);
  }
  if (sp == NIL_SUPER) return(ENFILE);	/* no super block available */

  /* Open the device the file system lives on. */
  if (dev_open(dev, who_e, m_in.rd_only ? R_BIT : (R_BIT|W_BIT)) != OK) 
  	return(EINVAL);

  /* Make the cache forget about blocks it has open on the filesystem */
  (void) do_sync();
  invalidate(dev);

  /* Fill in the super block. */
  sp->s_dev = dev;		/* read_super() needs to know which dev */
  r = read_super(sp);

  /* Is it recognized as a Minix filesystem? */
  if (r != OK) {
	dev_close(dev);
	sp->s_dev = NO_DEV;
	return(r);
  }

  /* Now get the inode of the file to be mounted on. */
  if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
	dev_close(dev);
	sp->s_dev = NO_DEV;
	return(err_code);
  }

  if (strcmp(user_path, "/") == 0 && allow_newroot)
  {
	printf("Replacing root\n");

	/* Get the root inode of the mounted file system. */
	if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code;
	if (root_ip != NIL_INODE && root_ip->i_mode == 0) {
		r = EINVAL;
	}

	/* If error, return the super block and both inodes; release the
	 * maps.
	 */
	if (r != OK) {
		put_inode(root_ip);
		(void) do_sync();
		invalidate(dev);
		dev_close(dev);
		sp->s_dev = NO_DEV;
		return(r);
	}

	/* Nothing else can go wrong.  Perform the mount. */
	sp->s_imount = root_ip;
	dup_inode(root_ip);
	sp->s_isup = root_ip;
	sp->s_rd_only = m_in.rd_only;
	root_dev= dev;

	/* Replace all root and working directories */
	for (i= 0, tfp= fproc; i<NR_PROCS; i++, tfp++)
	{
		if (tfp->fp_pid == PID_FREE)
			continue;
		if (tfp->fp_rootdir == NULL)
			panic("fs", "do_mount: null rootdir", i);
		put_inode(tfp->fp_rootdir);
		dup_inode(root_ip);
		tfp->fp_rootdir= root_ip;

		if (tfp->fp_workdir == NULL)
			panic("fs", "do_mount: null workdir", i);
		put_inode(tfp->fp_workdir);
		dup_inode(root_ip);
		tfp->fp_workdir= root_ip;
	}

	/* Leave the old filesystem lying around. */
	return(OK);
  }

  if ( (rip = eat_path(user_path)) == NIL_INODE) {
	dev_close(dev);
	sp->s_dev = NO_DEV;
	return(err_code);
  }

  /* It may not be busy. */
  r = OK;
  if (rip->i_count > 1) r = EBUSY;

  /* It may not be special. */
  bits = rip->i_mode & I_TYPE;
  if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR;

  /* Get the root inode of the mounted file system. */
  root_ip = NIL_INODE;		/* if 'r' not OK, make sure this is defined */
  if (r == OK) {
	if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code;
  }
  if (root_ip != NIL_INODE && root_ip->i_mode == 0) {
  	r = EINVAL;
  }

  /* File types of 'rip' and 'root_ip' may not conflict. */
  if (r == OK) {
	mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE iff dir */
	rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY);
	if (!mdir && rdir) r = EISDIR;
  }

  /* If error, return the super block and both inodes; release the maps. */
  if (r != OK) {
	put_inode(rip);
	put_inode(root_ip);
	(void) do_sync();
	invalidate(dev);
	dev_close(dev);
	sp->s_dev = NO_DEV;
	return(r);
  }

  /* Nothing else can go wrong.  Perform the mount. */
  rip->i_mount = I_MOUNT;	/* this bit says the inode is mounted on */
  sp->s_imount = rip;
  sp->s_isup = root_ip;
  sp->s_rd_only = m_in.rd_only;
  allow_newroot= 0;		/* The root is now fixed */
  return(OK);
}