VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/zip/pkzipvfs.cpp@ 51701

Last change on this file since 51701 was 51701, checked in by vboxsync, 11 years ago

elder gcc false positive warning

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.8 KB
Line 
1/* $Id: pkzipvfs.cpp 51701 2014-06-23 20:26:09Z vboxsync $ */
2/** @file
3 * IPRT - PKZIP Virtual Filesystem.
4 */
5
6/*
7 * Copyright (C) 2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/******************************************************************************
29 * Header Files *
30 ******************************************************************************/
31#include <iprt/zip.h>
32#include <iprt/assert.h>
33#include <iprt/err.h>
34#include <iprt/file.h>
35#include <iprt/mem.h>
36#include <iprt/poll.h>
37#include <iprt/string.h>
38#include <iprt/vfs.h>
39#include <iprt/vfslowlevel.h>
40#include <iprt/stream.h>
41
42
43/*******************************************************************************
44* Structures and Typedefs *
45*******************************************************************************/
46/* See http://www.pkware.com/documents/casestudies/APPNOTE.TXT */
47
48/**
49 * PKZip Local File Header.
50 */
51#pragma pack(1)
52typedef struct RTZIPPKZIPLOCALFILEHDR
53{
54 /** Magic value, see RTZIPPKZIPLOCALFILEHDR_MAGIC. */
55 uint32_t u32Magic;
56 /** Minimum version needed to extract. */
57 uint16_t u16Version;
58 /** General purpose bit flag. */
59 uint16_t fFlags;
60 /** Compression method. See RTZIPPKZIP_COMP_METHOD_XXX. */
61 uint16_t u16ComprMethod;
62 /** Last modified time, MS-DOS format: HHHHHMMM MMMSSSSS, multiply seconds by 2 */
63 uint16_t u16LastModifiedTime;
64 /** Last modified date, MS-DOS format: YYYYYYYM MMMDDDDD, year starts at 1980 */
65 uint16_t u16LastModifiedDate;
66 /** Checksum. */
67 uint32_t u32Crc;
68 /** Compressed size. */
69 uint32_t cbCompressed;
70 /** Uncompressed size. */
71 uint32_t cbUncompressed;
72 /** Length of the file name. */
73 uint16_t cbFilename;
74 /** Length of the extra field. */
75 uint16_t cbExtra;
76 /** Start of the file name. */
77 uint8_t u8Filename;
78} RTZIPPKZIPLOCALFILEHDR;
79#pragma pack()
80AssertCompileSize(RTZIPPKZIPLOCALFILEHDR, 30+1);
81/** Pointer to PKZip Local File Header. */
82typedef RTZIPPKZIPLOCALFILEHDR *PRTZIPPKZIPLOCALFILEHDR;
83
84#define RTZIPPKZIPLOCALFILEHDR_MAGIC RT_MAKE_U32_FROM_U8('P','K','\003','\004')
85
86/**
87 * PKZip compression method.
88 */
89typedef enum RTZIPPKZIP_COMP_METHOD
90{
91 /** No compression */
92 RTZIPPKZIP_COMP_METHOD_STORED = 0,
93 /** Shrunk */
94 RTZIPPKZIP_COMP_METHOD_SHRUNK = 1,
95 /** Reduced with compression factor 1 */
96 RTZIPPKZIP_COMP_METHOD_REDUCED1 = 2,
97 /** Reduced with compression factor 2 */
98 RTZIPPKZIP_COMP_METHOD_REDUCED2 = 3,
99 /** Reduced with compression factor 3 */
100 RTZIPPKZIP_COMP_METHOD_REDUCED3 = 4,
101 /** Reduced with compression factor 4 */
102 RTZIPPKZIP_COMP_METHOD_REDUCED4 = 5,
103 /** Imploded */
104 RTZIPPKZIP_COMP_METHOD_IMPLODED = 6,
105 /** Deflated */
106 RTZIPPKZIP_COMP_METHOD_DEFLATED = 8,
107 /** Deflated64 */
108 RTZIPPKZIP_COMP_METHOD_DEFLATED64 = 9,
109 /* Compressed using bzip2 */
110 RTZIPPKZIP_COMP_METHOD_BZIP2 = 12,
111 /** Compressed using LZMA */
112 RTZIPPKZIP_COMP_METHOD_LZMA = 14
113} RTZIPPKZIP_COMP_METHOD;
114
115/**
116 * PKZip Central Directory Header.
117 */
118#pragma pack(1)
119typedef struct RTZIPPKZIPCENTRDIRHDR
120{
121 /** The magic value. See RTZIPPKZIPCENTRDIRHDR_MAGIC. */
122 uint32_t u32Magic;
123 /** The version used for creating the item. */
124 uint16_t u16VerMade;
125 /** The minimum version required for extracting the item. */
126 uint16_t u16VerRequired;
127 /** General purpose flags. */
128 uint16_t fFlags;
129 /** Compresstion method. See RTZIPPKZIP_COMP_METHOD_XXX */
130 uint16_t u16ComprMethod;
131 /** Last modified time, MS-DOS format: HHHHHMMM MMMSSSSS, multiply seconds by 2 */
132 uint16_t u16LastModifiedTime;
133 /** Last modified date, MS-DOS format: YYYYYYYM MMMDDDDD, year starts at 1980 */
134 uint16_t u16LastModifiedDate;
135 /** Checksum. */
136 uint32_t u32Crc;
137 /** Compressed size. */
138 uint32_t cbCompressed;
139 /** Uncompressed size. */
140 uint32_t cbUncompressed;
141 /** Length of the object file name. */
142 uint16_t cbFilename;
143 /** Length of the extra field. */
144 uint16_t cbExtra;
145 /** Length of the object comment. */
146 uint16_t cbComment;
147 /** The number of the disk on which this file begins. */
148 uint16_t iDiskStart;
149 /** Internal attributes. */
150 uint16_t u16IntAttrib;
151 /** External attributes. */
152 uint32_t u32ExtAttrib;
153 /** Offset from the start of the first disk on which this file appears to
154 * where the local file header should be found. */
155 uint32_t offLocalFileHeader;
156 /** Start of the file name. */
157 uint8_t u8Filename;
158} RTZIPPKZIPCENTRDIRHDR;
159#pragma pack()
160AssertCompileSize(RTZIPPKZIPCENTRDIRHDR, 46+1);
161/** Pointer to the PKZip Central Directory Header. */
162typedef RTZIPPKZIPCENTRDIRHDR *PRTZIPPKZIPCENTRDIRHDR;
163
164#define RTZIPPKZIPCENTRDIRHDR_MAGIC RT_MAKE_U32_FROM_U8('P','K','\001','\002')
165
166/**
167 * PKZip End of Central Directory Record.
168 */
169#pragma pack(1)
170typedef struct RTZIPPKZIPENDOFCENTRDIRREC
171{
172 /** The magic value. See RTZIPPKZIPENDOFCENTRDIRREC_MAGIC. */
173 uint32_t u32Magic;
174 /** Number of this disk. */
175 uint16_t iThisDisk;
176 /** Number of the disk with the start of the Central Directory. */
177 uint16_t iDiskStartCentrDirectory;
178 /** Number of Central Directory entries on this disk. */
179 uint16_t cCentrDirRecordsThisDisk;
180 /** Number of Central Directory records. */
181 uint16_t cCentrDirRecords;
182 /** Size of the Central Directory in bytes. */
183 uint32_t cbCentrDir;
184 /** Offset of the Central Directory. */
185 uint32_t offCentrDir;
186 /** Size of the comment in bytes. */
187 uint16_t cbComment;
188 /** Start of the comment. */
189 uint8_t u8Comment;
190} RTZIPPKZIPENDOFCENTRDIRREC;
191#pragma pack()
192AssertCompileSize(RTZIPPKZIPENDOFCENTRDIRREC, 22+1);
193/** Pointer to the PKZip End of Central Directory Record. */
194typedef RTZIPPKZIPENDOFCENTRDIRREC const *PCRTZIPPKZIPENDOFCENTRDIRREC;
195
196#define RTZIPPKZIPENDOFCENTRDIRREC_MAGIC RT_MAKE_U32_FROM_U8('P','K','\005','\006')
197
198/**
199 * PKZip ZIP64 End of Central Directory Record.
200 */
201#pragma pack(1)
202typedef struct RTZIPPKZIP64ENDOFCENTRDIRREC
203{
204 /** The magic value. See RTZIPPKZIP64ENDOFCENTRDIRREC_MAGIC. */
205 uint32_t u32Magic;
206 /** Size of Zip64 end of Central Directory Record. */
207 uint64_t cbSizeEocdr;
208 /** The version used for creating the item. */
209 uint16_t u16VerMade;
210 /** The minimum version required for extracting the item. */
211 uint16_t u16VerRequired;
212 /** Number of this disk. */
213 uint32_t iThisDisk;
214 /** Number of the disk with the start of the Central Directory. */
215 uint32_t iDiskStartCentrDirectory;
216 /** Number of Central Directory entries on this disk. */
217 uint64_t cCentrDirRecordsThisDisk;
218 /** Number of Central Directory records. */
219 uint64_t cCentrDirRecords;
220 /** Size of the Central Directory in bytes. */
221 uint64_t cbCentrDir;
222 /** Offset of the Central Directory. */
223 uint64_t offCentrDir;
224} RTZIPPKZIP64ENDOFCENTRDIRREC;
225#pragma pack()
226AssertCompileSize(RTZIPPKZIP64ENDOFCENTRDIRREC, 56);
227/** Pointer to the 64-bit PKZip End of Central Directory Record. */
228typedef RTZIPPKZIP64ENDOFCENTRDIRREC *PRTZIPPKZIP64ENDOFCENTRDIRREC;
229
230#define RTZIPPKZIP64ENDOFCENTRDIRREC_MAGIC RT_MAKE_U32_FROM_U8('P','K','\006','\006')
231
232/**
233 * PKZip ZIP64 End of Central Directory Locator.
234 */
235#pragma pack(1)
236typedef struct RTZIPPKZIP64ENDOFCENTRDIRLOC
237{
238 /** The magic value. See RTZIPPKZIP64ENDOFCENTRDIRLOC_MAGIC. */
239 uint32_t u32Magic;
240 /** Number of the disk with the start of the ZIP64 End of Central Directory. */
241 uint32_t iDiskStartCentrDir;
242 /** Relative offset of the ZIP64 End of Central Directory Record. */
243 uint64_t offEndOfCentrDirRec;
244 /** Total number of disks. */
245 uint32_t cDisks;
246} RTZIPPKZIP64ENDOFCENTRDIRLOC;
247#pragma pack()
248AssertCompileSize(RTZIPPKZIP64ENDOFCENTRDIRLOC, 20);
249
250#define RTZIPPKZIP64ENDOFCENTRDIRLOC_MAGIC RT_MAKE_U32_FROM_U8('P','K','\006','\007')
251
252/**
253 * PKZip ZIP64 Extended Information Extra Field.
254 */
255#pragma pack(1)
256typedef struct RTZIPPKZIP64EXTRAFIELD
257{
258 /** Uncompressed size. */
259 uint64_t cbUncompressed;
260 /** Compressed size. */
261 uint64_t cbCompressed;
262 /** Offset from the start of the first disk on which this file appears to
263 * where the local file header should be found. */
264 uint64_t offLocalFileHeader;
265 /** The number of the disk on which this file begins. */
266 uint32_t iDiskStart;
267} RTZIPPKZIP64EXTRAFIELD;
268#pragma pack()
269/** Pointer to the ZIP64 Extended Information Extra Field. */
270typedef RTZIPPKZIP64EXTRAFIELD *PRTZIPPKZIP64EXTRAFIELD;
271AssertCompileSize(RTZIPPKZIP64EXTRAFIELD, 28);
272
273/**
274 * PKZip reader instance data.
275 */
276typedef struct RTZIPPKZIPREADER
277{
278 /** Set if we have the End of Central Directory record. */
279 bool fHaveEocd;
280 /** The Central Directory header. */
281 RTZIPPKZIPCENTRDIRHDR cdh;
282 /** ZIP64 extended information. */
283 RTZIPPKZIP64EXTRAFIELD cd64ex;
284 /** Set if ZIP64 End of Central Directory Locator is present (archive setting). */
285 bool fZip64Eocd;
286 /** Set if cd64ex is valid for the current file header (object setting). */
287 bool fZip64Ex;
288 /* The name of the current object. */
289 char szName[RTPATH_MAX];
290} RTZIPPKZIPREADER;
291/** Pointer to the PKZip reader instance data. */
292typedef RTZIPPKZIPREADER *PRTZIPPKZIPREADER;
293
294/**
295 * Pkzip object (directory).
296 */
297typedef struct RTZIPPKZIPBASEOBJ
298{
299 /** Pointer to the reader instance data (resides in the filesystem
300 * stream). */
301 PRTZIPPKZIPREADER pPkzipReader;
302 /** The object info with unix attributes. */
303 RTFSOBJINFO ObjInfo;
304} RTZIPPKZIPBASEOBJ;
305/** Pointer to a PKZIP filesystem stream base object. */
306typedef RTZIPPKZIPBASEOBJ *PRTZIPPKZIPBASEOBJ;
307
308/**
309 * Pkzip object (file) represented as a VFS I/O stream.
310 */
311typedef struct RTZIPPKZIPIOSTREAM
312{
313 /** The basic PKZIP object data. */
314 RTZIPPKZIPBASEOBJ BaseObj;
315 /** The number of (uncompressed) bytes in the file. */
316 uint64_t cbFile;
317 /** The current file position at uncompressed file data. */
318 uint64_t offFile;
319 /** The start position of the compressed data in the hVfsIos. */
320 uint64_t offCompStart;
321 /** The current position for decompressing bytes in the hVfsIos. */
322 uint64_t offComp;
323 /** The number of compressed bytes starting at offCompStart. */
324 uint64_t cbComp;
325 /** Set if we have to pass the type function the next time the input
326 * function is called. */
327 bool fPassZipType;
328 /** Set if we've reached the end of the file. */
329 bool fEndOfStream;
330 /** Pkzip compression method for this object. */
331 RTZIPPKZIP_COMP_METHOD enmCompMethod;
332 /** Zip compression method. */
333 RTZIPTYPE enmZipType;
334 /** The decompressor instance. */
335 PRTZIPDECOMP pZip;
336 /** The input I/O stream. */
337 RTVFSIOSTREAM hVfsIos;
338} RTZIPPKZIPIOSTREAM;
339/** Pointer to a the private data of a PKZIP file I/O stream. */
340typedef RTZIPPKZIPIOSTREAM *PRTZIPPKZIPIOSTREAM;
341
342
343/**
344 * PKZip filesystem stream private data. The stream must be seekable!
345 */
346typedef struct RTZIPPKZIPFSSTREAM
347{
348 /** The input I/O stream. */
349 RTVFSIOSTREAM hVfsIos;
350
351 /** The current object (referenced). */
352 RTVFSOBJ hVfsCurObj;
353 /** Pointer to the private data if hVfsCurObj is representing a file. */
354 PRTZIPPKZIPIOSTREAM pCurIosData;
355
356 /** The offset of the first Central Directory header. */
357 uint64_t offFirstCdh;
358 /** The offset of the next Central Directory header. */
359 uint64_t offNextCdh;
360
361 /** Size of the central directory. */
362 uint64_t cbCentrDir;
363 /** Current central directory entry. */
364 uint64_t iCentrDirEntry;
365 /** Number of central directory entries. */
366 uint64_t cCentrDirEntries;
367
368 /** Set if we have the End of Central Directory Record. */
369 bool fHaveEocd;
370 /** Set if we've reached the end of the stream. */
371 bool fEndOfStream;
372 /** Set if we've encountered a fatal error. */
373 int rcFatal;
374
375 /** The PKZIP reader instance data. */
376 RTZIPPKZIPREADER PkzipReader;
377} RTZIPPKZIPFSSTREAM;
378/** Pointer to a the private data of a PKZIP filesystem stream. */
379typedef RTZIPPKZIPFSSTREAM *PRTZIPPKZIPFSSTREAM;
380
381
382
383/**
384 * Decode date/time from DOS format as used in PKZip.
385 */
386static int rtZipPkzipReaderDecodeDosTime(PRTTIMESPEC pTimeSpec, uint16_t u16Time, uint16_t u16Date)
387{
388 RTTIME time;
389 RT_ZERO(time);
390 time.i32Year = ((u16Date & 0xfe00) >> 9) + 1980;
391 time.u8Month = (u16Date & 0x01e0) >> 5;
392 time.u8MonthDay = u16Date & 0x001f;
393 time.u8Hour = (u16Time & 0xf800) >> 11;
394 time.u8Minute = (u16Time & 0x07e0) >> 5;
395 time.u8Second = u16Time & 0x001f;
396 RTTimeNormalize(&time);
397 RTTimeImplode(pTimeSpec, &time);
398 return VINF_SUCCESS;
399}
400
401
402/**
403 * Parse the Local File Header.
404 * Just skip the data as we trust the Central Directory.
405 */
406static int rtZipPkzipParseLocalFileHeader(PRTZIPPKZIPREADER pThis, PRTZIPPKZIPLOCALFILEHDR pLfh, size_t *pcbExtra)
407{
408 if (pLfh->cbFilename >= sizeof(pThis->szName))
409 return VERR_PKZIP_NAME_TOO_LONG;
410
411 *pcbExtra = pLfh->cbFilename + pLfh->cbExtra;
412 return VINF_SUCCESS;
413}
414
415
416/**
417 * Parse the Central Directory Header.
418 */
419static int rtZipPkzipParseCentrDirHeader(PRTZIPPKZIPREADER pThis, PRTZIPPKZIPCENTRDIRHDR pCdh, size_t *pcbExtra)
420{
421 if (pCdh->u32Magic != RTZIPPKZIPCENTRDIRHDR_MAGIC)
422 return VERR_PKZIP_BAD_CDF_HEADER;
423
424 if (pCdh->cbFilename >= sizeof(pThis->szName))
425 return VERR_PKZIP_NAME_TOO_LONG;
426
427 *pcbExtra = pCdh->cbFilename + pCdh->cbExtra + pCdh->cbComment;
428
429 pThis->cdh = *pCdh;
430 pThis->fZip64Ex = false;
431 return VINF_SUCCESS;
432}
433
434
435/**
436 * Return the offset of the Local File Header.
437 */
438static uint64_t rtZipPkzipReaderOffLocalHeader(PRTZIPPKZIPREADER pThis)
439{
440 if (pThis->fZip64Ex && pThis->cdh.offLocalFileHeader == (uint32_t)-1)
441 return pThis->cd64ex.offLocalFileHeader;
442
443 return pThis->cdh.offLocalFileHeader;
444}
445
446
447/**
448 * Return the uncompressed object size.
449 */
450static uint64_t rtZipPkzipReaderUncompressed(PRTZIPPKZIPREADER pThis)
451{
452 if (pThis->fZip64Ex && pThis->cdh.cbUncompressed == (uint32_t)-1)
453 return pThis->cd64ex.cbUncompressed;
454
455 return pThis->cdh.cbUncompressed;
456}
457
458
459/**
460 * Return the compressed object size.
461 */
462static uint64_t rtZipPkzipReaderCompressed(PRTZIPPKZIPREADER pThis)
463{
464 if (pThis->fZip64Ex && pThis->cdh.cbCompressed == (uint32_t)-1)
465 return pThis->cd64ex.cbCompressed;
466
467 return pThis->cdh.cbCompressed;
468}
469
470
471/**
472 * Parse the extra part of the Central Directory Header.
473 */
474static int rtZipPkzipParseCentrDirHeaderExtra(PRTZIPPKZIPREADER pThis, uint8_t *pu8Buf, size_t cb,
475 RTZIPPKZIP_COMP_METHOD *penmCompMethod, uint64_t *pcbCompressed)
476{
477 int rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), (const char*)pu8Buf, pThis->cdh.cbFilename);
478 if (RT_SUCCESS(rc))
479 {
480 uint8_t *offStart = pu8Buf;
481 pu8Buf += pThis->cdh.cbFilename;
482 cb = pThis->cdh.cbExtra;
483 while (cb >= 4)
484 {
485 uint16_t idExtra = *(uint16_t*)pu8Buf;
486 pu8Buf += 2;
487 uint16_t cbExtra = *(uint16_t*)pu8Buf;
488 pu8Buf += 2;
489 cb -= 4;
490
491 if (cb >= cbExtra)
492 {
493 switch (idExtra)
494 {
495 case 0x0001:
496 /*
497 * ZIP64 Extended Information Extra Field.
498 */
499 if (!pThis->fZip64Eocd)
500 return VERR_PKZIP_ZIP64EX_IN_ZIP32;
501 /* Not all fields are really used. */
502 RT_ZERO(pThis->cd64ex);
503 memcpy(&pThis->cd64ex, pu8Buf, cbExtra);
504 pThis->fZip64Ex = true;
505 break;
506
507 default:
508 /* unknown, just skip */
509 break;
510 }
511 pu8Buf += cbExtra;
512 cb -= cbExtra;
513 }
514 else
515 {
516 rc = VERR_PKZIP_BAD_CDF_HEADER;
517 break;
518 }
519 }
520
521 *penmCompMethod = (RTZIPPKZIP_COMP_METHOD)pThis->cdh.u16ComprMethod;
522 *pcbCompressed = rtZipPkzipReaderCompressed(pThis);
523 }
524 return VINF_SUCCESS;
525}
526
527
528/**
529 * Translate a PKZip header to an IPRT object info structure.
530 */
531static int rtZipPkzipReaderGetFsObjInfo(PRTZIPPKZIPREADER pThis, PRTFSOBJINFO pObjInfo)
532{
533 /*
534 * Zap the whole structure, this takes care of unused space in the union.
535 */
536 RT_ZERO(*pObjInfo);
537 pObjInfo->cbObject = rtZipPkzipReaderUncompressed(pThis);
538 pObjInfo->cbAllocated = rtZipPkzipReaderUncompressed(pThis); /* XXX */
539 RTTIMESPEC ts;
540 rtZipPkzipReaderDecodeDosTime(&ts, pThis->cdh.u16LastModifiedTime, pThis->cdh.u16LastModifiedDate);
541 pObjInfo->ChangeTime = ts;
542 pObjInfo->ModificationTime = ts;
543 pObjInfo->AccessTime = ts;
544 pObjInfo->BirthTime = ts;
545 const char *pszEnd = strchr(pThis->szName, '\0');
546 if (pszEnd == &pThis->szName[0] || pszEnd[-1] != '/')
547 pObjInfo->Attr.fMode = RTFS_TYPE_FILE | RTFS_UNIX_IRUSR | RTFS_UNIX_IRWXU;
548 else
549 pObjInfo->Attr.fMode = RTFS_TYPE_DIRECTORY | RTFS_UNIX_IRUSR | RTFS_UNIX_IRUSR | RTFS_UNIX_IXUSR;
550 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
551 pObjInfo->Attr.u.Unix.cHardlinks = 1;
552
553 return VINF_SUCCESS;
554}
555
556
557/**
558 * Search the magic value of the End Of Central Directory Record.
559 *
560 * @returns true if found, false otherwise.
561 * @param pu8Buf buffer.
562 * @param cb size of buffer.
563 * @param piPos where to store the position of the magic value.
564 */
565static bool rtZipPkzipReaderScanEocd(const uint8_t *pu8Buf, size_t cb, int *piPos)
566{
567 if (cb < 4)
568 return false;
569 ssize_t i;
570 for (i = (ssize_t)cb - 4; i >= 0; --i)
571 if (*(uint32_t*)(pu8Buf + i) == RTZIPPKZIPENDOFCENTRDIRREC_MAGIC)
572 {
573 *piPos = i;
574 return true;
575 }
576 return false;
577}
578
579
580/**
581 * Read the Local File Header. We ignore the content -- we trust the Central
582 * Directory.
583 */
584static int rtZipPkzipFssIosReadLfh(PRTZIPPKZIPFSSTREAM pThis, uint64_t *poffStartData)
585{
586 RTZIPPKZIPLOCALFILEHDR lfh;
587 uint64_t offLocalFileHeader = rtZipPkzipReaderOffLocalHeader(&pThis->PkzipReader);
588 int rc = RTVfsIoStrmReadAt(pThis->hVfsIos, offLocalFileHeader,
589 &lfh, sizeof(lfh) - 1, true /*fBlocking*/, NULL);
590 if (RT_SUCCESS(rc))
591 {
592 if (lfh.u32Magic == RTZIPPKZIPLOCALFILEHDR_MAGIC)
593 {
594 size_t cbExtra = 0;
595 rc = rtZipPkzipParseLocalFileHeader(&pThis->PkzipReader, &lfh, &cbExtra);
596 if (RT_SUCCESS(rc))
597 {
598 /* Just skip the file name and and extra field. We use the data
599 * from the Central Directory Header. */
600 rc = RTVfsIoStrmSkip(pThis->hVfsIos, cbExtra);
601 if (RT_SUCCESS(rc))
602 *poffStartData = offLocalFileHeader + sizeof(lfh) - 1 + cbExtra;
603 }
604 }
605 else
606 rc = VERR_PKZIP_BAD_LF_HEADER;
607 }
608
609 return rc;
610}
611
612
613/**
614 * Scan the current Central Directory Header.
615 */
616static int rtZipPkzipFssIosReadCdh(PRTZIPPKZIPFSSTREAM pThis, uint64_t *poffStartData,
617 RTZIPPKZIP_COMP_METHOD *penmCompMethod, uint64_t *pcbCompressed)
618{
619 int rc;
620
621 uint64_t offCd = pThis->offNextCdh - pThis->offFirstCdh;
622 if ( pThis->iCentrDirEntry < pThis->cCentrDirEntries
623 || offCd + sizeof(RTZIPPKZIPCENTRDIRHDR) - 1 <= pThis->cbCentrDir)
624 {
625 RTZIPPKZIPCENTRDIRHDR cdh;
626 rc = RTVfsIoStrmReadAt(pThis->hVfsIos, pThis->offNextCdh,
627 &cdh, sizeof(cdh) - 1, true /*fBlocking*/, NULL);
628 if (RT_SUCCESS(rc))
629 {
630 pThis->offNextCdh += sizeof(cdh) - 1;
631 pThis->iCentrDirEntry++;
632 size_t cbExtra = 0;
633 rc = rtZipPkzipParseCentrDirHeader(&pThis->PkzipReader, &cdh, &cbExtra);
634 if (RT_SUCCESS(rc))
635 {
636 if (offCd + sizeof(RTZIPPKZIPCENTRDIRHDR) - 1 + cbExtra <= pThis->cbCentrDir)
637 {
638 /* extra data up to 64k */
639 uint8_t *pu8Buf = (uint8_t*)RTMemTmpAlloc(cbExtra);
640 if (pu8Buf)
641 {
642 rc = RTVfsIoStrmRead(pThis->hVfsIos, pu8Buf, cbExtra, true /*fBlocking*/, NULL);
643 if (RT_SUCCESS(rc))
644 {
645 rc = rtZipPkzipParseCentrDirHeaderExtra(&pThis->PkzipReader, pu8Buf, cbExtra,
646 penmCompMethod, pcbCompressed);
647 if (RT_SUCCESS(rc))
648 rc = rtZipPkzipFssIosReadLfh(pThis, poffStartData);
649 }
650 pThis->offNextCdh += cbExtra;
651 RTMemTmpFree(pu8Buf);
652 }
653 else
654 rc = VERR_NO_MEMORY;
655 }
656 else
657 rc = VERR_EOF;
658 }
659 }
660 }
661 else
662 rc = VERR_EOF;
663
664 return rc;
665}
666
667
668/**
669 * Scan for the End of Central Directory Record. Of course this works not if
670 * the stream is non-seekable (i.e. a pipe).
671 */
672static int rtZipPkzipFssIosReadEocb(PRTZIPPKZIPFSSTREAM pThis)
673{
674 uint64_t cbFile;
675 int rc = RTVfsFileSeek(RTVfsIoStrmToFile(pThis->hVfsIos), 0, RTFILE_SEEK_END, &cbFile);
676 if (RT_FAILURE(rc))
677 return rc;
678
679 if (cbFile < sizeof(RTZIPPKZIPENDOFCENTRDIRREC)-1)
680 return VERR_PKZIP_NO_EOCB;
681
682 /* search for start of the 'end of Central Directory Record' */
683 size_t cbBuf = RT_MIN(_1K, cbFile);
684 uint8_t *pu8Buf = (uint8_t*)RTMemTmpAlloc(cbBuf);
685 if (!pu8Buf)
686 return VERR_NO_MEMORY;
687
688 /* maximum size of EOCD comment 2^16-1 */
689 const size_t cbHdrMax = 0xffff + sizeof(RTZIPPKZIPENDOFCENTRDIRREC) - 1;
690 uint64_t offMin = cbFile >= cbHdrMax ? cbFile - cbHdrMax : 0;
691
692 uint64_t off = cbFile - cbBuf;
693 while (off >= offMin)
694 {
695 rc = RTVfsIoStrmReadAt(pThis->hVfsIos, off, pu8Buf, cbBuf, true /*fBlocking*/, NULL);
696 if (RT_FAILURE(rc))
697 break;
698 int offMagic;
699 if (rtZipPkzipReaderScanEocd(pu8Buf, cbBuf, &offMagic))
700 {
701 off += offMagic;
702 RTZIPPKZIPENDOFCENTRDIRREC eocd;
703 rc = RTVfsIoStrmReadAt(pThis->hVfsIos, off, &eocd, sizeof(eocd) - 1,
704 true /*fBlocking*/, NULL);
705 if (RT_SUCCESS(rc))
706 {
707 /* well, this shouldn't fail if the content didn't change */
708 if (eocd.u32Magic == RTZIPPKZIPENDOFCENTRDIRREC_MAGIC)
709 {
710 /* sanity check */
711 if (off + RT_OFFSETOF(RTZIPPKZIPENDOFCENTRDIRREC, u8Comment) + eocd.cbComment == cbFile)
712 {
713 pThis->offFirstCdh = eocd.offCentrDir;
714 pThis->offNextCdh = eocd.offCentrDir;
715 pThis->iCentrDirEntry = 0;
716 pThis->cCentrDirEntries = eocd.cCentrDirRecords;
717 pThis->cbCentrDir = eocd.cbCentrDir;
718 pThis->PkzipReader.fHaveEocd = true;
719 }
720 else
721 rc = VERR_PKZIP_NO_EOCB;
722 }
723 else
724 rc = VERR_PKZIP_NO_EOCB;
725 }
726 if (rc != VERR_PKZIP_NO_EOCB)
727 break;
728 }
729 else
730 rc = VERR_PKZIP_NO_EOCB;
731 /* overlap the following read */
732 off -= cbBuf - 4;
733 }
734
735 RTMemTmpFree(pu8Buf);
736
737 /*
738 * Now check for the presence of the Zip64 End of Central Directory Locator.
739 */
740 if ( RT_SUCCESS(rc)
741 && off > (unsigned)sizeof(RTZIPPKZIP64ENDOFCENTRDIRLOC))
742 {
743 off -= sizeof(RTZIPPKZIP64ENDOFCENTRDIRLOC);
744
745 RTZIPPKZIP64ENDOFCENTRDIRLOC eocd64loc;
746 rc = RTVfsIoStrmReadAt(pThis->hVfsIos, off, &eocd64loc, sizeof(eocd64loc), true /*fBlocking*/, NULL);
747 if (RT_SUCCESS(rc))
748 {
749 if (eocd64loc.u32Magic == RTZIPPKZIP64ENDOFCENTRDIRLOC_MAGIC)
750 pThis->PkzipReader.fZip64Eocd = true;
751 }
752 }
753 return rc;
754}
755
756
757/**
758 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
759 */
760static DECLCALLBACK(int) rtZipPkzipFssBaseObj_Close(void *pvThis)
761{
762 PRTZIPPKZIPBASEOBJ pThis = (PRTZIPPKZIPBASEOBJ)pvThis;
763
764 return VINF_SUCCESS;
765}
766
767
768/**
769 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
770 */
771static DECLCALLBACK(int) rtZipPkzipFssBaseObj_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
772{
773 PRTZIPPKZIPBASEOBJ pThis = (PRTZIPPKZIPBASEOBJ)pvThis;
774
775 /*
776 * Copy the desired data.
777 */
778 switch (enmAddAttr)
779 {
780 case RTFSOBJATTRADD_NOTHING:
781 case RTFSOBJATTRADD_UNIX:
782 *pObjInfo = pThis->ObjInfo;
783 break;
784
785 case RTFSOBJATTRADD_UNIX_OWNER:
786 *pObjInfo = pThis->ObjInfo;
787 break;
788
789 case RTFSOBJATTRADD_UNIX_GROUP:
790 *pObjInfo = pThis->ObjInfo;
791 break;
792
793 case RTFSOBJATTRADD_EASIZE:
794 *pObjInfo = pThis->ObjInfo;
795 break;
796
797 default:
798 return VERR_NOT_SUPPORTED;
799 }
800
801 return VINF_SUCCESS;
802}
803
804
805/**
806 * PKZip filesystem base object operations (directory objects).
807 */
808static const RTVFSOBJOPS g_rtZipPkzipFssBaseObjOps =
809{
810 RTVFSOBJOPS_VERSION,
811 RTVFSOBJTYPE_BASE,
812 "PkzipFsStream::Obj",
813 rtZipPkzipFssBaseObj_Close,
814 rtZipPkzipFssBaseObj_QueryInfo,
815 RTVFSOBJOPS_VERSION
816};
817
818
819/**
820 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
821 */
822static DECLCALLBACK(int) rtZipPkzipFssIos_Close(void *pvThis)
823{
824 PRTZIPPKZIPIOSTREAM pThis = (PRTZIPPKZIPIOSTREAM)pvThis;
825
826 RTVfsIoStrmRelease(pThis->hVfsIos);
827 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
828
829 if (pThis->pZip)
830 {
831 RTZipDecompDestroy(pThis->pZip);
832 pThis->pZip = NULL;
833 }
834
835 return rtZipPkzipFssBaseObj_Close(&pThis->BaseObj);
836}
837
838
839/**
840 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
841 */
842static DECLCALLBACK(int) rtZipPkzipFssIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
843{
844 PRTZIPPKZIPIOSTREAM pThis = (PRTZIPPKZIPIOSTREAM)pvThis;
845 return rtZipPkzipFssBaseObj_QueryInfo(&pThis->BaseObj, pObjInfo, enmAddAttr);
846}
847
848
849/**
850 * Callback function for rtZipPkzipFssIos_Read. For feeding compressed data
851 * into the decompressor function.
852 */
853static DECLCALLBACK(int) rtZipPkzipFssIosReadHelper(void *pvThis, void *pvBuf, size_t cbToRead, size_t *pcbRead)
854{
855 PRTZIPPKZIPIOSTREAM pThis = (PRTZIPPKZIPIOSTREAM)pvThis;
856 int rc = VINF_SUCCESS;
857 if (!cbToRead)
858 return rc;
859 if ( pThis->fPassZipType
860 && cbToRead > 0)
861 {
862 uint8_t *pu8Buf = (uint8_t*)pvBuf;
863 pu8Buf[0] = pThis->enmZipType;
864 pvBuf = &pu8Buf[1];
865 cbToRead--;
866 pThis->fPassZipType = false;
867 }
868 if (cbToRead > 0)
869 {
870 size_t cbRead = 0;
871 const size_t cbAvail = pThis->cbComp;
872 rc = RTVfsIoStrmReadAt(pThis->hVfsIos, pThis->offComp, pvBuf,
873 RT_MIN(cbToRead, cbAvail), true /*fBlocking*/, &cbRead);
874 if ( RT_SUCCESS(rc)
875 && cbToRead > cbAvail)
876 rc = pcbRead ? VINF_EOF : VERR_EOF;
877 if ( rc == VINF_EOF
878 && !pcbRead)
879 rc = VERR_EOF;
880 pThis->offComp += cbRead;
881 if (pcbRead)
882 *pcbRead = cbRead;
883 }
884 return rc;
885}
886
887
888/**
889 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
890 */
891static DECLCALLBACK(int) rtZipPkzipFssIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
892{
893 PRTZIPPKZIPIOSTREAM pThis = (PRTZIPPKZIPIOSTREAM)pvThis;
894 Assert(pSgBuf->cSegs == 1);
895
896 if (off < 0)
897 off = pThis->offFile;
898 if (off >= (RTFOFF)pThis->cbFile)
899 return pcbRead ? VINF_EOF : VERR_EOF;
900
901 Assert(pThis->cbFile >= pThis->offFile);
902 uint64_t cbLeft = (uint64_t)(pThis->cbFile - pThis->offFile);
903 size_t cbToRead = pSgBuf->paSegs[0].cbSeg;
904 if (cbToRead > cbLeft)
905 {
906 if (!pcbRead)
907 return VERR_EOF;
908 cbToRead = (size_t)cbLeft;
909 }
910
911 /*
912 * Restart decompression at start of stream or on backward seeking.
913 */
914 if ( !pThis->pZip
915 || !off
916 || off < (RTFOFF)pThis->offFile)
917 {
918 switch (pThis->enmCompMethod)
919 {
920 case RTZIPPKZIP_COMP_METHOD_STORED:
921 pThis->enmZipType = RTZIPTYPE_STORE;
922 break;
923
924 case RTZIPPKZIP_COMP_METHOD_DEFLATED:
925 pThis->enmZipType = RTZIPTYPE_ZLIB_NO_HEADER;
926 break;
927
928 default:
929 pThis->enmZipType = RTZIPTYPE_INVALID;
930 break;
931 }
932
933 if (pThis->pZip)
934 {
935 RTZipDecompDestroy(pThis->pZip);
936 pThis->pZip = NULL;
937 }
938 int rc = RTZipDecompCreate(&pThis->pZip, (void*)pThis, rtZipPkzipFssIosReadHelper);
939 if (RT_FAILURE(rc))
940 return rc;
941 }
942
943 /*
944 * Skip bytes if necessary.
945 */
946 if (off > (RTFOFF)pThis->offFile)
947 {
948 uint8_t u8Buf[_1K];
949 while (off > (RTFOFF)pThis->offFile)
950 {
951 size_t cbSkip = off - pThis->offFile;
952 if (cbSkip > sizeof(u8Buf))
953 cbSkip = sizeof(u8Buf);
954 int rc = RTZipDecompress(pThis->pZip, u8Buf, cbSkip, NULL);
955 if (RT_FAILURE(rc))
956 return rc;
957 pThis->offFile += cbSkip;
958 }
959 }
960
961 /*
962 * Do the actual reading.
963 */
964 size_t cbReadStack = 0;
965 if (!pcbRead)
966 pcbRead = &cbReadStack;
967 int rc = RTZipDecompress(pThis->pZip, pSgBuf->paSegs[0].pvSeg, cbToRead, pcbRead);
968 pThis->offFile = off + *pcbRead;
969 if (pThis->offFile >= pThis->cbFile)
970 {
971 Assert(pThis->offFile == pThis->cbFile);
972 pThis->fEndOfStream = true;
973 }
974
975 return rc;
976}
977
978
979/**
980 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
981 */
982static DECLCALLBACK(int) rtZipPkzipFssIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies,
983 bool fIntr, uint32_t *pfRetEvents)
984{
985 PRTZIPPKZIPIOSTREAM pThis = (PRTZIPPKZIPIOSTREAM)pvThis;
986
987 /* When we've reached the end, read will be set to indicate it. */
988 if ( (fEvents & RTPOLL_EVT_READ)
989 && pThis->fEndOfStream)
990 {
991 int rc = RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, 0, fIntr, pfRetEvents);
992 if (RT_SUCCESS(rc))
993 *pfRetEvents |= RTPOLL_EVT_READ;
994 else
995 *pfRetEvents = RTPOLL_EVT_READ;
996 return VINF_SUCCESS;
997 }
998
999 return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
1000}
1001
1002
1003/**
1004 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
1005 */
1006static DECLCALLBACK(int) rtZipPkzipFssIos_Tell(void *pvThis, PRTFOFF poffActual)
1007{
1008 PRTZIPPKZIPIOSTREAM pThis = (PRTZIPPKZIPIOSTREAM)pvThis;
1009 *poffActual = pThis->offFile;
1010 return VINF_SUCCESS;
1011}
1012
1013
1014/**
1015 * Pkzip I/O object stream operations.
1016 */
1017static const RTVFSIOSTREAMOPS g_rtZipPkzipFssIosOps =
1018{
1019 { /* Obj */
1020 RTVFSOBJOPS_VERSION,
1021 RTVFSOBJTYPE_IO_STREAM,
1022 "PkzipFsStream::IoStream",
1023 rtZipPkzipFssIos_Close,
1024 rtZipPkzipFssIos_QueryInfo,
1025 RTVFSOBJOPS_VERSION
1026 },
1027 RTVFSIOSTREAMOPS_VERSION,
1028 RTVFSIOSTREAMOPS_FEAT_NO_SG,
1029 rtZipPkzipFssIos_Read,
1030 NULL /*Write*/,
1031 NULL /*Flush*/,
1032 rtZipPkzipFssIos_PollOne,
1033 rtZipPkzipFssIos_Tell,
1034 NULL /*Skip*/,
1035 NULL /*ZeroFill*/,
1036 RTVFSIOSTREAMOPS_VERSION
1037};
1038
1039/**
1040 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
1041 */
1042static DECLCALLBACK(int) rtZipPkzipFss_Close(void *pvThis)
1043{
1044 PRTZIPPKZIPFSSTREAM pThis = (PRTZIPPKZIPFSSTREAM)pvThis;
1045
1046 RTVfsObjRelease(pThis->hVfsCurObj);
1047 pThis->hVfsCurObj = NIL_RTVFSOBJ;
1048 pThis->pCurIosData = NULL;
1049
1050 RTVfsIoStrmRelease(pThis->hVfsIos);
1051 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
1052
1053 return VINF_SUCCESS;
1054}
1055
1056
1057/**
1058 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
1059 */
1060static DECLCALLBACK(int) rtZipPkzipFss_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1061{
1062 PRTZIPPKZIPFSSTREAM pThis = (PRTZIPPKZIPFSSTREAM)pvThis;
1063 /* Take the lazy approach here, with the sideffect of providing some info
1064 that is actually kind of useful. */
1065 return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
1066}
1067
1068
1069/**
1070 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
1071 */
1072static DECLCALLBACK(int) rtZipPkzipFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
1073{
1074 PRTZIPPKZIPFSSTREAM pThis = (PRTZIPPKZIPFSSTREAM)pvThis;
1075
1076 /*
1077 * Dispense with the current object.
1078 */
1079 if (pThis->hVfsCurObj != NIL_RTVFSOBJ)
1080 {
1081 if (pThis->pCurIosData)
1082 {
1083 pThis->pCurIosData->fEndOfStream = true;
1084 pThis->pCurIosData->offFile = pThis->pCurIosData->cbFile;
1085 pThis->pCurIosData = NULL;
1086 }
1087
1088 RTVfsObjRelease(pThis->hVfsCurObj);
1089 pThis->hVfsCurObj = NIL_RTVFSOBJ;
1090 }
1091
1092 /*
1093 * Check if we've already reached the end in some way.
1094 */
1095 if (pThis->fEndOfStream)
1096 return VERR_EOF;
1097 if (pThis->rcFatal != VINF_SUCCESS)
1098 return pThis->rcFatal;
1099
1100 int rc = VINF_SUCCESS;
1101
1102 /*
1103 * Read the end of Central Directory Record once.
1104 */
1105 if (!pThis->PkzipReader.fHaveEocd)
1106 rc = rtZipPkzipFssIosReadEocb(pThis);
1107 uint64_t offData = 0;
1108
1109 /*
1110 * Parse the current Central Directory Header.
1111 */
1112 RTZIPPKZIP_COMP_METHOD enmCompMethod = RTZIPPKZIP_COMP_METHOD_STORED;
1113 uint64_t cbCompressed = 0;
1114 if (RT_SUCCESS(rc))
1115 rc = rtZipPkzipFssIosReadCdh(pThis, &offData, &enmCompMethod, &cbCompressed);
1116 if (RT_FAILURE(rc))
1117 return pThis->rcFatal = rc;
1118
1119 /*
1120 * Fill an object info structure from the current Pkzip state.
1121 */
1122 RTFSOBJINFO Info;
1123 rc = rtZipPkzipReaderGetFsObjInfo(&pThis->PkzipReader, &Info);
1124 if (RT_FAILURE(rc))
1125 return pThis->rcFatal = rc;
1126
1127 /*
1128 * Create an object of the appropriate type.
1129 */
1130 RTVFSOBJTYPE enmType;
1131 RTVFSOBJ hVfsObj;
1132 RTFMODE fType = Info.Attr.fMode & RTFS_TYPE_MASK;
1133 switch (fType)
1134 {
1135 case RTFS_TYPE_FILE:
1136 RTVFSIOSTREAM hVfsIos;
1137 PRTZIPPKZIPIOSTREAM pIosData;
1138 rc = RTVfsNewIoStream(&g_rtZipPkzipFssIosOps,
1139 sizeof(*pIosData),
1140 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
1141 NIL_RTVFS,
1142 NIL_RTVFSLOCK,
1143 &hVfsIos,
1144 (void **)&pIosData);
1145 if (RT_FAILURE(rc))
1146 return pThis->rcFatal = rc;
1147
1148 pIosData->BaseObj.pPkzipReader = &pThis->PkzipReader;
1149 pIosData->BaseObj.ObjInfo = Info;
1150 pIosData->cbFile = Info.cbObject;
1151 pIosData->offFile = 0;
1152 pIosData->offComp = offData;
1153 pIosData->offCompStart = offData;
1154 pIosData->cbComp = cbCompressed;
1155 pIosData->enmCompMethod = enmCompMethod;
1156 pIosData->fPassZipType = true;
1157 pIosData->hVfsIos = pThis->hVfsIos;
1158 RTVfsIoStrmRetain(pThis->hVfsIos);
1159 pThis->pCurIosData = pIosData;
1160 enmType = RTVFSOBJTYPE_IO_STREAM;
1161 hVfsObj = RTVfsObjFromIoStream(hVfsIos);
1162 RTVfsIoStrmRelease(hVfsIos);
1163 break;
1164
1165 case RTFS_TYPE_DIRECTORY:
1166 PRTZIPPKZIPBASEOBJ pBaseObjData;
1167 rc = RTVfsNewBaseObj(&g_rtZipPkzipFssBaseObjOps,
1168 sizeof(*pBaseObjData),
1169 NIL_RTVFS,
1170 NIL_RTVFSLOCK,
1171 &hVfsObj,
1172 (void **)&pBaseObjData);
1173 if (RT_FAILURE(rc))
1174 return pThis->rcFatal = rc;
1175
1176 pBaseObjData->pPkzipReader = &pThis->PkzipReader;
1177 pBaseObjData->ObjInfo = Info;
1178 enmType = RTVFSOBJTYPE_BASE;
1179 break;
1180
1181 default:
1182 return pThis->rcFatal = VERR_PKZIP_UNKNOWN_TYPE_FLAG;
1183 }
1184
1185 if (ppszName)
1186 {
1187 rc = RTStrDupEx(ppszName, pThis->PkzipReader.szName);
1188 if (RT_FAILURE(rc))
1189 return pThis->rcFatal = rc;
1190 }
1191
1192 if (phVfsObj)
1193 {
1194 RTVfsObjRetain(hVfsObj);
1195 *phVfsObj = hVfsObj;
1196 }
1197
1198 if (penmType)
1199 *penmType = enmType;
1200
1201 return VINF_SUCCESS;
1202}
1203
1204
1205/**
1206 * PKZip filesystem stream operations.
1207 */
1208static const RTVFSFSSTREAMOPS rtZipPkzipFssOps =
1209{
1210 { /* Obj */
1211 RTVFSOBJOPS_VERSION,
1212 RTVFSOBJTYPE_FS_STREAM,
1213 "PkzipFsStream",
1214 rtZipPkzipFss_Close,
1215 rtZipPkzipFss_QueryInfo,
1216 RTVFSOBJOPS_VERSION
1217 },
1218 RTVFSFSSTREAMOPS_VERSION,
1219 0,
1220 rtZipPkzipFss_Next,
1221 RTVFSFSSTREAMOPS_VERSION
1222};
1223
1224
1225RTDECL(int) RTZipPkzipFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
1226{
1227 /*
1228 * Input validation.
1229 */
1230 AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
1231 *phVfsFss = NIL_RTVFSFSSTREAM;
1232 AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE);
1233 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1234
1235 uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn);
1236 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
1237
1238 /*
1239 * Retain the input stream and create a new filesystem stream handle.
1240 */
1241 PRTZIPPKZIPFSSTREAM pThis;
1242 RTVFSFSSTREAM hVfsFss;
1243 int rc = RTVfsNewFsStream(&rtZipPkzipFssOps, sizeof(*pThis),
1244 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFss, (void **)&pThis);
1245 if (RT_SUCCESS(rc))
1246 {
1247 pThis->hVfsIos = hVfsIosIn;
1248 pThis->hVfsCurObj = NIL_RTVFSOBJ;
1249 pThis->pCurIosData = NULL;
1250 pThis->fEndOfStream = false;
1251 pThis->rcFatal = VINF_SUCCESS;
1252 pThis->fHaveEocd = false;
1253
1254 *phVfsFss = hVfsFss;
1255 return VINF_SUCCESS;
1256 }
1257
1258 RTVfsIoStrmRelease(hVfsIosIn);
1259 return rc;
1260}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette