/*
 *  This function adds an entry in the database
 */
fsal_status_t fsal_internal_posixdb_add_entry(fsal_posixdb_conn * p_conn,
                                              fsal_name_t * p_filename,
                                              fsal_posixdb_fileinfo_t * p_info,
                                              posixfsal_handle_t * p_dir_handle,
                                              posixfsal_handle_t * p_new_handle)
{
  fsal_posixdb_status_t stdb;

  if(!p_info || !p_conn || !p_new_handle)       /* p_filename & p_dir_handle can be NULL for the root */
    ReturnCode(ERR_FSAL_FAULT, 0);

 add:
  stdb = fsal_posixdb_add(p_conn, p_info, p_dir_handle, p_filename, p_new_handle);

  if(stdb.major == ERR_FSAL_POSIXDB_CONSISTENCY)
    {                           /* there is already an entry with this path, but it's an inconsistent one */
      stdb = fsal_posixdb_deleteHandle(p_conn, p_new_handle);
      if(FSAL_POSIXDB_IS_ERROR(stdb))
        return posixdb2fsal_error(stdb);
      goto add;
    }
  else if(FSAL_POSIXDB_IS_ERROR(stdb))
    {
      return posixdb2fsal_error(stdb);
    }

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}
/** 
 * @brief Get the handle of a file, knowing its name and its parent dir
 * 
 * @param p_context 
 * @param p_parent_dir_handle 
 *    Handle of the parent directory
 * @param p_fsalname 
 *    Name of the object
 * @param p_infofs
 *    Information about the file (taken from the filesystem) to be compared to information stored in database
 * @param p_object_handle 
 *    Handle of the file.
 * 
 * @return
 *    ERR_FSAL_NOERR, if no error
 *    Anothere error code else.
 */
