Ejemplo n.º 1
0
// Deletes a file.
//
int
unlink(const char *path)
{
	int r;
	struct Inode *dirino, *ino;
	struct Direntry *de;

	if ((r = path_walk(path, &dirino, &de, 0)) < 0)
		goto done;
	if ((r = inode_open(de->de_inum, &ino)) < 0)
		goto closedirino;
	if (ino->i_ftype == FTYPE_DIR) {
		r = -E_IS_DIR;
		goto closeino;
	}
	// clear directory entry
	de->de_inum = 0;
	--ino->i_refcount;
	bcache_ipc(de, BCREQ_FLUSH);
	bcache_ipc(ino, BCREQ_FLUSH);
	r = 0;
 closeino:
	inode_close(ino);
 closedirino:
	inode_close(dirino);
 done:
	return r;
}
Ejemplo n.º 2
0
/* Traverse -- if thread is non-NULL, update the path of the thread */
block_sector_t
path_traverse (char *path, struct thread *t)
{
  char *token, *save_ptr;
  bool found;
  struct dir dir;
  struct dir_entry entry;
  block_sector_t sector;

  if (path == NULL) return thread_get_cwd ();

  /* Check if absolute path */
  if (path[0] == '/')
  {
    sector = free_map_root_sector ();
    path++;
    if (t != NULL) thread_clear_dirs (t);
  } else {
    sector = thread_get_cwd ();
  }

  for (token = strtok_r (path, "/", &save_ptr); token != NULL;
       token = strtok_r (NULL, "/", &save_ptr))
  {
    /* Open the inode for this directory */
    dir.inode = inode_open (sector);
    dir.pos = 0;
    if (dir.inode == NULL || !inode_is_directory (dir.inode))
    {
      sector = INODE_INVALID_BLOCK_SECTOR;
      inode_close (dir.inode);
      break;
    }
    
    /* Make the thread leave the directory if applicable */
    if (t != NULL) 
      thread_leave_dir (t, dir.inode);

    /* Look up in current directory */
    found = lookup (&dir, token, &entry, NULL);
    if (found)
    {
      sector = entry.inode_sector;

      /* Make thread enter the directory if applicable */
      if (t != NULL)
        thread_enter_dir (t, dir.inode);

      inode_close (dir.inode);
    } else {
      sector = INODE_INVALID_BLOCK_SECTOR;
      inode_close (dir.inode);
      break;
    }
  }

  return sector;
}
Ejemplo n.º 3
0
// Walks 'path' down the file system.
// Stores the rightmost directory inode in '*dirino_store',
// and a pointer to the directory entry in '*de_store'.
// For instance, if path == "/a/b/c/hello",
// then '*dirino_store' is the inode for "/a/b/c"
// and '*de_store' points to the embedded directory entry for "hello".
// If 'create != 0', the final directory entry is created if necessary.
//   A newly created entry will have 'de_inum == 0'.  (All real entries have
//   'de_inum != 0'.)
// On success, '*dirino_store' is locked and must be closed with
// inode_close().
//
// Returns 0 on success, < 0 on error.
// Error codes: See dir_find().
//
static int
path_walk(const char *path,
	  struct Inode **dirino_store, struct Direntry **de_store,
	  int create)
{
	int r;
	struct Inode *ino, *next_ino;
	struct Direntry *de;
	const char *component;
	int component_len;

	*dirino_store = 0;
	*de_store = 0;
	if ((r = inode_open(1, &ino)) < 0)
		return r;

	while (1) {
		// Find next path component
		path = path_next_component(path, &component, &component_len);

		// Special case: root directory
		if (component_len == 0) {
			*dirino_store = ino;
			*de_store = &super->s_root;
			return 0;
		}

		// Look up directory component
		// (This is the last path component iff *path == 0.)
		if ((r = dir_find(ino, component, component_len, &de,
				  create && *path == 0)) < 0)
			goto fail;

		// If done, return this direntry
		if (*path == 0) {
			*dirino_store = ino;
			*de_store = de;
			return 0;
		}

		// Otherwise, walk into subdirectory.
		// Always open the next inode before closing the current one.
		if ((r = inode_open(de->de_inum, &next_ino)) < 0)
			goto fail;
		inode_close(ino);
		ino = next_ino;
	}

 fail:
	inode_close(ino);
	return r;
}
Ejemplo n.º 4
0
/* Opens a file for the given INODE, of which it takes ownership,
   and returns the new file.  Returns a null pointer if an
   allocation fails or if INODE is null. */
