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 00053 fsal_status_t VFSFSAL_create(fsal_handle_t * p_parent_directory_handle, /* IN */ 00054 fsal_name_t * p_filename, /* IN */ 00055 fsal_op_context_t * p_context, /* IN */ 00056 fsal_accessmode_t accessmode, /* IN */ 00057 fsal_handle_t * p_object_handle, /* OUT */ 00058 fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ 00059 ) 00060 { 00061 00062 int rc, errsv; 00063 int setgid_bit = 0; 00064 fsal_status_t status; 00065 00066 int fd, newfd; 00067 struct stat buffstat; 00068 mode_t unix_mode; 00069 00070 /* sanity checks. 00071 * note : object_attributes is optional. 00072 */ 00073 if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename) 00074 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); 00075 00076 /* convert fsal mode to unix mode. */ 00077 unix_mode = fsal2unix_mode(accessmode); 00078 00079 /* Apply umask */ 00080 unix_mode = unix_mode & ~global_fs_info.umask; 00081 00082 LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); 00083 00084 TakeTokenFSCall(); 00085 status = 00086 fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY); 00087 ReleaseTokenFSCall(); 00088 if(FSAL_IS_ERROR(status)) 00089 ReturnStatus(status, INDEX_FSAL_create); 00090 00091 /* retrieve directory metadata */ 00092 TakeTokenFSCall(); 00093 rc = fstat(fd, &buffstat); 00094 errsv = errno; 00095 ReleaseTokenFSCall(); 00096 if(rc) 00097 { 00098 close(fd); 00099 00100 if(errsv == ENOENT) 00101 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_create); 00102 else 00103 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); 00104 } 00105 00106 /* Check the user can write in the directory, and check the setgid bit on the directory */ 00107 00108 if(buffstat.st_mode & S_ISGID) 00109 setgid_bit = 1; 00110 00111 status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); 00112 if(FSAL_IS_ERROR(status)) 00113 ReturnStatus(status, INDEX_FSAL_create); 00114 00115 /* call to filesystem */ 00116 00117 TakeTokenFSCall(); 00118 /* create the file. 00119 * O_EXCL=> error if the file already exists */ 00120 newfd = openat(fd, p_filename->name, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode); 00121 errsv = errno; 00122 00123 if(newfd == -1) 00124 { 00125 close(fd); 00126 ReleaseTokenFSCall(); 00127 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); 00128 } 00129 00130 /* get the new file handle */ 00131 status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); 00132 00133 ReleaseTokenFSCall(); 00134 00135 if(FSAL_IS_ERROR(status)) 00136 { 00137 close(fd); 00138 close(newfd); 00139 ReturnStatus(status, INDEX_FSAL_create); 00140 } 00141 /* the file has been created */ 00142 /* chown the file to the current user */ 00143 00144 if(((vfsfsal_op_context_t *)p_context)->credential.user != geteuid()) 00145 { 00146 TakeTokenFSCall(); 00147 /* 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 */ 00148 rc = fchown(newfd, ((vfsfsal_op_context_t *)p_context)->credential.user, 00149 setgid_bit ? -1 : (int)((vfsfsal_op_context_t *)p_context)->credential.group); /* -1 ??? */ 00150 errsv = errno; 00151 ReleaseTokenFSCall(); 00152 if(rc) 00153 { 00154 close(fd); 00155 close(newfd); 00156 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); 00157 } 00158 } 00159 00160 close(fd); 00161 close(newfd); 00162 00163 /* retrieve file attributes */ 00164 if(p_object_attributes) 00165 { 00166 status = VFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes); 00167 00168 /* on error, we set a special bit in the mask. */ 00169 if(FSAL_IS_ERROR(status)) 00170 { 00171 FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); 00172 FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00173 } 00174 00175 } 00176 00177 /* OK */ 00178 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); 00179 00180 } 00181 00211 fsal_status_t VFSFSAL_mkdir(fsal_handle_t * p_parent_directory_handle, /* IN */ 00212 fsal_name_t * p_dirname, /* IN */ 00213 fsal_op_context_t * p_context, /* IN */ 00214 fsal_accessmode_t accessmode, /* IN */ 00215 fsal_handle_t * p_object_handle, /* OUT */ 00216 fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ 00217 ) 00218 { 00219 00220 int rc, errsv; 00221 int setgid_bit = 0; 00222 struct stat buffstat; 00223 mode_t unix_mode; 00224 fsal_status_t status; 00225 int fd, newfd; 00226 00227 /* sanity checks. 00228 * note : object_attributes is optional. 00229 */ 00230 if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname) 00231 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); 00232 00233 /* convert FSAL mode to VFS mode. */ 00234 unix_mode = fsal2unix_mode(accessmode); 00235 00236 /* Apply umask */ 00237 unix_mode = unix_mode & ~global_fs_info.umask; 00238 00239 TakeTokenFSCall(); 00240 status = 00241 fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY); 00242 ReleaseTokenFSCall(); 00243 00244 if(FSAL_IS_ERROR(status)) 00245 ReturnStatus(status, INDEX_FSAL_mkdir); 00246 00247 /* get directory metadata */ 00248 TakeTokenFSCall(); 00249 rc = fstat(fd, &buffstat); 00250 errsv = errno; 00251 ReleaseTokenFSCall(); 00252 if(rc) 00253 { 00254 close(fd); 00255 00256 if(errsv == ENOENT) 00257 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_create); 00258 else 00259 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); 00260 } 00261 00262 /* Check the user can write in the directory, and check the setgid bit on the directory */ 00263 00264 if(buffstat.st_mode & S_ISGID) 00265 setgid_bit = 1; 00266 00267 status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); 00268 if(FSAL_IS_ERROR(status)) 00269 ReturnStatus(status, INDEX_FSAL_mkdir); 00270 00271 /* build new entry path */ 00272 00273 /* creates the directory and get its handle */ 00274 00275 TakeTokenFSCall(); 00276 rc = mkdirat(fd, p_dirname->name, unix_mode); 00277 errsv = errno; 00278 if(rc) 00279 { 00280 close(fd); 00281 00282 ReleaseTokenFSCall(); 00283 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); 00284 } 00285 00286 /* get the new handle */ 00287 00288 if((newfd = openat(fd, p_dirname->name, O_RDONLY | O_DIRECTORY, 0600)) < 0) 00289 { 00290 errsv = errno; 00291 close(fd); 00292 ReleaseTokenFSCall(); 00293 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); 00294 } 00295 00296 status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); 00297 ReleaseTokenFSCall(); 00298 00299 if(FSAL_IS_ERROR(status)) 00300 { 00301 close(fd); 00302 close(newfd); 00303 ReturnStatus(status, INDEX_FSAL_mkdir); 00304 } 00305 00306 /* the directory has been created */ 00307 /* chown the file to the current user/group */ 00308 00309 if(((vfsfsal_op_context_t *)p_context)->credential.user != geteuid()) 00310 { 00311 TakeTokenFSCall(); 00312 /* 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 */ 00313 rc = fchown(newfd, ((vfsfsal_op_context_t *)p_context)->credential.user, 00314 setgid_bit ? -1 : (int)((vfsfsal_op_context_t *)p_context)->credential.group); 00315 errsv = errno; 00316 ReleaseTokenFSCall(); 00317 if(rc) 00318 { 00319 close(fd); 00320 close(newfd); 00321 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); 00322 } 00323 } 00324 00325 close(fd); 00326 close(newfd); 00327 00328 /* retrieve file attributes */ 00329 if(p_object_attributes) 00330 { 00331 status = VFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes); 00332 00333 /* on error, we set a special bit in the mask. */ 00334 if(FSAL_IS_ERROR(status)) 00335 { 00336 FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); 00337 FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00338 } 00339 00340 } 00341 00342 /* OK */ 00343 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir); 00344 00345 } 00346 00376 fsal_status_t VFSFSAL_link(fsal_handle_t * p_target_handle, /* IN */ 00377 fsal_handle_t * p_dir_handle, /* IN */ 00378 fsal_name_t * p_link_name, /* IN */ 00379 fsal_op_context_t * p_context, /* IN */ 00380 fsal_attrib_list_t * p_attributes /* [ IN/OUT ] */ 00381 ) 00382 { 00383 00384 int rc, errsv; 00385 fsal_status_t status; 00386 int srcfd, dstfd; 00387 struct stat buffstat_dir; 00388 00389 /* sanity checks. 00390 * note : attributes is optional. 00391 */ 00392 if(!p_target_handle || !p_dir_handle || !p_context || !p_link_name) 00393 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); 00394 00395 /* Tests if hardlinking is allowed by configuration. */ 00396 00397 if(!global_fs_info.link_support) 00398 Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_link); 00399 00400 /* LogFullDebug(COMPONENT_FSAL, "linking %#llx:%#x:%#x to %#llx:%#x:%#x/%s", */ 00401 00402 /* get the target handle access by fid */ 00403 TakeTokenFSCall(); 00404 status = fsal_internal_handle2fd(p_context, p_target_handle, &srcfd, O_DIRECTORY); 00405 ReleaseTokenFSCall(); 00406 if(FSAL_IS_ERROR(status)) 00407 ReturnStatus(status, INDEX_FSAL_link); 00408 00409 /* build the destination path and check permissions on the directory */ 00410 TakeTokenFSCall(); 00411 status = fsal_internal_handle2fd(p_context, p_dir_handle, &dstfd, O_DIRECTORY); 00412 ReleaseTokenFSCall(); 00413 if(FSAL_IS_ERROR(status)) 00414 { 00415 close(srcfd); 00416 ReturnStatus(status, INDEX_FSAL_link); 00417 } 00418 /* retrieve target directory metadata */ 00419 00420 TakeTokenFSCall(); 00421 rc = fstat(dstfd, &buffstat_dir); 00422 errsv = errno; 00423 ReleaseTokenFSCall(); 00424 00425 if(rc) 00426 { 00427 close(srcfd); 00428 close(dstfd); 00429 00430 if(errsv == ENOENT) 00431 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_link); 00432 else 00433 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_link); 00434 } 00435 00436 /* check permission on target directory */ 00437 status = 00438 fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat_dir, NULL); 00439 if(FSAL_IS_ERROR(status)) 00440 { 00441 close(srcfd), close(dstfd); 00442 ReturnStatus(status, INDEX_FSAL_link); 00443 } 00444 /* Create the link on the filesystem */ 00445 00446 TakeTokenFSCall(); 00447 rc = linkat(srcfd, "", dstfd, p_link_name->name, AT_EMPTY_PATH); 00448 errsv = errno; 00449 ReleaseTokenFSCall(); 00450 if(rc) 00451 { 00452 close(srcfd), close(dstfd); 00453 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_link); 00454 } 00455 /* optionnaly get attributes */ 00456 00457 if(p_attributes) 00458 { 00459 status = VFSFSAL_getattrs(p_target_handle, p_context, p_attributes); 00460 00461 /* on error, we set a special bit in the mask. */ 00462 if(FSAL_IS_ERROR(status)) 00463 { 00464 FSAL_CLEAR_MASK(p_attributes->asked_attributes); 00465 FSAL_SET_MASK(p_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00466 } 00467 } 00468 00469 /* OK */ 00470 close(srcfd); 00471 close(dstfd); 00472 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); 00473 00474 } 00475 00480 fsal_status_t VFSFSAL_mknode(fsal_handle_t * parentdir_handle, /* IN */ 00481 fsal_name_t * p_node_name, /* IN */ 00482 fsal_op_context_t * p_context, /* IN */ 00483 fsal_accessmode_t accessmode, /* IN */ 00484 fsal_nodetype_t nodetype, /* IN */ 00485 fsal_dev_t * dev, /* IN */ 00486 fsal_handle_t * p_object_handle, /* OUT (handle to the created node) */ 00487 fsal_attrib_list_t * node_attributes /* [ IN/OUT ] */ 00488 ) 00489 { 00490 int rc, errsv; 00491 int setgid_bit = 0; 00492 struct stat buffstat; 00493 fsal_status_t status; 00494 int fd, newfd; 00495 00496 mode_t unix_mode = 0; 00497 dev_t unix_dev = 0; 00498 00499 /* sanity checks. 00500 * note : link_attributes is optional. 00501 */ 00502 if(!parentdir_handle || !p_context || !p_node_name) 00503 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); 00504 00505 unix_mode = fsal2unix_mode(accessmode); 00506 00507 /* Apply umask */ 00508 unix_mode = unix_mode & ~global_fs_info.umask; 00509 00510 switch (nodetype) 00511 { 00512 case FSAL_TYPE_BLK: 00513 if(!dev) 00514 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); 00515 unix_mode |= S_IFBLK; 00516 unix_dev = (dev->major << 8) | (dev->minor & 0xFF); 00517 break; 00518 00519 case FSAL_TYPE_CHR: 00520 if(!dev) 00521 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); 00522 unix_mode |= S_IFCHR; 00523 unix_dev = (dev->major << 8) | (dev->minor & 0xFF); 00524 break; 00525 00526 case FSAL_TYPE_SOCK: 00527 unix_mode |= S_IFSOCK; 00528 break; 00529 00530 case FSAL_TYPE_FIFO: 00531 unix_mode |= S_IFIFO; 00532 break; 00533 00534 default: 00535 LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", 00536 nodetype); 00537 Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode); 00538 } 00539 00540 /* build the directory path */ 00541 TakeTokenFSCall(); 00542 status = fsal_internal_handle2fd(p_context, parentdir_handle, &fd, O_DIRECTORY); 00543 ReleaseTokenFSCall(); 00544 00545 if(FSAL_IS_ERROR(status)) 00546 ReturnStatus(status, INDEX_FSAL_mknode); 00547 00548 /* retrieve directory attributes */ 00549 TakeTokenFSCall(); 00550 rc = fstat(fd, &buffstat); 00551 errsv = errno; 00552 ReleaseTokenFSCall(); 00553 00554 if(rc) 00555 { 00556 close(fd); 00557 00558 if(errsv == ENOENT) 00559 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_mknode); 00560 else 00561 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); 00562 } 00563 00564 /* Check the user can write in the directory, and check weither the setgid bit on the directory */ 00565 if(buffstat.st_mode & S_ISGID) 00566 setgid_bit = 1; 00567 00568 status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); 00569 if(FSAL_IS_ERROR(status)) 00570 ReturnStatus(status, INDEX_FSAL_mknode); 00571 00572 /* creates the node, then stats it */ 00573 TakeTokenFSCall(); 00574 rc = mknodat(fd, p_node_name->name, unix_mode, unix_dev); 00575 errsv = (rc == 0 )?0:errno; 00576 00577 if(rc) 00578 { 00579 close(fd); 00580 ReleaseTokenFSCall(); 00581 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); 00582 } 00583 00584 /* get the new object handle */ 00585 if((newfd = openat(fd, p_node_name->name, O_NONBLOCK | O_RDONLY, 00586 unix_mode)) < 0) 00587 { 00588 errsv = errno; 00589 close(fd); 00590 ReleaseTokenFSCall(); 00591 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); 00592 } 00593 00594 status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); 00595 ReleaseTokenFSCall(); 00596 00597 if(FSAL_IS_ERROR(status)) 00598 { 00599 close(fd); 00600 close(newfd); 00601 ReturnStatus(status, INDEX_FSAL_mknode); 00602 } 00603 00604 /* the node has been created */ 00605 /* chown the file to the current user/group */ 00606 00607 if(((vfsfsal_op_context_t *)p_context)->credential.user != geteuid()) 00608 { 00609 TakeTokenFSCall(); 00610 00611 /* 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 */ 00612 rc = fchown(newfd, ((vfsfsal_op_context_t *)p_context)->credential.user, 00613 setgid_bit ? -1 : (int)((vfsfsal_op_context_t *)p_context)->credential.group); 00614 errsv = errno; 00615 00616 ReleaseTokenFSCall(); 00617 00618 if(rc) 00619 { 00620 close(fd); 00621 close(newfd); 00622 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); 00623 } 00624 } 00625 00626 close(fd); 00627 close(newfd); 00628 00629 /* Fills the attributes if needed */ 00630 if(node_attributes) 00631 { 00632 00633 status = VFSFSAL_getattrs(p_object_handle, p_context, node_attributes); 00634 00635 /* on error, we set a special bit in the mask. */ 00636 00637 if(FSAL_IS_ERROR(status)) 00638 { 00639 FSAL_CLEAR_MASK(node_attributes->asked_attributes); 00640 FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00641 } 00642 00643 } 00644 00645 /* Finished */ 00646 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode); 00647 00648 }