fsal_status_t fsal_internal_getInfoFromName(posixfsal_op_context_t * p_context, /* IN */
                                            posixfsal_handle_t * p_parent_dir_handle,   /* IN */
                                            fsal_name_t * p_fsalname,   /* IN */
                                            fsal_posixdb_fileinfo_t * p_infofs, /* IN */
                                            posixfsal_handle_t * p_object_handle)       /* OUT */
{
  fsal_posixdb_status_t stdb;
  fsal_status_t st;

  stdb = fsal_posixdb_getInfoFromName(p_context->p_conn,
                                      p_parent_dir_handle,
                                      p_fsalname, NULL, p_object_handle);
  switch (stdb.major)
    {
    case ERR_FSAL_POSIXDB_NOERR:
      /* No error, the object is in the database */
      /* check consistency */
      if(fsal_posixdb_consistency_check(&(p_object_handle->data.info), p_infofs))
        {
          /* Entry not consistent */
          /* Delete the Handle entry, then add a new one (with a Parent entry) */
          stdb = fsal_posixdb_deleteHandle(p_context->p_conn, p_object_handle);
          if(FSAL_POSIXDB_IS_ERROR(stdb) && FSAL_IS_ERROR(st = posixdb2fsal_error(stdb)))
            return st;
          /* don't break, add a new entry */
        }
      else
        {
          break;
        }
    case ERR_FSAL_POSIXDB_NOENT:
      /* object not in the database, add a new entry */
      st = fsal_internal_posixdb_add_entry(p_context->p_conn,
                                           p_fsalname,
                                           p_infofs,
                                           p_parent_dir_handle, p_object_handle);
      if(FSAL_IS_ERROR(st))
        return st;
      break;
    default:
      /* error */
      if(FSAL_IS_ERROR(st = posixdb2fsal_error(stdb)))
        return st;
    }

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}
Exemple #3
0
/**
 * FSAL_readdir :
 *     Read the entries of an opened directory.
 *     
 * \param dir_descriptor (input):
 *        Pointer to the directory descriptor filled by FSAL_opendir.
 * \param start_position (input):
 *        Cookie that indicates the first object to be read during
 *        this readdir operation.
 *        This should be :
 *        - FSAL_READDIR_FROM_BEGINNING for reading the content
 *          of the directory from the beginning.
 *        - The end_position parameter returned by the previous
 *          call to FSAL_readdir.
 * \param get_attr_mask (input)
 *        Specify the set of attributes to be retrieved for directory entries.
 * \param buffersize (input)
 *        The size (in bytes) of the buffer where
 *        the direntries are to be stored.
 * \param pdirent (output)
 *        Adresse of the buffer where the direntries are to be stored.
 * \param end_position (output)
 *        Cookie that indicates the current position in the directory.
 * \param nb_entries (output)
 *        Pointer to the number of entries read during the call.
 * \param end_of_dir (output)
 *        Pointer to a boolean that indicates if the end of dir
 *        has been reached during the call.
 * 
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t POSIXFSAL_readdir(fsal_dir_t * dir_descriptor,     /* IN */
                                fsal_cookie_t start_pos,      /* IN */
                                fsal_attrib_mask_t get_attr_mask,       /* IN */
                                fsal_mdsize_t buffersize,       /* IN */
                                fsal_dirent_t * p_pdirent,      /* OUT */
                                fsal_cookie_t * end_position,    /* OUT */
                                fsal_count_t * p_nb_entries,    /* OUT */
                                fsal_boolean_t * p_end_of_dir   /* OUT */
    )
{
  posixfsal_dir_t * p_dir_descriptor = (posixfsal_dir_t *) dir_descriptor;
  posixfsal_cookie_t start_position, telldir_pos;
  posixfsal_cookie_t * p_end_position = (posixfsal_cookie_t *) end_position;
  fsal_status_t st;
  fsal_posixdb_status_t stdb;
  fsal_count_t max_dir_entries;
  struct dirent *dp;
  struct dirent dpe;
  struct stat buffstat;
  fsal_path_t fsalpath;
  fsal_posixdb_fileinfo_t infofs;
  int rc;

  /*****************/
  /* sanity checks */
  /*****************/

  if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);

  max_dir_entries = (buffersize / sizeof(fsal_dirent_t));

  /***************************/
  /* seek into the directory */
  /***************************/
  memcpy ( (char *)&start_position.data.cookie, (char *)&start_pos.data, sizeof( off_t ) ) ;

  errno = 0;
  if(start_position.data.cookie == 0)
    {
      rewinddir(p_dir_descriptor->p_dir);
      rc = errno;
    }
  else
    {
      seekdir(p_dir_descriptor->p_dir, start_position.data.cookie);
      rc = errno;
    }

  if(rc)
    {
      st.major = posix2fsal_error(rc);
      st.minor = rc;
      goto readdir_error;
    }

  /************************/
  /* browse the directory */
  /************************/

  *p_nb_entries = 0;
  while(*p_nb_entries < max_dir_entries)
    {
    /***********************/
      /* read the next entry */
    /***********************/
      TakeTokenFSCall();
      rc = readdir_r(p_dir_descriptor->p_dir, &dpe, &dp);
      ReleaseTokenFSCall();
      if(rc)
        {
          st.major = posix2fsal_error(errno);
          st.minor = errno;
          goto readdir_error;
        }                       /* End of directory */
      if(!dp)
        {
          *p_end_of_dir = 1;
          break;
        }

    /***********************************/
      /* Get information about the entry */
    /***********************************/

      /* build the full path of the file into "fsalpath */
      if(FSAL_IS_ERROR
         (st =
          FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN, &(p_pdirent[*p_nb_entries].name))))
        goto readdir_error;
      memcpy(&fsalpath, &(p_dir_descriptor->path), sizeof(fsal_path_t));
      st = fsal_internal_appendFSALNameToFSALPath(&fsalpath,
                                                  &(p_pdirent[*p_nb_entries].name));
      if(FSAL_IS_ERROR(st))
        goto readdir_error;

      /* get object info */
      TakeTokenFSCall();
      rc = lstat(fsalpath.path, &buffstat);
      ReleaseTokenFSCall();
      if(rc)
        {
          st.major = posix2fsal_error(errno);
          st.minor = errno;
          goto readdir_error;
        }
      if(FSAL_IS_ERROR(st = fsal_internal_posix2posixdb_fileinfo(&buffstat, &infofs)))
        goto readdir_error;

    /********************/
      /* fills the handle */
    /********************/

      /* check for "." and ".." */
      if(!strcmp(dp->d_name, "."))
        {
          memcpy(&(p_pdirent[*p_nb_entries].handle), &(p_dir_descriptor->handle),
                 sizeof(posixfsal_handle_t));
        }
      else if(!strcmp(dp->d_name, ".."))
        {
          stdb = fsal_posixdb_getParentDirHandle(p_dir_descriptor->context.p_conn,
                                                 &(p_dir_descriptor->handle),
                                                 (posixfsal_handle_t *) &(p_pdirent[*p_nb_entries].handle));
          if(FSAL_POSIXDB_IS_ERROR(stdb) && FSAL_IS_ERROR(st = posixdb2fsal_error(stdb)))
            goto readdir_error;
        }
      else
        {
#ifdef _USE_POSIXDB_READDIR_BLOCK
          if(p_dir_descriptor->dbentries_count > -1)
            {                   /* look for the entry in dbentries */
              st = fsal_internal_getInfoFromChildrenList(&(p_dir_descriptor->context),
                                                         &(p_dir_descriptor->handle),
                                                         &(p_pdirent[*p_nb_entries].name),
                                                         &infofs,
                                                         p_dir_descriptor->p_dbentries,
                                                         p_dir_descriptor->
                                                         dbentries_count,
                                                         &(p_pdirent[*p_nb_entries].
                                                           handle));
            }
          else
#endif
            {                   /* get handle for the entry */
              st = fsal_internal_getInfoFromName(&(p_dir_descriptor->context),
                                                 &(p_dir_descriptor->handle),
                                                 &(p_pdirent[*p_nb_entries].name),
                                                 &infofs,
                                                 (posixfsal_handle_t *) &(p_pdirent[*p_nb_entries].handle));
            }
          if(FSAL_IS_ERROR(st))
            goto readdir_error;
        }                       /* end of name check for "." and ".." */

    /************************
     * Fills the attributes *
     ************************/
      p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask;
      st = posix2fsal_attributes(&buffstat, &(p_pdirent[*p_nb_entries].attributes));
      if(FSAL_IS_ERROR(st))
        goto readdir_error;

      /*
       * 
       **/
      telldir_pos.data.cookie = telldir(p_dir_descriptor->p_dir);
      memcpy(&p_pdirent[*p_nb_entries].cookie, &telldir_pos, sizeof(fsal_cookie_t));
      p_pdirent[*p_nb_entries].nextentry = NULL;
      if(*p_nb_entries)
        p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]);

      memcpy(p_end_position, &p_pdirent[*p_nb_entries].cookie, sizeof(fsal_cookie_t));
      (*p_nb_entries)++;
    };

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);

  /* return error, and free what must be freed */
 readdir_error:
  Return(st.major, st.minor, INDEX_FSAL_readdir);
}
/** 
 * @brief Get the handle of a file from a fsal_posixdb_child array, knowing its name
 * 
 * @param p_context 
 * @param p_parent_dir_handle 
 *    Handle of the parent directory
 * @param p_fsalname 
 *    Name of the object
 * @param p_infofs
 *    Information about the file (taken from the filesystem) to be compared to information stored in database
 * @param p_children
 *    fsal_posixdb_child array (that contains the entries of the directory stored in the db)
 * @param p_object_handle 
 *    Handle of the file.
 * 
 * @return
 *    ERR_FSAL_NOERR, if no error
 *    Anothere error code else.
 */