struct file *
file_open (struct inode *inode) 
{
  struct file *file = calloc (1, sizeof *file);

  if (inode != NULL && file != NULL)
    {
      /* Open the directory if possible. */
      if (inode->data.is_dir)
        {
          struct dir *opened_dir = dir_open (inode);
          ASSERT (opened_dir != NULL);
          file->opened_dir = opened_dir;
        }
      else
        {
          file->opened_dir = NULL;
        }

      file->inode = inode;
      file->pos = 0;
      file->deny_write = false;
      return file;
    }
  else
    {
      inode_close (inode);
      free (file);
      return NULL; 
    }
}
Ejemplo n.º 5
0
/*! Closes FILE. */
void file_close(struct file *file) {
    if (file != NULL) {
        file_allow_write(file);
        inode_close(file->inode);
        free(file); 
    }
}
Ejemplo n.º 6
0
/* Removes any entry for NAME in DIR.
   Returns true if successful, false on failure,
   which occurs only if there is no file with the given NAME. */
bool
dir_remove (struct dir *dir, const char *name) 
{
  struct dir_entry e;
  struct inode *inode = NULL;
  bool success = false;
  off_t ofs;

  ASSERT (dir != NULL);
  ASSERT (name != NULL);

  /* Find directory entry. */
  if (!lookup (dir, name, &e, &ofs))
    goto done;

  /* Open inode. */
  inode = inode_open (e.inode_sector);
  if (inode == NULL)
    goto done;

  /* Erase directory entry. */
  e.in_use = false;
  if (inode_write_at (dir->inode, &e, sizeof e, ofs) != sizeof e) 
    goto done;

  /* Remove inode. */
  inode_remove (inode);
  success = true;

 done:
  inode_close (inode);
  return success;
}
Ejemplo n.º 7
0
/* Open system call. */
static int
sys_open (const char *ufile) 
{
  char *kfile = copy_in_string (ufile);
  struct file_descriptor *fd;
  int handle = -1;
 
  fd = calloc (1, sizeof *fd);
  if (fd != NULL)
    {
      struct inode *inode = filesys_open (kfile);
      if (inode != NULL)
        {
          if (inode_get_type (inode) == FILE_INODE)
            fd->file = file_open (inode);
          else
            fd->dir = dir_open (inode);
          if (fd->file != NULL || fd->dir != NULL)
            {
              struct thread *cur = thread_current ();
              handle = fd->handle = cur->next_handle++;
              list_push_front (&cur->fds, &fd->elem);
            }
          else 
            {
              free (fd);
              inode_close (inode);
            }
        }
    }
  
  palloc_free_page (kfile);
  return handle;
}
Ejemplo n.º 8
0
/* Opens a directory */
struct dir *dir_open (size_t count, struct inode *inode,
    struct dir *directory_)
{
  struct dir *dir = calloc (1, sizeof *dir);
  //open root directory
  if (count == 0)
    inode = inode_open (ROOT_DIR_SECTOR);

  //reopen a directory
  if (count == 1)
    inode = inode_reopen (directory_->inode);

