--- cpio-2.7/src/copyin.c.chmodRaceC 2006-11-03 11:52:13.000000000 +0100 +++ cpio-2.7/src/copyin.c 2006-11-03 13:20:50.000000000 +0100 @@ -186,11 +186,12 @@ static int try_existing_file(struct cpio_file_stat* file_hdr, int in_file_des, - int *existing_dir) + int *existing_dir, mode_t *existing_mode) { struct stat file_stat; *existing_dir = false; + *existing_mode = 0; if (lstat (file_hdr->c_name, &file_stat) == 0) { if (S_ISDIR (file_stat.st_mode) @@ -200,6 +201,7 @@ we are trying to create, don't complain about it. */ *existing_dir = true; + *existing_mode = file_stat.st_mode; return 0; } else if (!unconditional_flag @@ -387,10 +389,10 @@ continue; } + set_perms_fd (out_file_des, &d->header); + if (close (out_file_des) < 0) close_error (d->header.c_name); - - set_perms (&d->header); } } @@ -540,6 +542,9 @@ write (out_file_des, "", 1); delayed_seek_count = 0; } + + set_perms_fd (out_file_des, file_hdr); + if (close (out_file_des) < 0) close_error (file_hdr->c_name); @@ -550,8 +555,6 @@ file_hdr->c_name, crc, file_hdr->c_chksum); } - set_perms (file_hdr); - tape_skip_padding (in_file_des, file_hdr->c_filesize); if (file_hdr->c_nlink > 1 && (archive_format == arf_newascii || archive_format == arf_crcascii) ) @@ -565,7 +568,7 @@ } static void -copyin_directory(struct cpio_file_stat* file_hdr, int existing_dir) +copyin_directory(struct cpio_file_stat* file_hdr, int existing_dir, mode_t existing_mode) { int res; /* Result of various function calls. */ #ifdef HPUX_CDF @@ -608,14 +611,22 @@ cdf_flag = 1; } #endif - res = mkdir (file_hdr->c_name, file_hdr->c_mode); + res = mkdir (file_hdr->c_name, file_hdr->c_mode & ~077); + } + else + { + if (!no_chown_flag && (existing_mode & 077) != 0 + && chmod (file_hdr->c_name, existing_mode & 07700) < 0) + { + error (0, errno, "%s: chmod", file_hdr->c_name); + return; + } + res = 0; } - else - res = 0; if (res < 0 && create_dir_flag) { create_all_directories (file_hdr->c_name); - res = mkdir (file_hdr->c_name, file_hdr->c_mode); + res = mkdir (file_hdr->c_name, file_hdr->c_mode & ~077); } if (res < 0) { @@ -690,12 +701,12 @@ return; } - res = mknod (file_hdr->c_name, file_hdr->c_mode, + res = mknod (file_hdr->c_name, file_hdr->c_mode & ~077, makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min)); if (res < 0 && create_dir_flag) { create_all_directories (file_hdr->c_name); - res = mknod (file_hdr->c_name, file_hdr->c_mode, + res = mknod (file_hdr->c_name, file_hdr->c_mode & ~077, makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min)); } if (res < 0) @@ -769,9 +780,10 @@ copyin_file (struct cpio_file_stat* file_hdr, int in_file_des) { int existing_dir; + mode_t existing_mode; if (!to_stdout_option - && try_existing_file (file_hdr, in_file_des, &existing_dir) < 0) + && try_existing_file (file_hdr, in_file_des, &existing_dir, &existing_mode) < 0) return; /* Do the real copy or link. */ @@ -782,7 +794,7 @@ break; case CP_IFDIR: - copyin_directory(file_hdr, existing_dir); + copyin_directory(file_hdr, existing_dir, existing_mode); break; case CP_IFCHR: --- cpio-2.7/src/util.c.chmodRaceC 2006-11-03 12:22:40.000000000 +0100 +++ cpio-2.7/src/util.c 2006-11-03 12:28:54.000000000 +0100 @@ -1274,6 +1274,29 @@ } void +set_perms_fd (int fd, struct cpio_file_stat *header) +{ + if (!no_chown_flag) + { + uid_t uid = set_owner_flag ? set_owner : header->c_uid; + gid_t gid = set_group_flag ? set_group : header->c_gid; + if ((fchown (fd, uid, gid) < 0) && errno != EPERM) + chown_error_details (header->c_name, uid, gid); + } + /* chown may have turned off some permissions we wanted. */ + if (fchmod (fd, header->c_mode) < 0) + chmod_error_details (header->c_name, header->c_mode); +#ifdef HPUX_CDF + if ((header->c_mode & CP_IFMT) && cdf_flag) + /* Once we "hide" the directory with the chmod(), + we have to refer to it using name+ instead of name. */ + file_hdr->c_name [cdf_char] = '+'; +#endif + if (retain_time_flag) + set_file_times (header->c_name, header->c_mtime, header->c_mtime); +} + +void set_file_times (const char *name, unsigned long atime, unsigned long mtime) { struct timespec ts[2]; --- cpio-2.7/src/copypass.c.chmodRaceC 2006-11-03 13:21:05.000000000 +0100 +++ cpio-2.7/src/copypass.c 2006-11-03 13:49:44.000000000 +0100 @@ -42,6 +42,15 @@ set_perms (&header); } +static void +set_copypass_perms_fd (int fd, const char *name, struct stat *st) +{ + struct cpio_file_stat header; + header.c_name = name; + stat_to_cpio (&header, st); + set_perms_fd (fd, &header); +} + /* Copy files listed on the standard input into directory `directory_name'. If `link_flag', link instead of copying. */ @@ -194,10 +203,12 @@ } if (close (in_file_des) < 0) close_error (input_name.ds_string); + + set_copypass_perms_fd (out_file_des, output_name.ds_string, &out_file_stat); + if (close (out_file_des) < 0) close_error (output_name.ds_string); - set_copypass_perms (input_name.ds_string, &in_file_stat); if (reset_time_flag) { @@ -232,15 +243,23 @@ cdf_flag = 1; } #endif - res = mkdir (output_name.ds_string, in_file_stat.st_mode); + res = mkdir (output_name.ds_string, in_file_stat.st_mode & ~077); } else - res = 0; + { + if (!no_chown_flag && (out_file_stat.st_mode & 077) != 0 + && chmod (output_name.ds_string, out_file_stat.st_mode & 07700) < 0) + { + error (0, errno, "%s: chmod", output_name.ds_string); + continue; + } + res = 0; + } if (res < 0 && create_dir_flag) { create_all_directories (output_name.ds_string); - res = mkdir (output_name.ds_string, in_file_stat.st_mode); + res = mkdir (output_name.ds_string, in_file_stat.st_mode & ~077); } if (res < 0) { @@ -283,12 +302,12 @@ if (link_res < 0) { - res = mknod (output_name.ds_string, in_file_stat.st_mode, + res = mknod (output_name.ds_string, in_file_stat.st_mode & ~077, in_file_stat.st_rdev); if (res < 0 && create_dir_flag) { create_all_directories (output_name.ds_string); - res = mknod (output_name.ds_string, in_file_stat.st_mode, + res = mknod (output_name.ds_string, in_file_stat.st_mode & ~077, in_file_stat.st_rdev); } if (res < 0)