nfs-ganesha 1.4

nfs4_op_setattr.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 
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 
00041 #ifdef _SOLARIS
00042 #include "solaris_port.h"
00043 #endif
00044 
00045 #include <stdio.h>
00046 #include <string.h>
00047 #include <pthread.h>
00048 #include <fcntl.h>
00049 #include <sys/file.h>           /* for having FNDELAY */
00050 #include "HashData.h"
00051 #include "HashTable.h"
00052 #include "log.h"
00053 #include "ganesha_rpc.h"
00054 #include "nfs23.h"
00055 #include "nfs4.h"
00056 #include "mount.h"
00057 #include "nfs_core.h"
00058 #include "cache_inode.h"
00059 #include "nfs_exports.h"
00060 #include "nfs_creds.h"
00061 #include "nfs_proto_functions.h"
00062 #include "nfs_proto_tools.h"
00063 #include "nfs_tools.h"
00064 #include "nfs_file_handle.h"
00065 #include "sal_functions.h"
00066 
00080 #define arg_SETATTR4 op->nfs_argop4_u.opsetattr
00081 #define res_SETATTR4 resp->nfs_resop4_u.opsetattr
00082 
00083 int nfs4_op_setattr(struct nfs_argop4 *op,
00084                     compound_data_t * data, struct nfs_resop4 *resp)
00085 {
00086   struct timeval         t;
00087   fsal_attrib_list_t     sattr;
00088   fsal_attrib_list_t     parent_attr;
00089   cache_inode_status_t   cache_status = CACHE_INODE_SUCCESS;
00090   const char           * tag = "SETATTR";
00091   state_t              * pstate_found = NULL;
00092   state_t              * pstate_open  = NULL;
00093   cache_entry_t        * pentry       = NULL;
00094 
00095   memset(&sattr, 0, sizeof(sattr));
00096   memset(&parent_attr, 0, sizeof(parent_attr));
00097   resp->resop = NFS4_OP_SETATTR;
00098   res_SETATTR4.status = NFS4_OK;
00099 
00100   /* Do basic checks on a filehandle */
00101   res_SETATTR4.status = nfs4_sanity_check_FH(data,0LL);
00102   if(res_SETATTR4.status != NFS4_OK)
00103     return res_SETATTR4.status;
00104 
00105   /* Pseudo Fs is explictely a Read-Only File system */
00106   if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
00107     {
00108       res_SETATTR4.status = NFS4ERR_ROFS;
00109       return res_SETATTR4.status;
00110     }
00111 
00112   /* Get only attributes that are allowed to be read */
00113   if(!nfs4_Fattr_Check_Access(&arg_SETATTR4.obj_attributes, FATTR4_ATTR_WRITE))
00114     {
00115       res_SETATTR4.status = NFS4ERR_INVAL;
00116       return res_SETATTR4.status;
00117     }
00118 
00119   /* Ask only for supported attributes */
00120   if(!nfs4_Fattr_Supported(&arg_SETATTR4.obj_attributes))
00121     {
00122       res_SETATTR4.status = NFS4ERR_ATTRNOTSUPP;
00123       return res_SETATTR4.status;
00124     }
00125 
00126   /* Convert the fattr4 in the request to a nfs3_sattr structure */
00127   res_SETATTR4.status = nfs4_Fattr_To_FSAL_attr(&sattr, &(arg_SETATTR4.obj_attributes));
00128   if(res_SETATTR4.status != NFS4_OK)
00129     return res_SETATTR4.status;
00130 
00131   /*
00132    * trunc may change Xtime so we have to start with trunc and finish
00133    * by the mtime and atime 
00134    */
00135   if(FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_SIZE))
00136     {
00137       /* Setting the size of a directory is prohibited */
00138       if(data->current_filetype == DIRECTORY)
00139         {
00140           res_SETATTR4.status = NFS4ERR_ISDIR;
00141           return res_SETATTR4.status;
00142         }
00143       /* Object should be a file */
00144       if(data->current_entry->type != REGULAR_FILE)
00145         {
00146           res_SETATTR4.status = NFS4ERR_INVAL;
00147           return res_SETATTR4.status;
00148         }
00149 
00150       /* vnode to manage is the current one */
00151       pentry = data->current_entry;
00152 
00153       /* Check stateid correctness and get pointer to state */
00154       res_SETATTR4.status = nfs4_Check_Stateid(&arg_SETATTR4.stateid,
00155                                                data->current_entry,
00156                                                &pstate_found,
00157                                                data,
00158                                                STATEID_SPECIAL_ANY,
00159                                                tag);
00160       if(res_SETATTR4.status != NFS4_OK)
00161         return res_SETATTR4.status;
00162 
00163       /* NB: After this points, if pstate_found == NULL, then the stateid is all-0 or all-1 */
00164       if(pstate_found != NULL)
00165         {
00166           switch(pstate_found->state_type)
00167             {
00168               case STATE_TYPE_SHARE:
00169                 pstate_open = pstate_found;
00170                 break;
00171 
00172               case STATE_TYPE_LOCK:
00173                 pstate_open = pstate_found->state_data.lock.popenstate;
00174                 break;
00175 
00176               case STATE_TYPE_DELEG:
00177                 pstate_open = NULL;
00178                 break;
00179 
00180               default:
00181                 res_SETATTR4.status = NFS4ERR_BAD_STATEID;
00182                 return res_SETATTR4.status;
00183             }
00184 
00185           /* This is a size operation, this means that the file MUST have been opened for writing */
00186           if(pstate_open != NULL &&
00187              (pstate_open->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE) == 0)
00188             {
00189               /* Bad open mode, return NFS4ERR_OPENMODE */
00190               res_SETATTR4.status = NFS4ERR_OPENMODE;
00191               return res_SETATTR4.status;
00192             }
00193         }
00194       else
00195         {
00196           /* Special stateid, no open state, check to see if any share conflicts */
00197           pstate_open = NULL;
00198 
00199           /*
00200            * Special stateid, no open state, check to see if any share conflicts
00201            * The stateid is all-0 or all-1
00202            */
00203           res_SETATTR4.status = nfs4_check_special_stateid(pentry,
00204                                                            "SETATTR(size)",
00205                                                            FATTR4_ATTR_WRITE);
00206           if(res_SETATTR4.status != NFS4_OK)
00207             return res_SETATTR4.status;
00208         }
00209 
00210       if((cache_status = cache_inode_truncate(data->current_entry,
00211                                               sattr.filesize,
00212                                               &parent_attr,
00213                                               data->pcontext,
00214                                               &cache_status)) != CACHE_INODE_SUCCESS)
00215         {
00216           res_SETATTR4.status = nfs4_Errno(cache_status);
00217           return res_SETATTR4.status;
00218         }
00219       /* we just did the truncate, turn off these attrs */
00220       sattr.asked_attributes &= ~FSAL_ATTR_SPACEUSED;
00221       sattr.asked_attributes &= ~FSAL_ATTR_SIZE;
00222     }
00223 
00224   /* Now, we set the mode */
00225   if(FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_MODE) ||
00226      FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_OWNER) ||
00227      FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_GROUP) ||
00228      FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_MTIME) ||
00229 #ifdef _USE_NFS4_ACL
00230      FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_ATIME) ||
00231      FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_ACL))
00232 #else
00233      FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_ATIME))
00234 #endif
00235     {
00236       /* Check for root access when using chmod */
00237       if(FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_MODE))
00238         {
00239           if(((sattr.mode & FSAL_MODE_SUID) &&
00240               ((data->pexport->options & EXPORT_OPTION_NOSUID) == EXPORT_OPTION_NOSUID))
00241              || ((sattr.mode & FSAL_MODE_SGID)
00242                  && ((data->pexport->options & EXPORT_OPTION_NOSGID) ==
00243                      EXPORT_OPTION_NOSGID)))
00244             {
00245               LogInfo(COMPONENT_NFS_V4,
00246                       "Setattr denied because setuid or setgid bit is disabled in configuration file. setuid=%d, setgid=%d",
00247                       sattr.mode & FSAL_MODE_SUID ? 1 : 0,
00248                       sattr.mode & FSAL_MODE_SGID ? 1 : 0);
00249               res_SETATTR4.status = NFS4ERR_PERM;
00250               return res_SETATTR4.status;
00251             }
00252         }
00253 
00254 #define S_NSECS 1000000000UL  /* nsecs in 1s */
00255       /* Set the atime and mtime (ctime is not setable) */
00256 
00257       /* get the current time */
00258        gettimeofday(&t, NULL);
00259 
00261       if(FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_ATIME) == SET_TO_SERVER_TIME4)
00262         {
00263           sattr.atime.seconds = t.tv_sec;
00264           sattr.atime.nseconds = t.tv_usec;
00265         }
00266       else
00267         {
00268           /* a carry into seconds considered invalid */
00269           if (sattr.atime.nseconds >= S_NSECS)
00270           {
00271             res_SETATTR4.status = NFS4ERR_INVAL;
00272             return res_SETATTR4.status;
00273           }
00274         }
00275       /* Should we use the time from the client handside or from the server handside ? */
00277       if(FSAL_TEST_MASK(sattr.asked_attributes, FSAL_ATTR_MTIME) == SET_TO_SERVER_TIME4)
00278         {
00279           sattr.mtime.seconds = t.tv_sec;
00280           sattr.mtime.nseconds = t.tv_usec;
00281         }
00282       else
00283         {
00284           if (sattr.mtime.nseconds >= S_NSECS)
00285           {
00286             res_SETATTR4.status = NFS4ERR_INVAL;
00287             return res_SETATTR4.status;
00288           }
00289         }
00290 
00291       if(cache_inode_setattr(data->current_entry,
00292                              &sattr,
00293                              data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
00294         {
00295           res_SETATTR4.status = nfs4_Errno(cache_status);
00296           return res_SETATTR4.status;
00297         }
00298     }
00299 
00300   /* Set the replyed structure */
00301   res_SETATTR4.attrsset.bitmap4_len = arg_SETATTR4.obj_attributes.attrmask.bitmap4_len;
00302 
00303   if((res_SETATTR4.attrsset.bitmap4_val =
00304       gsh_calloc(res_SETATTR4.attrsset.bitmap4_len, sizeof(uint32_t))) == NULL)
00305     {
00306       res_SETATTR4.status = NFS4ERR_SERVERFAULT;
00307       return res_SETATTR4.status;
00308     }
00309 
00310   memcpy(res_SETATTR4.attrsset.bitmap4_val,
00311          arg_SETATTR4.obj_attributes.attrmask.bitmap4_val,
00312          res_SETATTR4.attrsset.bitmap4_len * sizeof(u_int));
00313 
00314   /* Exit with no error */
00315   res_SETATTR4.status = NFS4_OK;
00316 
00317   return res_SETATTR4.status;
00318 }                               /* nfs4_op_setattr */
00319 
00330 void nfs4_op_setattr_Free(SETATTR4res * resp)
00331 {
00332   if(resp->status == NFS4_OK)
00333     gsh_free(resp->attrsset.bitmap4_val);
00334   return;
00335 }                               /* nfs4_op_setattr_Free */