fsal_status_t fsal_internal_getInfoFromChildrenList(posixfsal_op_context_t * p_context, /* IN */
                                                    posixfsal_handle_t * p_parent_dir_handle,   /* IN */
                                                    fsal_name_t * p_fsalname,   /* IN */
                                                    fsal_posixdb_fileinfo_t * p_infofs, /* IN */
                                                    fsal_posixdb_child * p_children,    /* IN */
                                                    unsigned int children_count,        /* IN */
                                                    posixfsal_handle_t * p_object_handle)       /* OUT */
{
  fsal_posixdb_status_t stdb;
  fsal_status_t st;
  int cmp = -1;                 /* when no children is available */
  unsigned int count;

  /* sanity check */
  if(!p_context || !p_parent_dir_handle || !p_fsalname || (!p_children && children_count)
     || !p_object_handle)
    ReturnCode(ERR_FSAL_FAULT, 0);

  /* check if the filename is in the list */
  for(count = 0; count < children_count; count++)
    {
      cmp = FSAL_namecmp(p_fsalname, &(p_children[count].name));
      if(!cmp)
        break;
      /* maybe a sorted list could give better result */
    }

  switch (cmp)
    {
    case 0:
      /* Entry found : check consistency */

      if(fsal_posixdb_consistency_check(&(p_children[count].handle.data.info), p_infofs))
        {
          /* Entry not consistent */
          /* Delete the Handle entry, then add a new one (with a Parent entry) */
          stdb =
              fsal_posixdb_deleteHandle(p_context->p_conn, &(p_children[count].handle));

          if(FSAL_POSIXDB_IS_ERROR(stdb) && FSAL_IS_ERROR(st = posixdb2fsal_error(stdb)))
            return st;

          /* don't break, add a new entry */

        }
      else
        {
          memcpy(p_object_handle, &(p_children[count].handle),
                 sizeof(posixfsal_handle_t));
          break;
        }

    default:
      /* not found ! Add it */
      st = fsal_internal_posixdb_add_entry(p_context->p_conn,
                                           p_fsalname,
                                           p_infofs,
                                           p_parent_dir_handle, p_object_handle);
      if(FSAL_IS_ERROR(st))
        return st;
    }

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}
/**
 * Get a valid path associated to an handle.
 * The function selects many paths from the DB and return the first valid one. If is_dir is set, then only 1 path will be constructed from the database.
 */
