nfs-ganesha 1.4
|
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 */