Ignore:
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • ChangeLog

    r1797 r1788  
    1 2013-02-09  Miloslav Trmač  <mitr@redhat.com> 
    2  
    3         * lib/fs.c (struct copy_access_options): Remove member ignore_eexist. 
    4         (copy_symlink, copy_regular_file, lu_copy_dir_and_close): Remove the 
    5         possibility to ignore EEXIST, always fail on pre-existing contents. 
    6         (lu_homedir_populate): Incompatible change: Refuse to populate 
    7         pre-existing directories. 
    8         (lu_homedir_move): Stop setting access_options.ignore_eexist. 
    9         * tests/fs_test.py (main): Beautify output on createHome failure 
    10         to help checking the output. 
    11         * tests/fs_test: Fix mv2_output check.  Test that attempts to 
    12         populate a pre-existing home directory are refused. 
    13  
    1412013-02-08  Miloslav Trmač  <mitr@redhat.com> 
    15  
    16         * lib/fs.c (copy_regular_file): Rename from... 
    17         (copy_regular_file_and_close): ... this, and stop closing src_fd; we 
    18         don't really need to use this irregular model here. 
    19         (copy_dir_entry): Update. 
    20  
    21         * lib/fs.c (lu_homedir_populate, lu_homedir_move) 
    22         (lu_nscd_flush_cache, lu_mail_spool_create) 
    23         (lu_mail_spool_remove): These functions are public API, add 
    24         g_return_*_if_fail() checks for input parameters. 
    25  
    26         * lib/fs.c (copy_symlink): Fix comments. 
    27  
    28         * lib/fs.c (copy_symlink, copy_regular_file_and_close) 
    29         (copy_dir_entry, lu_homedir_copy, lu_homedir_populate) 
    30         (mail_spool_path, lu_mail_spool_remove): Add LU_ERROR_CHECK calls. 
    31  
    32         * lib/fs.c (copy_symlink, copy_regular_file_and_close): Use simpler 
    33         parameter names. 
    34  
    35         * lib/fs.c (copy_dir_entry): Split from ... 
    36         (lu_copy_dir_and_close): ... to simplify handling of src_path_buf and 
    37         dest_path_buf. 
    38  
    39         * lib/fs.c (lu_copy_dir_and_close, lu_homedir_copy): Use GString 
    40         buffers to build paths, removing the PATH_MAX limit and reducing O(N^2) 
    41         memory use to O(N). 
    42  
    43         * lib/fs.c (remove_subdirectory, lu_homedir_remove): Use a single 
    44         GString to build all paths, removing the PATH_MAX limit and 
    45         reducing O(N^2) memory use to O(N). 
    46  
    47         * lib/fs.c (lu_copy_dir_and_close): Simplify the control flow a little. 
    482 
    493        * lib/fs.c (copy_symlink, copy_regular_file_and_close): Split from ... 
  • lib/fs.c

    r1797 r1788  
    6666           the following fields.. */ 
    6767        gboolean preserve_source; 
     68        /* Ignore EEXIST errors.  This will go away in the future. */ 
     69        gboolean ignore_eexist; 
    6870        uid_t uid;           /* UID to use for the copy if !preserve_source. */ 
    6971        /* GID to use for the copy if !preserve_source and original is owned by 
     
    102104} 
    103105 
    104 /* Copy symlink SYMLINK_NAME in SRC_DIR_FD, which corresponds to SRC_PATH, to 
    105    SYMLINK_NAME in DEST_DIR_FD, which corresponds to DEST_PATH.  Use 
    106    ACCESS_OPTIONS.  Use SRC_STAT for data about SRC_PATH. 
     106/* Copy symlink SYMLINK_NAME in SRC_DIR_FD, which corresponds to SRC_ENT_PATH, 
     107   to SYMLINK_NAME in DEST_DIR_FD, which corresponds to DEST_ENT_PATH.  Use 
     108   ACCESS_OPTIONS.  Use SRC_ENT_STAT for data about SRC_ENT_PATH. 
    107109 
    108110   On return from this function, SELinux fscreate context is unspecified. 
    109111 
    110    Note that SRC_PATH should only be used for error messages, not to access the 
    111    files; if the user is still logged in, a directory in the path may be 
     112   Note that SRC_ENT_PATH should only be used for error messages, not to access 
     113   the files; if the user is still logged in, a directory in the path may be 
    112114   replaced by a symbolic link, redirecting the access outside of 
    113    SRC_DIR_FD/SYMLINK_NAME.  Likewise for DEST_*. */ 
     115   SRC_PARENT_FD/SRC_DIR_NAME.   Likewise for DEST_*. */ 
    114116static gboolean 
    115 copy_symlink(int src_dir_fd, const char *src_path, int dest_dir_fd, 
    116              const char *dest_path, const char *symlink_name, 
    117              const struct stat *src_stat, 
     117copy_symlink(int src_dir_fd, const char *src_ent_path, int dest_dir_fd, 
     118             const char *dest_ent_path, const char *symlink_name, 
     119             const struct stat *src_ent_stat, 
    118120             const struct copy_access_options *access_options, 
    119121             struct lu_error **error) 
     
    123125        struct timespec timebuf[2]; 
    124126 
    125         LU_ERROR_CHECK(error); 
    126  
    127127        /* In the worst case here, we end up with a wrong SELinux context for a 
    128128           symbolic link due to a path name lookup race.  That's unfortunate, 
    129129           but symlink contents are more or less public anyway... (A possible 
    130            improvement would be to use Linux-only O_PATH to open src_path 
     130           improvement would be to use Linux-only O_PATH to open src_ent_path 
    131131           first, then see if it is a symlink, and "upgrade" to an O_RDONLY if 
    132132           not.  But O_PATH is available only in Linux >= 2.6.39.) 
     
    137137           but symlinkat()/the rest is definitely unatomic.  Rely on having an 
    138138           unwritable the parent directory, same as in the mkdirat()/openat() 
    139            case of lu_homedir_copy_and_close(). */ 
     139           case. */ 
    140140        if (access_options->preserve_source) { 
    141                 if (!lu_util_fscreate_from_lfile(src_path, error)) 
     141                if (!lu_util_fscreate_from_lfile(src_ent_path, error)) 
    142142                        return FALSE; 
    143         } else if (!lu_util_fscreate_for_path(dest_path, 
    144                                               src_stat->st_mode & S_IFMT, 
     143        } else if (!lu_util_fscreate_for_path(dest_ent_path, 
     144                                              src_ent_stat->st_mode & S_IFMT, 
    145145                                              error)) 
    146146                return FALSE; 
     
    149149        if (len == -1) { 
    150150                lu_error_new(error, lu_error_generic, 
    151                              _("Error reading `%s': %s"), src_path, 
     151                             _("Error reading `%s': %s"), src_ent_path, 
    152152                             strerror(errno)); 
    153153                return FALSE; 
     
    155155        buf[len] = '\0'; 
    156156        if (symlinkat(buf, dest_dir_fd, symlink_name) == -1) { 
    157                 lu_error_new(error, lu_error_generic, 
    158                              _("Error creating `%s': %s"), dest_path, 
     157                if (errno == EEXIST && access_options->ignore_eexist) 
     158                        return TRUE; 
     159                lu_error_new(error, lu_error_generic, 
     160                             _("Error creating `%s': %s"), dest_ent_path, 
    159161                             strerror(errno)); 
    160162                return FALSE; 
    161163        } 
    162164        if (fchownat(dest_dir_fd, symlink_name, 
    163                      uid_for_copy(access_options, src_stat), 
    164                      gid_for_copy(access_options, src_stat), 
     165                     uid_for_copy(access_options, src_ent_stat), 
     166                     gid_for_copy(access_options, src_ent_stat), 
    165167                     AT_SYMLINK_NOFOLLOW) == -1 
    166168            && errno != EPERM && errno != EOPNOTSUPP) { 
    167169                lu_error_new(error, lu_error_generic, 
    168                              _("Error changing owner of `%s': %s"), dest_path, 
    169                              strerror(errno)); 
    170                 return FALSE; 
    171         } 
    172         timebuf[0] = src_stat->st_atim; 
    173         timebuf[1] = src_stat->st_mtim; 
     170                             _("Error changing owner of `%s': %s"), 
     171                             dest_ent_path, strerror(errno)); 
     172                return FALSE; 
     173        } 
     174        timebuf[0] = src_ent_stat->st_atim; 
     175        timebuf[1] = src_ent_stat->st_mtim; 
    174176        utimensat(dest_dir_fd, symlink_name, timebuf, AT_SYMLINK_NOFOLLOW); 
    175177        return TRUE; 
    176178} 
    177179 
    178 /* Copy SRC_FD, which corresponds to SRC_PATH, to DEST_NAME in DEST_DIR_FD, 
    179    which corresponds to DEST_PATH.  Use ACCESS_OPTIONS.  Use SRC_STAT for data 
    180    about SRC_PATH. 
     180/* Copy SRC_FD, which corresponds to SRC_ENT_PATH, to DEST_ENT_NAME in 
     181   DEST_DIR_FD, which corresponds to DEST_ENT_PATH.  Use ACCESS_OPTIONS.  Use 
     182   SRC_ENT_STAT for data about SRC_ENT_PATH. 
     183 
     184   In every case, even on error, close SRC_FD. 
    181185 
    182186   On return from this function, SELinux fscreate context is unspecified. 
    183187 
    184    Note that SRC_PATH should only be used for error messages, not to access the 
    185    files; if the user is still logged in, a directory in the path may be 
     188   Note that SRC_ENT_PATH should only be used for error messages, not to access 
     189   the files; if the user is still logged in, a directory in the path may be 
    186190   replaced by a symbolic link, redirecting the access outside of SRC_FD. 
    187191   Likewise for DEST_*. */ 
    188192static gboolean 
    189 copy_regular_file(int src_fd, const char *src_path, int dest_dir_fd, 
    190                   const char *dest_name, const char *dest_path, 
    191                   const struct stat *src_stat, 
    192                   const struct copy_access_options *access_options, 
    193                   struct lu_error **error) 
     193copy_regular_file_and_close(int src_fd, const char *src_ent_path, 
     194                            int dest_dir_fd, const char *dest_ent_name, 
     195                            const char *dest_ent_path, 
     196                            const struct stat *src_ent_stat, 
     197                            const struct copy_access_options *access_options, 
     198                            struct lu_error **error) 
    194199{ 
    195200        int dest_fd; 
     
    197202        gboolean ret = FALSE; 
    198203 
    199         LU_ERROR_CHECK(error); 
    200  
    201204        if (access_options->preserve_source) { 
    202                 if (!lu_util_fscreate_from_fd(src_fd, src_path, error)) 
    203                         return FALSE; 
    204         } else if (!lu_util_fscreate_for_path(dest_path, 
    205                                               src_stat->st_mode & S_IFMT, 
     205                if (!lu_util_fscreate_from_fd(src_fd, src_ent_path, error)) 
     206                        goto err_src_fd; 
     207        } else if (!lu_util_fscreate_for_path(dest_ent_path, 
     208                                              src_ent_stat->st_mode & S_IFMT, 
    206209                                              error)) 
    207                 return FALSE; 
     210                goto err_src_fd; 
    208211        /* Start with absolutely restrictive permissions; the original file may 
    209212           be e.g. a hardlink to /etc/shadow. */ 
    210         dest_fd = openat(dest_dir_fd, dest_name, 
     213        dest_fd = openat(dest_dir_fd, dest_ent_name, 
    211214                         O_EXCL | O_CREAT | O_WRONLY | O_NOFOLLOW, 0); 
    212215        if (dest_fd == -1) { 
     216                if (errno == EEXIST && access_options->ignore_eexist) { 
     217                        ret = TRUE; 
     218                        goto err_src_fd; 
     219                } 
    213220                lu_error_new(error, lu_error_open, _("Error writing `%s': %s"), 
    214                              dest_path, strerror(errno)); 
    215                 return FALSE; 
     221                             dest_ent_path, strerror(errno)); 
     222                goto err_src_fd; 
    216223        } 
    217224 
     
    227234                                continue; 
    228235                        lu_error_new(error, lu_error_read, 
    229                                      _("Error reading `%s': %s"), src_path, 
     236                                     _("Error reading `%s': %s"), src_ent_path, 
    230237                                     strerror(errno)); 
    231238                        goto err_dest_fd; 
     
    243250                                lu_error_new(error, lu_error_write, 
    244251                                             _("Error writing `%s': %s"), 
    245                                              dest_path, strerror(errno)); 
     252                                             dest_ent_path, 
     253                                             strerror(errno)); 
    246254                                goto err_dest_fd; 
    247255                        } 
     
    252260 
    253261        /* Set the ownership; permissions are still restrictive. */ 
    254         if (fchown(dest_fd, uid_for_copy(access_options, src_stat), 
    255                    gid_for_copy(access_options, src_stat)) == -1 
     262        if (fchown(dest_fd, uid_for_copy(access_options, src_ent_stat), 
     263                   gid_for_copy(access_options, src_ent_stat)) == -1 
    256264            && errno != EPERM) { 
    257265                lu_error_new(error, lu_error_generic, 
    258                              _("Error changing owner of `%s': %s"), dest_path, 
    259                              strerror(errno)); 
     266                             _("Error changing owner of `%s': %s"), 
     267                             dest_ent_path, strerror(errno)); 
    260268                goto err_dest_fd; 
    261269        } 
     
    264272           other bits.  Do this after chown, because chown is permitted to 
    265273           reset these bits. */ 
    266         if (fchmod(dest_fd, mode_for_copy(access_options, src_stat)) == -1) { 
    267                 lu_error_new(error, lu_error_generic, 
    268                              _("Error setting mode of `%s': %s"), dest_path, 
     274        if (fchmod(dest_fd, mode_for_copy(access_options, src_ent_stat)) 
     275            == -1) { 
     276                lu_error_new(error, lu_error_generic, 
     277                             _("Error setting mode of `%s': %s"), dest_ent_path, 
    269278                             strerror(errno)); 
    270279                goto err_dest_fd; 
    271280        } 
    272281 
    273         timebuf[0] = src_stat->st_atim; 
    274         timebuf[1] = src_stat->st_mtim; 
     282        timebuf[0] = src_ent_stat->st_atim; 
     283        timebuf[1] = src_ent_stat->st_mtim; 
    275284        futimens(dest_fd, timebuf); 
    276285 
     
    280289err_dest_fd: 
    281290        close(dest_fd); 
     291err_src_fd: 
     292        close(src_fd); 
    282293        return ret; 
    283294} 
    284295 
    285 /* Forward declaration. */ 
    286 static gboolean lu_copy_dir_and_close(int src_dir_fd, GString *src_path_buf, 
    287                                       int dest_parent_fd, 
    288                                       const char *dest_dir_name, 
    289                                       GString *dest_path_buf, 
    290                                       const struct stat *src_dir_stat, 
    291                                       const struct copy_access_options 
    292                                       *access_options, struct lu_error **error); 
    293  
    294 /* Copy ENT_NAME in SRC_DIR_FD, which corresponds to SRC_PATH_BUF, 
    295    to DEST_DIR_FD, which corresponds to DEST_PATH_BUF.  Use ACCESS_OPTIONS. 
    296  
    297    On return from this function, SELinux fscreate context is unspecified.  This 
    298    function may temporarily modify SRC_PATH_BUF and DEST_PATH_BUF, but they 
    299    will be unchanged on return. 
    300  
    301    Note that SRC_PATH_BUF should only be used for error messages, not to access 
    302    the files; if the user is still logged in, a directory in the path may be 
    303    replaced by a symbolic link, redirecting the access outside of SRC_DIR_FD. 
    304    Likewise for DEST_*. */ 
    305 static gboolean 
    306 copy_dir_entry(int src_dir_fd, GString *src_path_buf, int dest_dir_fd, 
    307                GString *dest_path_buf, const char *ent_name, 
    308                const struct copy_access_options *access_options, 
    309                struct lu_error **error) 
    310 { 
    311         struct stat st; 
    312         int ifd; 
    313         gboolean ret = FALSE; 
    314  
    315         LU_ERROR_CHECK(error); 
    316  
    317         /* Open the input entry first, then we can fstat() it and be certain 
    318            that it is still the same file.  O_NONBLOCK protects us against 
    319            FIFOs and perhaps side-effects of the open() of a device file if 
    320            there ever was one here, and doesn't matter for regular files or 
    321            directories. */ 
    322         ifd = openat(src_dir_fd, ent_name, 
    323                      O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK); 
    324         if (ifd == -1) { 
    325                 int saved_errno; 
    326  
    327                 saved_errno = errno; 
    328                 if (errno != ELOOP || fstatat(src_dir_fd, ent_name, &st, 
    329                                               AT_SYMLINK_NOFOLLOW) != 0 
    330                     || !S_ISLNK(st.st_mode)) { 
    331                         lu_error_new(error, lu_error_open, 
    332                                      _("Error opening `%s': %s"), 
    333                                      src_path_buf->str, strerror(saved_errno)); 
    334                         return FALSE; 
    335                 } 
    336  
    337                 return copy_symlink(src_dir_fd, src_path_buf->str, dest_dir_fd, 
    338                                     dest_path_buf->str, ent_name, &st, 
    339                                     access_options, error); 
    340         } 
    341  
    342         if (fstat(ifd, &st) != 0) { 
    343                 lu_error_new(error, lu_error_stat, _("couldn't stat `%s': %s"), 
    344                              src_path_buf->str, strerror(errno)); 
    345                 goto err_ifd; 
    346         } 
    347         g_assert(!S_ISLNK(st.st_mode)); 
    348  
    349         if (S_ISDIR(st.st_mode)) { 
    350                 ret = lu_copy_dir_and_close(ifd, src_path_buf, dest_dir_fd, 
    351                                             ent_name, dest_path_buf, &st, 
    352                                             access_options, error); 
    353                 ifd = -1; 
    354         } else if (S_ISREG(st.st_mode)) 
    355                 ret = copy_regular_file(ifd, src_path_buf->str, dest_dir_fd, 
    356                                         ent_name, dest_path_buf->str, &st, 
    357                                         access_options, error); 
    358         else 
    359                 /* Note that we don't copy device specials. */ 
    360                 ret = TRUE; 
    361         /* Fall through */ 
    362  
    363 err_ifd: 
    364         if (ifd != -1) 
    365                 close(ifd); 
    366         return ret; 
    367 } 
    368  
    369 /* Copy SRC_DIR_FD, which corresponds to SRC_PATH_BUF, to DEST_DIR_NAME under 
    370    DEST_PARENT_FD, which corresponds to DEST_PATH_BUF.  Use ACCESS_OPTIONS.  Use 
    371    SRC_DIR_STAT for data about SRC_PATH_BUF. 
     296/* Copy SRC_DIR_FD, which corresponds to SRC_DIR_PATH, to DEST_DIR_NAME under 
     297   DEST_PARENT_FD, which corresponds to DEST_DIR_PATH.  Use ACCESS_OPTIONS.  Use 
     298   SRC_DIR_STAT for data about SRC_DIR_PATH. 
    372299 
    373300   In every case, even on error, close SRC_DIR_FD. 
    374301 
    375302   DEST_PARENT_FD may be AT_FDCWD.  On return from this function, SELinux 
    376    fscreate context is unspecified.  This function may temporarily modify 
    377    SRC_PATH_BUF and DEST_PATH_BUF, but they will be unchanged on return. 
    378  
    379    Note that SRC_PATH_BUF should only be used for error messages, not to access 
     303   fscreate context is unspecified. 
     304 
     305   Note that SRC_DIR_PATH should only be used for error messages, not to access 
    380306   the files; if the user is still logged in, a directory in the path may be 
    381307   replaced by a symbolic link, redirecting the access outside of 
    382308   SRC_PARENT_FD/SRC_DIR_NAME.   Likewise for DEST_*. */ 
    383309static gboolean 
    384 lu_copy_dir_and_close(int src_dir_fd, GString *src_path_buf, int dest_parent_fd, 
    385                       const char *dest_dir_name, GString *dest_path_buf, 
     310lu_copy_dir_and_close(int src_dir_fd, const char *src_dir_path, 
     311                      int dest_parent_fd, const char *dest_dir_name, 
     312                      const char *dest_dir_path, 
    386313                      const struct stat *src_dir_stat, 
    387314                      const struct copy_access_options *access_options, 
    388315                      struct lu_error **error) 
    389316{ 
    390         size_t orig_src_path_buf_len, orig_dest_path_buf_len; 
    391317        struct dirent *ent; 
    392318        DIR *dir; 
    393         int dest_dir_fd; 
     319        int dest_dir_fd, ifd; 
    394320        struct timespec timebuf[2]; 
    395321        gboolean ret = FALSE; 
    396322 
    397323        LU_ERROR_CHECK(error); 
    398         orig_src_path_buf_len = src_path_buf->len; 
    399         orig_dest_path_buf_len = dest_path_buf->len; 
    400  
    401         if (*dest_path_buf->str != '/') { 
     324 
     325        if (*dest_dir_path != '/') { 
    402326                lu_error_new(error, lu_error_generic, 
    403327                             _("Home directory path `%s' is not absolute"), 
    404                              dest_path_buf->str); 
     328                             dest_dir_path); 
    405329                goto err_src_dir_fd; 
    406330        } 
     
    409333        if (dir == NULL) { 
    410334                lu_error_new(error, lu_error_generic, 
    411                              _("Error reading `%s': %s"), src_path_buf->str, 
     335                             _("Error reading `%s': %s"), src_dir_path, 
    412336                             strerror(errno)); 
    413337                goto err_src_dir_fd; 
     
    415339 
    416340        if (access_options->preserve_source) { 
    417                 if (!lu_util_fscreate_from_fd(src_dir_fd, src_path_buf->str, 
    418                                               error)) 
     341                if (!lu_util_fscreate_from_fd(src_dir_fd, src_dir_path, error)) 
    419342                        goto err_dir; 
    420         } else if (!lu_util_fscreate_for_path(dest_path_buf->str, 
     343        } else if (!lu_util_fscreate_for_path(dest_dir_path, 
    421344                                              src_dir_stat->st_mode & S_IFMT, 
    422345                                              error)) 
     
    426349           fairly restrictive permissions that still allow us to use the 
    427350           directory. */ 
    428         if (mkdirat(dest_parent_fd, dest_dir_name, S_IRWXU) == -1) { 
    429                 lu_error_new(error, lu_error_generic, 
    430                              _("Error creating `%s': %s"), dest_path_buf->str, 
     351        if (mkdirat(dest_parent_fd, dest_dir_name, S_IRWXU) == -1 
     352            && (errno != EEXIST || !access_options->ignore_eexist)) { 
     353                lu_error_new(error, lu_error_generic, 
     354                             _("Error creating `%s': %s"), dest_dir_path, 
    431355                             strerror(errno)); 
    432356                goto err_dir; 
     
    438362        if (dest_dir_fd == -1) { 
    439363                lu_error_new(error, lu_error_open, _("Error opening `%s': %s"), 
    440                              dest_path_buf->str, strerror(errno)); 
     364                             dest_dir_path, strerror(errno)); 
    441365                goto err_dir; 
    442366        } 
     
    452376           directory, and for the others we achieve this by creating them 
    453377           root-owned and S_IRWXU, and only applying the original ownership and 
    454            permissions after finishing other work.  See also the comment in 
    455            copy_symlink(). */ 
     378           permissions after finishing other work.  See also the comment below 
     379           about symlinks. 
     380 
     381           Handling any preexisting directory structure complicates this - 
     382           should we temporarily chown/chmod any existing directory to 
     383           root:root/S_IRWXU?  That might be very disruptive, and such 
     384           structures should not exist in the first place. */ 
    456385 
    457386        while ((ent = readdir(dir)) != NULL) { 
    458                 if (strcmp(ent->d_name, ".") == 0 
    459                     || strcmp(ent->d_name, "..") == 0) 
     387                char src_ent_path[PATH_MAX], dest_ent_path[PATH_MAX]; 
     388                struct stat st; 
     389 
     390                /* Iterate through each item in the directory. */ 
     391                /* Skip over self and parent hard links. */ 
     392                if (strcmp(ent->d_name, ".") == 0) { 
    460393                        continue; 
     394                } 
     395                if (strcmp(ent->d_name, "..") == 0) { 
     396                        continue; 
     397                } 
    461398 
    462399                /* Build the path of the source file or directory and its 
    463400                   corresponding member in the new tree. */ 
    464                 g_string_append_c(src_path_buf, '/'); 
    465                 g_string_append(src_path_buf, ent->d_name); 
    466                 g_string_append_c(dest_path_buf, '/'); 
    467                 g_string_append(dest_path_buf, ent->d_name); 
    468  
    469                 if (!copy_dir_entry(src_dir_fd, src_path_buf, dest_dir_fd, 
    470                                     dest_path_buf, ent->d_name, access_options, 
    471                                     error)) 
     401                snprintf(src_ent_path, sizeof(src_ent_path), "%s/%s", 
     402                         src_dir_path, ent->d_name); 
     403                snprintf(dest_ent_path, sizeof(dest_ent_path), "%s/%s", 
     404                         dest_dir_path, ent->d_name); 
     405 
     406                /* Open the input entry first, then we can fstat() it and be 
     407                   certain that it is still the same file.  O_NONBLOCK protects 
     408                   us against FIFOs and perhaps side-effects of the open() of a 
     409                   device file if there ever was one here, and doesn't matter 
     410                   for regular files or directories. */ 
     411                ifd = openat(src_dir_fd, ent->d_name, 
     412                             O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK); 
     413                if (ifd == -1) { 
     414                        int saved_errno; 
     415 
     416                        saved_errno = errno; 
     417                        if (errno != ELOOP 
     418                            || fstatat(src_dir_fd, ent->d_name, &st, 
     419                                       AT_SYMLINK_NOFOLLOW) != 0 
     420                            || !S_ISLNK(st.st_mode)) { 
     421                                lu_error_new(error, lu_error_open, 
     422                                             _("Error opening `%s': %s"), 
     423                                             src_ent_path, 
     424                                             strerror(saved_errno)); 
     425                                goto err_dest_dir_fd; 
     426                        } 
     427 
     428                        if (!copy_symlink(src_dir_fd, src_ent_path, 
     429                                          dest_dir_fd, dest_ent_path, 
     430                                          ent->d_name, &st, access_options, 
     431                                          error)) 
     432                                goto err_dest_dir_fd; 
     433                        continue; 
     434                } 
     435 
     436                if (fstat(ifd, &st) != 0) { 
     437                        lu_error_new(error, lu_error_stat, 
     438                                     _("couldn't stat `%s': %s"), src_ent_path, 
     439                                     strerror(errno)); 
     440                        close(ifd); 
    472441                        goto err_dest_dir_fd; 
    473  
    474                 g_string_truncate(src_path_buf, orig_src_path_buf_len); 
    475                 g_string_truncate(dest_path_buf, orig_dest_path_buf_len); 
     442                } 
     443                g_assert(!S_ISLNK(st.st_mode)); 
     444 
     445                /* If it's a directory, descend into it. */ 
     446                if (S_ISDIR(st.st_mode)) { 
     447                        if (!lu_copy_dir_and_close(ifd, src_ent_path, 
     448                                                   dest_dir_fd, ent->d_name, 
     449                                                   dest_ent_path, &st, 
     450                                                   access_options, error)) 
     451                                /* Aargh!  Fail up. */ 
     452                                goto err_dest_dir_fd; 
     453                        continue; 
     454                } 
     455 
     456                /* If it's a regular file, copy it. */ 
     457                if (S_ISREG(st.st_mode)) { 
     458                        if (!copy_regular_file_and_close(ifd, src_ent_path, 
     459                                                         dest_dir_fd, 
     460                                                         ent->d_name, 
     461                                                         dest_ent_path, &st, 
     462                                                         access_options, error)) 
     463                                goto err_dest_dir_fd; 
     464                        continue; 
     465                } 
     466                /* Note that we don't copy device specials. */ 
     467                close(ifd); 
    476468        } 
    477469 
     
    483475                lu_error_new(error, lu_error_generic, 
    484476                             _("Error changing owner of `%s': %s"), 
    485                              dest_path_buf->str, strerror(errno)); 
     477                             dest_dir_path, strerror(errno)); 
    486478                goto err_dest_dir_fd; 
    487479        } 
     
    493485                   mode_for_copy(access_options, src_dir_stat)) == -1) { 
    494486                lu_error_new(error, lu_error_generic, 
    495                              _("Error setting mode of `%s': %s"), 
    496                              dest_path_buf->str, strerror(errno)); 
     487                             _("Error setting mode of `%s': %s"), dest_dir_path, 
     488                             strerror(errno)); 
    497489                goto err_dest_dir_fd; 
    498490        } 
     
    513505        if (src_dir_fd != -1) 
    514506                close(src_dir_fd); 
    515         g_string_truncate(src_path_buf, orig_src_path_buf_len); 
    516         g_string_truncate(dest_path_buf, orig_dest_path_buf_len); 
    517507        return ret; 
    518508} 
     
    535525        int fd; 
    536526        struct stat st; 
    537         GString *src_path_buf, *dest_path_buf; 
    538527        gboolean ret; 
    539  
    540         LU_ERROR_CHECK(error); 
    541528 
    542529        ret = FALSE; 
     
    556543        } 
    557544 
    558         src_path_buf = g_string_new(src_dir); 
    559         dest_path_buf = g_string_new(dest_dir); 
    560         ret = lu_copy_dir_and_close(fd, src_path_buf, AT_FDCWD, dest_dir, 
    561                                     dest_path_buf, &st, access_options, error); 
    562         g_string_free(dest_path_buf, TRUE); 
    563         g_string_free(src_path_buf, TRUE); 
     545        ret = lu_copy_dir_and_close(fd, src_dir, AT_FDCWD, dest_dir, dest_dir, 
     546                                    &st, access_options, error); 
    564547        goto err_fscreate; 
    565548 
     
    598581        struct copy_access_options access_options; 
    599582 
    600         LU_ERROR_CHECK(error); 
    601         g_return_val_if_fail(ctx != NULL, FALSE); 
    602         g_return_val_if_fail(directory != NULL, FALSE); 
    603  
    604583        if (skeleton == NULL) 
    605584                skeleton = lu_cfg_read_single(ctx, "defaults/skeleton", 
    606585                                              "/etc/skel"); 
    607586        access_options.preserve_source = FALSE; 
     587        access_options.ignore_eexist = TRUE; 
    608588        access_options.uid = owner; 
    609589        access_options.gid = group; 
     
    641621 
    642622/* Recursively remove directory DIR_NAME under PARENT_FD, which corresponds to 
    643    PATH_BUF. 
     623   DIR_PATH. 
    644624 
    645625   Return TRUE on sucess. 
    646626 
    647    PARENT_FD may be AT_FDCWD.  This function may temporarily modify PATH_BUF, 
    648    but it will be unchanged on return. 
    649  
    650    Note that PATH_BUF should only be used for error messages, not to access 
     627   PARENT_FD may be AT_FDCWD. 
     628 
     629   Note that DIR_PATH should only be used for error messages, not to access 
    651630   the files; if the user is still logged in, a directory in the path may be 
    652631   replaced by a symbolic link, redirecting the access outside of 
    653632   PARENT_FD/DIR_NAME. */ 
    654633static gboolean 
    655 remove_subdirectory(int parent_fd, const char *dir_name, GString *path_buf, 
     634remove_subdirectory(int parent_fd, const char *dir_name, const char *dir_path, 
    656635                    struct lu_error **error) 
    657636{ 
    658         size_t orig_path_buf_len; 
    659637        int dir_fd; 
    660638        struct dirent *ent; 
     
    662640 
    663641        LU_ERROR_CHECK(error); 
    664         orig_path_buf_len = path_buf->len; 
    665642 
    666643        dir_fd = openat(parent_fd, dir_name, 
     
    668645        if (dir_fd == -1) { 
    669646                lu_error_new(error, lu_error_open, 
    670                              _("Error opening `%s': %s"), path_buf->str, 
     647                             _("Error opening `%s': %s"), dir_path, 
    671648                             strerror(errno)); 
    672649                return FALSE; 
     
    675652        if (dir == NULL) { 
    676653                lu_error_new(error, lu_error_open, 
    677                              _("Error opening `%s': %s"), path_buf->str, 
     654                             _("Error opening `%s': %s"), dir_path, 
    678655                             strerror(errno)); 
    679656                close(dir_fd); 
     
    684661        while ((ent = readdir(dir)) != NULL) { 
    685662                struct stat st; 
     663                char path[PATH_MAX]; 
    686664 
    687665                /* Skip over the self and parent hard links. */ 
     
    691669 
    692670                /* Generate the full path of the next victim. */ 
    693                 g_string_append_c(path_buf, '/'); 
    694                 g_string_append(path_buf, ent->d_name); 
     671                snprintf(path, sizeof(path), "%s/%s", dir_path, ent->d_name); 
    695672 
    696673                /* What we do next depends on whether or not the next item to 
     
    699676                            AT_SYMLINK_NOFOLLOW) == -1) { 
    700677                        lu_error_new(error, lu_error_stat, 
    701                                      _("couldn't stat `%s': %s"), path_buf->str, 
     678                                     _("couldn't stat `%s': %s"), path, 
    702679                                     strerror(errno)); 
    703680                        goto err_dir; 
     
    705682                if (S_ISDIR(st.st_mode)) { 
    706683                        /* We descend into subdirectories... */ 
    707                         if (remove_subdirectory(dir_fd, ent->d_name, path_buf, 
     684                        if (remove_subdirectory(dir_fd, ent->d_name, path, 
    708685                                                error) == FALSE) 
    709686                                goto err_dir; 
     
    712689                        if (unlinkat(dir_fd, ent->d_name, 0) == -1) { 
    713690                                lu_error_new(error, lu_error_generic, 
    714                                              _("Error removing `%s': %s"), 
    715                                              path_buf->str, strerror(errno)); 
     691                                             _("Error removing `%s': %s"), path, 
     692                                             strerror(errno)); 
    716693                                goto err_dir; 
    717694                        } 
    718695                } 
    719  
    720                 g_string_truncate(path_buf, orig_path_buf_len); 
    721696        } 
    722697 
     
    726701        if (unlinkat(parent_fd, dir_name, AT_REMOVEDIR) == -1) { 
    727702                lu_error_new(error, lu_error_generic, 
    728                              _("Error removing `%s': %s"), path_buf->str, 
     703                             _("Error removing `%s': %s"), dir_path, 
    729704                             strerror(errno)); 
    730705                return FALSE; 
     
    735710err_dir: 
    736711        closedir(dir); 
    737         g_string_truncate(path_buf, orig_path_buf_len); 
    738712        return FALSE; 
    739713} 
     
    754728lu_homedir_remove(const char *directory, struct lu_error ** error) 
    755729{ 
    756         gboolean ret; 
    757         GString *path_buf; 
    758  
    759730        LU_ERROR_CHECK(error); 
    760731        g_return_val_if_fail(directory != NULL, FALSE); 
    761         path_buf = g_string_new(directory); 
    762         ret = remove_subdirectory(AT_FDCWD, directory, path_buf, error); 
    763         g_string_free(path_buf, TRUE); 
    764         return ret; 
     732        return remove_subdirectory(AT_FDCWD, directory, directory, error); 
    765733} 
    766734 
     
    790758 
    791759        LU_ERROR_CHECK(error); 
    792         g_return_val_if_fail(oldhome != NULL, FALSE); 
    793         g_return_val_if_fail(newhome != NULL, FALSE); 
    794760 
    795761        access_options.preserve_source = TRUE; 
     762        access_options.ignore_eexist = FALSE; 
    796763        if (!lu_homedir_copy(oldhome, newhome, &access_options, error)) 
    797764                return FALSE; 
     
    811778{ 
    812779        static char *const envp[] = { NULL }; 
    813  
    814         g_return_if_fail(table != NULL); 
    815780 
    816781        posix_spawn_file_actions_t fa; 
     
    845810        char *p, *username; 
    846811 
    847         LU_ERROR_CHECK(error); 
    848  
    849812        /* Now get the user's login. */ 
    850813        username = lu_ent_get_first_value_strdup(ent, LU_USERNAME); 
     
    886849 
    887850        LU_ERROR_CHECK(error); 
    888         g_return_val_if_fail(ctx != NULL, FALSE); 
    889         g_return_val_if_fail(ent != NULL, FALSE); 
    890         g_return_val_if_fail(ent->type == lu_user, FALSE); 
    891  
    892851        spool_path = mail_spool_path(ctx, ent, error); 
    893852        if (spool_path == NULL) 
     
    979938        char *p; 
    980939 
    981         LU_ERROR_CHECK(error); 
    982         g_return_val_if_fail(ctx != NULL, FALSE); 
    983         g_return_val_if_fail(ent != NULL, FALSE); 
    984         g_return_val_if_fail(ent->type == lu_user, FALSE); 
    985  
    986940        p = mail_spool_path(ctx, ent, error); 
    987941        if (p == NULL) 
  • tests/fs_test

    r1797 r1783  
    1771771 
    178178EOF 
    179 if [ $? -ne 0 ]; then 
    180     exit 1 
    181 fi 
    182179 
    183180 
     
    236233    exit 1 
    237234fi 
    238  
    239 # Populating an existing directory is prohibited 
    240 fakeroot > pop2_output 2>&1 <<EOF 
    241 rm -rf "$workdir"/skel 
    242 mkdir "$workdir"/{skel,pop2} 
    243  
    244 $VALGRIND python "$srcdir"/fs_test.py --populate "$workdir"/pop2 556 557 
    245 echo \$? 
    246 EOF 
    247 diff pop2_output - <<EOF 
    248 Error creating \`$workdir/pop2': File exists 
    249 1 
    250 EOF 
    251 if [ $? -ne 0 ]; then 
    252     exit 1 
    253 fi 
  • tests/fs_test.py

    r1797 r1783  
    4343        u[libuser.UIDNUMBER] = int(sys.argv[3]) 
    4444        u[libuser.GIDNUMBER] = int(sys.argv[4]) 
    45         try: 
    46             a.createHome(u) 
    47         except RuntimeError, e: 
    48             sys.exit(str(e)) 
     45        a.createHome(u) 
    4946    else: 
    5047        sys.exit('Unexpected mode') 
Note: See TracChangeset for help on using the changeset viewer.