VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/zip/cpiovfs.cpp@ 106580

Last change on this file since 106580 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.7 KB
Line 
1/* $Id: cpiovfs.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - CPIO Virtual Filesystem, Reader.
4 */
5
6/*
7 * Copyright (C) 2020-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "internal/iprt.h"
42#include <iprt/zip.h>
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/ctype.h>
47#include <iprt/err.h>
48#include <iprt/poll.h>
49#include <iprt/file.h>
50#include <iprt/string.h>
51#include <iprt/vfs.h>
52#include <iprt/vfslowlevel.h>
53
54#include "cpiovfsreader.h"
55
56
57/**
58 * Converts a octal numeric header field to the C native type.
59 *
60 * @returns IPRT status code.
61 * @param pachField The CPIO header field.
62 * @param cchField The length of the field.
63 * @param pi64 Where to store the value.
64 */
65static int rtZipCpioHdrOctalFieldToNum(const char *pachField, size_t cchField, int64_t *pi64)
66{
67 /*
68 * Skip leading zeros to save a few slower loops below.
69 */
70 while (cchField > 0 && *pachField == '0')
71 cchField--, pachField++;
72
73 /*
74 * Convert octal digits.
75 */
76 int64_t i64 = 0;
77 while (cchField > 0)
78 {
79 unsigned char uDigit = *pachField - '0';
80 if (uDigit >= 8)
81 return VERR_TAR_BAD_NUM_FIELD;
82 i64 <<= 3;
83 i64 |= uDigit;
84
85 pachField++;
86 cchField--;
87 }
88 *pi64 = i64;
89
90 return VINF_SUCCESS;
91}
92
93
94/**
95 * Converts a hex character to the appropriate nibble.
96 *
97 * @returns Nibble of the character.
98 * @param chVal The value to convert.
99 */
100static inline uint8_t rtZipCpioHexToNibble(char chVal)
101{
102 if (chVal >= '0' && chVal <= '9')
103 return chVal - '0';
104 else if (chVal >= 'a' && chVal <= 'f')
105 return chVal - 'a' + 10;
106 else if (chVal >= 'A' && chVal <= 'F')
107 return chVal - 'A' + 10;
108
109 return 0xff;
110}
111
112
113/**
114 * Converts a hexadecimal numeric header field to the C native type.
115 *
116 * @returns IPRT status code.
117 * @param pachField The CPIO header field.
118 * @param cchField The length of the field.
119 * @param pi64 Where to store the value.
120 */
121static int rtZipCpioHdrHexFieldToNum(const char *pachField, size_t cchField, int64_t *pi64)
122{
123 uint64_t u64 = 0;
124
125 while (cchField-- > 0)
126 {
127 uint8_t bNb = rtZipCpioHexToNibble(*pachField++);
128
129 if (RT_LIKELY(bNb != 0xff))
130 u64 = (u64 << 4) | bNb;
131 else
132 return VERR_TAR_BAD_NUM_FIELD;
133 }
134
135 *pi64 = (int64_t)u64;
136 return VINF_SUCCESS;
137}
138
139
140/**
141 * Parses the given ancient binary header and converts it to an FS object info structure.
142 *
143 * @returns IPRT status code.
144 * @param pThis The CPIO reader state.
145 * @param pHdr The header to convert.
146 * @param pcbFilePath Where to store the file path size on success.
147 * @param pcbPad Where to store the number of bytes padded after the header and file path
148 * before the content begins.
149 */
150static int rtZipCpioReaderParseHeaderAncientBin(PRTZIPCPIOREADER pThis, PCCPIOHDRBIN pHdr,
151 uint32_t *pcbFilePath, uint32_t *pcbPad)
152{
153 RT_NOREF(pThis, pHdr, pcbFilePath, pcbPad);
154 return VERR_NOT_SUPPORTED;
155}
156
157
158/**
159 * Parses the given SuSv2 ASCII header and converts it to an FS object info structure.
160 *
161 * @returns IPRT status code.
162 * @param pThis The CPIO reader state.
163 * @param pHdr The header to convert.
164 * @param pcbFilePath Where to store the file path size on success.
165 * @param pcbPad Where to store the number of bytes padded after the header and file path
166 * before the content begins.
167 */
168static int rtZipCpioReaderParseHeaderAsciiSusV2(PRTZIPCPIOREADER pThis, PCCPIOHDRSUSV2 pHdr,
169 uint32_t *pcbFilePath, uint32_t *pcbPad)
170{
171 PRTFSOBJINFO pObjInfo = &pThis->ObjInfo;
172 int rc;
173 int64_t i64Tmp;
174 int64_t c64SecModTime;
175
176 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
177 pObjInfo->Attr.u.Unix.Device = 0;
178 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
179
180#define GET_CPIO_NUMERIC_FIELD_RET(a_Var, a_Field) \
181 do { \
182 rc = rtZipCpioHdrOctalFieldToNum(a_Field, sizeof(a_Field), &i64Tmp); \
183 if (RT_FAILURE(rc)) \
184 return rc; \
185 (a_Var) = i64Tmp; \
186 if ((a_Var) != i64Tmp) \
187 return VERR_TAR_NUM_VALUE_TOO_LARGE; \
188 } while (0)
189
190#define GET_CPIO_NUMERIC_FIELD_RET_U64(a_Var, a_Field) \
191 do { \
192 rc = rtZipCpioHdrOctalFieldToNum(a_Field, sizeof(a_Field), &i64Tmp); \
193 if (RT_FAILURE(rc)) \
194 return rc; \
195 (a_Var) = (uint64_t)i64Tmp; \
196 if ((a_Var) != (uint64_t)i64Tmp) \
197 return VERR_TAR_NUM_VALUE_TOO_LARGE; \
198 } while (0)
199
200 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->Attr.fMode, pHdr->achMode);
201 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->Attr.u.Unix.uid, pHdr->achUid);
202 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->Attr.u.Unix.gid, pHdr->achGid);
203 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->Attr.u.Unix.cHardlinks, pHdr->achNLinks);
204 GET_CPIO_NUMERIC_FIELD_RET_U64(pObjInfo->Attr.u.Unix.INodeId, pHdr->achInode);
205 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->Attr.u.Unix.Device, pHdr->achDev);
206 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->cbObject, pHdr->achFileSize);
207 pObjInfo->cbAllocated = pObjInfo->cbObject;
208 GET_CPIO_NUMERIC_FIELD_RET( c64SecModTime, pHdr->achMTime);
209 RTTimeSpecSetSeconds(&pObjInfo->ChangeTime, c64SecModTime);
210 RTTimeSpecSetSeconds(&pObjInfo->ModificationTime, c64SecModTime);
211 RTTimeSpecSetSeconds(&pObjInfo->AccessTime, c64SecModTime);
212 RTTimeSpecSetSeconds(&pObjInfo->BirthTime, c64SecModTime);
213 if (c64SecModTime != RTTimeSpecGetSeconds(&pObjInfo->ModificationTime))
214 return VERR_TAR_NUM_VALUE_TOO_LARGE;
215
216 GET_CPIO_NUMERIC_FIELD_RET(*pcbFilePath, pHdr->achNameSize);
217
218 /* There is never any padding. */
219 *pcbPad = 0;
220
221#undef GET_CPIO_NUMERIC_FIELD_RET
222#undef GET_CPIO_NUMERIC_FIELD_RET_U64
223
224 return rc;
225}
226
227
228/**
229 * Parses the given "new" ASCII header and converts it to an FS object info structure.
230 *
231 * @returns IPRT status code.
232 * @param pThis The CPIO reader state.
233 * @param pHdr The header to convert.
234 * @param fWithChksum Flag whether the header uses the checksum field.
235 * @param pcbFilePath Where to store the file path size on success.
236 * @param pcbPad Where to store the number of bytes padded after the header and file path
237 * before the content begins.
238 */
239static int rtZipCpioReaderParseHeaderAsciiNew(PRTZIPCPIOREADER pThis, PCCPIOHDRNEW pHdr, bool fWithChksum,
240 uint32_t *pcbFilePath, uint32_t *pcbPad)
241{
242 RT_NOREF(fWithChksum); /** @todo */
243 PRTFSOBJINFO pObjInfo = &pThis->ObjInfo;
244 int rc;
245 int64_t i64Tmp;
246 int64_t c64SecModTime;
247 uint32_t uMajor, uMinor;
248
249 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
250 pObjInfo->Attr.u.Unix.Device = 0;
251 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
252
253#define GET_CPIO_NUMERIC_FIELD_RET(a_Var, a_Field) \
254 do { \
255 rc = rtZipCpioHdrHexFieldToNum(a_Field, sizeof(a_Field), &i64Tmp); \
256 if (RT_FAILURE(rc)) \
257 return rc; \
258 (a_Var) = i64Tmp; \
259 if ((a_Var) != i64Tmp) \
260 return VERR_TAR_NUM_VALUE_TOO_LARGE; \
261 } while (0)
262
263#define GET_CPIO_NUMERIC_FIELD_RET_U64(a_Var, a_Field) \
264 do { \
265 rc = rtZipCpioHdrHexFieldToNum(a_Field, sizeof(a_Field), &i64Tmp); \
266 if (RT_FAILURE(rc)) \
267 return rc; \
268 (a_Var) = (uint64_t)i64Tmp; \
269 if ((a_Var) != (uint64_t)i64Tmp) \
270 return VERR_TAR_NUM_VALUE_TOO_LARGE; \
271 } while (0)
272
273 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->Attr.fMode, pHdr->achMode);
274 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->Attr.u.Unix.uid, pHdr->achUid);
275 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->Attr.u.Unix.gid, pHdr->achGid);
276 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->Attr.u.Unix.cHardlinks, pHdr->achNLinks);
277 GET_CPIO_NUMERIC_FIELD_RET_U64(pObjInfo->Attr.u.Unix.INodeId, pHdr->achInode);
278 GET_CPIO_NUMERIC_FIELD_RET( uMajor, pHdr->achDevMajor);
279 GET_CPIO_NUMERIC_FIELD_RET( uMinor, pHdr->achDevMinor);
280 GET_CPIO_NUMERIC_FIELD_RET( pObjInfo->cbObject, pHdr->achFileSize);
281 pObjInfo->cbAllocated = RT_ALIGN_64(pObjInfo->cbObject, 4);
282 GET_CPIO_NUMERIC_FIELD_RET( c64SecModTime, pHdr->achMTime);
283 RTTimeSpecSetSeconds(&pObjInfo->ChangeTime, c64SecModTime);
284 RTTimeSpecSetSeconds(&pObjInfo->ModificationTime, c64SecModTime);
285 RTTimeSpecSetSeconds(&pObjInfo->AccessTime, c64SecModTime);
286 RTTimeSpecSetSeconds(&pObjInfo->BirthTime, c64SecModTime);
287 if (c64SecModTime != RTTimeSpecGetSeconds(&pObjInfo->ModificationTime))
288 return VERR_TAR_NUM_VALUE_TOO_LARGE;
289 pObjInfo->Attr.u.Unix.Device = RTDEV_MAKE(uMajor, uMinor);
290 if ( uMajor != RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device)
291 || uMinor != RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device))
292 return VERR_TAR_DEV_VALUE_TOO_LARGE;
293
294 GET_CPIO_NUMERIC_FIELD_RET(*pcbFilePath, pHdr->achNameSize);
295
296 /* Header and file path are padded with 0 bytes to a 4 byte boundary. */
297 uint32_t cbComp = *pcbFilePath + sizeof(*pHdr);
298 *pcbPad = RT_ALIGN_32(cbComp, 4) - cbComp;
299
300#undef GET_CPIO_NUMERIC_FIELD_RET
301#undef GET_CPIO_NUMERIC_FIELD_RET_U64
302
303 return rc;
304}
305
306
307/**
308 * Parses and validates a CPIO header.
309 *
310 * @returns IPRT status code.
311 * @param pThis The CPIO reader state.
312 * @param enmType The CPIO header type.
313 * @param pHdr The CPIO header that has been read.
314 * @param pcbFilePath Where to store the size of the file path on success.
315 * @param pcbPad Where to store the number of bytes padded after the header and file path
316 * before the content begins.
317 */
318static int rtZipCpioReaderParseHeader(PRTZIPCPIOREADER pThis, RTZIPCPIOTYPE enmType, PCCPIOHDR pHdr,
319 uint32_t *pcbFilePath, uint32_t *pcbPad)
320{
321 int rc;
322
323 switch (enmType)
324 {
325 case RTZIPCPIOTYPE_ANCIENT_BIN:
326 rc = rtZipCpioReaderParseHeaderAncientBin(pThis, &pHdr->AncientBin,
327 pcbFilePath, pcbPad);
328 break;
329 case RTZIPCPIOTYPE_ASCII_SUSV2:
330 rc = rtZipCpioReaderParseHeaderAsciiSusV2(pThis, &pHdr->AsciiSuSv2,
331 pcbFilePath, pcbPad);
332 break;
333 case RTZIPCPIOTYPE_ASCII_NEW:
334 rc = rtZipCpioReaderParseHeaderAsciiNew(pThis, &pHdr->AsciiNew, false /*fWithChksum*/,
335 pcbFilePath, pcbPad);
336 break;
337 case RTZIPCPIOTYPE_ASCII_NEW_CHKSUM:
338 rc = rtZipCpioReaderParseHeaderAsciiNew(pThis, &pHdr->AsciiNew, true /*fWithChksum*/,
339 pcbFilePath, pcbPad);
340 break;
341 default:
342 AssertMsgFailedBreakStmt(("Invalid CPIO type %d\n", enmType), rc = VERR_INTERNAL_ERROR);
343 }
344
345 return rc;
346}
347
348
349/**
350 * Reads the file path from the CPIO archive stream.
351 *
352 * @returns IPRT status code.
353 * @param hVfsIos The I/O stream to read from.
354 * @param pThis The CPIO reader state.
355 * @param cbFilePath Size of the file path in bytes.
356 */
357static int rtZipCpioReaderReadPath(RTVFSIOSTREAM hVfsIos, PRTZIPCPIOREADER pThis, size_t cbFilePath)
358{
359 if (cbFilePath >= sizeof(pThis->szName))
360 return VERR_TAR_NAME_TOO_LONG;
361
362 size_t cbRead;
363 int rc = RTVfsIoStrmRead(hVfsIos, &pThis->szName[0], cbFilePath, true /*fBlocking*/, &cbRead);
364 if (RT_FAILURE(rc))
365 return rc;
366 if (cbRead != cbFilePath)
367 return VERR_TAR_UNEXPECTED_EOS;
368
369 /* The read file name should be zero terminated at the end. */
370 if (pThis->szName[cbFilePath - 1] != '\0')
371 return VERR_TAR_MALFORMED_GNU_LONGXXXX;
372
373 return VINF_SUCCESS;
374}
375
376
377/*
378 *
379 * 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.
380 * 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.
381 * 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.
382 *
383 */
384
385/**
386 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
387 */
388static DECLCALLBACK(int) rtZipCpioFssBaseObj_Close(void *pvThis)
389{
390 PRTZIPCPIOBASEOBJ pThis = (PRTZIPCPIOBASEOBJ)pvThis;
391
392 /* Currently there is nothing we really have to do here. */
393 pThis->offHdr = -1;
394
395 return VINF_SUCCESS;
396}
397
398
399/**
400 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
401 */
402static DECLCALLBACK(int) rtZipCpioFssBaseObj_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
403{
404 PRTZIPCPIOBASEOBJ pThis = (PRTZIPCPIOBASEOBJ)pvThis;
405
406 /*
407 * Copy the desired data.
408 */
409 switch (enmAddAttr)
410 {
411 case RTFSOBJATTRADD_NOTHING:
412 case RTFSOBJATTRADD_UNIX:
413 *pObjInfo = pThis->ObjInfo;
414 break;
415
416 case RTFSOBJATTRADD_UNIX_OWNER:
417 *pObjInfo = pThis->ObjInfo;
418 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
419 pObjInfo->Attr.u.UnixOwner.uid = pThis->ObjInfo.Attr.u.Unix.uid;
420 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
421 break;
422
423 case RTFSOBJATTRADD_UNIX_GROUP:
424 *pObjInfo = pThis->ObjInfo;
425 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
426 pObjInfo->Attr.u.UnixGroup.gid = pThis->ObjInfo.Attr.u.Unix.gid;
427 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
428 break;
429
430 case RTFSOBJATTRADD_EASIZE:
431 *pObjInfo = pThis->ObjInfo;
432 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
433 RT_ZERO(pObjInfo->Attr.u);
434 break;
435
436 default:
437 return VERR_NOT_SUPPORTED;
438 }
439
440 return VINF_SUCCESS;
441}
442
443
444/**
445 * Tar filesystem base object operations.
446 */
447static const RTVFSOBJOPS g_rtZipCpioFssBaseObjOps =
448{
449 RTVFSOBJOPS_VERSION,
450 RTVFSOBJTYPE_BASE,
451 "CpioFsStream::Obj",
452 rtZipCpioFssBaseObj_Close,
453 rtZipCpioFssBaseObj_QueryInfo,
454 NULL,
455 RTVFSOBJOPS_VERSION
456};
457
458
459/**
460 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
461 */
462static DECLCALLBACK(int) rtZipCpioFssIos_Close(void *pvThis)
463{
464 PRTZIPCPIOIOSTREAM pThis = (PRTZIPCPIOIOSTREAM)pvThis;
465
466 RTVfsIoStrmRelease(pThis->hVfsIos);
467 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
468
469 return rtZipCpioFssBaseObj_Close(&pThis->BaseObj);
470}
471
472
473/**
474 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
475 */
476static DECLCALLBACK(int) rtZipCpioFssIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
477{
478 PRTZIPCPIOIOSTREAM pThis = (PRTZIPCPIOIOSTREAM)pvThis;
479 return rtZipCpioFssBaseObj_QueryInfo(&pThis->BaseObj, pObjInfo, enmAddAttr);
480}
481
482
483/**
484 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
485 */
486static DECLCALLBACK(int) rtZipCpioFssIos_Read(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
487{
488 PRTZIPCPIOIOSTREAM pThis = (PRTZIPCPIOIOSTREAM)pvThis;
489 Assert(pSgBuf->cSegs == 1);
490
491 /*
492 * Make offset into a real offset so it's possible to do random access
493 * on CPIO files that are seekable. Fend of reads beyond the end of the
494 * stream.
495 */
496 if (off < 0)
497 off = pThis->offFile;
498 if (off >= pThis->cbFile)
499 return pcbRead ? VINF_EOF : VERR_EOF;
500
501
502 Assert(pThis->cbFile >= pThis->offFile);
503 uint64_t cbLeft = (uint64_t)(pThis->cbFile - off);
504 size_t cbToRead = pSgBuf->paSegs[0].cbSeg;
505 if (cbToRead > cbLeft)
506 {
507 if (!pcbRead)
508 return VERR_EOF;
509 cbToRead = (size_t)cbLeft;
510 }
511
512 /*
513 * Do the reading.
514 */
515 size_t cbReadStack = 0;
516 if (!pcbRead)
517 pcbRead = &cbReadStack;
518 int rc = RTVfsIoStrmReadAt(pThis->hVfsIos, pThis->offStart + off, pSgBuf->paSegs[0].pvSeg, cbToRead, fBlocking, pcbRead);
519 pThis->offFile = off + *pcbRead;
520 RTSgBufAdvance(pSgBuf, *pcbRead);
521
522 if (pThis->offFile >= pThis->cbFile)
523 {
524 Assert(pThis->offFile == pThis->cbFile);
525 pThis->fEndOfStream = true;
526 RTVfsIoStrmSkip(pThis->hVfsIos, pThis->cbPadding);
527 }
528
529 return rc;
530}
531
532
533/**
534 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
535 */
536static DECLCALLBACK(int) rtZipCpioFssIos_Write(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
537{
538 /* Cannot write to a read-only I/O stream. */
539 NOREF(pvThis); NOREF(off); NOREF(pSgBuf); NOREF(fBlocking); NOREF(pcbWritten);
540 return VERR_ACCESS_DENIED;
541}
542
543
544/**
545 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
546 */
547static DECLCALLBACK(int) rtZipCpioFssIos_Flush(void *pvThis)
548{
549 /* It's a read only stream, nothing dirty to flush. */
550 NOREF(pvThis);
551 return VINF_SUCCESS;
552}
553
554
555/**
556 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
557 */
558static DECLCALLBACK(int) rtZipCpioFssIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
559 uint32_t *pfRetEvents)
560{
561 PRTZIPCPIOIOSTREAM pThis = (PRTZIPCPIOIOSTREAM)pvThis;
562
563 /* When we've reached the end, read will be set to indicate it. */
564 if ( (fEvents & RTPOLL_EVT_READ)
565 && pThis->fEndOfStream)
566 {
567 int rc = RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, 0, fIntr, pfRetEvents);
568 if (RT_SUCCESS(rc))
569 *pfRetEvents |= RTPOLL_EVT_READ;
570 else
571 *pfRetEvents = RTPOLL_EVT_READ;
572 return VINF_SUCCESS;
573 }
574
575 return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
576}
577
578
579/**
580 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
581 */
582static DECLCALLBACK(int) rtZipCpioFssIos_Tell(void *pvThis, PRTFOFF poffActual)
583{
584 PRTZIPCPIOIOSTREAM pThis = (PRTZIPCPIOIOSTREAM)pvThis;
585 *poffActual = pThis->offFile;
586 return VINF_SUCCESS;
587}
588
589
590/**
591 * Tar I/O stream operations.
592 */
593static const RTVFSIOSTREAMOPS g_rtZipCpioFssIosOps =
594{
595 { /* Obj */
596 RTVFSOBJOPS_VERSION,
597 RTVFSOBJTYPE_IO_STREAM,
598 "CpioFsStream::IoStream",
599 rtZipCpioFssIos_Close,
600 rtZipCpioFssIos_QueryInfo,
601 NULL,
602 RTVFSOBJOPS_VERSION
603 },
604 RTVFSIOSTREAMOPS_VERSION,
605 RTVFSIOSTREAMOPS_FEAT_NO_SG,
606 rtZipCpioFssIos_Read,
607 rtZipCpioFssIos_Write,
608 rtZipCpioFssIos_Flush,
609 rtZipCpioFssIos_PollOne,
610 rtZipCpioFssIos_Tell,
611 NULL /*Skip*/,
612 NULL /*ZeroFill*/,
613 RTVFSIOSTREAMOPS_VERSION
614};
615
616
617/**
618 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
619 */
620static DECLCALLBACK(int) rtZipCpioFssSym_Close(void *pvThis)
621{
622 PRTZIPCPIOBASEOBJ pThis = (PRTZIPCPIOBASEOBJ)pvThis;
623 return rtZipCpioFssBaseObj_Close(pThis);
624}
625
626
627/**
628 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
629 */
630static DECLCALLBACK(int) rtZipCpioFssSym_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
631{
632 PRTZIPCPIOBASEOBJ pThis = (PRTZIPCPIOBASEOBJ)pvThis;
633 return rtZipCpioFssBaseObj_QueryInfo(pThis, pObjInfo, enmAddAttr);
634}
635
636/**
637 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
638 */
639static DECLCALLBACK(int) rtZipCpioFssSym_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
640{
641 NOREF(pvThis); NOREF(fMode); NOREF(fMask);
642 return VERR_ACCESS_DENIED;
643}
644
645
646/**
647 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
648 */
649static DECLCALLBACK(int) rtZipCpioFssSym_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
650 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
651{
652 NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
653 return VERR_ACCESS_DENIED;
654}
655
656
657/**
658 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
659 */
660static DECLCALLBACK(int) rtZipCpioFssSym_SetOwner(void *pvThis, RTUID uid, RTGID gid)
661{
662 NOREF(pvThis); NOREF(uid); NOREF(gid);
663 return VERR_ACCESS_DENIED;
664}
665
666
667/**
668 * @interface_method_impl{RTVFSSYMLINKOPS,pfnRead}
669 */
670static DECLCALLBACK(int) rtZipCpioFssSym_Read(void *pvThis, char *pszTarget, size_t cbTarget)
671{
672 PRTZIPCPIOBASEOBJ pThis = (PRTZIPCPIOBASEOBJ)pvThis;
673 return RTStrCopy(pszTarget, cbTarget, pThis->pCpioReader->szTarget);
674}
675
676
677/**
678 * CPIO symbolic (and hardlink) operations.
679 */
680static const RTVFSSYMLINKOPS g_rtZipCpioFssSymOps =
681{
682 { /* Obj */
683 RTVFSOBJOPS_VERSION,
684 RTVFSOBJTYPE_SYMLINK,
685 "CpioFsStream::Symlink",
686 rtZipCpioFssSym_Close,
687 rtZipCpioFssSym_QueryInfo,
688 NULL,
689 RTVFSOBJOPS_VERSION
690 },
691 RTVFSSYMLINKOPS_VERSION,
692 0,
693 { /* ObjSet */
694 RTVFSOBJSETOPS_VERSION,
695 RT_UOFFSETOF(RTVFSSYMLINKOPS, ObjSet) - RT_UOFFSETOF(RTVFSSYMLINKOPS, Obj),
696 rtZipCpioFssSym_SetMode,
697 rtZipCpioFssSym_SetTimes,
698 rtZipCpioFssSym_SetOwner,
699 RTVFSOBJSETOPS_VERSION
700 },
701 rtZipCpioFssSym_Read,
702 RTVFSSYMLINKOPS_VERSION
703};
704
705
706/**
707 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
708 */
709static DECLCALLBACK(int) rtZipCpioFss_Close(void *pvThis)
710{
711 PRTZIPCPIOFSSTREAM pThis = (PRTZIPCPIOFSSTREAM)pvThis;
712
713 RTVfsObjRelease(pThis->hVfsCurObj);
714 pThis->hVfsCurObj = NIL_RTVFSOBJ;
715 pThis->pCurIosData = NULL;
716
717 RTVfsIoStrmRelease(pThis->hVfsIos);
718 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
719
720 return VINF_SUCCESS;
721}
722
723
724/**
725 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
726 */
727static DECLCALLBACK(int) rtZipCpioFss_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
728{
729 PRTZIPCPIOFSSTREAM pThis = (PRTZIPCPIOFSSTREAM)pvThis;
730 /* Take the lazy approach here, with the sideffect of providing some info
731 that is actually kind of useful. */
732 return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
733}
734
735
736/**
737 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
738 */
739DECL_HIDDEN_CALLBACK(int) rtZipCpioFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
740{
741 PRTZIPCPIOFSSTREAM pThis = (PRTZIPCPIOFSSTREAM)pvThis;
742
743 /*
744 * Dispense with the current object.
745 */
746 if (pThis->hVfsCurObj != NIL_RTVFSOBJ)
747 {
748 if (pThis->pCurIosData)
749 {
750 pThis->pCurIosData->fEndOfStream = true;
751 pThis->pCurIosData->offFile = pThis->pCurIosData->cbFile;
752 pThis->pCurIosData = NULL;
753 }
754
755 RTVfsObjRelease(pThis->hVfsCurObj);
756 pThis->hVfsCurObj = NIL_RTVFSOBJ;
757 }
758
759 /*
760 * Check if we've already reached the end in some way.
761 */
762 if (pThis->fEndOfStream)
763 return VERR_EOF;
764 if (pThis->rcFatal != VINF_SUCCESS)
765 return pThis->rcFatal;
766
767 /*
768 * Make sure the input stream is in the right place.
769 */
770 RTFOFF offHdr = RTVfsIoStrmTell(pThis->hVfsIos);
771 while ( offHdr >= 0
772 && offHdr < pThis->offNextHdr)
773 {
774 int rc = RTVfsIoStrmSkip(pThis->hVfsIos, pThis->offNextHdr - offHdr);
775 if (RT_FAILURE(rc))
776 {
777 /** @todo Ignore if we're at the end of the stream? */
778 return pThis->rcFatal = rc;
779 }
780
781 offHdr = RTVfsIoStrmTell(pThis->hVfsIos);
782 }
783
784 if (offHdr < 0)
785 return pThis->rcFatal = (int)offHdr;
786 if (offHdr > pThis->offNextHdr)
787 return pThis->rcFatal = VERR_INTERNAL_ERROR_3;
788 Assert(pThis->offNextHdr == offHdr);
789 pThis->offCurHdr = offHdr;
790
791 /*
792 * Consume CPIO headers.
793 */
794 size_t cbHdr = 0;
795 /*
796 * Read the next header.
797 *
798 * Read the first 6 bytes to determine the header type and continue reading the
799 * rest of the header.
800 */
801 CPIOHDR Hdr;
802 RTZIPCPIOTYPE enmHdrType = RTZIPCPIOTYPE_INVALID;
803 size_t cbRead;
804 int rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr.ab[0], sizeof(Hdr.AsciiNew.achMagic), true /*fBlocking*/, &cbRead);
805 if (RT_FAILURE(rc))
806 return pThis->rcFatal = rc;
807 if (rc == VINF_EOF && cbRead == 0)
808 {
809 pThis->fEndOfStream = true;
810 return VERR_EOF;
811 }
812 if (cbRead != sizeof(Hdr.AsciiNew.achMagic))
813 return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS;
814
815 if (Hdr.AncientBin.u16Magic == CPIO_HDR_BIN_MAGIC)
816 {
817 cbHdr = sizeof(Hdr.AncientBin);
818 enmHdrType = RTZIPCPIOTYPE_ANCIENT_BIN;
819 }
820 else if (!strncmp(&Hdr.AsciiSuSv2.achMagic[0], CPIO_HDR_SUSV2_MAGIC, sizeof(Hdr.AsciiSuSv2.achMagic)))
821 {
822 cbHdr = sizeof(Hdr.AsciiSuSv2);
823 enmHdrType = RTZIPCPIOTYPE_ASCII_SUSV2;
824 }
825 else if (!strncmp(&Hdr.AsciiNew.achMagic[0], CPIO_HDR_NEW_MAGIC, sizeof(Hdr.AsciiNew.achMagic)))
826 {
827 cbHdr = sizeof(Hdr.AsciiNew);
828 enmHdrType = RTZIPCPIOTYPE_ASCII_NEW;
829 }
830 else if (!strncmp(&Hdr.AsciiNew.achMagic[0], CPIO_HDR_NEW_CHKSUM_MAGIC, sizeof(Hdr.AsciiNew.achMagic)))
831 {
832 cbHdr = sizeof(Hdr.AsciiNew);
833 enmHdrType = RTZIPCPIOTYPE_ASCII_NEW_CHKSUM;
834 }
835 else
836 return pThis->rcFatal = VERR_TAR_UNKNOWN_TYPE_FLAG; /** @todo Dedicated status code. */
837
838 /* Read the rest of the header. */
839 size_t cbHdrLeft = cbHdr - sizeof(Hdr.AsciiNew.achMagic);
840 rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr.ab[sizeof(Hdr.AsciiNew.achMagic)], cbHdr - sizeof(Hdr.AsciiNew.achMagic), true /*fBlocking*/, &cbRead);
841 if (RT_FAILURE(rc))
842 return pThis->rcFatal = rc;
843 if (cbRead != cbHdrLeft)
844 return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS;
845
846 /*
847 * Parse it.
848 */
849 uint32_t cbFilePath = 0;
850 uint32_t cbPad = 0;
851 rc = rtZipCpioReaderParseHeader(&pThis->CpioReader, enmHdrType, &Hdr, &cbFilePath, &cbPad);
852 if (RT_FAILURE(rc))
853 return pThis->rcFatal = rc;
854
855 /* Read the file path following the header. */
856 rc = rtZipCpioReaderReadPath(pThis->hVfsIos, &pThis->CpioReader, cbFilePath);
857 if (RT_FAILURE(rc))
858 return pThis->rcFatal = rc;
859
860 if (cbPad)
861 RTVfsIoStrmSkip(pThis->hVfsIos, cbPad);
862 pThis->offNextHdr = offHdr + cbHdr + cbFilePath + cbPad;
863
864 /*
865 * CPIO uses a special trailer file record with a 0 mode and size and using a special
866 * marker filename. The filesystem stream is marked EOS When such a record is encountered
867 * to not try to read anything which might come behind it, imagine an initramfs image consisting
868 * of multiple archives which don't need to be necessarily be all of the CPIO kind (yes, this is
869 * a reality with ubuntu for example containing microcode updates as seperate CPIO archives
870 * coming before the main LZ4 compressed CPIO archive...).
871 */
872 PCRTFSOBJINFO pInfo = &pThis->CpioReader.ObjInfo;
873 if (RT_UNLIKELY( !pInfo->Attr.fMode
874 && !pInfo->cbAllocated
875 && !strcmp(&pThis->CpioReader.szName[0], CPIO_EOS_FILE_NAME)))
876 {
877 pThis->fEndOfStream = true;
878 return VERR_EOF;
879 }
880
881 /*
882 * Create an object of the appropriate type.
883 */
884 RTVFSOBJTYPE enmType;
885 RTVFSOBJ hVfsObj;
886 RTFMODE fType = pInfo->Attr.fMode & RTFS_TYPE_MASK;
887 switch (fType)
888 {
889 /*
890 * Files are represented by a VFS I/O stream, hardlinks have their content
891 * embedded as it is another file.
892 */
893 case RTFS_TYPE_FILE:
894 {
895 RTVFSIOSTREAM hVfsIos;
896 PRTZIPCPIOIOSTREAM pIosData;
897 rc = RTVfsNewIoStream(&g_rtZipCpioFssIosOps,
898 sizeof(*pIosData),
899 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
900 NIL_RTVFS,
901 NIL_RTVFSLOCK,
902 &hVfsIos,
903 (void **)&pIosData);
904 if (RT_FAILURE(rc))
905 return pThis->rcFatal = rc;
906
907 pIosData->BaseObj.offHdr = offHdr;
908 pIosData->BaseObj.offNextHdr = pThis->offNextHdr;
909 pIosData->BaseObj.pCpioReader = &pThis->CpioReader;
910 pIosData->BaseObj.ObjInfo = *pInfo;
911 pIosData->cbFile = pInfo->cbObject;
912 pIosData->offFile = 0;
913 pIosData->offStart = RTVfsIoStrmTell(pThis->hVfsIos);
914 pIosData->cbPadding = (uint32_t)(pInfo->cbAllocated - pInfo->cbObject);
915 pIosData->fEndOfStream = false;
916 pIosData->hVfsIos = pThis->hVfsIos;
917 RTVfsIoStrmRetain(pThis->hVfsIos);
918
919 pThis->pCurIosData = pIosData;
920 pThis->offNextHdr += pIosData->cbFile + pIosData->cbPadding;
921
922 enmType = RTVFSOBJTYPE_IO_STREAM;
923 hVfsObj = RTVfsObjFromIoStream(hVfsIos);
924 RTVfsIoStrmRelease(hVfsIos);
925 break;
926 }
927
928 case RTFS_TYPE_SYMLINK:
929 {
930 RTVFSSYMLINK hVfsSym;
931 PRTZIPCPIOBASEOBJ pBaseObjData;
932 rc = RTVfsNewSymlink(&g_rtZipCpioFssSymOps,
933 sizeof(*pBaseObjData),
934 NIL_RTVFS,
935 NIL_RTVFSLOCK,
936 &hVfsSym,
937 (void **)&pBaseObjData);
938 if (RT_FAILURE(rc))
939 return pThis->rcFatal = rc;
940
941 pBaseObjData->offHdr = offHdr;
942 pBaseObjData->offNextHdr = pThis->offNextHdr;
943 pBaseObjData->pCpioReader = &pThis->CpioReader;
944 pBaseObjData->ObjInfo = *pInfo;
945
946 /* Read the body of the symlink (as normal file data). */
947 if (pInfo->cbObject + 1 > (RTFOFF)sizeof(pThis->CpioReader.szTarget))
948 return VERR_TAR_NAME_TOO_LONG;
949
950 cbPad = (uint32_t)(pInfo->cbAllocated - pInfo->cbObject);
951 rc = RTVfsIoStrmRead(pThis->hVfsIos, &pThis->CpioReader.szTarget[0], pInfo->cbObject, true /*fBlocking*/, &cbRead);
952 if (RT_FAILURE(rc))
953 return pThis->rcFatal = rc;
954 if (cbRead != (uint32_t)pInfo->cbObject)
955 return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS;
956
957 pThis->CpioReader.szTarget[pInfo->cbObject] = '\0';
958
959 if (cbPad)
960 rc = RTVfsIoStrmSkip(pThis->hVfsIos, cbPad);
961 if (RT_FAILURE(rc))
962 return pThis->rcFatal = rc;
963
964 pThis->offNextHdr += pInfo->cbAllocated;
965
966 enmType = RTVFSOBJTYPE_SYMLINK;
967 hVfsObj = RTVfsObjFromSymlink(hVfsSym);
968 RTVfsSymlinkRelease(hVfsSym);
969 break;
970 }
971
972 /*
973 * All other objects are repesented using a VFS base object since they
974 * carry no data streams.
975 */
976 case RTFS_TYPE_DEV_BLOCK:
977 case RTFS_TYPE_DEV_CHAR:
978 case RTFS_TYPE_DIRECTORY:
979 case RTFS_TYPE_FIFO:
980 {
981 PRTZIPCPIOBASEOBJ pBaseObjData;
982 rc = RTVfsNewBaseObj(&g_rtZipCpioFssBaseObjOps,
983 sizeof(*pBaseObjData),
984 NIL_RTVFS,
985 NIL_RTVFSLOCK,
986 &hVfsObj,
987 (void **)&pBaseObjData);
988 if (RT_FAILURE(rc))
989 return pThis->rcFatal = rc;
990
991 pBaseObjData->offHdr = offHdr;
992 pBaseObjData->offNextHdr = pThis->offNextHdr;
993 pBaseObjData->pCpioReader = &pThis->CpioReader;
994 pBaseObjData->ObjInfo = *pInfo;
995
996 enmType = RTVFSOBJTYPE_BASE;
997 break;
998 }
999
1000 default:
1001 AssertFailed();
1002 return pThis->rcFatal = VERR_INTERNAL_ERROR_5;
1003 }
1004 pThis->hVfsCurObj = hVfsObj;
1005
1006 /*
1007 * Set the return data and we're done.
1008 */
1009 if (ppszName)
1010 {
1011 rc = RTStrDupEx(ppszName, pThis->CpioReader.szName);
1012 if (RT_FAILURE(rc))
1013 return rc;
1014 }
1015
1016 if (phVfsObj)
1017 {
1018 RTVfsObjRetain(hVfsObj);
1019 *phVfsObj = hVfsObj;
1020 }
1021
1022 if (penmType)
1023 *penmType = enmType;
1024
1025 return VINF_SUCCESS;
1026}
1027
1028
1029
1030/**
1031 * CPIO filesystem stream operations.
1032 */
1033static const RTVFSFSSTREAMOPS rtZipCpioFssOps =
1034{
1035 { /* Obj */
1036 RTVFSOBJOPS_VERSION,
1037 RTVFSOBJTYPE_FS_STREAM,
1038 "CpioFsStream",
1039 rtZipCpioFss_Close,
1040 rtZipCpioFss_QueryInfo,
1041 NULL,
1042 RTVFSOBJOPS_VERSION
1043 },
1044 RTVFSFSSTREAMOPS_VERSION,
1045 0,
1046 rtZipCpioFss_Next,
1047 NULL,
1048 NULL,
1049 NULL,
1050 RTVFSFSSTREAMOPS_VERSION
1051};
1052
1053
1054/**
1055 * Internal function use both by RTZipCpioFsStreamFromIoStream() and by
1056 * RTZipCpioFsStreamForFile() in updating mode.
1057 */
1058DECLHIDDEN(void) rtZipCpioReaderInit(PRTZIPCPIOFSSTREAM pThis, RTVFSIOSTREAM hVfsIos, uint64_t offStart)
1059{
1060 pThis->hVfsIos = hVfsIos;
1061 pThis->hVfsCurObj = NIL_RTVFSOBJ;
1062 pThis->pCurIosData = NULL;
1063 pThis->offStart = offStart;
1064 pThis->offNextHdr = offStart;
1065 pThis->fEndOfStream = false;
1066 pThis->rcFatal = VINF_SUCCESS;
1067
1068 /* Don't check if it's a CPIO stream here, do that in the
1069 rtZipCpioFss_Next. */
1070}
1071
1072
1073RTDECL(int) RTZipCpioFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
1074{
1075 /*
1076 * Input validation.
1077 */
1078 AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
1079 *phVfsFss = NIL_RTVFSFSSTREAM;
1080 AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE);
1081 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1082
1083 RTFOFF const offStart = RTVfsIoStrmTell(hVfsIosIn);
1084 AssertReturn(offStart >= 0, (int)offStart);
1085
1086 uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn);
1087 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
1088
1089 /*
1090 * Retain the input stream and create a new filesystem stream handle.
1091 */
1092 PRTZIPCPIOFSSTREAM pThis;
1093 RTVFSFSSTREAM hVfsFss;
1094 int rc = RTVfsNewFsStream(&rtZipCpioFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_READ,
1095 &hVfsFss, (void **)&pThis);
1096 if (RT_SUCCESS(rc))
1097 {
1098 rtZipCpioReaderInit(pThis, hVfsIosIn, fFlags);
1099 *phVfsFss = hVfsFss;
1100 return VINF_SUCCESS;
1101 }
1102
1103 RTVfsIoStrmRelease(hVfsIosIn);
1104 return rc;
1105}
1106
1107
1108/**
1109 * Used by RTZipCpioFsStreamTruncate to resolve @a hVfsObj.
1110 */
1111DECLHIDDEN(PRTZIPCPIOBASEOBJ) rtZipCpioFsStreamBaseObjToPrivate(PRTZIPCPIOFSSTREAM pThis, RTVFSOBJ hVfsObj)
1112{
1113 PRTZIPCPIOBASEOBJ pThisObj;
1114 RTVFSOBJTYPE enmType = RTVfsObjGetType(hVfsObj);
1115 switch (enmType)
1116 {
1117 case RTVFSOBJTYPE_IO_STREAM:
1118 {
1119 RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
1120 AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, NULL);
1121 PRTZIPCPIOIOSTREAM pThisStrm = (PRTZIPCPIOIOSTREAM)RTVfsIoStreamToPrivate(hVfsIos, &g_rtZipCpioFssIosOps);
1122 RTVfsIoStrmRelease(hVfsIos);
1123 pThisObj = &pThisStrm->BaseObj;
1124 break;
1125 }
1126
1127 case RTVFSOBJTYPE_SYMLINK:
1128 {
1129 RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
1130 AssertReturn(hVfsSymlink != NIL_RTVFSSYMLINK, NULL);
1131 pThisObj = (PRTZIPCPIOBASEOBJ)RTVfsSymlinkToPrivate(hVfsSymlink, &g_rtZipCpioFssSymOps);
1132 RTVfsSymlinkRelease(hVfsSymlink);
1133 break;
1134 }
1135
1136 case RTVFSOBJTYPE_BASE:
1137 pThisObj = (PRTZIPCPIOBASEOBJ)RTVfsObjToPrivate(hVfsObj, &g_rtZipCpioFssBaseObjOps);
1138 break;
1139
1140 default:
1141 /** @todo implement. */
1142 AssertFailedReturn(NULL);
1143 }
1144
1145 AssertReturn(pThisObj->pCpioReader == &pThis->CpioReader, NULL);
1146 return pThisObj;
1147}
1148
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