nfs-ganesha 1.4

fsal_symlinks.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  * ------------- 
00024  */
00025 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif
00037 
00038 #include "fsal.h"
00039 #include "fsal_internal.h"
00040 #include "fsal_convert.h"
00041 #include <string.h>
00042 #include <unistd.h>
00043 
00067 fsal_status_t GPFSFSAL_readlink(fsal_handle_t * p_linkhandle,       /* IN */
00068                             fsal_op_context_t * p_context,      /* IN */
00069                             fsal_path_t * p_link_content,       /* OUT */
00070                             fsal_attrib_list_t * p_link_attributes      /* [ IN/OUT ] */
00071     )
00072 {
00073 
00074 /*   int errsv; */
00075   fsal_status_t status;
00076   char link_content_out[FSAL_MAX_PATH_LEN];
00077 
00078   /* sanity checks.
00079    * note : link_attributes is optional.
00080    */
00081   if(!p_linkhandle || !p_context || !p_link_content)
00082     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readlink);
00083 
00084   /* Read the link on the filesystem */
00085   TakeTokenFSCall();
00086   status =
00087       fsal_readlink_by_handle(p_context, p_linkhandle, link_content_out,
00088                               FSAL_MAX_PATH_LEN);
00089 /*   errsv = errno; */
00090   ReleaseTokenFSCall();
00091 
00092   if(FSAL_IS_ERROR(status))
00093     ReturnStatus(status, INDEX_FSAL_readlink);
00094 
00095   /* convert char * to fsal_path_t */
00096   status = FSAL_str2path(link_content_out, FSAL_MAX_PATH_LEN, p_link_content);
00097 
00098   if(FSAL_IS_ERROR(status))
00099     ReturnStatus(status, INDEX_FSAL_readlink);
00100 
00101   /* retrieves object attributes, if asked */
00102 
00103   if(p_link_attributes)
00104     {
00105 
00106       status = GPFSFSAL_getattrs(p_linkhandle, p_context, p_link_attributes);
00107 
00108       /* On error, we set a flag in the returned attributes */
00109 
00110       if(FSAL_IS_ERROR(status))
00111         {
00112           FSAL_CLEAR_MASK(p_link_attributes->asked_attributes);
00113           FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00114         }
00115 
00116     }
00117 
00118   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readlink);
00119 
00120 }
00121 
00151 fsal_status_t GPFSFSAL_symlink(fsal_handle_t * p_parent_directory_handle,   /* IN */
00152                            fsal_name_t * p_linkname,    /* IN */
00153                            fsal_path_t * p_linkcontent, /* IN */
00154                            fsal_op_context_t * p_context,       /* IN */
00155                            fsal_accessmode_t accessmode,        /* IN (ignored) */
00156                            fsal_handle_t * p_link_handle,       /* OUT */
00157                            fsal_attrib_list_t * p_link_attributes       /* [ IN/OUT ] */
00158     )
00159 {
00160 
00161   int rc, errsv;
00162   fsal_status_t status;
00163   int fd;
00164   int setgid_bit = FALSE;
00165   fsal_accessflags_t access_mask = 0;
00166   fsal_attrib_list_t parent_dir_attrs;
00167 
00168   /* sanity checks.
00169    * note : link_attributes is optional.
00170    */
00171   if(!p_parent_directory_handle || !p_context ||
00172      !p_link_handle || !p_linkname || !p_linkcontent)
00173     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink);
00174 
00175   /* Tests if symlinking is allowed by configuration. */
00176 
00177   if(!global_fs_info.symlink_support)
00178     Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_symlink);
00179 
00180   TakeTokenFSCall();
00181   status =
00182       fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd,
00183                               O_RDONLY | O_DIRECTORY);
00184   ReleaseTokenFSCall();
00185 
00186   if(FSAL_IS_ERROR(status))
00187     ReturnStatus(status, INDEX_FSAL_symlink);
00188 
00189   /* retrieve directory metadata, for checking access */
00190   parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
00191   status = GPFSFSAL_getattrs(p_parent_directory_handle, p_context, &parent_dir_attrs);
00192   if(FSAL_IS_ERROR(status))
00193     {
00194       close(fd);
00195       ReturnStatus(status, INDEX_FSAL_symlink);
00196     }
00197 
00198   if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID)
00199     setgid_bit = TRUE;
00200 
00201   /* Set both mode and ace4 mask */
00202   access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
00203                 FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);
00204 
00205   if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
00206   status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs);
00207   else
00208     status = fsal_internal_access(p_context, p_parent_directory_handle,access_mask,
00209                                   &parent_dir_attrs);
00210   if(FSAL_IS_ERROR(status))
00211     {
00212       close(fd);
00213       ReturnStatus(status, INDEX_FSAL_symlink);
00214     }
00215 
00216   /* build symlink path */
00217 
00218   /* create the symlink on the filesystem. */
00219 
00220   TakeTokenFSCall();
00221   rc = symlinkat(p_linkcontent->path, fd, p_linkname->name);
00222   errsv = errno;
00223   ReleaseTokenFSCall();
00224 
00225   if(rc)
00226     {
00227       close(fd);
00228       Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink);
00229     }
00230 
00231   /* now get the associated handle, while there is a race, there is
00232      also a race lower down  */
00233   status = fsal_internal_get_handle_at(fd, p_linkname, p_link_handle);
00234 
00235   if(FSAL_IS_ERROR(status))
00236     {
00237       close(fd);
00238       ReturnStatus(status, INDEX_FSAL_symlink);
00239     }
00240 
00241   /* chown the symlink to the current user/group */
00242   TakeTokenFSCall();
00243   rc = fchownat(fd, p_linkname->name, p_context->credential.user,
00244                 setgid_bit ? -1 : p_context->credential.group, AT_SYMLINK_NOFOLLOW);
00245   errsv = errno;
00246   ReleaseTokenFSCall();
00247 
00248   close(fd);
00249 
00250   if(rc)
00251     Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink);
00252 
00253   /* get attributes if asked */
00254 
00255   if(p_link_attributes)
00256     {
00257 
00258       status = GPFSFSAL_getattrs(p_link_handle, p_context, p_link_attributes);
00259 
00260       /* On error, we set a flag in the returned attributes */
00261 
00262       if(FSAL_IS_ERROR(status))
00263         {
00264           FSAL_CLEAR_MASK(p_link_attributes->asked_attributes);
00265           FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00266         }
00267 
00268     }
00269 
00270   /* OK */
00271   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_symlink);
00272 }