VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/zip/tarvfs.cpp@ 34079

Last change on this file since 34079 was 34060, checked in by vboxsync, 14 years ago

some tar bits

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.7 KB
Line 
1/* $Id: tarvfs.cpp 34060 2010-11-14 23:15:04Z vboxsync $ */
2/** @file
3 * IPRT - TAR Virtual Filesystem.
4 */
5
6/*
7 * Copyright (C) 2010 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 "internal/iprt.h"
32#include <iprt/zip.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/poll.h>
38#include <iprt/file.h>
39#include <iprt/string.h>
40#include <iprt/vfs.h>
41#include <iprt/vfslowlevel.h>
42
43#include "tar.h"
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/**
50 * Tar directory, character device, block device, fifo socket or symbolic link.
51 */
52typedef struct RTZIPTARBASEOBJ
53{
54 /** The stream offset of the (first) header. */
55 RTFOFF offHdr;
56 /** The tar header. */
57 RTZIPTARHDR Hdr;
58 /** The object info with unix attributes. */
59 RTFSOBJINFO ObjInfo;
60} RTZIPTARBASEOBJ;
61/** Pointer to a tar filesystem stream base object. */
62typedef RTZIPTARBASEOBJ *PRTZIPTARBASEOBJ;
63
64
65/**
66 * Tar file represented as a VFS I/O stream.
67 */
68typedef struct RTZIPTARIOSTREAM
69{
70 /** The basic tar object data. */
71 RTZIPTARBASEOBJ BaseObj;
72 /** The number of bytes in the file. */
73 RTFOFF cbFile;
74 /** The current file position. */
75 RTFOFF offFile;
76 /** The number of padding bytes following the file. */
77 uint32_t cbPadding;
78 /** Set if we've reached the end of the file. */
79 bool fEndOfStream;
80 /** The input I/O stream. */
81 RTVFSIOSTREAM hVfsIos;
82} RTZIPTARIOSTREAM;
83/** Pointer to a the private data of a tar file I/O stream. */
84typedef RTZIPTARIOSTREAM *PRTZIPTARIOSTREAM;
85
86
87/**
88 * Tar filesystem stream private data.
89 */
90typedef struct RTZIPTARFSSTREAM
91{
92 /** The input I/O stream. */
93 RTVFSIOSTREAM hVfsIos;
94
95 /** The current object (referenced). */
96 RTVFSOBJ hVfsCurObj;
97 /** Pointer to the private data if hVfsCurObj is representing a file. */
98 PRTZIPTARIOSTREAM pCurIosData;
99
100 /** The start offset. */
101 RTFOFF offStart;
102 /** The offset of the next header. */
103 RTFOFF offNextHdr;
104
105 /** Set if we've reached the end of the stream. */
106 bool fEndOfStream;
107 /** Set if we've encountered a fatal error. */
108 int rcFatal;
109} RTZIPTARFSSTREAM;
110/** Pointer to a the private data of a tar filesystem stream. */
111typedef RTZIPTARFSSTREAM *PRTZIPTARFSSTREAM;
112
113
114/**
115 * Checks if the TAR header is in the ustar format.
116 *
117 * @returns true / false.
118 * @param pTar The TAR header.
119 */
120DECLINLINE(bool) rtZipTarHdrIsUstar(PCRTZIPTARHDR pTar)
121{
122 return pTar->Posix.magic[0] == 'u'
123 && pTar->Posix.magic[1] == 's'
124 && pTar->Posix.magic[2] == 't'
125 && pTar->Posix.magic[3] == 'a'
126 && pTar->Posix.magic[4] == 'r'
127 && pTar->Posix.magic[5] == '\0'
128 && pTar->Posix.version[0] == '0'
129 && pTar->Posix.version[1] == '0';
130}
131
132
133/**
134 * Checks if the TAR header is in the ustar format and has a regular file type.
135 *
136 * @returns true / false.
137 * @param pTar The TAR header.
138 */
139DECLINLINE(bool) rtZipTarHdrIsRegularUstar(PCRTZIPTARHDR pTar)
140{
141 return rtZipTarHdrIsUstar(pTar)
142 && ( ( pTar->Posix.typeflag >= RTZIPTAR_TF_NORMAL
143 && pTar->Posix.typeflag <= RTZIPTAR_TF_CONTIG)
144 || pTar->Posix.typeflag == RTZIPTAR_TF_OLDNORMAL);
145}
146
147
148/**
149 * Checks if the TAR header includes a posix user name field.
150 *
151 * @returns true / false.
152 * @param pTar The TAR header.
153 */
154DECLINLINE(bool) rtZipTarHdrHasPosixUserName(PCRTZIPTARHDR pTar)
155{
156 return pTar->Posix.uname[0] != '\0'
157 && rtZipTarHdrIsUstar(pTar);
158}
159
160
161/**
162 * Checks if the TAR header includes a posix group name field.
163 *
164 * @returns true / false.
165 * @param pTar The TAR header.
166 */
167DECLINLINE(bool) rtZipTarHdrHasPosixGroupName(PCRTZIPTARHDR pTar)
168{
169 return pTar->Posix.gname[0] != '\0'
170 && rtZipTarHdrIsUstar(pTar);
171}
172
173
174/**
175 * Checks if the TAR header includes a posix compatible path prefix field.
176 *
177 * @returns true / false.
178 * @param pTar The TAR header.
179 */
180DECLINLINE(bool) rtZipTarHdrHasPrefix(PCRTZIPTARHDR pTar)
181{
182 return pTar->Posix.prefix[0] != '\0'
183 && rtZipTarHdrIsUstar(pTar);
184}
185
186
187/**
188 * Converts a numeric header field to the C native type.
189 *
190 * @returns IPRT status code.
191 *
192 * @param pszField The TAR header field.
193 * @param cchField The length of the field.
194 * @param fOctalOnly Must be octal.
195 * @param pi64 Where to store the value.
196 */
197static int rtZipTarHdrFieldToNum(const char *pszField, size_t cchField, bool fOctalOnly, int64_t *pi64)
198{
199 size_t const cchFieldOrg = cchField;
200 if ( fOctalOnly
201 || !(*(unsigned char *)pszField & 0x80))
202 {
203 /*
204 * Skip leading zeros, saving a few slower loops below.
205 */
206 while (cchField > 0 && *pszField == '0')
207 cchField--, pszField++;
208
209 /*
210 * Convert octal digits.
211 */
212 int64_t i64 = 0;
213 while (cchField > 0)
214 {
215 unsigned char uDigit = *pszField - '0';
216 if (uDigit >= 8)
217 break;
218 i64 <<= 3;
219 i64 |= uDigit;
220
221 pszField++;
222 cchField--;
223 }
224 *pi64 = i64;
225
226 /*
227 * Was it terminated correctly?
228 */
229 while (cchField > 0)
230 {
231 char ch = *pszField++;
232 if (ch != 0 && ch != ' ')
233 return cchField < cchFieldOrg
234 ? VERR_TAR_BAD_NUM_FIELD_TERM
235 : VERR_TAR_BAD_NUM_FIELD;
236 cchField--;
237 }
238 }
239 else
240 {
241 /** @todo implement base-256 encoded fields. */
242 return VERR_TAR_BASE_256_NOT_SUPPORTED;
243 }
244
245 return VINF_SUCCESS;
246}
247
248
249/**
250 * Calculates the tar header checksums and detects if it's all zeros.
251 *
252 * @returns true if all zeros, false if not.
253 * @param pHdr The header to checksum.
254 * @param pi32Unsigned Where to store the checksum calculated using
255 * unsigned chars. This is the one POSIX
256 * specifies.
257 * @param pi32Signed Where to store the checksum calculated using
258 * signed chars.
259 *
260 * @remarks The reason why we calculate the checksum as both signed and unsigned
261 * has to do with various the char C type being signed on some hosts
262 * and unsigned on others.
263 */
264static bool rtZipTarCalcChkSum(PCRTZIPTARHDR pHdr, int32_t *pi32Unsigned, int32_t *pi32Signed)
265{
266 int32_t i32Unsigned = 0;
267 int32_t i32Signed = 0;
268
269 /*
270 * Sum up the entire header.
271 */
272 const char *pch = (const char *)pHdr;
273 const char *pchEnd = pch + sizeof(*pHdr);
274 do
275 {
276 i32Unsigned += *(unsigned char *)pch;
277 i32Signed += *(signed char *)pch;
278 } while (++pch != pchEnd);
279
280 /*
281 * Check if it's all zeros and replace the chksum field with spaces.
282 */
283 bool const fZeroHdr = i32Unsigned == 0;
284
285 pch = pHdr->Posix.chksum;
286 pchEnd = pch + sizeof(pHdr->Posix.chksum);
287 do
288 {
289 i32Unsigned -= *(unsigned char *)pch;
290 i32Signed -= *(signed char *)pch;
291 } while (++pch != pchEnd);
292
293 i32Unsigned += (unsigned char)' ' * sizeof(pHdr->Posix.chksum);
294 i32Signed += (signed char)' ' * sizeof(pHdr->Posix.chksum);
295
296 *pi32Unsigned = i32Unsigned;
297 if (pi32Signed)
298 *pi32Signed = i32Signed;
299 return fZeroHdr;
300}
301
302
303/**
304 * Validates the TAR header.
305 *
306 * @returns VINF_SUCCESS if valid, appropriate VERR_TAR_XXX if not.
307 * @param pTar The TAR header.
308 * @param penmType Where to return the type of header on success.
309 */
310static int rtZipTarHdrValidate(PCRTZIPTARHDR pTar, PRTZIPTARTYPE penmType)
311{
312 /*
313 * Calc the checksum first since this enables us to detect zero headers.
314 */
315 int32_t i32ChkSum;
316 int32_t i32ChkSumSignedAlt;
317 if (rtZipTarCalcChkSum(pTar, &i32ChkSum, &i32ChkSumSignedAlt))
318 return VERR_TAR_ZERO_HEADER;
319
320 /*
321 * Read the checksum field and match the checksums.
322 */
323 int64_t i64HdrChkSum;
324 int rc = rtZipTarHdrFieldToNum(pTar->Posix.chksum, sizeof(pTar->Posix.chksum), true /*fOctalOnly*/, &i64HdrChkSum);
325 if (RT_FAILURE(rc))
326 return VERR_TAR_BAD_CHKSUM_FIELD;
327 if ( i32ChkSum != i64HdrChkSum
328 && i32ChkSumSignedAlt != i64HdrChkSum) /** @todo test this */
329 return VERR_TAR_CHKSUM_MISMATCH;
330
331 /*
332 * Detect the tar type.
333 */
334 RTZIPTARTYPE enmType;
335 if ( pTar->Posix.magic[0] == 'u'
336 && pTar->Posix.magic[1] == 's'
337 && pTar->Posix.magic[2] == 't'
338 && pTar->Posix.magic[3] == 'a'
339 && pTar->Posix.magic[4] == 'r')
340 {
341 if ( pTar->Posix.magic[5] == '\0'
342 && pTar->Posix.version[0] == '0'
343 && pTar->Posix.version[1] == '0')
344 enmType = RTZIPTARTYPE_POSIX;
345 else if ( pTar->Posix.magic[5] == ' '
346 && pTar->Posix.version[0] == ' '
347 && pTar->Posix.version[1] == '\0')
348 enmType = RTZIPTARTYPE_GNU;
349 else
350 return VERR_TAR_NOT_USTAR_V00;
351 }
352 else
353 enmType = RTZIPTARTYPE_ANCIENT;
354 *penmType = enmType;
355
356 /*
357 * Perform some basic checks.
358 */
359 /** @todo more/less? */
360 switch (pTar->Posix.typeflag)
361 {
362 case RTZIPTAR_TF_OLDNORMAL:
363 case RTZIPTAR_TF_NORMAL:
364 case RTZIPTAR_TF_CONTIG:
365 case RTZIPTAR_TF_LINK:
366 case RTZIPTAR_TF_SYMLINK:
367 case RTZIPTAR_TF_CHR:
368 case RTZIPTAR_TF_BLK:
369 case RTZIPTAR_TF_FIFO:
370 {
371 if (!pTar->Posix.name[0])
372 return VERR_TAR_EMPTY_NAME;
373
374 /** @todo People claim some (older and newer buggy) tar stores dirs as regular files with a trailing slash. */
375 const char *pchEnd = RTStrEnd(&pTar->Posix.name[0], sizeof(pTar->Posix.name));
376 pchEnd = pchEnd ? pchEnd - 1 : &pTar->Posix.name[sizeof(pTar->Posix.name) - 1];
377 if (*pchEnd == '/')
378 return VERR_TAR_NON_DIR_ENDS_WITH_SLASH;
379 break;
380 }
381
382 case RTZIPTAR_TF_DIR:
383 if (!pTar->Posix.name[0])
384 return VERR_TAR_EMPTY_NAME;
385 break;
386
387 case RTZIPTAR_TF_X_HDR:
388 case RTZIPTAR_TF_X_GLOBAL:
389 return VERR_TAR_UNSUPPORTED_PAX_TYPE;
390
391 case RTZIPTAR_TF_SOLARIS_XHDR:
392 return VERR_TAR_UNSUPPORTED_SOLARIS_HDR_TYPE;
393
394 case RTZIPTAR_TF_GNU_DUMPDIR:
395 case RTZIPTAR_TF_GNU_LONGLINK:
396 case RTZIPTAR_TF_GNU_LONGNAME:
397 case RTZIPTAR_TF_GNU_MULTIVOL:
398 case RTZIPTAR_TF_GNU_SPARSE:
399 case RTZIPTAR_TF_GNU_VOLDHR:
400 return VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE;
401 }
402
403
404 return VINF_SUCCESS;
405}
406
407
408/**
409 * Translate a TAR header to an IPRT object info structure with additional UNIX
410 * attributes.
411 *
412 * This completes the validation done by rtZipTarHdrValidate.
413 *
414 * @returns VINF_SUCCESS if valid, appropriate VERR_TAR_XXX if not.
415 * @param pTar The TAR header (input).
416 * @param pObjInfo The object info structure (output).
417 */
418static int rtZipTarHdrToFsObjInfo(PCRTZIPTARHDR pTar, PRTFSOBJINFO pObjInfo)
419{
420 /*
421 * Zap the whole structure, this takes care of unused space in the union.
422 */
423 RT_ZERO(*pObjInfo);
424
425 /*
426 * Convert the tar field in RTFSOBJINFO order.
427 */
428 int rc;
429 int64_t i64Tmp;
430#define GET_TAR_NUMERIC_FIELD_RET(a_Var, a_Field) \
431 do { \
432 rc = rtZipTarHdrFieldToNum(a_Field, sizeof(a_Field), false /*fOctalOnly*/, &i64Tmp); \
433 if (RT_FAILURE(rc)) \
434 return rc; \
435 (a_Var) = i64Tmp; \
436 if ((a_Var) != i64Tmp) \
437 return VERR_TAR_NUM_VALUE_TOO_LARGE; \
438 } while (0)
439
440 GET_TAR_NUMERIC_FIELD_RET(pObjInfo->cbObject, pTar->Posix.size);
441 pObjInfo->cbAllocated = RT_ALIGN_64(pObjInfo->cbObject, 512);
442 int64_t c64SecModTime;
443 GET_TAR_NUMERIC_FIELD_RET(c64SecModTime, pTar->Posix.mtime);
444 RTTimeSpecSetSeconds(&pObjInfo->ChangeTime, c64SecModTime);
445 RTTimeSpecSetSeconds(&pObjInfo->ModificationTime, c64SecModTime);
446 RTTimeSpecSetSeconds(&pObjInfo->AccessTime, c64SecModTime);
447 RTTimeSpecSetSeconds(&pObjInfo->BirthTime, c64SecModTime);
448 if (c64SecModTime != RTTimeSpecGetSeconds(&pObjInfo->ModificationTime))
449 return VERR_TAR_NUM_VALUE_TOO_LARGE;
450 GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.fMode, pTar->Posix.mode);
451 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
452 GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.uid, pTar->Posix.uid);
453 GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.gid, pTar->Posix.gid);
454 pObjInfo->Attr.u.Unix.cHardlinks = 1;
455 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
456 pObjInfo->Attr.u.Unix.INodeId = 0;
457 pObjInfo->Attr.u.Unix.fFlags = 0;
458 pObjInfo->Attr.u.Unix.GenerationId = 0;
459 pObjInfo->Attr.u.Unix.Device = 0;
460 if ( pTar->Posix.typeflag == RTZIPTAR_TF_CHR
461 || pTar->Posix.typeflag == RTZIPTAR_TF_BLK)
462 {
463 uint32_t uMajor, uMinor;
464 GET_TAR_NUMERIC_FIELD_RET(uMajor, pTar->Posix.devmajor);
465 GET_TAR_NUMERIC_FIELD_RET(uMinor, pTar->Posix.devminor);
466 pObjInfo->Attr.u.Unix.Device = RTDEV_MAKE(uMajor, uMinor);
467 if ( uMajor != RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device)
468 || uMinor != RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device))
469 return VERR_TAR_DEV_VALUE_TOO_LARGE;
470 }
471
472#undef GET_TAR_NUMERIC_FIELD_RET
473
474 /*
475 * Massage the result a little bit.
476 * Also validate some more now that we've got the numbers to work with.
477 */
478 if (pObjInfo->Attr.fMode & ~RTFS_UNIX_MASK)
479 return VERR_TAR_BAD_MODE_FIELD;
480
481 RTFMODE fModeType = 0;
482 switch (pTar->Posix.typeflag)
483 {
484 case RTZIPTAR_TF_OLDNORMAL:
485 case RTZIPTAR_TF_NORMAL:
486 case RTZIPTAR_TF_CONTIG:
487 fModeType |= RTFS_TYPE_FILE;
488 break;
489
490 case RTZIPTAR_TF_LINK:
491 if (pObjInfo->cbObject != 0)
492 return VERR_TAR_SIZE_NOT_ZERO;
493 fModeType |= RTFS_TYPE_FILE; /* no better idea for now */
494 break;
495
496 case RTZIPTAR_TF_SYMLINK:
497 fModeType |= RTFS_TYPE_SYMLINK;
498 break;
499
500 case RTZIPTAR_TF_CHR:
501 fModeType |= RTFS_TYPE_DEV_CHAR;
502 break;
503
504 case RTZIPTAR_TF_BLK:
505 fModeType |= RTFS_TYPE_DEV_BLOCK;
506 break;
507
508 case RTZIPTAR_TF_DIR:
509 fModeType |= RTFS_TYPE_DIRECTORY;
510 break;
511
512 case RTZIPTAR_TF_FIFO:
513 fModeType |= RTFS_TYPE_FIFO;
514 break;
515
516 default:
517 return VERR_TAR_UNKNOWN_TYPE_FLAG; /* Should've been caught in validate. */
518 }
519 if ( (pObjInfo->Attr.fMode & RTFS_TYPE_MASK)
520 && (pObjInfo->Attr.fMode & RTFS_TYPE_MASK) != fModeType)
521 return VERR_TAR_MODE_WITH_TYPE;
522 pObjInfo->Attr.fMode |= fModeType;
523
524 switch (pTar->Posix.typeflag)
525 {
526 case RTZIPTAR_TF_CHR:
527 case RTZIPTAR_TF_BLK:
528 case RTZIPTAR_TF_DIR:
529 case RTZIPTAR_TF_FIFO:
530 pObjInfo->cbObject = 0;
531 pObjInfo->cbAllocated = 0;
532 break;
533 }
534
535 return VINF_SUCCESS;
536}
537
538
539/*
540 *
541 * T h e V F S F i l e s y s t e m S t r e a m B i t s.
542 * T h e V F S F i l e s y s t e m S t r e a m B i t s.
543 * T h e V F S F i l e s y s t e m S t r e a m B i t s.
544 *
545 */
546
547/**
548 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
549 */
550static DECLCALLBACK(int) rtZipTarFssBaseObj_Close(void *pvThis)
551{
552 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
553
554 /* Currently there is nothing we really have to do here. */
555 pThis->offHdr = -1;
556
557 return VINF_SUCCESS;
558}
559
560
561/**
562 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
563 */
564static DECLCALLBACK(int) rtZipTarFssBaseObj_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
565{
566 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
567
568 /*
569 * Copy the desired data.
570 */
571 switch (enmAddAttr)
572 {
573 case RTFSOBJATTRADD_NOTHING:
574 case RTFSOBJATTRADD_UNIX:
575 *pObjInfo = pThis->ObjInfo;
576 break;
577
578 case RTFSOBJATTRADD_UNIX_OWNER:
579 *pObjInfo = pThis->ObjInfo;
580 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
581 pObjInfo->Attr.u.UnixOwner.uid = pThis->ObjInfo.Attr.u.Unix.uid;
582 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
583 if (rtZipTarHdrHasPosixUserName(&pThis->Hdr))
584 RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName), pThis->Hdr.Posix.uname);
585 break;
586
587 case RTFSOBJATTRADD_UNIX_GROUP:
588 *pObjInfo = pThis->ObjInfo;
589 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
590 pObjInfo->Attr.u.UnixGroup.gid = pThis->ObjInfo.Attr.u.Unix.gid;
591 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
592 if (rtZipTarHdrHasPosixGroupName(&pThis->Hdr))
593 RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName), pThis->Hdr.Posix.gname);
594 break;
595
596 case RTFSOBJATTRADD_EASIZE:
597 *pObjInfo = pThis->ObjInfo;
598 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
599 RT_ZERO(pObjInfo->Attr.u);
600 break;
601
602 default:
603 return VERR_NOT_SUPPORTED;
604 }
605
606 return VINF_SUCCESS;
607}
608
609
610/**
611 * Tar filesystem base object operations.
612 */
613static const RTVFSOBJOPS g_rtZipTarFssBaseObjOps =
614{
615 RTVFSOBJOPS_VERSION,
616 RTVFSOBJTYPE_BASE,
617 "TarFsStream::Obj",
618 rtZipTarFssBaseObj_Close,
619 rtZipTarFssBaseObj_QueryInfo,
620 RTVFSOBJOPS_VERSION
621};
622
623
624/**
625 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
626 */
627static DECLCALLBACK(int) rtZipTarFssIos_Close(void *pvThis)
628{
629 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
630
631 RTVfsIoStrmRelease(pThis->hVfsIos);
632 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
633
634 return rtZipTarFssBaseObj_Close(&pThis->BaseObj);
635}
636
637
638/**
639 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
640 */
641static DECLCALLBACK(int) rtZipTarFssIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
642{
643 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
644 return rtZipTarFssBaseObj_QueryInfo(&pThis->BaseObj, pObjInfo, enmAddAttr);
645}
646
647
648/**
649 * Reads one segment.
650 *
651 * @returns IPRT status code.
652 * @param pThis The instance data.
653 * @param pvBuf Where to put the read bytes.
654 * @param cbToRead The number of bytes to read.
655 * @param fBlocking Whether to block or not.
656 * @param pcbRead Where to store the number of bytes actually read.
657 */
658static int rtZipTarFssIos_ReadOneSeg(PRTZIPTARIOSTREAM pThis, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
659{
660 /*
661 * Fend of reads beyond the end of the stream here.
662 */
663 if (pThis->fEndOfStream)
664 return pcbRead ? VINF_EOF : VERR_EOF;
665
666 Assert(pThis->cbFile >= pThis->offFile);
667 uint64_t cbLeft = (uint64_t)(pThis->cbFile - pThis->offFile);
668 if (cbToRead > cbLeft)
669 {
670 if (!pcbRead)
671 return VERR_EOF;
672 cbToRead = (size_t)cbLeft;
673 }
674
675 /*
676 * Do the reading.
677 */
678 size_t cbReadStack = 0;
679 if (!pcbRead)
680 pcbRead = &cbReadStack;
681 int rc = RTVfsIoStrmRead(pThis->hVfsIos, pvBuf, cbToRead, fBlocking, pcbRead);
682 pThis->offFile += *pcbRead;
683 if (pThis->offFile >= pThis->cbFile)
684 {
685 Assert(pThis->offFile == pThis->cbFile);
686 pThis->fEndOfStream = true;
687 RTVfsIoStrmSkip(pThis->hVfsIos, pThis->cbPadding);
688 }
689
690 return rc;
691}
692
693
694/**
695 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
696 */
697static DECLCALLBACK(int) rtZipTarFssIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
698{
699 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
700 int rc;
701
702 if (pSgBuf->cSegs == 1)
703 rc = rtZipTarFssIos_ReadOneSeg(pThis, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, fBlocking, pcbRead);
704 else
705 {
706 rc = VINF_SUCCESS;
707 size_t cbRead = 0;
708 size_t cbReadSeg;
709 size_t *pcbReadSeg = pcbRead ? &cbReadSeg : NULL;
710 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
711 {
712 cbReadSeg = 0;
713 rc = rtZipTarFssIos_ReadOneSeg(pThis, pSgBuf->paSegs[iSeg].pvSeg, pSgBuf->paSegs[iSeg].cbSeg, fBlocking, pcbReadSeg);
714 if (RT_FAILURE(rc))
715 break;
716 if (pcbRead)
717 {
718 cbRead += cbReadSeg;
719 if (cbReadSeg != pSgBuf->paSegs[iSeg].cbSeg)
720 break;
721 }
722 }
723 if (pcbRead)
724 *pcbRead = cbRead;
725 }
726
727 return rc;
728}
729
730
731/**
732 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
733 */
734static DECLCALLBACK(int) rtZipTarFssIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
735{
736 /* Cannot write to a read-only I/O stream. */
737 NOREF(pvThis); NOREF(off); NOREF(pSgBuf); NOREF(fBlocking); NOREF(pcbWritten);
738 return VERR_ACCESS_DENIED;
739}
740
741
742/**
743 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
744 */
745static DECLCALLBACK(int) rtZipTarFssIos_Flush(void *pvThis)
746{
747 /* It's a read only stream, nothing dirty to flush. */
748 NOREF(pvThis);
749 return VINF_SUCCESS;
750}
751
752
753/**
754 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
755 */
756static DECLCALLBACK(int) rtZipTarFssIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
757 uint32_t *pfRetEvents)
758{
759 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
760
761 /* When we've reached the end, read will be set to indicate it. */
762 if ( (fEvents & RTPOLL_EVT_READ)
763 && pThis->fEndOfStream)
764 {
765 int rc = RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, 0, fIntr, pfRetEvents);
766 if (RT_SUCCESS(rc))
767 *pfRetEvents |= RTPOLL_EVT_READ;
768 else
769 *pfRetEvents = RTPOLL_EVT_READ;
770 return VINF_SUCCESS;
771 }
772
773 return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
774}
775
776
777/**
778 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
779 */
780static DECLCALLBACK(int) rtZipTarFssIos_Tell(void *pvThis, PRTFOFF poffActual)
781{
782 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
783 return pThis->offFile;
784}
785
786
787/**
788 * Tar I/O stream operations.
789 */
790static const RTVFSIOSTREAMOPS g_rtZipTarFssIosOps =
791{
792 { /* Obj */
793 RTVFSOBJOPS_VERSION,
794 RTVFSOBJTYPE_IO_STREAM,
795 "TarFsStream::IoStream",
796 rtZipTarFssIos_Close,
797 rtZipTarFssIos_QueryInfo,
798 RTVFSOBJOPS_VERSION
799 },
800 RTVFSIOSTREAMOPS_VERSION,
801 0,
802 rtZipTarFssIos_Read,
803 rtZipTarFssIos_Write,
804 rtZipTarFssIos_Flush,
805 rtZipTarFssIos_PollOne,
806 rtZipTarFssIos_Tell,
807 NULL /*Skip*/,
808 NULL /*ZeroFill*/,
809 RTVFSIOSTREAMOPS_VERSION
810};
811
812
813/**
814 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
815 */
816static DECLCALLBACK(int) rtZipTarFssSym_Close(void *pvThis)
817{
818 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
819 return rtZipTarFssBaseObj_Close(pThis);
820}
821
822
823/**
824 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
825 */
826static DECLCALLBACK(int) rtZipTarFssSym_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
827{
828 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
829 return rtZipTarFssBaseObj_QueryInfo(pThis, pObjInfo, enmAddAttr);
830}
831
832/**
833 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
834 */
835static DECLCALLBACK(int) rtZipTarFssSym_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
836{
837 NOREF(pvThis); NOREF(fMode); NOREF(fMask);
838 return VERR_ACCESS_DENIED;
839}
840
841
842/**
843 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
844 */
845static DECLCALLBACK(int) rtZipTarFssSym_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
846 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
847{
848 NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
849 return VERR_ACCESS_DENIED;
850}
851
852
853/**
854 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
855 */
856static DECLCALLBACK(int) rtZipTarFssSym_SetOwner(void *pvThis, RTUID uid, RTGID gid)
857{
858 NOREF(pvThis); NOREF(uid); NOREF(gid);
859 return VERR_ACCESS_DENIED;
860}
861
862
863/**
864 * @interface_method_impl{RTVFSSYMLINKOPS,pfnRead}
865 */
866static DECLCALLBACK(int) rtZipTarFssSym_Read(void *pvThis, char *pszTarget, size_t cbTarget)
867{
868 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;
869 return RTStrCopy(pszTarget, cbTarget, pThis->Hdr.Posix.linkname);
870}
871
872
873/**
874 * Tar symbolic (and hardlink) operations.
875 */
876static const RTVFSSYMLINKOPS g_rtZipTarFssSymOps =
877{
878 { /* Obj */
879 RTVFSOBJOPS_VERSION,
880 RTVFSOBJTYPE_SYMLINK,
881 "TarFsStream::Symlink",
882 rtZipTarFssSym_Close,
883 rtZipTarFssSym_QueryInfo,
884 RTVFSOBJOPS_VERSION
885 },
886 RTVFSSYMLINKOPS_VERSION,
887 0,
888 { /* ObjSet */
889 RTVFSOBJSETOPS_VERSION,
890 RT_OFFSETOF(RTVFSSYMLINKOPS, Obj) - RT_OFFSETOF(RTVFSSYMLINKOPS, ObjSet),
891 rtZipTarFssSym_SetMode,
892 rtZipTarFssSym_SetTimes,
893 rtZipTarFssSym_SetOwner,
894 RTVFSOBJSETOPS_VERSION
895 },
896 rtZipTarFssSym_Read,
897 RTVFSSYMLINKOPS_VERSION
898};
899
900
901/**
902 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
903 */
904static DECLCALLBACK(int) rtZipTarFss_Close(void *pvThis)
905{
906 PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
907
908 RTVfsObjRelease(pThis->hVfsCurObj);
909 pThis->hVfsCurObj = NIL_RTVFSOBJ;
910 pThis->pCurIosData = NULL;
911
912 RTVfsIoStrmRelease(pThis->hVfsIos);
913 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
914
915 return VINF_SUCCESS;
916}
917
918
919/**
920 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
921 */
922static DECLCALLBACK(int) rtZipTarFss_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
923{
924 PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
925 /* Take the lazy approach here, with the sideffect of providing some info
926 that is actually kind of useful. */
927 return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
928}
929
930
931/**
932 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
933 */
934static DECLCALLBACK(int) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
935{
936 PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
937
938 /*
939 * Dispense with the current object.
940 */
941 if (pThis->hVfsCurObj != NIL_RTVFSOBJ)
942 {
943 if (pThis->pCurIosData)
944 {
945 pThis->pCurIosData->fEndOfStream = true;
946 pThis->pCurIosData->offFile = pThis->pCurIosData->cbFile;
947 pThis->pCurIosData = NULL;
948 }
949
950 RTVfsObjRelease(pThis->hVfsCurObj);
951 pThis->hVfsCurObj = NIL_RTVFSOBJ;
952 }
953
954 /*
955 * Check if we've already reached the end in some way.
956 */
957 if (pThis->fEndOfStream)
958 return VERR_EOF;
959 if (pThis->rcFatal != VINF_SUCCESS)
960 return pThis->rcFatal;
961
962 /*
963 * Make sure the input stream is in the right place.
964 */
965 RTFOFF off = RTVfsIoStrmTell(pThis->hVfsIos);
966 while ( off >= 0
967 && off < pThis->offNextHdr)
968 {
969 int rc = RTVfsIoStrmSkip(pThis->hVfsIos, pThis->offNextHdr - off);
970 if (RT_FAILURE(rc))
971 {
972 /** @todo Ignore if we're at the end of the stream? */
973 return pThis->rcFatal = rc;
974 }
975
976 off = RTVfsIoStrmTell(pThis->hVfsIos);
977 }
978
979 if (off < 0)
980 return pThis->rcFatal = (int)off;
981 if (off > pThis->offNextHdr)
982 return pThis->rcFatal = VERR_INTERNAL_ERROR_3;
983
984 /*
985 * Read the next header.
986 */
987 size_t cbRead;
988 RTZIPTARHDR Hdr;
989 int rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
990 if (RT_FAILURE(rc))
991 return pThis->rcFatal = rc;
992 if (rc == VINF_EOF && cbRead == 0)
993 {
994 pThis->fEndOfStream = true;
995 return VERR_EOF;
996 }
997 if (cbRead != sizeof(Hdr))
998 return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS;
999
1000 pThis->offNextHdr = off + sizeof(Hdr);
1001
1002 /*
1003 * Validate the header and convert to binary object info.
1004 * We pick up the start of the zero headers here in the failure path.
1005 */
1006 RTZIPTARTYPE enmTarType;
1007 rc = rtZipTarHdrValidate(&Hdr, &enmTarType);
1008 if (RT_FAILURE_NP(rc))
1009 {
1010 if (rc == VERR_TAR_ZERO_HEADER)
1011 {
1012 int rc2 = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
1013 if (RT_FAILURE(rc2))
1014 return pThis->rcFatal = rc2;
1015 if (ASMMemIsAllU32(&Hdr, sizeof(Hdr), 0) == NULL)
1016 {
1017 pThis->fEndOfStream = true;
1018 if (RTVfsIoStrmIsAtEnd(pThis->hVfsIos))
1019 return VERR_EOF;
1020
1021 /* Just drain the stream because blocksize may dictate that
1022 there is a whole bunch of stuff comming up. */
1023 for (uint32_t i = 0; i < _32K / 512; i++)
1024 {
1025 rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
1026 if (rc == VINF_EOF)
1027 return VERR_EOF;
1028 if (RT_FAILURE(rc))
1029 break;
1030 Assert(cbRead == sizeof(Hdr));
1031 }
1032 }
1033 }
1034
1035 return pThis->rcFatal = rc;
1036 }
1037
1038 RTFSOBJINFO Info;
1039 rc = rtZipTarHdrToFsObjInfo(&Hdr, &Info);
1040 if (RT_FAILURE(rc))
1041 return pThis->rcFatal = rc;
1042
1043 /*
1044 * Create an object of the appropriate type.
1045 */
1046 RTVFSOBJTYPE enmType;
1047 RTVFSOBJ hVfsObj;
1048 switch (Hdr.Posix.typeflag)
1049 {
1050 /*
1051 * Files are represented by a VFS I/O stream.
1052 */
1053 case RTZIPTAR_TF_NORMAL:
1054 case RTZIPTAR_TF_OLDNORMAL:
1055 case RTZIPTAR_TF_CONTIG:
1056 {
1057 RTVFSIOSTREAM hVfsIos;
1058 PRTZIPTARIOSTREAM pIosData;
1059 rc = RTVfsNewIoStream(&g_rtZipTarFssIosOps,
1060 sizeof(*pIosData),
1061 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
1062 NIL_RTVFS,
1063 NIL_RTVFSLOCK,
1064 &hVfsIos,
1065 (void **)&pIosData);
1066 if (RT_FAILURE(rc))
1067 return pThis->rcFatal = rc;
1068
1069 pIosData->BaseObj.offHdr = off;
1070 pIosData->BaseObj.Hdr = Hdr;
1071 pIosData->BaseObj.ObjInfo = Info;
1072 pIosData->cbFile = Info.cbObject;
1073 pIosData->offFile = 0;
1074 pIosData->cbPadding = Info.cbAllocated - Info.cbObject;
1075 pIosData->fEndOfStream = false;
1076 pIosData->hVfsIos = pThis->hVfsIos;
1077 RTVfsIoStrmRetain(pThis->hVfsIos);
1078
1079 pThis->pCurIosData = pIosData;
1080 pThis->offNextHdr += pIosData->cbFile + pIosData->cbPadding;
1081
1082 enmType = RTVFSOBJTYPE_IO_STREAM;
1083 hVfsObj = RTVfsObjFromIoStream(hVfsIos);
1084 RTVfsIoStrmRelease(hVfsIos);
1085 break;
1086 }
1087
1088 /*
1089 * We represent hard links using a symbolic link object. This fits
1090 * best with the way TAR stores it and there is currently no better
1091 * fitting VFS type alternative.
1092 */
1093 case RTZIPTAR_TF_LINK:
1094 case RTZIPTAR_TF_SYMLINK:
1095 {
1096 RTVFSSYMLINK hVfsSym;
1097 PRTZIPTARBASEOBJ pBaseObjData;
1098 rc = RTVfsNewSymlink(&g_rtZipTarFssSymOps,
1099 sizeof(*pBaseObjData),
1100 NIL_RTVFS,
1101 NIL_RTVFSLOCK,
1102 &hVfsSym,
1103 (void **)&pBaseObjData);
1104 if (RT_FAILURE(rc))
1105 return pThis->rcFatal = rc;
1106
1107 pBaseObjData->offHdr = off;
1108 pBaseObjData->Hdr = Hdr;
1109 pBaseObjData->ObjInfo = Info;
1110
1111 enmType = RTVFSOBJTYPE_SYMLINK;
1112 hVfsObj = RTVfsObjFromSymlink(hVfsSym);
1113 RTVfsSymlinkRelease(hVfsSym);
1114 break;
1115 }
1116
1117 /*
1118 * All other objects are repesented using a VFS base object since they
1119 * carry no data streams (unless some tar extension implements extended
1120 * attributes / alternative streams).
1121 */
1122 case RTZIPTAR_TF_CHR:
1123 case RTZIPTAR_TF_BLK:
1124 case RTZIPTAR_TF_DIR:
1125 case RTZIPTAR_TF_FIFO:
1126 {
1127 PRTZIPTARBASEOBJ pBaseObjData;
1128 rc = RTVfsNewBaseObj(&g_rtZipTarFssBaseObjOps,
1129 sizeof(*pBaseObjData),
1130 NIL_RTVFS,
1131 NIL_RTVFSLOCK,
1132 &hVfsObj,
1133 (void **)&pBaseObjData);
1134 if (RT_FAILURE(rc))
1135 return pThis->rcFatal = rc;
1136
1137 pBaseObjData->offHdr = off;
1138 pBaseObjData->Hdr = Hdr;
1139 pBaseObjData->ObjInfo = Info;
1140
1141 enmType = RTVFSOBJTYPE_BASE;
1142 break;
1143 }
1144
1145 default:
1146 AssertFailed();
1147 return pThis->rcFatal = VERR_INTERNAL_ERROR_5;
1148 }
1149 pThis->hVfsCurObj = hVfsObj;
1150
1151 /*
1152 * Set the return data and we're done.
1153 */
1154 if (ppszName)
1155 {
1156 if (rtZipTarHdrHasPrefix(&Hdr))
1157 {
1158 *ppszName = NULL;
1159 rc = RTStrAAppendExN(ppszName, 3,
1160 Hdr.Posix.prefix, sizeof(Hdr.Posix.prefix),
1161 "/", 1,
1162 Hdr.Posix.name, sizeof(Hdr.Posix.name));
1163 }
1164 else
1165 {
1166 *ppszName = RTStrDupN(Hdr.Posix.name, sizeof(Hdr.Posix.name));
1167 rc = *ppszName ? VINF_SUCCESS : VERR_NO_STR_MEMORY;
1168 }
1169 if (RT_FAILURE(rc))
1170 return rc;
1171 }
1172
1173 if (phVfsObj)
1174 {
1175 RTVfsObjRetain(hVfsObj);
1176 *phVfsObj = hVfsObj;
1177 }
1178
1179 if (penmType)
1180 *penmType = enmType;
1181
1182 return VINF_SUCCESS;
1183}
1184
1185
1186
1187/**
1188 * Tar filesystem stream operations.
1189 */
1190static const RTVFSFSSTREAMOPS rtZipTarFssOps =
1191{
1192 { /* Obj */
1193 RTVFSOBJOPS_VERSION,
1194 RTVFSOBJTYPE_FS_STREAM,
1195 "TarFsStream",
1196 rtZipTarFss_Close,
1197 rtZipTarFss_QueryInfo,
1198 RTVFSOBJOPS_VERSION
1199 },
1200 RTVFSFSSTREAMOPS_VERSION,
1201 0,
1202 rtZipTarFss_Next,
1203 RTVFSFSSTREAMOPS_VERSION
1204};
1205
1206
1207RTDECL(int) RTZipTarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
1208{
1209 /*
1210 * Input validation.
1211 */
1212 AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
1213 *phVfsFss = NIL_RTVFSFSSTREAM;
1214 AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE);
1215 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1216
1217 RTFOFF const offStart = RTVfsIoStrmTell(hVfsIosIn);
1218 AssertReturn(offStart >= 0, (int)offStart);
1219
1220 uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn);
1221 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
1222
1223 /*
1224 * Retain the input stream and create a new filesystem stream handle.
1225 */
1226 PRTZIPTARFSSTREAM pThis;
1227 RTVFSFSSTREAM hVfsFss;
1228 int rc = RTVfsNewFsStream(&rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFss, (void **)&pThis);
1229 if (RT_SUCCESS(rc))
1230 {
1231 pThis->hVfsIos = hVfsIosIn;
1232 pThis->hVfsCurObj = NIL_RTVFSOBJ;
1233 pThis->pCurIosData = NULL;
1234 pThis->offStart = offStart;
1235 pThis->offNextHdr = offStart;
1236 pThis->fEndOfStream = false;
1237 pThis->rcFatal = VINF_SUCCESS;
1238
1239 /* Don't check if it's a TAR stream here, do that in the
1240 rtZipTarFss_Next. */
1241
1242 *phVfsFss = hVfsFss;
1243 return VINF_SUCCESS;
1244 }
1245
1246 RTVfsIoStrmRelease(hVfsIosIn);
1247 return rc;
1248}
1249
Note: See TracBrowser for help on using the repository browser.

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