/*===========================================================================*
 *				new_node				     *
 *===========================================================================*/
PRIVATE struct inode *new_node(struct inode **ldirp,
	char *path, mode_t bits, zone_t z0, int opaque, char *parsed)
{
/* New_node() is called by common_open(), do_mknod(), and do_mkdir().  
 * In all cases it allocates a new inode, makes a directory entry for it on 
 * the path 'path', and initializes it.  It returns a pointer to the inode if 
 * it can do this; otherwise it returns NIL_INODE.  It always sets 'err_code'
 * to an appropriate value (OK or an error code).
 * 
 * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
 * has to hold at least NAME_MAX bytes.
 */

  register struct inode *rip;
  register int r;
  char string[NAME_MAX];

  *ldirp = parse_path(path, string, opaque ? LAST_DIR : LAST_DIR_EATSYM);       
  if (*ldirp == NIL_INODE) return(NIL_INODE);

  /* The final directory is accessible. Get final component of the path. */
  rip = advance(ldirp, string);

  if (S_ISDIR(bits) && 
      (*ldirp)->i_nlinks >= ((*ldirp)->i_sp->s_version == V1 ?
      CHAR_MAX : SHRT_MAX)) {
        /* New entry is a directory, alas we can't give it a ".." */
        put_inode(rip);
        err_code = EMLINK;
        return(NIL_INODE);
  }

  if ( rip == NIL_INODE && err_code == ENOENT) {
	/* Last path component does not exist.  Make new directory entry. */
	if ( (rip = alloc_inode((*ldirp)->i_dev, bits)) == NIL_INODE) {
		/* Can't creat new inode: out of inodes. */
		return(NIL_INODE);
	}

	/* Force inode to the disk before making directory entry to make
	 * the system more robust in the face of a crash: an inode with
	 * no directory entry is much better than the opposite.
	 */
	rip->i_nlinks++;
	rip->i_zone[0] = z0;		/* major/minor device numbers */
	rw_inode(rip, WRITING);		/* force inode to disk now */

	/* New inode acquired.  Try to make directory entry. */
	if ((r = search_dir(*ldirp, string, &rip->i_num,ENTER)) != OK) {
		rip->i_nlinks--;	/* pity, have to free disk inode */
		rip->i_dirt = DIRTY;	/* dirty inodes are written out */
		put_inode(rip);	/* this call frees the inode */
		err_code = r;
		return(NIL_INODE);
	}

  } else {
	/* Either last component exists, or there is some problem. */
	if (rip != NIL_INODE)
		r = EEXIST;
	else
		r = err_code;
  }

  if(parsed) { /* Give the caller the parsed string if requested. */
	strncpy(parsed, string, NAME_MAX-1);
	parsed[NAME_MAX-1] = '\0';
  }

  /* The caller has to return the directory inode (*ldirp).  */
  err_code = r;
  return(rip);
}
/*===========================================================================*
 *				do_close				     *
 *===========================================================================*/
PUBLIC int do_close()
{
/* Perform the close(fd) system call. */

  register struct filp *rfilp;
  register struct inode *rip;
  struct file_lock *flp;
  int rw, mode_word, lock_count;
  dev_t dev;

  /* First locate the inode that belongs to the file descriptor. */
  if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
  rip = rfilp->filp_ino;	/* 'rip' points to the inode */

  if (rfilp->filp_count - 1 == 0 && rfilp->filp_mode != FILP_CLOSED) {
	/* Check to see if the file is special. */
	mode_word = rip->i_mode & I_TYPE;
	if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) {
		dev = (dev_t) rip->i_zone[0];
		if (mode_word == I_BLOCK_SPECIAL)  {
			/* Invalidate cache entries unless special is mounted
			 * or ROOT
			 */
			if (!mounted(rip)) {
			        (void) do_sync();	/* purge cache */
				invalidate(dev);
			}    
		}
		/* Do any special processing on device close. */
		dev_close(dev);
	}
  }

  /* If the inode being closed is a pipe, release everyone hanging on it. */
  if (rip->i_pipe == I_PIPE) {
	rw = (rfilp->filp_mode & R_BIT ? WRITE : READ);
	release(rip, rw, NR_PROCS);
  }

  /* If a write has been done, the inode is already marked as DIRTY. */
  if (--rfilp->filp_count == 0) {
	if (rip->i_pipe == I_PIPE && rip->i_count > 1) {
		/* Save the file position in the i-node in case needed later.
		 * The read and write positions are saved separately.  The
		 * last 3 zones in the i-node are not used for (named) pipes.
		 */
		if (rfilp->filp_mode == R_BIT)
			rip->i_zone[V2_NR_DZONES+0] = (zone_t) rfilp->filp_pos;
		else
			rip->i_zone[V2_NR_DZONES+1] = (zone_t) rfilp->filp_pos;
	}
	put_inode(rip);
  }

  fp->fp_cloexec &= ~(1L << m_in.fd);	/* turn off close-on-exec bit */
  fp->fp_filp[m_in.fd] = NIL_FILP;
  FD_CLR(m_in.fd, &fp->fp_filp_inuse);

  /* Check to see if the file is locked.  If so, release all locks. */
  if (nr_locks == 0) return(OK);
  lock_count = nr_locks;	/* save count of locks */
  for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
	if (flp->lock_type == 0) continue;	/* slot not in use */
	if (flp->lock_inode == rip && flp->lock_pid == fp->fp_pid) {
		flp->lock_type = 0;
		nr_locks--;
	}
  }
  if (nr_locks < lock_count) lock_revive();	/* lock released */
  return(OK);
}
Exemple #3
0
/*===========================================================================*
 *				fs_readsuper				     *
 *===========================================================================*/
PUBLIC int fs_readsuper()
{
/* This function reads the superblock of the partition, gets the root inode
 * and sends back the details of them. Note, that the FS process does not
 * know the index of the vmnt object which refers to it, whenever the pathname 
 * lookup leaves a partition an ELEAVEMOUNT error is transferred back 
 * so that the VFS knows that it has to find the vnode on which this FS 
 * process' partition is mounted on.
 */
  struct inode *root_ip;
  cp_grant_id_t label_gid;
  size_t label_len;
  int r;
  endpoint_t driver_e;
  int readonly, isroot;

  fs_dev    = (dev_t) fs_m_in.REQ_DEV;
  label_gid = (cp_grant_id_t) fs_m_in.REQ_GRANT;
  label_len = (size_t) fs_m_in.REQ_PATH_LEN;
  readonly  = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0;
  isroot    = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0;

  if (label_len > sizeof(fs_dev_label))
	return(EINVAL);

  r = sys_safecopyfrom(fs_m_in.m_source, label_gid, (vir_bytes) 0,
		       (vir_bytes) fs_dev_label, label_len, D);
  if (r != OK) {
	printf("MFS %s:%d safecopyfrom failed: %d\n", __FILE__, __LINE__, r);
	return(EINVAL);
  }

  r = ds_retrieve_label_endpt(fs_dev_label, &driver_e);
  if (r != OK) {
	printf("MFS %s:%d ds_retrieve_label_endpt failed for '%s': %d\n",
		__FILE__, __LINE__, fs_dev_label, r);
	return(EINVAL);
  }

  /* Map the driver endpoint for this major */
  bdev_driver(fs_dev, driver_e);

  /* Open the device the file system lives on. */
  if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT) ) != OK) {
        return(EINVAL);
  }
  
  /* Fill in the super block. */
  superblock.s_dev = fs_dev;	/* read_super() needs to know which dev */
  r = read_super(&superblock);

  /* Is it recognized as a Minix filesystem? */
  if (r != OK) {
	superblock.s_dev = NO_DEV;
	bdev_close(fs_dev);
	return(r);
  }

  set_blocksize(&superblock);
  
  /* Get the root inode of the mounted file system. */
  if( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL)  {
	printf("MFS: couldn't get root inode\n");
	superblock.s_dev = NO_DEV;
	bdev_close(fs_dev);
	return(EINVAL);
  }
  
  if(root_ip->i_mode == 0) {
	printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__);
	put_inode(root_ip);
	superblock.s_dev = NO_DEV;
	bdev_close(fs_dev);
	return(EINVAL);
  }

  superblock.s_rd_only = readonly;
  superblock.s_is_root = isroot;
  
  /* Root inode properties */
  fs_m_out.RES_INODE_NR = root_ip->i_num;
  fs_m_out.RES_MODE = root_ip->i_mode;
  fs_m_out.RES_FILE_SIZE_LO = root_ip->i_size;
  fs_m_out.RES_UID = root_ip->i_uid;
  fs_m_out.RES_GID = root_ip->i_gid;

  fs_m_out.RES_CONREQS = 1;	/* We can handle only 1 request at a time */

  return(r);
}
Exemple #4
0
/*===========================================================================*
 *				fs_utime				     *
 *===========================================================================*/
