LCOV - code coverage report
Current view: top level - tools - files.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 170 248 68.5 %
Date: 2012-11-29 Functions: 10 10 100.0 %
Branches: 86 522 16.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :     Authors:
       3                 :            :         Jakub Hrozek <jhrozek@redhat.com>
       4                 :            : 
       5                 :            :     Copyright (C) 2009 Red Hat
       6                 :            : 
       7                 :            :     This program is free software; you can redistribute it and/or modify
       8                 :            :     it under the terms of the GNU General Public License as published by
       9                 :            :     the Free Software Foundation; either version 3 of the License, or
      10                 :            :     (at your option) any later version.
      11                 :            : 
      12                 :            :     This program is distributed in the hope that it will be useful,
      13                 :            :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :     GNU General Public License for more details.
      16                 :            : 
      17                 :            :     You should have received a copy of the GNU General Public License
      18                 :            :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19                 :            : */
      20                 :            : 
      21                 :            : /*
      22                 :            :  * This file incorporates work covered by the following copyright and
      23                 :            :  * permission notice:
      24                 :            :  *
      25                 :            :  * Copyright (c) 1991 - 1994, Julianne Frances Haugh
      26                 :            :  * Copyright (c) 1996 - 2001, Marek Michałkiewicz
      27                 :            :  * Copyright (c) 2003 - 2006, Tomasz Kłoczko
      28                 :            :  * Copyright (c) 2007 - 2008, Nicolas François
      29                 :            :  *
      30                 :            :  * All rights reserved.
      31                 :            :  *
      32                 :            :  * Redistribution and use in source and binary forms, with or without
      33                 :            :  * modification, are permitted provided that the following conditions
      34                 :            :  * are met:
      35                 :            :  * 1. Redistributions of source code must retain the above copyright
      36                 :            :  *    notice, this list of conditions and the following disclaimer.
      37                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      38                 :            :  *    notice, this list of conditions and the following disclaimer in the
      39                 :            :  *    documentation and/or other materials provided with the distribution.
      40                 :            :  * 3. The name of the copyright holders or contributors may not be used to
      41                 :            :  *    endorse or promote products derived from this software without
      42                 :            :  *    specific prior written permission.
      43                 :            :  *
      44                 :            :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      45                 :            :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      46                 :            :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
      47                 :            :  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
      48                 :            :  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      49                 :            :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      50                 :            :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      51                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      52                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      53                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      54                 :            :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      55                 :            :  */
      56                 :            : 
      57                 :            : #include <sys/stat.h>
      58                 :            : #include <sys/types.h>
      59                 :            : #include <sys/time.h>
      60                 :            : #include <dirent.h>
      61                 :            : #include <fcntl.h>
      62                 :            : #include <errno.h>
      63                 :            : #include <talloc.h>
      64                 :            : 
      65                 :            : #include "config.h"
      66                 :            : #include "util/util.h"
      67                 :            : #include "tools/tools_util.h"
      68                 :            : 
      69                 :            : int copy_tree(const char *src_root, const char *dst_root,
      70                 :            :               uid_t uid, gid_t gid);
      71                 :            : 
      72                 :            : struct copy_ctx {
      73                 :            :     const char *src_orig;
      74                 :            :     const char *dst_orig;
      75                 :            :     dev_t       src_dev;
      76                 :            : };
      77                 :            : 
      78                 :            : /* wrapper in order not to create a temporary context in
      79                 :            :  * every iteration */
      80                 :            : static int remove_tree_with_ctx(TALLOC_CTX *mem_ctx,
      81                 :            :                                 dev_t parent_dev,
      82                 :            :                                 const char *root);
      83                 :            : 
      84                 :          1 : int remove_tree(const char *root)
      85                 :            : {
      86                 :          1 :     TALLOC_CTX *tmp_ctx = NULL;
      87                 :            :     int ret;
      88                 :            : 
      89                 :          1 :     tmp_ctx = talloc_new(NULL);
      90         [ +  - ]:          1 :     if (!tmp_ctx) {
      91                 :            :         return ENOMEM;
      92                 :            :     }
      93                 :            : 
      94                 :          1 :     ret = remove_tree_with_ctx(tmp_ctx, 0, root);
      95                 :          1 :     talloc_free(tmp_ctx);
      96                 :          1 :     return ret;
      97                 :            : }
      98                 :            : 
      99                 :            : /*
     100                 :            :  * The context is not freed in case of error
     101                 :            :  * because this is a recursive function, will be freed when we
     102                 :            :  * reach the top level remove_tree() again
     103                 :            :  */
     104                 :          3 : static int remove_tree_with_ctx(TALLOC_CTX *mem_ctx,
     105                 :            :                                 dev_t parent_dev,
     106                 :            :                                 const char *root)
     107                 :            : {
     108                 :          3 :     char *fullpath = NULL;
     109                 :            :     struct dirent *result;
     110                 :            :     struct dirent direntp;
     111                 :            :     struct stat statres;
     112                 :          3 :     DIR *rootdir = NULL;
     113                 :            :     int ret, err;
     114                 :            : 
     115                 :          3 :     rootdir = opendir(root);
     116         [ +  - ]:          3 :     if (rootdir == NULL) {
     117                 :          0 :         ret = errno;
     118 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot open directory %s [%d][%s]\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     119                 :            :                   root, ret, strerror(ret)));
     120                 :            :         goto fail;
     121                 :            :     }
     122                 :            : 
     123         [ +  - ]:         13 :     while (readdir_r(rootdir, &direntp, &result) == 0) {
     124         [ +  + ]:         13 :         if (result == NULL) {
     125                 :            :             /* End of directory */
     126                 :            :             break;
     127                 :            :         }
     128                 :            : 
     129 [ +  + ][ +  + ]:         17 :         if (strcmp (direntp.d_name, ".") == 0 ||
                 [ +  + ]
     130 [ +  + ][ +  - ]:          7 :             strcmp (direntp.d_name, "..") == 0) {
     131                 :          6 :             continue;
     132                 :            :         }
     133                 :            : 
     134                 :          4 :         fullpath = talloc_asprintf(mem_ctx, "%s/%s", root, direntp.d_name);
     135         [ +  - ]:          4 :         if (fullpath == NULL) {
     136                 :            :             ret = ENOMEM;
     137                 :            :             goto fail;
     138                 :            :         }
     139                 :            : 
     140                 :          4 :         ret = lstat(fullpath, &statres);
     141         [ -  + ]:          4 :         if (ret != 0) {
     142                 :          0 :             ret = errno;
     143 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("Cannot stat %s: [%d][%s]\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     144                 :            :                       fullpath, ret, strerror(ret)));
     145                 :            :             goto fail;
     146                 :            :         }
     147                 :            : 
     148         [ +  + ]:          4 :         if (S_ISDIR(statres.st_mode)) {
     149                 :            :             /* if directory, recursively descend, but check if on the same FS */
     150 [ +  + ][ -  + ]:          2 :             if (parent_dev && parent_dev != statres.st_dev) {
     151 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("Directory %s is on different filesystem, "
         [ #  # ][ #  # ]
                 [ #  # ]
     152                 :            :                           "will not follow\n", fullpath));
     153                 :            :                 ret = EFAULT;
     154                 :            :                 goto fail;
     155                 :            :             }
     156                 :            : 
     157                 :          2 :             ret = remove_tree_with_ctx(mem_ctx, statres.st_dev, fullpath);
     158         [ -  + ]:          2 :             if (ret != EOK) {
     159 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("Removing subdirectory %s failed: [%d][%s]\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     160                 :            :                             fullpath, ret, strerror(ret)));
     161                 :            :                 goto fail;
     162                 :            :             }
     163                 :            :         } else {
     164                 :          2 :             ret = unlink(fullpath);
     165         [ -  + ]:          2 :             if (ret != 0) {
     166                 :          0 :                 ret = errno;
     167 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("Removing file %s failed: [%d][%s]\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     168                 :            :                           fullpath, ret, strerror(ret)));
     169                 :            :                 goto fail;
     170                 :            :             }
     171                 :            :         }
     172                 :            : 
     173                 :         10 :         talloc_free(fullpath);
     174                 :            :     }
     175                 :            : 
     176                 :          3 :     ret = closedir(rootdir);
     177                 :          3 :     rootdir = NULL;
     178         [ -  + ]:          3 :     if (ret != 0) {
     179                 :          0 :         ret = errno;
     180                 :          0 :         goto fail;
     181                 :            :     }
     182                 :            : 
     183                 :          3 :     ret = rmdir(root);
     184         [ -  + ]:          3 :     if (ret != 0) {
     185                 :          0 :         ret = errno;
     186                 :          0 :         goto fail;
     187                 :            :     }
     188                 :            : 
     189                 :            :     ret = EOK;
     190                 :            : 
     191                 :            : fail:
     192         [ -  + ]:          3 :     if (rootdir) {  /* clean up on abnormal exit but retain return code */
     193                 :          0 :         err = closedir(rootdir);
     194         [ #  # ]:          0 :         if (err) {
     195 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("closedir failed, bad dirp?\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     196                 :            :         }
     197                 :            :     }
     198                 :          3 :     return ret;
     199                 :            : }
     200                 :            : 
     201                 :          1 : static int copy_dir(const char *src, const char *dst,
     202                 :            :                     const struct stat *statp, const struct timeval mt[2],
     203                 :            :                     uid_t uid, gid_t gid)
     204                 :            : {
     205                 :          1 :     int ret = 0;
     206                 :            : 
     207                 :            :     /*
     208                 :            :      * Create a new target directory, make it owned by
     209                 :            :      * the user and then recursively copy that directory.
     210                 :            :      */
     211                 :          1 :     selinux_file_context(dst);
     212                 :            : 
     213                 :          1 :     ret = mkdir(dst, statp->st_mode);
     214         [ -  + ]:          1 :     if (ret != 0) {
     215                 :          0 :         ret = errno;
     216 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot mkdir directory '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     217                 :            :                   dst, ret, strerror(ret)));
     218                 :            :         return ret;
     219                 :            :     }
     220                 :            : 
     221                 :          1 :     ret = chown(dst, uid, gid);
     222         [ -  + ]:          1 :     if (ret != 0) {
     223                 :          0 :         ret = errno;
     224 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot chown directory '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     225                 :            :                   dst, ret, strerror(ret)));
     226                 :            :         return ret;
     227                 :            :     }
     228                 :            : 
     229                 :          1 :     ret = chmod(dst, statp->st_mode);
     230         [ -  + ]:          1 :     if (ret != 0) {
     231                 :          0 :         ret = errno;
     232 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot chmod directory '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     233                 :            :                   dst, ret, strerror(ret)));
     234                 :            :         return ret;
     235                 :            :     }
     236                 :            : 
     237                 :          1 :     ret = copy_tree(src, dst, uid, gid);
     238         [ -  + ]:          1 :     if (ret != 0) {
     239                 :          0 :         ret = errno;
     240 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot copy directory from '%s' to '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     241                 :            :                   src, dst, ret, strerror(ret)));
     242                 :            :         return ret;
     243                 :            :     }
     244                 :            : 
     245                 :          1 :     ret = utimes(dst, mt);
     246         [ -  + ]:          1 :     if (ret != 0) {
     247                 :          0 :         ret = errno;
     248 [ #  # ][ #  # ]:          1 :         DEBUG(1, ("Cannot set utimes on a directory '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     249                 :            :                   dst, ret, strerror(ret)));
     250                 :            :         return ret;
     251                 :            :     }
     252                 :            : 
     253                 :            :     return EOK;
     254                 :            : }
     255                 :            : 
     256                 :          1 : static char *talloc_readlink(TALLOC_CTX *mem_ctx, const char *filename)
     257                 :            : {
     258                 :          1 :     size_t size = 1024;
     259                 :            :     ssize_t nchars;
     260                 :            :     char *buffer;
     261                 :            : 
     262                 :          1 :     buffer = talloc_array(mem_ctx, char, size);
     263         [ +  - ]:          1 :     if (!buffer) {
     264                 :            :         return NULL;
     265                 :            :     }
     266                 :            : 
     267                 :            :     while (1) {
     268                 :          1 :         nchars = readlink(filename, buffer, size);
     269         [ +  - ]:          1 :         if (nchars < 0) {
     270                 :            :             return NULL;
     271                 :            :         }
     272                 :            : 
     273         [ -  + ]:          1 :         if ((size_t) nchars < size) {
     274                 :            :             /* The buffer was large enough */
     275                 :            :             break;
     276                 :            :         }
     277                 :            : 
     278                 :            :         /* Try again with a bigger buffer */
     279                 :          0 :         size *= 2;
     280                 :          0 :         buffer = talloc_realloc(mem_ctx, buffer, char, size);
     281         [ #  # ]:          0 :         if (!buffer) {
     282                 :            :             return NULL;
     283                 :            :         }
     284                 :            :     }
     285                 :            : 
     286                 :            :     /* readlink does not nul-terminate */
     287                 :          1 :     buffer[nchars] = '\0';
     288                 :          1 :     return buffer;
     289                 :            : }
     290                 :            : 
     291                 :          1 : static int copy_symlink(struct copy_ctx *cctx,
     292                 :            :                         const char *src,
     293                 :            :                         const char *dst,
     294                 :            :                         const struct stat *statp,
     295                 :            :                         const struct timeval mt[],
     296                 :            :                         uid_t uid, gid_t gid)
     297                 :            : {
     298                 :            :     int ret;
     299                 :            :     char *oldlink;
     300                 :            :     char *tmp;
     301                 :          1 :     TALLOC_CTX *tmp_ctx = NULL;
     302                 :            : 
     303                 :          1 :     tmp_ctx = talloc_new(cctx);
     304         [ +  - ]:          1 :     if (!tmp_ctx) {
     305                 :            :         return ENOMEM;
     306                 :            :     }
     307                 :            : 
     308                 :            :     /*
     309                 :            :      * Get the name of the file which the link points
     310                 :            :      * to.  If that name begins with the original
     311                 :            :      * source directory name, that part of the link
     312                 :            :      * name will be replaced with the original
     313                 :            :      * destination directory name.
     314                 :            :      */
     315                 :          1 :     oldlink = talloc_readlink(tmp_ctx, src);
     316         [ +  - ]:          1 :     if (oldlink == NULL) {
     317                 :            :         ret = ENOMEM;
     318                 :            :         goto done;
     319                 :            :     }
     320                 :            : 
     321                 :            :     /* If src was a link to an entry of the src_orig directory itself,
     322                 :            :      * create a link to the corresponding entry in the dst_orig
     323                 :            :      * directory.
     324                 :            :      * FIXME: This may change a relative link to an absolute link
     325                 :            :      */
     326         [ -  + ]:          1 :     if (strncmp(oldlink, cctx->src_orig, strlen(cctx->src_orig)) == 0) {
     327                 :          0 :         tmp = talloc_asprintf(tmp_ctx, "%s%s", cctx->dst_orig, oldlink + strlen(cctx->src_orig));
     328         [ #  # ]:          0 :         if (tmp == NULL) {
     329                 :            :             ret = ENOMEM;
     330                 :            :             goto done;
     331                 :            :         }
     332                 :            : 
     333                 :          0 :         talloc_free(oldlink);
     334                 :          0 :         oldlink = tmp;
     335                 :            :     }
     336                 :            : 
     337                 :          1 :     selinux_file_context(dst);
     338                 :            : 
     339                 :          1 :     ret = symlink(oldlink, dst);
     340         [ -  + ]:          1 :     if (ret != 0) {
     341                 :          0 :         ret = errno;
     342 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("symlink() failed on file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     343                 :            :                   dst, ret, strerror(ret)));
     344                 :            :         goto done;
     345                 :            :     }
     346                 :            : 
     347                 :          1 :     ret = lchown(dst, uid, gid);
     348         [ -  + ]:          1 :     if (ret != 0) {
     349                 :          0 :         ret = errno;
     350 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("lchown() failed on file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     351                 :            :                   dst, ret, strerror(ret)));
     352                 :            :         goto done;
     353                 :            :     }
     354                 :            : 
     355                 :            : done:
     356                 :          1 :     talloc_free(tmp_ctx);
     357                 :            :     return ret;
     358                 :            : }
     359                 :            : 
     360                 :          1 : static int copy_special(const char *dst,
     361                 :            :                         const struct stat *statp,
     362                 :            :                         const struct timeval mt[],
     363                 :            :                         uid_t uid, gid_t gid)
     364                 :            : {
     365                 :          1 :     int ret = 0;
     366                 :            : 
     367                 :          1 :     selinux_file_context(dst);
     368                 :            : 
     369                 :          2 :     ret = mknod(dst, statp->st_mode & ~07777, statp->st_rdev);
     370         [ -  + ]:          1 :     if (ret != 0) {
     371                 :          0 :         ret = errno;
     372 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot mknod special file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     373                 :            :                   dst, ret, strerror(ret)));
     374                 :            :         return ret;
     375                 :            :     }
     376                 :            : 
     377                 :          1 :     ret = chown(dst, uid, gid);
     378         [ -  + ]:          1 :     if (ret != 0) {
     379                 :          0 :         ret = errno;
     380 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot chown special file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     381                 :            :                   dst, ret, strerror(ret)));
     382                 :            :         return ret;
     383                 :            :     }
     384                 :            : 
     385                 :          1 :     ret = chmod(dst, statp->st_mode & 07777);
     386         [ -  + ]:          1 :     if (ret != 0) {
     387                 :          0 :         ret = errno;
     388 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot chmod special file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     389                 :            :                   dst, ret, strerror(ret)));
     390                 :            :         return ret;
     391                 :            :     }
     392                 :            : 
     393                 :          1 :     ret = utimes(dst, mt);
     394         [ -  + ]:          1 :     if (ret != 0) {
     395                 :          0 :         ret = errno;
     396 [ #  # ][ #  # ]:          1 :         DEBUG(1, ("Cannot call utimes on special file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     397                 :            :                   dst, ret, strerror(ret)));
     398                 :            :         return ret;
     399                 :            :     }
     400                 :            : 
     401                 :            :     return EOK;
     402                 :            : }
     403                 :            : 
     404                 :          3 : static int copy_file(const char *src,
     405                 :            :                      const char *dst,
     406                 :            :                      const struct stat *statp,
     407                 :            :                      const struct timeval mt[],
     408                 :            :                      uid_t uid, gid_t gid)
     409                 :            : {
     410                 :            :     int ret;
     411                 :          3 :     int ifd = -1;
     412                 :          3 :     int ofd = -1;
     413                 :            :     char buf[1024];
     414                 :            :     ssize_t cnt, written;
     415                 :            :     struct stat fstatbuf;
     416                 :            : 
     417                 :          3 :     ifd = open(src, O_RDONLY);
     418         [ -  + ]:          3 :     if (ifd < 0) {
     419                 :          0 :         ret = errno;
     420 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot open() source file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     421                 :            :                   src, ret, strerror(ret)));
     422                 :            :         goto fail;
     423                 :            :     }
     424                 :            : 
     425                 :          3 :     ret = fstat(ifd, &fstatbuf);
     426         [ -  + ]:          3 :     if (ret != 0) {
     427                 :          0 :         ret = errno;
     428 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot fstat() source file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     429                 :            :                   src, ret, strerror(ret)));
     430                 :            :         goto fail;
     431                 :            :     }
     432                 :            : 
     433 [ +  - ][ -  + ]:          3 :     if (statp->st_dev != fstatbuf.st_dev ||
     434                 :          3 :         statp->st_ino != fstatbuf.st_ino) {
     435 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("File %s was modified between lstat and open.\n", src));
         [ #  # ][ #  # ]
                 [ #  # ]
     436                 :            :         ret = EIO;
     437                 :            :         goto fail;
     438                 :            :     }
     439                 :            : 
     440                 :          3 :     selinux_file_context(dst);
     441                 :            : 
     442                 :          3 :     ofd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
     443         [ -  + ]:          3 :     if (ofd < 0) {
     444                 :          0 :         ret = errno;
     445 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot open() destination file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     446                 :            :                   dst, ret, strerror(ret)));
     447                 :            :         goto fail;
     448                 :            :     }
     449                 :            : 
     450                 :          3 :     ret = fchown(ofd, uid, gid);
     451         [ -  + ]:          3 :     if (ret != 0) {
     452                 :          0 :         ret = errno;
     453 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot fchown() destination file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     454                 :            :                   dst, ret, strerror(ret)));
     455                 :            :         goto fail;
     456                 :            :     }
     457                 :            : 
     458                 :          3 :     ret = fchmod(ofd, statp->st_mode & 07777);
     459         [ -  + ]:          3 :     if (ret != 0) {
     460                 :          0 :         ret = errno;
     461 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot fchmod() destination file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     462                 :            :                   dst, ret, strerror(ret)));
     463                 :            :         goto fail;
     464                 :            :     }
     465                 :            : 
     466         [ +  + ]:          6 :     while ((cnt = sss_atomic_read_s(ifd, buf, sizeof(buf))) != 0) {
     467         [ -  + ]:          3 :         if (cnt == -1) {
     468                 :          0 :             ret = errno;
     469 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     470                 :            :                   ("Cannot read() from source file '%s': [%d][%s].\n",
     471                 :            :                    src, ret, strerror(ret)));
     472                 :            :             goto fail;
     473                 :            :         }
     474                 :            : 
     475                 :          3 :         errno = 0;
     476                 :          3 :         written = sss_atomic_write_s(ofd, buf, cnt);
     477         [ -  + ]:          3 :         if (written == -1) {
     478                 :          0 :             ret = errno;
     479 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     480                 :            :                   ("Cannot write() to destination file '%s': [%d][%s].\n",
     481                 :            :                    dst, ret, strerror(ret)));
     482                 :            :             goto fail;
     483                 :            :         }
     484                 :            : 
     485         [ -  + ]:          3 :         if (written != cnt) {
     486 [ #  # ][ #  # ]:          3 :             DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     487                 :            :                   ("Wrote %d bytes, expected %d\n", written, cnt));
     488                 :            :             goto fail;
     489                 :            :         }
     490                 :            :     }
     491                 :            : 
     492                 :          3 :     ret = close(ifd);
     493                 :          3 :     ifd = -1;
     494         [ -  + ]:          3 :     if (ret != 0) {
     495                 :          0 :         ret = errno;
     496 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot close() source file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     497                 :            :                   dst, ret, strerror(ret)));
     498                 :            :         goto fail;
     499                 :            :     }
     500                 :            : 
     501                 :          3 :     ret = close(ofd);
     502                 :          3 :     ifd = -1;
     503         [ -  + ]:          3 :     if (ret != 0) {
     504                 :          0 :         ret = errno;
     505 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot close() destination file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     506                 :            :                   dst, ret, strerror(ret)));
     507                 :            :         goto fail;
     508                 :            :     }
     509                 :            : 
     510                 :          3 :     ret = utimes(dst, mt);
     511         [ -  + ]:          3 :     if (ret != 0) {
     512                 :          0 :         ret = errno;
     513 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot call utimes() on destination file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     514                 :            :                   dst, ret, strerror(ret)));
     515                 :            :         goto fail;
     516                 :            :     }
     517                 :            : 
     518                 :            :     return EOK;
     519                 :            : 
     520                 :            :     /* Reachable by jump only */
     521                 :            : fail:
     522         [ #  # ]:          0 :     if (ifd != -1) close(ifd);
     523         [ #  # ]:          3 :     if (ofd != -1) close(ofd);
     524                 :            :     return ret;
     525                 :            : }
     526                 :            : 
     527                 :            : /*
     528                 :            :  * The context is not freed in case of error
     529                 :            :  * because this is a recursive function, will be freed when we
     530                 :            :  * reach the top level copy_tree() again
     531                 :            :  */
     532                 :          6 : static int copy_entry(struct copy_ctx *cctx,
     533                 :            :                       const char *src,
     534                 :            :                       const char *dst,
     535                 :            :                       uid_t uid,
     536                 :            :                       gid_t gid)
     537                 :            : {
     538                 :          6 :     int ret = EOK;
     539                 :            :     struct stat sb;
     540                 :            :     struct timeval mt[2];
     541                 :            : 
     542                 :          6 :     ret = lstat(src, &sb);
     543         [ -  + ]:          6 :     if (ret == -1) {
     544                 :          0 :         ret = errno;
     545 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot lstat() the source file '%s': [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     546                 :            :                   src, ret, strerror(ret)));
     547                 :            :         return ret;
     548                 :            :     }
     549                 :            : 
     550                 :          6 :     mt[0].tv_sec  = sb.st_atime;
     551                 :          6 :     mt[0].tv_usec = 0;
     552                 :            : 
     553                 :          6 :     mt[1].tv_sec  = sb.st_mtime;
     554                 :          6 :     mt[1].tv_usec = 0;
     555                 :            : 
     556         [ +  + ]:          6 :     if (S_ISLNK (sb.st_mode)) {
     557                 :          1 :         ret = copy_symlink(cctx, src, dst, &sb, mt, uid, gid);
     558         [ -  + ]:          1 :         if (ret != EOK) {
     559 [ #  # ][ #  # ]:          1 :             DEBUG(1, ("Cannot copy symlink '%s' to '%s': [%d][%s]\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     560                 :            :                       src, dst, ret, strerror(ret)));
     561                 :            :         }
     562                 :            :         return ret;
     563                 :            :     }
     564                 :            : 
     565         [ +  + ]:          5 :     if (S_ISDIR(sb.st_mode)) {
     566                 :            :         /* Check if we're still on the same FS */
     567         [ -  + ]:          1 :         if (sb.st_dev != cctx->src_dev) {
     568 [ #  # ][ #  # ]:          0 :             DEBUG(2, ("Will not descend to other FS\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     569                 :            :             /* Skip this without error */
     570                 :            :             return EOK;
     571                 :            :         }
     572                 :          1 :         return copy_dir(src, dst, &sb, mt, uid, gid);
     573         [ +  + ]:          4 :     } else if (!S_ISREG(sb.st_mode)) {
     574                 :            :         /*
     575                 :            :          * Deal with FIFOs and special files.  The user really
     576                 :            :          * shouldn't have any of these, but it seems like it
     577                 :            :          * would be nice to copy everything ...
     578                 :            :          */
     579                 :          1 :         return copy_special(dst, &sb, mt, uid, gid);
     580                 :            :     } else {
     581                 :            :         /*
     582                 :            :          * Create the new file and copy the contents.  The new
     583                 :            :          * file will be owned by the provided UID and GID values.
     584                 :            :          */
     585                 :          6 :         return copy_file(src, dst, &sb, mt, uid, gid);
     586                 :            :     }
     587                 :            : 
     588                 :            :     return ret;
     589                 :            : }
     590                 :            : 
     591                 :            : /*
     592                 :            :  * The context is not freed in case of error
     593                 :            :  * because this is a recursive function, will be freed when we
     594                 :            :  * reach the top level copy_tree() again
     595                 :            :  */
     596                 :          4 : static int copy_tree_ctx(struct copy_ctx *cctx,
     597                 :            :                          const char *src_root,
     598                 :            :                          const char *dst_root,
     599                 :            :                          uid_t uid,
     600                 :            :                          gid_t gid)
     601                 :            : {
     602                 :          4 :     DIR *src_dir = NULL;
     603                 :            :     int ret, err;
     604                 :            :     struct dirent *result;
     605                 :            :     struct dirent direntp;
     606                 :            :     char *src_name, *dst_name;
     607                 :            :     TALLOC_CTX *tmp_ctx;
     608                 :            : 
     609                 :          4 :     tmp_ctx = talloc_new(cctx);
     610                 :            : 
     611                 :          4 :     src_dir = opendir(src_root);
     612         [ +  - ]:          4 :     if (src_dir == NULL) {
     613                 :          0 :         ret = errno;
     614 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot open the source directory %s: [%d][%s].\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     615                 :            :                   src_root, ret, strerror(ret)));
     616                 :            :         goto fail;
     617                 :            :     }
     618                 :            : 
     619         [ +  - ]:         18 :     while (readdir_r(src_dir, &direntp, &result) == 0) {
     620         [ +  + ]:         18 :         if (result == NULL) {
     621                 :            :             /* End of directory */
     622                 :            :             break;
     623                 :            :         }
     624                 :            : 
     625 [ +  + ][ +  + ]:         24 :         if (strcmp (direntp.d_name, ".") == 0 ||
                 [ +  + ]
     626 [ +  + ][ +  - ]:         10 :             strcmp (direntp.d_name, "..") == 0) {
     627                 :          8 :             continue;
     628                 :            :         }
     629                 :            : 
     630                 :            :         /* build src and dst paths */
     631                 :          6 :         src_name = talloc_asprintf(tmp_ctx, "%s/%s", src_root, direntp.d_name);
     632                 :          6 :         dst_name = talloc_asprintf(tmp_ctx, "%s/%s", dst_root, direntp.d_name);
     633         [ +  - ]:          6 :         if (dst_name == NULL || src_name == NULL) {
     634                 :            :             ret = ENOMEM;
     635                 :            :             goto fail;
     636                 :            :         }
     637                 :            : 
     638                 :            :         /* copy */
     639                 :          6 :         ret = copy_entry(cctx, src_name, dst_name, uid, gid);
     640         [ -  + ]:          6 :         if (ret != EOK) {
     641 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("Cannot copy '%s' to '%s', error %d\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     642                 :            :                       src_name, dst_name, ret));
     643                 :            :             goto fail;
     644                 :            :         }
     645                 :          6 :         talloc_free(src_name);
     646                 :         14 :         talloc_free(dst_name);
     647                 :            :     }
     648                 :            : 
     649                 :          4 :     ret = closedir(src_dir);
     650                 :          4 :     src_dir = NULL;
     651         [ -  + ]:          4 :     if (ret != 0) {
     652                 :          0 :         ret = errno;
     653                 :          0 :         goto fail;
     654                 :            :     }
     655                 :            : 
     656                 :            :     ret = EOK;
     657                 :            : fail:
     658         [ -  + ]:          4 :     if (src_dir) {  /* clean up on abnormal exit but retain return code */
     659                 :          0 :         err = closedir(src_dir);
     660         [ #  # ]:          0 :         if (err) {
     661 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("closedir failed, bad dirp?\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     662                 :            :         }
     663                 :            :     }
     664                 :          4 :     talloc_free(tmp_ctx);
     665                 :          4 :     return ret;
     666                 :            : }
     667                 :            : 
     668                 :          4 : int copy_tree(const char *src_root, const char *dst_root,
     669                 :            :               uid_t uid, gid_t gid)
     670                 :            : {
     671                 :          4 :     int ret = EOK;
     672                 :          4 :     struct copy_ctx *cctx = NULL;
     673                 :            :     struct stat s_src;
     674                 :            : 
     675                 :          4 :     cctx = talloc_zero(NULL, struct copy_ctx);
     676                 :            : 
     677                 :          4 :     ret = lstat(src_root, &s_src);
     678         [ -  + ]:          4 :     if (ret != 0) {
     679                 :          0 :         ret = errno;
     680 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot lstat the source directory '%s': [%d][%s]\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     681                 :            :                   src_root, ret, strerror(ret)));
     682                 :            :         goto fail;
     683                 :            :     }
     684                 :            : 
     685                 :          4 :     cctx->src_orig = src_root;
     686                 :          4 :     cctx->dst_orig = dst_root;
     687                 :          4 :     cctx->src_dev  = s_src.st_dev;
     688                 :            : 
     689                 :          4 :     ret = copy_tree_ctx(cctx, src_root, dst_root, uid, gid);
     690         [ -  + ]:          4 :     if (ret != EOK) {
     691 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("copy_tree_ctx failed: [%d][%s]\n", ret, strerror(ret)));
         [ #  # ][ #  # ]
                 [ #  # ]
     692                 :            :         goto fail;
     693                 :            :     }
     694                 :            : 
     695                 :            : fail:
     696                 :          4 :     reset_selinux_file_context();
     697                 :          4 :     talloc_free(cctx);
     698                 :          4 :     return ret;
     699                 :            : }
     700                 :            : 

Generated by: LCOV version 1.9