nfs-ganesha 1.4

fsal_create.c

Go to the documentation of this file.
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 }