int fs_utime()
{
  register struct inode *rip;
  register int r;

  /* Temporarily open the file. */
  if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
        return(EINVAL);

  /*
   * Only the owner of a file or the super_user can change the timestamps.
   * Here we assume VFS did that check before.
   */

  r = OK;
  if(read_only(rip) != OK) r = EROFS;	/* not even su can touch if R/O */
  if(r == OK) {
	rip->i_update = CTIME;	/* discard any stale ATIME and MTIME flags */
	switch(fs_m_in.REQ_ACNSEC) {
	case UTIME_NOW:
		rip->i_update |= ATIME;
		break;
	case UTIME_OMIT: /* do not touch */
		break;
	default:
		/*
		 * cases fs_m_in.REQ_ACNSEC < 0 || fs_m_in.REQ_ACNSEC >= 1E9
		 * are caught by VFS to cooperate with old instances of EXT2
		 */
		rip->i_atime = fs_m_in.REQ_ACTIME;
		/*
		 * Ext2FS does not support better than second resolution,
		 * so we discard REQ_ACNSEC to round down
		 */
		break;
	}

	switch(fs_m_in.REQ_MODNSEC) {
	case UTIME_NOW:
		rip->i_update |= MTIME;
		break;
	case UTIME_OMIT: /* do not touch */
		break;
	default:
		/*
		 * cases fs_m_in.REQ_MODNSEC < 0 || fs_m_in.REQ_MODNSEC >= 1E9
		 * are caught by VFS to cooperate with old instances of EXT2
		 */
		rip->i_mtime = fs_m_in.REQ_MODTIME;
		/*
		 * Ext2FS does not support better than second resolution,
		 * so we discard REQ_MODNSEC to round down
		 */
		break;
	}

	rip->i_dirt = IN_DIRTY;
  }

  put_inode(rip);
  return(r);
}
Exemple #5
0
/*===========================================================================*
 *				fs_mkdir				     *
 *===========================================================================*/
int fs_mkdir()
{
  int r1, r2;			/* status codes */
  ino_t dot, dotdot;		/* inode numbers for . and .. */
  struct inode *rip, *ldirp;
  char lastc[NAME_MAX + 1];         /* last component */
  phys_bytes len;

  /* Copy the last component and set up caller's user and group id */
  len = fs_m_in.REQ_PATH_LEN; /* including trailing '\0' */
  if (len > NAME_MAX + 1 || len > EXT2_NAME_MAX + 1)
	return(ENAMETOOLONG);

  err_code = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
			      (vir_bytes) 0, (vir_bytes) lastc, (phys_bytes) len);
  if(err_code != OK) return(err_code);
  NUL(lastc, len, sizeof(lastc));

  caller_uid = (uid_t) fs_m_in.REQ_UID;
  caller_gid = (gid_t) fs_m_in.REQ_GID;

  /* Get last directory inode */
  if((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
      return(ENOENT);

  /* Next make the inode. If that fails, return error code. */
  rip = new_node(ldirp, lastc, (ino_t) fs_m_in.REQ_MODE, (block_t) 0);

  if(rip == NULL || err_code == EEXIST) {
	  put_inode(rip);		/* can't make dir: it already exists */
	  put_inode(ldirp);
	  return(err_code);
  }

  /* Get the inode numbers for . and .. to enter in the directory. */
  dotdot = ldirp->i_num;	/* parent's inode number */
  dot = rip->i_num;		/* inode number of the new dir itself */

  /* Now make dir entries for . and .. unless the disk is completely full. */
  /* Use dot1 and dot2, so the mode of the directory isn't important. */
  rip->i_mode = (mode_t) fs_m_in.REQ_MODE;	/* set mode */
  /* enter . in the new dir*/
  r1 = search_dir(rip, dot1, &dot, ENTER, IGN_PERM, I_DIRECTORY);
  /* enter .. in the new dir */
  r2 = search_dir(rip, dot2, &dotdot, ENTER, IGN_PERM, I_DIRECTORY);

  /* If both . and .. were successfully entered, increment the link counts. */
  if (r1 == OK && r2 == OK) {
	  /* Normal case.  It was possible to enter . and .. in the new dir. */
	  rip->i_links_count++;	/* this accounts for . */
	  ldirp->i_links_count++;	/* this accounts for .. */
	  ldirp->i_dirt = IN_DIRTY;	/* mark parent's inode as dirty */
  } else {
	  /* It was not possible to enter . or .. probably disk was full -
	   * links counts haven't been touched. */
	  if (search_dir(ldirp, lastc, NULL, DELETE, IGN_PERM, 0) != OK)
		  panic("Dir disappeared: %d ", rip->i_num);
	  rip->i_links_count--;	/* undo the increment done in new_node() */
  }
  rip->i_dirt = IN_DIRTY;		/* either way, i_links_count has changed */

  put_inode(ldirp);		/* return the inode of the parent dir */
  put_inode(rip);		/* return the inode of the newly made dir */
  return(err_code);		/* new_node() always sets 'err_code' */
}
Exemple #6
0
/*===========================================================================*
 *				do_getdents				     *
 *===========================================================================*/
PUBLIC int do_getdents()
{
/* Retrieve directory entries.
 */
  char name[NAME_MAX+1];
  struct inode *ino, *child;
  struct dirent *dent;
  struct hgfs_attr attr;
  size_t len, off, user_off, user_left;
  off_t pos;
  int r;
  /* must be at least sizeof(struct dirent) + NAME_MAX */
  static char buf[BLOCK_SIZE];

  attr.a_mask = HGFS_ATTR_MODE;

  if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
	return EINVAL;

  if (m_in.REQ_SEEK_POS_HI != 0) return EINVAL;

  if (!IS_DIR(ino)) return ENOTDIR;

  /* We are going to need at least one free inode to store children in. */
  if (!have_free_inode()) return ENFILE;

  /* If we don't have a directory handle yet, get one now. */
  if ((r = get_handle(ino)) != OK)
	return r;

  off = 0;
  user_off = 0;
  user_left = m_in.REQ_MEM_SIZE;

  /* We use the seek position as file index number. The first position is for
   * the "." entry, the second position is for the ".." entry, and the next
   * position numbers each represent a file in the directory.
   */
  for (pos = m_in.REQ_SEEK_POS_LO; ; pos++) {
	/* Determine which inode and name to use for this entry.
	 * We have no idea whether the HGFS host will give us "." and/or "..",
	 * so generate our own and skip those from the host.
	 */
	if (pos == 0) {
		/* Entry for ".". */
		child = ino;

		strcpy(name, ".");

		get_inode(child);
	}
	else if (pos == 1) {
		/* Entry for "..", but only when there is a parent. */
		if (ino->i_parent == NULL)
			continue;

		child = ino->i_parent;

		strcpy(name, "..");

		get_inode(child);
	}
	else {
		/* Any other entry, not being "." or "..". */
		r = hgfs_readdir(ino->i_dir, pos - 2, name, sizeof(name),
			&attr);

		if (r != OK || !name[0]) {
			/* No more entries? Then close the handle and stop. */
			/* VMware Player 3 returns an empty name, instead of
			 * EINVAL, when reading from an EOF position right
			 * after opening the directory handle. Seems to be a
			 * newly introduced bug..
			 */
			if (r == EINVAL || !name[0]) {
				put_handle(ino);

				break;
			}

			/* FIXME: what if the error is ENAMETOOLONG? */
			return r;
		}

		if (!strcmp(name, ".") || !strcmp(name, ".."))
			continue;

		if ((child = lookup_dentry(ino, name)) == NULL) {
			child = get_free_inode();

			/* We were promised a free inode! */
			assert(child != NULL);

			child->i_flags = MODE_TO_DIRFLAG(attr.a_mode);

			add_dentry(ino, name, child);
		}
	}

	len = DWORD_ALIGN(sizeof(struct dirent) + strlen(name));

	/* Is the user buffer too small to store another record?
	 * Note that we will be rerequesting the same dentry upon a subsequent
	 * getdents call this way, but we really need the name length for this.
	 */
	if (user_off + off + len > user_left) {
		put_inode(child);

		/* Is the user buffer too small for even a single record? */
		if (user_off == 0 && off == 0)
			return EINVAL;

		break;
	}

	/* If our own buffer cannot contain the new record, copy out first. */
	if (off + len > sizeof(buf)) {
		r = sys_safecopyto(m_in.m_source, m_in.REQ_GRANT,
			user_off, (vir_bytes) buf, off, D);

		if (r != OK) {
			put_inode(child);

			return r;
		}

		user_off += off;
		user_left -= off;
		off = 0;
	}

	/* Fill in the actual directory entry. */
	dent = (struct dirent *) &buf[off];
	dent->d_ino = INODE_NR(child);
	dent->d_off = pos;
	dent->d_reclen = len;
	strcpy(dent->d_name, name);

	off += len;

	put_inode(child);
  }

  /* If there is anything left in our own buffer, copy that out now. */
  if (off > 0) {
	r = sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, user_off,
		(vir_bytes) buf, off, D);

	if (r != OK)
		return r;

	user_off += off;
  }

  m_out.RES_SEEK_POS_HI = 0;
  m_out.RES_SEEK_POS_LO = pos;
  m_out.RES_NBYTES = user_off;

  return OK;
}
Exemple #7
0
int mkfs(struct filesys *fs, dev_t dev)
{
	struct superblock *sb;
	struct block_device *bdev;
	int i, bcount;

	if(!(bdev = blk_open(dev))) {
		return -1;
	}
	fs->bdev = bdev;

	if(!(sb = malloc(BLKSZ))) {
		blk_close(bdev);
		return -1;
	}
	fs->sb = sb;

	/* populate the superblock */
	sb->magic = MAGIC;
	sb->ver = FS_VER;
	sb->blksize = BLKSZ;

	sb->num_blocks = bdev->size;
	sb->num_inodes = sb->num_blocks / 4;

	/* inode bitmap just after the superblock */
	sb->ibm_start = 2;
	sb->ibm_count = (sb->num_inodes + BLKBITS - 1) / BLKBITS;
	/* also allocate and initialize in-memory inode bitmap */
	sb->ibm = malloc(sb->ibm_count * BLKSZ);
	assert(sb->ibm);
	memset(sb->ibm, 0, sb->ibm_count * BLKSZ);

	/* XXX mark inode 0 as used always */
	BM_SET(sb->ibm, 0);

	/* block bitmap just after the inode bitmap */
	sb->bm_start = sb->ibm_start + sb->ibm_count;
	sb->bm_count = (sb->num_blocks + BLKBITS - 1) / BLKBITS;
	/* also allocate and initialize in-memory block bitmap */
	sb->bm = malloc(sb->bm_count * BLKSZ);
	assert(sb->bm);
	memset(sb->bm, 0, sb->bm_count * BLKSZ);

	/* inode table, just after the block bitmap */
	sb->itbl_start = sb->bm_start + sb->bm_count;
	sb->itbl_count = (sb->num_inodes * sizeof(struct inode) + BLKSZ - 1) / BLKSZ;

	/* mark all used blocks as used */
	bcount = sb->itbl_start + sb->itbl_count;
	memset(sb->bm, 0xff, bcount / 8);
	for(i=0; i<bcount % 8; i++) {
		int bit = bcount / 8 + i;
		BM_SET(sb->bm, bit);
	}

	/* create the root directory */
	sb->root = newdir(fs, 0);
	sb->root_ino = sb->root->ino;
	/* and write the inode to disk */
	put_inode(fs, sb->root);

	return 0;
}
Exemple #8
0
int searchdir(const char *name)
{
    struct inode *inode = NULL;
    struct inode *parent = NULL;
    struct file *file;
    char *pathbuf = NULL;
    char *part, *p, echar;
    int symlink_count = MAX_SYMLINK_CNT;

    dprintf("searchdir: %s  root: %p  cwd: %p\n",
	    name, this_fs->root, this_fs->cwd);

    if (!(file = alloc_file()))
	goto err_no_close;
    file->fs = this_fs;

    /* if we have ->searchdir method, call it */
    if (file->fs->fs_ops->searchdir) {
	file->fs->fs_ops->searchdir(name, file);

	if (file->inode)
	    return file_to_handle(file);
	else
	    goto err;
    }

    /* else, try the generic-path-lookup method */

    parent = get_inode(this_fs->cwd);
    p = pathbuf = strdup(name);
    if (!pathbuf)
	goto err;

    do {
    got_link:
	if (*p == '/') {
	    put_inode(parent);
	    parent = get_inode(this_fs->root);
	}

	do {
	    inode = get_inode(parent);

	    while (*p == '/')
		p++;

	    if (!*p)
		break;

	    part = p;
	    while ((echar = *p) && echar != '/')
		p++;
	    *p++ = '\0';

	    if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {
		if (inode->parent) {
		    put_inode(parent);
		    parent = get_inode(inode->parent);
		    put_inode(inode);
		    inode = NULL;
		    if (!echar) {
			/* Terminal double dots */
			inode = parent;
			parent = inode->parent ?
			    get_inode(inode->parent) : NULL;
		    }
		}
	    } else if (part[0] != '.' || part[1] != '\0') {
		inode = this_fs->fs_ops->iget(part, parent);
		if (!inode)
		    goto err;
		if (inode->mode == DT_LNK) {
		    char *linkbuf, *q;
		    int name_len = echar ? strlen(p) : 0;
		    int total_len = inode->size + name_len + 2;
		    int link_len;

		    if (!this_fs->fs_ops->readlink ||
			--symlink_count == 0       ||      /* limit check */
			total_len > MAX_SYMLINK_BUF)
			goto err;

		    linkbuf = malloc(total_len);
		    if (!linkbuf)
			goto err;

		    link_len = this_fs->fs_ops->readlink(inode, linkbuf);
		    if (link_len <= 0) {
			free(linkbuf);
			goto err;
		    }

		    q = linkbuf + link_len;

		    if (echar) {
			if (link_len > 0 && q[-1] != '/')
			    *q++ = '/';

			memcpy(q, p, name_len+1);
		    } else {
			*q = '\0';
		    }

		    free(pathbuf);
		    p = pathbuf = linkbuf;
		    put_inode(inode);
		    inode = NULL;
		    goto got_link;
		}

		inode->name = strdup(part);
		dprintf("path component: %s\n", inode->name);

		inode->parent = parent;
		parent = NULL;

		if (!echar)
		    break;

		if (inode->mode != DT_DIR)
		    goto err;

		parent = inode;
		inode = NULL;
	    }
	} while (echar);
    } while (0);

    free(pathbuf);
    pathbuf = NULL;
    put_inode(parent);
    parent = NULL;

    if (!inode)
	goto err;

    file->inode  = inode;
    file->offset = 0;

    return file_to_handle(file);

err:
    put_inode(inode);
    put_inode(parent);
    if (pathbuf)
	free(pathbuf);
    _close_file(file);
err_no_close:
    return -1;
}
Exemple #9
0
/*===========================================================================*
 *				fs_link 				     *
 *===========================================================================*/
