XRootD
XrdOssArcZipFile.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O s s A r c Z i p F i l e . h h */
4 /* */
5 /* (c) 2024 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <sys/stat.h>
36 
37 #include <zip.h>
38 
39 #include "XrdOss/XrdOss.hh"
41 #include "XrdOuc/XrdOucEnv.hh"
42 #include "XrdOuc/XrdOucString.hh"
43 #include "XrdSys/XrdSysError.hh"
44 #include "XrdSys/XrdSysFD.hh"
45 
46 /******************************************************************************/
47 /* G l o b a l O b j e c t s */
48 /******************************************************************************/
49 
50 namespace XrdOssArcGlobals
51 {
52 extern XrdSysError Elog;
53 }
54 using namespace XrdOssArcGlobals;
55 
56 /******************************************************************************/
57 /* C o n s t r u c t o r */
58 /******************************************************************************/
59 
60 XrdOssArcZipFile::XrdOssArcZipFile(const char* path, int &rc)
61 {
62  XrdOucEnv zipEnv;
63  int zFD, zrc;
64 
65 // Try to open the file. We only support read mode.
66 //
67  if ((zFD = XrdSysFD_Open(path, O_RDONLY)) < 0)
68  {rc = -errno;
69  return;
70  }
71 
72 // Get the stat information for the archive now using the retrned FD as
73 // as attaching the FD to a zipfile "destroys" the original FD.
74 //
75  if (fstat(zFD, &zFStat)) memset(&zFStat, 0, sizeof(zFStat));
76 
77 // Record path
78 //
79  zPath = strdup(path);
80 
81 // Convert open to archive open
82 //
83  if ((zFile = zip_fdopen(zFD, ZIP_CHECKCONS, &zrc)) == 0)
84  {rc = zip2syserr("fdopen", zrc);
85  close(zFD);
86  return;
87  }
88 }
89 
90 /******************************************************************************/
91 /* D e s t r u c t o r */
92 /******************************************************************************/
93 
95 {
96 // If we have an open subfile, close it
97 //
98  if (zSubFile) Close();
99 
100 // Close the archive itself
101 //
102  if (zFile)
103  {if (zip_close(zFile))
104  {zipEmsg("close", zip_get_error(zFile));
105  zip_discard(zFile);
106  }
107  zFile = 0;
108  }
109 
110 // Free up any storage
111 //
112  if (zPath) free(zPath);
113 }
114 
115 /******************************************************************************/
116 /* C l o s e */
117 /******************************************************************************/
118 
120 {
121  int zrc = 0;
122 
123 // Close the member subfile if it is open
124 //
125  if (zSubFile)
126  {if ((zrc = zip_fclose(zSubFile))) zrc = zip2syserr("close member", zrc);
127  zSubFile = 0;
128  }
129 
130 // Remove all vestigaes of this subfile
131 //
132  if (zMember) {free(zMember); zMember = 0;}
133 
134 // All done
135 //
136  return zrc;
137 }
138 
139 /******************************************************************************/
140 /* O p e n */
141 /******************************************************************************/
142 
143 int XrdOssArcZipFile::Open(const char* member)
144 {
145  int rc;
146 
147 // Make sure we have an open archive here
148 //
149  if (zFile == 0) return -EBADF;
150 
151 // If an archive member is alreaddy open then close it
152 //
153  if (zSubFile)
154  {if ((rc = zip_fclose(zSubFile))) zip2syserr("close", rc, true);
155  free(zMember);
156  zMember = 0;
157  zSubFile = 0;
158  }
159 
160 // Set member name we are handling
161 //
162  if (zMember) free(zMember);
163  zMember = strdup(member);
164 
165 // Open the archive member
166 //
167  zSubFile = zip_fopen(zFile, zMember, 0);
168  if (zSubFile == 0) return zip2syserr("open", zip_get_error(zFile));
169 
170 // We should check if this is a compressed archive as ther can onl be read
171 // sequentially. However, that is not supported until v 10.1 and the current
172 // rpms available at 1.7. So, we punt on this and assume it not compressed and
173 // is seekable. Note that compressed files are not seekable.
174 //
175 // zSeek = zip_file_is_seekable(zSubFile) == 1;
176  zSeek = true;
177  zOffset = 0;
178 
179 // All done
180 //
181  return 0;
182 }
183 
184 /******************************************************************************/
185 /* R e a d */
186 /******************************************************************************/
187 
188 ssize_t XrdOssArcZipFile::Read(void *buff, off_t offset, size_t blen)
189 {
190 // Make sure this file is actually open
191 //
192  if (zSubFile == 0) return -EBADF;
193  if (!blen) return 0;
194 
195 // If this file does not support seeks, return a seek error if a seek wanted
196 //
197  if (offset != zOffset)
198  {if (!zSeek) return -ESPIPE;
199  if (zip_fseek(zSubFile, offset, SEEK_SET))
200  return zip2syserr("seek into", zip_file_get_error(zSubFile));
201  zEOF = false;
202  }
203 
204 // Check if we have reached EOF
205 //
206  if (zEOF) return 0;
207 
208 // Perform the read
209 //
210  zip_int64_t ret = zip_fread(zSubFile, buff, blen);
211  if (ret < 0)
212  return zip2syserr("read", zip_file_get_error(zSubFile));
213 
214 // Update offset and check for EOF
215 //
216  zOffset += ret;
217  if (ret < (zip_int64_t)blen) zEOF = true;
218  return ret;
219 }
220 
221 /******************************************************************************/
222 /* S t a t */
223 /******************************************************************************/
224 
225 int XrdOssArcZipFile::Stat(struct stat& buf)
226 {
227  zip_stat_t zStat;
228 
229 // Make sure this file is actually open
230 //
231  if (zSubFile == 0) return -EBADF;
232 
233 // Iniialize the stat buffer
234 //
235  memcpy(&buf, &zFStat, sizeof(struct stat));
236 
237 // Clear the stat structures
238 //
239  zip_stat_init(&zStat);
240 
241 // Get information
242 //
243  if (zip_stat(zFile, zMember, 0, &zStat) < 0)
244  return zip2syserr("stat", zip_get_error(zFile));
245 
246 // Copy the relevant information
247 //
248  if (zStat.valid & ZIP_STAT_INDEX) buf.st_ino = zStat.index;
249  if (zStat.valid & ZIP_STAT_SIZE) buf.st_size = zStat.size;
250 
251 // All done
252 //
253  return 0;
254 }
255 
256 /******************************************************************************/
257 
258 int XrdOssArcZipFile::Stat(const char* mName, struct stat& buf)
259 {
260  zip_stat_t zStat;
261 
262 // Iniialize the stat buffer
263 //
264  memcpy(&buf, &zFStat, sizeof(struct stat));
265 
266 // Clear the stat structures
267 //
268  zip_stat_init(&zStat);
269 
270 // Get information
271 //
272  if (zip_stat(zFile, mName, 0, &zStat) < 0)
273  return zip2syserr("stat", zip_get_error(zFile));
274 
275 // Copy the relevant information
276 //
277  if (zStat.valid & ZIP_STAT_INDEX) buf.st_ino = zStat.index;
278  if (zStat.valid & ZIP_STAT_SIZE) buf.st_size = zStat.size;
279 
280 // All done
281 //
282  return 0;
283 }
284 
285 /******************************************************************************/
286 /* z i p E m s g */
287 /******************************************************************************/
288 
289 void XrdOssArcZipFile::zipEmsg(const char *what, zip_error_t* zerr)
290 {
291  XrdOucString target(zPath, 280);
292 
293 // Create target name
294 //
295  target += '[';
296  if (zMember) target += zMember;
297  target += "];";
298 
299 // Create starting error message
300 //
301  char eText[80];
302  snprintf(eText, sizeof(eText), "unable to %s", what);
303 
304 // Issue message
305 //
306  Elog.Emsg("ZipFile", eText, target.c_str(), zip_error_strerror(zerr));
307 }
308 
309 /******************************************************************************/
310 /* Private: z i p 2 s y s e r r */
311 /******************************************************************************/
312 
313 int XrdOssArcZipFile::zip2syserr(const char *what, zip_error_t* zerr, bool msg)
314 {
315  int retc = zip_error_code_zip(zerr);
316  if (retc != ZIP_ER_OK)
317  {switch(retc)
318  {case ZIP_ER_CRC: retc = EILSEQ; break;
319  case ZIP_ER_EXISTS: retc = EEXIST; break;
320  case ZIP_ER_INCONS: retc = ENOEXEC; break;
321  case ZIP_ER_INUSE: retc = EBUSY; break;
322  case ZIP_ER_INVAL: retc = EINVAL; break;
323  case ZIP_ER_MEMORY: retc = ENOMEM; break;
324  case ZIP_ER_NOENT: retc = ENOENT; break;
325  case ZIP_ER_NOZIP: retc = ENOTBLK; break;
326  case ZIP_ER_OPNOTSUPP: retc = EOPNOTSUPP; break;
327  case ZIP_ER_RDONLY: retc = EROFS; break;
328  case ZIP_ER_READ: retc = EIO; break;
329  case ZIP_ER_SEEK: retc = ESPIPE; break;
330  case ZIP_ER_WRITE: retc = EIO; break;
331  default: retc = EDOM; break;
332  }
333  } else {
334  retc = zip_error_code_system(zerr);
335  if (retc == 0) retc = ENOMSG;
336  else if (retc < 0) retc = -retc;
337  }
338  if (msg) zipEmsg(what, zerr);
339  zip_error_fini(zerr);
340  return -retc;
341 }
342 
343 int XrdOssArcZipFile::zip2syserr(const char *what, int zrc, bool msg)
344 {
345  zip_error_t zerr;
346  zip_error_init_with_code(&zerr, zrc);
347  return zip2syserr(what, &zerr, msg);
348 }
zip_error zip_error_t
#define close(a)
Definition: XrdPosix.hh:48
#define fstat(a, b)
Definition: XrdPosix.hh:109
#define stat(a, b)
Definition: XrdPosix.hh:105
int Stat(struct stat &buf)
XrdOssArcZipFile(const char *path, int &rc)
ssize_t Read(void *buff, off_t offset, size_t blen)
int Open(const char *member)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:116
CloseImpl< false > Close(Ctx< File > file, time_t timeout=0)
Factory for creating CloseImpl objects.
XrdSysError Elog(0, "OssArc_")