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 <inttypes.h>
00044 
00045 #define MAX_2( x, y )    ( (x) > (y) ? (x) : (y) )
00046 
00047 static fsal_status_t
00048 bulkstat_by_inode(fsal_op_context_t * context, ino_t inum, fsal_attrib_list_t * p_fsalattr_out)
00049 {
00050   xfsfsal_op_context_t * p_context = (xfsfsal_op_context_t *)context;
00051   xfs_bstat_t stat;
00052   struct stat sb;
00053   int fd = 0;
00054   int errsv, rc;
00055 
00056   if((fd = open(p_context->export_context->mount_point, O_DIRECTORY)) == -1)
00057     ReturnCode(posix2fsal_error(errno), errno);
00058 
00059   rc = fsal_internal_get_bulkstat_by_inode(fd, &inum, &stat);
00060   errsv = errno;
00061   close(fd);
00062 
00063   if(rc < 0)
00064     ReturnCode(posix2fsal_error(errsv), errsv);
00065 
00066   memset(&sb, 0, sizeof(sb));
00067   sb.st_mode = stat.bs_mode;
00068   sb.st_size = stat.bs_size;
00069   sb.st_dev = context->export_context->dev_id;
00070   sb.st_ino = stat.bs_ino;
00071   sb.st_nlink = stat.bs_nlink;
00072   sb.st_uid = stat.bs_uid;
00073   sb.st_gid = stat.bs_gid;
00074   sb.st_atim.tv_sec = stat.bs_atime.tv_sec;
00075   sb.st_atim.tv_nsec = stat.bs_atime.tv_nsec;
00076   sb.st_ctim.tv_sec = stat.bs_ctime.tv_sec;
00077   sb.st_ctim.tv_nsec = stat.bs_ctime.tv_nsec;
00078   sb.st_mtim.tv_sec = stat.bs_mtime.tv_sec;
00079   sb.st_mtim.tv_nsec = stat.bs_mtime.tv_nsec;
00080   sb.st_blocks = stat.bs_blocks;
00081   sb.st_blksize = stat.bs_blksize;
00082   sb.st_rdev = stat.bs_rdev;
00083 
00084   return posix2fsal_attributes(&sb, p_fsalattr_out);
00085 }
00086 
00106 fsal_status_t XFSFSAL_getattrs(fsal_handle_t * p_filehandle, /* IN */
00107                                fsal_op_context_t * p_context,        /* IN */
00108                                fsal_attrib_list_t * p_object_attributes /* IN/OUT */
00109     )
00110 {
00111   int rc, errsv;
00112   fsal_status_t st;
00113   int fd;
00114   struct stat buffstat;
00115   xfsfsal_handle_t *xh = (xfsfsal_handle_t *)p_filehandle;
00116 
00117   /* sanity checks.
00118    * note : object_attributes is mandatory in FSAL_getattrs.
00119    */
00120   if(!p_filehandle || !p_context || !p_object_attributes)
00121     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs);
00122 
00123   switch(xh->data.type)
00124     {
00125     case DT_LNK:
00126     case DT_BLK:
00127     case DT_SOCK:
00128     case DT_CHR:
00129     case DT_FIFO:
00130       TakeTokenFSCall();
00131       st = bulkstat_by_inode(p_context, xh->data.inode, p_object_attributes);
00132       ReleaseTokenFSCall();
00133       break;
00134 
00135     case DT_REG:
00136     case DT_DIR:
00137       TakeTokenFSCall();
00138       st = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY);
00139       ReleaseTokenFSCall();
00140 
00141       if(FSAL_IS_ERROR(st))
00142         ReturnStatus(st, INDEX_FSAL_getattrs);
00143 
00144       /* get file metadata */
00145       TakeTokenFSCall();
00146       rc = fstat(fd, &buffstat);
00147       errsv = errno;
00148       ReleaseTokenFSCall();
00149 
00150       close(fd);
00151 
00152       if(rc != 0)
00153         {
00154           if(errsv == ENOENT)
00155             Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_getattrs);
00156           else
00157             Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_getattrs);
00158         }
00159 
00160       /* convert attributes */
00161       st = posix2fsal_attributes(&buffstat, p_object_attributes);
00162       break;
00163 
00164     default:
00165         LogEvent(COMPONENT_FSAL,
00166                  "Corrupted filehandle - unexpected file type %d",
00167                  xh->data.type);
00168         Return(ERR_FSAL_BADHANDLE, EINVAL, INDEX_FSAL_getattrs);
00169     }
00170   if(FSAL_IS_ERROR(st))
00171     {
00172       FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00173       FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00174       ReturnStatus(st, INDEX_FSAL_getattrs);
00175     }
00176 
00177   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs);
00178 
00179 }
00180 
00205 fsal_status_t XFSFSAL_setattrs(fsal_handle_t * p_filehandle, /* IN */
00206                                fsal_op_context_t * p_context,        /* IN */
00207                                fsal_attrib_list_t * p_attrib_set,       /* IN */
00208                                fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */
00209     )
00210 {
00211 
00212   int rc, errsv;
00213   unsigned int i;
00214   fsal_status_t status;
00215   fsal_attrib_list_t attrs;
00216 
00217   int fd;
00218   struct stat buffstat;
00219   uid_t userid = ((xfsfsal_op_context_t *)p_context)->credential.user;
00220   gid_t groupid = ((xfsfsal_op_context_t *)p_context)->credential.group;
00221 
00222   /* sanity checks.
00223    * note : object_attributes is optional.
00224    */
00225   if(!p_filehandle || !p_context || !p_attrib_set)
00226     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);
00227 
00228   /* local copy of attributes */
00229   attrs = *p_attrib_set;
00230 
00231   /* It does not make sense to setattr on a symlink */
00232   if(((xfsfsal_handle_t *)p_filehandle)->data.type == DT_LNK)
00233     return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set,
00234                                           p_object_attributes);
00235 
00236   /* First, check that FSAL attributes changes are allowed. */
00237 
00238   /* Is it allowed to change times ? */
00239 
00240   if(!global_fs_info.cansettime)
00241     {
00242 
00243       if(attrs.asked_attributes
00244          & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME))
00245         {
00246           /* handled as an unsettable attribute. */
00247           Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs);
00248         }
00249     }
00250 
00251   /* apply umask, if mode attribute is to be changed */
00252   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
00253     {
00254       attrs.mode &= (~global_fs_info.umask);
00255     }
00256 
00257   TakeTokenFSCall();
00258   status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDWR);
00259   ReleaseTokenFSCall();
00260   if(FSAL_IS_ERROR(status))
00261     ReturnStatus(status, INDEX_FSAL_setattrs);
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((userid != 0)
00293              && (userid != buffstat.st_uid))
00294             {
00295 
00296               LogFullDebug(COMPONENT_FSAL, 
00297                                 "Permission denied for CHMOD opeartion: current owner=%d, credential=%d",
00298                                 buffstat.st_uid, userid);
00299 
00300               close(fd);
00301               Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00302             }
00303 
00304           TakeTokenFSCall();
00305           rc = fchmod(fd, fsal2unix_mode(attrs.mode));
00306           errsv = errno;
00307 
00308           ReleaseTokenFSCall();
00309 
00310           if(rc)
00311             {
00312               close(fd);
00313               Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs);
00314             }
00315 
00316         }
00317 
00318     }
00319 
00320   /***********
00321    *  CHOWN  *
00322    ***********/
00323   /* Only root can change uid and A normal user must be in the group he wants to set */
00324   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER))
00325     {
00326 
00327       /* For modifying owner, user must be root or current owner==wanted==client */
00328       if((userid != 0) &&
00329          ((userid != buffstat.st_uid) ||
00330           (userid != attrs.owner)))
00331         {
00332 
00333           LogFullDebug(COMPONENT_FSAL,
00334                             "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d",
00335                             buffstat.st_uid, userid, attrs.owner);
00336 
00337           close(fd);
00338           Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00339         }
00340     }
00341 
00342   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP))
00343     {
00344 
00345       /* For modifying group, user must be root or current owner */
00346       if((userid != 0)
00347          && (userid != buffstat.st_uid))
00348         {
00349           close(fd);
00350           Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00351         }
00352 
00353       int in_grp = 0;
00354       /* set in_grp */
00355       if(groupid == attrs.group)
00356         in_grp = 1;
00357       else
00358         for(i = 0; i < ((xfsfsal_op_context_t *)p_context)->credential.nbgroups; i++)
00359           {
00360             if((in_grp = (attrs.group == ((xfsfsal_op_context_t *)p_context)->credential.alt_groups[i])))
00361               break;
00362           }
00363 
00364       /* it must also be in target group */
00365       if(userid != 0 && !in_grp)
00366         {
00367 
00368           LogFullDebug(COMPONENT_FSAL,
00369                             "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d",
00370                             buffstat.st_gid, groupid, attrs.group);
00371 
00372           close(fd);
00373           Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
00374         }
00375     }
00376 
00377   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
00378     {
00379 
00380       LogFullDebug(COMPONENT_FSAL, "Performing chown(inode=%"PRIu64", %d,%d)",
00381                         buffstat.st_ino, FSAL_TEST_MASK(attrs.asked_attributes,
00382                                                       FSAL_ATTR_OWNER) ? (int)attrs.owner
00383                         : -1, FSAL_TEST_MASK(attrs.asked_attributes,
00384                                              FSAL_ATTR_GROUP) ? (int)attrs.group : -1);
00385 
00386 
00387       TakeTokenFSCall();
00388       rc = fchown(fd,
00389                   FSAL_TEST_MASK(attrs.asked_attributes,
00390                                  FSAL_ATTR_OWNER) ? (int)attrs.owner : -1,
00391                   FSAL_TEST_MASK(attrs.asked_attributes,
00392                                  FSAL_ATTR_GROUP) ? (int)attrs.group : -1);
00393       ReleaseTokenFSCall();
00394       if(rc)
00395         {
00396           close(fd);
00397           Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);
00398         }
00399     }
00400 
00401   /***********
00402    *  UTIME  *
00403    ***********/
00404 
00405   /* user must be the owner or have read access to modify 'atime' */
00406   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME)
00407      && (userid != 0)
00408      && (userid != buffstat.st_uid)
00409      && ((status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL)).major
00410          != ERR_FSAL_NO_ERROR))
00411     {
00412       close(fd);
00413       ReturnStatus(status, INDEX_FSAL_setattrs);
00414     }
00415   /* user must be the owner or have write access to modify 'mtime' */
00416   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME)
00417      && (userid != 0)
00418      && (userid != buffstat.st_uid)
00419      && ((status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL)).major
00420          != ERR_FSAL_NO_ERROR))
00421     {
00422       close(fd);
00423       ReturnStatus(status, INDEX_FSAL_setattrs);
00424     }
00425 
00426   if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME))
00427     {
00428 
00429       struct timeval timebuf[2];
00430 
00431       /* Atime */
00432       timebuf[0].tv_sec =
00433           (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs.
00434            atime.seconds : buffstat.st_atime);
00435       timebuf[0].tv_usec = 0;
00436 
00437       /* Mtime */
00438       timebuf[1].tv_sec =
00439           (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs.
00440            mtime.seconds : buffstat.st_mtime);
00441       timebuf[1].tv_usec = 0;
00442 
00443       TakeTokenFSCall();
00444       rc = futimes(fd, timebuf);
00445       errsv = errno;
00446       ReleaseTokenFSCall();
00447       if(rc)
00448         {
00449           close(fd);
00450           Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);
00451         }
00452     }
00453 
00454   /* Optionaly fills output attributes. */
00455 
00456   if(p_object_attributes)
00457     {
00458       status = XFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);
00459 
00460       /* on error, we set a special bit in the mask. */
00461       if(FSAL_IS_ERROR(status))
00462         {
00463           close(fd);
00464           FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
00465           FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
00466         }
00467 
00468     }
00469 
00470   close(fd);
00471   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);
00472 
00473 }
00474 
00494 fsal_status_t XFSFSAL_getextattrs(fsal_handle_t * p_filehandle, /* IN */
00495                                   fsal_op_context_t * p_context,        /* IN */
00496                                   fsal_extattrib_list_t * p_object_attributes /* OUT */
00497     )
00498 {
00499   fsal_status_t st ;
00500   xfs_bstat_t bstat;
00501   xfs_ino_t xfs_ino;
00502   int fd = 0 ;
00503 
00504   /* sanity checks.
00505    * note : object_attributes is mandatory in FSAL_getattrs.
00506    */
00507   if(!p_filehandle || !p_context || !p_object_attributes)
00508     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs);
00509 
00510   TakeTokenFSCall();
00511   st = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY);
00512   ReleaseTokenFSCall();
00513 
00514   if(FSAL_IS_ERROR(st))
00515     ReturnStatus(st, INDEX_FSAL_getextattrs);
00516 
00517   if( p_object_attributes->asked_attributes & FSAL_ATTR_GENERATION )
00518    {
00519      /* get file metadata */
00520      xfs_ino = ((xfsfsal_handle_t *)p_filehandle)->data.inode ;
00521      TakeTokenFSCall();
00522      if(fsal_internal_get_bulkstat_by_inode(fd, &xfs_ino, &bstat) < 0)
00523       {
00524         close(fd);
00525         ReleaseTokenFSCall();
00526         ReturnCode(posix2fsal_error(errno), errno);
00527       }
00528      ReleaseTokenFSCall();
00529 
00530      p_object_attributes->generation = bstat.bs_gen ;
00531     }
00532  
00533   Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getextattrs);
00534 } /* XFSFSAL_getextattrs */