int fs_link()
{
/* Perform the link(name1, name2) system call. */

  struct inode *ip, *rip;
  register int r;
  char string[MFS_NAME_MAX];
  struct inode *new_ip;
  phys_bytes len;

  len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(string));
  /* Copy the link name's last component */
  r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
  		       (vir_bytes) 0, (vir_bytes) string, (size_t) len);
  if (r != OK) return r;
  NUL(string, len, sizeof(string));
  
  /* Temporarily open the file. */
  if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
	  return(EINVAL);
  
  /* Check to see if the file has maximum number of links already. */
  r = OK;
  if(rip->i_nlinks >= LINK_MAX)
	  r = EMLINK;

  /* Only super_user may link to directories. */
  if(r == OK)
	  if( (rip->i_mode & I_TYPE) == I_DIRECTORY && caller_uid != SU_UID) 
		  r = EPERM;

  /* If error with 'name', return the inode. */
  if (r != OK) {
	  put_inode(rip);
	  return(r);
  }

  /* Temporarily open the last dir */
  if( (ip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_DIR_INO)) == NULL) {
	put_inode(rip);
	return(EINVAL);
  }

  if (ip->i_nlinks == NO_LINK) {	/* Dir does not actually exist */
  	put_inode(rip);
	put_inode(ip);
  	return(ENOENT);
  }

  /* If 'name2' exists in full (even if no space) set 'r' to error. */
  if((new_ip = advance(ip, string, IGN_PERM)) == NULL) {
	  r = err_code;
	  if(r == ENOENT)
		  r = OK;
  } else {
	  put_inode(new_ip);
	  r = EEXIST;
  }
  
  /* Try to link. */
  if(r == OK)
	  r = search_dir(ip, string, &rip->i_num, ENTER, IGN_PERM);

  /* If success, register the linking. */
  if(r == OK) {
	  rip->i_nlinks++;
	  rip->i_update |= CTIME;
	  IN_MARKDIRTY(rip);
  }
  
  /* Done.  Release both inodes. */
  put_inode(rip);
  put_inode(ip);
  return(r);
}
Exemple #10
0
static int file_block(struct filesys *fs, struct inode *node, int boffs, int allocate)
{
	int res, idx, node_dirty = 0;
	blkid *barr;

	/* out of bounds */
	if(boffs < 0 || boffs >= MAX_DIND) {
		return 0;
	}

	/* is it a direct block ? */
	if(boffs < NDIRBLK) {
		if(!(res = node->blk[boffs]) && allocate) {
			res = node->blk[boffs] = alloc_block(fs);
			if(res) {
				zero_block(fs, res);
				/* also write back the modified inode */
				put_inode(fs, node);
			}
		}
		return res;
	}

	barr = malloc(fs->sb->blksize);
	assert(barr);

	/* is it an indirect block ? */
	if(boffs < MAX_IND) {
		int ind_dirty = 0;

		if(node->ind) {
			/* read the indirect block */
			blk_read(fs->bdev, node->ind, 1, barr);
		} else {
			/* does not exist... try to allocate if requested */
			if(!allocate || !(node->ind = alloc_block(fs))) {
				res = 0;
				goto end;
			}

			/* allocated a block clear the buffer, and invalidate everything */
			memset(barr, 0, sizeof fs->sb->blksize);
			node_dirty = 1;
			ind_dirty = 1;
		}

		idx = boffs - NDIRBLK;

		if(!(res = barr[idx])) {
			if(allocate && (res = barr[idx] = alloc_block(fs))) {
				ind_dirty = 1;
			}
		}

		/* write back the indirect block if needed */
		if(ind_dirty) {
			blk_write(fs->bdev, node->ind, 1, barr);
		}
		goto end;
	}

	/* TODO check/rewrite this */
#if 0
	/* is it a double-indirect block ? */
	if(boffs < MAX_DIND) {
		/* first read the dind block and find the index of the ind block */
		if(!node->dind) {
			if(allocate) {
				/* allocate and zero-out the double indirect block */
				res = node->dind = alloc_block(fs);
				if(res) {
					zero_block(fs, res);
				}
			} else {
				res = 0;
				goto end;
			}
		}
		blk_read(fd->bdev, node->dind, 1, barr);
		idx = (boffs - MAX_IND) / BLK_BLKID;

		/* then read the ind block and find the index of the block */
		if(!barr[idx]) {
			res = 0;
			goto end;
		}
		blk_read(fd->bdev, barr[idx], 1, barr);
		res = barr[(boffs - MAX_IND) % BLK_BLKID];
	}
#endif

end:
	if(node_dirty) {
		put_inode(fs, node);
	}
	free(barr);
	return res;
}
Exemple #11
0
/**
 * Remove a file.
 *
 * @note We clear the i-node in inode_array[] although it is not really needed.
 *       We don't clear the data bytes so the file is recoverable.
 * 
 * @return On success, zero is returned.  On error, -1 is returned.
 *****************************************************************************/
