nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=4:tabstop=4: 00003 */ 00004 00014 #ifdef HAVE_CONFIG_H 00015 #include "config.h" 00016 #endif 00017 00018 #include "fsal.h" 00019 #include "fsal_internal.h" 00020 #include "FSAL/access_check.h" 00021 #include "fsal_convert.h" 00022 #include <unistd.h> 00023 #include <fcntl.h> 00024 00025 /* Dirty work-around to be used for managing NFS related link semantics */ 00026 static int linkat2(int srcfd, int dirdestfd, char *destname) 00027 { 00028 char procpath[MAXPATHLEN]; 00029 char pathproccontent[MAXPATHLEN]; 00030 00031 memset(procpath, 0, MAXPATHLEN); 00032 memset(pathproccontent, 0, MAXPATHLEN); 00033 00034 snprintf(procpath, MAXPATHLEN, "/proc/%u/fd/%u", getpid(), srcfd); 00035 00036 if(readlink(procpath, pathproccontent, MAXPATHLEN) == -1) 00037 return -1; 00038 00039 return linkat(0, pathproccontent, dirdestfd, destname, 0); 00040 } /* linkat2 */ 00041 00070 fsal_status_t XFSFSAL_create(fsal_handle_t * p_parent_directory_handle, /* IN */ 00071 fsal_name_t * p_filename, /* IN */ 00072 fsal_op_context_t * p_context, /* IN */ 00073 fsal_accessmode_t accessmode, /* IN */ 00074 fsal_handle_t * p_object_handle, /* OUT */ 00075 fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ 00076 ) 00077 { 00078 00079 int rc, errsv; 00080 int setgid_bit = 0; 00081 fsal_status_t status; 00082 00083 int fd, newfd; 00084 struct stat buffstat; 00085 mode_t unix_mode; 00086 00087 /* sanity checks. 00088 * note : object_attributes is optional. 00089 */ 00090 if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename) 00091 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); 00092 00093 /* convert fsal mode to unix mode. */ 00094 unix_mode = fsal2unix_mode(accessmode); 00095 00096 /* Apply umask */ 00097 unix_mode = unix_mode & ~global_fs_info.umask; 00098 00099 LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); 00100 00101 TakeTokenFSCall(); 00102 status = 00103 fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY); 00104 ReleaseTokenFSCall(); 00105 if(FSAL_IS_ERROR(status)) 00106 ReturnStatus(status, INDEX_FSAL_create); 00107 00108 /* retrieve directory metadata */ 00109 TakeTokenFSCall(); 00110 rc = fstat(fd, &buffstat); 00111 errsv = errno; 00112 ReleaseTokenFSCall(); 00113 if(rc) 00114 { 00115 close(fd); 00116 00117 if(errsv == ENOENT) 00118 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_create); 00119 else 00120 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); 00121 } 00122 00123 /* Check the user can write in the directory, and check the setgid bit on the directory */ 00124 00125 if(buffstat.st_mode & S_ISGID) 00126 setgid_bit = 1; 00127 00128 status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); 00129 if(FSAL_IS_ERROR(status)) 00130 ReturnStatus(status, INDEX_FSAL_create); 00131 00132 /* call to filesystem */ 00133 00134 TakeTokenFSCall(); 00135 /* create the file. 00136 * O_EXCL=> error if the file already exists */ 00137 newfd = openat(fd, p_filename->name, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode); 00138 errsv = errno; 00139 00140 if(newfd == -1) 00141 { 00142 close(fd); 00143 ReleaseTokenFSCall(); 00144 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); 00145 } 00146 00147 /* get the new file handle */ 00148 status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); 00149 00150 ReleaseTokenFSCall(); 00151 00152 if(FSAL_IS_ERROR(status)) 00153 { 00154 close(fd); 00155 close(newfd); 00156 ReturnStatus(status, INDEX_FSAL_create); 00157 } 00158 /* the file has been created */ 00159 /* chown the file to the current user */ 00160 00161 if(((xfsfsal_op_context_t *)p_context)->credential.user != geteuid()) 00162 { 00163 TakeTokenFSCall(); 00164 /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ 00165 rc = fchown(newfd, ((xfsfsal_op_context_t *)p_context)->credential.user, 00166 setgid_bit ? -1 : (int)((xfsfsal_op_context_t *)p_context)->credential.group); 00167 errsv = errno; 00168 ReleaseTokenFSCall(); 00169 if(rc) 00170 { 00171 close(fd); 00172 close(newfd); 00173 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); 00174 } 00175 } 00176 00177 close(fd); 00178 close(newfd); 00179 00180 /* retrieve file attributes */ 00181 if(p_object_attributes) 00182 { 00183 status = XFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes); 00184 00185 /* on error, we set a special bit in the mask. */ 00186 if(FSAL_IS_ERROR(status)) 00187 { 00188 FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); 00189 FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00190 } 00191 00192 } 00193 00194 /* OK */ 00195 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); 00196 00197 } 00198 00228 fsal_status_t XFSFSAL_mkdir(fsal_handle_t * p_parent_directory_handle, /* IN */ 00229 fsal_name_t * p_dirname, /* IN */ 00230 fsal_op_context_t * p_context, /* IN */ 00231 fsal_accessmode_t accessmode, /* IN */ 00232 fsal_handle_t * p_object_handle, /* OUT */ 00233 fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ 00234 ) 00235 { 00236 00237 int rc, errsv; 00238 int setgid_bit = 0; 00239 struct stat buffstat; 00240 mode_t unix_mode; 00241 fsal_status_t status; 00242 int fd, newfd; 00243 00244 /* sanity checks. 00245 * note : object_attributes is optional. 00246 */ 00247 if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname) 00248 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); 00249 00250 /* convert FSAL mode to HPSS mode. */ 00251 unix_mode = fsal2unix_mode(accessmode); 00252 00253 /* Apply umask */ 00254 unix_mode = unix_mode & ~global_fs_info.umask; 00255 00256 TakeTokenFSCall(); 00257 status = 00258 fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY); 00259 ReleaseTokenFSCall(); 00260 00261 if(FSAL_IS_ERROR(status)) 00262 ReturnStatus(status, INDEX_FSAL_mkdir); 00263 00264 /* get directory metadata */ 00265 TakeTokenFSCall(); 00266 rc = fstat(fd, &buffstat); 00267 errsv = errno; 00268 ReleaseTokenFSCall(); 00269 if(rc) 00270 { 00271 close(fd); 00272 00273 if(errsv == ENOENT) 00274 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_create); 00275 else 00276 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); 00277 } 00278 00279 /* Check the user can write in the directory, and check the setgid bit on the directory */ 00280 00281 if(buffstat.st_mode & S_ISGID) 00282 setgid_bit = 1; 00283 00284 status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); 00285 if(FSAL_IS_ERROR(status)) 00286 ReturnStatus(status, INDEX_FSAL_mkdir); 00287 00288 /* build new entry path */ 00289 00290 /* creates the directory and get its handle */ 00291 00292 TakeTokenFSCall(); 00293 rc = mkdirat(fd, p_dirname->name, unix_mode); 00294 errsv = errno; 00295 if(rc) 00296 { 00297 close(fd); 00298 00299 ReleaseTokenFSCall(); 00300 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); 00301 } 00302 00303 /* get the new handle */ 00304 00305 if((newfd = openat(fd, p_dirname->name, O_RDONLY | O_DIRECTORY, 0600)) < 0) 00306 { 00307 errsv = errno; 00308 close(fd); 00309 ReleaseTokenFSCall(); 00310 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); 00311 } 00312 00313 status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); 00314 ReleaseTokenFSCall(); 00315 00316 if(FSAL_IS_ERROR(status)) 00317 { 00318 close(fd); 00319 close(newfd); 00320 ReturnStatus(status, INDEX_FSAL_mkdir); 00321 } 00322 00323 /* the directory has been created */ 00324 /* chown the file to the current user/group */ 00325 00326 if(((xfsfsal_op_context_t *)p_context)->credential.user != geteuid()) 00327 { 00328 TakeTokenFSCall(); 00329 /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ 00330 rc = fchown(newfd, ((xfsfsal_op_context_t *)p_context)->credential.user, 00331 setgid_bit ? -1 : (int)((xfsfsal_op_context_t *)p_context)->credential.group); 00332 errsv = errno; 00333 ReleaseTokenFSCall(); 00334 if(rc) 00335 { 00336 close(fd); 00337 close(newfd); 00338 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); 00339 } 00340 } 00341 00342 close(fd); 00343 close(newfd); 00344 00345 /* retrieve file attributes */ 00346 if(p_object_attributes) 00347 { 00348 status = XFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes); 00349 00350 /* on error, we set a special bit in the mask. */ 00351 if(FSAL_IS_ERROR(status)) 00352 { 00353 FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); 00354 FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00355 } 00356 00357 } 00358 00359 /* OK */ 00360 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir); 00361 00362 } 00363 00393 fsal_status_t XFSFSAL_link(fsal_handle_t * p_target_handle, /* IN */ 00394 fsal_handle_t * p_dir_handle, /* IN */ 00395 fsal_name_t * p_link_name, /* IN */ 00396 fsal_op_context_t * p_context, /* IN */ 00397 fsal_attrib_list_t * p_attributes /* [ IN/OUT ] */ 00398 ) 00399 { 00400 00401 int rc, errsv; 00402 fsal_status_t status; 00403 int srcfd, dstfd; 00404 struct stat buffstat_dir; 00405 00406 /* sanity checks. 00407 * note : attributes is optional. 00408 */ 00409 if(!p_target_handle || !p_dir_handle || !p_context || !p_link_name) 00410 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); 00411 00412 /* Tests if hardlinking is allowed by configuration. */ 00413 00414 if(!global_fs_info.link_support) 00415 Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_link); 00416 00417 /* LogFullDebug(COMPONENT_FSAL, "linking %#llx:%#x:%#x to %#llx:%#x:%#x/%s", */ 00418 00419 /* get the target handle access by fid */ 00420 TakeTokenFSCall(); 00421 status = fsal_internal_handle2fd(p_context, p_target_handle, &srcfd, O_DIRECTORY); 00422 ReleaseTokenFSCall(); 00423 if(FSAL_IS_ERROR(status)) 00424 ReturnStatus(status, INDEX_FSAL_link); 00425 00426 /* build the destination path and check permissions on the directory */ 00427 TakeTokenFSCall(); 00428 status = fsal_internal_handle2fd(p_context, p_dir_handle, &dstfd, O_DIRECTORY); 00429 ReleaseTokenFSCall(); 00430 if(FSAL_IS_ERROR(status)) 00431 { 00432 close(srcfd); 00433 ReturnStatus(status, INDEX_FSAL_link); 00434 } 00435 /* retrieve target directory metadata */ 00436 00437 TakeTokenFSCall(); 00438 rc = fstat(dstfd, &buffstat_dir); 00439 errsv = errno; 00440 ReleaseTokenFSCall(); 00441 00442 if(rc) 00443 { 00444 close(srcfd); 00445 close(dstfd); 00446 00447 if(errsv == ENOENT) 00448 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_link); 00449 else 00450 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_link); 00451 } 00452 00453 /* check permission on target directory */ 00454 status = 00455 fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat_dir, NULL); 00456 if(FSAL_IS_ERROR(status)) 00457 { 00458 close(srcfd), close(dstfd); 00459 ReturnStatus(status, INDEX_FSAL_link); 00460 } 00461 /* Create the link on the filesystem */ 00462 00463 TakeTokenFSCall(); 00464 rc = linkat2(srcfd, dstfd, p_link_name->name); 00465 errsv = errno; 00466 ReleaseTokenFSCall(); 00467 if(rc) 00468 { 00469 close(srcfd), close(dstfd); 00470 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_link); 00471 } 00472 /* optionnaly get attributes */ 00473 00474 if(p_attributes) 00475 { 00476 status = XFSFSAL_getattrs(p_target_handle, p_context, p_attributes); 00477 00478 /* on error, we set a special bit in the mask. */ 00479 if(FSAL_IS_ERROR(status)) 00480 { 00481 FSAL_CLEAR_MASK(p_attributes->asked_attributes); 00482 FSAL_SET_MASK(p_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00483 } 00484 } 00485 00486 /* OK */ 00487 close(srcfd); 00488 close(dstfd); 00489 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); 00490 00491 } 00492 00500 fsal_status_t XFSFSAL_mknode(fsal_handle_t * parentdir_handle, /* IN */ 00501 fsal_name_t * p_node_name, /* IN */ 00502 fsal_op_context_t * p_context, /* IN */ 00503 fsal_accessmode_t accessmode, /* IN */ 00504 fsal_nodetype_t nodetype, /* IN */ 00505 fsal_dev_t * dev, /* IN */ 00506 fsal_handle_t * p_object_handle, /* OUT (handle to the created node) */ 00507 fsal_attrib_list_t * node_attributes /* [ IN/OUT ] */ 00508 ) 00509 { 00510 int rc, errsv; 00511 int setgid_bit = 0; 00512 struct stat buffstat; 00513 fsal_status_t status; 00514 int fd, newfd; 00515 00516 mode_t unix_mode = 0; 00517 dev_t unix_dev = 0; 00518 00519 /* sanity checks. 00520 * note : link_attributes is optional. 00521 */ 00522 if(!parentdir_handle || !p_context || !p_node_name) 00523 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); 00524 00525 unix_mode = fsal2unix_mode(accessmode); 00526 00527 /* Apply umask */ 00528 unix_mode = unix_mode & ~global_fs_info.umask; 00529 00530 switch (nodetype) 00531 { 00532 case FSAL_TYPE_BLK: 00533 if(!dev) 00534 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); 00535 unix_mode |= S_IFBLK; 00536 unix_dev = (dev->major << 8) | (dev->minor & 0xFF); 00537 break; 00538 00539 case FSAL_TYPE_CHR: 00540 if(!dev) 00541 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); 00542 unix_mode |= S_IFCHR; 00543 unix_dev = (dev->major << 8) | (dev->minor & 0xFF); 00544 break; 00545 00546 case FSAL_TYPE_SOCK: 00547 unix_mode |= S_IFSOCK; 00548 break; 00549 00550 case FSAL_TYPE_FIFO: 00551 unix_mode |= S_IFIFO; 00552 break; 00553 00554 default: 00555 LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", 00556 nodetype); 00557 Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode); 00558 } 00559 00560 /* build the directory path */ 00561 TakeTokenFSCall(); 00562 status = fsal_internal_handle2fd(p_context, parentdir_handle, &fd, O_DIRECTORY); 00563 ReleaseTokenFSCall(); 00564 00565 if(FSAL_IS_ERROR(status)) 00566 ReturnStatus(status, INDEX_FSAL_mknode); 00567 00568 /* retrieve directory attributes */ 00569 TakeTokenFSCall(); 00570 rc = fstat(fd, &buffstat); 00571 errsv = errno; 00572 ReleaseTokenFSCall(); 00573 00574 if(rc) 00575 { 00576 close(fd); 00577 00578 if(errsv == ENOENT) 00579 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_mknode); 00580 else 00581 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); 00582 } 00583 00584 /* Check the user can write in the directory, and check weither the setgid bit on the directory */ 00585 if(buffstat.st_mode & S_ISGID) 00586 setgid_bit = 1; 00587 00588 status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); 00589 if(FSAL_IS_ERROR(status)) 00590 ReturnStatus(status, INDEX_FSAL_mknode); 00591 00592 /* creates the node, then stats it */ 00593 TakeTokenFSCall(); 00594 rc = mknodat(fd, p_node_name->name, unix_mode, unix_dev); 00595 errsv = errno; 00596 00597 if(rc) 00598 { 00599 close(fd); 00600 ReleaseTokenFSCall(); 00601 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); 00602 } 00603 00604 /* get the new object handle */ 00605 if((newfd = openat(fd, p_node_name->name, O_RDONLY, 0600)) < 0) 00606 { 00607 errsv = errno; 00608 close(fd); 00609 ReleaseTokenFSCall(); 00610 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); 00611 } 00612 00613 status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); 00614 ReleaseTokenFSCall(); 00615 00616 if(FSAL_IS_ERROR(status)) 00617 { 00618 close(fd); 00619 close(newfd); 00620 ReturnStatus(status, INDEX_FSAL_mknode); 00621 } 00622 00623 /* the node has been created */ 00624 /* chown the file to the current user/group */ 00625 00626 if(((xfsfsal_op_context_t *)p_context)->credential.user != geteuid()) 00627 { 00628 TakeTokenFSCall(); 00629 00630 /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ 00631 rc = fchown(newfd, ((xfsfsal_op_context_t *)p_context)->credential.user, 00632 setgid_bit ? -1 : (int)((xfsfsal_op_context_t *)p_context)->credential.group); 00633 errsv = errno; 00634 00635 ReleaseTokenFSCall(); 00636 00637 if(rc) 00638 { 00639 close(fd); 00640 close(newfd); 00641 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); 00642 } 00643 } 00644 00645 close(fd); 00646 close(newfd); 00647 00648 /* Fills the attributes if needed */ 00649 if(node_attributes) 00650 { 00651 00652 status = XFSFSAL_getattrs(p_object_handle, p_context, node_attributes); 00653 00654 /* on error, we set a special bit in the mask. */ 00655 00656 if(FSAL_IS_ERROR(status)) 00657 { 00658 FSAL_CLEAR_MASK(node_attributes->asked_attributes); 00659 FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00660 } 00661 00662 } 00663 00664 /* Finished */ 00665 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode); 00666 00667 }