1
2 #include <stdlib.h>
3 #include <time.h>
4 #include <errno.h>
5 #include <sys/stat.h>
6 #include <sys/time.h>
7
8 #ifdef _WIN32
9 #include <direct.h> /* _mkdir */
10 #include <windows.h>
11 #endif
12
13 #include <Rinternals.h>
14
15 #include "miniz.h"
16 #include "zip.h"
17
R_zip_list(SEXP zipfile)18 SEXP R_zip_list(SEXP zipfile) {
19 const char *czipfile = CHAR(STRING_ELT(zipfile, 0));
20 size_t num_files;
21 unsigned int i;
22 SEXP result = R_NilValue;
23 mz_bool status;
24 mz_zip_archive zip_archive;
25
26 FILE *fh;
27 wchar_t *uzipfile = NULL;
28 size_t uzipfile_len = 0;
29
30 #ifdef _WIN32
31 if (zip__utf8_to_utf16(czipfile, &uzipfile, &uzipfile_len)) {
32 if (uzipfile) free(uzipfile);
33 error("Cannot convert zip file name to unicode");
34 }
35 fh = zip_long_wfopen(uzipfile, L"rb");
36 #else
37 fh = fopen(czipfile, "rb");
38 #endif
39
40 if (fh == NULL) {
41 if (uzipfile) free(uzipfile);
42 error("Cannot open zip file `%s`");
43 }
44
45 fseek(fh, 0, SEEK_END);
46 size_t file_size = ftell(fh);
47 fseek(fh, 0, SEEK_SET);
48
49 memset(&zip_archive, 0, sizeof(zip_archive));
50 status = mz_zip_reader_init_cfile(&zip_archive, fh, file_size, 0);
51 if (!status) {
52 fclose(fh);
53 free(uzipfile);
54 error("Cannot open zip file `%s`", czipfile);
55 }
56
57 num_files = mz_zip_reader_get_num_files(&zip_archive);
58 result = PROTECT(allocVector(VECSXP, 7));
59 SET_VECTOR_ELT(result, 0, allocVector(STRSXP, num_files));
60 SET_VECTOR_ELT(result, 1, allocVector(REALSXP, num_files));
61 SET_VECTOR_ELT(result, 2, allocVector(REALSXP, num_files));
62 SET_VECTOR_ELT(result, 3, allocVector(INTSXP, num_files));
63 SET_VECTOR_ELT(result, 4, allocVector(INTSXP, num_files));
64 SET_VECTOR_ELT(result, 5, allocVector(INTSXP, num_files));
65 SET_VECTOR_ELT(result, 6, allocVector(REALSXP, num_files));
66
67 for (i = 0; i < num_files; i++) {
68 mz_zip_archive_file_stat file_stat;
69 mode_t mode;
70 status = mz_zip_reader_file_stat (&zip_archive, i, &file_stat);
71 if (!status) goto cleanup;
72
73 SET_STRING_ELT(VECTOR_ELT(result, 0), i, mkChar(file_stat.m_filename));
74 REAL(VECTOR_ELT(result, 1))[i] = file_stat.m_comp_size;
75 REAL(VECTOR_ELT(result, 2))[i] = file_stat.m_uncomp_size;
76 INTEGER(VECTOR_ELT(result, 3))[i] = (int) file_stat.m_time;
77 zip_get_permissions(&file_stat, &mode);
78 INTEGER(VECTOR_ELT(result, 4))[i] = (int) mode;
79 INTEGER(VECTOR_ELT(result, 5))[i] = (int) file_stat.m_crc32;
80 REAL(VECTOR_ELT(result, 6))[i] = (double) file_stat.m_local_header_ofs;
81 }
82
83 fclose(fh);
84 free(uzipfile);
85 mz_zip_reader_end(&zip_archive);
86 UNPROTECT(1);
87 return result;
88
89 cleanup:
90 fclose(fh);
91 mz_zip_reader_end(&zip_archive);
92 error("Cannot list zip entries, corrupt zip file?");
93 return result;
94 }
95
R_zip_error_handler(const char * reason,const char * file,int line,int zip_errno,int eno)96 void R_zip_error_handler(const char *reason, const char *file,
97 int line, int zip_errno, int eno) {
98 error("zip error: `%s` in file `%s:%i`", reason, file, line);
99 }
100
R_zip_zip(SEXP zipfile,SEXP keys,SEXP files,SEXP dirs,SEXP mtime,SEXP compression_level,SEXP append)101 SEXP R_zip_zip(SEXP zipfile, SEXP keys, SEXP files, SEXP dirs, SEXP mtime,
102 SEXP compression_level, SEXP append) {
103
104 const char *czipfile = CHAR(STRING_ELT(zipfile, 0));
105 const char **ckeys = 0, **cfiles = 0;
106 int *cdirs = INTEGER(dirs);
107 double *cmtimes = REAL(mtime);
108 int ccompression_level = INTEGER(compression_level)[0];
109 int cappend = LOGICAL(append)[0];
110 int i, n = LENGTH(keys);
111
112 /* The reason we allocate n+1 here is that otherwise R_alloc will
113 return a NULL pointer for n == 0, and zip_unzip interprets that
114 as extracting the whole archive. */
115
116 ckeys = (const char **) R_alloc(n + 1, sizeof(char*));
117 cfiles = (const char **) R_alloc(n + 1, sizeof(char*));
118 for (i = 0; i < n; i++) {
119 ckeys [i] = CHAR(STRING_ELT(keys, i));
120 cfiles[i] = CHAR(STRING_ELT(files, i));
121 }
122
123 zip_set_error_handler(R_zip_error_handler);
124
125 zip_zip(czipfile, n, ckeys, cfiles, cdirs, cmtimes, ccompression_level,
126 cappend);
127
128 return R_NilValue;
129 }
130
R_zip_unzip(SEXP zipfile,SEXP files,SEXP overwrite,SEXP junkpaths,SEXP exdir)131 SEXP R_zip_unzip(SEXP zipfile, SEXP files, SEXP overwrite, SEXP junkpaths,
132 SEXP exdir) {
133
134 const char *czipfile = CHAR(STRING_ELT(zipfile, 0));
135 int coverwrite = LOGICAL(overwrite)[0];
136 int cjunkpaths = LOGICAL(junkpaths)[0];
137 const char *cexdir = CHAR(STRING_ELT(exdir, 0));
138 int allfiles = isNull(files);
139 int i, n = allfiles ? 0 : LENGTH(files);
140 const char **cfiles = 0;
141
142 if (!isNull(files)) {
143 /* The reason we allocate n+1 here is that otherwise R_alloc will
144 return a NULL pointer for n == 0, and zip_unzip interprets that
145 as extracting the whole archive. */
146 cfiles = (const char**) R_alloc(n + 1, sizeof(char*));
147 for (i = 0; i < n; i++) cfiles[i] = CHAR(STRING_ELT(files, i));
148 }
149
150 zip_set_error_handler(R_zip_error_handler);
151 zip_unzip(czipfile, cfiles, n, coverwrite, cjunkpaths, cexdir);
152
153 return R_NilValue;
154 }
155
156
157 #ifdef __APPLE__
158 #include <fcntl.h>
159 #include <unistd.h>
160 #endif
161
162
163 #ifdef _WIN32
164
165 int zip__utf8_to_utf16(const char* s, wchar_t** buffer,
166 size_t *buffer_size);
167
168 #endif
169
R_make_big_file(SEXP filename,SEXP mb)170 SEXP R_make_big_file(SEXP filename, SEXP mb) {
171
172 #ifdef _WIN32
173
174 const char *cfilename = CHAR(STRING_ELT(filename, 0));
175 LARGE_INTEGER li;
176
177 wchar_t *wfilename = NULL;
178 size_t wfilename_size = 0;
179
180 if (zip__utf8_to_utf16(cfilename, &wfilename, &wfilename_size)) {
181 error("utf8 -> utf16 conversion");
182 }
183
184 HANDLE h = CreateFileW(
185 wfilename,
186 GENERIC_WRITE,
187 FILE_SHARE_DELETE,
188 NULL,
189 CREATE_NEW,
190 FILE_ATTRIBUTE_NORMAL,
191 NULL);
192 if (h == INVALID_HANDLE_VALUE) {
193 if (wfilename) free(wfilename);
194 error("Cannot create big file");
195 }
196
197 li.QuadPart = INTEGER(mb)[0] * 1024.0 * 1024.0;
198 li.LowPart = SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
199
200 if (0xffffffff == li.LowPart && GetLastError() != NO_ERROR) {
201 CloseHandle(h);
202 if (wfilename) free(wfilename);
203 error("Cannot create big file");
204 }
205
206 if (!SetEndOfFile(h)) {
207 CloseHandle(h);
208 if (wfilename) free(wfilename);
209 error("Cannot create big file");
210 }
211
212 if (wfilename) free(wfilename);
213 CloseHandle(h);
214
215 #endif
216
217 #ifdef __APPLE__
218
219 const char *cfilename = CHAR(STRING_ELT(filename, 0));
220 int fd = open(cfilename, O_WRONLY | O_CREAT);
221 double sz = INTEGER(mb)[0] * 1024.0 * 1024.0;
222 fstore_t store = { F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, (off_t) sz };
223 // Try to get a continous chunk of disk space
224 int ret = fcntl(fd, F_PREALLOCATE, &store);
225 if (-1 == ret) {
226 // OK, perhaps we are too fragmented, allocate non-continuous
227 store.fst_flags = F_ALLOCATEALL;
228 ret = fcntl(fd, F_PREALLOCATE, &store);
229 if (-1 == ret) error("Cannot create big file");
230 }
231
232 if (ftruncate(fd, (off_t) sz)) {
233 close(fd);
234 error("Cannot create big file");
235 }
236
237 close(fd);
238
239 #endif
240
241 #ifndef _WIN32
242 #ifndef __APPLE__
243 error("cannot create big file (only implemented for windows and macos");
244 #endif
245 #endif
246
247 return R_NilValue;
248 }
249