PUBLIC int do_unlink()
{
	char pathname[MAX_PATH];

	/* get parameters from the message */
	int name_len = fs_msg.NAME_LEN;	/* length of filename */
	int src = fs_msg.source;	/* caller proc nr. */
	assert(name_len < MAX_PATH);
	phys_copy((void*)va2la(TASK_FS, pathname),
		  (void*)va2la(src, fs_msg.PATHNAME),
		  name_len);
	pathname[name_len] = 0;

	if (strcmp(pathname , "/") == 0) {
		printl("FS:do_unlink():: cannot unlink the root\n");
		return -1;
	}

	int inode_nr = search_file(pathname);
	if (inode_nr == INVALID_INODE) {	/* file not found */
		printl("FS::do_unlink():: search_file() returns "
			"invalid inode: %s\n", pathname);
		return -1;
	}

	char filename[MAX_PATH];
	struct inode * dir_inode;
	if (strip_path(filename, pathname, &dir_inode) != 0)
		return -1;

	struct inode * pin = get_inode(dir_inode->i_dev, inode_nr);

	if (pin->i_mode != I_REGULAR) { /* can only remove regular files */
		printl("cannot remove file %s, because "
		       "it is not a regular file.\n",
		       pathname);
		return -1;
	}

	if (pin->i_cnt > 1) {	/* the file was opened */
		printl("cannot remove file %s, because pin->i_cnt is %d.\n",
		       pathname, pin->i_cnt);
		return -1;
	}

	struct super_block * sb = get_super_block(pin->i_dev);

	/*************************/
	/* free the bit in i-map */
	/*************************/
	int byte_idx = inode_nr / 8;
	int bit_idx = inode_nr % 8;
	assert(byte_idx < SECTOR_SIZE);	/* we have only one i-map sector */
	/* read sector 2 (skip bootsect and superblk): */
	RD_SECT(pin->i_dev, 2);
	assert(fsbuf[byte_idx % SECTOR_SIZE] & (1 << bit_idx));
	fsbuf[byte_idx % SECTOR_SIZE] &= ~(1 << bit_idx);
	WR_SECT(pin->i_dev, 2);

	/**************************/
	/* free the bits in s-map */
	/**************************/
	/*
	 *           bit_idx: bit idx in the entire i-map
	 *     ... ____|____
	 *                  \        .-- byte_cnt: how many bytes between
	 *                   \      |              the first and last byte
	 *        +-+-+-+-+-+-+-+-+ V +-+-+-+-+-+-+-+-+
	 *    ... | | | | | |*|*|*|...|*|*|*|*| | | | |
	 *        +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
	 *         0 1 2 3 4 5 6 7     0 1 2 3 4 5 6 7
	 *  ...__/
	 *      byte_idx: byte idx in the entire i-map
	 */
	bit_idx  = pin->i_start_sect - sb->n_1st_sect + 1;
	byte_idx = bit_idx / 8;
	int bits_left = pin->i_nr_sects;
	int byte_cnt = (bits_left - (8 - (bit_idx % 8))) / 8;

	/* current sector nr. */
	int s = 2  /* 2: bootsect + superblk */
		+ sb->nr_imap_sects + byte_idx / SECTOR_SIZE;

	RD_SECT(pin->i_dev, s);

	int i;
	/* clear the first byte */
	for (i = bit_idx % 8; (i < 8) && bits_left; i++,bits_left--) {
		//assert((fsbuf[byte_idx % SECTOR_SIZE] >> i & 1) == 1);
		fsbuf[byte_idx % SECTOR_SIZE] &= ~(1 << i);
	}

	/* clear bytes from the second byte to the second to last */
	int k;
	i = (byte_idx % SECTOR_SIZE) + 1;	/* the second byte */
	for (k = 0; k < byte_cnt; k++,i++,bits_left-=8) {
		if (i == SECTOR_SIZE) {
			i = 0;
			WR_SECT(pin->i_dev, s);
			RD_SECT(pin->i_dev, ++s);
		}
		//assert(fsbuf[i] == 0xFF);
		fsbuf[i] = 0;
	}

	/* clear the last byte */
	if (i == SECTOR_SIZE) {
		i = 0;
		WR_SECT(pin->i_dev, s);
		RD_SECT(pin->i_dev, ++s);
	}
	unsigned char mask = ~((unsigned char)(~0) << bits_left);
	//assert((fsbuf[i] & mask) == mask);
	fsbuf[i] &= (~0) << bits_left;
	WR_SECT(pin->i_dev, s);

	/***************************/
	/* clear the i-node itself */
	/***************************/
	pin->i_mode = 0;
	pin->i_size = 0;
	pin->i_start_sect = 0;
	pin->i_nr_sects = 0;
	sync_inode(pin);
	/* release slot in inode_table[] */
	put_inode(pin);

	/************************************************/
	/* set the inode-nr to 0 in the directory entry */
	/************************************************/
	int dir_blk0_nr = dir_inode->i_start_sect;
	int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE;
	int nr_dir_entries =
		dir_inode->i_size / DIR_ENTRY_SIZE; /* including unused slots
						     * (the file has been
						     * deleted but the slot
						     * is still there)
						     */
	int m = 0;
	struct dir_entry * pde = 0;
	int flg = 0;
	int dir_size = 0;

	for (i = 0; i < nr_dir_blks; i++) {
		RD_SECT(dir_inode->i_dev, dir_blk0_nr + i);

		pde = (struct dir_entry *)fsbuf;
		int j;
		for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) {
			if (++m > nr_dir_entries)
				break;

			if (pde->inode_nr == inode_nr) {
				/* pde->inode_nr = 0; */
				memset(pde, 0, DIR_ENTRY_SIZE);
				WR_SECT(dir_inode->i_dev, dir_blk0_nr + i);
				flg = 1;
				break;
			}

			if (pde->inode_nr != INVALID_INODE)
				dir_size += DIR_ENTRY_SIZE;
		}

		if (m > nr_dir_entries || /* all entries have been iterated OR */
		    flg) /* file is found */
			break;
	}
	assert(flg);
	if (m == nr_dir_entries) { /* the file is the last one in the dir */
		dir_inode->i_size = dir_size;
		sync_inode(dir_inode);
	}

	return 0;
}
Exemple #12
0
/*===========================================================================*
 *				fs_link 				     *
 *===========================================================================*/
