nfs-ganesha 1.4

nfs4_op_create.c

Go to the documentation of this file.
00001  /*
00002   * vim:expandtab:shiftwidth=8:tabstop=8:
00003   *
00004   * Copyright CEA/DAM/DIF  (2008)
00005   * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006   *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007   *
00008   *
00009   * This program is free software; you can redistribute it and/or
00010   * modify it under the terms of the GNU Lesser General Public
00011   * License as published by the Free Software Foundation; either
00012   * version 3 of the License, or (at your option) any later version.
00013   * 
00014   * This program is distributed in the hope that it will be useful,
00015   * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017   * Lesser General Public License for more details.
00018   * 
00019   * You should have received a copy of the GNU Lesser General Public
00020   * License along with this library; if not, write to the Free Software
00021   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022   * 
00023   * ---------------------------------------
00024   */
00025 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #ifdef _SOLARIS
00041 #include "solaris_port.h"
00042 #endif
00043 
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <pthread.h>
00047 #include <fcntl.h>
00048 #include <sys/file.h>           /* for having FNDELAY */
00049 #include "HashData.h"
00050 #include "HashTable.h"
00051 #include "log.h"
00052 #include "ganesha_rpc.h"
00053 #include "nfs23.h"
00054 #include "nfs4.h"
00055 #include "mount.h"
00056 #include "nfs_core.h"
00057 #include "cache_inode.h"
00058 #include "nfs_exports.h"
00059 #include "nfs_creds.h"
00060 #include "nfs_proto_functions.h"
00061 #include "nfs_proto_tools.h"
00062 #include "nfs_tools.h"
00063 #include "nfs_file_handle.h"
00064 
00078 #define arg_CREATE4 op->nfs_argop4_u.opcreate
00079 #define res_CREATE4 resp->nfs_resop4_u.opcreate
00080 
00081 int nfs4_op_create(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
00082 {
00083   char __attribute__ ((__unused__)) funcname[] = "nfs4_op_create";
00084 
00085   cache_entry_t        * pentry_parent = NULL;
00086   cache_entry_t        * pentry_new = NULL;
00087   fsal_attrib_list_t     attr_parent;
00088   fsal_attrib_list_t     attr_new;
00089   fsal_attrib_list_t     sattr;
00090   fsal_handle_t        * pnewfsal_handle = NULL;
00091   nfs_fh4                newfh4;
00092   cache_inode_status_t   cache_status;
00093   int                    convrc = 0;
00094   fsal_accessmode_t      mode = 0777;
00095   fsal_name_t            name;
00096 #ifdef _USE_QUOTA
00097   fsal_status_t          fsal_status ;
00098 #endif
00099   cache_inode_create_arg_t create_arg;
00100   unsigned int             i = 0;
00101 
00102   memset(&create_arg, 0, sizeof(create_arg));
00103 
00104   resp->resop = NFS4_OP_CREATE;
00105   res_CREATE4.status = NFS4_OK;
00106 
00107   /* Do basic checks on a filehandle */
00108   res_CREATE4.status = nfs4_sanity_check_FH(data, 0LL);
00109   if(res_CREATE4.status != NFS4_OK)
00110     return res_CREATE4.status;
00111 
00112 #ifdef _USE_QUOTA
00113   /* if quota support is active, then we should check is the FSAL allows inode creation or not */
00114   fsal_status = FSAL_check_quota( data->pexport->fullpath, 
00115                                   FSAL_QUOTA_INODES,
00116                                   FSAL_OP_CONTEXT_TO_UID( data->pcontext ) ) ;
00117   if( FSAL_IS_ERROR( fsal_status ) )
00118     {
00119       res_CREATE4.status = NFS4ERR_DQUOT ;
00120       return res_CREATE4.status;
00121     }
00122 #endif /* _USE_QUOTA */
00123 
00124   /* Pseudo Fs is explictely a Read-Only File system */
00125   if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
00126     {
00127       res_CREATE4.status = NFS4ERR_ROFS;
00128       return res_CREATE4.status;
00129     }
00130 
00131   if (nfs_export_check_security(data->reqp, data->pexport) == FALSE)
00132     {
00133       res_CREATE4.status = NFS4ERR_PERM;
00134       return res_CREATE4.status;
00135     }
00136 
00137   /* Ask only for supported attributes */
00138   if(!nfs4_Fattr_Supported(&arg_CREATE4.createattrs))
00139     {
00140       res_CREATE4.status = NFS4ERR_ATTRNOTSUPP;
00141       return res_CREATE4.status;
00142     }
00143 
00144   /* Do not use READ attr, use WRITE attr */
00145   if(!nfs4_Fattr_Check_Access(&arg_CREATE4.createattrs, FATTR4_ATTR_WRITE))
00146     {
00147       res_CREATE4.status = NFS4ERR_INVAL;
00148       return res_CREATE4.status;
00149     }
00150 
00151   /* Check for name to long */
00152   if(arg_CREATE4.objname.utf8string_len > FSAL_MAX_NAME_LEN)
00153     {
00154       res_CREATE4.status = NFS4ERR_NAMETOOLONG;
00155       return res_CREATE4.status;
00156     }
00157 
00158   /* 
00159    * This operation is used to create a non-regular file, 
00160    * this means: - a symbolic link
00161    *             - a block device file
00162    *             - a character device file
00163    *             - a socket file
00164    *             - a fifo
00165    *             - a directory 
00166    *
00167    * You can't use this operation to create a regular file, you have to use NFS4_OP_OPEN for this
00168    */
00169 
00170   /* Convert the UFT8 objname to a regular string */
00171   if(arg_CREATE4.objname.utf8string_len == 0)
00172     {
00173       res_CREATE4.status = NFS4ERR_INVAL;
00174       return res_CREATE4.status;
00175     }
00176 
00177   if(utf82str(name.name, sizeof(name.name), &arg_CREATE4.objname) == -1)
00178     {
00179       res_CREATE4.status = NFS4ERR_INVAL;
00180       return res_CREATE4.status;
00181     }
00182   name.len = strlen(name.name);
00183 
00184   /* Sanuty check: never create a directory named '.' or '..' */
00185   if(arg_CREATE4.objtype.type == NF4DIR)
00186     {
00187       if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT)
00188          || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT))
00189         {
00190           res_CREATE4.status = NFS4ERR_BADNAME;
00191           return res_CREATE4.status;
00192         }
00193 
00194     }
00195 
00196   /* Filename should contain not slash */
00197   for(i = 0; i < name.len; i++)
00198     {
00199       if(name.name[i] == '/')
00200         {
00201           res_CREATE4.status = NFS4ERR_BADCHAR;
00202           return res_CREATE4.status;
00203         }
00204     }
00205   /* Convert current FH into a cached entry, the current_pentry (assocated with the current FH will be used for this */
00206   pentry_parent = data->current_entry;
00207 
00208   /* The currentFH must point to a directory (objects are always created within a directory) */
00209   if(data->current_filetype != DIRECTORY)
00210     {
00211       res_CREATE4.status = NFS4ERR_NOTDIR;
00212       return res_CREATE4.status;
00213     }
00214 
00215   /* get attributes of parent directory, for 'change4' info replyed */
00216   if((cache_status = cache_inode_getattr(pentry_parent,
00217                                          &attr_parent,
00218                                          data->pcontext,
00219                                          &cache_status)) != CACHE_INODE_SUCCESS)
00220     {
00221       res_CREATE4.status = nfs4_Errno(cache_status);
00222       return res_CREATE4.status;
00223     }
00224 
00225   res_CREATE4.CREATE4res_u.resok4.cinfo.before
00226        = cache_inode_get_changeid4(pentry_parent);
00227 
00228   /* Convert the incoming fattr4 to a vattr structure, if such arguments are supplied */
00229   if(arg_CREATE4.createattrs.attrmask.bitmap4_len != 0)
00230     {
00231       /* Arguments were supplied, extract them */
00232       convrc = nfs4_Fattr_To_FSAL_attr(&sattr, &(arg_CREATE4.createattrs));
00233 
00234       if(convrc != NFS4_OK)
00235         {
00236           res_CREATE4.status = convrc;
00237           return res_CREATE4.status;
00238         }
00239     }
00240 
00241   /* Create either a symbolic link or a directory */
00242   switch (arg_CREATE4.objtype.type)
00243     {
00244     case NF4LNK:
00245       /* Convert the name to link from into a regular string */
00246       if(arg_CREATE4.objtype.createtype4_u.linkdata.utf8string_len == 0)
00247         {
00248           res_CREATE4.status = NFS4ERR_INVAL;
00249           return res_CREATE4.status;
00250         }
00251       else
00252         {
00253           if(utf82str
00254              (create_arg.link_content.path, sizeof(create_arg.link_content.path),
00255               &arg_CREATE4.objtype.createtype4_u.linkdata) == -1)
00256             {
00257               res_CREATE4.status = NFS4ERR_INVAL;
00258               return res_CREATE4.status;
00259             }
00260           create_arg.link_content.len = strlen(create_arg.link_content.path);
00261         }
00262 
00263       /* do the symlink operation */
00264       if((pentry_new = cache_inode_create(pentry_parent,
00265                                           &name,
00266                                           SYMBOLIC_LINK,
00267                                           mode,
00268                                           &create_arg,
00269                                           &attr_new,
00270                                           data->pcontext, &cache_status)) == NULL)
00271         {
00272           res_CREATE4.status = nfs4_Errno(cache_status);
00273           return res_CREATE4.status;
00274         }
00275 
00276       /* If entry exists pentry_new is not null but cache_status was set */
00277       if(cache_status == CACHE_INODE_ENTRY_EXISTS)
00278         {
00279           res_CREATE4.status = NFS4ERR_EXIST;
00280           cache_inode_put(pentry_new);
00281           return res_CREATE4.status;
00282         }
00283 
00284       break;
00285     case NF4DIR:
00286       /* Create a new directory */
00287 
00288       /* The create_arg structure contains the information "newly created directory"
00289        * to be passed to cache_inode_new_entry from cache_inode_create */
00290       create_arg.newly_created_dir = TRUE ;
00291 
00292       if((pentry_new = cache_inode_create(pentry_parent,
00293                                           &name,
00294                                           DIRECTORY,
00295                                           mode,
00296                                           &create_arg,
00297                                           &attr_new,
00298                                           data->pcontext, &cache_status)) == NULL)
00299         {
00300           res_CREATE4.status = nfs4_Errno(cache_status);
00301           return res_CREATE4.status;
00302         }
00303 
00304       /* If entry exists pentry_new is not null but cache_status was set */
00305       if(cache_status == CACHE_INODE_ENTRY_EXISTS)
00306         {
00307           res_CREATE4.status = NFS4ERR_EXIST;
00308           cache_inode_put(pentry_new);
00309           return res_CREATE4.status;
00310         }
00311       break;
00312 
00313     case NF4SOCK:
00314 
00315       /* Create a new socket file */
00316       if((pentry_new = cache_inode_create(pentry_parent,
00317                                           &name,
00318                                           SOCKET_FILE,
00319                                           mode,
00320                                           NULL,
00321                                           &attr_new,
00322                                           data->pcontext, &cache_status)) == NULL)
00323         {
00324           res_CREATE4.status = nfs4_Errno(cache_status);
00325           return res_CREATE4.status;
00326         }
00327 
00328       /* If entry exists pentry_new is not null but cache_status was set */
00329       if(cache_status == CACHE_INODE_ENTRY_EXISTS)
00330         {
00331           res_CREATE4.status = NFS4ERR_EXIST;
00332           cache_inode_put(pentry_new);
00333           return res_CREATE4.status;
00334         }
00335       break;
00336 
00337     case NF4FIFO:
00338 
00339       /* Create a new socket file */
00340       if((pentry_new = cache_inode_create(pentry_parent,
00341                                           &name,
00342                                           FIFO_FILE,
00343                                           mode,
00344                                           NULL,
00345                                           &attr_new,
00346                                           data->pcontext, &cache_status)) == NULL)
00347         {
00348           res_CREATE4.status = nfs4_Errno(cache_status);
00349           return res_CREATE4.status;
00350         }
00351 
00352       /* If entry exists pentry_new is not null but cache_status was set */
00353       if(cache_status == CACHE_INODE_ENTRY_EXISTS)
00354         {
00355           res_CREATE4.status = NFS4ERR_EXIST;
00356           cache_inode_put(pentry_new);
00357           return res_CREATE4.status;
00358         }
00359       break;
00360 
00361     case NF4CHR:
00362 
00363       create_arg.dev_spec.major = arg_CREATE4.objtype.createtype4_u.devdata.specdata1;
00364       create_arg.dev_spec.minor = arg_CREATE4.objtype.createtype4_u.devdata.specdata2;
00365 
00366       /* Create a new socket file */
00367       if((pentry_new = cache_inode_create(pentry_parent,
00368                                           &name,
00369                                           CHARACTER_FILE,
00370                                           mode,
00371                                           &create_arg,
00372                                           &attr_new,
00373                                           data->pcontext, &cache_status)) == NULL)
00374         {
00375           res_CREATE4.status = nfs4_Errno(cache_status);
00376           return res_CREATE4.status;
00377         }
00378 
00379       /* If entry exists pentry_new is not null but cache_status was set */
00380       if(cache_status == CACHE_INODE_ENTRY_EXISTS)
00381         {
00382           res_CREATE4.status = NFS4ERR_EXIST;
00383           cache_inode_put(pentry_new);
00384           return res_CREATE4.status;
00385         }
00386       break;
00387 
00388     case NF4BLK:
00389 
00390       create_arg.dev_spec.major = arg_CREATE4.objtype.createtype4_u.devdata.specdata1;
00391       create_arg.dev_spec.minor = arg_CREATE4.objtype.createtype4_u.devdata.specdata2;
00392 
00393       /* Create a new socket file */
00394       if((pentry_new = cache_inode_create(pentry_parent,
00395                                           &name,
00396                                           BLOCK_FILE,
00397                                           mode,
00398                                           &create_arg,
00399                                           &attr_new,
00400                                           data->pcontext, &cache_status)) == NULL)
00401         {
00402           res_CREATE4.status = nfs4_Errno(cache_status);
00403           return res_CREATE4.status;
00404         }
00405 
00406       /* If entry exists pentry_new is not null but cache_status was set */
00407       if(cache_status == CACHE_INODE_ENTRY_EXISTS)
00408         {
00409           res_CREATE4.status = NFS4ERR_EXIST;
00410           cache_inode_put(pentry_new);
00411           return res_CREATE4.status;
00412         }
00413       break;
00414 
00415     default:
00416       /* Should never happen, but return NFS4ERR_BADTYPE in this case */
00417       res_CREATE4.status = NFS4ERR_BADTYPE;
00418       return res_CREATE4.status;
00419       break;
00420     }                           /* switch( arg_CREATE4.objtype.type ) */
00421 
00422   /* Now produce the filehandle to this file */
00423   pnewfsal_handle = &pentry_new->handle;
00424 
00425   /* Allocation of a new file handle */
00426   if(nfs4_AllocateFH(&newfh4) != NFS4_OK)
00427     {
00428       res_CREATE4.status = NFS4ERR_SERVERFAULT;
00429       cache_inode_put(pentry_new);
00430       return res_CREATE4.status;
00431     }
00432 
00433   /* Building the new file handle */
00434   if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
00435     {
00436       res_CREATE4.status = NFS4ERR_SERVERFAULT;
00437       cache_inode_put(pentry_new);
00438       return res_CREATE4.status;
00439     }
00440 
00441   /* This new fh replaces the current FH */
00442   data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
00443   memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len);
00444 
00445   /* No do not need newfh any more */
00446   gsh_free(newfh4.nfs_fh4_val);
00447 
00448   /* Set the mode if requested */
00449   /* Use the same fattr mask for reply, if one attribute was not settable, NFS4ERR_ATTRNOTSUPP was replyied */
00450   res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len =
00451       arg_CREATE4.createattrs.attrmask.bitmap4_len;
00452 
00453   if(arg_CREATE4.createattrs.attrmask.bitmap4_len != 0)
00454     {
00455       if((cache_status = cache_inode_setattr(pentry_new,
00456                                              &sattr,
00457                                              data->pcontext,
00458                                              &cache_status)) != CACHE_INODE_SUCCESS)
00459 
00460         {
00461           res_CREATE4.status = nfs4_Errno(cache_status);
00462           cache_inode_put(pentry_new);
00463           return res_CREATE4.status;
00464         }
00465 
00466       /* Allocate a new bitmap */
00467       res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val =
00468         gsh_calloc(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len,
00469                    sizeof(uint32_t));
00470 
00471       if(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val == NULL)
00472         {
00473           res_CREATE4.status = NFS4ERR_SERVERFAULT;
00474           cache_inode_put(pentry_new);
00475           return res_CREATE4.status;
00476         }
00477       memcpy(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val,
00478              arg_CREATE4.createattrs.attrmask.bitmap4_val,
00479              res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len
00480              * sizeof(uint32_t));
00481     }
00482 
00483   /* Get the change info on parent directory after the operation was successfull */
00484   if((cache_status = cache_inode_getattr(pentry_parent,
00485                                          &attr_parent,
00486                                          data->pcontext,
00487                                          &cache_status)) != CACHE_INODE_SUCCESS)
00488     {
00489       res_CREATE4.status = nfs4_Errno(cache_status);
00490       cache_inode_put(pentry_new);
00491       return res_CREATE4.status;
00492     }
00493   memset(&(res_CREATE4.CREATE4res_u.resok4.cinfo.after), 0, sizeof(changeid4));
00494   res_CREATE4.CREATE4res_u.resok4.cinfo.after
00495        = cache_inode_get_changeid4(pentry_parent);
00496 
00497   /* Operation is supposed to be atomic .... */
00498   res_CREATE4.CREATE4res_u.resok4.cinfo.atomic = FALSE;
00499 
00500   LogFullDebug(COMPONENT_NFS_V4,
00501                "CREATE CINFO before = %"PRIu64"  after = %"PRIu64"  atomic = %d",
00502                res_CREATE4.CREATE4res_u.resok4.cinfo.before,
00503                res_CREATE4.CREATE4res_u.resok4.cinfo.after,
00504                res_CREATE4.CREATE4res_u.resok4.cinfo.atomic);
00505 
00506   /* @todo : BUGAZOMEU: fair ele free dans cette fonction */
00507 
00508   /* Keep the vnode entry for the file in the compound data */
00509 
00510   if (data->current_entry) {
00511       cache_inode_put(data->current_entry);
00512   }
00513   data->current_entry = pentry_new;
00514   data->current_filetype = pentry_new->type;
00515 
00516   /* If you reach this point, then no error occured */
00517   res_CREATE4.status = NFS4_OK;
00518 
00519   return res_CREATE4.status;
00520 }                               /* nfs4_op_create */
00521 
00532 void nfs4_op_create_Free(CREATE4res * resp)
00533 {
00534   if(resp->status == NFS4_OK)
00535     gsh_free(resp->CREATE4res_u.resok4.attrset.bitmap4_val);
00536 
00537   return;
00538 }                               /* nfs4_op_create_Free */