  if (dir == NULL && inode == NULL)
  {
    inode_close (inode);
    free (dir);
    return NULL;

  } else
  {
    dir->pos = 0;
    dir->inode = inode;
    return dir;
  }
}
Ejemplo n.º 9
0
/* Closes the directory and frees it */
void dir_close (struct dir* directory)
{
  if (directory != NULL)
  {
    inode_close (directory->inode);
    free (directory);
  }
}
Ejemplo n.º 10
0
/* Destroys DIR and frees associated resources. */
void
dir_close (struct dir *dir) 
{
  if (dir != NULL)
    {
      inode_close (dir->inode);
      free (dir);
    }
}
Ejemplo n.º 11
0
/* 关闭文件 */
int32_t file_close(struct file* file) {
   if (file == NULL) {
      return -1;
   }
   file->fd_inode->write_deny = false;
   inode_close(file->fd_inode);
   file->fd_inode = NULL;   // 使文件结构可用
   return 0;
}
Ejemplo n.º 12
0
// Write at most 'n' bytes from 'buf' to 'fd' at the current seek position.
// Advance 'fd->f_offset' by the number of bytes written.
//
// Returns:
//	 The number of bytes successfully written.
//	 < 0 on error.
static ssize_t
devfile_write(struct Fd *fd, const void *buf, size_t n)
{
	// Use inode_open, inode_close, maybe inode_set_size, and inode_data.
	// Be careful of block boundaries!
	// Flush any blocks you change using BCREQ_FLUSH.
	//
	// LAB 5: Your code here.
    int r;
    size_t orig_offset = fd->fd_offset;
    struct Inode *ino;
    if((r = inode_open(fd->fd_file.inum, &ino)) < 0)
        return r;
    void *data;
    size_t n2 = ROUNDUP(fd->fd_offset, PGSIZE) - fd->fd_offset;
    if (n2 > n)
        n2 = n;
    if(n2)
    {
        n -= n2;
        if(fd->fd_offset + n2 > (size_t)ino->i_size && 
           inode_set_size(ino, fd->fd_offset + n2) < 0)
            goto wrapup;
        data = inode_data(ino, fd->fd_offset);
        memcpy(data, buf, n2);
        fd->fd_offset += n2;
        bcache_ipc(data, BCREQ_FLUSH);
        buf = (void *)((char *)buf + n2);
    }
    while (n / PGSIZE)
    {
        if(fd->fd_offset + PGSIZE > (size_t)ino->i_size && 
           inode_set_size(ino, fd->fd_offset + PGSIZE) < 0)
            goto wrapup;
        data = inode_data(ino, fd->fd_offset);
        memcpy(data, buf, PGSIZE);
        bcache_ipc(data, BCREQ_FLUSH);
        n -= PGSIZE;
        buf = (void *)((char *)buf + PGSIZE);
        fd->fd_offset += PGSIZE;
    }
    if (n > 0)
    {
        if(fd->fd_offset + n > (size_t)ino->i_size && 
           inode_set_size(ino, fd->fd_offset + n) < 0)
            goto wrapup;
        data = inode_data(ino, fd->fd_offset);
        memcpy(data, buf, n);
        bcache_ipc(data, BCREQ_FLUSH);
        fd->fd_offset += n;
    }

wrapup:
    inode_close(ino);
    return fd->fd_offset - orig_offset;
}
Ejemplo n.º 13
0
/* Removes any entry for NAME in DIR.
   Returns true if successful, false on failure,
   which occurs only if there is no file with the given NAME. */
bool
dir_remove (struct dir *dir, const char *name) 
{
  struct dir_entry e;
  struct inode *inode = NULL;
  bool success = false;
  off_t ofs;

  ASSERT (dir != NULL);
  ASSERT (name != NULL);

  //lock the directory for the rest of the lookup operation
  inode_lock(dir->inode);
  name = getfilename(name);

  /* Find directory entry. */
  if (!lookup (dir, name, &e, &ofs))
    goto done;

  /* Open inode. */
  inode = inode_open (e.inode_sector);
  if (inode == NULL)
    goto done;

  //if it is still open don't allow deletion
  if(inode_type(inode) == FILE_DIR) {
	//is file in use?
	if(inode_opencnt(inode) > 1)
		goto done;
	char * temp = (char *)malloc(sizeof(char) * (NAME_MAX + 1) );
	struct dir * dirtemp = dir_open(inode);
	//is dir empty?
	if (dir_readdir(dirtemp,temp)) {
		free(temp);
		dir_close(dirtemp);
		goto done;
	}
	free(temp);
	dir_close(dirtemp);	
  }

  /* Erase directory entry. */
  e.in_use = false;
  if (inode_write_at (dir->inode, &e, sizeof e, ofs) != sizeof e) 
    goto done;

  /* Remove inode. */
  inode_remove (inode);
  success = true;

 done:
  //unlock the directory
  inode_unlock(dir->inode);
  inode_close (inode);
  return success;
}
Ejemplo n.º 14
0
struct dir *get_directory(const char *path, bool flag){
  if(strlen(path)==0)
    return NULL;
  struct dir *curr;
  char *word, *brkt, *buffer = malloc(strlen(path)+1), *save, *last;
  struct inode *inode;
  memcpy(buffer, path, strlen(path)+1);
  save = buffer;
  if(buffer[0]=='/'){
    curr = dir_open_root();
    last = strtok_r(buffer+1, "/", &brkt);
  }
  else{
    if(thread_current()->dir)
      curr = dir_reopen(thread_current()->dir);
    else
      curr = dir_open_root();
    last = strtok_r(buffer, "/", &brkt);
  }
  
