nfs-ganesha 1.4

fsal_rename.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 
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 }