Example #1
0
int nfs3_Readdirplus(nfs_arg_t * parg,
                     exportlist_t * pexport,
                     fsal_op_context_t * pcontext,
                     cache_inode_client_t * pclient,
                     hash_table_t * ht, struct svc_req *preq, nfs_res_t * pres)
{
  static char __attribute__ ((__unused__)) funcName[] = "nfs3_Readdirplus";

  typedef char entry_name_array_item_t[FSAL_MAX_NAME_LEN];
  typedef char fh3_buffer_item_t[NFS3_FHSIZE];

  unsigned int delta = 0;
  cache_entry_t *dir_pentry = NULL;
  cache_entry_t *pentry_dot_dot = NULL;
  unsigned long dircount;
  unsigned long maxcount;
  fsal_attrib_list_t dir_attr;
  fsal_attrib_list_t entry_attr;
  unsigned int begin_cookie;
  unsigned int end_cookie;
  unsigned int cache_inode_cookie;
  cache_inode_dir_entry_t *dirent_array = NULL;
  unsigned int *cookie_array = NULL;
  cookieverf3 cookie_verifier;
  int rc;
  unsigned int i = 0;
  unsigned int num_entries;
  unsigned long space_used;
  unsigned long estimated_num_entries;
  unsigned long asked_num_entries;
  cache_inode_file_type_t dir_filetype;
  cache_inode_endofdir_t eod_met = UNASSIGNED_EOD;
  cache_inode_status_t cache_status;
  cache_inode_status_t cache_status_gethandle;
  fsal_handle_t *pfsal_handle = NULL;
  entry_name_array_item_t *entry_name_array = NULL;
  fh3_buffer_item_t *fh3_array = NULL;

  /* to avoid setting it on each error case */
  pres->res_readdir3.READDIR3res_u.resfail.dir_attributes.attributes_follow = FALSE;

  dircount = parg->arg_readdirplus3.dircount;
  maxcount = parg->arg_readdirplus3.maxcount;
  begin_cookie = (unsigned int)parg->arg_readdirplus3.cookie;
  space_used = sizeof(READDIRPLUS3resok);
  estimated_num_entries = dircount / sizeof(entryplus3);

  LogFullDebug(COMPONENT_NFS_READDIR,
      "---> nfs3_Readdirplus: dircount=%d  maxcount=%d  begin_cookie=%d  space_used=%d  estimated_num_entries=%d\n",
       dircount, maxcount, begin_cookie, space_used, estimated_num_entries);

  /* Is this a xattr FH ? */
  if(nfs3_Is_Fh_Xattr(&(parg->arg_readdirplus3.dir)))
    return nfs3_Readdirplus_Xattr(parg, pexport, pcontext, pclient, ht, preq, pres);

  /* Convert file handle into a vnode */
  /* BUGAZOMEU : rajouter acces direct au DIR_CONTINUE */
  if((dir_pentry = nfs_FhandleToCache(preq->rq_vers,
                                      NULL,
                                      &(parg->arg_readdirplus3.dir),
                                      NULL,
                                      NULL,
                                      &(pres->res_readdirplus3.status),
                                      NULL,
                                      &dir_attr, pcontext, pclient, ht, &rc)) == NULL)
    {
      /* return NFS_REQ_DROP ; */
      return rc;
    }

  /* Extract the filetype */
  dir_filetype = cache_inode_fsal_type_convert(dir_attr.type);

  /* Sanity checks -- must be a directory */

  if((dir_filetype != DIR_BEGINNING) && (dir_filetype != DIR_CONTINUE))
    {
      pres->res_readdirplus3.status = NFS3ERR_NOTDIR;
      return NFS_REQ_OK;
    }

  /* switch */
  memset(cookie_verifier, 0, sizeof(cookieverf3));

  /*
   * If cookie verifier is used, then an non-trivial value is
   * returned to the client         This value is the mtime of
   * the directory. If verifier is unused (as in many NFS
   * Servers) then only a set of zeros is returned (trivial
   * value) 
   */

  if(pexport->UseCookieVerifier)
    memcpy(cookie_verifier, &(dir_attr.mtime), sizeof(dir_attr.mtime));

  /*
   * nothing to do if != 0 because the area is already full of
   * zero 
   */

  if(pexport->UseCookieVerifier && (begin_cookie != 0))
    {
      /*
       * Not the first call, so we have to check the cookie
       * verifier 
       */
      if(memcmp(cookie_verifier, parg->arg_readdirplus3.cookieverf, NFS3_COOKIEVERFSIZE)
         != 0)
        {
          pres->res_readdirplus3.status = NFS3ERR_BAD_COOKIE;

          return NFS_REQ_OK;
        }
    }
#ifdef _DEBUG_MEMLEAKS
  /* For debugging memory leaks */
  BuddySetDebugLabel("cache_inode_dir_entry_t in nfs3_Readdirplus");
#endif

  if((dirent_array =
      (cache_inode_dir_entry_t *) Mem_Alloc(estimated_num_entries *
                                            sizeof(cache_inode_dir_entry_t))) == NULL)
    {
      pres->res_readdirplus3.status = NFS3ERR_IO;
      return NFS_REQ_DROP;
    }
#ifdef _DEBUG_MEMLEAKS
  /* For debugging memory leaks */
  BuddySetDebugLabel("cookie array in nfs3_Readdirplus");
#endif

  if((cookie_array =
      (unsigned int *)Mem_Alloc(estimated_num_entries * sizeof(unsigned int))) == NULL)
    {
      Mem_Free((char *)dirent_array);
      pres->res_readdirplus3.status = NFS3ERR_IO;
      return NFS_REQ_DROP;
    }

  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL;
  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE;

  /* How many entries will we retry from cache_inode ? */
  if(begin_cookie > 1)
    {
      asked_num_entries = estimated_num_entries;
      cache_inode_cookie = begin_cookie - 2;
    }
  else
    {
      asked_num_entries = ((estimated_num_entries > 2) ? estimated_num_entries - 2 : 0);        /* Keep space for '.' and '..' */
      cache_inode_cookie = 0;
    }

  /* A definition that will be very useful to avoid very long names for variables */
#define RES_READDIRPLUS_REPLY pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply

  /* Call readdir */
  if(cache_inode_readdir(dir_pentry,
                         cache_inode_cookie,
                         asked_num_entries,
                         &num_entries,
                         &end_cookie,
                         &eod_met,
                         dirent_array,
                         cookie_array,
                         ht, pclient, pcontext, &cache_status) == CACHE_INODE_SUCCESS)
    {
      LogFullDebug(COMPONENT_NFS_READDIR,
          "-- Readdirplus3 -> Call to cache_inode_readdir( cookie=%d, asked=%d ) -> num_entries = %d\n",
           cache_inode_cookie, asked_num_entries, num_entries);

      if(eod_met == END_OF_DIR)
        {
          LogFullDebug(COMPONENT_NFS_READDIR, "+++++++++++++++++++++++++++++++++++++++++> EOD MET \n");
        }

      /* If nothing was found, return nothing, but if cookie=0, we should return . and .. */
      if((num_entries == 0) && (asked_num_entries != 0) && (begin_cookie > 1))
        {
          pres->res_readdirplus3.status = NFS3_OK;
          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL;
          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE;

          nfs_SetPostOpAttr(pcontext, pexport,
                            dir_pentry,
                            NULL,
                            &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.
                              dir_attributes));

          memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf,
                 cookie_verifier, sizeof(cookieverf3));
        }
      else
        {
#ifdef _DEBUG_MEMLEAKS
          /* For debugging memory leaks */
          BuddySetDebugLabel("entry_name_array in nfs3_Readdirplus");
#endif
          /* Allocation of the structure for reply */
          entry_name_array =
              (entry_name_array_item_t *) Mem_Alloc(estimated_num_entries *
                                                    (FSAL_MAX_NAME_LEN + 1));

          if(entry_name_array == NULL)
            {
              Mem_Free((char *)dirent_array);
              Mem_Free((char *)cookie_array);
              return NFS_REQ_DROP;
            }
#ifdef _DEBUG_MEMLEAKS
          /* For debugging memory leaks */
          BuddySetDebugLabel("READDIRPLUS3res_u.resok.reply.entries");
#endif
          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries =
              (entryplus3 *) Mem_Alloc(estimated_num_entries * sizeof(entryplus3));

          if(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries == NULL)
            {
              Mem_Free((char *)dirent_array);
              Mem_Free((char *)cookie_array);
              Mem_Free((char *)entry_name_array);
              return NFS_REQ_DROP;
            }

          /* Allocation of the file handles */
#ifdef _DEBUG_MEMLEAKS
          /* For debugging memory leaks */
          BuddySetDebugLabel("Filehandle V3 in nfs3_Readdirplus");
#endif
          fh3_array =
              (fh3_buffer_item_t *) Mem_Alloc(estimated_num_entries * NFS3_FHSIZE);

#ifdef _DEBUG_MEMLEAKS
          /* For debugging memory leaks */
          BuddySetDebugLabel("N/A");
#endif

          if(fh3_array == NULL)
            {
              Mem_Free((char *)dirent_array);
              Mem_Free((char *)cookie_array);
              Mem_Free((char *)entry_name_array);

              return NFS_REQ_DROP;
            }

          delta = 0;

          /* manage . and .. */
          if(begin_cookie == 0)
            {
              /* Fill in '.' */
              if(estimated_num_entries > 0)
                {
                  if((pfsal_handle = cache_inode_get_fsal_handle(dir_pentry,
                                                                 &cache_status_gethandle))
                     == NULL)
                    {
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)cookie_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle);
                      return NFS_REQ_OK;
                    }

                  FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext),
                                    FSAL_DIGEST_FILEID3,
                                    pfsal_handle,
                                    (caddr_t) & (RES_READDIRPLUS_REPLY.entries[0].
                                                 fileid));

                  RES_READDIRPLUS_REPLY.entries[0].name = entry_name_array[0];
                  strcpy(RES_READDIRPLUS_REPLY.entries[0].name, ".");

                  RES_READDIRPLUS_REPLY.entries[0].cookie = 1;

                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0].
                      name_handle.post_op_fh3_u.handle.data.data_val =
                      (char *)fh3_array[0];

                  if(nfs3_FSALToFhandle
                     (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0].
                      name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0)
                    {
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)cookie_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = NFS3ERR_BADHANDLE;
                      return NFS_REQ_OK;
                    }

                  RES_READDIRPLUS_REPLY.entries[0].name_attributes.attributes_follow =
                      FALSE;
                  RES_READDIRPLUS_REPLY.entries[0].name_handle.handle_follows = FALSE;

                  cache_inode_get_attributes(dir_pentry, &entry_attr);

                  /* Set PostPoFh3 structure */
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0].
                      name_handle.handle_follows = TRUE;
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0].
                      name_handle.post_op_fh3_u.handle.data.data_len =
                      sizeof(file_handle_v3_t);

                  nfs_SetPostOpAttr(pcontext, pexport,
                                    dir_pentry,
                                    &entry_attr,
                                    &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.
                                      reply.entries[0].name_attributes));

                  delta += 1;
                }

            }

          /* Fill in '..' */
          if(begin_cookie <= 1)
            {
              if(estimated_num_entries > delta)
                {
                  if((pentry_dot_dot = cache_inode_lookupp(dir_pentry,
                                                           ht,
                                                           pclient,
                                                           pcontext,
                                                           &cache_status_gethandle)) ==
                     NULL)
                    {
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)cookie_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle);
                      return NFS_REQ_OK;
                    }

                  if((pfsal_handle = cache_inode_get_fsal_handle(pentry_dot_dot,
                                                                 &cache_status_gethandle))
                     == NULL)
                    {
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)cookie_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle);
                      return NFS_REQ_OK;
                    }

                  FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext),
                                    FSAL_DIGEST_FILEID3,
                                    pfsal_handle,
                                    (caddr_t) & (RES_READDIRPLUS_REPLY.entries[delta].
                                                 fileid));

                  RES_READDIRPLUS_REPLY.entries[delta].name = entry_name_array[delta];
                  strcpy(RES_READDIRPLUS_REPLY.entries[delta].name, "..");

                  /* Getting a file handle */
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta].
                      name_handle.post_op_fh3_u.handle.data.data_val =
                      (char *)fh3_array[delta];

                  if(nfs3_FSALToFhandle
                     (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0].
                      name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0)
                    {
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)cookie_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = NFS3ERR_BADHANDLE;
                      return NFS_REQ_OK;
                    }

                  RES_READDIRPLUS_REPLY.entries[delta].cookie = 2;

                  RES_READDIRPLUS_REPLY.entries[delta].name_attributes.attributes_follow =
                      FALSE;
                  RES_READDIRPLUS_REPLY.entries[delta].name_handle.handle_follows = FALSE;

                  cache_inode_get_attributes(pentry_dot_dot, &entry_attr);

                  /* Set PostPoFh3 structure */
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta].
                      name_handle.handle_follows = TRUE;
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta].
                      name_handle.post_op_fh3_u.handle.data.data_len =
                      sizeof(file_handle_v3_t);

                  nfs_SetPostOpAttr(pcontext, pexport,
                                    pentry_dot_dot,
                                    &entry_attr,
                                    &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.
                                      reply.entries[delta].name_attributes));

                }
              RES_READDIRPLUS_REPLY.entries[0].nextentry =
                  &(RES_READDIRPLUS_REPLY.entries[delta]);

              if(num_entries > delta + 1)       /* not 0 ??? */
                RES_READDIRPLUS_REPLY.entries[delta].nextentry =
                    &(RES_READDIRPLUS_REPLY.entries[delta + 1]);
              else
                RES_READDIRPLUS_REPLY.entries[delta].nextentry = NULL;

              delta += 1;
            }
          /* if( begin_cookie == 0 ) */
          for(i = delta; i < num_entries + delta; i++)
            {
              unsigned long needed;

              /* dircount is the size without the FH and attributes overhead, so entry3 is used intead of entryplus3 */
              needed =
                  sizeof(entry3) + ((strlen(dirent_array[i - delta].name.name) + 3) & ~3);

              /* LogFullDebug(COMPONENT_NFS_READDIR, "==============> i=%d sizeof(entryplus3)=%d needed=%d space_used=%d maxcount=%d num_entries=%d asked_num_entries=%d\n",
                 i, sizeof( entryplus3 ), needed, space_used, maxcount, num_entries, asked_num_entries ) ; */
              if((space_used += needed) > maxcount)
                {
                  if(i == delta)
                    {
                      /*
                       * Not enough room to make even a single reply 
                       */
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)cookie_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = NFS3ERR_TOOSMALL;

                      return NFS_REQ_OK;
                    }
                  break;        /* Make post traitement */
                }

              /*
               * Get information specific to this entry
               */
              if((pfsal_handle =
                  cache_inode_get_fsal_handle(dirent_array[i - delta].pentry,
                                              &cache_status_gethandle)) == NULL)
                {
                  Mem_Free((char *)dirent_array);
                  Mem_Free((char *)cookie_array);
                  Mem_Free((char *)entry_name_array);
                  Mem_Free((char *)fh3_array);

                  pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle);
                  return NFS_REQ_OK;
                }

              /* Now fill in the replyed entryplus3 list */
              FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext),
                                FSAL_DIGEST_FILEID3,
                                pfsal_handle,
                                (caddr_t) & (RES_READDIRPLUS_REPLY.entries[i].fileid));

              FSAL_name2str(&dirent_array[i - delta].name, entry_name_array[i],
                            FSAL_MAX_NAME_LEN);
              RES_READDIRPLUS_REPLY.entries[i].name = entry_name_array[i];

              if(i != num_entries + delta - 1)
                RES_READDIRPLUS_REPLY.entries[i].cookie = cookie_array[i + 1 - delta] + 2;
              else
                RES_READDIRPLUS_REPLY.entries[i].cookie = end_cookie + 2;

              RES_READDIRPLUS_REPLY.entries[i].name_attributes.attributes_follow = FALSE;
              RES_READDIRPLUS_REPLY.entries[i].name_handle.handle_follows = FALSE;

              cache_inode_get_attributes(dirent_array[i - delta].pentry, &entry_attr);

              pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.
                  post_op_fh3_u.handle.data.data_val = (char *)fh3_array[i];

              /* Compute the NFSv3 file handle */
              if(nfs3_FSALToFhandle
                 (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].
                  name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0)
                {
                  Mem_Free((char *)dirent_array);
                  Mem_Free((char *)cookie_array);
                  Mem_Free((char *)entry_name_array);
                  Mem_Free((char *)fh3_array);

                  pres->res_readdirplus3.status = NFS3ERR_BADHANDLE;
                  return NFS_REQ_OK;
                }
              LogFullDebug(COMPONENT_NFS_READDIR,
                  "-- Readdirplus3 -> i=%d num_entries=%d needed=%d space_used=%lu maxcount=%lu Name=%s FileId=%llu Cookie=%llu\n",
                   i, num_entries, needed, space_used, maxcount,
                   dirent_array[i - delta].name.name,
                   RES_READDIRPLUS_REPLY.entries[i].fileid,
                   RES_READDIRPLUS_REPLY.entries[i].cookie);

              /* Set PostPoFh3 structure */
              pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.
                  handle_follows = TRUE;
              pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.
                  post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t);

              nfs_SetPostOpAttr(pcontext, pexport,
                                dirent_array[i - delta].pentry,
                                &entry_attr,
                                &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.
                                  entries[i].name_attributes));

              RES_READDIRPLUS_REPLY.entries[i].nextentry = NULL;
              if(i != 0)
                RES_READDIRPLUS_REPLY.entries[i - 1].nextentry =
                    &(RES_READDIRPLUS_REPLY.entries[i]);
            }

          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE;
        }

      nfs_SetPostOpAttr(pcontext,
                        pexport,
                        dir_pentry,
                        &dir_attr,
                        &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes));

      memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf,
             cookie_verifier, sizeof(cookieverf3));

      pres->res_readdirplus3.status = NFS3_OK;

      if((eod_met == END_OF_DIR) && (i == num_entries + delta))
        {
          /* End of directory */
          LogFullDebug(COMPONENT_NFS_READDIR,
              "============================================================> EOD MET !!!!!!\n");
          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE;
        }
      else
        pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE;

      nfs_SetPostOpAttr(pcontext, pexport,
                        dir_pentry,
                        &dir_attr,
                        &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes));
      memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier,
             sizeof(cookieverf3));

      LogFullDebug(COMPONENT_NFS_READDIR,"============================================================\n");

      /* Free the memory */
      Mem_Free((char *)dirent_array);
      Mem_Free((char *)cookie_array);

      return NFS_REQ_OK;
    }

  /* If we are here, there was an error */

  /* Free the memory */
  Mem_Free((char *)dirent_array);
  Mem_Free((char *)cookie_array);
  Mem_Free((char *)entry_name_array);
  Mem_Free((char *)fh3_array);

  /* Is this a retryable error */
  if(nfs_RetryableError(cache_status))
    return NFS_REQ_DROP;

  /* Set failed status */
  nfs_SetFailedStatus(pcontext, pexport,
                      NFS_V3,
                      cache_status,
                      NULL,
                      &pres->res_readdirplus3.status,
                      dir_pentry,
                      &(pres->res_readdirplus3.READDIRPLUS3res_u.resfail.dir_attributes),
                      NULL, NULL, NULL, NULL, NULL, NULL);

  return NFS_REQ_OK;
}                               /* nfs3_Readdirplus */
Example #2
0
int nfs_Mkdir(nfs_arg_t * parg,
              exportlist_t * pexport,
              fsal_op_context_t * pcontext,
              cache_inode_client_t * pclient,
              hash_table_t * ht, struct svc_req *preq, nfs_res_t * pres)
{
  static char __attribute__ ((__unused__)) funcName[] = "nfs_Mkdir";

  char *str_dir_name = NULL;
  fsal_accessmode_t mode = 0;
  cache_entry_t *dir_pentry = NULL;
  cache_entry_t *parent_pentry = NULL;
  int rc = 0;
  fsal_attrib_list_t parent_attr;
  fsal_attrib_list_t attr;
  fsal_attrib_list_t *ppre_attr;
  fsal_attrib_list_t attr_parent_after;
  cache_inode_file_type_t parent_filetype;
  fsal_handle_t *pfsal_handle;
  fsal_name_t dir_name;
  cache_inode_status_t cache_status = CACHE_INODE_SUCCESS;
  cache_inode_status_t cache_status_lookup;

  if(isDebug(COMPONENT_NFSPROTO))
    {
      char str[LEN_FH_STR];

      switch (preq->rq_vers)
        {
        case NFS_V2:
          str_dir_name = parg->arg_mkdir2.where.name;
          break;
        case NFS_V3:
          str_dir_name = parg->arg_mkdir3.where.name;
          break;
        }

      nfs_FhandleToStr(preq->rq_vers,
                       &(parg->arg_mkdir2.where.dir),
                       &(parg->arg_mkdir3.where.dir),
                       NULL,
                       str);
      LogDebug(COMPONENT_NFSPROTO,
               "REQUEST PROCESSING: Calling nfs_Mkdir handle: %s name: %s",
               str, str_dir_name);
    }

  if(preq->rq_vers == NFS_V3)
    {
      /* to avoid setting it on each error case */
      pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.before.attributes_follow = FALSE;
      pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.after.attributes_follow = FALSE;
      ppre_attr = NULL;
    }

  if((parent_pentry = nfs_FhandleToCache(preq->rq_vers,
                                         &(parg->arg_mkdir2.where.dir),
                                         &(parg->arg_mkdir3.where.dir),
                                         NULL,
                                         &(pres->res_dirop2.status),
                                         &(pres->res_mkdir3.status),
                                         NULL,
                                         &parent_attr,
                                         pcontext, pclient, ht, &rc)) == NULL)
    {
      /* Stale NFS FH ? */
      return rc;
    }

  /* get directory attributes before action (for V3 reply) */
  ppre_attr = &parent_attr;

  /* Extract the filetype */
  parent_filetype = cache_inode_fsal_type_convert(parent_attr.type);

  /*
   * Sanity checks: 
   */
  if(parent_filetype != DIRECTORY)
    {
      switch (preq->rq_vers)
        {
        case NFS_V2:
          pres->res_dirop2.status = NFSERR_NOTDIR;
          break;

        case NFS_V3:
          pres->res_mkdir3.status = NFS3ERR_NOTDIR;
          break;
        }

      return NFS_REQ_OK;
    }

  switch (preq->rq_vers)
    {
    case NFS_V2:
      str_dir_name = parg->arg_mkdir2.where.name;

      if(parg->arg_mkdir2.attributes.mode != (unsigned int)-1)
        {
          mode = (fsal_accessmode_t) parg->arg_mkdir2.attributes.mode;
        }
      else
        {
          mode = (fsal_accessmode_t) 0;
        }
      break;

    case NFS_V3:
      str_dir_name = parg->arg_mkdir3.where.name;

      if(parg->arg_mkdir3.attributes.mode.set_it == TRUE)
        mode = (fsal_accessmode_t) parg->arg_mkdir3.attributes.mode.set_mode3_u.mode;
      else
        mode = (fsal_accessmode_t) 0;
      break;
    }

  //if(str_dir_name == NULL || strlen(str_dir_name) == 0)
  if(str_dir_name == NULL || *str_dir_name == '\0' )
    {
      if(preq->rq_vers == NFS_V2)
        pres->res_dirop2.status = NFSERR_IO;
      if(preq->rq_vers == NFS_V3)
        pres->res_mkdir3.status = NFS3ERR_INVAL;
    }
  else
    {
      /* Make the directory */
      if((cache_status = cache_inode_error_convert(FSAL_str2name(str_dir_name,
                                                                 FSAL_MAX_NAME_LEN,
                                                                 &dir_name))) ==
         CACHE_INODE_SUCCESS)
        {
          /*
           * Lookup file to see if it exists.  If so, use it.  Otherwise
           * create a new one.  
           */
          dir_pentry = cache_inode_lookup( parent_pentry,
                                           &dir_name,
                                           pexport->cache_inode_policy,
                                           &attr,
                                           ht, 
                                           pclient, 
                                           pcontext, 
                                           &cache_status_lookup);

          if(cache_status_lookup == CACHE_INODE_NOT_FOUND)
            {
              /* Create the directory */
              if((dir_pentry = cache_inode_create(parent_pentry,
                                                  &dir_name,
                                                  DIRECTORY,
                                                  pexport->cache_inode_policy,
                                                  mode,
                                                  NULL,
                                                  &attr,
                                                  ht,
                                                  pclient,
                                                  pcontext, &cache_status)) != NULL)
                {
                  /*
                   * Get the FSAL handle for this entry 
                   */
                  pfsal_handle = cache_inode_get_fsal_handle(dir_pentry, &cache_status);

                  if(cache_status == CACHE_INODE_SUCCESS)
                    {
                      switch (preq->rq_vers)
                        {
                        case NFS_V2:
                          /* Build file handle */
                          if(!nfs2_FSALToFhandle
                             (&(pres->res_dirop2.DIROP2res_u.diropok.file), pfsal_handle,
                              pexport))
                            pres->res_dirop2.status = NFSERR_IO;
                          else
                            {
                              /*
                               * Build entry
                               * attributes 
                               */
                              if(nfs2_FSALattr_To_Fattr(pexport, &attr,
                                                        &(pres->res_dirop2.DIROP2res_u.
                                                          diropok.attributes)) == 0)
                                pres->res_dirop2.status = NFSERR_IO;
                              else
                                pres->res_dirop2.status = NFS_OK;
                            }
                          break;

                        case NFS_V3:
                          /* Build file handle */
                          if((pres->res_mkdir3.MKDIR3res_u.resok.obj.post_op_fh3_u.
                              handle.data.data_val = Mem_Alloc_Label(NFS3_FHSIZE,
                                                                     "Filehandle V3 in nfs3_mkdir")) == NULL)
                            {
                              pres->res_mkdir3.status = NFS3ERR_IO;
                              return NFS_REQ_OK;
                            }

                          if(nfs3_FSALToFhandle
                             (&pres->res_mkdir3.MKDIR3res_u.resok.obj.post_op_fh3_u.
                              handle, pfsal_handle, pexport) == 0)
                            {
                              Mem_Free((char *)pres->res_mkdir3.MKDIR3res_u.resok.obj.
                                       post_op_fh3_u.handle.data.data_val);
                              pres->res_mkdir3.status = NFS3ERR_INVAL;
                              return NFS_REQ_OK;
                            }
                          else
                            {
                              /* Set Post Op Fh3 structure */
                              pres->res_mkdir3.MKDIR3res_u.resok.obj.handle_follows =
                                  TRUE;
                              pres->res_mkdir3.MKDIR3res_u.resok.obj.post_op_fh3_u.handle.
                                  data.data_len = sizeof(file_handle_v3_t);

                              /*
                               * Build entry
                               * attributes 
                               */
                              nfs_SetPostOpAttr(pcontext, pexport,
                                                dir_pentry,
                                                &attr,
                                                &(pres->res_mkdir3.MKDIR3res_u.resok.
                                                  obj_attributes));

                              /* Get the attributes of the parent after the operation */
                              cache_inode_get_attributes(parent_pentry,
                                                         &attr_parent_after);

                              /*
                               * Build Weak Cache
                               * Coherency data 
                               */
                              nfs_SetWccData(pcontext, pexport,
                                             parent_pentry,
                                             ppre_attr,
                                             &attr_parent_after,
                                             &(pres->res_mkdir3.MKDIR3res_u.resok.
                                               dir_wcc));

                              pres->res_mkdir3.status = NFS3_OK;
                            }

                          break;
                        }
                      return NFS_REQ_OK;
                    }
                }
            }                   /* If( cache_status_lookup == CACHE_INODE_NOT_FOUND ) */
          else
            {
              /* object already exists or failure during lookup */
              if(cache_status_lookup == CACHE_INODE_SUCCESS)
                {
                  /* Trying to create a file that already exists */
                  cache_status = CACHE_INODE_ENTRY_EXISTS;

                  switch (preq->rq_vers)
                    {
                    case NFS_V2:
                      pres->res_dirop2.status = NFSERR_EXIST;
                      break;

                    case NFS_V3:
                      pres->res_mkdir3.status = NFS3ERR_EXIST;
                      break;
                    }
                }
              else
                {
                  /* Server fault */
                  cache_status = cache_status_lookup;

                  switch (preq->rq_vers)
                    {
                    case NFS_V2:
                      pres->res_dirop2.status = NFSERR_IO;
                      break;

                    case NFS_V3:
                      pres->res_mkdir3.status = NFS3ERR_INVAL;
                      break;
                    }
                }

              nfs_SetFailedStatus(pcontext, pexport,
                                  preq->rq_vers,
                                  cache_status,
                                  &pres->res_dirop2.status,
                                  &pres->res_mkdir3.status,
                                  NULL, NULL,
                                  parent_pentry,
                                  ppre_attr,
                                  &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc),
                                  NULL, NULL, NULL);

              return NFS_REQ_OK;
            }
        }
    }

  /* If we are here, there was an error */
  if(nfs_RetryableError(cache_status))
    {
      return NFS_REQ_DROP;

    }
  nfs_SetFailedStatus(pcontext, pexport,
                      preq->rq_vers,
                      cache_status,
                      &pres->res_dirop2.status,
                      &pres->res_mkdir3.status,
                      NULL, NULL,
                      parent_pentry,
                      ppre_attr,
                      &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc), NULL, NULL, NULL);

  return NFS_REQ_OK;

}