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