  while(1){
    word = last;
    if(word == NULL) break;
    last = strtok_r(NULL, "/", &brkt);
    if(last == NULL && flag) break;
    if(strcmp(word,"")==0);
    else if(strcmp(word,".")==0);
    else if(strcmp(word,"..")==0){
      inode = inode_open(inode_parent_number(dir_get_inode(curr)));
      dir_close(curr);
      curr = dir_open(inode);
    }
    else{
      inode = NULL;
      if(dir_lookup(curr, word, &inode)){
        dir_close(curr);
        if(inode_is_dir(inode))
          curr = dir_open(inode);
        else{
          inode_close(inode);
          free(save);
          return NULL;
        }
      }
      else{
        dir_close(curr);
        free(save);
        return NULL;
      }
    }
  }
  free(save);
  if(inode_removed(curr->inode))
    return NULL;
  return curr;
}
Ejemplo n.º 15
0
bool isdirectory(block_sector_t sector)
{
    bool a;
    struct inode * inode;
    ASSERT(sector < 20000);
    inode = inode_open(sector);
    a = inode->data.is_dir;
    inode_close(inode);
    return a;
}
Ejemplo n.º 16
0
/* Creates a directory with space for ENTRY_CNT entries in the
   given SECTOR.  Returns true if successful, false on failure. */
bool
dir_create (disk_sector_t sector, size_t entry_cnt, disk_sector_t parent_sector)
{
  if(!inode_create (sector, entry_cnt * sizeof (struct dir_entry), INODE_MAX_LEVEL, true))
    return false;
  struct inode *inode = inode_open(sector);
  inode_set_parent(inode, parent_sector);
  inode_close(inode);
  return true;
}
Ejemplo n.º 17
0
struct dir*
get_containing_dir (const char* path)
{
   char s[strlen(path)+1];
   memcpy(s, path, strlen(path)+1);
   
   char *save_ptr, *next_token = NULL, *token = strtok_r(s, "/", &save_ptr);
   struct dir* dir;
   if (s[0] == 47 || !thread_current ()->cwd)
   {
	dir = dir_open_root ();
   } 
   else
   {
       dir = dir_reopen (thread_current()->cwd);
   }
  
   if (token)
   {
      next_token = strtok_r (NULL, "/",  &save_ptr);
   }
   while (next_token != NULL)
   {
        if (strcmp(token, ".") != 0)
        {
	    struct inode *inode;
	    if (strcmp(token, "..") == 0)
            {
                if (!dir_get_parent (dir, &inode))
	        {
		    return NULL;
	        }
	    }
	    else
	    {
		if (!dir_lookup (dir, token, &inode))
		 {
			return NULL;
		 }
	    }
	    if (inode_is_dir (inode))
	    {
	        dir_close (dir);
	        dir = dir_open (inode);
	    }
	    else
	    {
	        inode_close (inode);
            }
         }
	token = next_token;
        next_token = strtok_r (NULL, "/", &save_ptr);   
   }
   return dir;
}
Ejemplo n.º 18
0
/* 回收inode的数据块和inode本身 */
void inode_release(struct partition* part, uint32_t inode_no) {
   struct inode* inode_to_del = inode_open(part, inode_no);
   ASSERT(inode_to_del->i_no == inode_no);

/* 1 回收inode占用的所有块 */
   uint8_t block_idx = 0, block_cnt = 12;
   uint32_t block_bitmap_idx;
   uint32_t all_blocks[140] = {0};	  //12个直接块+128个间接块

   /* a 先将前12个直接块存入all_blocks */
   while (block_idx < 12) {
      all_blocks[block_idx] = inode_to_del->i_sectors[block_idx];
      block_idx++;
   }

   /* b 如果一级间接块表存在,将其128个间接块读到all_blocks[12~], 并释放一级间接块表所占的扇区 */
   if (inode_to_del->i_sectors[12] != 0) {
      ide_read(part->my_disk, inode_to_del->i_sectors[12], all_blocks + 12, 1);
      block_cnt = 140;

      /* 回收一级间接块表占用的扇区 */
      block_bitmap_idx = inode_to_del->i_sectors[12] - part->sb->data_start_lba;
      ASSERT(block_bitmap_idx > 0);
      bitmap_set(&part->block_bitmap, block_bitmap_idx, 0);
      bitmap_sync(cur_part, block_bitmap_idx, BLOCK_BITMAP);
   }
   
   /* c inode所有的块地址已经收集到all_blocks中,下面逐个回收 */
   block_idx = 0;
   while (block_idx < block_cnt) {
      if (all_blocks[block_idx] != 0) {
	 block_bitmap_idx = 0;
	 block_bitmap_idx = all_blocks[block_idx] - part->sb->data_start_lba;
	 ASSERT(block_bitmap_idx > 0);
	 bitmap_set(&part->block_bitmap, block_bitmap_idx, 0);
	 bitmap_sync(cur_part, block_bitmap_idx, BLOCK_BITMAP);
      }
      block_idx++; 
   }

/*2 回收该inode所占用的inode */
   bitmap_set(&part->inode_bitmap, inode_no, 0);  
   bitmap_sync(cur_part, inode_no, INODE_BITMAP);

   /******     以下inode_delete是调试用的    ******
   * 此函数会在inode_table中将此inode清0,
   * 但实际上是不需要的,inode分配是由inode位图控制的,
   * 硬盘上的数据不需要清0,可以直接覆盖*/
   void* io_buf = sys_malloc(1024);
   inode_delete(part, inode_no, io_buf);
   sys_free(io_buf);
   /***********************************************/
    
   inode_close(inode_to_del);
}
Ejemplo n.º 19
0
/* Destroys DIR and frees associated resources. */
void
dir_close (struct dir *dir)
{
//  lock_acquire(&directory_lock);
  if (dir != NULL)
    {
      inode_close (dir->inode);
      free (dir);
    }
//  lock_release(&directory_lock);
}
Ejemplo n.º 20
0
/* Opens the file with the given NAME.
   Returns the new file if successful or a null pointer
   otherwise.
   Fails if no file named NAME exists,
   if directory was there,
   or if an internal memory allocation fails. */