int fs_link(ino_t dir_nr, char *name, ino_t ino_nr)
{
    /* Perform the link(name1, name2) system call. */

    struct inode *ip, *rip;
    register int r;
    struct inode *new_ip;

    /* Temporarily open the file. */
    if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
        return(EINVAL);

    /* Check to see if the file has maximum number of links already. */
    r = OK;
    if (rip->i_links_count >= USHRT_MAX)
        r = EMLINK;
    if(rip->i_links_count >= LINK_MAX)
        r = EMLINK;

    /* Linking to directories is too dangerous to allow. */
    if(r == OK)
        if( (rip->i_mode & I_TYPE) == I_DIRECTORY)
            r = EPERM;

    /* If error with 'name', return the inode. */
    if (r != OK) {
        put_inode(rip);
        return(r);
    }

    /* Temporarily open the last dir */
    if( (ip = get_inode(fs_dev, dir_nr)) == NULL) {
        put_inode(rip);
        return(EINVAL);
    }

    if (ip->i_links_count == NO_LINK) {	/* Dir does not actually exist */
        put_inode(rip);
        put_inode(ip);
        return(ENOENT);
    }

    /* If 'name2' exists in full (even if no space) set 'r' to error. */
    if ((new_ip = advance(ip, name)) == NULL) {
        r = err_code;
        if(r == ENOENT)
            r = OK;
    } else {
        put_inode(new_ip);
        r = EEXIST;
    }

    /* Try to link. */
    if(r == OK)
        r = search_dir(ip, name, &rip->i_num, ENTER, rip->i_mode & I_TYPE);

    /* If success, register the linking. */
    if(r == OK) {
        rip->i_links_count++;
        rip->i_update |= CTIME;
        rip->i_dirt = IN_DIRTY;
    }

    /* Done.  Release both inodes. */
    put_inode(rip);
    put_inode(ip);
    return(r);
}
Exemple #13
0
void dir_test(){
    struct inode* root_inode;
    struct inode *rip;
    char string[DIRSIZ];
    int number;
    int * inode_num = & number;
    int r;

    root_inode = get_inode(1);
    if(root_inode == NIL_INODE){
        printf("root_inode is a null inode\n");
        return;
    }
    /* printf("root_inode size is %d\n", root_inode->i_size); */
    /* delete_dir(root_inode, 0); */
    /* empty_inode_space(root_inode); */
    /* put_inode(root_inode); */
    /* return; */

    /* my_strcpy(string, "usr"); */
    /* if( r = search_dir(root_inode, string, inode_num, LOOK_UP) != OK){ */
        /* printf("LOOK_UP a usr error: %s\n", strerror(r)); */
        /* put_inode(root_inode); */
        /* return; */
    /* } */
    /* printf("this time i node size is %d\n", root_inode->i_size); */
    /* put_inode(root_inode); */
    /* return; */

    my_strcpy(string, "..");
    *inode_num = root_inode->i_num;
    if (r = search_dir(root_inode, string, inode_num, ENTER) != OK){
        printf("enter a item error: %s\n", strerror(r));
        put_inode(root_inode);
        return;
    }
    my_strcpy(string, ".");
    *inode_num = root_inode->i_num;
    if (r = search_dir(root_inode, string, inode_num, ENTER) != OK){
        printf("enter a item error: %s\n", strerror(r));
        put_inode(root_inode);
        return;
    }
    root_inode->i_dirt = DIRTY;
    put_inode(root_inode);
    show_file_list();
    /* return; */
    printf("\n");

    my_strcpy(string, ".");
    root_inode = get_inode(1);
    *inode_num = 0;
    if (r = search_dir(root_inode, string, inode_num, LOOK_UP) != OK){
        printf("find a item error: %s\n", strerror(r));
        put_inode(root_inode);
        return;
    }
    if(*inode_num != root_inode->i_num){
        printf("can't find . in the root directory!!!\n");
        put_inode(root_inode);
        return;
    }
    put_inode(root_inode);

    my_mkdir("./usr");
    my_mkdir("src");
    my_mkdir("../root");
    show_file_list();
    printf("\n");

    root_inode = last_dir("./../usr", string);
    if(root_inode == NIL_INODE){
        printf("last_dir error: can't find root dir\n");
        return;
    }
    if(root_inode->i_num != 1){
        printf("this time last dir is not root_inode, it's i_num is %d\n", root_inode->i_num);
        put_inode(root_inode);
        return;
    }
    printf("string remain is %s\n", string);
    show_file_list();
    printf("\n");
    rip = advance(root_inode, string);
    if(rip == NIL_INODE){
        printf("advance error: can't find usr dir\n");
        return;
    }
    show_file_list();
    printf("\n");
    put_inode(rip);
    put_inode(root_inode);

    if(my_rmdir("/src") != OK){
        printf("can't remove dir src\n");
        return;
    }
    show_file_list();
}
/*===========================================================================*
 *                             do_slink					     *
 *===========================================================================*/
PUBLIC int do_slink()
{
/* Perform the symlink(name1, name2) system call. */

  register int r;              /* error code */
  char string[NAME_MAX];       /* last component of the new dir's path name */
  struct inode *sip;           /* inode containing symbolic link */
  struct buf *bp;              /* disk buffer for link */
  struct inode *ldirp;         /* directory containing link */

  if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK)
       return(err_code);

  if (m_in.name1_length <= 1 || m_in.name1_length >= _MIN_BLOCK_SIZE)
       return(ENAMETOOLONG);

  /* Create the inode for the symlink. */
  sip = new_node(&ldirp, user_path, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
                 (zone_t) 0, TRUE, string);

  /* Allocate a disk block for the contents of the symlink.
   * Copy contents of symlink (the name pointed to) into first disk block.
   */
  if ((r = err_code) == OK) {
       r = (bp = new_block(sip, (off_t) 0)) == NIL_BUF
           ? err_code
           : sys_vircopy(who_e, D, (vir_bytes) m_in.name1,
                       SELF, D, (vir_bytes) bp->b_data,
		       (vir_bytes) m_in.name1_length-1);

	if(r == OK) {
		bp->b_data[_MIN_BLOCK_SIZE-1] = '\0';
		sip->i_size = strlen(bp->b_data);
		if(sip->i_size != m_in.name1_length-1) {
			/* This can happen if the user provides a buffer
			 * with a \0 in it. This can cause a lot of trouble
			 * when the symlink is used later. We could just use
			 * the strlen() value, but we want to let the user
			 * know he did something wrong. ENAMETOOLONG doesn't
			 * exactly describe the error, but there is no
			 * ENAMETOOWRONG.
			 */
			r = ENAMETOOLONG;
		}
	}
  
       put_block(bp, DIRECTORY_BLOCK); 	/* put_block() accepts NIL_BUF. */
  
       if (r != OK) {
               sip->i_nlinks = 0;
               if (search_dir(ldirp, string, (ino_t *) 0, DELETE) != OK)
                       panic(__FILE__, "Symbolic link vanished", NO_NUM);
       } 
  }

  /* put_inode() accepts NIL_INODE as a noop, so the below are safe. */
  put_inode(sip);
  put_inode(ldirp);

  return(r);
}
Exemple #15
0
/*===========================================================================*
 *                             fs_slink 				     *
 *===========================================================================*/
PUBLIC int fs_slink()
{
  phys_bytes len;
  struct inode *sip;           /* inode containing symbolic link */
  struct inode *ldirp;         /* directory containing link */
  register int r;              /* error code */
  char string[MFS_NAME_MAX];       /* last component of the new dir's path name */
  struct buf *bp;              /* disk buffer for link */
    
  caller_uid = (uid_t) fs_m_in.REQ_UID;
  caller_gid = (gid_t) fs_m_in.REQ_GID;
  
  /* Copy the link name's last component */
  len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(string));
  r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
  			(vir_bytes) 0, (vir_bytes) string, (size_t) len, D);
  if (r != OK) return(r);
  NUL(string, len, sizeof(string));
  
  /* Temporarily open the dir. */
  if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
	  return(EINVAL);

  /* Create the inode for the symlink. */
  sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
		   (zone_t) 0);

  /* Allocate a disk block for the contents of the symlink.
   * Copy contents of symlink (the name pointed to) into first disk block. */
  if( (r = err_code) == OK) {
  	bp = new_block(sip, (off_t) 0);
  	if (bp == NULL)
  		r = err_code;
  	else
  		r = sys_safecopyfrom(VFS_PROC_NR,
  				     (cp_grant_id_t) fs_m_in.REQ_GRANT3,
				     (vir_bytes) 0, (vir_bytes) bp->b_data,
				     (size_t) fs_m_in.REQ_MEM_SIZE, D);

	if(bp != NULL && r == OK) {
		bp->b_data[_MIN_BLOCK_SIZE-1] = '\0';
		sip->i_size = (off_t) strlen(bp->b_data);
		if(sip->i_size != fs_m_in.REQ_MEM_SIZE) {
			/* This can happen if the user provides a buffer
			 * with a \0 in it. This can cause a lot of trouble
			 * when the symlink is used later. We could just use
			 * the strlen() value, but we want to let the user
			 * know he did something wrong. ENAMETOOLONG doesn't
			 * exactly describe the error, but there is no
			 * ENAMETOOWRONG.
			 */
			r = ENAMETOOLONG;
		}
	}
	  
	put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NULL. */
  
	if(r != OK) {
		sip->i_nlinks = NO_LINK;
		if(search_dir(ldirp, string, NULL, DELETE, IGN_PERM) != OK)
			  panic("Symbolic link vanished");
	} 
  }

  /* put_inode() accepts NULL as a noop, so the below are safe. */
  put_inode(sip);
  put_inode(ldirp);
  
  return(r);
}
/*===========================================================================*
 *				common_open				     *
 *===========================================================================*/
