Skip to content

Commit 31d9df1

Browse files
tommadyvrmiguel
andauthored
Fix folder softlink is not preserved after packing (#850)
* Fix folder softlink is not preserved after packing Signed-off-by: tommady <[email protected]> * enhance test case Signed-off-by: tommady <[email protected]> * fix test case Signed-off-by: tommady <[email protected]> * add changelog Signed-off-by: tommady <[email protected]> * fixup windows zip while unpacking should use symlink_dir Signed-off-by: tommady <[email protected]> * address comment Signed-off-by: tommady <[email protected]> --------- Signed-off-by: tommady <[email protected]> Co-authored-by: Vinícius Miguel <[email protected]>
1 parent 2e2fe80 commit 31d9df1

File tree

4 files changed

+34
-10
lines changed

4 files changed

+34
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Categories Used:
4343
- Fix tar extraction count when --quiet [\#824](https://github.com/ouch-org/ouch/pull/824) ([marcospb19](https://github.com/marcospb19))
4444
- Fix 7z BadSignature error when compressing and then listing [\#819](https://github.com/ouch-org/ouch/pull/819) ([tommady](https://github.com/tommady))
4545
- Fix unpacking with merge flag failing without --dir flag [\#826](https://github.com/ouch-org/ouch/pull/826) ([tommady](https://github.com/tommady))
46+
- Fix folder softlink is not preserved after packing [\#850](https://github.com/ouch-org/ouch/pull/850) ([tommady](https://github.com/tommady))
4647

4748
### Tweaks
4849

src/archive/tar.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ pub fn unpack_archive(reader: Box<dyn Read>, output_folder: &Path, quiet: bool)
4040

4141
#[cfg(unix)]
4242
std::os::unix::fs::symlink(&target, &full_path)?;
43+
44+
// FIXME: how to detect whether the destination is a folder or a regular file?
45+
// regular file should use fs::symlink_file
46+
// folder should use fs::symlink_dir
4347
#[cfg(windows)]
4448
std::os::windows::fs::symlink_file(&target, &full_path)?;
4549
}
@@ -141,9 +145,7 @@ where
141145
info(format!("Compressing '{}'", EscapedPathDisplay::new(path)));
142146
}
143147

144-
if path.is_dir() {
145-
builder.append_dir(path, path)?;
146-
} else if path.is_symlink() && !follow_symlinks {
148+
if !follow_symlinks && path.symlink_metadata()?.is_symlink() {
147149
let target_path = path.read_link()?;
148150

149151
let mut header = tar::Header::new_gnu();
@@ -155,6 +157,8 @@ where
155157
.detail("Unexpected error while trying to read link")
156158
.detail(format!("Error: {err}."))
157159
})?;
160+
} else if path.is_dir() {
161+
builder.append_dir(path, path)?;
158162
} else {
159163
let mut file = match fs::File::open(path) {
160164
Ok(f) => f,

src/archive/zip.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,21 @@ where
6464
if !quiet {
6565
info(format!("File {} extracted to \"{}\"", idx, file_path.display()));
6666
}
67-
fs::create_dir_all(&file_path)?;
67+
68+
let mode = file.unix_mode();
69+
let is_symlink = mode.is_some_and(|mode| mode & 0o170000 == 0o120000);
70+
71+
if is_symlink {
72+
let mut target = String::new();
73+
file.read_to_string(&mut target)?;
74+
75+
#[cfg(unix)]
76+
std::os::unix::fs::symlink(&target, &file_path)?;
77+
#[cfg(windows)]
78+
std::os::windows::fs::symlink_dir(&target, file_path)?;
79+
} else {
80+
fs::create_dir_all(&file_path)?;
81+
}
6882
}
6983
_is_file @ false => {
7084
if let Some(path) = file_path.parent() {
@@ -242,9 +256,7 @@ where
242256
.detail(format!("File at '{path:?}' has a non-UTF-8 name"))
243257
})?;
244258

245-
if metadata.is_dir() {
246-
writer.add_directory(entry_name, options)?;
247-
} else if path.is_symlink() && !follow_symlinks {
259+
if !follow_symlinks && path.symlink_metadata()?.is_symlink() {
248260
let target_path = path.read_link()?;
249261
let target_name = target_path.to_str().ok_or_else(|| {
250262
FinalError::with_title("Zip requires that all directories names are valid UTF-8")
@@ -259,6 +271,8 @@ where
259271
let symlink_options = options.unix_permissions(0o120777);
260272

261273
writer.add_symlink(entry_name, target_name, symlink_options)?;
274+
} else if path.is_dir() {
275+
writer.add_directory(entry_name, options)?;
262276
} else {
263277
#[cfg(not(unix))]
264278
let options = if is_executable::is_executable(path) {

tests/integration.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,8 @@ fn symlink_pack_and_unpack(
689689
let root_path = temp_dir.path();
690690

691691
let src_files_path = root_path.join("src_files");
692-
fs::create_dir_all(&src_files_path)?;
692+
let folder_path = src_files_path.join("folder");
693+
fs::create_dir_all(&folder_path)?;
693694

694695
let mut files_path = ["file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt"]
695696
.into_iter()
@@ -704,10 +705,15 @@ fn symlink_pack_and_unpack(
704705
fs::create_dir_all(&dest_files_path)?;
705706

706707
let symlink_path = src_files_path.join(Path::new("symlink"));
708+
let symlink_folder_path = src_files_path.join(Path::new("symlink_folder"));
707709
#[cfg(unix)]
708710
std::os::unix::fs::symlink(&files_path[0], &symlink_path)?;
711+
#[cfg(unix)]
712+
std::os::unix::fs::symlink(&folder_path, &symlink_folder_path)?;
709713
#[cfg(windows)]
710714
std::os::windows::fs::symlink_file(&files_path[0], &symlink_path)?;
715+
#[cfg(windows)]
716+
std::os::windows::fs::symlink_dir(&folder_path, &symlink_folder_path)?;
711717

712718
files_path.push(symlink_path);
713719

@@ -728,11 +734,10 @@ fn symlink_pack_and_unpack(
728734
.assert()
729735
.success();
730736

731-
assert_same_directory(&src_files_path, &dest_files_path, false);
732737
// check the symlink stand still
733738
for f in dest_files_path.as_path().read_dir()? {
734739
let f = f?;
735-
if f.file_name() == "symlink" {
740+
if f.file_name() == "symlink" || f.file_name() == "symlink_folder" {
736741
assert!(f.file_type()?.is_symlink())
737742
}
738743
}

0 commit comments

Comments
 (0)