fsal_status_t fsal_internal_getPathFromHandle(posixfsal_op_context_t * p_context,       /* IN */
                                              posixfsal_handle_t * p_handle,    /* IN */
                                              int is_dir,       /* IN */
                                              fsal_path_t * p_fsalpath, /* OUT */
                                              struct stat *p_buffstat /* OUT */ )
{
  fsal_status_t status;
  fsal_posixdb_status_t statusdb;
  int rc, errsv, count, i;
  fsal_posixdb_fileinfo_t infofs;
  fsal_path_t paths[global_fs_info.maxlink];

  if(!p_context || !p_handle || !p_fsalpath)
    ReturnCode(ERR_FSAL_FAULT, 0);

  /* if there is a path in the posixfsal_handle_t variable, then try to use it instead of querying the database for it */
  /* Read the path from the Handle. If it's valid & coherent, then no need to query the database ! */
  /* if !p_buffstat, we don't need to check the path */
  statusdb = fsal_posixdb_getInfoFromHandle(p_context->p_conn,
                                            p_handle,
                                            paths,
                                            (is_dir ? 1 : global_fs_info.maxlink),
                                            &count);
  if(FSAL_POSIXDB_IS_ERROR(statusdb)
     && FSAL_IS_ERROR(status = posixdb2fsal_error(statusdb)))
    return status;

  /* if !p_buffstat, then we do not stat the path to test if file is valid */
  if(p_buffstat)
    {
      for(i = 0; i < count; i++)
        {
          TakeTokenFSCall();
          rc = lstat(paths[i].path, p_buffstat);
          errsv = errno;
          ReleaseTokenFSCall();

          if(rc)
            {
              /* error : delete the bad path from the database */
              char dirc[FSAL_MAX_PATH_LEN];
              char basec[FSAL_MAX_PATH_LEN];
              fsal_path_t parentdir;
              fsal_name_t filename;
              posixfsal_handle_t parenthdl;
              char *dname, *bname;

              /* split /path/to/filename in /path/to & filename */
              strncpy(dirc, paths[i].path, FSAL_MAX_PATH_LEN);
              strncpy(basec, paths[i].path, FSAL_MAX_PATH_LEN);
              dname = dirname(dirc);
              bname = basename(basec);

              status = FSAL_str2path(dname, FSAL_MAX_PATH_LEN, &parentdir);
              status = FSAL_str2name(bname, FSAL_MAX_NAME_LEN, &filename);

              /* get the handle of /path/to */
              status = POSIXFSAL_lookupPath(&parentdir, p_context, &parenthdl, NULL);

              if(!FSAL_IS_ERROR(status))
                {
                  statusdb =
                      fsal_posixdb_delete(p_context->p_conn, &parenthdl, &filename, NULL);
                  /* no need to check if there was an error, because it doesn't change the behavior of the function */
                }

            }
          else
            {                   /* no error */
              FSAL_pathcpy(p_fsalpath, &(paths[0]));
              break;
            }
        }
      if(i == count)
        ReturnCode(ERR_FSAL_STALE, 0);

      /* check consistency */
      status = fsal_internal_posix2posixdb_fileinfo(p_buffstat, &infofs);
      if(FSAL_IS_ERROR(status))
        return status;

      if(fsal_posixdb_consistency_check(&(p_handle->data.info), &infofs))
        {
          /* not consistent !! */
          /* delete the stale handle */
          statusdb = fsal_posixdb_deleteHandle(p_context->p_conn, p_handle);
          if(FSAL_POSIXDB_IS_ERROR(statusdb)
             && FSAL_IS_ERROR(status = posixdb2fsal_error(statusdb)))
            return status;

          ReturnCode(ERR_FSAL_STALE, 0);
        }

    }
  else
    {
      /* @TODO : check that there si at liste 1 path */
      FSAL_pathcpy(p_fsalpath, &(paths[0]));
    }

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}