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 VFSFSAL_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 user = ((vfsfsal_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 = fsal_internal_handle2fd(p_context, p_old_parentdir_handle, 00106 &old_parent_fd, 00107 O_RDONLY | 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(!FSAL_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 = fsal_internal_handle2fd(p_context, p_new_parentdir_handle, 00140 &new_parent_fd, 00141 O_RDONLY | 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 if(errsv == ENOENT) 00161 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_rename); 00162 else 00163 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); 00164 } 00165 00166 } 00167 00168 /* check access rights */ 00169 00170 status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, 00171 &old_parent_buffstat, 00172 NULL); 00173 if(FSAL_IS_ERROR(status)) { 00174 close(old_parent_fd); 00175 if (!src_equal_tgt) 00176 close(new_parent_fd); 00177 ReturnStatus(status, INDEX_FSAL_rename); 00178 } 00179 if(!src_equal_tgt) 00180 { 00181 status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, 00182 &new_parent_buffstat, 00183 NULL); 00184 if(FSAL_IS_ERROR(status)) { 00185 close(old_parent_fd); 00186 close(new_parent_fd); 00187 ReturnStatus(status, INDEX_FSAL_rename); 00188 } 00189 } 00190 00191 /* build file paths */ 00192 TakeTokenFSCall(); 00193 rc = fstatat(old_parent_fd, p_old_name->name, &buffstat, AT_SYMLINK_NOFOLLOW); 00194 errsv = errno; 00195 ReleaseTokenFSCall(); 00196 if(rc) { 00197 close(old_parent_fd); 00198 if (!src_equal_tgt) 00199 close(new_parent_fd); 00200 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); 00201 } 00202 00203 /* Check sticky bits */ 00204 00205 /* Sticky bit on the source directory => the user who wants to delete the file must own it or its parent dir */ 00206 if((old_parent_buffstat.st_mode & S_ISVTX) && 00207 old_parent_buffstat.st_uid != user && 00208 buffstat.st_uid != user && user != 0) { 00209 close(old_parent_fd); 00210 if (!src_equal_tgt) 00211 close(new_parent_fd); 00212 Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); 00213 } 00214 00215 /* Sticky bit on the target directory => the user who wants to create the file must own it or its parent dir */ 00216 if(new_parent_buffstat.st_mode & S_ISVTX) 00217 { 00218 TakeTokenFSCall(); 00219 rc = fstatat(new_parent_fd, p_new_name->name, &buffstat, AT_SYMLINK_NOFOLLOW); 00220 errsv = errno; 00221 ReleaseTokenFSCall(); 00222 00223 if(rc < 0) 00224 { 00225 if(errsv != ENOENT) 00226 { 00227 close(old_parent_fd); 00228 if (!src_equal_tgt) 00229 close(new_parent_fd); 00230 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); 00231 } 00232 } 00233 else 00234 { 00235 00236 if(new_parent_buffstat.st_uid != user 00237 && buffstat.st_uid != user 00238 && user != 0) 00239 { 00240 close(old_parent_fd); 00241 if (!src_equal_tgt) 00242 close(new_parent_fd); 00243 Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); 00244 } 00245 } 00246 } 00247 00248 /************************************* 00249 * Rename the file on the filesystem * 00250 *************************************/ 00251 TakeTokenFSCall(); 00252 rc = renameat(old_parent_fd, p_old_name->name, new_parent_fd, p_new_name->name); 00253 errsv = errno; 00254 ReleaseTokenFSCall(); 00255 close(old_parent_fd); 00256 if (!src_equal_tgt) 00257 close(new_parent_fd); 00258 00259 if(rc) 00260 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); 00261 00262 /*********************** 00263 * Fill the attributes * 00264 ***********************/ 00265 00266 if(p_src_dir_attributes) 00267 { 00268 00269 status = VFSFSAL_getattrs(p_old_parentdir_handle, p_context, p_src_dir_attributes); 00270 00271 if(FSAL_IS_ERROR(status)) 00272 { 00273 FSAL_CLEAR_MASK(p_src_dir_attributes->asked_attributes); 00274 FSAL_SET_MASK(p_src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00275 } 00276 00277 } 00278 00279 if(p_tgt_dir_attributes) 00280 { 00281 00282 status = VFSFSAL_getattrs(p_new_parentdir_handle, p_context, p_tgt_dir_attributes); 00283 00284 if(FSAL_IS_ERROR(status)) 00285 { 00286 FSAL_CLEAR_MASK(p_tgt_dir_attributes->asked_attributes); 00287 FSAL_SET_MASK(p_tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00288 } 00289 00290 } 00291 00292 /* OK */ 00293 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); 00294 00295 }