PRIVATE int common_open(register int oflags, mode_t omode)
{
/* Common code from do_creat and do_open. */

  struct inode *rip, *ldirp;
  int r, b, exist = TRUE;
  dev_t dev;
  mode_t bits;
  off_t pos;
  struct filp *fil_ptr, *filp2;

  /* Remap the bottom two bits of oflags. */
  bits = (mode_t) mode_map[oflags & O_ACCMODE];

  /* See if file descriptor and filp slots are available. */
  if ( (r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r);

  /* If O_CREATE is set, try to make the file. */ 
  if (oflags & O_CREAT) {
  	/* Create a new inode by calling new_node(). */
        omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask);
    	rip = new_node(&ldirp, user_path, omode, NO_ZONE, oflags&O_EXCL, NULL);
    	r = err_code;
        put_inode(ldirp);
    	if (r == OK) exist = FALSE;      /* we just created the file */
	else if (r != EEXIST) return(r); /* other error */
	else exist = !(oflags & O_EXCL); /* file exists, if the O_EXCL 
					    flag is set this is an error */
  } else {
	 /* Scan path name. */
    	if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
  }

  /* Claim the file descriptor and filp slot and fill them in. */
  fp->fp_filp[m_in.fd] = fil_ptr;
  FD_SET(m_in.fd, &fp->fp_filp_inuse);
  fil_ptr->filp_count = 1;
  fil_ptr->filp_ino = rip;
  fil_ptr->filp_flags = oflags;

  /* Only do the normal open code if we didn't just create the file. */
  if (exist) {
  	/* Check protections. */
  	if ((r = forbidden(rip, bits)) == OK) {
  		/* Opening reg. files directories and special files differ. */
	  	switch (rip->i_mode & I_TYPE) {
    		   case I_REGULAR: 
			/* Truncate regular file if O_TRUNC. */
			if (oflags & O_TRUNC) {
				if ((r = forbidden(rip, W_BIT)) !=OK) break;
				truncate_inode(rip, 0);
				wipe_inode(rip);
				/* Send the inode from the inode cache to the
				 * block cache, so it gets written on the next
				 * cache flush.
				 */
				rw_inode(rip, WRITING);
			}
			break;
 
	    	   case I_DIRECTORY: 
			/* Directories may be read but not written. */
			r = (bits & W_BIT ? EISDIR : OK);
			break;

	     	   case I_CHAR_SPECIAL:
     		   case I_BLOCK_SPECIAL:
			/* Invoke the driver for special processing. */
			dev = (dev_t) rip->i_zone[0];
			r = dev_open(dev, who_e, bits | (oflags & ~O_ACCMODE));
			break;

		   case I_NAMED_PIPE:
			oflags |= O_APPEND;	/* force append mode */
			fil_ptr->filp_flags = oflags;
			r = pipe_open(rip, bits, oflags);
			if (r != ENXIO) {
				/* See if someone else is doing a rd or wt on
				 * the FIFO.  If so, use its filp entry so the
				 * file position will be automatically shared.
				 */
				b = (bits & R_BIT ? R_BIT : W_BIT);
				fil_ptr->filp_count = 0; /* don't find self */
				if ((filp2 = find_filp(rip, b)) != NIL_FILP) {
					/* Co-reader or writer found. Use it.*/
					fp->fp_filp[m_in.fd] = filp2;
					filp2->filp_count++;
					filp2->filp_ino = rip;
					filp2->filp_flags = oflags;

					/* i_count was incremented incorrectly
					 * by eatpath above, not knowing that
					 * we were going to use an existing
					 * filp entry.  Correct this error.
					 */
					rip->i_count--;
				} else {
					/* Nobody else found.  Restore filp. */
					fil_ptr->filp_count = 1;
					if (b == R_BIT)
					     pos = rip->i_zone[V2_NR_DZONES+0];
					else
					     pos = rip->i_zone[V2_NR_DZONES+1];
					fil_ptr->filp_pos = pos;
				}
			}
			break;
 		}
  	}
  }

  /* If error, release inode. */
  if (r != OK) {
	if (r == SUSPEND) return(r);		/* Oops, just suspended */
	fp->fp_filp[m_in.fd] = NIL_FILP;
  	FD_CLR(m_in.fd, &fp->fp_filp_inuse);
	fil_ptr->filp_count= 0;
	put_inode(rip);
	return(r);
  }
  
  return(m_in.fd);
}
Exemple #17
0
/*===========================================================================*
 *				new_node				     *
 *===========================================================================*/
PRIVATE struct inode *new_node(struct inode *ldirp,
	char *string, mode_t bits, zone_t z0)
{
/* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().  
 * In all cases it allocates a new inode, makes a directory entry for it in
 * the ldirp directory with string name, and initializes it.  
 * It returns a pointer to the inode if it can do this; 
 * otherwise it returns NULL.  It always sets 'err_code'
 * to an appropriate value (OK or an error code).
 * 
 * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
 * has to hold at least MFS_NAME_MAX bytes.
 */

  register struct inode *rip;
  register int r;

  if (ldirp->i_nlinks == NO_LINK) {	/* Dir does not actually exist */
  	err_code = ENOENT;
  	return(NULL);
  }

  /* Get final component of the path. */
  rip = advance(ldirp, string, IGN_PERM);

  if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) {
        /* New entry is a directory, alas we can't give it a ".." */
        put_inode(rip);
        err_code = EMLINK;
        return(NULL);
  }

  if ( rip == NULL && err_code == ENOENT) {
	/* Last path component does not exist.  Make new directory entry. */
	if ( (rip = alloc_inode((ldirp)->i_dev, bits)) == NULL) {
		/* Can't creat new inode: out of inodes. */
		return(NULL);
	}

	/* Force inode to the disk before making directory entry to make
	 * the system more robust in the face of a crash: an inode with
	 * no directory entry is much better than the opposite.
	 */
	rip->i_nlinks++;
	rip->i_zone[0] = z0;		/* major/minor device numbers */
	rw_inode(rip, WRITING);		/* force inode to disk now */

	/* New inode acquired.  Try to make directory entry. */
	if((r=search_dir(ldirp, string, &rip->i_num, ENTER, IGN_PERM)) != OK) {
		rip->i_nlinks--;	/* pity, have to free disk inode */
		rip->i_dirt = DIRTY;	/* dirty inodes are written out */
		put_inode(rip);	/* this call frees the inode */
		err_code = r;
		return(NULL);
	}

  } else if (err_code == EENTERMOUNT || err_code == ELEAVEMOUNT) {
  	r = EEXIST;
  } else { 
	/* Either last component exists, or there is some problem. */
	if (rip != NULL)
		r = EEXIST;
	else
		r = err_code;
  }

  /* The caller has to return the directory inode (*ldirp).  */
  err_code = r;
  return(rip);
}
Exemple #18
0
/*===========================================================================*
 *				fs_readwrite				     *
 *===========================================================================*/
int fs_readwrite(void)
{
  int r, rw_flag;
  block_t b;
  struct buf *bp;
  cp_grant_id_t gid;
  off_t position, f_size;
  unsigned int nrbytes, cum_io;
  mode_t mode_word;
  struct pipe_inode *rip;
  ino_t inumb;

  r = 0;
  cum_io = 0;
  inumb = fs_m_in.REQ_INODE_NR;
  rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING);
#if 0  
  printk("PFS: going to %s inode %d\n", (rw_flag == READING? "read from": "write to"), inumb);
