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 XFSFSAL_readlink(fsal_handle_t * 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 xfsfsal_handle_t * p_linkhandle = (xfsfsal_handle_t *)linkhandle; 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 00089 TakeTokenFSCall(); 00090 rc = readlink_by_handle(p_linkhandle->data.handle_val, p_linkhandle->data.handle_len, 00091 link_content_out, FSAL_MAX_PATH_LEN); 00092 errsv = errno; 00093 ReleaseTokenFSCall(); 00094 00095 /* rc is the length for the symlink content or -1 on error !!! */ 00096 if(rc < 0) 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 = XFSFSAL_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 XFSFSAL_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, lbuffstat; 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, O_DIRECTORY); 00186 ReleaseTokenFSCall(); 00187 00188 if(FSAL_IS_ERROR(status)) 00189 ReturnStatus(status, INDEX_FSAL_symlink); 00190 00191 /* retrieve directory metadata, for checking access */ 00192 TakeTokenFSCall(); 00193 rc = fstat(fd, &buffstat); 00194 errsv = errno; 00195 ReleaseTokenFSCall(); 00196 00197 if(rc) 00198 { 00199 close(fd); 00200 00201 if(errsv == ENOENT) 00202 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_symlink); 00203 else 00204 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); 00205 } 00206 00207 if(buffstat.st_mode & S_ISGID) 00208 setgid_bit = TRUE; 00209 00210 status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL); 00211 if(FSAL_IS_ERROR(status)) 00212 ReturnStatus(status, INDEX_FSAL_symlink); 00213 00214 /* create the symlink on the filesystem. */ 00215 00216 TakeTokenFSCall(); 00217 rc = symlinkat(p_linkcontent->path, fd, p_linkname->name); 00218 errsv = errno; 00219 ReleaseTokenFSCall(); 00220 00221 if(rc) 00222 { 00223 close(fd); 00224 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); 00225 } 00226 00227 /* chown the symlink to the current user/group */ 00228 00229 TakeTokenFSCall(); 00230 rc = fchownat(fd, p_linkname->name, ((xfsfsal_op_context_t*)p_context)->credential.user, 00231 setgid_bit ? -1 : ((xfsfsal_op_context_t*)p_context)->credential.group, AT_SYMLINK_NOFOLLOW); 00232 errsv = errno; 00233 ReleaseTokenFSCall(); 00234 00235 if(rc) 00236 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); 00237 00238 /* Build xfsfsal_handle_t */ 00239 /* build symlink path */ 00240 TakeTokenFSCall(); 00241 rc = fstatat(fd, p_linkname->name, &lbuffstat, AT_SYMLINK_NOFOLLOW); 00242 errsv = errno; 00243 ReleaseTokenFSCall(); 00244 if(rc) 00245 { 00246 close(fd); 00247 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); 00248 } 00249 00250 close(fd); 00251 00252 status = fsal_internal_inum2handle(p_context, lbuffstat.st_ino, p_link_handle); 00253 if(FSAL_IS_ERROR(status)) 00254 ReturnStatus(status, INDEX_FSAL_symlink); 00255 00256 /* get attributes if asked */ 00257 00258 if(p_link_attributes) 00259 { 00260 00261 status = posix2fsal_attributes(&lbuffstat, p_link_attributes); 00262 00263 /* On error, we set a flag in the returned attributes */ 00264 if(FSAL_IS_ERROR(status)) 00265 { 00266 FSAL_CLEAR_MASK(p_link_attributes->asked_attributes); 00267 FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00268 } 00269 00270 } 00271 00272 /* OK */ 00273 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_symlink); 00274 }