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 
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 }