#endif

  /* Find the inode referred */
  if ((rip = find_inode(inumb)) == NIL_INODE) return(-EINVAL);

  mode_word = rip->i_mode & I_TYPE;
  if (mode_word != I_NAMED_PIPE) return(-EIO);
  f_size = rip->i_size;
  
  /* Get the values from the request message */ 
  rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING);
  gid = fs_m_in.REQ_GRANT;
  position = fs_m_in.REQ_SEEK_POS_LO;
  nrbytes = (unsigned) fs_m_in.REQ_NBYTES;
  
  if (rw_flag == WRITING) {
	  /* Check in advance to see if file will grow too big. */
	  if (position > PIPE_BUF - nrbytes) return(-EFBIG);
  }

  /* Mark inode in use */
  if ((get_inode(rip->i_dev, rip->i_num)) == NIL_INODE) return(err_code);
  if ((bp = get_block(rip->i_dev, rip->i_num)) == NIL_BUF) return(err_code);

  if (rw_flag == READING) {
	/* Copy a chunk from the block buffer to user space. */
	r = sys_safecopyto(VFS_PROC_NR, gid, 0,
		(vir_bytes) (bp->b_data+position), (phys_bytes) nrbytes, D);
  } else {
	/* Copy a chunk from user space to the block buffer. */
	r = sys_safecopyfrom(VFS_PROC_NR, gid, 0,
		(vir_bytes) (bp->b_data+position), (phys_bytes) nrbytes, D);
  }

  if (r == 0) {
	position += nrbytes; /* Update position */
	cum_io += nrbytes;
  }

  fs_m_out.RES_SEEK_POS_LO = position; /* It might change later and the VFS
					   has to know this value */
  
  /* On write, update file size and access time. */
  if (rw_flag == WRITING) {
	  if (position > f_size) rip->i_size = position;
  } else {
	if(position >= rip->i_size) {
		/* All data in the pipe is read, so reset pipe pointers */
		rip->i_size = 0;	/* no data left */
		position = 0;		/* reset reader(s) */
	}
  }

  bp->b_bytes = position;
  if (rw_flag == READING) rip->i_update |= ATIME;
  if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
  fs_m_out.RES_NBYTES = cum_io;
  put_inode(rip);
  put_block(rip->i_dev, rip->i_num);

  return(r);
}
Exemple #19
0
int restore_state()
{
   FILE *fp;
   int  i;
   struct hnode t_hnode;         /* Temporary hash nodes */
   struct unode t_unode;
   struct rnode t_rnode;
   struct anode t_anode;
   struct snode t_snode;
   struct inode t_inode;

   char   buffer[BUFSIZE];
   char   tmp_buf[BUFSIZE];

   u_long ul_bogus=0;

   fp=fopen(state_fname,"r");
   if (fp==NULL)
   {
      /* Previous run data not found... */
      if (verbose>1) printf("%s\n",msg_no_data);
      return 0;   /* return with ok code */
   }

   /* Reading previous run data... */
   if (verbose>1) printf("%s %s\n",msg_get_data,state_fname);

   /* get easy stuff */
   sprintf(tmp_buf,"# Webalizer V%s    ",version);
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)                 /* Header record */
     {if (strncmp(buffer,tmp_buf,17)) return 99;} /* bad magic? */
   else return 1;   /* error exit */

   /* Get current timestamp */
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      sscanf(buffer,"%d %d %d %d %d %d",
       &cur_year, &cur_month, &cur_day,
       &cur_hour, &cur_min, &cur_sec);
   } else return 2;  /* error exit */

   /* calculate current timestamp (seconds since epoch) */
   cur_tstamp=((jdate(cur_day,cur_month,cur_year)-epoch)*86400)+
                     (cur_hour*3600)+(cur_min*60)+cur_sec;

   /* Get monthly totals */
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      sscanf(buffer,"%lu %lu %lu %lu %lu %lu %lf %lu %lu %lu",
       &t_hit, &t_file, &t_site, &t_url,
       &t_ref, &t_agent, &t_xfer, &t_page, &t_visit, &t_user);
   } else return 3;  /* error exit */
     
   /* Get daily totals */
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      sscanf(buffer,"%lu %lu %lu %d %d",
       &dt_site, &ht_hit, &mh_hit, &f_day, &l_day);
   } else return 4;  /* error exit */

   /* get daily totals */
   for (i=0;i<31;i++)
   {
      if ((fgets(buffer,BUFSIZE,fp)) != NULL)
      {
         sscanf(buffer,"%lu %lu %lf %lu %lu %lu",
          &tm_hit[i],&tm_file[i],&tm_xfer[i],&tm_site[i],&tm_page[i],
          &tm_visit[i]);
      } else return 5;  /* error exit */
   }

   /* get hourly totals */
   for (i=0;i<24;i++)
   {
      if ((fgets(buffer,BUFSIZE,fp)) != NULL)
      {
         sscanf(buffer,"%lu %lu %lf %lu",
          &th_hit[i],&th_file[i],&th_xfer[i],&th_page[i]);
      } else return 6;  /* error exit */
   }

   /* get response code totals */
   for (i=0;i<TOTAL_RC;i++)
   {
      if ((fgets(buffer,BUFSIZE,fp)) != NULL)
         sscanf(buffer,"%lu",&response[i].count);
      else return 7;  /* error exit */
   }

   /* Kludge for V2.01-06 TOTAL_RC off by one bug */
   if (!strncmp(buffer,"# -urls- ",9)) response[TOTAL_RC-1].count=0;
   else
   {
      /* now do hash tables */

      /* url table */
      if ((fgets(buffer,BUFSIZE,fp)) != NULL)            /* Table header */
      { if (strncmp(buffer,"# -urls- ",9)) return 10; }  /* (url)        */
      else return 10;   /* error exit */
   }

   while ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      if (!strncmp(buffer,"# End Of Table ",15)) break;
      strncpy(tmp_buf,buffer,MAXURLH);
      tmp_buf[strlen(tmp_buf)-1]=0;

      if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 10;  /* error exit */
      if (!isdigit((int)buffer[0])) return 10;  /* error exit */

      /* load temporary node data */
      sscanf(buffer,"%d %lu %lu %lf %lu %lu",
         &t_unode.flag,&t_unode.count,
         &t_unode.files, &t_unode.xfer,
         &t_unode.entry, &t_unode.exit);

      /* Good record, insert into hash table */
      if (put_unode(tmp_buf,t_unode.flag,t_unode.count,
         t_unode.xfer,&ul_bogus,t_unode.entry,t_unode.exit,um_htab))
      {
         if (verbose)
         /* Error adding URL node, skipping ... */
         fprintf(stderr,"%s %s\n", msg_nomem_u, t_unode.string);
      }
   }

   /* monthly sites table */
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)               /* Table header */
   { if (strncmp(buffer,"# -sites- ",10)) return 8; }    /* (monthly)    */
   else return 8;   /* error exit */

   while ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      /* Check for end of table */
      if (!strncmp(buffer,"# End Of Table ",15)) break;
      strncpy(tmp_buf,buffer,MAXHOST);
      tmp_buf[strlen(buffer)-1]=0;

      if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 8;  /* error exit */
      if (!isdigit((int)buffer[0])) return 8;  /* error exit */

      /* load temporary node data */
      sscanf(buffer,"%d %lu %lu %lf %lu %lu",
         &t_hnode.flag,&t_hnode.count,
         &t_hnode.files, &t_hnode.xfer,
         &t_hnode.visit, &t_hnode.tstamp);

      /* get last url */
      if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 8;  /* error exit */
      if (buffer[0]=='-') t_hnode.lasturl=blank_str;
      else
      {
         buffer[strlen(buffer)-1]=0;
         t_hnode.lasturl=find_url(buffer);
      }

      /* Good record, insert into hash table */
      if (put_hnode(tmp_buf,t_hnode.flag,
         t_hnode.count,t_hnode.files,t_hnode.xfer,&ul_bogus,
         t_hnode.visit+1,t_hnode.tstamp,t_hnode.lasturl,sm_htab))
      {
         /* Error adding host node (monthly), skipping .... */
         if (verbose) fprintf(stderr,"%s %s\n",msg_nomem_mh, t_hnode.string);
      }
   }

   /* Daily sites table */
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)               /* Table header */
   { if (strncmp(buffer,"# -sites- ",10)) return 9; }    /* (daily)      */
   else return 9;   /* error exit */

   while ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      /* Check for end of table */
      if (!strncmp(buffer,"# End Of Table ",15)) break;
      strncpy(tmp_buf,buffer,MAXHOST);
      tmp_buf[strlen(buffer)-1]=0;

      if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 9;  /* error exit */
      if (!isdigit((int)buffer[0])) return 9;  /* error exit */

      /* load temporary node data */
      sscanf(buffer,"%d %lu %lu %lf %lu %lu",
          &t_hnode.flag,&t_hnode.count,
          &t_hnode.files, &t_hnode.xfer,
          &t_hnode.visit, &t_hnode.tstamp);

      /* get last url */
      if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 9;  /* error exit */
      if (buffer[0]=='-') t_hnode.lasturl=blank_str;
      else
      {
         buffer[strlen(buffer)-1]=0;
         t_hnode.lasturl=find_url(buffer);
      }

      /* Good record, insert into hash table */
      if (put_hnode(tmp_buf,t_hnode.flag,
         t_hnode.count,t_hnode.files,t_hnode.xfer,&ul_bogus,
         t_hnode.visit+1,t_hnode.tstamp,t_hnode.lasturl,sd_htab))
      {
         /* Error adding host node (daily), skipping .... */
         if (verbose) fprintf(stderr,"%s %s\n",msg_nomem_dh, t_hnode.string);
      }
   }

   /* Referrers table */
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)               /* Table header */
   { if (strncmp(buffer,"# -referrers- ",14)) return 11; } /* (referrers)*/
   else return 11;   /* error exit */

   while ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      if (!strncmp(buffer,"# End Of Table ",15)) break;
      strncpy(tmp_buf,buffer,MAXREFH);
      tmp_buf[strlen(buffer)-1]=0;

      if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 11;  /* error exit */
      if (!isdigit((int)buffer[0])) return 11;  /* error exit */

      /* load temporary node data */
      sscanf(buffer,"%d %lu",&t_rnode.flag,&t_rnode.count);

      /* insert node */
      if (put_rnode(tmp_buf,t_rnode.flag,
         t_rnode.count, &ul_bogus, rm_htab))
      {
         if (verbose) fprintf(stderr,"%s %s\n", msg_nomem_r, log_rec.refer);
      }
   }

   /* Agents table */
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)               /* Table header */
   { if (strncmp(buffer,"# -agents- ",11)) return 12; } /* (agents)*/
   else return 12;   /* error exit */

   while ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      if (!strncmp(buffer,"# End Of Table ",15)) break;
      strncpy(tmp_buf,buffer,MAXAGENT);
      tmp_buf[strlen(buffer)-1]=0;

      if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 12;  /* error exit */
      if (!isdigit((int)buffer[0])) return 12;  /* error exit */

      /* load temporary node data */
      sscanf(buffer,"%d %lu",&t_anode.flag,&t_anode.count);

      /* insert node */
      if (put_anode(tmp_buf,t_anode.flag,t_anode.count,
         &ul_bogus,am_htab))
      {
         if (verbose) fprintf(stderr,"%s %s\n", msg_nomem_a, log_rec.agent);
      }
   }

   /* Search Strings table */
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)               /* Table header */
   { if (strncmp(buffer,"# -search string",16)) return 13; }  /* (search)*/
   else return 13;   /* error exit */

   while ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      if (!strncmp(buffer,"# End Of Table ",15)) break;
      strncpy(tmp_buf,buffer,MAXSRCH);
      tmp_buf[strlen(buffer)-1]=0;

      if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 13;  /* error exit */
      if (!isdigit((int)buffer[0])) return 13;  /* error exit */

      /* load temporary node data */
      sscanf(buffer,"%lu",&t_snode.count);

      /* insert node */
      if (put_snode(tmp_buf,t_snode.count,sr_htab))
      {
         if (verbose) fprintf(stderr,"%s %s\n", msg_nomem_sc, t_snode.string);
      }
   }

   /* usernames table */
   if ((fgets(buffer,BUFSIZE,fp)) != NULL)               /* Table header */
   { if (strncmp(buffer,"# -usernames- ",10)) return 14; }
   else return 14;   /* error exit */

   while ((fgets(buffer,BUFSIZE,fp)) != NULL)
   {
      /* Check for end of table */
      if (!strncmp(buffer,"# End Of Table ",15)) break;
      strncpy(tmp_buf,buffer,MAXIDENT);
      tmp_buf[strlen(buffer)-1]=0;

      if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 14;  /* error exit */
      if (!isdigit((int)buffer[0])) return 14;  /* error exit */

      /* load temporary node data */
      sscanf(buffer,"%d %lu %lu %lf %lu %lu",
         &t_inode.flag,&t_inode.count,
         &t_inode.files, &t_inode.xfer,
         &t_inode.visit, &t_inode.tstamp);

      /* Good record, insert into hash table */
      if (put_inode(tmp_buf,t_inode.flag,
         t_inode.count,t_inode.files,t_inode.xfer,&ul_bogus,
         t_inode.visit+1,t_inode.tstamp,im_htab))
      {
         if (verbose)
         /* Error adding username node, skipping .... */
         fprintf(stderr,"%s %s\n",msg_nomem_i, t_inode.string);
      }
   }

   fclose(fp);
   check_dup = 1;              /* enable duplicate checking */
   return 0;                   /* return with ok code       */
}
Exemple #20
0
/*===========================================================================*
 *                             fs_slink 				     *
 *===========================================================================*/
