nfs-ganesha 1.4

fsal_attrs.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 
00032 #ifdef HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035 
00036 #include "fsal.h"
00037 #include "fsal_internal.h"
00038 #include "FSAL/access_check.h"
00039 #include "fsal_convert.h"
00040 #include <sys/types.h>
00041 #include <unistd.h>
00042 #include <utime.h>
00043 #include <sys/time.h>
00044 
00045 extern fsal_status_t posixstat64_2_fsal_attributes(struct stat64 *p_buffstat,
00046                                                    fsal_attrib_list_t * p_fsalattr_out);
00047 
00067 fsal_status_t VFSFSAL_getattrs(fsal_handle_t * p_filehandle,       /* IN */
00068                             fsal_op_context_t * p_context,      /* IN */
00069                             fsal_attrib_list_t * p_object_attributes    /* IN/OUT */
00070     )
00071 {
00072   fsal_status_t st;
00073   int rc = 0 ;
00074   int errsv;
00075   struct stat buffstat;
00076 
00077   /* sanity checks.
00078    * note : object_attributes is mandatory in VFSFSAL_getattrs.
00079    */
00080   if(!p_filehandle || !p_context || !p_object_attributes)
00081     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs);
00082 
00083   TakeTokenFSCall();
00084   rc = vfs_stat_by_handle( ((vfsfsal_op_context_t *)p_context)->export_context->mount_root_fd,
00085                            &((vfsfsal_handle_t *)p_filehandle)->data.vfs_handle,
00086                            &buffstat ) ;
00087   errsv = errno;
00088   ReleaseTokenFSCall();
00089 
00090   if( rc == -1 )
00091     Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_getattrs);
00092 
00093   /* convert attributes */
00094   st = posix2fsal_attributes(&buffstat, p_object_attributes);
00095   if(FSAL_IS_ERROR(st))
00096     {
00097       FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00098       FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00099       ReturnStatus(st, INDEX_FSAL_getattrs);
00100     }
00101 
00102   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs);
00103 
00104 }
00105 
00127 fsal_status_t VFSFSAL_getattrs_descriptor(fsal_file_t * p_file_descriptor,     /* IN */
00128                                            fsal_handle_t * p_filehandle,        /* IN */
00129                                            fsal_op_context_t * p_context,       /* IN */
00130                                            fsal_attrib_list_t * p_object_attributes /* IN/OUT */
00131     )
00132 {
00133   fsal_status_t st;
00134   struct stat64 buffstat;
00135   int rc, errsv;
00136 
00137   /* sanity checks.
00138    * note : object_attributes is mandatory in VFSFSAL_getattrs.
00139    */
00140   if(!p_file_descriptor || !p_filehandle || !p_context || !p_object_attributes)
00141     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs_descriptor);
00142 
00143   TakeTokenFSCall();
00144   rc = fstat64(((vfsfsal_file_t *)p_file_descriptor)->fd, &buffstat);
00145   errsv = errno;
00146   ReleaseTokenFSCall();
00147 
00148   if(rc == -1)
00149     Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_getattrs_descriptor);
00150 
00151   /* convert attributes */
00152   st = posixstat64_2_fsal_attributes(&buffstat, p_object_attributes);
00153   if(FSAL_IS_ERROR(st))
00154     {
00155       FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00156       FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00157       ReturnStatus(st, INDEX_FSAL_getattrs_descriptor);
00158     }
00159 
00160   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs_descriptor);
00161 
00162 }
00163 
00188 fsal_status_t VFSFSAL_setattrs(fsal_handle_t * p_filehandle,       /* IN */
00189                             fsal_op_context_t * p_context,      /* IN */
00190                             fsal_attrib_list_t * p_attrib_set,  /* IN */
00191                             fsal_attrib_list_t * p_object_attributes    /* [ IN/OUT ] */
00192     )
00193 {
00194   vfsfsal_op_context_t * vfs_context = (vfsfsal_op_context_t *) p_context;
00195   int rc, errsv;
00196   unsigned int i;
00197   fsal_status_t status;
00198   fsal_attrib_list_t attrs;
00199 
00200   int fd;
00201   struct stat buffstat;
00202 
00203   /* sanity checks.
00204    * note : object_attributes is optional.
00205    */
00206   if(!p_filehandle || !p_context || !p_attrib_set)
00207     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);
00208 
00209   /* local copy of attributes */
00210   attrs = *p_attrib_set;
00211 
00212   /* It does not make sense to setattr on a symlink */
00213   /* if(p_filehandle->type == DT_LNK)
00214      return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set,
00215      p_object_attributes);
00216    */
00217   /* First, check that FSAL attributes changes are allowed. */
00218 
00219   /* Is it allowed to change times ? */
00220 
00221   if(!global_fs_info.cansettime)
00222     {
00223 
00224       if(attrs.asked_attributes
00225          & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME))
00226         {
00227           /* handled as an unsettable attribute. */
00228           Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs);
00229         }
00230     }
00231 
00232   /* apply umask, if mode attribute is to be changed */
00233   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
00234     {
00235       attrs.mode &= (~global_fs_info.umask);
00236     }
00237 
00238   TakeTokenFSCall();
00239   status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY);
00240   ReleaseTokenFSCall();
00241   if(FSAL_IS_ERROR(status))
00242    {
00243      /* Symbolic link are handled here, they are to be opened as O_PATH */
00244      if( status.minor == ELOOP )
00245       {
00246            if(p_object_attributes)
00247              {
00248                status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);
00249 
00250                /* on error, we set a special bit in the mask. */
00251                if(FSAL_IS_ERROR(status))
00252                  {
00253                    FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00254                    FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00255                  }
00256              }
00257            Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);
00258       }
00259 
00260      ReturnStatus( status, INDEX_FSAL_setattrs);
00261    }
00262 
00263   /* get current attributes */
00264   TakeTokenFSCall();
00265   rc = fstat(fd, &buffstat);
00266   errsv = errno;
00267   ReleaseTokenFSCall();
00268 
00269   if(rc != 0)
00270     {
00271       close(fd);
00272 
00273       if(errsv == ENOENT)
00274         Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_setattrs);
00275       else
00276         Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs);
00277     }
00278 
00279   /***********
00280    *  CHMOD  *
00281    ***********/
00282   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
00283     {
00284 
00285       /* The POSIX chmod call don't affect the symlink object, but
00286        * the entry it points to. So we must ignore it.
00287        */
00288       if(!S_ISLNK(buffstat.st_mode))
00289         {
00290 
00291           /* For modifying mode, user must be root or the owner */
00292           if((vfs_context->credential.user != 0)
00293              && (vfs_context->credential.user != buffstat.st_uid))
00294             {
00295               LogFullDebug(COMPONENT_FSAL,
00296                            "Permission denied for CHMOD opeartion: current owner=%d, credential=%d",
00297                            buffstat.st_uid, vfs_context->credential.user);
00298               close(fd);
00299               Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00300             }
00301 
00302           TakeTokenFSCall();
00303           rc = fchmod(fd, fsal2unix_mode(attrs.mode));
00304           errsv = errno;
00305           ReleaseTokenFSCall();
00306 
00307           if(rc)
00308             {
00309               close(fd);
00310               Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs);
00311             }
00312 
00313         }
00314 
00315     }
00316 
00317   /***********
00318    *  CHOWN  *
00319    ***********/
00320   /* Only root can change uid and A normal user must be in the group he wants to set */
00321   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER))
00322     {
00323 
00324       /* For modifying owner, user must be root or current owner==wanted==client */
00325       if((vfs_context->credential.user != 0) &&
00326          ((vfs_context->credential.user != buffstat.st_uid) ||
00327           (vfs_context->credential.user != attrs.owner)))
00328         {
00329           LogFullDebug(COMPONENT_FSAL,
00330                        "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d",
00331                        buffstat.st_uid, vfs_context->credential.user, attrs.owner);
00332           close(fd);
00333           Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00334         }
00335     }
00336 
00337   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP))
00338     {
00339 
00340       /* For modifying group, user must be root or current owner */
00341       if((vfs_context->credential.user != 0)
00342          && (vfs_context->credential.user != buffstat.st_uid))
00343         {
00344           close(fd);
00345           Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00346         }
00347 
00348       int in_grp = 0;
00349       /* set in_grp */
00350       if(vfs_context->credential.group == attrs.group)
00351         in_grp = 1;
00352       else
00353         for(i = 0; i < vfs_context->credential.nbgroups; i++)
00354           {
00355             if((in_grp = (attrs.group == vfs_context->credential.alt_groups[i])))
00356               break;
00357           }
00358 
00359       /* it must also be in target group */
00360       if(vfs_context->credential.user != 0 && !in_grp)
00361         {
00362           LogFullDebug(COMPONENT_FSAL,
00363                        "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d",
00364                        buffstat.st_gid, vfs_context->credential.group, attrs.group);
00365           close(fd);
00366           Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00367         }
00368     }
00369 
00370   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
00371     {
00372       /*      LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)",
00373                         fsalpath.path, FSAL_TEST_MASK(attrs.asked_attributes,
00374                                                       FSAL_ATTR_OWNER) ? (int)attrs.owner
00375                         : -1, FSAL_TEST_MASK(attrs.asked_attributes,
00376                         FSAL_ATTR_GROUP) ? (int)attrs.group : -1);*/
00377 
00378       TakeTokenFSCall();
00379       rc = fchown(fd,
00380                   FSAL_TEST_MASK(attrs.asked_attributes,
00381                                  FSAL_ATTR_OWNER) ? (int)attrs.owner : -1,
00382                   FSAL_TEST_MASK(attrs.asked_attributes,
00383                                  FSAL_ATTR_GROUP) ? (int)attrs.group : -1);
00384       ReleaseTokenFSCall();
00385       if(rc)
00386         {
00387           close(fd);
00388           Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);
00389         }
00390     }
00391 
00392   /***********
00393    *  UTIME  *
00394    ***********/
00395 
00396   /* user must be the owner or have read access to modify 'atime' */
00397   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME)
00398      && (vfs_context->credential.user != 0)
00399      && (vfs_context->credential.user != buffstat.st_uid)
00400      && ((status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL)).major
00401          != ERR_FSAL_NO_ERROR))
00402     {
00403       close(fd);
00404       ReturnStatus(status, INDEX_FSAL_setattrs);
00405     }
00406   /* user must be the owner or have write access to modify 'mtime' */
00407   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME)
00408      && (vfs_context->credential.user != 0)
00409      && (vfs_context->credential.user != buffstat.st_uid)
00410      && ((status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL)).major
00411          != ERR_FSAL_NO_ERROR))
00412     {
00413       close(fd);
00414       ReturnStatus(status, INDEX_FSAL_setattrs);
00415     }
00416 
00417   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME))
00418     {
00419 
00420       struct timeval timebuf[2];
00421 
00422       /* Atime */
00423       timebuf[0].tv_sec =
00424           (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs.
00425            atime.seconds : buffstat.st_atime);
00426       timebuf[0].tv_usec = 0;
00427 
00428       /* Mtime */
00429       timebuf[1].tv_sec =
00430           (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs.
00431            mtime.seconds : buffstat.st_mtime);
00432       timebuf[1].tv_usec = 0;
00433 
00434       TakeTokenFSCall();
00435       rc = futimes(fd, timebuf);
00436       errsv = errno;
00437       ReleaseTokenFSCall();
00438       if(rc)
00439         {
00440           close(fd);
00441           Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);
00442         }
00443     }
00444 
00445   /* Optionaly fills output attributes. */
00446 
00447   if(p_object_attributes)
00448     {
00449       status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);
00450 
00451       /* on error, we set a special bit in the mask. */
00452       if(FSAL_IS_ERROR(status))
00453         {
00454           FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00455           FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00456         }
00457 
00458     }
00459 
00460   close(fd);
00461   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);
00462 
00463 }