LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - pvfs_sys.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 38 331 11.5 %
Date: 2024-02-28 12:06:22 Functions: 7 13 53.8 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    POSIX NTVFS backend - pvfs_sys wrappers
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2010
       7             :    Copyright (C) Andrew Bartlett 2010
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "vfs_posix.h"
      25             : #include "../lib/util/unix_privs.h"
      26             : 
      27             : /*
      28             :   these wrapper functions must only be called when the appropriate ACL
      29             :   has already been checked. The wrappers will override a EACCES result
      30             :   by gaining root privileges if the 'pvfs:perm override' is set on the
      31             :   share (it is enabled by default)
      32             : 
      33             :   Careful use of O_NOFOLLOW and O_DIRECTORY is used to prevent
      34             :   security attacks via symlinks
      35             :  */
      36             : 
      37             : 
      38             : struct pvfs_sys_ctx {
      39             :         struct pvfs_state *pvfs;
      40             :         void *privs;
      41             :         const char *old_wd;
      42             :         struct stat st_orig;
      43             : };
      44             : 
      45             : 
      46             : /*
      47             :   we create PVFS_NOFOLLOW and PVFS_DIRECTORY as aliases for O_NOFOLLOW
      48             :   and O_DIRECTORY on systems that have them. On systems that don't
      49             :   have O_NOFOLLOW we are less safe, but the root override code is off
      50             :   by default.
      51             :  */
      52             : #ifdef O_NOFOLLOW
      53             : #define PVFS_NOFOLLOW O_NOFOLLOW
      54             : #else
      55             : #define PVFS_NOFOLLOW 0
      56             : #endif
      57             : #ifdef O_DIRECTORY
      58             : #define PVFS_DIRECTORY O_DIRECTORY
      59             : #else
      60             : #define PVFS_DIRECTORY 0
      61             : #endif
      62             : 
      63             : /*
      64             :   return to original directory when context is destroyed
      65             :  */
      66           0 : static int pvfs_sys_pushdir_destructor(struct pvfs_sys_ctx *ctx)
      67             : {
      68           0 :         struct stat st;
      69             : 
      70           0 :         if (ctx->old_wd == NULL) {
      71           0 :                 return 0;
      72             :         }
      73             : 
      74           0 :         if (chdir(ctx->old_wd) != 0) {
      75           0 :                 smb_panic("Failed to restore working directory");
      76             :         }
      77           0 :         if (stat(".", &st) != 0) {
      78           0 :                 smb_panic("Failed to stat working directory");
      79             :         }
      80           0 :         if (st.st_ino != ctx->st_orig.st_ino ||
      81           0 :             st.st_dev != ctx->st_orig.st_dev) {
      82           0 :                 smb_panic("Working directory changed during call");
      83             :         }
      84             : 
      85           0 :         return 0;
      86             : }
      87             : 
      88             : 
      89             : /*
      90             :   chdir() to the directory part of a pathname, but disallow any
      91             :   component with a symlink
      92             : 
      93             :   Note that we can't use O_NOFOLLOW on the whole path as that only
      94             :   prevents links in the final component of the path
      95             :  */
      96           0 : static int pvfs_sys_chdir_nosymlink(struct pvfs_sys_ctx *ctx, const char *pathname)
      97             : {
      98           0 :         char *p, *path;
      99           0 :         size_t base_len = strlen(ctx->pvfs->base_directory);
     100             : 
     101             :         /* don't check for symlinks in the base directory of the share */
     102           0 :         if (strncmp(ctx->pvfs->base_directory, pathname, base_len) == 0 &&
     103           0 :             pathname[base_len] == '/') {
     104           0 :                 if (chdir(ctx->pvfs->base_directory) != 0) {
     105           0 :                         return -1;
     106             :                 }
     107           0 :                 pathname += base_len + 1;
     108             :         }
     109             : 
     110           0 :         path = talloc_strdup(ctx, pathname);
     111           0 :         if (path == NULL) {
     112           0 :                 return -1;
     113             :         }
     114           0 :         while ((p = strchr(path, '/'))) {
     115           0 :                 int fd;
     116           0 :                 struct stat st1, st2;
     117           0 :                 *p = 0;
     118           0 :                 fd = open(path, PVFS_NOFOLLOW | PVFS_DIRECTORY | O_RDONLY);
     119           0 :                 if (fd == -1) {
     120           0 :                         return -1;
     121             :                 }
     122           0 :                 if (chdir(path) != 0) {
     123           0 :                         close(fd);
     124           0 :                         return -1;
     125             :                 }
     126           0 :                 if (stat(".", &st1) != 0 ||
     127           0 :                     fstat(fd, &st2) != 0) {
     128           0 :                         close(fd);
     129           0 :                         return -1;
     130             :                 }
     131           0 :                 close(fd);
     132           0 :                 if (st1.st_ino != st2.st_ino ||
     133           0 :                     st1.st_dev != st2.st_dev) {
     134           0 :                         DEBUG(0,(__location__ ": Inode changed during chdir in '%s' - symlink attack?\n",
     135             :                                  pathname));
     136           0 :                         return -1;
     137             :                 }
     138           0 :                 path = p + 1;
     139             :         }
     140             : 
     141           0 :         return 0;
     142             : }
     143             : 
     144             : 
     145             : /*
     146             :   become root, and change directory to the directory component of a
     147             :   path. Return a talloc context which when freed will move us back
     148             :   to the original directory, and return us to the original uid
     149             : 
     150             :   change the pathname argument to contain just the base component of
     151             :   the path
     152             : 
     153             :   return NULL on error, which could include an attempt to subvert
     154             :   security using symlink tricks
     155             :  */
     156           0 : static struct pvfs_sys_ctx *pvfs_sys_pushdir(struct pvfs_state *pvfs,
     157             :                                              const char **pathname)
     158             : {
     159           0 :         struct pvfs_sys_ctx *ctx;
     160           0 :         char *cwd, *p, *dirname;
     161           0 :         int ret;
     162             : 
     163           0 :         ctx = talloc_zero(pvfs, struct pvfs_sys_ctx);
     164           0 :         if (ctx == NULL) {
     165           0 :                 return NULL;
     166             :         }
     167           0 :         ctx->pvfs = pvfs;
     168           0 :         ctx->privs = root_privileges();
     169           0 :         if (ctx->privs == NULL) {
     170           0 :                 talloc_free(ctx);
     171           0 :                 return NULL;
     172             :         }
     173             : 
     174           0 :         talloc_steal(ctx, ctx->privs);
     175             : 
     176           0 :         if (!pathname) {
     177             :                 /* no pathname needed */
     178           0 :                 return ctx;
     179             :         }
     180             : 
     181           0 :         p = strrchr(*pathname, '/');
     182           0 :         if (p == NULL) {
     183             :                 /* we don't need to change directory */
     184           0 :                 return ctx;
     185             :         }
     186             : 
     187             :         /* we keep the old st around, so we can tell that
     188             :            we have come back to the right directory */
     189           0 :         if (stat(".", &ctx->st_orig) != 0) {
     190           0 :                 talloc_free(ctx);
     191           0 :                 return NULL;
     192             :         }
     193             : 
     194           0 :         cwd = get_current_dir_name();
     195           0 :         if (cwd == NULL) {
     196           0 :                 talloc_free(ctx);
     197           0 :                 return NULL;
     198             :         }
     199             : 
     200           0 :         ctx->old_wd = talloc_strdup(ctx, cwd);
     201           0 :         free(cwd);
     202             : 
     203           0 :         if (ctx->old_wd == NULL) {
     204           0 :                 talloc_free(ctx);
     205           0 :                 return NULL;
     206             :         }
     207             : 
     208           0 :         dirname = talloc_strndup(ctx, *pathname, (p - *pathname));
     209           0 :         if (dirname == NULL) {
     210           0 :                 talloc_free(ctx);
     211           0 :                 return NULL;
     212             :         }
     213             : 
     214           0 :         ret = pvfs_sys_chdir_nosymlink(ctx, *pathname);
     215           0 :         if (ret == -1) {
     216           0 :                 talloc_free(ctx);
     217           0 :                 return NULL;
     218             :         }
     219             : 
     220           0 :         talloc_set_destructor(ctx, pvfs_sys_pushdir_destructor);
     221             : 
     222             :         /* return the basename as the filename that should be operated on */
     223           0 :         (*pathname) = talloc_strdup(ctx, p+1);
     224           0 :         if (! *pathname) {
     225           0 :                 talloc_free(ctx);
     226           0 :                 return NULL;
     227             :         }
     228             : 
     229           0 :         return ctx;
     230             : }
     231             : 
     232             : 
     233             : /*
     234             :   chown a file that we created with a root privileges override
     235             :  */
     236           0 : static int pvfs_sys_fchown(struct pvfs_state *pvfs, struct pvfs_sys_ctx *ctx, int fd)
     237             : {
     238           0 :         return fchown(fd, root_privileges_original_uid(ctx->privs), -1);
     239             : }
     240             : 
     241             : /*
     242             :   chown a directory that we created with a root privileges override
     243             :  */
     244           0 : static int pvfs_sys_chown(struct pvfs_state *pvfs, struct pvfs_sys_ctx *ctx, const char *name)
     245             : {
     246             :         /* to avoid symlink hacks, we need to use fchown() on a directory fd */
     247           0 :         int ret, fd;
     248           0 :         fd = open(name, PVFS_DIRECTORY | PVFS_NOFOLLOW | O_RDONLY);
     249           0 :         if (fd == -1) {
     250           0 :                 return -1;
     251             :         }
     252           0 :         ret = pvfs_sys_fchown(pvfs, ctx, fd);
     253           0 :         close(fd);
     254           0 :         return ret;
     255             : }
     256             : 
     257             : 
     258             : /*
     259             :   wrap open for system override
     260             : */
     261      186184 : int pvfs_sys_open(struct pvfs_state *pvfs, const char *filename, int flags, mode_t mode, bool allow_override)
     262             : {
     263           0 :         int fd, ret;
     264           0 :         struct pvfs_sys_ctx *ctx;
     265           0 :         int saved_errno, orig_errno;
     266      186184 :         int retries = 5;
     267             : 
     268      186184 :         orig_errno = errno;
     269             : 
     270      186184 :         fd = open(filename, flags, mode);
     271      186184 :         if (fd != -1 ||
     272           0 :             !allow_override ||
     273           0 :             errno != EACCES) {
     274      186184 :                 return fd;
     275             :         }
     276             : 
     277           0 :         saved_errno = errno;
     278           0 :         ctx = pvfs_sys_pushdir(pvfs, &filename);
     279           0 :         if (ctx == NULL) {
     280           0 :                 errno = saved_errno;
     281           0 :                 return -1;
     282             :         }
     283             : 
     284             :         /* don't allow permission overrides to follow links */
     285           0 :         flags |= PVFS_NOFOLLOW;
     286             : 
     287             :         /*
     288             :            if O_CREAT was specified and O_EXCL was not specified
     289             :            then initially do the open without O_CREAT, as in that case
     290             :            we know that we did not create the file, so we don't have
     291             :            to fchown it
     292             :          */
     293           0 :         if ((flags & O_CREAT) && !(flags & O_EXCL)) {
     294           0 :         try_again:
     295           0 :                 fd = open(filename, flags & ~O_CREAT, mode);
     296             :                 /* if this open succeeded, or if it failed
     297             :                    with anything other than ENOENT, then we return the
     298             :                    open result, with the original errno */
     299           0 :                 if (fd == -1 && errno != ENOENT) {
     300           0 :                         talloc_free(ctx);
     301           0 :                         errno = saved_errno;
     302           0 :                         return -1;
     303             :                 }
     304           0 :                 if (fd != -1) {
     305             :                         /* the file already existed and we opened it */
     306           0 :                         talloc_free(ctx);
     307           0 :                         errno = orig_errno;
     308           0 :                         return fd;
     309             :                 }
     310             : 
     311           0 :                 fd = open(filename, flags | O_EXCL, mode);
     312           0 :                 if (fd == -1 && errno != EEXIST) {
     313           0 :                         talloc_free(ctx);
     314           0 :                         errno = saved_errno;
     315           0 :                         return -1;
     316             :                 }
     317           0 :                 if (fd != -1) {
     318             :                         /* we created the file, we need to set the
     319             :                            right ownership on it */
     320           0 :                         ret = pvfs_sys_fchown(pvfs, ctx, fd);
     321           0 :                         if (ret == -1) {
     322           0 :                                 close(fd);
     323           0 :                                 unlink(filename);
     324           0 :                                 talloc_free(ctx);
     325           0 :                                 errno = saved_errno;
     326           0 :                                 return -1;
     327             :                         }
     328           0 :                         talloc_free(ctx);
     329           0 :                         errno = orig_errno;
     330           0 :                         return fd;
     331             :                 }
     332             : 
     333             :                 /* the file got created between the two times
     334             :                    we tried to open it! Try again */
     335           0 :                 if (retries-- > 0) {
     336           0 :                         goto try_again;
     337             :                 }
     338             : 
     339           0 :                 talloc_free(ctx);
     340           0 :                 errno = saved_errno;
     341           0 :                 return -1;
     342             :         }
     343             : 
     344           0 :         fd = open(filename, flags, mode);
     345           0 :         if (fd == -1) {
     346           0 :                 talloc_free(ctx);
     347           0 :                 errno = saved_errno;
     348           0 :                 return -1;
     349             :         }
     350             : 
     351             :         /* if we have created a file then fchown it */
     352           0 :         if (flags & O_CREAT) {
     353           0 :                 ret = pvfs_sys_fchown(pvfs, ctx, fd);
     354           0 :                 if (ret == -1) {
     355           0 :                         close(fd);
     356           0 :                         unlink(filename);
     357           0 :                         talloc_free(ctx);
     358           0 :                         errno = saved_errno;
     359           0 :                         return -1;
     360             :                 }
     361             :         }
     362             : 
     363           0 :         talloc_free(ctx);
     364           0 :         return fd;
     365             : }
     366             : 
     367             : 
     368             : /*
     369             :   wrap unlink for system override
     370             : */
     371       96969 : int pvfs_sys_unlink(struct pvfs_state *pvfs, const char *filename, bool allow_override)
     372             : {
     373           0 :         int ret;
     374           0 :         struct pvfs_sys_ctx *ctx;
     375           0 :         int saved_errno, orig_errno;
     376             : 
     377       96969 :         orig_errno = errno;
     378             : 
     379       96969 :         ret = unlink(filename);
     380       96969 :         if (ret != -1 ||
     381           0 :             !allow_override ||
     382           0 :             errno != EACCES) {
     383       96969 :                 return ret;
     384             :         }
     385             : 
     386           0 :         saved_errno = errno;
     387             : 
     388           0 :         ctx = pvfs_sys_pushdir(pvfs, &filename);
     389           0 :         if (ctx == NULL) {
     390           0 :                 errno = saved_errno;
     391           0 :                 return -1;
     392             :         }
     393             : 
     394           0 :         ret = unlink(filename);
     395           0 :         if (ret == -1) {
     396           0 :                 talloc_free(ctx);
     397           0 :                 errno = saved_errno;
     398           0 :                 return -1;
     399             :         }
     400             : 
     401           0 :         talloc_free(ctx);
     402           0 :         errno = orig_errno;
     403           0 :         return ret;
     404             : }
     405             : 
     406             : 
     407           0 : static bool contains_symlink(const char *path)
     408             : {
     409           0 :         int fd = open(path, PVFS_NOFOLLOW | O_RDONLY);
     410           0 :         int posix_errno = errno;
     411           0 :         if (fd != -1) {
     412           0 :                 close(fd);
     413           0 :                 return false;
     414             :         }
     415             : 
     416             : #if defined(ENOTSUP) && defined(OSF1)
     417             :         /* handle special Tru64 errno */
     418             :         if (errno == ENOTSUP) {
     419             :                 posix_errno = ELOOP;
     420             :         }
     421             : #endif /* ENOTSUP */
     422             : 
     423             : #ifdef EFTYPE
     424             :         /* fix broken NetBSD errno */
     425             :         if (errno == EFTYPE) {
     426             :                 posix_errno = ELOOP;
     427             :         }
     428             : #endif /* EFTYPE */
     429             : 
     430             :         /* fix broken FreeBSD errno */
     431           0 :         if (errno == EMLINK) {
     432           0 :                 posix_errno = ELOOP;
     433             :         }
     434             : 
     435           0 :         return (posix_errno == ELOOP);
     436             : }
     437             : 
     438             : /*
     439             :   wrap rename for system override
     440             : */
     441         116 : int pvfs_sys_rename(struct pvfs_state *pvfs, const char *name1, const char *name2, bool allow_override)
     442             : {
     443           0 :         int ret;
     444           0 :         struct pvfs_sys_ctx *ctx;
     445           0 :         int saved_errno, orig_errno;
     446             : 
     447         116 :         orig_errno = errno;
     448             : 
     449         116 :         ret = rename(name1, name2);
     450         116 :         if (ret != -1 ||
     451           4 :             !allow_override ||
     452           0 :             errno != EACCES) {
     453         116 :                 return ret;
     454             :         }
     455             : 
     456           0 :         saved_errno = errno;
     457             : 
     458           0 :         ctx = pvfs_sys_pushdir(pvfs, &name1);
     459           0 :         if (ctx == NULL) {
     460           0 :                 errno = saved_errno;
     461           0 :                 return -1;
     462             :         }
     463             : 
     464             :         /* we need the destination as an absolute path */
     465           0 :         if (name2[0] != '/') {
     466           0 :                 name2 = talloc_asprintf(ctx, "%s/%s", ctx->old_wd, name2);
     467           0 :                 if (name2 == NULL) {
     468           0 :                         talloc_free(ctx);
     469           0 :                         errno = saved_errno;
     470           0 :                         return -1;
     471             :                 }
     472             :         }
     473             : 
     474             :         /* make sure the destination isn't a symlink beforehand */
     475           0 :         if (contains_symlink(name2)) {
     476           0 :                 talloc_free(ctx);
     477           0 :                 errno = saved_errno;
     478           0 :                 return -1;
     479             :         }
     480             : 
     481           0 :         ret = rename(name1, name2);
     482           0 :         if (ret == -1) {
     483           0 :                 talloc_free(ctx);
     484           0 :                 errno = saved_errno;
     485           0 :                 return -1;
     486             :         }
     487             : 
     488             :         /* make sure the destination isn't a symlink afterwards */
     489           0 :         if (contains_symlink(name2)) {
     490           0 :                 DEBUG(0,(__location__ ": Possible symlink attack in rename to '%s' - unlinking\n", name2));
     491           0 :                 unlink(name2);
     492           0 :                 talloc_free(ctx);
     493           0 :                 errno = saved_errno;
     494           0 :                 return -1;
     495             :         }
     496             : 
     497           0 :         talloc_free(ctx);
     498           0 :         errno = orig_errno;
     499           0 :         return ret;
     500             : }
     501             : 
     502             : 
     503             : /*
     504             :   wrap mkdir for system override
     505             : */
     506        7252 : int pvfs_sys_mkdir(struct pvfs_state *pvfs, const char *dirname, mode_t mode, bool allow_override)
     507             : {
     508           0 :         int ret;
     509           0 :         struct pvfs_sys_ctx *ctx;
     510           0 :         int saved_errno, orig_errno;
     511             : 
     512        7252 :         orig_errno = errno;
     513             : 
     514        7252 :         ret = mkdir(dirname, mode);
     515        7252 :         if (ret != -1 ||
     516           0 :             !allow_override ||
     517           0 :             errno != EACCES) {
     518        7252 :                 return ret;
     519             :         }
     520             : 
     521           0 :         saved_errno = errno;
     522           0 :         ctx = pvfs_sys_pushdir(pvfs, &dirname);
     523           0 :         if (ctx == NULL) {
     524           0 :                 errno = saved_errno;
     525           0 :                 return -1;
     526             :         }
     527             : 
     528           0 :         ret = mkdir(dirname, mode);
     529           0 :         if (ret == -1) {
     530           0 :                 talloc_free(ctx);
     531           0 :                 errno = saved_errno;
     532           0 :                 return -1;
     533             :         }
     534             : 
     535           0 :         ret = pvfs_sys_chown(pvfs, ctx, dirname);
     536           0 :         if (ret == -1) {
     537           0 :                 rmdir(dirname);
     538           0 :                 talloc_free(ctx);
     539           0 :                 errno = saved_errno;
     540           0 :                 return -1;
     541             :         }
     542             : 
     543           0 :         talloc_free(ctx);
     544           0 :         errno = orig_errno;
     545           0 :         return ret;
     546             : }
     547             : 
     548             : 
     549             : /*
     550             :   wrap rmdir for system override
     551             : */
     552        7294 : int pvfs_sys_rmdir(struct pvfs_state *pvfs, const char *dirname, bool allow_override)
     553             : {
     554           0 :         int ret;
     555           0 :         struct pvfs_sys_ctx *ctx;
     556           0 :         int saved_errno, orig_errno;
     557             : 
     558        7294 :         orig_errno = errno;
     559             : 
     560        7294 :         ret = rmdir(dirname);
     561        7294 :         if (ret != -1 ||
     562          22 :             !allow_override ||
     563           0 :             errno != EACCES) {
     564        7294 :                 return ret;
     565             :         }
     566             : 
     567           0 :         saved_errno = errno;
     568             : 
     569           0 :         ctx = pvfs_sys_pushdir(pvfs, &dirname);
     570           0 :         if (ctx == NULL) {
     571           0 :                 errno = saved_errno;
     572           0 :                 return -1;
     573             :         }
     574             : 
     575           0 :         ret = rmdir(dirname);
     576           0 :         if (ret == -1) {
     577           0 :                 talloc_free(ctx);
     578           0 :                 errno = saved_errno;
     579           0 :                 return -1;
     580             :         }
     581             : 
     582           0 :         talloc_free(ctx);
     583           0 :         errno = orig_errno;
     584           0 :         return ret;
     585             : }
     586             : 
     587             : /*
     588             :   wrap fchmod for system override
     589             : */
     590         804 : int pvfs_sys_fchmod(struct pvfs_state *pvfs, int fd, mode_t mode, bool allow_override)
     591             : {
     592           0 :         int ret;
     593           0 :         struct pvfs_sys_ctx *ctx;
     594           0 :         int saved_errno, orig_errno;
     595             : 
     596         804 :         orig_errno = errno;
     597             : 
     598         804 :         ret = fchmod(fd, mode);
     599         804 :         if (ret != -1 ||
     600           0 :             !allow_override ||
     601           0 :             errno != EACCES) {
     602         804 :                 return ret;
     603             :         }
     604             : 
     605           0 :         saved_errno = errno;
     606             : 
     607           0 :         ctx = pvfs_sys_pushdir(pvfs, NULL);
     608           0 :         if (ctx == NULL) {
     609           0 :                 errno = saved_errno;
     610           0 :                 return -1;
     611             :         }
     612             : 
     613           0 :         ret = fchmod(fd, mode);
     614           0 :         if (ret == -1) {
     615           0 :                 talloc_free(ctx);
     616           0 :                 errno = saved_errno;
     617           0 :                 return -1;
     618             :         }
     619             : 
     620           0 :         talloc_free(ctx);
     621           0 :         errno = orig_errno;
     622           0 :         return ret;
     623             : }
     624             : 
     625             : 
     626             : /*
     627             :   wrap chmod for system override
     628             : */
     629         135 : int pvfs_sys_chmod(struct pvfs_state *pvfs, const char *filename, mode_t mode, bool allow_override)
     630             : {
     631           0 :         int ret;
     632           0 :         struct pvfs_sys_ctx *ctx;
     633           0 :         int saved_errno, orig_errno;
     634             : 
     635         135 :         orig_errno = errno;
     636             : 
     637         135 :         ret = chmod(filename, mode);
     638         135 :         if (ret != -1 ||
     639           0 :             !allow_override ||
     640           0 :             errno != EACCES) {
     641         135 :                 return ret;
     642             :         }
     643             : 
     644           0 :         saved_errno = errno;
     645             : 
     646           0 :         ctx = pvfs_sys_pushdir(pvfs, &filename);
     647           0 :         if (ctx == NULL) {
     648           0 :                 errno = saved_errno;
     649           0 :                 return -1;
     650             :         }
     651             : 
     652           0 :         ret = chmod(filename, mode);
     653           0 :         if (ret == -1) {
     654           0 :                 talloc_free(ctx);
     655           0 :                 errno = saved_errno;
     656           0 :                 return -1;
     657             :         }
     658             : 
     659           0 :         talloc_free(ctx);
     660           0 :         errno = orig_errno;
     661           0 :         return ret;
     662             : }

Generated by: LCOV version 1.14