Changeset 84192 in vbox
- Timestamp:
- May 7, 2020 8:56:01 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/mangling.h
r84163 r84192 2808 2808 # define RTVfsObjToFsStream RT_MANGLER(RTVfsObjToFsStream) 2809 2809 # define RTVfsObjToIoStream RT_MANGLER(RTVfsObjToIoStream) 2810 # define RTVfsObjToPrivate RT_MANGLER(RTVfsObjToPrivate) 2810 2811 # define RTVfsObjToSymlink RT_MANGLER(RTVfsObjToSymlink) 2811 2812 # define RTVfsObjToVfs RT_MANGLER(RTVfsObjToVfs) … … 2828 2829 # define RTVfsSymlinkSetOwner RT_MANGLER(RTVfsSymlinkSetOwner) 2829 2830 # define RTVfsSymlinkSetTimes RT_MANGLER(RTVfsSymlinkSetTimes) 2831 # define RTVfsSymlinkToPrivate RT_MANGLER(RTVfsSymlinkToPrivate) 2830 2832 # define RTVfsUtilDummyPollOne RT_MANGLER(RTVfsUtilDummyPollOne) 2831 2833 # define RTVfsUtilPumpIoStreams RT_MANGLER(RTVfsUtilPumpIoStreams) -
trunk/include/iprt/vfslowlevel.h
r82968 r84192 311 311 PRTVFSOBJ phVfsObj, void **ppvInstance); 312 312 313 314 /** 315 * Gets the private data of a base object. 316 * 317 * @returns Pointer to the private data. NULL if the handle is invalid in some 318 * way. 319 * @param hVfsObj The I/O base object handle. 320 * @param pObjOps The base object operations. This servers as a 321 * sort of password. 322 */ 323 RTDECL(void *) RTVfsObjToPrivate(RTVFSOBJ hVfsObj, PCRTVFSOBJOPS pObjOps); 313 324 314 325 /** … … 493 504 * object. The reference is consumed. NIL and 494 505 * special lock handles are fine. 495 * @param f ReadOnly Set if read-only, clear if write-only.506 * @param fAccess RTFILE_O_READ and/or RTFILE_O_WRITE. 496 507 * @param phVfsFss Where to return the new handle. 497 508 * @param ppvInstance Where to return the pointer to the instance data 498 509 * (size is @a cbInstance). 499 510 */ 500 RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, bool fReadOnly,511 RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, uint32_t fAccess, 501 512 PRTVFSFSSTREAM phVfsFss, void **ppvInstance); 502 513 … … 828 839 PRTVFSSYMLINK phVfsSym, void **ppvInstance); 829 840 841 842 /** 843 * Gets the private data of a symbolic link. 844 * 845 * @returns Pointer to the private data. NULL if the handle is invalid in some 846 * way. 847 * @param hVfsIos The I/O stream handle. 848 * @param pSymlinkOps The symlink operations. This servers as a sort 849 * of password. 850 */ 851 RTDECL(void *) RTVfsSymlinkToPrivate(RTVFSSYMLINK hVfsSym, PCRTVFSSYMLINKOPS pSymlinkOps); 830 852 831 853 /** -
trunk/include/iprt/zip.h
r82968 r84192 324 324 * twice. */ 325 325 #define RTZIPTAR_C_SPARSE RT_BIT_32(0) 326 /** Set if opening for updating. */ 327 #define RTZIPTAR_C_UPDATE RT_BIT_32(1) 326 328 /** Valid bits. */ 327 #define RTZIPTAR_C_VALID_MASK UINT32_C(0x0000000 1)329 #define RTZIPTAR_C_VALID_MASK UINT32_C(0x00000003) 328 330 /** @} */ 329 331 … … 392 394 RTDECL(int) RTZipTarFsStreamSetMTime(RTVFSFSSTREAM hVfsFss, PCRTTIMESPEC pModificationTime); 393 395 396 /** 397 * Truncates a TAR creator stream in update mode. 398 * 399 * Use RTVfsFsStrmNext to examine the TAR stream and locate the cut-off point. 400 * 401 * After performing this call, the stream will be in write mode and 402 * RTVfsFsStrmNext will stop working (VERR_WRONG_ORDER). The RTVfsFsStrmAdd() 403 * and RTVfsFsStrmPushFile() can be used to add new object to the TAR file, 404 * starting at the trunction point. RTVfsFsStrmEnd() is used to finish the TAR 405 * file (this performs the actual file trunction). 406 * 407 * @returns IPRT status code. 408 * @param hVfsFss The handle to a TAR creator in update mode. 409 * @param hVfsObj Object returned by RTVfsFsStrmNext that the 410 * trunction is relative to. This doesn't have to 411 * be the current stream object, it can be an 412 * earlier one too. 413 * @param fAfter If set, @a hVfsObj will remain in the update TAR 414 * file. If clear, @a hVfsObj will not be 415 * included. 416 */ 417 RTDECL(int) RTZipTarFsStreamTruncate(RTVFSFSSTREAM hVfsFss, RTVFSOBJ hVfsObj, bool fAfter); 394 418 395 419 /** -
trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp
r82968 r84192 813 813 *ppvInstance = pThis->pvThis; 814 814 return VINF_SUCCESS; 815 } 816 817 818 RTDECL(void *) RTVfsObjToPrivate(RTVFSOBJ hVfsObj, PCRTVFSOBJOPS pObjOps) 819 { 820 RTVFSOBJINTERNAL *pThis = hVfsObj; 821 AssertPtrReturn(pThis, NULL); 822 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NULL); 823 if (pThis->pOps != pObjOps) 824 return NULL; 825 return pThis->pvThis; 815 826 } 816 827 … … 2282 2293 2283 2294 2284 RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, bool fReadOnly,2295 RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, uint32_t fAccess, 2285 2296 PRTVFSFSSTREAM phVfsFss, void **ppvInstance) 2286 2297 { … … 2293 2304 Assert(!pFsStreamOps->fReserved); 2294 2305 RTVFSOBJ_ASSERT_OPS(&pFsStreamOps->Obj, RTVFSOBJTYPE_FS_STREAM); 2295 if (fReadOnly) 2306 Assert((fAccess & (RTFILE_O_READ | RTFILE_O_WRITE)) == fAccess); 2307 Assert(fAccess); 2308 if (fAccess & RTFILE_O_READ) 2296 2309 AssertPtr(pFsStreamOps->pfnNext); 2297 else2310 if (fAccess & RTFILE_O_WRITE) 2298 2311 { 2299 2312 AssertPtr(pFsStreamOps->pfnAdd); … … 2324 2337 2325 2338 pThis->uMagic = RTVFSFSSTREAM_MAGIC; 2326 pThis->fFlags = fReadOnly2327 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE2328 : RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_ALL;2329 2339 pThis->pOps = pFsStreamOps; 2340 pThis->fFlags = fAccess; 2341 if (fAccess == RTFILE_O_READ) 2342 pThis->fFlags |= RTFILE_O_OPEN | RTFILE_O_DENY_NONE; 2343 else if (fAccess == RTFILE_O_WRITE) 2344 pThis->fFlags |= RTFILE_O_CREATE | RTFILE_O_DENY_ALL; 2345 else 2346 pThis->fFlags |= RTFILE_O_OPEN | RTFILE_O_DENY_ALL; 2330 2347 2331 2348 *phVfsFss = pThis; … … 3277 3294 3278 3295 3296 RTDECL(void *) RTVfsSymlinkToPrivate(RTVFSSYMLINK hVfsSym, PCRTVFSSYMLINKOPS pSymlinkOps) 3297 { 3298 RTVFSSYMLINKINTERNAL *pThis = hVfsSym; 3299 AssertPtrReturn(pThis, NULL); 3300 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, NULL); 3301 if (pThis->pOps != pSymlinkOps) 3302 return NULL; 3303 return pThis->Base.pvThis; 3304 } 3305 3306 3279 3307 RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym) 3280 3308 { -
trunk/src/VBox/Runtime/common/vfs/vfsfss2dir.cpp
r82968 r84192 311 311 PRTVFSFSSWRITE2DIR pThis; 312 312 RTVFSFSSTREAM hVfsFss; 313 int rc = RTVfsNewFsStream(&g_rtVfsFssToDirOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, false /*fReadOnly*/,313 int rc = RTVfsNewFsStream(&g_rtVfsFssToDirOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE, 314 314 &hVfsFss, (void **)&pThis); 315 315 if (RT_SUCCESS(rc)) … … 370 370 RTVFSFSSTREAM hVfsFss; 371 371 rc = RTVfsNewFsStream(&g_rtVfsFssToDirOps, RT_UOFFSETOF_DYN(RTVFSFSSWRITE2DIR, szBaseDir[cbBaseDir]), 372 NIL_RTVFS, NIL_RTVFSLOCK, false /*fReadOnly*/, &hVfsFss, (void **)&pThis);372 NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE, &hVfsFss, (void **)&pThis); 373 373 if (RT_SUCCESS(rc)) 374 374 { -
trunk/src/VBox/Runtime/common/zip/pkzipvfs.cpp
r82968 r84192 1264 1264 PRTZIPPKZIPFSSTREAM pThis; 1265 1265 RTVFSFSSTREAM hVfsFss; 1266 int rc = RTVfsNewFsStream(&rtZipPkzipFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, true /*fReadOnly*/,1266 int rc = RTVfsNewFsStream(&rtZipPkzipFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_READ, 1267 1267 &hVfsFss, (void **)&pThis); 1268 1268 if (RT_SUCCESS(rc)) -
trunk/src/VBox/Runtime/common/zip/tarvfs.cpp
r82968 r84192 43 43 44 44 #include "tar.h" 45 46 47 /********************************************************************************************************************************* 48 * Structures and Typedefs * 49 *********************************************************************************************************************************/ 50 /** 51 * TAR reader state machine states. 52 */ 53 typedef enum RTZIPTARREADERSTATE 54 { 55 /** Invalid state. */ 56 RTZIPTARREADERSTATE_INVALID = 0, 57 /** Expecting the next file/dir/whatever entry. */ 58 RTZIPTARREADERSTATE_FIRST, 59 /** Expecting more zero headers or the end of the stream. */ 60 RTZIPTARREADERSTATE_ZERO, 61 /** Expecting a GNU long name. */ 62 RTZIPTARREADERSTATE_GNU_LONGNAME, 63 /** Expecting a GNU long link. */ 64 RTZIPTARREADERSTATE_GNU_LONGLINK, 65 /** Expecting a normal header or another GNU specific one. */ 66 RTZIPTARREADERSTATE_GNU_NEXT, 67 /** End of valid states (not included). */ 68 RTZIPTARREADERSTATE_END 69 } RTZIPTARREADERSTATE; 70 71 /** 72 * Tar reader instance data. 73 */ 74 typedef struct RTZIPTARREADER 75 { 76 /** Zero header counter. */ 77 uint32_t cZeroHdrs; 78 /** The state machine state. */ 79 RTZIPTARREADERSTATE enmState; 80 /** The type of the previous TAR header. 81 * @remarks Same a enmType for the first header in the TAR stream. */ 82 RTZIPTARTYPE enmPrevType; 83 /** The type of the current TAR header. */ 84 RTZIPTARTYPE enmType; 85 /** The current header. */ 86 RTZIPTARHDR Hdr; 87 /** The expected long name/link length (GNU). */ 88 uint32_t cbGnuLongExpect; 89 /** The current long name/link length (GNU). */ 90 uint32_t offGnuLongCur; 91 /** The name of the current object. 92 * This is for handling GNU and PAX long names. */ 93 char szName[RTPATH_MAX]; 94 /** The current link target if symlink or hardlink. */ 95 char szTarget[RTPATH_MAX]; 96 } RTZIPTARREADER; 97 /** Pointer to the TAR reader instance data. */ 98 typedef RTZIPTARREADER *PRTZIPTARREADER; 99 100 /** 101 * Tar directory, character device, block device, fifo socket or symbolic link. 102 */ 103 typedef struct RTZIPTARBASEOBJ 104 { 105 /** The stream offset of the (first) header. */ 106 RTFOFF offHdr; 107 /** Pointer to the reader instance data (resides in the filesystem 108 * stream). 109 * @todo Fix this so it won't go stale... Back ref from this obj to fss? */ 110 PRTZIPTARREADER pTarReader; 111 /** The object info with unix attributes. */ 112 RTFSOBJINFO ObjInfo; 113 } RTZIPTARBASEOBJ; 114 /** Pointer to a TAR filesystem stream base object. */ 115 typedef RTZIPTARBASEOBJ *PRTZIPTARBASEOBJ; 116 117 118 /** 119 * Tar file represented as a VFS I/O stream. 120 */ 121 typedef struct RTZIPTARIOSTREAM 122 { 123 /** The basic TAR object data. */ 124 RTZIPTARBASEOBJ BaseObj; 125 /** The number of bytes in the file. */ 126 RTFOFF cbFile; 127 /** The current file position. */ 128 RTFOFF offFile; 129 /** The start position in the hVfsIos (for seekable hVfsIos). */ 130 RTFOFF offStart; 131 /** The number of padding bytes following the file. */ 132 uint32_t cbPadding; 133 /** Set if we've reached the end of the file. */ 134 bool fEndOfStream; 135 /** The input I/O stream. */ 136 RTVFSIOSTREAM hVfsIos; 137 } RTZIPTARIOSTREAM; 138 /** Pointer to a the private data of a TAR file I/O stream. */ 139 typedef RTZIPTARIOSTREAM *PRTZIPTARIOSTREAM; 140 141 142 /** 143 * Tar filesystem stream private data. 144 */ 145 typedef struct RTZIPTARFSSTREAM 146 { 147 /** The input I/O stream. */ 148 RTVFSIOSTREAM hVfsIos; 149 150 /** The current object (referenced). */ 151 RTVFSOBJ hVfsCurObj; 152 /** Pointer to the private data if hVfsCurObj is representing a file. */ 153 PRTZIPTARIOSTREAM pCurIosData; 154 155 /** The start offset. */ 156 RTFOFF offStart; 157 /** The offset of the next header. */ 158 RTFOFF offNextHdr; 159 160 /** Set if we've reached the end of the stream. */ 161 bool fEndOfStream; 162 /** Set if we've encountered a fatal error. */ 163 int rcFatal; 164 165 /** The TAR reader instance data. */ 166 RTZIPTARREADER TarReader; 167 } RTZIPTARFSSTREAM; 168 /** Pointer to a the private data of a TAR filesystem stream. */ 169 typedef RTZIPTARFSSTREAM *PRTZIPTARFSSTREAM; 170 45 #include "tarvfsreader.h" 171 46 172 47 … … 1236 1111 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext} 1237 1112 */ 1238 static DECLCALLBACK(int) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)1113 DECLHIDDEN(DECLCALLBACK(int)) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj) 1239 1114 { 1240 1115 PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis; … … 1285 1160 if (offHdr > pThis->offNextHdr) 1286 1161 return pThis->rcFatal = VERR_INTERNAL_ERROR_3; 1162 Assert(pThis->offNextHdr == offHdr); 1163 pThis->offCurHdr = offHdr; 1287 1164 1288 1165 /* … … 1356 1233 return pThis->rcFatal = rc; 1357 1234 1358 pIosData->BaseObj.offHdr = offHdr; 1359 pIosData->BaseObj.pTarReader= &pThis->TarReader; 1360 pIosData->BaseObj.ObjInfo = Info; 1361 pIosData->cbFile = Info.cbObject; 1362 pIosData->offFile = 0; 1363 pIosData->offStart = RTVfsIoStrmTell(pThis->hVfsIos); 1364 pIosData->cbPadding = (uint32_t)(Info.cbAllocated - Info.cbObject); 1365 pIosData->fEndOfStream = false; 1366 pIosData->hVfsIos = pThis->hVfsIos; 1235 pIosData->BaseObj.offHdr = offHdr; 1236 pIosData->BaseObj.offNextHdr = pThis->offNextHdr; 1237 pIosData->BaseObj.pTarReader = &pThis->TarReader; 1238 pIosData->BaseObj.ObjInfo = Info; 1239 pIosData->cbFile = Info.cbObject; 1240 pIosData->offFile = 0; 1241 pIosData->offStart = RTVfsIoStrmTell(pThis->hVfsIos); 1242 pIosData->cbPadding = (uint32_t)(Info.cbAllocated - Info.cbObject); 1243 pIosData->fEndOfStream = false; 1244 pIosData->hVfsIos = pThis->hVfsIos; 1367 1245 RTVfsIoStrmRetain(pThis->hVfsIos); 1368 1246 … … 1394 1272 return pThis->rcFatal = rc; 1395 1273 1396 pBaseObjData->offHdr = offHdr; 1397 pBaseObjData->pTarReader= &pThis->TarReader; 1398 pBaseObjData->ObjInfo = Info; 1274 pBaseObjData->offHdr = offHdr; 1275 pBaseObjData->offNextHdr = pThis->offNextHdr; 1276 pBaseObjData->pTarReader = &pThis->TarReader; 1277 pBaseObjData->ObjInfo = Info; 1399 1278 1400 1279 enmType = RTVFSOBJTYPE_SYMLINK; … … 1424 1303 return pThis->rcFatal = rc; 1425 1304 1426 pBaseObjData->offHdr = offHdr; 1427 pBaseObjData->pTarReader= &pThis->TarReader; 1428 pBaseObjData->ObjInfo = Info; 1305 pBaseObjData->offHdr = offHdr; 1306 pBaseObjData->offNextHdr = pThis->offNextHdr; 1307 pBaseObjData->pTarReader = &pThis->TarReader; 1308 pBaseObjData->ObjInfo = Info; 1429 1309 1430 1310 enmType = RTVFSOBJTYPE_BASE; … … 1485 1365 1486 1366 1367 /** 1368 * Internal function use both by RTZipTarFsStreamFromIoStream() and by 1369 * RTZipTarFsStreamForFile() in updating mode. 1370 */ 1371 DECLHIDDEN(void) rtZipTarReaderInit(PRTZIPTARFSSTREAM pThis, RTVFSIOSTREAM hVfsIos, uint64_t offStart) 1372 { 1373 pThis->hVfsIos = hVfsIos; 1374 pThis->hVfsCurObj = NIL_RTVFSOBJ; 1375 pThis->pCurIosData = NULL; 1376 pThis->offStart = offStart; 1377 pThis->offNextHdr = offStart; 1378 pThis->fEndOfStream = false; 1379 pThis->rcFatal = VINF_SUCCESS; 1380 pThis->TarReader.enmPrevType= RTZIPTARTYPE_INVALID; 1381 pThis->TarReader.enmType = RTZIPTARTYPE_INVALID; 1382 pThis->TarReader.enmState = RTZIPTARREADERSTATE_FIRST; 1383 1384 /* Don't check if it's a TAR stream here, do that in the 1385 rtZipTarFss_Next. */ 1386 } 1387 1388 1487 1389 RTDECL(int) RTZipTarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss) 1488 1390 { … … 1506 1408 PRTZIPTARFSSTREAM pThis; 1507 1409 RTVFSFSSTREAM hVfsFss; 1508 int rc = RTVfsNewFsStream(&rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, true /*fReadOnly*/,1410 int rc = RTVfsNewFsStream(&rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_READ, 1509 1411 &hVfsFss, (void **)&pThis); 1510 1412 if (RT_SUCCESS(rc)) 1511 1413 { 1512 pThis->hVfsIos = hVfsIosIn; 1513 pThis->hVfsCurObj = NIL_RTVFSOBJ; 1514 pThis->pCurIosData = NULL; 1515 pThis->offStart = offStart; 1516 pThis->offNextHdr = offStart; 1517 pThis->fEndOfStream = false; 1518 pThis->rcFatal = VINF_SUCCESS; 1519 pThis->TarReader.enmPrevType= RTZIPTARTYPE_INVALID; 1520 pThis->TarReader.enmType = RTZIPTARTYPE_INVALID; 1521 pThis->TarReader.enmState = RTZIPTARREADERSTATE_FIRST; 1522 1523 /* Don't check if it's a TAR stream here, do that in the 1524 rtZipTarFss_Next. */ 1525 1414 rtZipTarReaderInit(pThis, hVfsIosIn, fFlags); 1526 1415 *phVfsFss = hVfsFss; 1527 1416 return VINF_SUCCESS; … … 1532 1421 } 1533 1422 1423 1424 /** 1425 * Used by RTZipTarFsStreamTruncate to resolve @a hVfsObj. 1426 */ 1427 DECLHIDDEN(PRTZIPTARBASEOBJ) rtZipTarFsStreamBaseObjToPrivate(PRTZIPTARFSSTREAM pThis, RTVFSOBJ hVfsObj) 1428 { 1429 PRTZIPTARBASEOBJ pThisObj; 1430 RTVFSOBJTYPE enmType = RTVfsObjGetType(hVfsObj); 1431 switch (enmType) 1432 { 1433 case RTVFSOBJTYPE_IO_STREAM: 1434 { 1435 RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj); 1436 AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, NULL); 1437 PRTZIPTARIOSTREAM pThisStrm = (PRTZIPTARIOSTREAM)RTVfsIoStreamToPrivate(hVfsIos, &g_rtZipTarFssIosOps); 1438 RTVfsIoStrmRelease(hVfsIos); 1439 pThisObj = &pThisStrm->BaseObj; 1440 break; 1441 } 1442 1443 case RTVFSOBJTYPE_SYMLINK: 1444 { 1445 RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj); 1446 AssertReturn(hVfsSymlink != NIL_RTVFSSYMLINK, NULL); 1447 pThisObj = (PRTZIPTARBASEOBJ)RTVfsSymlinkToPrivate(hVfsSymlink, &g_rtZipTarFssSymOps); 1448 RTVfsSymlinkRelease(hVfsSymlink); 1449 break; 1450 } 1451 1452 case RTVFSOBJTYPE_BASE: 1453 pThisObj = (PRTZIPTARBASEOBJ)RTVfsObjToPrivate(hVfsObj, &g_rtZipTarFssBaseObjOps); 1454 break; 1455 1456 default: 1457 /** @todo implement. */ 1458 AssertFailedReturn(NULL); 1459 } 1460 1461 AssertReturn(pThisObj->pTarReader == &pThis->TarReader, NULL); 1462 return pThisObj; 1463 } 1464 -
trunk/src/VBox/Runtime/common/zip/tarvfsreader.h
r84160 r84192 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - TAR Virtual Filesystem , Reader.3 * IPRT - TAR Virtual Filesystem. 4 4 */ 5 5 … … 25 25 */ 26 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> 27 #ifndef IPRT_INCLUDED_SRC_common_zip_tarvfsreader_h 28 #define IPRT_INCLUDED_SRC_common_zip_tarvfsreader_h 29 #ifndef RT_WITHOUT_PRAGMA_ONCE 30 # pragma once 31 #endif 43 32 44 33 #include "tar.h" 45 34 46 35 47 /*********************************************************************************************************************************48 * Structures and Typedefs *49 *********************************************************************************************************************************/50 36 /** 51 37 * TAR reader state machine states. … … 103 89 typedef struct RTZIPTARBASEOBJ 104 90 { 105 /** The stream offset of the (first) header . */91 /** The stream offset of the (first) header in the input stream/file. */ 106 92 RTFOFF offHdr; 93 /** The stream offset of the first header of the next object (for truncating the 94 * tar file after this object (updating)). */ 95 RTFOFF offNextHdr; 107 96 /** Pointer to the reader instance data (resides in the filesystem 108 97 * stream). … … 131 120 /** The number of padding bytes following the file. */ 132 121 uint32_t cbPadding; 133 /** Set if we've reached the end of th efile. */122 /** Set if we've reached the end of this file. */ 134 123 bool fEndOfStream; 135 124 /** The input I/O stream. */ … … 157 146 /** The offset of the next header. */ 158 147 RTFOFF offNextHdr; 148 /** The offset of the first header for the current object. 149 * When reaching the end, this will be the same as offNextHdr which will be 150 * pointing to the first zero header */ 151 RTFOFF offCurHdr; 159 152 160 153 /** Set if we've reached the end of the stream. */ … … 169 162 typedef RTZIPTARFSSTREAM *PRTZIPTARFSSTREAM; 170 163 164 DECLHIDDEN(void) rtZipTarReaderInit(PRTZIPTARFSSTREAM pThis, RTVFSIOSTREAM hVfsIos, uint64_t offStart); 165 DECLHIDDEN(DECLCALLBACK(int)) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj); 166 DECLHIDDEN(PRTZIPTARBASEOBJ) rtZipTarFsStreamBaseObjToPrivate(PRTZIPTARFSSTREAM pThis, RTVFSOBJ hVfsObj); 171 167 168 #endif /* !IPRT_INCLUDED_SRC_common_zip_tarvfsreader_h */ 172 169 173 /**174 * Converts a numeric header field to the C native type.175 *176 * @returns IPRT status code.177 *178 * @param pszField The TAR header field.179 * @param cchField The length of the field.180 * @param fOctalOnly Must be octal.181 * @param pi64 Where to store the value.182 */183 static int rtZipTarHdrFieldToNum(const char *pszField, size_t cchField, bool fOctalOnly, int64_t *pi64)184 {185 unsigned char const *puchField = (unsigned char const *)pszField;186 size_t const cchFieldOrg = cchField;187 if ( fOctalOnly188 || !(*puchField & 0x80))189 {190 /*191 * Skip leading spaces. Include zeros to save a few slower loops below.192 */193 unsigned char ch;194 while (cchField > 0 && ((ch = *puchField) == ' '|| ch == '0'))195 cchField--, puchField++;196 197 /*198 * Convert octal digits.199 */200 int64_t i64 = 0;201 while (cchField > 0)202 {203 unsigned char uDigit = *puchField - '0';204 if (uDigit >= 8)205 break;206 i64 <<= 3;207 i64 |= uDigit;208 209 puchField++;210 cchField--;211 }212 *pi64 = i64;213 214 /*215 * Was it terminated correctly?216 */217 while (cchField > 0)218 {219 ch = *puchField++;220 if (ch != 0 && ch != ' ')221 return cchField < cchFieldOrg222 ? VERR_TAR_BAD_NUM_FIELD_TERM223 : VERR_TAR_BAD_NUM_FIELD;224 cchField--;225 }226 }227 else228 {229 /*230 * The first byte has the bit 7 set to indicate base-256, while bit 6231 * is the signed bit. Bits 5:0 are the most significant value bits.232 */233 uint64_t u64;234 if (!(0x40 & *puchField))235 {236 /* Positive or zero value. */237 u64 = *puchField & 0x3f;238 cchField--;239 puchField++;240 241 while (cchField-- > 0)242 {243 if (RT_LIKELY(u64 <= (uint64_t)INT64_MAX / 256))244 u64 = (u64 << 8) | *puchField++;245 else246 return VERR_TAR_NUM_VALUE_TOO_LARGE;247 }248 }249 else250 {251 /* Negative value (could be used in timestamp). We do manual sign extending here. */252 u64 = (UINT64_MAX << 6) | (*puchField & 0x3f);253 cchField--;254 puchField++;255 256 while (cchField-- > 0)257 {258 if (RT_LIKELY(u64 >= (uint64_t)(INT64_MIN / 256)))259 u64 = (u64 << 8) | *puchField++;260 else261 return VERR_TAR_NUM_VALUE_TOO_LARGE;262 }263 }264 *pi64 = (int64_t)u64;265 }266 267 return VINF_SUCCESS;268 }269 270 271 /**272 * Validates the TAR header.273 *274 * @returns VINF_SUCCESS if valid, VERR_TAR_ZERO_HEADER if all zeros, and275 * the appropriate VERR_TAR_XXX otherwise.276 * @param pTar The TAR header.277 * @param penmType Where to return the type of header on success.278 */279 static int rtZipTarHdrValidate(PCRTZIPTARHDR pTar, PRTZIPTARTYPE penmType)280 {281 /*282 * Calc the checksum first since this enables us to detect zero headers.283 */284 int32_t i32ChkSum;285 int32_t i32ChkSumSignedAlt;286 if (rtZipTarCalcChkSum(pTar, &i32ChkSum, &i32ChkSumSignedAlt))287 return VERR_TAR_ZERO_HEADER;288 289 /*290 * Read the checksum field and match the checksums.291 */292 int64_t i64HdrChkSum;293 int rc = rtZipTarHdrFieldToNum(pTar->Common.chksum, sizeof(pTar->Common.chksum), true /*fOctalOnly*/, &i64HdrChkSum);294 if (RT_FAILURE(rc))295 return VERR_TAR_BAD_CHKSUM_FIELD;296 if ( i32ChkSum != i64HdrChkSum297 && i32ChkSumSignedAlt != i64HdrChkSum) /** @todo test this */298 return VERR_TAR_CHKSUM_MISMATCH;299 300 /*301 * Detect the TAR type.302 */303 RTZIPTARTYPE enmType;304 if ( pTar->Common.magic[0] == 'u'305 && pTar->Common.magic[1] == 's'306 && pTar->Common.magic[2] == 't'307 && pTar->Common.magic[3] == 'a'308 && pTar->Common.magic[4] == 'r')309 {310 /** @todo detect star headers */311 if ( pTar->Common.magic[5] == '\0'312 && pTar->Common.version[0] == '0'313 && pTar->Common.version[1] == '0')314 enmType = RTZIPTARTYPE_POSIX;315 else if ( pTar->Common.magic[5] == ' '316 && pTar->Common.version[0] == ' '317 && pTar->Common.version[1] == '\0')318 enmType = RTZIPTARTYPE_GNU;319 else if ( pTar->Common.magic[5] == '\0' /* VMWare ambiguity - they probably mean posix but */320 && pTar->Common.version[0] == ' ' /* got the version wrong. */321 && pTar->Common.version[1] == '\0')322 enmType = RTZIPTARTYPE_POSIX;323 else324 return VERR_TAR_NOT_USTAR_V00;325 }326 else327 enmType = RTZIPTARTYPE_ANCIENT;328 *penmType = enmType;329 330 /*331 * Perform some basic checks.332 */333 switch (enmType)334 {335 case RTZIPTARTYPE_POSIX:336 if ( !RT_C_IS_ALNUM(pTar->Common.typeflag)337 && pTar->Common.typeflag != '\0')338 return VERR_TAR_UNKNOWN_TYPE_FLAG;339 break;340 341 case RTZIPTARTYPE_GNU:342 switch (pTar->Common.typeflag)343 {344 case RTZIPTAR_TF_OLDNORMAL:345 case RTZIPTAR_TF_NORMAL:346 case RTZIPTAR_TF_CONTIG:347 case RTZIPTAR_TF_DIR:348 case RTZIPTAR_TF_CHR:349 case RTZIPTAR_TF_BLK:350 case RTZIPTAR_TF_LINK:351 case RTZIPTAR_TF_SYMLINK:352 case RTZIPTAR_TF_FIFO:353 break;354 355 case RTZIPTAR_TF_GNU_LONGLINK:356 case RTZIPTAR_TF_GNU_LONGNAME:357 break;358 359 case RTZIPTAR_TF_GNU_DUMPDIR:360 case RTZIPTAR_TF_GNU_MULTIVOL:361 case RTZIPTAR_TF_GNU_SPARSE:362 case RTZIPTAR_TF_GNU_VOLDHR:363 /** @todo Implement full GNU TAR support. .*/364 return VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE;365 366 default:367 return VERR_TAR_UNKNOWN_TYPE_FLAG;368 }369 break;370 371 case RTZIPTARTYPE_ANCIENT:372 switch (pTar->Common.typeflag)373 {374 case RTZIPTAR_TF_OLDNORMAL:375 case RTZIPTAR_TF_NORMAL:376 case RTZIPTAR_TF_CONTIG:377 case RTZIPTAR_TF_DIR:378 case RTZIPTAR_TF_LINK:379 case RTZIPTAR_TF_SYMLINK:380 case RTZIPTAR_TF_FIFO:381 break;382 default:383 return VERR_TAR_UNKNOWN_TYPE_FLAG;384 }385 break;386 default: /* shut up gcc */387 AssertFailedReturn(VERR_INTERNAL_ERROR_3);388 }389 390 return VINF_SUCCESS;391 }392 393 394 /**395 * Parses and validates the first TAR header of a archive/file/dir/whatever.396 *397 * @returns IPRT status code.398 * @param pThis The TAR reader stat.399 * @param pTar The TAR header that has been read.400 * @param fFirst Set if this is the first header, otherwise401 * clear.402 */403 static int rtZipTarReaderParseNextHeader(PRTZIPTARREADER pThis, PCRTZIPTARHDR pHdr, bool fFirst)404 {405 int rc;406 407 /*408 * Basic header validation and detection first.409 */410 RTZIPTARTYPE enmType;411 rc = rtZipTarHdrValidate(pHdr, &enmType);412 if (RT_FAILURE_NP(rc))413 {414 if (rc == VERR_TAR_ZERO_HEADER)415 {416 pThis->cZeroHdrs = 1;417 pThis->enmState = RTZIPTARREADERSTATE_ZERO;418 return VINF_SUCCESS;419 }420 return rc;421 }422 if (fFirst)423 {424 pThis->enmType = enmType;425 if (pThis->enmPrevType == RTZIPTARTYPE_INVALID)426 pThis->enmPrevType = enmType;427 }428 429 /*430 * Handle the header by type.431 */432 switch (pHdr->Common.typeflag)433 {434 case RTZIPTAR_TF_OLDNORMAL:435 case RTZIPTAR_TF_NORMAL:436 case RTZIPTAR_TF_CONTIG:437 case RTZIPTAR_TF_LINK:438 case RTZIPTAR_TF_SYMLINK:439 case RTZIPTAR_TF_CHR:440 case RTZIPTAR_TF_BLK:441 case RTZIPTAR_TF_FIFO:442 case RTZIPTAR_TF_DIR:443 /*444 * Extract the name first.445 */446 if (!pHdr->Common.name[0])447 return VERR_TAR_EMPTY_NAME;448 if (pThis->enmType == RTZIPTARTYPE_POSIX)449 {450 Assert(pThis->offGnuLongCur == 0); Assert(pThis->szName[0] == '\0');451 pThis->szName[0] = '\0';452 if (pHdr->Posix.prefix[0])453 {454 rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Posix.prefix, sizeof(pHdr->Posix.prefix));455 AssertRC(rc); /* shall not fail */456 rc = RTStrCat(pThis->szName, sizeof(pThis->szName), "/");457 AssertRC(rc); /* ditto */458 }459 rc = RTStrCatEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name));460 AssertRCReturn(rc, rc);461 }462 else if (pThis->enmType == RTZIPTARTYPE_GNU)463 {464 if (!pThis->szName[0])465 {466 rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name));467 AssertRCReturn(rc, rc);468 }469 }470 else471 {472 /* Old TAR */473 Assert(pThis->offGnuLongCur == 0); Assert(pThis->szName[0] == '\0');474 rc = RTStrCopyEx(pThis->szName, sizeof(pThis->szName), pHdr->Common.name, sizeof(pHdr->Common.name));475 AssertRCReturn(rc, rc);476 }477 478 /*479 * Extract the link target.480 */481 if ( pHdr->Common.typeflag == RTZIPTAR_TF_LINK482 || pHdr->Common.typeflag == RTZIPTAR_TF_SYMLINK)483 {484 if ( pThis->enmType == RTZIPTARTYPE_POSIX485 || pThis->enmType == RTZIPTARTYPE_ANCIENT486 || (pThis->enmType == RTZIPTARTYPE_GNU && pThis->szTarget[0] == '\0')487 )488 {489 Assert(pThis->szTarget[0] == '\0');490 rc = RTStrCopyEx(pThis->szTarget, sizeof(pThis->szTarget),491 pHdr->Common.linkname, sizeof(pHdr->Common.linkname));492 AssertRCReturn(rc, rc);493 }494 }495 else496 pThis->szTarget[0] = '\0';497 498 pThis->Hdr = *pHdr;499 break;500 501 case RTZIPTAR_TF_X_HDR:502 case RTZIPTAR_TF_X_GLOBAL:503 /** @todo implement PAX */504 return VERR_TAR_UNSUPPORTED_PAX_TYPE;505 506 case RTZIPTAR_TF_SOLARIS_XHDR:507 /** @todo implement solaris / pax attribute lists. */508 return VERR_TAR_UNSUPPORTED_SOLARIS_HDR_TYPE;509 510 511 /*512 * A GNU long name or long link is a dummy record followed by one or513 * more 512 byte string blocks holding the long name/link. The name514 * lenght is encoded in the size field, null terminator included. If515 * it is a symlink or hard link the long name may be followed by a516 * long link sequence.517 */518 case RTZIPTAR_TF_GNU_LONGNAME:519 case RTZIPTAR_TF_GNU_LONGLINK:520 {521 if (strcmp(pHdr->Gnu.name, "././@LongLink"))522 return VERR_TAR_MALFORMED_GNU_LONGXXXX;523 524 int64_t cb64;525 rc = rtZipTarHdrFieldToNum(pHdr->Gnu.size, sizeof(pHdr->Gnu.size), false /*fOctalOnly*/, &cb64);526 if (RT_FAILURE(rc) || cb64 < 0 || cb64 > _1M)527 return VERR_TAR_MALFORMED_GNU_LONGXXXX;528 uint32_t cb = (uint32_t)cb64;529 if (cb >= sizeof(pThis->szName))530 return VERR_TAR_NAME_TOO_LONG;531 532 pThis->cbGnuLongExpect = cb;533 pThis->offGnuLongCur = 0;534 pThis->enmState = pHdr->Common.typeflag == RTZIPTAR_TF_GNU_LONGNAME535 ? RTZIPTARREADERSTATE_GNU_LONGNAME536 : RTZIPTARREADERSTATE_GNU_LONGLINK;537 break;538 }539 540 case RTZIPTAR_TF_GNU_DUMPDIR:541 case RTZIPTAR_TF_GNU_MULTIVOL:542 case RTZIPTAR_TF_GNU_SPARSE:543 case RTZIPTAR_TF_GNU_VOLDHR:544 /** @todo Implement or skip GNU headers */545 return VERR_TAR_UNSUPPORTED_GNU_HDR_TYPE;546 547 default:548 return VERR_TAR_UNKNOWN_TYPE_FLAG;549 }550 551 return VINF_SUCCESS;552 }553 554 555 /**556 * Parses and validates a TAR header.557 *558 * @returns IPRT status code.559 * @param pThis The TAR reader stat.560 * @param pTar The TAR header that has been read.561 */562 static int rtZipTarReaderParseHeader(PRTZIPTARREADER pThis, PCRTZIPTARHDR pHdr)563 {564 switch (pThis->enmState)565 {566 /*567 * The first record for a file/directory/whatever.568 */569 case RTZIPTARREADERSTATE_FIRST:570 pThis->Hdr.Common.typeflag = 0x7f;571 pThis->enmPrevType = pThis->enmType;572 pThis->enmType = RTZIPTARTYPE_INVALID;573 pThis->offGnuLongCur = 0;574 pThis->cbGnuLongExpect = 0;575 pThis->szName[0] = '\0';576 pThis->szTarget[0] = '\0';577 return rtZipTarReaderParseNextHeader(pThis, pHdr, true /*fFirst*/);578 579 /*580 * There should only be so many zero headers at the end of the file as581 * it is a function of the block size used when writing. Don't go on582 * reading them forever in case someone points us to /dev/zero.583 */584 case RTZIPTARREADERSTATE_ZERO:585 if (!ASMMemIsZero(pHdr, sizeof(*pHdr)))586 return VERR_TAR_ZERO_HEADER;587 pThis->cZeroHdrs++;588 if (pThis->cZeroHdrs <= _64K / 512 + 2)589 return VINF_SUCCESS;590 return VERR_TAR_ZERO_HEADER;591 592 case RTZIPTARREADERSTATE_GNU_LONGNAME:593 case RTZIPTARREADERSTATE_GNU_LONGLINK:594 {595 size_t cbIncoming = RTStrNLen((const char *)pHdr->ab, sizeof(*pHdr));596 if (cbIncoming < sizeof(*pHdr))597 cbIncoming += 1;598 599 if (cbIncoming + pThis->offGnuLongCur > pThis->cbGnuLongExpect)600 return VERR_TAR_MALFORMED_GNU_LONGXXXX;601 if ( cbIncoming < sizeof(*pHdr)602 && cbIncoming + pThis->offGnuLongCur != pThis->cbGnuLongExpect)603 return VERR_TAR_MALFORMED_GNU_LONGXXXX;604 605 char *pszDst = pThis->enmState == RTZIPTARREADERSTATE_GNU_LONGNAME ? pThis->szName : pThis->szTarget;606 pszDst += pThis->offGnuLongCur;607 memcpy(pszDst, pHdr->ab, cbIncoming);608 609 pThis->offGnuLongCur += (uint32_t)cbIncoming;610 if (pThis->offGnuLongCur == pThis->cbGnuLongExpect)611 pThis->enmState = RTZIPTARREADERSTATE_GNU_NEXT;612 return VINF_SUCCESS;613 }614 615 case RTZIPTARREADERSTATE_GNU_NEXT:616 pThis->enmState = RTZIPTARREADERSTATE_FIRST;617 return rtZipTarReaderParseNextHeader(pThis, pHdr, false /*fFirst*/);618 619 default:620 return VERR_INTERNAL_ERROR_5;621 }622 }623 624 625 /**626 * Translate a TAR header to an IPRT object info structure with additional UNIX627 * attributes.628 *629 * This completes the validation done by rtZipTarHdrValidate.630 *631 * @returns VINF_SUCCESS if valid, appropriate VERR_TAR_XXX if not.632 * @param pThis The TAR reader instance.633 * @param pObjInfo The object info structure (output).634 */635 static int rtZipTarReaderGetFsObjInfo(PRTZIPTARREADER pThis, PRTFSOBJINFO pObjInfo)636 {637 /*638 * Zap the whole structure, this takes care of unused space in the union.639 */640 RT_ZERO(*pObjInfo);641 642 /*643 * Convert the TAR field in RTFSOBJINFO order.644 */645 int rc;646 int64_t i64Tmp;647 #define GET_TAR_NUMERIC_FIELD_RET(a_Var, a_Field) \648 do { \649 rc = rtZipTarHdrFieldToNum(a_Field, sizeof(a_Field), false /*fOctalOnly*/, &i64Tmp); \650 if (RT_FAILURE(rc)) \651 return rc; \652 (a_Var) = i64Tmp; \653 if ((a_Var) != i64Tmp) \654 return VERR_TAR_NUM_VALUE_TOO_LARGE; \655 } while (0)656 657 GET_TAR_NUMERIC_FIELD_RET(pObjInfo->cbObject, pThis->Hdr.Common.size);658 pObjInfo->cbAllocated = RT_ALIGN_64(pObjInfo->cbObject, 512);659 int64_t c64SecModTime;660 GET_TAR_NUMERIC_FIELD_RET(c64SecModTime, pThis->Hdr.Common.mtime);661 RTTimeSpecSetSeconds(&pObjInfo->ChangeTime, c64SecModTime);662 RTTimeSpecSetSeconds(&pObjInfo->ModificationTime, c64SecModTime);663 RTTimeSpecSetSeconds(&pObjInfo->AccessTime, c64SecModTime);664 RTTimeSpecSetSeconds(&pObjInfo->BirthTime, c64SecModTime);665 if (c64SecModTime != RTTimeSpecGetSeconds(&pObjInfo->ModificationTime))666 return VERR_TAR_NUM_VALUE_TOO_LARGE;667 GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.fMode, pThis->Hdr.Common.mode);668 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;669 GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.uid, pThis->Hdr.Common.uid);670 GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.gid, pThis->Hdr.Common.gid);671 pObjInfo->Attr.u.Unix.cHardlinks = 1;672 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;673 pObjInfo->Attr.u.Unix.INodeId = 0;674 pObjInfo->Attr.u.Unix.fFlags = 0;675 pObjInfo->Attr.u.Unix.GenerationId = 0;676 pObjInfo->Attr.u.Unix.Device = 0;677 switch (pThis->enmType)678 {679 case RTZIPTARTYPE_POSIX:680 case RTZIPTARTYPE_GNU:681 if ( pThis->Hdr.Common.typeflag == RTZIPTAR_TF_CHR682 || pThis->Hdr.Common.typeflag == RTZIPTAR_TF_BLK)683 {684 uint32_t uMajor, uMinor;685 GET_TAR_NUMERIC_FIELD_RET(uMajor, pThis->Hdr.Common.devmajor);686 GET_TAR_NUMERIC_FIELD_RET(uMinor, pThis->Hdr.Common.devminor);687 pObjInfo->Attr.u.Unix.Device = RTDEV_MAKE(uMajor, uMinor);688 if ( uMajor != RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device)689 || uMinor != RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device))690 return VERR_TAR_DEV_VALUE_TOO_LARGE;691 }692 break;693 694 default:695 if ( pThis->Hdr.Common.typeflag == RTZIPTAR_TF_CHR696 || pThis->Hdr.Common.typeflag == RTZIPTAR_TF_BLK)697 return VERR_TAR_UNKNOWN_TYPE_FLAG;698 }699 700 #undef GET_TAR_NUMERIC_FIELD_RET701 702 /*703 * Massage the result a little bit.704 * Also validate some more now that we've got the numbers to work with.705 */706 if ( (pObjInfo->Attr.fMode & ~RTFS_UNIX_MASK)707 && pThis->enmType == RTZIPTARTYPE_POSIX)708 return VERR_TAR_BAD_MODE_FIELD;709 pObjInfo->Attr.fMode &= RTFS_UNIX_MASK;710 711 RTFMODE fModeType = 0;712 switch (pThis->Hdr.Common.typeflag)713 {714 case RTZIPTAR_TF_OLDNORMAL:715 case RTZIPTAR_TF_NORMAL:716 case RTZIPTAR_TF_CONTIG:717 {718 const char *pszEnd = strchr(pThis->szName, '\0');719 if (pszEnd == &pThis->szName[0] || pszEnd[-1] != '/')720 fModeType |= RTFS_TYPE_FILE;721 else722 fModeType |= RTFS_TYPE_DIRECTORY;723 break;724 }725 726 case RTZIPTAR_TF_LINK:727 if (pObjInfo->cbObject != 0)728 #if 0 /* too strict */729 return VERR_TAR_SIZE_NOT_ZERO;730 #else731 pObjInfo->cbObject = pObjInfo->cbAllocated = 0;732 #endif733 fModeType |= RTFS_TYPE_FILE; /* no better idea for now */734 break;735 736 case RTZIPTAR_TF_SYMLINK:737 fModeType |= RTFS_TYPE_SYMLINK;738 break;739 740 case RTZIPTAR_TF_CHR:741 fModeType |= RTFS_TYPE_DEV_CHAR;742 break;743 744 case RTZIPTAR_TF_BLK:745 fModeType |= RTFS_TYPE_DEV_BLOCK;746 break;747 748 case RTZIPTAR_TF_DIR:749 fModeType |= RTFS_TYPE_DIRECTORY;750 break;751 752 case RTZIPTAR_TF_FIFO:753 fModeType |= RTFS_TYPE_FIFO;754 break;755 756 case RTZIPTAR_TF_GNU_LONGLINK:757 case RTZIPTAR_TF_GNU_LONGNAME:758 /* ASSUMES RTFS_TYPE_XXX uses the same values as GNU stored in the mode field. */759 fModeType = pObjInfo->Attr.fMode & RTFS_TYPE_MASK;760 switch (fModeType)761 {762 case RTFS_TYPE_FILE:763 case RTFS_TYPE_DIRECTORY:764 case RTFS_TYPE_SYMLINK:765 case RTFS_TYPE_DEV_BLOCK:766 case RTFS_TYPE_DEV_CHAR:767 case RTFS_TYPE_FIFO:768 break;769 770 default:771 case 0:772 return VERR_TAR_UNKNOWN_TYPE_FLAG; /** @todo new status code */773 }774 break;775 776 default:777 return VERR_TAR_UNKNOWN_TYPE_FLAG; /* Should've been caught in validate. */778 }779 if ( (pObjInfo->Attr.fMode & RTFS_TYPE_MASK)780 && (pObjInfo->Attr.fMode & RTFS_TYPE_MASK) != fModeType)781 return VERR_TAR_MODE_WITH_TYPE;782 pObjInfo->Attr.fMode &= ~RTFS_TYPE_MASK;783 pObjInfo->Attr.fMode |= fModeType;784 785 switch (pThis->Hdr.Common.typeflag)786 {787 case RTZIPTAR_TF_CHR:788 case RTZIPTAR_TF_BLK:789 case RTZIPTAR_TF_DIR:790 case RTZIPTAR_TF_FIFO:791 pObjInfo->cbObject = 0;792 pObjInfo->cbAllocated = 0;793 break;794 }795 796 return VINF_SUCCESS;797 }798 799 800 /**801 * Checks if the reader is expecting more headers.802 *803 * @returns true / false.804 * @param pThis The TAR reader instance.805 */806 static bool rtZipTarReaderExpectingMoreHeaders(PRTZIPTARREADER pThis)807 {808 return pThis->enmState != RTZIPTARREADERSTATE_FIRST;809 }810 811 812 /**813 * Checks if we're at the end of the TAR file.814 *815 * @returns true / false.816 * @param pThis The TAR reader instance.817 */818 static bool rtZipTarReaderIsAtEnd(PRTZIPTARREADER pThis)819 {820 /*821 * In theory there shall always be two zero headers at the end of the822 * archive, but life isn't that simple. We've been creating archives823 * without any zero headers at the end ourselves for a long long time824 * (old tar.cpp).825 *826 * So, we're fine if the state is 'FIRST' or 'ZERO' here, but we'll barf827 * if we're in the middle of a multi-header stream (long GNU names, sparse828 * files, PAX, etc).829 */830 return pThis->enmState == RTZIPTARREADERSTATE_FIRST831 || pThis->enmState == RTZIPTARREADERSTATE_ZERO;832 }833 834 835 /**836 * Checks if the current TAR object is a hard link or not.837 *838 * @returns true if it is, false if not.839 * @param pThis The TAR reader instance.840 */841 static bool rtZipTarReaderIsHardlink(PRTZIPTARREADER pThis)842 {843 return pThis->Hdr.Common.typeflag == RTZIPTAR_TF_LINK;844 }845 846 847 /**848 * Checks if the TAR header includes a POSIX or GNU user name field.849 *850 * @returns true / false.851 * @param pThis The TAR reader instance.852 */853 DECLINLINE(bool) rtZipTarReaderHasUserName(PRTZIPTARREADER pThis)854 {855 return pThis->Hdr.Common.uname[0] != '\0'856 && ( pThis->enmType == RTZIPTARTYPE_POSIX857 || pThis->enmType == RTZIPTARTYPE_GNU);858 }859 860 861 /**862 * Checks if the TAR header includes a POSIX or GNU group name field.863 *864 * @returns true / false.865 * @param pThis The TAR reader instance.866 */867 DECLINLINE(bool) rtZipTarReaderHasGroupName(PRTZIPTARREADER pThis)868 {869 return pThis->Hdr.Common.gname[0] != '\0'870 && ( pThis->enmType == RTZIPTARTYPE_POSIX871 || pThis->enmType == RTZIPTARTYPE_GNU);872 }873 874 875 /*876 *877 * 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.878 * 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.879 * 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.880 *881 */882 883 /**884 * @interface_method_impl{RTVFSOBJOPS,pfnClose}885 */886 static DECLCALLBACK(int) rtZipTarFssBaseObj_Close(void *pvThis)887 {888 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;889 890 /* Currently there is nothing we really have to do here. */891 pThis->offHdr = -1;892 893 return VINF_SUCCESS;894 }895 896 897 /**898 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}899 */900 static DECLCALLBACK(int) rtZipTarFssBaseObj_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)901 {902 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;903 904 /*905 * Copy the desired data.906 */907 switch (enmAddAttr)908 {909 case RTFSOBJATTRADD_NOTHING:910 case RTFSOBJATTRADD_UNIX:911 *pObjInfo = pThis->ObjInfo;912 break;913 914 case RTFSOBJATTRADD_UNIX_OWNER:915 *pObjInfo = pThis->ObjInfo;916 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;917 pObjInfo->Attr.u.UnixOwner.uid = pThis->ObjInfo.Attr.u.Unix.uid;918 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';919 if (rtZipTarReaderHasUserName(pThis->pTarReader))920 RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName),921 pThis->pTarReader->Hdr.Common.uname);922 break;923 924 case RTFSOBJATTRADD_UNIX_GROUP:925 *pObjInfo = pThis->ObjInfo;926 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;927 pObjInfo->Attr.u.UnixGroup.gid = pThis->ObjInfo.Attr.u.Unix.gid;928 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';929 if (rtZipTarReaderHasGroupName(pThis->pTarReader))930 RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName),931 pThis->pTarReader->Hdr.Common.gname);932 break;933 934 case RTFSOBJATTRADD_EASIZE:935 *pObjInfo = pThis->ObjInfo;936 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;937 RT_ZERO(pObjInfo->Attr.u);938 break;939 940 default:941 return VERR_NOT_SUPPORTED;942 }943 944 return VINF_SUCCESS;945 }946 947 948 /**949 * Tar filesystem base object operations.950 */951 static const RTVFSOBJOPS g_rtZipTarFssBaseObjOps =952 {953 RTVFSOBJOPS_VERSION,954 RTVFSOBJTYPE_BASE,955 "TarFsStream::Obj",956 rtZipTarFssBaseObj_Close,957 rtZipTarFssBaseObj_QueryInfo,958 RTVFSOBJOPS_VERSION959 };960 961 962 /**963 * @interface_method_impl{RTVFSOBJOPS,pfnClose}964 */965 static DECLCALLBACK(int) rtZipTarFssIos_Close(void *pvThis)966 {967 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;968 969 RTVfsIoStrmRelease(pThis->hVfsIos);970 pThis->hVfsIos = NIL_RTVFSIOSTREAM;971 972 return rtZipTarFssBaseObj_Close(&pThis->BaseObj);973 }974 975 976 /**977 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}978 */979 static DECLCALLBACK(int) rtZipTarFssIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)980 {981 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;982 return rtZipTarFssBaseObj_QueryInfo(&pThis->BaseObj, pObjInfo, enmAddAttr);983 }984 985 986 /**987 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}988 */989 static DECLCALLBACK(int) rtZipTarFssIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)990 {991 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;992 Assert(pSgBuf->cSegs == 1);993 994 /*995 * Make offset into a real offset so it's possible to do random access996 * on TAR files that are seekable. Fend of reads beyond the end of the997 * stream.998 */999 if (off < 0)1000 off = pThis->offFile;1001 if (off >= pThis->cbFile)1002 return pcbRead ? VINF_EOF : VERR_EOF;1003 1004 1005 Assert(pThis->cbFile >= pThis->offFile);1006 uint64_t cbLeft = (uint64_t)(pThis->cbFile - off);1007 size_t cbToRead = pSgBuf->paSegs[0].cbSeg;1008 if (cbToRead > cbLeft)1009 {1010 if (!pcbRead)1011 return VERR_EOF;1012 cbToRead = (size_t)cbLeft;1013 }1014 1015 /*1016 * Do the reading.1017 */1018 size_t cbReadStack = 0;1019 if (!pcbRead)1020 pcbRead = &cbReadStack;1021 int rc = RTVfsIoStrmReadAt(pThis->hVfsIos, pThis->offStart + off, pSgBuf->paSegs[0].pvSeg, cbToRead, fBlocking, pcbRead);1022 pThis->offFile = off + *pcbRead;1023 if (pThis->offFile >= pThis->cbFile)1024 {1025 Assert(pThis->offFile == pThis->cbFile);1026 pThis->fEndOfStream = true;1027 RTVfsIoStrmSkip(pThis->hVfsIos, pThis->cbPadding);1028 }1029 1030 return rc;1031 }1032 1033 1034 /**1035 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}1036 */1037 static DECLCALLBACK(int) rtZipTarFssIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)1038 {1039 /* Cannot write to a read-only I/O stream. */1040 NOREF(pvThis); NOREF(off); NOREF(pSgBuf); NOREF(fBlocking); NOREF(pcbWritten);1041 return VERR_ACCESS_DENIED;1042 }1043 1044 1045 /**1046 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}1047 */1048 static DECLCALLBACK(int) rtZipTarFssIos_Flush(void *pvThis)1049 {1050 /* It's a read only stream, nothing dirty to flush. */1051 NOREF(pvThis);1052 return VINF_SUCCESS;1053 }1054 1055 1056 /**1057 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}1058 */1059 static DECLCALLBACK(int) rtZipTarFssIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,1060 uint32_t *pfRetEvents)1061 {1062 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;1063 1064 /* When we've reached the end, read will be set to indicate it. */1065 if ( (fEvents & RTPOLL_EVT_READ)1066 && pThis->fEndOfStream)1067 {1068 int rc = RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, 0, fIntr, pfRetEvents);1069 if (RT_SUCCESS(rc))1070 *pfRetEvents |= RTPOLL_EVT_READ;1071 else1072 *pfRetEvents = RTPOLL_EVT_READ;1073 return VINF_SUCCESS;1074 }1075 1076 return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);1077 }1078 1079 1080 /**1081 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}1082 */1083 static DECLCALLBACK(int) rtZipTarFssIos_Tell(void *pvThis, PRTFOFF poffActual)1084 {1085 PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;1086 *poffActual = pThis->offFile;1087 return VINF_SUCCESS;1088 }1089 1090 1091 /**1092 * Tar I/O stream operations.1093 */1094 static const RTVFSIOSTREAMOPS g_rtZipTarFssIosOps =1095 {1096 { /* Obj */1097 RTVFSOBJOPS_VERSION,1098 RTVFSOBJTYPE_IO_STREAM,1099 "TarFsStream::IoStream",1100 rtZipTarFssIos_Close,1101 rtZipTarFssIos_QueryInfo,1102 RTVFSOBJOPS_VERSION1103 },1104 RTVFSIOSTREAMOPS_VERSION,1105 RTVFSIOSTREAMOPS_FEAT_NO_SG,1106 rtZipTarFssIos_Read,1107 rtZipTarFssIos_Write,1108 rtZipTarFssIos_Flush,1109 rtZipTarFssIos_PollOne,1110 rtZipTarFssIos_Tell,1111 NULL /*Skip*/,1112 NULL /*ZeroFill*/,1113 RTVFSIOSTREAMOPS_VERSION1114 };1115 1116 1117 /**1118 * @interface_method_impl{RTVFSOBJOPS,pfnClose}1119 */1120 static DECLCALLBACK(int) rtZipTarFssSym_Close(void *pvThis)1121 {1122 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;1123 return rtZipTarFssBaseObj_Close(pThis);1124 }1125 1126 1127 /**1128 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}1129 */1130 static DECLCALLBACK(int) rtZipTarFssSym_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)1131 {1132 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;1133 return rtZipTarFssBaseObj_QueryInfo(pThis, pObjInfo, enmAddAttr);1134 }1135 1136 /**1137 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}1138 */1139 static DECLCALLBACK(int) rtZipTarFssSym_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)1140 {1141 NOREF(pvThis); NOREF(fMode); NOREF(fMask);1142 return VERR_ACCESS_DENIED;1143 }1144 1145 1146 /**1147 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}1148 */1149 static DECLCALLBACK(int) rtZipTarFssSym_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,1150 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)1151 {1152 NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);1153 return VERR_ACCESS_DENIED;1154 }1155 1156 1157 /**1158 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}1159 */1160 static DECLCALLBACK(int) rtZipTarFssSym_SetOwner(void *pvThis, RTUID uid, RTGID gid)1161 {1162 NOREF(pvThis); NOREF(uid); NOREF(gid);1163 return VERR_ACCESS_DENIED;1164 }1165 1166 1167 /**1168 * @interface_method_impl{RTVFSSYMLINKOPS,pfnRead}1169 */1170 static DECLCALLBACK(int) rtZipTarFssSym_Read(void *pvThis, char *pszTarget, size_t cbTarget)1171 {1172 PRTZIPTARBASEOBJ pThis = (PRTZIPTARBASEOBJ)pvThis;1173 return RTStrCopy(pszTarget, cbTarget, pThis->pTarReader->szTarget);1174 }1175 1176 1177 /**1178 * Tar symbolic (and hardlink) operations.1179 */1180 static const RTVFSSYMLINKOPS g_rtZipTarFssSymOps =1181 {1182 { /* Obj */1183 RTVFSOBJOPS_VERSION,1184 RTVFSOBJTYPE_SYMLINK,1185 "TarFsStream::Symlink",1186 rtZipTarFssSym_Close,1187 rtZipTarFssSym_QueryInfo,1188 RTVFSOBJOPS_VERSION1189 },1190 RTVFSSYMLINKOPS_VERSION,1191 0,1192 { /* ObjSet */1193 RTVFSOBJSETOPS_VERSION,1194 RT_UOFFSETOF(RTVFSSYMLINKOPS, ObjSet) - RT_UOFFSETOF(RTVFSSYMLINKOPS, Obj),1195 rtZipTarFssSym_SetMode,1196 rtZipTarFssSym_SetTimes,1197 rtZipTarFssSym_SetOwner,1198 RTVFSOBJSETOPS_VERSION1199 },1200 rtZipTarFssSym_Read,1201 RTVFSSYMLINKOPS_VERSION1202 };1203 1204 1205 /**1206 * @interface_method_impl{RTVFSOBJOPS,pfnClose}1207 */1208 static DECLCALLBACK(int) rtZipTarFss_Close(void *pvThis)1209 {1210 PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;1211 1212 RTVfsObjRelease(pThis->hVfsCurObj);1213 pThis->hVfsCurObj = NIL_RTVFSOBJ;1214 pThis->pCurIosData = NULL;1215 1216 RTVfsIoStrmRelease(pThis->hVfsIos);1217 pThis->hVfsIos = NIL_RTVFSIOSTREAM;1218 1219 return VINF_SUCCESS;1220 }1221 1222 1223 /**1224 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}1225 */1226 static DECLCALLBACK(int) rtZipTarFss_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)1227 {1228 PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;1229 /* Take the lazy approach here, with the sideffect of providing some info1230 that is actually kind of useful. */1231 return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);1232 }1233 1234 1235 /**1236 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}1237 */1238 static DECLCALLBACK(int) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)1239 {1240 PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;1241 1242 /*1243 * Dispense with the current object.1244 */1245 if (pThis->hVfsCurObj != NIL_RTVFSOBJ)1246 {1247 if (pThis->pCurIosData)1248 {1249 pThis->pCurIosData->fEndOfStream = true;1250 pThis->pCurIosData->offFile = pThis->pCurIosData->cbFile;1251 pThis->pCurIosData = NULL;1252 }1253 1254 RTVfsObjRelease(pThis->hVfsCurObj);1255 pThis->hVfsCurObj = NIL_RTVFSOBJ;1256 }1257 1258 /*1259 * Check if we've already reached the end in some way.1260 */1261 if (pThis->fEndOfStream)1262 return VERR_EOF;1263 if (pThis->rcFatal != VINF_SUCCESS)1264 return pThis->rcFatal;1265 1266 /*1267 * Make sure the input stream is in the right place.1268 */1269 RTFOFF offHdr = RTVfsIoStrmTell(pThis->hVfsIos);1270 while ( offHdr >= 01271 && offHdr < pThis->offNextHdr)1272 {1273 int rc = RTVfsIoStrmSkip(pThis->hVfsIos, pThis->offNextHdr - offHdr);1274 if (RT_FAILURE(rc))1275 {1276 /** @todo Ignore if we're at the end of the stream? */1277 return pThis->rcFatal = rc;1278 }1279 1280 offHdr = RTVfsIoStrmTell(pThis->hVfsIos);1281 }1282 1283 if (offHdr < 0)1284 return pThis->rcFatal = (int)offHdr;1285 if (offHdr > pThis->offNextHdr)1286 return pThis->rcFatal = VERR_INTERNAL_ERROR_3;1287 1288 /*1289 * Consume TAR headers.1290 */1291 size_t cbHdrs = 0;1292 int rc;1293 do1294 {1295 /*1296 * Read the next header.1297 */1298 RTZIPTARHDR Hdr;1299 size_t cbRead;1300 rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);1301 if (RT_FAILURE(rc))1302 return pThis->rcFatal = rc;1303 if (rc == VINF_EOF && cbRead == 0)1304 {1305 pThis->fEndOfStream = true;1306 return rtZipTarReaderIsAtEnd(&pThis->TarReader) ? VERR_EOF : VERR_TAR_UNEXPECTED_EOS;1307 }1308 if (cbRead != sizeof(Hdr))1309 return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS;1310 1311 cbHdrs += sizeof(Hdr);1312 1313 /*1314 * Parse the it.1315 */1316 rc = rtZipTarReaderParseHeader(&pThis->TarReader, &Hdr);1317 if (RT_FAILURE(rc))1318 return pThis->rcFatal = rc;1319 } while (rtZipTarReaderExpectingMoreHeaders(&pThis->TarReader));1320 1321 pThis->offNextHdr = offHdr + cbHdrs;1322 1323 /*1324 * Fill an object info structure from the current TAR state.1325 */1326 RTFSOBJINFO Info;1327 rc = rtZipTarReaderGetFsObjInfo(&pThis->TarReader, &Info);1328 if (RT_FAILURE(rc))1329 return pThis->rcFatal = rc;1330 1331 /*1332 * Create an object of the appropriate type.1333 */1334 RTVFSOBJTYPE enmType;1335 RTVFSOBJ hVfsObj;1336 RTFMODE fType = Info.Attr.fMode & RTFS_TYPE_MASK;1337 if (rtZipTarReaderIsHardlink(&pThis->TarReader))1338 fType = RTFS_TYPE_SYMLINK;1339 switch (fType)1340 {1341 /*1342 * Files are represented by a VFS I/O stream.1343 */1344 case RTFS_TYPE_FILE:1345 {1346 RTVFSIOSTREAM hVfsIos;1347 PRTZIPTARIOSTREAM pIosData;1348 rc = RTVfsNewIoStream(&g_rtZipTarFssIosOps,1349 sizeof(*pIosData),1350 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,1351 NIL_RTVFS,1352 NIL_RTVFSLOCK,1353 &hVfsIos,1354 (void **)&pIosData);1355 if (RT_FAILURE(rc))1356 return pThis->rcFatal = rc;1357 1358 pIosData->BaseObj.offHdr = offHdr;1359 pIosData->BaseObj.pTarReader= &pThis->TarReader;1360 pIosData->BaseObj.ObjInfo = Info;1361 pIosData->cbFile = Info.cbObject;1362 pIosData->offFile = 0;1363 pIosData->offStart = RTVfsIoStrmTell(pThis->hVfsIos);1364 pIosData->cbPadding = (uint32_t)(Info.cbAllocated - Info.cbObject);1365 pIosData->fEndOfStream = false;1366 pIosData->hVfsIos = pThis->hVfsIos;1367 RTVfsIoStrmRetain(pThis->hVfsIos);1368 1369 pThis->pCurIosData = pIosData;1370 pThis->offNextHdr += pIosData->cbFile + pIosData->cbPadding;1371 1372 enmType = RTVFSOBJTYPE_IO_STREAM;1373 hVfsObj = RTVfsObjFromIoStream(hVfsIos);1374 RTVfsIoStrmRelease(hVfsIos);1375 break;1376 }1377 1378 /*1379 * We represent hard links using a symbolic link object. This fits1380 * best with the way TAR stores it and there is currently no better1381 * fitting VFS type alternative.1382 */1383 case RTFS_TYPE_SYMLINK:1384 {1385 RTVFSSYMLINK hVfsSym;1386 PRTZIPTARBASEOBJ pBaseObjData;1387 rc = RTVfsNewSymlink(&g_rtZipTarFssSymOps,1388 sizeof(*pBaseObjData),1389 NIL_RTVFS,1390 NIL_RTVFSLOCK,1391 &hVfsSym,1392 (void **)&pBaseObjData);1393 if (RT_FAILURE(rc))1394 return pThis->rcFatal = rc;1395 1396 pBaseObjData->offHdr = offHdr;1397 pBaseObjData->pTarReader= &pThis->TarReader;1398 pBaseObjData->ObjInfo = Info;1399 1400 enmType = RTVFSOBJTYPE_SYMLINK;1401 hVfsObj = RTVfsObjFromSymlink(hVfsSym);1402 RTVfsSymlinkRelease(hVfsSym);1403 break;1404 }1405 1406 /*1407 * All other objects are repesented using a VFS base object since they1408 * carry no data streams (unless some TAR extension implements extended1409 * attributes / alternative streams).1410 */1411 case RTFS_TYPE_DEV_BLOCK:1412 case RTFS_TYPE_DEV_CHAR:1413 case RTFS_TYPE_DIRECTORY:1414 case RTFS_TYPE_FIFO:1415 {1416 PRTZIPTARBASEOBJ pBaseObjData;1417 rc = RTVfsNewBaseObj(&g_rtZipTarFssBaseObjOps,1418 sizeof(*pBaseObjData),1419 NIL_RTVFS,1420 NIL_RTVFSLOCK,1421 &hVfsObj,1422 (void **)&pBaseObjData);1423 if (RT_FAILURE(rc))1424 return pThis->rcFatal = rc;1425 1426 pBaseObjData->offHdr = offHdr;1427 pBaseObjData->pTarReader= &pThis->TarReader;1428 pBaseObjData->ObjInfo = Info;1429 1430 enmType = RTVFSOBJTYPE_BASE;1431 break;1432 }1433 1434 default:1435 AssertFailed();1436 return pThis->rcFatal = VERR_INTERNAL_ERROR_5;1437 }1438 pThis->hVfsCurObj = hVfsObj;1439 1440 /*1441 * Set the return data and we're done.1442 */1443 if (ppszName)1444 {1445 rc = RTStrDupEx(ppszName, pThis->TarReader.szName);1446 if (RT_FAILURE(rc))1447 return rc;1448 }1449 1450 if (phVfsObj)1451 {1452 RTVfsObjRetain(hVfsObj);1453 *phVfsObj = hVfsObj;1454 }1455 1456 if (penmType)1457 *penmType = enmType;1458 1459 return VINF_SUCCESS;1460 }1461 1462 1463 1464 /**1465 * Tar filesystem stream operations.1466 */1467 static const RTVFSFSSTREAMOPS rtZipTarFssOps =1468 {1469 { /* Obj */1470 RTVFSOBJOPS_VERSION,1471 RTVFSOBJTYPE_FS_STREAM,1472 "TarFsStream",1473 rtZipTarFss_Close,1474 rtZipTarFss_QueryInfo,1475 RTVFSOBJOPS_VERSION1476 },1477 RTVFSFSSTREAMOPS_VERSION,1478 0,1479 rtZipTarFss_Next,1480 NULL,1481 NULL,1482 NULL,1483 RTVFSFSSTREAMOPS_VERSION1484 };1485 1486 1487 RTDECL(int) RTZipTarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)1488 {1489 /*1490 * Input validation.1491 */1492 AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);1493 *phVfsFss = NIL_RTVFSFSSTREAM;1494 AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE);1495 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);1496 1497 RTFOFF const offStart = RTVfsIoStrmTell(hVfsIosIn);1498 AssertReturn(offStart >= 0, (int)offStart);1499 1500 uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn);1501 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);1502 1503 /*1504 * Retain the input stream and create a new filesystem stream handle.1505 */1506 PRTZIPTARFSSTREAM pThis;1507 RTVFSFSSTREAM hVfsFss;1508 int rc = RTVfsNewFsStream(&rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, true /*fReadOnly*/,1509 &hVfsFss, (void **)&pThis);1510 if (RT_SUCCESS(rc))1511 {1512 pThis->hVfsIos = hVfsIosIn;1513 pThis->hVfsCurObj = NIL_RTVFSOBJ;1514 pThis->pCurIosData = NULL;1515 pThis->offStart = offStart;1516 pThis->offNextHdr = offStart;1517 pThis->fEndOfStream = false;1518 pThis->rcFatal = VINF_SUCCESS;1519 pThis->TarReader.enmPrevType= RTZIPTARTYPE_INVALID;1520 pThis->TarReader.enmType = RTZIPTARTYPE_INVALID;1521 pThis->TarReader.enmState = RTZIPTARREADERSTATE_FIRST;1522 1523 /* Don't check if it's a TAR stream here, do that in the1524 rtZipTarFss_Next. */1525 1526 *phVfsFss = hVfsFss;1527 return VINF_SUCCESS;1528 }1529 1530 RTVfsIoStrmRelease(hVfsIosIn);1531 return rc;1532 }1533 -
trunk/src/VBox/Runtime/common/zip/tarvfswriter.cpp
r82968 r84192 44 44 45 45 #include "tar.h" 46 47 #include "tarvfsreader.h" 46 48 47 49 … … 161 163 /** Set if we've encountered a fatal error. */ 162 164 int rcFatal; 163 /** Flags . */165 /** Flags, RTZIPTAR_C_XXX. */ 164 166 uint32_t fFlags; 165 167 … … 183 185 RTFMODE fDirModeOrMask; /**< Directory mode OR mask. */ 184 186 /** @} */ 187 188 /** When in update mode (RTZIPTAR_C_UPDATE) we have an reader FSS instance, 189 * though w/o the RTVFSFSSTREAM bits. (Allocated after this structure.) */ 190 PRTZIPTARFSSTREAM pRead; 191 /** Set if we're in writing mode and pfnNext shall fail. */ 192 bool fWriting; 185 193 186 194 … … 909 917 910 918 /** 919 * Does the actual work for rtZipTarFssWriter_SwitchToWriteMode(). 920 * 921 * @note We won't be here if we've truncate the tar file. Truncation 922 * switches it into write mode. 923 */ 924 DECL_NO_INLINE(static, int) rtZipTarFssWriter_SwitchToWriteModeSlow(PRTZIPTARFSSTREAMWRITER pThis) 925 { 926 /* Always go thru rtZipTarFssWriter_SwitchToWriteMode(). */ 927 AssertRCReturn(pThis->rcFatal, pThis->rcFatal); 928 AssertReturn(!pThis->fWriting, VINF_SUCCESS); 929 AssertReturn(pThis->fFlags & RTZIPTAR_C_UPDATE, VERR_INTERNAL_ERROR_3); 930 931 /* 932 * If we're not at the end, locate the end of the tar file. 933 * Because I'm lazy, we do that using rtZipTarFss_Next. This isn't entirely 934 * optimial as it involves VFS object instantations and such. 935 */ 936 /** @todo Optimize skipping to end of tar file in update mode. */ 937 while (!pThis->pRead->fEndOfStream) 938 { 939 int rc = rtZipTarFss_Next(pThis->pRead, NULL, NULL, NULL); 940 if (rc == VERR_EOF) 941 break; 942 AssertRCReturn(rc, rc); 943 } 944 945 /* 946 * Seek to the desired cut-off point and indicate that we've switched to writing. 947 */ 948 Assert(pThis->pRead->offNextHdr == pThis->pRead->offCurHdr); 949 int rc = RTVfsFileSeek(pThis->hVfsFile, pThis->pRead->offNextHdr, RTFILE_SEEK_BEGIN, NULL /*poffActual*/); 950 if (RT_SUCCESS(rc)) 951 pThis->fWriting = true; 952 else 953 pThis->rcFatal = rc; 954 955 return rc; 956 } 957 958 959 /** 960 * Switches the stream into writing mode if necessary. 961 * 962 * @returns VBox status code. 963 * @param pThis The TAR writer instance. 964 * 965 */ 966 DECLINLINE(int) rtZipTarFssWriter_SwitchToWriteMode(PRTZIPTARFSSTREAMWRITER pThis) 967 { 968 if (pThis->fWriting) 969 return VINF_SUCCESS; /* ASSUMES caller already checked pThis->rcFatal. */ 970 return rtZipTarFssWriter_SwitchToWriteModeSlow(pThis); 971 } 972 973 974 /** 911 975 * Allocates a buffer for transfering file data. 912 976 * … … 922 986 * @param cbFile The file size. Used as a buffer size hint. 923 987 */ 924 static uint8_t *rtZipTarFssWrite _AllocBuf(PRTZIPTARFSSTREAMWRITER pThis, size_t *pcbBuf, void **ppvFree, uint64_t cbObject)988 static uint8_t *rtZipTarFssWriter_AllocBuf(PRTZIPTARFSSTREAMWRITER pThis, size_t *pcbBuf, void **ppvFree, uint64_t cbObject) 925 989 { 926 990 uint8_t *pbBuf; … … 1274 1338 void *pvBufFree; 1275 1339 size_t cbBuf; 1276 uint8_t *pbBuf = rtZipTarFssWrite _AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject);1340 uint8_t *pbBuf = rtZipTarFssWriter_AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject); 1277 1341 1278 1342 PRTZIPTARSPARSE pSparse; … … 1399 1463 void *pvBufFree; 1400 1464 size_t cbBuf; 1401 uint8_t *pbBuf = rtZipTarFssWrite _AllocBuf(pThis, &cbBuf, &pvBufFree,1402 pObjInfo->cbObject > 0 && pObjInfo->cbObject != RTFOFF_MAX1403 ? pObjInfo->cbObject : _1G);1465 uint8_t *pbBuf = rtZipTarFssWriter_AllocBuf(pThis, &cbBuf, &pvBufFree, 1466 pObjInfo->cbObject > 0 && pObjInfo->cbObject != RTFOFF_MAX 1467 ? pObjInfo->cbObject : _1G); 1404 1468 1405 1469 uint64_t cbReadTotal = 0; … … 1502 1566 void *pvBufFree; 1503 1567 size_t cbBuf; 1504 uint8_t *pbBuf = rtZipTarFssWrite _AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject);1568 uint8_t *pbBuf = rtZipTarFssWriter_AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject); 1505 1569 1506 1570 uint64_t cbLeft = pObjInfo->cbObject; … … 1684 1748 1685 1749 /** 1750 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext} 1751 */ 1752 static DECLCALLBACK(int) rtZipTarFssWriter_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj) 1753 { 1754 PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis; 1755 1756 /* 1757 * This only works in update mode and up to the point where 1758 * modifications takes place (truncating the archive or appending files). 1759 */ 1760 AssertReturn(pThis->pRead, VERR_ACCESS_DENIED); 1761 AssertReturn(pThis->fFlags & RTZIPTAR_C_UPDATE, VERR_ACCESS_DENIED); 1762 1763 AssertReturn(!pThis->fWriting, VERR_WRONG_ORDER); 1764 1765 return rtZipTarFss_Next(pThis->pRead, ppszName, penmType, phVfsObj); 1766 } 1767 1768 1769 /** 1686 1770 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnAdd} 1687 1771 */ … … 1694 1778 */ 1695 1779 int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis); 1696 if (RT_FAILURE(rc)) 1697 return rc; 1780 AssertRCReturn(rc, rc); 1698 1781 1699 1782 /* … … 1713 1796 if (RT_FAILURE(rc) || ObjGrpName.Attr.u.UnixGroup.szName[0] == '\0') 1714 1797 strcpy(ObjGrpName.Attr.u.UnixGroup.szName, "somegroup"); 1798 1799 /* 1800 * Switch the stream into write mode if necessary. 1801 */ 1802 rc = rtZipTarFssWriter_SwitchToWriteMode(pThis); 1803 AssertRCReturn(rc, rc); 1715 1804 1716 1805 /* … … 1780 1869 */ 1781 1870 int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis); 1782 if (RT_FAILURE(rc)) 1783 return rc; 1871 AssertRCReturn(rc, rc); 1784 1872 1785 1873 /* … … 1833 1921 1834 1922 /* 1923 * Switch the stream into write mode if necessary. 1924 */ 1925 rc = rtZipTarFssWriter_SwitchToWriteMode(pThis); 1926 AssertRCReturn(rc, rc); 1927 1928 /* 1835 1929 * Create an I/O stream object for the caller to use. 1836 1930 */ … … 1925 2019 */ 1926 2020 rc = RTVfsIoStrmFlush(pThis->hVfsIos); 2021 2022 /* 2023 * If we're in update mode, set the end-of-file here to make sure 2024 * unwanted bytes are really discarded. 2025 */ 2026 if (RT_SUCCESS(rc) && (pThis->fFlags & RTZIPTAR_C_UPDATE)) 2027 { 2028 RTFOFF cbTarFile = RTVfsFileTell(pThis->hVfsFile); 2029 if (cbTarFile >= 0) 2030 rc = RTVfsFileSetSize(pThis->hVfsFile, (uint64_t)cbTarFile, RTVFSFILE_SIZE_F_NORMAL); 2031 else 2032 rc = (int)cbTarFile; 2033 } 2034 2035 /* 2036 * Success? 2037 */ 1927 2038 if (RT_SUCCESS(rc)) 1928 2039 return rc; … … 1949 2060 RTVFSFSSTREAMOPS_VERSION, 1950 2061 0, 1951 NULL,2062 rtZipTarFssWriter_Next, 1952 2063 rtZipTarFssWriter_Add, 1953 2064 rtZipTarFssWriter_PushFile, … … 1968 2079 AssertReturn(enmFormat > RTZIPTARFORMAT_INVALID && enmFormat < RTZIPTARFORMAT_END, VERR_INVALID_PARAMETER); 1969 2080 AssertReturn(!(fFlags & ~RTZIPTAR_C_VALID_MASK), VERR_INVALID_FLAGS); 2081 AssertReturn(!(fFlags & RTZIPTAR_C_UPDATE), VERR_NOT_SUPPORTED); /* Must use RTZipTarFsStreamForFile! */ 1970 2082 1971 2083 if (enmFormat == RTZIPTARFORMAT_DEFAULT) … … 1983 2095 PRTZIPTARFSSTREAMWRITER pThis; 1984 2096 RTVFSFSSTREAM hVfsFss; 1985 int rc = RTVfsNewFsStream(&g_rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, false /*fReadOnly*/,2097 int rc = RTVfsNewFsStream(&g_rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE, 1986 2098 &hVfsFss, (void **)&pThis); 1987 2099 if (RT_SUCCESS(rc)) … … 2004 2116 pThis->fDirModeAndMask = ~(RTFMODE)0; 2005 2117 pThis->fDirModeOrMask = 0; 2118 pThis->fWriting = true; 2006 2119 2007 2120 *phVfsFss = hVfsFss; … … 2010 2123 2011 2124 RTVfsIoStrmRelease(hVfsIosOut); 2125 return rc; 2126 } 2127 2128 2129 RTDECL(int) RTZipTarFsStreamForFile(RTVFSFILE hVfsFile, RTZIPTARFORMAT enmFormat, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss) 2130 { 2131 /* 2132 * Input validation. 2133 */ 2134 AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE); 2135 *phVfsFss = NIL_RTVFSFSSTREAM; 2136 AssertPtrReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE); 2137 AssertReturn(enmFormat > RTZIPTARFORMAT_INVALID && enmFormat < RTZIPTARFORMAT_END, VERR_INVALID_PARAMETER); 2138 AssertReturn(!(fFlags & ~RTZIPTAR_C_VALID_MASK), VERR_INVALID_FLAGS); 2139 2140 if (enmFormat == RTZIPTARFORMAT_DEFAULT) 2141 enmFormat = RTZIPTARFORMAT_GNU; 2142 AssertReturn( enmFormat == RTZIPTARFORMAT_GNU 2143 || enmFormat == RTZIPTARFORMAT_USTAR 2144 , VERR_NOT_IMPLEMENTED); /* Only implementing GNU and USTAR output at the moment. */ 2145 2146 RTFOFF const offStart = RTVfsFileTell(hVfsFile); 2147 AssertReturn(offStart >= 0, (int)offStart); 2148 2149 uint32_t cRefs = RTVfsFileRetain(hVfsFile); 2150 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE); 2151 2152 RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hVfsFile); 2153 AssertReturnStmt(hVfsIos != NIL_RTVFSIOSTREAM, RTVfsFileRelease(hVfsFile), VERR_INVALID_HANDLE); 2154 2155 /* 2156 * Retain the input stream and create a new filesystem stream handle. 2157 */ 2158 PRTZIPTARFSSTREAMWRITER pThis; 2159 size_t const cbThis = sizeof(*pThis) + (fFlags & RTZIPTAR_C_UPDATE ? sizeof(*pThis->pRead) : 0); 2160 RTVFSFSSTREAM hVfsFss; 2161 int rc = RTVfsNewFsStream(&g_rtZipTarFssOps, cbThis, NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE, 2162 &hVfsFss, (void **)&pThis); 2163 if (RT_SUCCESS(rc)) 2164 { 2165 pThis->hVfsIos = hVfsIos; 2166 pThis->hVfsFile = hVfsFile; 2167 2168 pThis->enmFormat = enmFormat; 2169 pThis->fFlags = fFlags; 2170 pThis->rcFatal = VINF_SUCCESS; 2171 2172 pThis->uidOwner = NIL_RTUID; 2173 pThis->pszOwner = NULL; 2174 pThis->gidGroup = NIL_RTGID; 2175 pThis->pszGroup = NULL; 2176 pThis->pszPrefix = NULL; 2177 pThis->pModTime = NULL; 2178 pThis->fFileModeAndMask = ~(RTFMODE)0; 2179 pThis->fFileModeOrMask = 0; 2180 pThis->fDirModeAndMask = ~(RTFMODE)0; 2181 pThis->fDirModeOrMask = 0; 2182 if (!(fFlags & RTZIPTAR_C_UPDATE)) 2183 pThis->fWriting = true; 2184 else 2185 { 2186 pThis->fWriting = false; 2187 pThis->pRead = (PRTZIPTARFSSTREAM)(pThis + 1); 2188 rtZipTarReaderInit(pThis->pRead, hVfsIos, (uint64_t)offStart); 2189 } 2190 2191 *phVfsFss = hVfsFss; 2192 return VINF_SUCCESS; 2193 } 2194 2195 RTVfsIoStrmRelease(hVfsIos); 2196 RTVfsFileRelease(hVfsFile); 2012 2197 return rc; 2013 2198 } … … 2136 2321 } 2137 2322 2323 2324 RTDECL(int) RTZipTarFsStreamTruncate(RTVFSFSSTREAM hVfsFss, RTVFSOBJ hVfsObj, bool fAfter) 2325 { 2326 /* 2327 * Translate and validate the input. 2328 */ 2329 PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)RTVfsFsStreamToPrivate(hVfsFss, &g_rtZipTarFssOps); 2330 AssertReturn(pThis, VERR_WRONG_TYPE); 2331 2332 AssertReturn(hVfsObj != NIL_RTVFSOBJ, VERR_INVALID_HANDLE); 2333 PRTZIPTARBASEOBJ pThisObj = rtZipTarFsStreamBaseObjToPrivate(pThis->pRead, hVfsObj); 2334 AssertReturn(pThis, VERR_NOT_OWNER); 2335 2336 AssertReturn(pThis->pRead, VERR_ACCESS_DENIED); 2337 AssertReturn(pThis->fFlags & RTZIPTAR_C_UPDATE, VERR_ACCESS_DENIED); 2338 AssertReturn(!pThis->fWriting, VERR_WRONG_ORDER); 2339 2340 /* 2341 * Seek to the desired cut-off point and indicate that we've switched to writing. 2342 */ 2343 int rc = RTVfsFileSeek(pThis->hVfsFile, fAfter ? pThisObj->offNextHdr : pThisObj->offHdr, 2344 RTFILE_SEEK_BEGIN, NULL /*poffActual*/); 2345 if (RT_SUCCESS(rc)) 2346 pThis->fWriting = true; 2347 else 2348 pThis->rcFatal = rc; 2349 return rc; 2350 } 2351 -
trunk/src/VBox/Runtime/common/zip/xarvfs.cpp
r82968 r84192 2090 2090 PRTZIPXARFSSTREAM pThis; 2091 2091 RTVFSFSSTREAM hVfsFss; 2092 rc = RTVfsNewFsStream(&rtZipXarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, true /*fReadOnly*/,2092 rc = RTVfsNewFsStream(&rtZipXarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_READ, 2093 2093 &hVfsFss, (void **)&pThis); 2094 2094 if (RT_SUCCESS(rc))
Note:
See TracChangeset
for help on using the changeset viewer.