[PATCH setup 05/11] Add separate symlink-creation phase when extracting archive
Jon Turney
jon.turney@dronecode.org.uk
Tue Aug 10 17:02:22 GMT 2021
Add a separate symlink-creation phase when extracting an archive, by
ignoring symlinks on the first pass, rewinding the archive, and
then extracting only symlinks on the second pass.
This helps a lot with native symlinks (which require the destination to
exist when created, so we can determine if it is a file or directory).
Alternative implementations:
We could collect symlinks, and defer making them until the end of
extracting the archive. We'd also need to report errors if making those
symlinks failed.
We could close and re-open the archive, rather than rewinding it. Error
handling if the archive isn't accessible the second time could be
complex.
---
install.cc | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/install.cc b/install.cc
index cec31a9..de98b99 100644
--- a/install.cc
+++ b/install.cc
@@ -99,7 +99,8 @@ class Installer
HWND owner,
io_stream *pkgfile,
archive *tarstream,
- io_stream *lst);
+ io_stream *lst,
+ bool symlink_phase);
};
Installer::Installer() : errors(0)
@@ -539,7 +540,12 @@ Installer::installOne (packagemeta &pkgm, const packageversion &ver,
Log (LOG_PLAIN) << "Extracting from " << source.Cached () << endLog;
bool error_in_this_package = _installOne(pkgm, prefixURL, prefixPath, owner,
- pkgfile, tarstream, lst);
+ pkgfile, tarstream, lst, false);
+ if (tarstream->seek(0, IO_SEEK_SET) == -1)
+ Log (LOG_PLAIN) << "Error rewinding to extract symlinks" << source.Cached () << endLog;
+
+ error_in_this_package |= _installOne(pkgm, prefixURL, prefixPath, owner,
+ pkgfile, tarstream, lst, true);
if (lst)
delete lst;
@@ -562,7 +568,8 @@ Installer::_installOne (packagemeta &pkgm,
HWND owner,
io_stream *pkgfile,
archive *tarstream,
- io_stream *lst)
+ io_stream *lst,
+ bool symlink_phase)
{
bool error_in_this_package = false;
bool ignoreInUseErrors = false;
@@ -571,6 +578,12 @@ Installer::_installOne (packagemeta &pkgm,
std::string fn;
while ((fn = tarstream->next_file_name ()).size ())
{
+ if (symlink_phase != (tarstream->next_file_type () == ARCHIVE_FILE_SYMLINK))
+ {
+ tarstream->skip_file();
+ continue;
+ }
+
std::string canonicalfn = prefixPath + fn;
// pathnames starting "." (i.e. dotfiles in the root directory) are
--
2.32.0
More information about the Cygwin-apps
mailing list