text: #include <xbook/fifo.h>
  #include <xbook/debug.h>
  #include <string.h>
  #include <math.h>
  #include <unistd.h>
  #include <errno.h>
  #include <sys/ipc.h>
  
  #include <xbook/semaphore.h>
  #include <xbook/schedule.h>
  #include <xbook/fsal.h>
  #include <xbook/path.h>
  #include <xbook/file.h>
  #include <xbook/dir.h>
  
  #define FIFOFS_PATH  "/fifofs"
  
  typedef struct {
      int handle;
  } fifofs_file_extention_t;
  
  fifo_t *fifo_table;
  DEFINE_SEMAPHORE(fifo_mutex, 1);
  
  static int fsal_fifofs_mount(char *source, char *target, char *fstype, unsigned long flags);
  static int fsal_fifofs_unmount(char *path, unsigned long flags);
  static int fifoif_open(void *pathname, int flags);
  static int fifoif_unlink(char *pathname);
  
  static fifo_t *fifo_find_by_name(char *name)
  {
      fifo_t *fifo;
      int i;
      for (i = 0; i < FIFO_NR; i++) {
          fifo = &fifo_table[i];
          if (fifo->name[0] != '\0') {
              if (!strcmp(fifo->name, name)) {
                  return fifo;
              }
          }
      }
      return NULL;
  }
  
  static fifo_t *fifo_find_by_id(int fifoid)
  {
      fifo_t *fifo;
      int i;
      for (i = 0; i < FIFO_NR; i++) {
          fifo = &fifo_table[i];
          if (fifo->id == fifoid && fifo->name[0] != '\0') { 
              return fifo;
          }
      }
      return NULL;
  }
  
  fifo_t *fifo_alloc(char *name)
  {
      fifo_t *fifo;
      int i;
      for (i = 0; i < FIFO_NR; i++) {
          fifo = &fifo_table[i];
          if (fifo->name[0] == '\0') {
              fifo->fifo = fifo_buf_alloc(FIFO_SIZE);
              if (fifo->fifo == NULL)
                  return NULL;
              memset(fifo->name, 0, FIFO_NAME_LEN);
              strcpy(fifo->name, name);
              atomic_set(&fifo->readref, 0);
              atomic_set(&fifo->writeref, 0);
              return fifo;
          }
      }
      return NULL;
  }
  
  int fifo_free(fifo_t *fifo)
  {
      if (fifo->fifo) {
          fifo_buf_free(fifo->fifo);
          fifo->fifo = NULL;
      }
      memset(fifo->name, 0, FIFO_NAME_LEN);
      return 0;
  }
  
  static int fifo_is_opened(fifo_t *fifo)
  {
      if (atomic_get(&fifo->readref) < 1 && atomic_get(&fifo->writeref) < 1)
          return 0;
      return 1;
  }
  
  /**
   * @flags: 获取标志
   *          IPC_CREAT: 如果管道不存在，则创建一个新的管道，否则就打开
   *          IPC_EXCL:  和CREAT一起使用，则要求创建一个新的管道，若已存在，就返回-1。
   *                    相当于在CREAT上面加了一个必须不存在的限定。
   *          IPC_READER: 读者进程
   *          IPC_WRITER: 写者进程
   * 只能有一个读者和一个写者
   * 读者注册时需要检测写者是否在同步等待自己，如果是，就唤醒写者。
   * @return: 成功返回管道id，失败返回-1
   */
  int fifo_get(char *name, unsigned long flags)
  {
      if (name == NULL)
          return -1;
      char craete_new = 0;
      fifo_t *fifo;
      int retval = -1;
      int rw = -1;
      semaphore_down(&fifo_mutex);
      if (flags & IPC_CREAT) {
          if (flags & IPC_READER) {
              rw = 0;
          } else if (flags & IPC_WRITER) {
              rw = 1;
          } else {
              keprint(PRINT_NOTICE "get fifo %s without reader or writer!\n", name);
          }
          if (flags & IPC_EXCL) {
              craete_new = 1;
          }
          fifo = fifo_find_by_name(name);
          if (fifo) {
              if (craete_new) {
                  goto err;
              }
              if (rw == 1) {
                  if (fifo->writer == NULL && !atomic_get(&fifo->writeref)) {
                      fifo->writer = task_current;                  
                  }
                  atomic_inc(&fifo->writeref);
                  if (flags & IPC_NOWAIT) {
                      fifo->flags |= (IPC_NOWAIT << 24);
                  }
              } else if (rw == 0) {
                  if (fifo->reader == NULL && !atomic_get(&fifo->readref)) {
                      fifo->reader = task_current;
                      if (fifo->writer && fifo->writer->state == TASK_BLOCKED && fifo->flags & FIFO_IN_WRITE) {              
                          task_unblock(fifo->writer);
                      }
                  }
                  atomic_inc(&fifo->readref);
                  if (flags & IPC_NOWAIT) {
                      fifo->flags |= (IPC_NOWAIT << 16);
                  }
              }
              retval = fifo->id;
          } else {
              errprint("fifo %s not found!\n", name);
              retval = -ENOFILE;
              goto err;
          }
      }
  err:
      semaphore_up(&fifo_mutex);
      return retval;
  }
  
  /**
   * 生成一个新的管道文件
   * 成功返回0
   * 如果文件已经存在就返回EEXIST，如果没有可用管道资源，则返回ENOMEN
   */
  int fifo_make(char *name, mode_t mode)
  {
      if (*name == '\0')
          return -EINVAL;
      fifo_t *fifo;
      int retval = -1;
      semaphore_down(&fifo_mutex);
      /* 如果文件已经存在则创建失败 */
      fifo = fifo_find_by_name(name);
      if (fifo) {
          retval = -EEXIST;
          goto err;
      }
  
      fifo = fifo_alloc(name);
      if (fifo == NULL) {
          retval = -ENOMEM;
          goto err;
      }
      retval = 0;
  err:
      semaphore_up(&fifo_mutex);
      return retval;
  }
  
  int fifo_remove(char *name)
  {
      if (*name == '\0')
          return -EINVAL;
      fifo_t *fifo;
      int retval = -1;
      
      if (semaphore_try_down(&fifo_mutex) < 0) {
          retval = -EBUSY;
          goto err;
      }
      /* 如果文件已经存在则创建失败 */
      fifo = fifo_find_by_name(name);
      if (!fifo) {
          retval = -ENFILE;
          goto err;
      }
  
      if (fifo_is_opened(fifo)) {
          retval = -EPERM;    /* opened! */
          goto err;
      }
  
      if (fifo_free(fifo) < 0) {
          retval = -EBUSY;
          goto err;
      }
      retval = 0;
  err:
      semaphore_up(&fifo_mutex);
      return retval;
  }
  
  int fifo_put(int fifoid)
  {
      fifo_t *fifo;
      semaphore_down(&fifo_mutex);
      fifo = fifo_find_by_id(fifoid);
  
      if (fifo) {
          mutex_lock(&fifo->mutex);
          if (task_current == fifo->reader) {
              atomic_dec(&fifo->readref);
              if (atomic_get(&fifo->readref) == 0) {
                  fifo->reader = NULL;
              }
          } else if (task_current == fifo->writer) {
              atomic_dec(&fifo->writeref);
              if (atomic_get(&fifo->writeref) == 0) {
                  fifo->writer = NULL;
              }
          }
          mutex_unlock(&fifo->mutex);
          semaphore_up(&fifo_mutex);        
          return 0;
      }
      semaphore_up(&fifo_mutex);
      return -1;
  }
  
  int fifo_write(int fifoid, void *buffer, size_t size)
  {
      if (buffer == NULL || !size) {
          keprint(PRINT_ERR "%s: arg error!\n");
          return -1;
      }
      fifo_t *fifo;
      semaphore_down(&fifo_mutex);
      fifo = fifo_find_by_id(fifoid);
      if (fifo == NULL) {
          semaphore_up(&fifo_mutex);
          keprint(PRINT_DEBUG "fifo_write: not found fifo id=%d!\n", fifoid);
          return -1;
      }   
      semaphore_up(&fifo_mutex);
      if (fifo->writer == NULL) {
          keprint(PRINT_ERR "%s: no writer!\n");
          return -1;
      }
      if (fifo->flags & (IPC_NOERROR << 24) && fifo->writer != task_current) {
          keprint(PRINT_ERR "%s: writer no current task!\n");
          return -1;
      }
      fifo->flags |= FIFO_IN_WRITE;
      if (fifo->reader == NULL) {
          if (!(fifo->flags & (IPC_NOSYNC << 24))) {
              task_block(TASK_BLOCKED);
          }
      }
  
      mutex_lock(&fifo->mutex);
      int left_size = (int )size;
      int off = 0;
      unsigned char *buf = buffer;
      int chunk = 0;
      int wrsize = 0;
      while (left_size > 0) {
          while (fifo_buf_avali(fifo->fifo) <= 0) {
              if (fifo->flags & (IPC_NOWAIT << 24)) {
                  fifo->flags &= ~FIFO_IN_WRITE;
                  mutex_unlock(&fifo->mutex);
                  return -1;
              }
              if (!fifo->reader || atomic_get(&fifo->readref) <= 0) {
                  exception_force_self(EXP_CODE_PIPE);
                  mutex_unlock(&fifo->mutex);
                  return -1; 
              }
              if (fifo->reader->state == TASK_BLOCKED &&
                  (fifo->flags & FIFO_IN_READ)) {
                  task_unblock(fifo->reader);
              }
              mutex_unlock(&fifo->mutex);
              task_block(TASK_BLOCKED);
              mutex_lock(&fifo->mutex);
          }
  
          chunk = MIN(left_size, FIFO_SIZE);
          chunk = MIN(chunk, fifo_buf_avali(fifo->fifo));
          chunk = fifo_buf_put(fifo->fifo, buf + off, chunk);
          off += chunk;
          left_size -= chunk;
          wrsize += chunk;
      }
      if (fifo->reader->state == TASK_BLOCKED &&
          (fifo->flags & FIFO_IN_READ)) {
          task_unblock(fifo->reader);
      }
      fifo->flags &= ~FIFO_IN_WRITE;
      mutex_unlock(&fifo->mutex);
      return wrsize;
  }
  
  int fifo_read(int fifoid, void *buffer, size_t size)
  {
      if (buffer == NULL || !size)
          return -1;
      fifo_t *fifo;
      semaphore_down(&fifo_mutex);
      fifo = fifo_find_by_id(fifoid);
      if (fifo == NULL) {
          semaphore_up(&fifo_mutex);    
          keprint(PRINT_ERR "fifo_read: not found message queue!\n");
          return -1;
      }
      semaphore_up(&fifo_mutex);
      if (fifo->reader == NULL) {
          keprint(PRINT_ERR "fifo_read: reader null!\n");
          return -1;
      }
      if (fifo->flags & (IPC_NOERROR << 16) && (fifo->reader != task_current))
          return -1;
      fifo->flags |= FIFO_IN_READ;
      if (fifo->writer == NULL && (fifo->flags & (IPC_NOSYNC << 16))) {
          keprint(PRINT_DEBUG "fifo_read: don't need sync for reader.\n");  
          return -1;
      }
  
      mutex_lock(&fifo->mutex);
      int rdsize = 0;
      int chunk;
      while (fifo_buf_len(fifo->fifo) <= 0) {
          if (fifo->flags & (IPC_NOWAIT << 16)) {
              fifo->flags &= ~FIFO_IN_READ;
              mutex_unlock(&fifo->mutex);
              return -1;
          }
          if (!fifo->writer || atomic_get(&fifo->writeref) <= 0) {
              mutex_unlock(&fifo->mutex);
              return -1;
          }
          if (exception_cause_exit(&task_current->exception_manager)) {
              mutex_unlock(&fifo->mutex);
              return -1;
          }
          mutex_unlock(&fifo->mutex);
          task_block(TASK_BLOCKED);
          mutex_lock(&fifo->mutex);
      }
  
      chunk = MIN(size, FIFO_SIZE);
      chunk = MIN(chunk, fifo_buf_len(fifo->fifo));
      chunk = fifo_buf_get(fifo->fifo, buffer, chunk);
      rdsize += chunk;
      if (fifo->writer && fifo->writer->state == TASK_BLOCKED && 
              (fifo->flags & FIFO_IN_WRITE)) {
          task_unblock(fifo->writer);
      }
      fifo->flags &= ~FIFO_IN_READ;
      mutex_unlock(&fifo->mutex);
      return rdsize;
  }
  
  int fifo_set_rdwr(int fifoid, unsigned long arg)
  {
      fifo_t *fifo;
      semaphore_down(&fifo_mutex);
      fifo = fifo_find_by_id(fifoid);
      if (fifo) {
          mutex_lock(&fifo->mutex);
          if (arg == IPC_READER) {
              fifo->reader = task_current;
          } else if (arg == IPC_WRITER) {
              fifo->writer = task_current;
          } else {
              mutex_unlock(&fifo->mutex);
              semaphore_up(&fifo_mutex);
              return -1;
          }
          mutex_unlock(&fifo->mutex);
          semaphore_up(&fifo_mutex);        
          return 0;
      }
      semaphore_up(&fifo_mutex);
      return -1;
  }
  
  int fifo_set_flags(int fifoid, unsigned int cmd, unsigned long arg)
  {
      fifo_t *fifo;
      semaphore_down(&fifo_mutex);
      fifo = fifo_find_by_id(fifoid);
      if (fifo) {
          mutex_lock(&fifo->mutex);
          if (fifo->reader == task_current) {
              fifo->flags |= (arg & 0xff) << 16;
          } else if (fifo->writer == task_current) {
              fifo->flags |= (arg & 0xff) << 24;
          } else {
              mutex_unlock(&fifo->mutex);
              semaphore_up(&fifo_mutex);
              return -1;
          }
          mutex_unlock(&fifo->mutex);
          semaphore_up(&fifo_mutex);        
          return 0;
      }
      semaphore_up(&fifo_mutex);
      return -1;
  }
  
  int fifo_ctl(int fifoid, unsigned int cmd, unsigned long arg)
  {
      int retval = 0;
      switch (cmd)
      {
      case IPC_SETRW:
          retval = fifo_set_rdwr(fifoid, arg);
          break;
      case IPC_SET:
          retval = fifo_set_flags(fifoid, cmd, arg);
          break;
      default:
          retval = -1;
          break;
      }
      return retval;
  }
  
  int fifo_incref(int fifoid)
  {
      fifo_t *fifo;
      semaphore_down(&fifo_mutex);
      fifo = fifo_find_by_id(fifoid);
      if (fifo) {
          mutex_lock(&fifo->mutex);
          if (task_current == fifo->reader && atomic_get(&fifo->readref) > 0) {
              atomic_inc(&fifo->readref);
          } else if (task_current == fifo->writer && atomic_get(&fifo->writeref) > 0) {
              atomic_inc(&fifo->writeref);
          } else {  
              dbgprint("[FIFO]: %s: %s: not reader or writer!\n", __func__, task_current->name);
              mutex_unlock(&fifo->mutex);
              semaphore_up(&fifo_mutex);        
              return -1;
          }
          mutex_unlock(&fifo->mutex);
          semaphore_up(&fifo_mutex);        
          return 0;
      }
      dbgprint("[FIFO]: %s: %s: fifo not found!\n", __func__, task_current->name);
      semaphore_up(&fifo_mutex);
      return -1;
  }
  
  int fifo_decref(int fifoid)
  {
      fifo_t *fifo;
      semaphore_down(&fifo_mutex);
      fifo = fifo_find_by_id(fifoid);
      if (fifo) {
          mutex_lock(&fifo->mutex);
          if (task_current == fifo->reader && atomic_get(&fifo->readref) > 0) {
              atomic_dec(&fifo->readref);
          } else if (task_current == fifo->writer && atomic_get(&fifo->writeref) > 0) {
              atomic_dec(&fifo->writeref);
          } else {  
              dbgprint("[FIFO]: %s: %s: not reader or writer!\n", __func__, task_current->name);
              mutex_unlock(&fifo->mutex);
              semaphore_up(&fifo_mutex);        
              return -1;
          }
          mutex_unlock(&fifo->mutex);
          semaphore_up(&fifo_mutex);        
          return 0;
      }
      dbgprint("[FIFO]: %s: %s: fifo not found!\n", __func__, task_current->name);
      semaphore_up(&fifo_mutex);
      return -1;
  }
  
  void fifo_init()
  {
      fifo_table = (fifo_t *)mem_alloc(sizeof(fifo_t) * FIFO_NR);
      if (fifo_table == NULL)
          panic(PRINT_EMERG "fifo_init: alloc mem for fifo_table failed! :(\n");
      
      int i;
      for (i = 0; i < FIFO_NR; i++) {
          fifo_table[i].id = 1 + i + i * 2;
          mutexlock_init(&fifo_table[i].mutex);
          memset(fifo_table[i].name, 0, FIFO_NAME_LEN);
          fifo_table[i].fifo = NULL;
          fifo_table[i].reader = NULL;
          fifo_table[i].writer = NULL;
      }
  }
  
  static int fifo_open(void *name, int flags)
  {
      char *p = (char *) name;
      unsigned long new_flags = IPC_CREAT;
      if (flags & O_CREAT) {
          new_flags |= IPC_EXCL;
      }
      if (flags & O_RDWR) {
          new_flags |= (IPC_READER | IPC_WRITER);
      } else if (flags & O_RDONLY) {
          new_flags |= IPC_READER;
      } else if (flags & O_WRONLY) {
          new_flags |= IPC_WRITER;
      }
      if (flags & O_NONBLOCK) {
          new_flags |= IPC_NOWAIT;
      }
      int handle = fifo_get(p, new_flags);
      return handle;
  }
  
  static int fifoif_incref(int idx)
  {
      if (FSAL_BAD_FILE_IDX(idx))
          return -1;
      fsal_file_t *fp = FSAL_IDX2FILE(idx);
      if (FSAL_BAD_FILE(fp)) 
          return -1;
      fifofs_file_extention_t *ext = (fifofs_file_extention_t *) fp->extension;
      return fifo_incref(ext->handle);
  }
  
  static int fifoif_decref(int idx)
  {
      if (FSAL_BAD_FILE_IDX(idx))
          return -1;
      fsal_file_t *fp = FSAL_IDX2FILE(idx);
      if (FSAL_BAD_FILE(fp)) 
          return -1;
      fifofs_file_extention_t *ext = (fifofs_file_extention_t *) fp->extension;
      return fifo_decref(ext->handle);
  }
  
  static int fifoif_read(int idx, void *buf, size_t size)
  {
      if (FSAL_BAD_FILE_IDX(idx))
          return -1;
      fsal_file_t *fp = FSAL_IDX2FILE(idx);
      if (FSAL_BAD_FILE(fp)) 
          return -1;
      fifofs_file_extention_t *ext = (fifofs_file_extention_t *) fp->extension;
      return fifo_read(ext->handle, buf, size);
  }
  
  static int fifoif_write(int idx, void *buf, size_t size)
  {
      if (FSAL_BAD_FILE_IDX(idx))
          return -1;
      fsal_file_t *fp = FSAL_IDX2FILE(idx);
      if (FSAL_BAD_FILE(fp)) 
          return -1;
      fifofs_file_extention_t *ext = (fifofs_file_extention_t *) fp->extension;
      return fifo_write(ext->handle, buf, size);
  }
  
  static int fifoif_ioctl(int idx, int cmd, void *arg)
  {
      if (FSAL_BAD_FILE_IDX(idx))
          return -1;
      fsal_file_t *fp = FSAL_IDX2FILE(idx);
      if (FSAL_BAD_FILE(fp)) 
          return -1;
      fifofs_file_extention_t *ext = (fifofs_file_extention_t *) fp->extension;
      return fifo_ctl(ext->handle, cmd, (unsigned long) arg);
  }
  
  static int fifoif_fcntl(int handle, int cmd, long arg)
  {
      if (FSAL_BAD_FILE_IDX(handle))
          return -1;
      fsal_file_t *fp = FSAL_IDX2FILE(handle);
      if (FSAL_BAD_FILE(fp)) 
          return -1;
      fifofs_file_extention_t *ext = (fifofs_file_extention_t *) fp->extension;
      return fifo_ctl(ext->handle, cmd, arg);
  }
  
  static int fifoif_close(int handle)
  {
      if (FSAL_BAD_FILE_IDX(handle))
          return -1;
      fsal_file_t *fp = FSAL_IDX2FILE(handle);
      if (FSAL_BAD_FILE(fp))
          return -1;
      fifofs_file_extention_t *ext = (fifofs_file_extention_t *) fp->extension;
      int retval = fifo_put(ext->handle);
      if (retval < 0)
          warnprint("fifofs: close fd %d, handle %d failed!\n", handle, ext->handle);
      if (fp->extension)
          mem_free(fp->extension);
      fp->extension = NULL;
      if (fsal_file_free(fp) < 0)
          return -1;
      return 0;
  }
  
  fsal_t fifofs_fsal = {
      .name       = "fifofs",
      .list       = LIST_HEAD_INIT(fifofs_fsal.list),
      .subtable   = NULL,
      .mkfs       = NULL,
      .mount      = fsal_fifofs_mount,
      .unmount    = fsal_fifofs_unmount,
      .open       = fifoif_open,
      .close      = fifoif_close,
      .read       = fifoif_read,
      .write      = fifoif_write,
      .lseek      = NULL,
      .opendir    = NULL,
      .closedir   = NULL,
      .readdir    = NULL,
      .mkdir      = NULL,
      .unlink     = fifoif_unlink,
      .rename     = NULL,
      .ftruncate  = NULL,
      .fsync      = NULL,
      .state      = NULL,
      .chmod      = NULL,
      .fchmod     = NULL,
      .utime      = NULL,
      .feof       = NULL,
      .ferror     = NULL,
      .ftell      = NULL,
      .fsize      = NULL,
      .rewind     = NULL,
      .rewinddir  = NULL,
      .rmdir      = NULL,
      .chdir      = NULL,
      .ioctl      = fifoif_ioctl,
      .fcntl      = fifoif_fcntl,
      .fstat      = NULL,
      .access     = NULL,
      .incref     = fifoif_incref,
      .decref     = fifoif_decref,
      .fastio     = NULL,
  };
  
  static int fsal_fifofs_mount(char *source, char *target, char *fstype, unsigned long flags)
  {
      if (strcmp(fstype, "fifofs")) {
          errprint("mount fifofs type %s failed!\n", fstype);
          return -1;
      }
      if (fsal_path_insert(source, FIFOFS_PATH, target, &fifofs_fsal)) {
          dbgprint("%s: %s: insert path %s failed!\n", FS_MODEL_NAME,__func__, target);
          return -1;
      }
      return 0;
  }
  
  static int fsal_fifofs_unmount(char *path, unsigned long flags)
  {
      if (fsal_path_remove((void *) path)) {
          dbgprint("%s: %s: remove path %s failed!\n", FS_MODEL_NAME,__func__, path);
          return -1;
      }
      return 0;
  }
  
  void *fifofs_path_translate(const char *pathname, const char *check_path)
  {
      if (!pathname)
          return NULL;
      if (strncmp(pathname, (const char *) check_path, strlen(check_path)) != 0) {   /* 校验路径，不是设备文件系统就退出 */
          return NULL;
      }
      char *p = (char *) pathname;
      p += strlen(check_path);
      while (*p && *p == '/')
          p++;
      return p;
  }
  
  int sys_mkfifo(const char *pathname, mode_t mode)
  {
      if (!pathname)
          return -EINVAL;
      char *p = fifofs_path_translate((const char *) pathname, FIFO_DIR_PATH);
      if (!p) {
          errprint("sys_mkfifo: file path %s translate faield!\n", pathname);
          return -EINVAL;
      }
      return fifo_make(p, mode);
  }
  
  static int fifoif_unlink(char *pathname)
  {
      if (!pathname)
          return -EINVAL;
      char *p = fifofs_path_translate((const char *) pathname, FIFOFS_PATH);
      if (!p) {
          errprint("fifoif_unlink: file path %s translate faield!\n", pathname);
          return -EINVAL;
      }
      return fifo_remove(p);
  }
  
  static int fifoif_open(void *pathname, int flags)
  {
      char *p = fifofs_path_translate((const char *) pathname, FIFOFS_PATH);
      if (!p) {
          errprint("fifofs: path %s translate faield!\n", pathname);
          return -EINVAL;
      }
      fsal_file_t *fp = fsal_file_alloc();
      if (fp == NULL) {
          errprint("fifofs: alloc file struct failed!\n");
          return -ENOMEM;
      }
      fp->extension = mem_alloc(sizeof(fifofs_file_extention_t));
      if (!fp->extension) {
          errprint("fifofs: alloc file %s extension for open failed!\n", p);
          fsal_file_free(fp);
          return -ENOMEM;
      }
      fp->fsal = &fifofs_fsal;
      int handle = fifo_open(p, flags);
      if (handle < 0) {
          errprint("fifofs: open fifo %s failed!\n", p);
          mem_free(fp->extension);
          fsal_file_free(fp);
          return -ENOFILE;
      }
      fifofs_file_extention_t *ext = (fifofs_file_extention_t *) fp->extension;
      ext->handle = handle;
      return FSAL_FILE2IDX(fp);
  }
  