Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zip_open fails with symbolic link on Windows #382

Open
ktakahashimtb opened this issue May 11, 2023 · 8 comments
Open

zip_open fails with symbolic link on Windows #382

ktakahashimtb opened this issue May 11, 2023 · 8 comments
Labels
bug libzip doesn't behave as expected. help wanted

Comments

@ktakahashimtb
Copy link

ktakahashimtb commented May 11, 2023

Describe the Bug
On Windows, zip_open fails when a path to a symbolic link is given, which points to a zip file.

Expected Behavior
zip_open opens the .zip file referenced by the symbolic link

Observed Behavior
zip_open fails with error code 28 (ZIP_ER_OPNOTSUPP).

To Reproduce

int error = 0;
const char* path_to_symbolic_link = ...;
zip_open(path_to_symbolic_link, ZIP_RDONLY, &error);

To create a symbolic link on Windows, 1) open command prompt with Admin privilege, 2) run "mklink <name> <target>"

libzip Version
v1.7.0 and newer

Operating System
Windows

Test Files
Any zip file.

Additional context
Not sure if this is supposed to work or not, but I see it worked up until version 1.6.1.
On version 1.7.3, the returned error code is 19 (ZIP_ER_NOZIP) instead.

@ktakahashimtb ktakahashimtb added the bug libzip doesn't behave as expected. label May 11, 2023
@0-wiz-0
Copy link
Member

0-wiz-0 commented May 19, 2023

We have no Windows expertise.
I wasn't even aware that Windows now supports symlinks. I thought this was implemented as .LNK file (which is a normal file which references the other file in some way.)
One possible problem might be that the link is opened as a zip archive instead of the file referenced by the link.
You'll have to debug this yourself, sorry.

@arsnyder16
Copy link

@0-wiz-0 This commit looks suspicious e049c609 (FILE_ATTRIBUTE_REPARSE_POINT ) should we check with Khaled Mardam-Bey since this appears to be his suggestion. Maybe the windows expert we are looking for?

@0-wiz-0
Copy link
Member

0-wiz-0 commented May 24, 2023

No, I don't think he is.
But that's a good idea - removing | FILE_ATTRIBUTE_REPARSE_POINT there might improve the situation for symlinks.
@ktakahashimtb Can you please give this a try?

@ktakahashimtb
Copy link
Author

ktakahashimtb commented May 24, 2023

@0-wiz-0 @arsnyder16 Thanks for the feedback!

I removed FILE_ATTRIBUTE_REPARSE_POINT on my local build and that appears to fix the issue!

I removed FILE_ATTRIBUTE_REPARSE_POINT, and it still fails at a different point. Now zip_open returns error code 19 instead of 28. This looks to be because ::GetFileAttributesEx returns 0 for the file size so st->size is set to 0 several lines below.

I also found that one way to workaround this issue is to call zip_source_filep_create followed by zip_open_from_source instead of zip_open. This way we're passing FILE* instead of filepath, and does not call into a function which checks on FILE_ATTRIBUTE_REPASE_POINT. If anyone else is hitting this problem, this may be an option.

@0-wiz-0
Copy link
Member

0-wiz-0 commented May 24, 2023

In your testing, please also try changing the file and report back if the symlinks is overwritten with a file, or the symlink target is replaced instead.

@ktakahashimtb
Copy link
Author

@0-wiz-0 Would you like to know how updating the file via symlink works on Windows in general or how libzip updates the file?

If it's the former, I tried notepad and ms word, and the target of the symlink is updated not the symlink file itself.

If the latter, my workaround seems to open the archive in readonly mode so my attempt of updating and overwriting the file did not do the trick. zip_open has this issue to begin with so I cannot open the archive to modify and save. I'm a newbie using libzip so I'm not sure if there are other ways to update archive with libzip calls. Any suggestion?

@ktakahashimtb
Copy link
Author

ktakahashimtb commented May 25, 2023

@0-wiz-0 I have a good news to share 😄

Spent some time trying to make zip_open work with removing FILE_ATTRIBUTE_REPARSE_POINT and a few more tweaking.

With GetFileAttributesEx call, the size of the file we receive is the size of the symbolic file itself, not the target.

We can instead first get the file handle by calling CreateFile (which returns the HANDLE of the target if we don't specify FILE_FLAG_OPEN_REPARSE_POINT. Then, call GetFileInformationByHandle, which returns the same kind of information (size, attributes, timestamp) as GetFileAttributesEx.

With this change, I can now both read and write to the target file of the symlink.

With this change, I can read the contents (testing with zip_get_num_entries) of the symlink's target file.

The write, however, replaces the symlink file itself. This seems because libzip calls MoveFileExW to move the contents of the temporarily created file to the actual file opened. With symlink, symlink file itself is updated so it ceases to be a symblic file.

@0-wiz-0
Copy link
Member

0-wiz-0 commented May 26, 2023

That's good progress.
I was expecting that the symlink would be replaced with a file, that's why I asked...
Please let us know if you make progress on that end as well - we're looking forward to your patch 😃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug libzip doesn't behave as expected. help wanted
Projects
None yet
Development

No branches or pull requests

4 participants