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 00032 #ifdef HAVE_CONFIG_H 00033 #include "config.h" 00034 #endif 00035 00036 #include "fsal.h" 00037 #include "fsal_internal.h" 00038 #include "FSAL/access_check.h" 00039 #include "fsal_convert.h" 00040 #include <sys/types.h> 00041 #include <unistd.h> 00042 #include <utime.h> 00043 #include <inttypes.h> 00044 00045 #define MAX_2( x, y ) ( (x) > (y) ? (x) : (y) ) 00046 00047 static fsal_status_t 00048 bulkstat_by_inode(fsal_op_context_t * context, ino_t inum, fsal_attrib_list_t * p_fsalattr_out) 00049 { 00050 xfsfsal_op_context_t * p_context = (xfsfsal_op_context_t *)context; 00051 xfs_bstat_t stat; 00052 struct stat sb; 00053 int fd = 0; 00054 int errsv, rc; 00055 00056 if((fd = open(p_context->export_context->mount_point, O_DIRECTORY)) == -1) 00057 ReturnCode(posix2fsal_error(errno), errno); 00058 00059 rc = fsal_internal_get_bulkstat_by_inode(fd, &inum, &stat); 00060 errsv = errno; 00061 close(fd); 00062 00063 if(rc < 0) 00064 ReturnCode(posix2fsal_error(errsv), errsv); 00065 00066 memset(&sb, 0, sizeof(sb)); 00067 sb.st_mode = stat.bs_mode; 00068 sb.st_size = stat.bs_size; 00069 sb.st_dev = context->export_context->dev_id; 00070 sb.st_ino = stat.bs_ino; 00071 sb.st_nlink = stat.bs_nlink; 00072 sb.st_uid = stat.bs_uid; 00073 sb.st_gid = stat.bs_gid; 00074 sb.st_atim.tv_sec = stat.bs_atime.tv_sec; 00075 sb.st_atim.tv_nsec = stat.bs_atime.tv_nsec; 00076 sb.st_ctim.tv_sec = stat.bs_ctime.tv_sec; 00077 sb.st_ctim.tv_nsec = stat.bs_ctime.tv_nsec; 00078 sb.st_mtim.tv_sec = stat.bs_mtime.tv_sec; 00079 sb.st_mtim.tv_nsec = stat.bs_mtime.tv_nsec; 00080 sb.st_blocks = stat.bs_blocks; 00081 sb.st_blksize = stat.bs_blksize; 00082 sb.st_rdev = stat.bs_rdev; 00083 00084 return posix2fsal_attributes(&sb, p_fsalattr_out); 00085 } 00086 00106 fsal_status_t XFSFSAL_getattrs(fsal_handle_t * p_filehandle, /* IN */ 00107 fsal_op_context_t * p_context, /* IN */ 00108 fsal_attrib_list_t * p_object_attributes /* IN/OUT */ 00109 ) 00110 { 00111 int rc, errsv; 00112 fsal_status_t st; 00113 int fd; 00114 struct stat buffstat; 00115 xfsfsal_handle_t *xh = (xfsfsal_handle_t *)p_filehandle; 00116 00117 /* sanity checks. 00118 * note : object_attributes is mandatory in FSAL_getattrs. 00119 */ 00120 if(!p_filehandle || !p_context || !p_object_attributes) 00121 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs); 00122 00123 switch(xh->data.type) 00124 { 00125 case DT_LNK: 00126 case DT_BLK: 00127 case DT_SOCK: 00128 case DT_CHR: 00129 case DT_FIFO: 00130 TakeTokenFSCall(); 00131 st = bulkstat_by_inode(p_context, xh->data.inode, p_object_attributes); 00132 ReleaseTokenFSCall(); 00133 break; 00134 00135 case DT_REG: 00136 case DT_DIR: 00137 TakeTokenFSCall(); 00138 st = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY); 00139 ReleaseTokenFSCall(); 00140 00141 if(FSAL_IS_ERROR(st)) 00142 ReturnStatus(st, INDEX_FSAL_getattrs); 00143 00144 /* get file metadata */ 00145 TakeTokenFSCall(); 00146 rc = fstat(fd, &buffstat); 00147 errsv = errno; 00148 ReleaseTokenFSCall(); 00149 00150 close(fd); 00151 00152 if(rc != 0) 00153 { 00154 if(errsv == ENOENT) 00155 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_getattrs); 00156 else 00157 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_getattrs); 00158 } 00159 00160 /* convert attributes */ 00161 st = posix2fsal_attributes(&buffstat, p_object_attributes); 00162 break; 00163 00164 default: 00165 LogEvent(COMPONENT_FSAL, 00166 "Corrupted filehandle - unexpected file type %d", 00167 xh->data.type); 00168 Return(ERR_FSAL_BADHANDLE, EINVAL, INDEX_FSAL_getattrs); 00169 } 00170 if(FSAL_IS_ERROR(st)) 00171 { 00172 FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); 00173 FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00174 ReturnStatus(st, INDEX_FSAL_getattrs); 00175 } 00176 00177 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs); 00178 00179 } 00180 00205 fsal_status_t XFSFSAL_setattrs(fsal_handle_t * p_filehandle, /* IN */ 00206 fsal_op_context_t * p_context, /* IN */ 00207 fsal_attrib_list_t * p_attrib_set, /* IN */ 00208 fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ 00209 ) 00210 { 00211 00212 int rc, errsv; 00213 unsigned int i; 00214 fsal_status_t status; 00215 fsal_attrib_list_t attrs; 00216 00217 int fd; 00218 struct stat buffstat; 00219 uid_t userid = ((xfsfsal_op_context_t *)p_context)->credential.user; 00220 gid_t groupid = ((xfsfsal_op_context_t *)p_context)->credential.group; 00221 00222 /* sanity checks. 00223 * note : object_attributes is optional. 00224 */ 00225 if(!p_filehandle || !p_context || !p_attrib_set) 00226 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); 00227 00228 /* local copy of attributes */ 00229 attrs = *p_attrib_set; 00230 00231 /* It does not make sense to setattr on a symlink */ 00232 if(((xfsfsal_handle_t *)p_filehandle)->data.type == DT_LNK) 00233 return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set, 00234 p_object_attributes); 00235 00236 /* First, check that FSAL attributes changes are allowed. */ 00237 00238 /* Is it allowed to change times ? */ 00239 00240 if(!global_fs_info.cansettime) 00241 { 00242 00243 if(attrs.asked_attributes 00244 & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME)) 00245 { 00246 /* handled as an unsettable attribute. */ 00247 Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs); 00248 } 00249 } 00250 00251 /* apply umask, if mode attribute is to be changed */ 00252 if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) 00253 { 00254 attrs.mode &= (~global_fs_info.umask); 00255 } 00256 00257 TakeTokenFSCall(); 00258 status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDWR); 00259 ReleaseTokenFSCall(); 00260 if(FSAL_IS_ERROR(status)) 00261 ReturnStatus(status, INDEX_FSAL_setattrs); 00262 00263 /* get current attributes */ 00264 TakeTokenFSCall(); 00265 rc = fstat(fd, &buffstat); 00266 errsv = errno; 00267 ReleaseTokenFSCall(); 00268 00269 if(rc != 0) 00270 { 00271 close(fd); 00272 00273 if(errsv == ENOENT) 00274 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_setattrs); 00275 else 00276 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs); 00277 } 00278 00279 /*********** 00280 * CHMOD * 00281 ***********/ 00282 if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) 00283 { 00284 00285 /* The POSIX chmod call don't affect the symlink object, but 00286 * the entry it points to. So we must ignore it. 00287 */ 00288 if(!S_ISLNK(buffstat.st_mode)) 00289 { 00290 00291 /* For modifying mode, user must be root or the owner */ 00292 if((userid != 0) 00293 && (userid != buffstat.st_uid)) 00294 { 00295 00296 LogFullDebug(COMPONENT_FSAL, 00297 "Permission denied for CHMOD opeartion: current owner=%d, credential=%d", 00298 buffstat.st_uid, userid); 00299 00300 close(fd); 00301 Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); 00302 } 00303 00304 TakeTokenFSCall(); 00305 rc = fchmod(fd, fsal2unix_mode(attrs.mode)); 00306 errsv = errno; 00307 00308 ReleaseTokenFSCall(); 00309 00310 if(rc) 00311 { 00312 close(fd); 00313 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs); 00314 } 00315 00316 } 00317 00318 } 00319 00320 /*********** 00321 * CHOWN * 00322 ***********/ 00323 /* Only root can change uid and A normal user must be in the group he wants to set */ 00324 if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER)) 00325 { 00326 00327 /* For modifying owner, user must be root or current owner==wanted==client */ 00328 if((userid != 0) && 00329 ((userid != buffstat.st_uid) || 00330 (userid != attrs.owner))) 00331 { 00332 00333 LogFullDebug(COMPONENT_FSAL, 00334 "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d", 00335 buffstat.st_uid, userid, attrs.owner); 00336 00337 close(fd); 00338 Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); 00339 } 00340 } 00341 00342 if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP)) 00343 { 00344 00345 /* For modifying group, user must be root or current owner */ 00346 if((userid != 0) 00347 && (userid != buffstat.st_uid)) 00348 { 00349 close(fd); 00350 Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); 00351 } 00352 00353 int in_grp = 0; 00354 /* set in_grp */ 00355 if(groupid == attrs.group) 00356 in_grp = 1; 00357 else 00358 for(i = 0; i < ((xfsfsal_op_context_t *)p_context)->credential.nbgroups; i++) 00359 { 00360 if((in_grp = (attrs.group == ((xfsfsal_op_context_t *)p_context)->credential.alt_groups[i]))) 00361 break; 00362 } 00363 00364 /* it must also be in target group */ 00365 if(userid != 0 && !in_grp) 00366 { 00367 00368 LogFullDebug(COMPONENT_FSAL, 00369 "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d", 00370 buffstat.st_gid, groupid, attrs.group); 00371 00372 close(fd); 00373 Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); 00374 } 00375 } 00376 00377 if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP)) 00378 { 00379 00380 LogFullDebug(COMPONENT_FSAL, "Performing chown(inode=%"PRIu64", %d,%d)", 00381 buffstat.st_ino, FSAL_TEST_MASK(attrs.asked_attributes, 00382 FSAL_ATTR_OWNER) ? (int)attrs.owner 00383 : -1, FSAL_TEST_MASK(attrs.asked_attributes, 00384 FSAL_ATTR_GROUP) ? (int)attrs.group : -1); 00385 00386 00387 TakeTokenFSCall(); 00388 rc = fchown(fd, 00389 FSAL_TEST_MASK(attrs.asked_attributes, 00390 FSAL_ATTR_OWNER) ? (int)attrs.owner : -1, 00391 FSAL_TEST_MASK(attrs.asked_attributes, 00392 FSAL_ATTR_GROUP) ? (int)attrs.group : -1); 00393 ReleaseTokenFSCall(); 00394 if(rc) 00395 { 00396 close(fd); 00397 Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); 00398 } 00399 } 00400 00401 /*********** 00402 * UTIME * 00403 ***********/ 00404 00405 /* user must be the owner or have read access to modify 'atime' */ 00406 if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) 00407 && (userid != 0) 00408 && (userid != buffstat.st_uid) 00409 && ((status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL)).major 00410 != ERR_FSAL_NO_ERROR)) 00411 { 00412 close(fd); 00413 ReturnStatus(status, INDEX_FSAL_setattrs); 00414 } 00415 /* user must be the owner or have write access to modify 'mtime' */ 00416 if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) 00417 && (userid != 0) 00418 && (userid != buffstat.st_uid) 00419 && ((status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL)).major 00420 != ERR_FSAL_NO_ERROR)) 00421 { 00422 close(fd); 00423 ReturnStatus(status, INDEX_FSAL_setattrs); 00424 } 00425 00426 if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) 00427 { 00428 00429 struct timeval timebuf[2]; 00430 00431 /* Atime */ 00432 timebuf[0].tv_sec = 00433 (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs. 00434 atime.seconds : buffstat.st_atime); 00435 timebuf[0].tv_usec = 0; 00436 00437 /* Mtime */ 00438 timebuf[1].tv_sec = 00439 (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs. 00440 mtime.seconds : buffstat.st_mtime); 00441 timebuf[1].tv_usec = 0; 00442 00443 TakeTokenFSCall(); 00444 rc = futimes(fd, timebuf); 00445 errsv = errno; 00446 ReleaseTokenFSCall(); 00447 if(rc) 00448 { 00449 close(fd); 00450 Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); 00451 } 00452 } 00453 00454 /* Optionaly fills output attributes. */ 00455 00456 if(p_object_attributes) 00457 { 00458 status = XFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); 00459 00460 /* on error, we set a special bit in the mask. */ 00461 if(FSAL_IS_ERROR(status)) 00462 { 00463 close(fd); 00464 FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); 00465 FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00466 } 00467 00468 } 00469 00470 close(fd); 00471 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); 00472 00473 } 00474 00494 fsal_status_t XFSFSAL_getextattrs(fsal_handle_t * p_filehandle, /* IN */ 00495 fsal_op_context_t * p_context, /* IN */ 00496 fsal_extattrib_list_t * p_object_attributes /* OUT */ 00497 ) 00498 { 00499 fsal_status_t st ; 00500 xfs_bstat_t bstat; 00501 xfs_ino_t xfs_ino; 00502 int fd = 0 ; 00503 00504 /* sanity checks. 00505 * note : object_attributes is mandatory in FSAL_getattrs. 00506 */ 00507 if(!p_filehandle || !p_context || !p_object_attributes) 00508 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs); 00509 00510 TakeTokenFSCall(); 00511 st = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY); 00512 ReleaseTokenFSCall(); 00513 00514 if(FSAL_IS_ERROR(st)) 00515 ReturnStatus(st, INDEX_FSAL_getextattrs); 00516 00517 if( p_object_attributes->asked_attributes & FSAL_ATTR_GENERATION ) 00518 { 00519 /* get file metadata */ 00520 xfs_ino = ((xfsfsal_handle_t *)p_filehandle)->data.inode ; 00521 TakeTokenFSCall(); 00522 if(fsal_internal_get_bulkstat_by_inode(fd, &xfs_ino, &bstat) < 0) 00523 { 00524 close(fd); 00525 ReleaseTokenFSCall(); 00526 ReturnCode(posix2fsal_error(errno), errno); 00527 } 00528 ReleaseTokenFSCall(); 00529 00530 p_object_attributes->generation = bstat.bs_gen ; 00531 } 00532 00533 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getextattrs); 00534 } /* XFSFSAL_getextattrs */