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_convert.h"
00039 #include <sys/types.h>
00040 #include <unistd.h>
00041 #include <utime.h>
00042 #include <sys/time.h>
00043 
00044 extern fsal_status_t gpfsfsal_xstat_2_fsal_attributes(gpfsfsal_xstat_t *p_buffxstat,
00045                                                       fsal_attrib_list_t *p_fsalattr_out);
00046 
00047 #ifdef _USE_NFS4_ACL
00048 extern fsal_status_t fsal_acl_2_gpfs_acl(fsal_acl_t *p_fsalacl, gpfsfsal_xstat_t *p_buffxstat);
00049 #endif                          /* _USE_NFS4_ACL */
00050 
00070 fsal_status_t GPFSFSAL_getattrs(fsal_handle_t * p_filehandle,       /* IN */
00071                             fsal_op_context_t * p_context,      /* IN */
00072                             fsal_attrib_list_t * p_object_attributes    /* IN/OUT */
00073     )
00074 {
00075   fsal_status_t st;
00076   gpfsfsal_xstat_t buffxstat;
00077 
00078 #ifdef _USE_NFS4_ACL
00079   fsal_accessflags_t access_mask = 0;
00080 #endif
00081 
00082   /* sanity checks.
00083    * note : object_attributes is mandatory in GPFSFSAL_getattrs.
00084    */
00085   if(!p_filehandle || !p_context || !p_object_attributes)
00086     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs);
00087 
00088   TakeTokenFSCall();
00089   st = fsal_get_xstat_by_handle(p_context,
00090                            p_filehandle,
00091                                 &buffxstat);
00092   ReleaseTokenFSCall();
00093 
00094   if(FSAL_IS_ERROR(st))
00095     ReturnStatus(st, INDEX_FSAL_getattrs);
00096 
00097   /* convert attributes */
00098   st = gpfsfsal_xstat_2_fsal_attributes(&buffxstat, p_object_attributes);
00099   if(FSAL_IS_ERROR(st))
00100     {
00101       FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00102       FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00103       ReturnStatus(st, INDEX_FSAL_getattrs);
00104     }
00105 
00106 #ifdef _USE_NFS4_ACL
00107       /* Check permission to get attributes and ACL. */
00108       access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy */
00109                     FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_READ_ATTR |
00110                                        FSAL_ACE_PERM_READ_ACL);
00111     
00112     if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
00113       st = fsal_internal_testAccess(p_context, access_mask, NULL, p_object_attributes);
00114     else
00115       st = fsal_internal_access(p_context, p_filehandle, access_mask,
00116                                 p_object_attributes);
00117 
00118       if(FSAL_IS_ERROR(st))
00119         ReturnStatus(st, INDEX_FSAL_getattrs);
00120 #endif
00121 
00122   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs);
00123 
00124 }
00125 
00147 fsal_status_t GPFSFSAL_getattrs_descriptor(fsal_file_t * p_file_descriptor,     /* IN */
00148                                            fsal_handle_t * p_filehandle,        /* IN */
00149                                            fsal_op_context_t * p_context,       /* IN */
00150                                            fsal_attrib_list_t * p_object_attributes /* IN/OUT */
00151     )
00152 {
00153   return GPFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);
00154 }
00155 
00180 fsal_status_t GPFSFSAL_setattrs(fsal_handle_t * p_filehandle,       /* IN */
00181                             fsal_op_context_t * p_context,      /* IN */
00182                             fsal_attrib_list_t * p_attrib_set,  /* IN */
00183                             fsal_attrib_list_t * p_object_attributes    /* [ IN/OUT ] */
00184     )
00185 {
00186   unsigned int i;
00187   fsal_status_t status;
00188 
00189   /* Buffer that will be passed to gpfs_ganesha API. */
00190   gpfsfsal_xstat_t buffxstat;
00191 
00192   /* Indicate if stat or acl or both should be changed. */
00193   int attr_valid = 0;
00194 
00195   /* Indiate which attribute in stat should be changed. */
00196   int attr_changed = 0;
00197 
00198   fsal_accessflags_t access_mask = 0;
00199   fsal_attrib_list_t wanted_attrs, current_attrs;
00200 
00201   /* sanity checks.
00202    * note : object_attributes is optional.
00203    */
00204   if(!p_filehandle || !p_context || !p_attrib_set)
00205     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);
00206 
00207   /* local copy of attributes */
00208   wanted_attrs = *p_attrib_set;
00209 
00210   /* It does not make sense to setattr on a symlink */
00211   /* if(p_filehandle->type == DT_LNK)
00212      return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set,
00213      p_object_attributes);
00214    */
00215   /* First, check that FSAL attributes changes are allowed. */
00216 
00217   /* Is it allowed to change times ? */
00218 
00219   if(!global_fs_info.cansettime)
00220     {
00221 
00222       if(wanted_attrs.asked_attributes
00223          & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME))
00224         {
00225           /* handled as an unsettable attribute. */
00226           Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs);
00227         }
00228     }
00229 
00230   /* apply umask, if mode attribute is to be changed */
00231   if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE))
00232     {
00233       wanted_attrs.mode &= (~global_fs_info.umask);
00234     }
00235 
00236   /* get current attributes */
00237   current_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
00238   status = GPFSFSAL_getattrs(p_filehandle, p_context, &current_attrs);
00239   if(FSAL_IS_ERROR(status))
00240     {
00241       FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00242       FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00243       ReturnStatus(status, INDEX_FSAL_setattrs);
00244     }
00245 
00246   /***********
00247    *  CHMOD  *
00248    ***********/
00249   if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE))
00250     {
00251 
00252       /* The POSIX chmod call don't affect the symlink object, but
00253        * the entry it points to. So we must ignore it.
00254        */
00255       if(current_attrs.type != FSAL_TYPE_LNK)
00256         {
00257 
00258               /* For modifying mode, user must be root or the owner */
00259               if((p_context->credential.user != 0)
00260                  && (p_context->credential.user != current_attrs.owner))
00261                 {
00262                   LogFullDebug(COMPONENT_FSAL,
00263                                "Permission denied for CHMOD opeartion: current owner=%d, credential=%d",
00264                                current_attrs.owner, p_context->credential.user);
00265                   Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00266                 }
00267 
00268 #ifdef _USE_NFS4_ACL
00269           /* Check permission using ACL. */
00270           access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy. */
00271                         FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);
00272 
00273           if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
00274             status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
00275           else
00276             status = fsal_internal_access(p_context, p_filehandle, access_mask,
00277                                           &current_attrs);
00278 
00279           if(FSAL_IS_ERROR(status))
00280             ReturnStatus(status, INDEX_FSAL_setattrs);
00281 #endif
00282     
00283             attr_valid |= XATTR_STAT;
00284             attr_changed |= XATTR_MODE;
00285     
00286             /* Fill wanted mode. */
00287             buffxstat.buffstat.st_mode = fsal2unix_mode(wanted_attrs.mode);
00288             LogDebug(COMPONENT_FSAL,
00289                      "current mode = %o, new mode = %o",
00290                      fsal2unix_mode(current_attrs.mode), buffxstat.buffstat.st_mode);
00291 
00292         }
00293 
00294     }
00295 
00296   /***********
00297    *  CHOWN  *
00298    ***********/
00299   /* Only root can change uid and A normal user must be in the group he wants to set */
00300   if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER))
00301     {
00302 
00303           /* For modifying owner, user must be root or current owner==wanted==client */
00304           if((p_context->credential.user != 0) &&
00305              ((p_context->credential.user != current_attrs.owner) ||
00306               (p_context->credential.user != wanted_attrs.owner)))
00307             {
00308               LogFullDebug(COMPONENT_FSAL,
00309                            "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d",
00310                            current_attrs.owner, p_context->credential.user, wanted_attrs.owner);
00311               Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00312             }
00313 
00314 #ifdef _USE_NFS4_ACL
00315           /* Check permission using ACL. */
00316           access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy. */
00317                         FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER);
00318 
00319         if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
00320           status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
00321         else
00322           status = fsal_internal_access(p_context, p_filehandle, access_mask,
00323                                         &current_attrs);
00324 
00325           if(FSAL_IS_ERROR(status))
00326             ReturnStatus(status, INDEX_FSAL_setattrs);
00327 #endif
00328 
00329         }
00330 
00331   if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP))
00332         {
00333 
00334           /* For modifying group, user must be root or current owner */
00335           if((p_context->credential.user != 0)
00336              && (p_context->credential.user != current_attrs.owner))
00337             {
00338               Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00339             }
00340     
00341           int in_grp = 0;
00342           /* set in_grp */
00343           if(p_context->credential.group == wanted_attrs.group)
00344             in_grp = 1;
00345           else
00346             for(i = 0; i < p_context->credential.nbgroups; i++)
00347               {
00348                 if((in_grp = (wanted_attrs.group == p_context->credential.alt_groups[i])))
00349                   break;
00350               }
00351     
00352           /* it must also be in target group */
00353           if(p_context->credential.user != 0 && !in_grp)
00354             {
00355               LogFullDebug(COMPONENT_FSAL,
00356                            "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d",
00357                            current_attrs.group, p_context->credential.group, wanted_attrs.group);
00358               Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00359             }
00360 
00361 #ifdef _USE_NFS4_ACL
00362       /* Check permission using ACL. */
00363       access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy. */
00364                     FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER);
00365 
00366       if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
00367         status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
00368       else
00369         status = fsal_internal_access(p_context, p_filehandle, access_mask,
00370                                       &current_attrs);
00371 
00372       if(FSAL_IS_ERROR(status))
00373         ReturnStatus(status, INDEX_FSAL_setattrs);
00374 #endif
00375 
00376     }
00377 
00378   if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
00379     {
00380       /*      LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)",
00381                         fsalpath.path, FSAL_TEST_MASK(wanted_attrs.asked_attributes,
00382                                                       FSAL_ATTR_OWNER) ? (int)wanted_attrs.owner
00383                         : -1, FSAL_TEST_MASK(wanted_attrs.asked_attributes,
00384                         FSAL_ATTR_GROUP) ? (int)wanted_attrs.group : -1);*/
00385 
00386       attr_valid |= XATTR_STAT;
00387       attr_changed |= FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER) ?
00388                       XATTR_UID : XATTR_GID;
00389 
00390       /* Fill wanted owner. */
00391       if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER))
00392         {
00393           buffxstat.buffstat.st_uid = (int)wanted_attrs.owner;
00394           LogDebug(COMPONENT_FSAL,
00395                    "current uid = %d, new uid = %d",
00396                    current_attrs.owner, buffxstat.buffstat.st_uid);
00397         }
00398 
00399       /* Fill wanted group. */
00400       if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP))
00401         {
00402           buffxstat.buffstat.st_gid = (int)wanted_attrs.group;
00403           LogDebug(COMPONENT_FSAL,
00404                    "current gid = %d, new gid = %d",
00405                    current_attrs.group, buffxstat.buffstat.st_gid);
00406         }
00407 
00408     }
00409 
00410   /***********
00411    *  UTIME  *
00412    ***********/
00413 
00414   /* user must be the owner or have read access to modify 'atime' */
00415   access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK) |
00416                 FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);
00417 
00418   if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
00419     status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
00420   else
00421     status = fsal_internal_access(p_context, p_filehandle, access_mask,
00422                                   &current_attrs);
00423 
00424   if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME)
00425      && (p_context->credential.user != 0)
00426      && (p_context->credential.user != current_attrs.owner)
00427      && (status.major
00428          != ERR_FSAL_NO_ERROR))
00429     {
00430       ReturnStatus(status, INDEX_FSAL_setattrs);
00431     }
00432   /* user must be the owner or have write access to modify 'mtime' */
00433   access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) |
00434                 FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);
00435 
00436   if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
00437     status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
00438   else
00439     status = fsal_internal_access(p_context, p_filehandle, access_mask,
00440                                   &current_attrs);
00441 
00442   if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME)
00443      && (p_context->credential.user != 0)
00444      && (p_context->credential.user != current_attrs.owner)
00445      && (status.major
00446          != ERR_FSAL_NO_ERROR))
00447     {
00448       ReturnStatus(status, INDEX_FSAL_setattrs);
00449     }
00450 
00451   if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME))
00452     {
00453       attr_valid |= XATTR_STAT;
00454 
00455       /* Fill wanted atime. */
00456       if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME))
00457         {
00458           attr_changed |= XATTR_ATIME;
00459           buffxstat.buffstat.st_atime = (time_t) wanted_attrs.atime.seconds;
00460           LogDebug(COMPONENT_FSAL,
00461                    "current atime = %lu, new atime = %lu",
00462                    (unsigned long)current_attrs.atime.seconds, (unsigned long)buffxstat.buffstat.st_atime);
00463         }
00464 
00465       /* Fill wanted mtime. */
00466       if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME))
00467         {
00468           attr_changed |= XATTR_CTIME;
00469           buffxstat.buffstat.st_mtime = (time_t) wanted_attrs.mtime.seconds;
00470           LogDebug(COMPONENT_FSAL,
00471                    "current mtime = %lu, new mtime = %lu",
00472                    (unsigned long)current_attrs.mtime.seconds, (unsigned long)buffxstat.buffstat.st_mtime);
00473         }
00474     }
00475 
00476 #ifdef _USE_NFS4_ACL
00477    /***********
00478    *  ACL  *
00479    ***********/
00480 
00481   if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ACL))
00482     {
00483       /* Check permission to set ACL. */
00484       access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy */
00485                     FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ACL);
00486 
00487       if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
00488       status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
00489       else
00490         status = fsal_internal_access(p_context, p_filehandle, access_mask,
00491                                       &current_attrs);
00492 
00493       if(FSAL_IS_ERROR(status))
00494         ReturnStatus(status, INDEX_FSAL_setattrs);
00495 
00496       if(wanted_attrs.acl)
00497         {
00498           attr_valid |= XATTR_ACL;
00499           LogDebug(COMPONENT_FSAL, "setattr acl = %p", wanted_attrs.acl);
00500 
00501           /* Convert FSAL ACL to GPFS NFS4 ACL and fill the buffer. */
00502           status = fsal_acl_2_gpfs_acl(wanted_attrs.acl, &buffxstat);
00503 
00504           if(FSAL_IS_ERROR(status))
00505             ReturnStatus(status, INDEX_FSAL_setattrs);
00506         }
00507       else
00508         {
00509           LogCrit(COMPONENT_FSAL, "setattr acl is NULL");
00510           Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);
00511         }
00512     }
00513 #endif                          /* _USE_NFS4_ACL */
00514 
00515   /* If there is any change in stat or acl or both, send it down to file system. */
00516   if((attr_valid == XATTR_STAT && attr_changed !=0) || attr_valid == XATTR_ACL)
00517     {
00518       status = fsal_set_xstat_by_handle(p_context,
00519                                         p_filehandle,
00520                                         attr_valid,
00521                                         attr_changed,
00522                                         &buffxstat);
00523 
00524       if(FSAL_IS_ERROR(status))
00525         ReturnStatus(status, INDEX_FSAL_setattrs);
00526     }
00527 
00528   /* Optionaly fills output attributes. */
00529 
00530   if(p_object_attributes)
00531     {
00532       status = GPFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);
00533 
00534       /* on error, we set a special bit in the mask. */
00535       if(FSAL_IS_ERROR(status))
00536         {
00537           FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00538           FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00539         }
00540 
00541     }
00542 
00543   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);
00544 
00545 }