int fs_slink()
{
  phys_bytes len;
  struct inode *sip;           /* inode containing symbolic link */
  struct inode *ldirp;         /* directory containing link */
  register int r;              /* error code */
  char string[NAME_MAX];       /* last component of the new dir's path name */
  char* link_target_buf = NULL;       /* either sip->i_block or bp->b_data */
  struct buf *bp = NULL;    /* disk buffer for link */

  caller_uid = (uid_t) fs_m_in.REQ_UID;
  caller_gid = (gid_t) fs_m_in.REQ_GID;

  /* Copy the link name's last component */
  len = fs_m_in.REQ_PATH_LEN;
  if (len > NAME_MAX || len > EXT2_NAME_MAX)
	return(ENAMETOOLONG);

  r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
		       (vir_bytes) 0, (vir_bytes) string, (size_t) len);
  if (r != OK) return(r);
  NUL(string, len, sizeof(string));

  /* Temporarily open the dir. */
  if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
	  return(EINVAL);

  /* Create the inode for the symlink. */
  sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
		   (block_t) 0);

  /* If we can then create fast symlink (store it in inode),
   * Otherwise allocate a disk block for the contents of the symlink and
   * copy contents of symlink (the name pointed to) into first disk block. */
  if( (r = err_code) == OK) {
	if ( (fs_m_in.REQ_MEM_SIZE + 1) > sip->i_sp->s_block_size) {
		r = ENAMETOOLONG;
	} else if ((fs_m_in.REQ_MEM_SIZE + 1) <= MAX_FAST_SYMLINK_LENGTH) {
		r = sys_safecopyfrom(VFS_PROC_NR,
				     (cp_grant_id_t) fs_m_in.REQ_GRANT3,
				     (vir_bytes) 0, (vir_bytes) sip->i_block,
                                     (vir_bytes) fs_m_in.REQ_MEM_SIZE);
		sip->i_dirt = IN_DIRTY;
		link_target_buf = (char*) sip->i_block;
        } else {
		if ((bp = new_block(sip, (off_t) 0)) != NULL) {
			sys_safecopyfrom(VFS_PROC_NR,
					 (cp_grant_id_t) fs_m_in.REQ_GRANT3,
					 (vir_bytes) 0, (vir_bytes) b_data(bp),
					 (vir_bytes) fs_m_in.REQ_MEM_SIZE);
			lmfs_markdirty(bp);
			link_target_buf = b_data(bp);
		} else {
			r = err_code;
		}
	}
	if (r == OK) {
		assert(link_target_buf);
		link_target_buf[fs_m_in.REQ_MEM_SIZE] = '\0';
		sip->i_size = (off_t) strlen(link_target_buf);
		if (sip->i_size != fs_m_in.REQ_MEM_SIZE) {
			  /* This can happen if the user provides a buffer
			   * with a \0 in it. This can cause a lot of trouble
			   * when the symlink is used later. We could just use
			   * the strlen() value, but we want to let the user
			   * know he did something wrong. ENAMETOOLONG doesn't
			   * exactly describe the error, but there is no
			   * ENAMETOOWRONG.
			   */
			  r = ENAMETOOLONG;
		  }
	}

	put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NULL. */

	if(r != OK) {
		sip->i_links_count = NO_LINK;
		if (search_dir(ldirp, string, NULL, DELETE, IGN_PERM, 0) != OK)
			panic("Symbolic link vanished");
	}
  }

  /* put_inode() accepts NULL as a noop, so the below are safe. */
  put_inode(sip);
  put_inode(ldirp);

  return(r);
}
Exemple #21
0
/*===========================================================================*
 *				fs_readsuper_s				     *
 *===========================================================================*/
PUBLIC int fs_readsuper_s()
{
/* This function reads the superblock of the partition, gets the root inode
 * and sends back the details of them. Note, that the FS process does not
 * know the index of the vmnt object which refers to it, whenever the pathname 
 * lookup leaves a partition an ELEAVEMOUNT error is transferred back 
 * so that the VFS knows that it has to find the vnode on which this FS 
 * process' partition is mounted on.
 */
  struct super_block *xp;
  struct inode *root_ip;
  cp_grant_id_t label_gid;
  size_t label_len;
  int r = OK;
  unsigned long tasknr;
  endpoint_t driver_e;

  fs_dev = fs_m_in.REQ_DEV;

  label_gid= fs_m_in.REQ_GRANT2;
  label_len= fs_m_in.REQ_PATH_LEN;

  if (label_len > sizeof(fs_dev_label))
  {
	printf("mfs:fs_readsuper: label too long\n");
	return EINVAL;
  }

  r= sys_safecopyfrom(fs_m_in.m_source, label_gid, 0, (vir_bytes)fs_dev_label,
	label_len, D);
  if (r != OK)
  {
	printf("mfs:fs_readsuper: safecopyfrom failed: %d\n", r);
	return EINVAL;
  }

  r= ds_retrieve_u32(fs_dev_label, &tasknr);
  if (r != OK)
  {
	printf("mfs:fs_readsuper: ds_retrieve_u32 failed for '%s': %d\n",
		fs_dev_label, r);
	return EINVAL;
  }

  driver_e= tasknr;

  /* Map the driver endpoint for this major */
  driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e =  driver_e;
  use_getuptime2= TRUE;				/* Should be removed with old
						 * getuptime call.
						 */
  vfs_slink_storage = (char *)0xdeadbeef;	/* Should be removed together
						 * with old lookup code.
						 */;

  /* Open the device the file system lives on. */
  if (dev_open(driver_e, fs_dev, driver_e,
	fs_m_in.REQ_READONLY ? R_BIT : (R_BIT|W_BIT)) != OK) {
        return(EINVAL);
  }
  
  /* Fill in the super block. */
  superblock.s_dev = fs_dev;	/* read_super() needs to know which dev */
  r = read_super(&superblock);

  /* Is it recognized as a Minix filesystem? */
  if (r != OK) {
	superblock.s_dev = NO_DEV;
  	dev_close(driver_e, fs_dev);
	return(r);
  }

  set_blocksize(superblock.s_block_size);
  
  /* Get the root inode of the mounted file system. */
  if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NIL_INODE)  {
	printf("MFS: couldn't get root inode?!\n");
	superblock.s_dev = NO_DEV;
  	dev_close(driver_e, fs_dev);
	return EINVAL;
  }
  
  if (root_ip != NIL_INODE && root_ip->i_mode == 0) {
	printf("MFS: zero mode for root inode?!\n");
        put_inode(root_ip);
	superblock.s_dev = NO_DEV;
  	dev_close(driver_e, fs_dev);
  	return EINVAL;
  }

  superblock.s_rd_only = fs_m_in.REQ_READONLY;
  superblock.s_is_root = fs_m_in.REQ_ISROOT;
  
  /* Root inode properties */
  fs_m_out.RES_INODE_NR = root_ip->i_num;
  fs_m_out.RES_MODE = root_ip->i_mode;
  fs_m_out.RES_FILE_SIZE = root_ip->i_size;
  fs_m_out.RES_UID = root_ip->i_uid;
  fs_m_out.RES_GID = root_ip->i_gid;

  return r;
}