struct file *
filesys_open (const char *path)
{
  bool is_directory;
  struct inode *inode = filesys_open_inode (path, &is_directory);
  if (inode != NULL && !is_directory)
    return file_open (inode);
  else
    inode_close (inode);
  return NULL;
}
Ejemplo n.º 21
0
/* 关闭目录 */
void dir_close(struct dir* dir) {
/*************      根目录不能关闭     ***************
 *1 根目录自打开后就不应该关闭,否则还需要再次open_root_dir();
 *2 root_dir所在的内存是低端1M之内,并非在堆中,free会出问题 */
   if (dir == &root_dir) {
   /* 不做任何处理直接返回*/
      return;
   }
   inode_close(dir->inode);
   sys_free(dir);
}
Ejemplo n.º 22
0
/* Opens the file with the given NAME.
   Returns the new file if successful or a null pointer
   otherwise.
   Fails if no file named NAME exists,
   or if an internal memory allocation fails. */
struct inode *
filesys_open (const char *name)
{
  struct dir *search_dir = get_cwd(name);

  if (search_dir == NULL) {
    return NULL;
  }

  struct inode *inode = NULL;

  if (name[0] == '/') {
    inode = dir_get_inode(search_dir);
  }

  char *part = malloc(NAME_MAX + 1);
  if (part == NULL) {
    return false;
  }
  memset(part, 0, NAME_MAX + 1);
  int retrieved_next_part;
  for (retrieved_next_part = get_next_part(part, &name); retrieved_next_part > 0;
       retrieved_next_part = get_next_part(part, &name)) {
    if (dir_lookup (search_dir, part, &inode)) {
      if (!inode_is_dir(inode)) {
        break;
      } else {
        dir_close(search_dir);
        search_dir = dir_open(inode);
        if (search_dir == NULL) {
          free(part);
          return false;
        }
      }
    } else {
      inode = NULL;
      break;
    }
  }
  if (inode != NULL && inode_is_dir(inode) && get_next_part(part, &name) == 0) {
    inode = inode_reopen(inode);
  }
  dir_close(search_dir);
  
  if (inode != NULL && get_next_part(part, &name) != 0) {
    inode_close(inode);
    inode = NULL;
  }
  free(part);
  return inode;
}
Ejemplo n.º 23
0
// Truncate or extend an open file to 'size' bytes
static int
devfile_trunc(struct Fd *fd, off_t newsize)
{
	int r;
	struct Inode *ino;

	if ((r = inode_open(fd->fd_file.inum, &ino)) < 0)
		return r;

	r = inode_set_size(ino, newsize);

	inode_close(ino);
	return r;
}
Ejemplo n.º 24
0
/*! Opens a file for the given INODE, of which it takes ownership,
    and returns the new file.  Returns a null pointer if an
    allocation fails or if INODE is null. */
