VirtualBox

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

Last change on this file since 86103 was 86035, checked in by vboxsync, 4 years ago

Runtime/cpiovfs.cpp: A simple CPIO archive reader (WIP, writer comes next and then some cleanup)

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