nfs-ganesha 1.4
|
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/access_check.h" 00041 #include "fsal_convert.h" 00042 #include <string.h> 00043 #include <unistd.h> 00044 00068 fsal_status_t VFSFSAL_readlink(fsal_handle_t * p_linkhandle, /* IN */ 00069 fsal_op_context_t * p_context, /* IN */ 00070 fsal_path_t * p_link_content, /* OUT */ 00071 fsal_attrib_list_t * p_link_attributes /* [ IN/OUT ] */ 00072 ) 00073 { 00074 00075 int rc, errsv; 00076 fsal_status_t status; 00077 char link_content_out[FSAL_MAX_PATH_LEN]; 00078 00079 /* sanity checks. 00080 * note : link_attributes is optional. 00081 */ 00082 if(!p_linkhandle || !p_context || !p_link_content) 00083 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readlink); 00084 00085 memset(link_content_out, 0, FSAL_MAX_PATH_LEN); 00086 00087 /* Read the link on the filesystem */ 00088 TakeTokenFSCall(); 00089 rc = vfs_readlink_by_handle(((vfsfsal_op_context_t *)p_context)->export_context->mount_root_fd, 00090 &((vfsfsal_handle_t *)p_linkhandle)->data.vfs_handle, 00091 link_content_out, 00092 FSAL_MAX_PATH_LEN ) ; 00093 errsv = errno; 00094 ReleaseTokenFSCall(); 00095 00096 if( rc == -1 ) 00097 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_readlink); 00098 00099 /* convert char * to fsal_path_t */ 00100 status = FSAL_str2path(link_content_out, FSAL_MAX_PATH_LEN, p_link_content); 00101 00102 if(FSAL_IS_ERROR(status)) 00103 ReturnStatus(status, INDEX_FSAL_readlink); 00104 00105 /* retrieves object attributes, if asked */ 00106 00107 if(p_link_attributes) 00108 { 00109 00110 status = VFSFSAL_getattrs(p_linkhandle, p_context, p_link_attributes); 00111 00112 /* On error, we set a flag in the returned attributes */ 00113 00114 if(FSAL_IS_ERROR(status)) 00115 { 00116 FSAL_CLEAR_MASK(p_link_attributes->asked_attributes); 00117 FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00118 } 00119 00120 } 00121 00122 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readlink); 00123 00124 } 00125 00155 fsal_status_t VFSFSAL_symlink(fsal_handle_t * p_parent_directory_handle, /* IN */ 00156 fsal_name_t * p_linkname, /* IN */ 00157 fsal_path_t * p_linkcontent, /* IN */ 00158 fsal_op_context_t * p_context, /* IN */ 00159 fsal_accessmode_t accessmode, /* IN (ignored) */ 00160 fsal_handle_t * p_link_handle, /* OUT */ 00161 fsal_attrib_list_t * p_link_attributes /* [ IN/OUT ] */ 00162 ) 00163 { 00164 00165 int rc, errsv; 00166 fsal_status_t status; 00167 int fd; 00168 struct stat buffstat; 00169 int setgid_bit = FALSE; 00170 00171 /* sanity checks. 00172 * note : link_attributes is optional. 00173 */ 00174 if(!p_parent_directory_handle || !p_context || 00175 !p_link_handle || !p_linkname || !p_linkcontent) 00176 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink); 00177 00178 /* Tests if symlinking is allowed by configuration. */ 00179 00180 if(!global_fs_info.symlink_support) 00181 Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_symlink); 00182 00183 TakeTokenFSCall(); 00184 status = 00185 fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, 00186 O_RDONLY | O_DIRECTORY); 00187 ReleaseTokenFSCall(); 00188 00189 if(FSAL_IS_ERROR(status)) 00190 ReturnStatus(status, INDEX_FSAL_symlink); 00191 00192 /* retrieve directory metadata, for checking access */ 00193 TakeTokenFSCall(); 00194 rc = fstat(fd, &buffstat); 00195 errsv = errno; 00196 ReleaseTokenFSCall(); 00197 00198 if(rc) 00199 { 00200 close(fd); 00201 00202 if(errsv == ENOENT) 00203 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_symlink); 00204 else 00205 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); 00206 } 00207 00208 if(buffstat.st_mode & S_ISGID) 00209 setgid_bit = TRUE; 00210 00211 status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL); 00212 if(FSAL_IS_ERROR(status)) 00213 ReturnStatus(status, INDEX_FSAL_symlink); 00214 00215 /* build symlink path */ 00216 00217 /* create the symlink on the filesystem. */ 00218 00219 TakeTokenFSCall(); 00220 rc = symlinkat(p_linkcontent->path, fd, p_linkname->name); 00221 errsv = errno; 00222 ReleaseTokenFSCall(); 00223 00224 if(rc) 00225 { 00226 close(fd); 00227 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); 00228 } 00229 00230 /* now get the associated handle, while there is a race, there is 00231 also a race lower down */ 00232 status = fsal_internal_get_handle_at(fd, p_linkname->name, p_link_handle); 00233 00234 if(FSAL_IS_ERROR(status)) 00235 { 00236 close(fd); 00237 ReturnStatus(status, INDEX_FSAL_symlink); 00238 } 00239 00240 /* chown the symlink to the current user/group */ 00241 TakeTokenFSCall(); 00242 rc = fchownat(fd, p_linkname->name, ((vfsfsal_op_context_t *)p_context)->credential.user, 00243 setgid_bit ? -1 : ((vfsfsal_op_context_t *)p_context)->credential.group, 00244 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 = VFSFSAL_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 }