ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I just want to extract the contents into a directory. I have no problem opening the archive, getting the number of files in the archive, using a for loop for the number of files to stat the files by index, open a file with the filename that corresponds to that index, run a read and write while loop, then close the file and close the zip archive. However, the issue is that some filenames that I get from the zip_stat_index are prepended with a directory. It would have been nice if the directory was listed on its own as a separate index but it is not. I don't see any options in the open system call to create one or more parent directories if the filename being opened/created is under one or more directories.
Here is my code so far
Code:
#include <zip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 4096
int main()
{
int i = 0;
int x = 0;
int n = 0;
int file = 0;
zip_int64_t *zipfile;
char buf[BUFSIZE];
struct zip *z;
struct zip_stat st;
int err = 0;
z = zip_open("/usr/share/httpd/mapcrafter/worlds/Freehold/freehold.zip", 0, &err);
zip_stat_init(&st);
x = zip_get_num_files(z);
printf("There are %i number of files in this archive.\n", x);
printf("Here is a list of the files in the archive.\n");
for (i = 0; i < x; i++) {
zip_stat_index(z, i, 0, &st);
file = open(st.name, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
zipfile = zip_fopen_index(z, i, 0);
while ((n = read(zipfile, buf, sizeof buf)) > 0)
write(file, buf, n);
close(file);
zip_fclose(zipfile);
printf("Copied %s...\n", st.name);
}
zip_close(z);
return 0;
}
I mean do I really have to stat each index and scan for "/" to see if that index contains a directory? There must be an easier way. Here are the docs for the libzip library. Thank you!!
the issue is that some filenames that I get from the zip_stat_index are prepended with a directory. It would have been nice if the directory was listed on its own as a separate index but it is not.
Code:
There are 222 number of files in this archive.
Here is a list of the files in the archive.
Copied DIM1/region/...
Copied DIM1/region/r.0.0.mca...
Copied DIM1/region/r.0.1.mca...
Copied DIM1/region/r.0.-1.mca...
Copied DIM1/region/r.0.2.mca...
I haven't checked the whole stat output inclusively, but I was thinking that what you said, "It would have been nice if the directory was listed on its own as a separate index" is exactly what things like zip and tar do.
Is not /DIM1/region/ a directory? And therefore it is there.
Added: OK a more detailed review shows that this is not universal. Plus it doesn't show DIM1/... for instance or some number of other ones.
Does a command line listing of this archive show the same 222 entries? Other than that, I have no understanding any better than you.
Yea you're right, I unzipped it and I got 230 entries instead of 222. Ok thanks.
-Tristan
Wow! What's up with that library then?!? I mean ... is it NOT the same code being used by the command line? Or nearly/very close? Maybe check that out. I can see that there would be several versions, or potentially a different library...
You should create a `pathopen` that splits filenames and creates the missing directories. While doing this, you should check for '..' as directoy-name, e.g. `src/../../../../etc/passwd`.
Note: opening an existing file can be problematic (e.g. symlink attack or text-file-busy problems) instead you could create the file on a temporary name in the same directory then `rename` to the final name.
I mean do I really have to stat each index and scan for "/" to see if that index contains a directory?
Yes. Usually there will be a separate entry for the directory in a ZIP archive (and there was in your case; it was the entry ending in a slash) but in general that’s not a guarantee. If you want your code to be robust, you should split and the name and check for all the directories on the path.
Quote:
Originally Posted by NevemTeve
Note: opening an existing file can be problematic (e.g. symlink attack or text-file-busy problems)
Worth noting that symlink attack may be performed with the leaf file name as well as with a directory on the path. E.g. one could craft a ZIP archive with ‘foo’ being symbolic link to ‘/etc/passwd’ and then another entry which overwrites contents of ‘foo’ but one could also craft a ZIP archive with ‘foo’ being symbolic link to ‘/etc’ and then have another entry ‘foo/passwd’ which overwrites contents of ‘passwd’.
To combat that, a good extracting tool should verify that whatever it creates is under the directory it was told to extract the archive into.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.