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 00035 #ifdef HAVE_CONFIG_H 00036 #include "config.h" 00037 #endif 00038 00039 #include "fsal.h" 00040 #include "fsal_internal.h" 00041 #include "FSAL/access_check.h" 00042 #include "fsal_convert.h" 00043 00078 fsal_status_t XFSFSAL_rename(fsal_handle_t * p_old_parentdir_handle, /* IN */ 00079 fsal_name_t * p_old_name, /* IN */ 00080 fsal_handle_t * p_new_parentdir_handle, /* IN */ 00081 fsal_name_t * p_new_name, /* IN */ 00082 fsal_op_context_t * p_context, /* IN */ 00083 fsal_attrib_list_t * p_src_dir_attributes, /* [ IN/OUT ] */ 00084 fsal_attrib_list_t * p_tgt_dir_attributes /* [ IN/OUT ] */ 00085 ) 00086 { 00087 00088 int rc, errsv; 00089 fsal_status_t status; 00090 struct stat old_parent_buffstat, new_parent_buffstat, buffstat; 00091 int old_parent_fd, new_parent_fd; 00092 int src_equal_tgt = FALSE; 00093 uid_t userid = ((xfsfsal_op_context_t*)p_context)->credential.user; 00094 00095 /* sanity checks. 00096 * note : src/tgt_dir_attributes are optional. 00097 */ 00098 if(!p_old_parentdir_handle || !p_new_parentdir_handle 00099 || !p_old_name || !p_new_name || !p_context) 00100 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); 00101 00102 /* Get directory access path by fid */ 00103 00104 TakeTokenFSCall(); 00105 status = 00106 fsal_internal_handle2fd(p_context, p_old_parentdir_handle, &old_parent_fd, 00107 O_DIRECTORY); 00108 ReleaseTokenFSCall(); 00109 00110 if(FSAL_IS_ERROR(status)) 00111 ReturnStatus(status, INDEX_FSAL_rename); 00112 00113 /* retrieve directory metadata for checking access rights */ 00114 00115 TakeTokenFSCall(); 00116 rc = fstat(old_parent_fd, &old_parent_buffstat); 00117 errsv = errno; 00118 ReleaseTokenFSCall(); 00119 00120 if(rc) 00121 { 00122 close(old_parent_fd); 00123 if(errsv == ENOENT) 00124 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_rename); 00125 else 00126 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); 00127 } 00128 00129 /* optimisation : don't do the job twice if source dir = dest dir */ 00130 if(!XFSFSAL_handlecmp(p_old_parentdir_handle, p_new_parentdir_handle, &status)) 00131 { 00132 new_parent_fd = old_parent_fd; 00133 src_equal_tgt = TRUE; 00134 new_parent_buffstat = old_parent_buffstat; 00135 } 00136 else 00137 { 00138 TakeTokenFSCall(); 00139 status = 00140 fsal_internal_handle2fd(p_context, p_new_parentdir_handle, &new_parent_fd, 00141 O_DIRECTORY); 00142 ReleaseTokenFSCall(); 00143 00144 if(FSAL_IS_ERROR(status)) 00145 { 00146 close(old_parent_fd); 00147 ReturnStatus(status, INDEX_FSAL_rename); 00148 } 00149 /* retrieve destination attrs */ 00150 TakeTokenFSCall(); 00151 rc = fstat(new_parent_fd, &new_parent_buffstat); 00152 errsv = errno; 00153 ReleaseTokenFSCall(); 00154 00155 if(rc) 00156 { 00157 /* close old and new parent fd */ 00158 close(old_parent_fd); 00159 close(new_parent_fd); 00160 00161 if(errsv == ENOENT) 00162 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_rename); 00163 else 00164 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); 00165 } 00166 00167 } 00168 00169 /* check access rights */ 00170 00171 status = 00172 fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &old_parent_buffstat, 00173 NULL); 00174 if(FSAL_IS_ERROR(status)) 00175 { 00176 close(old_parent_fd); 00177 if (!src_equal_tgt) 00178 close(new_parent_fd); 00179 ReturnStatus(status, INDEX_FSAL_rename); 00180 } 00181 00182 if(!src_equal_tgt) 00183 { 00184 status = 00185 fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &new_parent_buffstat, 00186 NULL); 00187 if(FSAL_IS_ERROR(status)) 00188 { 00189 close(old_parent_fd); 00190 close(new_parent_fd); 00191 ReturnStatus(status, INDEX_FSAL_rename); 00192 } 00193 } 00194 00195 /* build file paths */ 00196 TakeTokenFSCall(); 00197 rc = fstatat(old_parent_fd, p_old_name->name, &buffstat, AT_SYMLINK_NOFOLLOW); 00198 errsv = errno; 00199 ReleaseTokenFSCall(); 00200 if(rc) 00201 { 00202 close(old_parent_fd); 00203 if (!src_equal_tgt) 00204 close(new_parent_fd); 00205 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); 00206 } 00207 /* Check sticky bits */ 00208 00209 /* Sticky bit on the source directory => the user who wants to delete the file must own it or its parent dir */ 00210 if((old_parent_buffstat.st_mode & S_ISVTX) 00211 && old_parent_buffstat.st_uid != userid 00212 && buffstat.st_uid != userid 00213 && userid != 0) 00214 { 00215 close(old_parent_fd); 00216 if (!src_equal_tgt) 00217 close(new_parent_fd); 00218 Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); 00219 } 00220 /* Sticky bit on the target directory => the user who wants to create the file must own it or its parent dir */ 00221 if(new_parent_buffstat.st_mode & S_ISVTX) 00222 { 00223 TakeTokenFSCall(); 00224 rc = fstatat(new_parent_fd, p_new_name->name, &buffstat, AT_SYMLINK_NOFOLLOW); 00225 errsv = errno; 00226 ReleaseTokenFSCall(); 00227 00228 if(rc < 0) 00229 { 00230 if(errsv != ENOENT) 00231 { 00232 close(old_parent_fd); 00233 if(!src_equal_tgt) 00234 close(new_parent_fd); 00235 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); 00236 } 00237 } 00238 else 00239 { 00240 00241 if(new_parent_buffstat.st_uid != userid 00242 && buffstat.st_uid != userid 00243 && userid != 0) 00244 { 00245 close(old_parent_fd); 00246 if( !src_equal_tgt ) 00247 close(new_parent_fd); 00248 Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); 00249 } 00250 } 00251 } 00252 00253 /************************************* 00254 * Rename the file on the filesystem * 00255 *************************************/ 00256 TakeTokenFSCall(); 00257 rc = renameat(old_parent_fd, p_old_name->name, new_parent_fd, p_new_name->name); 00258 errsv = errno; 00259 ReleaseTokenFSCall(); 00260 close(old_parent_fd); 00261 if(!src_equal_tgt) 00262 close(new_parent_fd); 00263 00264 if(rc) 00265 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); 00266 00267 /*********************** 00268 * Fill the attributes * 00269 ***********************/ 00270 00271 if(p_src_dir_attributes) 00272 { 00273 00274 status = XFSFSAL_getattrs(p_old_parentdir_handle, p_context, p_src_dir_attributes); 00275 00276 if(FSAL_IS_ERROR(status)) 00277 { 00278 FSAL_CLEAR_MASK(p_src_dir_attributes->asked_attributes); 00279 FSAL_SET_MASK(p_src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00280 } 00281 00282 } 00283 00284 if(p_tgt_dir_attributes) 00285 { 00286 00287 status = XFSFSAL_getattrs(p_new_parentdir_handle, p_context, p_tgt_dir_attributes); 00288 00289 if(FSAL_IS_ERROR(status)) 00290 { 00291 FSAL_CLEAR_MASK(p_tgt_dir_attributes->asked_attributes); 00292 FSAL_SET_MASK(p_tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00293 } 00294 00295 } 00296 00297 /* OK */ 00298 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); 00299 00300 }