X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fextract.c;h=6711f8736951a3a541d85dec9c845a9bc5e38f97;hb=dda6367c9eac71da8f2ab1c60b3df60f19ce4755;hp=0d23d4ab55ec9027b45bfd5ae3dff676ef223e3f;hpb=ee168310ec4227174ace489bf5f81f8c2f91cde0;p=debian%2Ftar diff --git a/src/extract.c b/src/extract.c index 0d23d4ab..6711f873 100644 --- a/src/extract.c +++ b/src/extract.c @@ -777,7 +777,7 @@ extract_dir (char *file_name, int typeflag) for (;;) { - status = mkdir (file_name, mode); + status = mkdirat (chdir_fd, file_name, mode); if (status == 0) { current_mode = mode & ~ current_umask; @@ -864,6 +864,20 @@ open_output_file (char const *file_name, int typeflag, mode_t mode, } } + /* If O_NOFOLLOW is needed but does not work, check for a symlink + separately. There's a race condition, but that cannot be avoided + on hosts lacking O_NOFOLLOW. */ + if (! O_NOFOLLOW && overwriting_old_files && ! dereference_option) + { + struct stat st; + if (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0 + && S_ISLNK (st.st_mode)) + { + errno = ELOOP; + return -1; + } + } + fd = openat (chdir_fd, file_name, openflag, mode); if (0 <= fd) { @@ -1191,7 +1205,7 @@ static int extract_node (char *file_name, int typeflag) { bool interdir_made = false; - mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX + mode_t mode = (current_stat_info.stat.st_mode & (MODE_RWX | S_IFBLK | S_IFCHR) & ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0)); while (mknodat (chdir_fd, file_name, mode, current_stat_info.stat.st_rdev)