struct file * file_open(struct inode *inode) {
    struct file *file = calloc(1, sizeof *file);
    if (inode != NULL && file != NULL) {
        file->inode = inode;
        file->pos = 0;
        file->deny_write = false;
        return file;
    }
    else {
        inode_close(inode);
        free(file);
        return NULL; 
    }
}
Ejemplo n.º 25
0
static int
devfile_stat(struct Fd *fd, struct Stat *stat)
{
	int r;
	struct Inode *ino;

	if ((r = inode_open(fd->fd_file.inum, &ino)) < 0)
		return r;

	strcpy(stat->st_name, fd->fd_file.open_path);
	stat_base(ino, stat);

	inode_close(ino);
	return 0;
}
Ejemplo n.º 26
0
int
istat(inum_t inum, struct Stat *stat)
{
	int r;
	struct Inode *ino;

	if ((r = inode_open(inum, &ino)) < 0)
		return r;

	strcpy(stat->st_name, "<inode>");
	stat_base(ino, stat);

	inode_close(ino);
	return 0;
}
Ejemplo n.º 27
0
/* Closes FILE. */
void
file_close (struct file *file) 
{
  if (file != NULL)
    {
      /* Close the directory if possible. */
      if (file->inode->data.is_dir)
        {
          dir_close (file->opened_dir);
        }
      file_allow_write (file);
      inode_close (file->inode);
      free (file);
    }
}
Ejemplo n.º 28
0
/* Opens and returns the directory for the given INODE, of which
   it takes ownership.  Returns a null pointer on failure. */
struct dir *
dir_open (struct inode *inode) 
{
  struct dir *dir = calloc (1, sizeof *dir);
  if (inode != NULL && dir != NULL)
    {
      dir->inode = inode;
      dir->pos = 0;
      return dir;
    }
  else
    {
      inode_close (inode);
      free (dir);
      return NULL; 
    }
}
Ejemplo n.º 29
0
/* Creates a file named NAME with the given INITIAL_SIZE.*/
bool
filesys_create (const char *name, off_t initial_size, bool isdir) 
{
  if (strlen(name) == 0) return false;
  block_sector_t inode_sector = 0;

  struct dir *dir_ = filesys_get_dir(name);
  char *name_ = filesys_get_name(name);
  bool success = false;

  if (strcmp (name_, "") == 0) goto done;
  success = (dir_ && free_map_allocate (1, &inode_sector)
    && inode_create (inode_sector, initial_size) 
    && dir_add (dir_, name_, inode_sector, isdir));

  struct inode *ninode = NULL;
  struct dir *ndir = NULL;
  bool success1 = true;
  if (success && isdir){
    success1 = ((ninode = inode_open (inode_sector))
      && (ndir = dir_open (ninode))
      && dir_add (ndir, ".", inode_sector, true)
      && dir_add (ndir, "..",inode_get_inumber (dir_get_inode (dir_)), true));
  }

  if (inode_sector != 0 && !success) 
    free_map_release (inode_sector, 1);

  if (success && !success1) {
    success = false;
    printf("Failure: create dir: %s\n", name);
    dir_remove (dir_, name_);
  }

  done:
    dir_close (dir_);

  free(name_);
  if (!ndir && ninode){
    inode_close(ninode);
  } else if (ndir) {
    dir_close(ndir);
  }

  return success;
}
Ejemplo n.º 30
0
gfarm_error_t
process_close_file(struct process *process, struct peer *peer, int fd)
{
	int is_file;
	struct file_opening *fo;
	gfarm_error_t e = process_get_file_opening(process, fd, &fo);

	if (e != GFARM_ERR_NO_ERROR)
		return (e);

	is_file = inode_is_file(fo->inode);

	if (fo->opener != peer) {
		if (!is_file) /* i.e. is a directory */
			return (GFARM_ERR_OPERATION_NOT_PERMITTED);
		if (fo->u.f.spool_opener != peer)
			return (GFARM_ERR_OPERATION_NOT_PERMITTED);
		/* i.e. REOPENed file, and I am a gfsd. */
		if (fo->opener != NULL) {
			/*
			 * a gfsd is closing a REOPENed file,
			 * but the client is still opening it.
			 */
			fo->u.f.spool_opener = NULL;
			fo->u.f.spool_host = NULL;
			return (GFARM_ERR_NO_ERROR);
		}
	} else {
		if (is_file &&
		    fo->u.f.spool_opener != NULL &&
		    fo->u.f.spool_opener != peer) {
			/*
			 * a client is closing a file,
			 * but the gfsd is still opening it.
			 */
			fo->opener = NULL;
			return (GFARM_ERR_NO_ERROR);
			
		}
	}

	inode_close(fo);
	file_opening_free(fo, is_file);
	process->filetab[fd] = NULL;
	return (GFARM_ERR_NO_ERROR);
}