nfs-ganesha 1.4

fsal_create.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
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_convert.h"
00021 
00050 fsal_status_t POSIXFSAL_create(fsal_handle_t * parent_directory_handle,  /* IN */
00051                                fsal_name_t * p_filename,        /* IN */
00052                                fsal_op_context_t * context,      /* IN */
00053                                fsal_accessmode_t accessmode,    /* IN */
00054                                fsal_handle_t * object_handle,    /* OUT */
00055                                fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */
00056     )
00057 {
00058 
00059   posixfsal_handle_t * p_parent_directory_handle
00060     = (posixfsal_handle_t *) parent_directory_handle;
00061   posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context;
00062   posixfsal_handle_t * p_object_handle = (posixfsal_handle_t *) object_handle;
00063   int rc, fd, errsv;
00064   int setgid_bit = 0;
00065   fsal_status_t status;
00066 
00067   fsal_path_t fsalpath;
00068   struct stat buffstat;
00069   fsal_posixdb_fileinfo_t info;
00070   mode_t unix_mode;
00071 
00072   /* sanity checks.
00073    * note : object_attributes is optional.
00074    */
00075   if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename)
00076     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);
00077 
00078   /* convert fsal mode to unix mode. */
00079   unix_mode = fsal2unix_mode(accessmode);
00080 
00081   /* Apply umask */
00082   unix_mode = unix_mode & ~global_fs_info.umask;
00083 
00084   LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);
00085 
00086   /* build the destination path */
00087   status =
00088       fsal_internal_getPathFromHandle(p_context, p_parent_directory_handle, 1, &fsalpath,
00089                                       &buffstat);
00090   if(FSAL_IS_ERROR(status))
00091     Return(status.major, status.minor, INDEX_FSAL_create);
00092 
00093   /* Check the user can write in the directory, and check the setgid bit on the directory */
00094   if(buffstat.st_mode & S_ISGID)
00095     setgid_bit = 1;
00096 
00097   status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL);
00098   if(FSAL_IS_ERROR(status))
00099     Return(status.major, status.minor, INDEX_FSAL_create);
00100 
00101   status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_filename);
00102   if(FSAL_IS_ERROR(status))
00103     Return(status.major, status.minor, INDEX_FSAL_create);
00104 
00105   /* call to API */
00106 
00107   TakeTokenFSCall();
00108   /* create the file */
00109   fd = open(fsalpath.path, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode);   /* error if the file already exists */
00110   errsv = errno;
00111   if(fd == -1)
00112     goto releaseToken;
00113   /* close the file descriptor */
00114   rc = close(fd);
00115   errsv = errno;
00116   if(rc)
00117     goto releaseToken;
00118   /* stat the new file */
00119   rc = lstat(fsalpath.path, &buffstat);
00120   errsv = errno;
00121 
00122  releaseToken:
00123   ReleaseTokenFSCall();
00124 
00125   if(fd == -1 || rc)
00126     Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
00127 
00128   /* add the file to the database */
00129   if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info)))
00130     Return(status.major, status.minor, INDEX_FSAL_create);
00131   if(FSAL_IS_ERROR
00132      (status =
00133       fsal_internal_posixdb_add_entry(p_context->p_conn, p_filename, &info,
00134                                       p_parent_directory_handle, p_object_handle)))
00135     Return(status.major, status.minor, INDEX_FSAL_create);
00136 
00137   /* the file has been created */
00138   /* chown the file to the current user */
00139 
00140   if(p_context->credential.user != geteuid())
00141     {
00142       TakeTokenFSCall();
00143       /* if the setgid_bit was set on the parent directory,
00144        * do not change the group of the created file,
00145        * because it's already the parentdir's group */
00146       rc = lchown(fsalpath.path, p_context->credential.user,
00147                   setgid_bit ? -1 : (int)p_context->credential.group);
00148       errsv = errno;
00149       ReleaseTokenFSCall();
00150       if(rc)
00151         Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
00152 
00153       buffstat.st_uid = p_context->credential.user;
00154       buffstat.st_gid = p_context->credential.group;
00155     }
00156 
00157   /* add the file to the database */
00158 
00159   if(p_object_attributes)
00160     {
00161 
00162       /* convert POSIX attributes to fsal attributes */
00163       status = posix2fsal_attributes(&buffstat, p_object_attributes);
00164       /* on error, we set a special bit in the mask. */
00165       if(FSAL_IS_ERROR(status))
00166         {
00167           FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00168           FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00169         }
00170 
00171     }
00172 
00173   /* OK */
00174   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);
00175 
00176 }
00177 
00207 fsal_status_t POSIXFSAL_mkdir(fsal_handle_t * parent_directory_handle,   /* IN */
00208                               fsal_name_t * p_dirname,  /* IN */
00209                               fsal_op_context_t * context,       /* IN */
00210                               fsal_accessmode_t accessmode,     /* IN */
00211                               fsal_handle_t * object_handle,     /* OUT */
00212                               fsal_attrib_list_t * p_object_attributes  /* [ IN/OUT ] */
00213     )
00214 {
00215 
00216   posixfsal_handle_t * p_parent_directory_handle
00217     = (posixfsal_handle_t *) parent_directory_handle;
00218   posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context;
00219   posixfsal_handle_t * p_object_handle = (posixfsal_handle_t *) object_handle;
00220   int rc, errsv;
00221   int setgid_bit = 0;
00222   struct stat buffstat;
00223   mode_t unix_mode;
00224   fsal_status_t status;
00225   fsal_path_t fsalpath;
00226   fsal_posixdb_fileinfo_t info;
00227 
00228   /* sanity checks.
00229    * note : object_attributes is optional.
00230    */
00231   if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname)
00232     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir);
00233 
00234   /* convert FSAL mode to HPSS mode. */
00235   unix_mode = fsal2unix_mode(accessmode);
00236 
00237   /* Apply umask */
00238   unix_mode = unix_mode & ~global_fs_info.umask;
00239 
00240   /* build the destination path */
00241   status =
00242       fsal_internal_getPathFromHandle(p_context, p_parent_directory_handle, 1, &fsalpath,
00243                                       &buffstat);
00244   if(FSAL_IS_ERROR(status))
00245     Return(status.major, status.minor, INDEX_FSAL_mkdir);
00246 
00247   /* Check the user can write in the directory, and check the setgid bit on the directory */
00248   if(buffstat.st_mode & S_ISGID)
00249     setgid_bit = 1;
00250 
00251   status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL);
00252   if(FSAL_IS_ERROR(status))
00253     Return(status.major, status.minor, INDEX_FSAL_mkdir);
00254 
00255   status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_dirname);
00256   if(FSAL_IS_ERROR(status))
00257     Return(status.major, status.minor, INDEX_FSAL_mkdir);
00258 
00259   /* creates the directory and stats it */
00260   TakeTokenFSCall();
00261 
00262   rc = mkdir(fsalpath.path, unix_mode);
00263   if(!rc)
00264     rc = lstat(fsalpath.path, &buffstat);
00265   errsv = errno;
00266 
00267   ReleaseTokenFSCall();
00268 
00269   if(rc)
00270     Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
00271 
00272   /* add the directory to the database */
00273   if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info)))
00274     Return(status.major, status.minor, INDEX_FSAL_mkdir);
00275   if(FSAL_IS_ERROR
00276      (status =
00277       fsal_internal_posixdb_add_entry(p_context->p_conn, p_dirname, &info,
00278                                       p_parent_directory_handle, p_object_handle)))
00279     Return(status.major, status.minor, INDEX_FSAL_mkdir);
00280 
00281   /* the directory has been created */
00282   /* chown the file to the current user/group */
00283 
00284   if(p_context->credential.user != geteuid())
00285     {
00286       TakeTokenFSCall();
00287       /* 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 */
00288       rc = lchown(fsalpath.path, p_context->credential.user,
00289                   setgid_bit ? -1 : (int)p_context->credential.group);
00290       errsv = errno;
00291       ReleaseTokenFSCall();
00292       if(rc)
00293         Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
00294 
00295       buffstat.st_uid = p_context->credential.user;
00296       buffstat.st_gid = p_context->credential.group;
00297     }
00298 
00299   /* Fills the attributes if needed */
00300   if(p_object_attributes)
00301     {
00302 
00303       status = posix2fsal_attributes(&buffstat, p_object_attributes);
00304 
00305       /* on error, we set a special bit in the mask. */
00306 
00307       if(FSAL_IS_ERROR(status))
00308         {
00309           FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00310           FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00311         }
00312 
00313     }
00314 
00315   /* OK */
00316   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir);
00317 
00318 }
00319 
00349 fsal_status_t POSIXFSAL_link(fsal_handle_t * target_handle,      /* IN */
00350                              fsal_handle_t * dir_handle, /* IN */
00351                              fsal_name_t * p_link_name, /* IN */
00352                              fsal_op_context_t * context,        /* IN */
00353                              fsal_attrib_list_t * p_attributes  /* [ IN/OUT ] */
00354     )
00355 {
00356 
00357   posixfsal_handle_t * p_target_handle = (posixfsal_handle_t *) target_handle;
00358   posixfsal_handle_t * p_dir_handle = (posixfsal_handle_t *) dir_handle;
00359   posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context;
00360   int rc, errsv;
00361   fsal_status_t status;
00362   fsal_path_t fsalpath_old, fsalpath_new;
00363   fsal_posixdb_fileinfo_t info;
00364   posixfsal_handle_t newhandle;
00365   struct stat buffstat, buffstat_dir;
00366 
00367   /* sanity checks.
00368    * note : attributes is optional.
00369    */
00370   if(!p_target_handle || !p_dir_handle || !p_context || !p_link_name)
00371     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link);
00372 
00373   /* Tests if hardlinking is allowed by configuration. */
00374 
00375   if(!global_fs_info.link_support)
00376     Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_link);
00377 
00378   LogFullDebug(COMPONENT_FSAL, "linking %llu/%i to %llu.%i/%s \n", p_target_handle->data.id,
00379                p_target_handle->data.ts, p_dir_handle->data.id, p_dir_handle->data.ts, p_link_name->name);
00380 
00381   /* get the old path */
00382   status =
00383       fsal_internal_getPathFromHandle(p_context, p_target_handle, 0, &fsalpath_old,
00384                                       &buffstat);
00385   if(FSAL_IS_ERROR(status))
00386     {
00387       Return(status.major, status.minor, INDEX_FSAL_link);
00388     }
00389 
00390   /* build the destination path and check permissions on the directory */
00391   status =
00392       fsal_internal_getPathFromHandle(p_context, p_dir_handle, 1, &fsalpath_new,
00393                                       &buffstat_dir);
00394   if(FSAL_IS_ERROR(status))
00395     Return(status.major, status.minor, INDEX_FSAL_link);
00396 
00397   status =
00398       fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat_dir, NULL);
00399   if(FSAL_IS_ERROR(status))
00400     Return(status.major, status.minor, INDEX_FSAL_link);
00401 
00402   status = fsal_internal_appendFSALNameToFSALPath(&fsalpath_new, p_link_name);
00403   if(FSAL_IS_ERROR(status))
00404     Return(status.major, status.minor, INDEX_FSAL_link);
00405 
00406   /* Create the link on the filesystem */
00407 
00408   TakeTokenFSCall();
00409   rc = link(fsalpath_old.path, fsalpath_new.path);
00410   errsv = errno;
00411   ReleaseTokenFSCall();
00412   if(rc)
00413     Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_link);
00414 
00415   /* add the link in the database */
00416   buffstat.st_nlink++;          /* avoid to stat the new file */
00417   status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info);
00418   if(FSAL_IS_ERROR(status))
00419     Return(status.major, status.minor, INDEX_FSAL_link);
00420 
00421   if(FSAL_IS_ERROR
00422      (status =
00423       fsal_internal_posixdb_add_entry(p_context->p_conn, p_link_name, &info,
00424                                       p_dir_handle, &newhandle)))
00425     Return(status.major, status.minor, INDEX_FSAL_link);
00426 
00427   /* optionnaly get attributes */
00428 
00429   if(p_attributes)
00430     {
00431       TakeTokenFSCall();
00432       rc = lstat(fsalpath_old.path, &buffstat);
00433       errsv = errno;
00434       ReleaseTokenFSCall();
00435       if(rc)
00436         {
00437           status.major = posix2fsal_error(errsv);
00438           status.minor = errsv;
00439         }
00440       else
00441         {
00442           status = posix2fsal_attributes(&buffstat, p_attributes);
00443         }
00444 
00445       /* on error, we set a special bit in the mask. */
00446       if(FSAL_IS_ERROR(status))
00447         {
00448           FSAL_CLEAR_MASK(p_attributes->asked_attributes);
00449           FSAL_SET_MASK(p_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00450         }
00451 
00452     }
00453 
00454   /* OK */
00455   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link);
00456 
00457 }
00458 
00466 fsal_status_t POSIXFSAL_mknode(fsal_handle_t * parentdir_hdl,   /* IN */
00467                                fsal_name_t * p_node_name,       /* IN */
00468                                fsal_op_context_t * context,      /* IN */
00469                                fsal_accessmode_t accessmode,    /* IN */
00470                                fsal_nodetype_t nodetype,        /* IN */
00471                                fsal_dev_t * dev,        /* IN */
00472                                fsal_handle_t * object_handle,    /* OUT (handle to the created node) */
00473                                fsal_attrib_list_t * node_attributes     /* [ IN/OUT ] */
00474     )
00475 {
00476   posixfsal_handle_t * parentdir_handle = (posixfsal_handle_t *) parentdir_hdl;
00477   posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context;
00478   posixfsal_handle_t * p_object_handle = (posixfsal_handle_t *) object_handle;
00479   int rc, errsv;
00480   int setgid_bit = 0;
00481   struct stat buffstat;
00482   fsal_status_t status;
00483   fsal_path_t fsalpath;
00484   fsal_posixdb_fileinfo_t info;
00485 
00486   mode_t unix_mode = 0;
00487   dev_t unix_dev = 0;
00488 
00489   /* sanity checks.
00490    * note : link_attributes is optional.
00491    */
00492   if(!parentdir_handle || !p_context || !p_node_name)
00493     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
00494 
00495   unix_mode = fsal2unix_mode(accessmode);
00496 
00497   /* Apply umask */
00498   unix_mode = unix_mode & ~global_fs_info.umask;
00499 
00500   switch (nodetype)
00501     {
00502     case FSAL_TYPE_BLK:
00503       if(!dev)
00504         Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
00505       unix_mode |= S_IFBLK;
00506       unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
00507       break;
00508 
00509     case FSAL_TYPE_CHR:
00510       if(!dev)
00511         Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
00512       unix_mode |= S_IFCHR;
00513       unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
00514       break;
00515 
00516     case FSAL_TYPE_SOCK:
00517       unix_mode |= S_IFSOCK;
00518       break;
00519 
00520     case FSAL_TYPE_FIFO:
00521       unix_mode |= S_IFIFO;
00522       break;
00523 
00524     default:
00525       LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype);
00526       Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode);
00527     }
00528 
00529   /* build the destination path */
00530   status =
00531       fsal_internal_getPathFromHandle(p_context, parentdir_handle, 1, &fsalpath,
00532                                       &buffstat);
00533   if(FSAL_IS_ERROR(status))
00534     Return(status.major, status.minor, INDEX_FSAL_mknode);
00535 
00536   /* Check the user can write in the directory, and check weither the setgid bit on the directory */
00537   if(buffstat.st_mode & S_ISGID)
00538     setgid_bit = 1;
00539 
00540   status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL);
00541   if(FSAL_IS_ERROR(status))
00542     Return(status.major, status.minor, INDEX_FSAL_mknode);
00543 
00544   status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_node_name);
00545   if(FSAL_IS_ERROR(status))
00546     Return(status.major, status.minor, INDEX_FSAL_mknode);
00547 
00548   /* creates the node, then stats it */
00549   TakeTokenFSCall();
00550 
00551   rc = mknod(fsalpath.path, unix_mode, unix_dev);
00552   if(!rc)
00553     rc = lstat(fsalpath.path, &buffstat);
00554   errsv = errno;
00555 
00556   ReleaseTokenFSCall();
00557 
00558   if(rc)
00559     Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode);
00560 
00561   /* add the object to the database */
00562   if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info)))
00563     Return(status.major, status.minor, INDEX_FSAL_mknode);
00564 
00565   if(FSAL_IS_ERROR
00566      (status =
00567       fsal_internal_posixdb_add_entry(p_context->p_conn, p_node_name, &info,
00568                                       parentdir_handle, p_object_handle)))
00569     Return(status.major, status.minor, INDEX_FSAL_mknode);
00570 
00571   /* the node has been created */
00572   /* chown the file to the current user/group */
00573 
00574   if(p_context->credential.user != geteuid())
00575     {
00576       TakeTokenFSCall();
00577 
00578       /* 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 */
00579       rc = lchown(fsalpath.path, p_context->credential.user,
00580                   setgid_bit ? -1 : (int)p_context->credential.group);
00581       errsv = errno;
00582 
00583       ReleaseTokenFSCall();
00584 
00585       if(rc)
00586         Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode);
00587 
00588       buffstat.st_uid = p_context->credential.user;
00589       buffstat.st_gid = p_context->credential.group;
00590     }
00591 
00592   /* Fills the attributes if needed */
00593   if(node_attributes)
00594     {
00595 
00596       status = posix2fsal_attributes(&buffstat, node_attributes);
00597 
00598       /* on error, we set a special bit in the mask. */
00599 
00600       if(FSAL_IS_ERROR(status))
00601         {
00602           FSAL_CLEAR_MASK(node_attributes->asked_attributes);
00603           FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00604         }
00605 
00606     }
00607 
00608   /* Finished */
00609   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode);
00610 
00611 }