[34002] | 1 | /* $Id: tarvfswriter.cpp 103005 2024-01-23 23:55:58Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[67116] | 3 | * IPRT - TAR Virtual Filesystem, Writer.
|
---|
[34002] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2010-2023 Oracle and/or its affiliates.
|
---|
[34002] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
[34002] | 11 | *
|
---|
[96407] | 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
[34002] | 25 | * The contents of this file may alternatively be used under the terms
|
---|
| 26 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 27 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
| 28 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
[34002] | 29 | * CDDL are applicable instead of those of the GPL.
|
---|
| 30 | *
|
---|
| 31 | * You may elect to license modified versions of this file under the
|
---|
| 32 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
[96407] | 33 | *
|
---|
| 34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[34002] | 35 | */
|
---|
| 36 |
|
---|
| 37 |
|
---|
[57368] | 38 | /*********************************************************************************************************************************
|
---|
| 39 | * Header Files *
|
---|
| 40 | *********************************************************************************************************************************/
|
---|
[34002] | 41 | #include "internal/iprt.h"
|
---|
| 42 | #include <iprt/zip.h>
|
---|
| 43 |
|
---|
[103005] | 44 | #include <iprt/asm-mem.h>
|
---|
[34002] | 45 | #include <iprt/assert.h>
|
---|
| 46 | #include <iprt/err.h>
|
---|
[67123] | 47 | #include <iprt/file.h>
|
---|
[67116] | 48 | #include <iprt/mem.h>
|
---|
| 49 | #include <iprt/path.h>
|
---|
[34002] | 50 | #include <iprt/string.h>
|
---|
| 51 | #include <iprt/vfs.h>
|
---|
| 52 | #include <iprt/vfslowlevel.h>
|
---|
[67123] | 53 | #include <iprt/zero.h>
|
---|
[34002] | 54 |
|
---|
[84192] | 55 | #include "tarvfsreader.h"
|
---|
[98457] | 56 | #include "cpiovfsreader.h"
|
---|
[34002] | 57 |
|
---|
[84192] | 58 |
|
---|
[57358] | 59 | /*********************************************************************************************************************************
|
---|
[67134] | 60 | * Defined Constants And Macros *
|
---|
| 61 | *********************************************************************************************************************************/
|
---|
| 62 | /** The TAR block size we're using in this implementation.
|
---|
| 63 | * @remarks Should technically be user configurable, but we don't currently need that. */
|
---|
| 64 | #define RTZIPTAR_BLOCKSIZE sizeof(RTZIPTARHDR)
|
---|
| 65 |
|
---|
| 66 | /** Minimum file size we consider for sparse files. */
|
---|
| 67 | #define RTZIPTAR_MIN_SPARSE _64K
|
---|
| 68 |
|
---|
| 69 |
|
---|
| 70 | /*********************************************************************************************************************************
|
---|
[57358] | 71 | * Structures and Typedefs *
|
---|
| 72 | *********************************************************************************************************************************/
|
---|
[34002] | 73 | /**
|
---|
[67134] | 74 | * A data span descriptor in a sparse file.
|
---|
| 75 | */
|
---|
| 76 | typedef struct RTZIPTARSPARSESPAN
|
---|
| 77 | {
|
---|
| 78 | /** Byte offset into the file of the data. */
|
---|
| 79 | uint64_t off;
|
---|
| 80 | /** Number of bytes of data, rounded up to a multiple of blocksize. */
|
---|
| 81 | uint64_t cb;
|
---|
| 82 | } RTZIPTARSPARSESPAN;
|
---|
| 83 | /** Pointer to a data span. */
|
---|
| 84 | typedef RTZIPTARSPARSESPAN *PRTZIPTARSPARSESPAN;
|
---|
| 85 | /** Pointer to a const data span. */
|
---|
| 86 | typedef RTZIPTARSPARSESPAN const *PCRTZIPTARSPARSESPAN;
|
---|
| 87 |
|
---|
| 88 | /**
|
---|
| 89 | * Chunk of TAR sparse file data spans.
|
---|
| 90 | */
|
---|
| 91 | typedef struct RTZIPTARSPARSECHUNK
|
---|
| 92 | {
|
---|
| 93 | /** List entry. */
|
---|
| 94 | RTLISTNODE Entry;
|
---|
| 95 | /** Array of data spans. */
|
---|
| 96 | RTZIPTARSPARSESPAN aSpans[63];
|
---|
| 97 | } RTZIPTARSPARSECHUNK;
|
---|
| 98 | AssertCompile(sizeof(RTZIPTARSPARSECHUNK) <= 1024);
|
---|
| 99 | AssertCompile(sizeof(RTZIPTARSPARSECHUNK) >= 1008);
|
---|
| 100 | /** Pointer to a chunk of TAR data spans. */
|
---|
| 101 | typedef RTZIPTARSPARSECHUNK *PRTZIPTARSPARSECHUNK;
|
---|
| 102 | /** Pointer to a const chunk of TAR data spans. */
|
---|
| 103 | typedef RTZIPTARSPARSECHUNK const *PCRTZIPTARSPARSECHUNK;
|
---|
| 104 |
|
---|
| 105 | /**
|
---|
| 106 | * TAR sparse file info.
|
---|
| 107 | */
|
---|
| 108 | typedef struct RTZIPTARSPARSE
|
---|
| 109 | {
|
---|
| 110 | /** Number of data bytes (real size). */
|
---|
| 111 | uint64_t cbDataSpans;
|
---|
| 112 | /** Number of data spans. */
|
---|
| 113 | uint32_t cDataSpans;
|
---|
| 114 | /** The index of the next span in the tail chunk (to avoid modulus 63). */
|
---|
| 115 | uint32_t iNextSpan;
|
---|
| 116 | /** Head of the data span chunk list (PRTZIPTARSPARSECHUNK). */
|
---|
| 117 | RTLISTANCHOR ChunkHead;
|
---|
| 118 | } RTZIPTARSPARSE;
|
---|
| 119 | /** Pointer to TAR sparse file info. */
|
---|
| 120 | typedef RTZIPTARSPARSE *PRTZIPTARSPARSE;
|
---|
| 121 | /** Pointer to a const TAR sparse file info. */
|
---|
| 122 | typedef RTZIPTARSPARSE const *PCRTZIPTARSPARSE;
|
---|
| 123 |
|
---|
[67149] | 124 |
|
---|
| 125 | /** Pointer to a the private data of a TAR filesystem stream. */
|
---|
| 126 | typedef struct RTZIPTARFSSTREAMWRITER *PRTZIPTARFSSTREAMWRITER;
|
---|
| 127 |
|
---|
| 128 |
|
---|
[67134] | 129 | /**
|
---|
[67149] | 130 | * Instance data for a file or I/O stream returned by
|
---|
| 131 | * RTVFSFSSTREAMOPS::pfnPushFile.
|
---|
| 132 | */
|
---|
| 133 | typedef struct RTZIPTARFSSTREAMWRITERPUSH
|
---|
| 134 | {
|
---|
| 135 | /** Pointer to the parent FS stream writer instance.
|
---|
| 136 | * This is set to NULL should the push object live longer than the stream. */
|
---|
| 137 | PRTZIPTARFSSTREAMWRITER pParent;
|
---|
| 138 | /** The header offset, UINT64_MAX if non-seekable output. */
|
---|
| 139 | uint64_t offHdr;
|
---|
| 140 | /** The data offset, UINT64_MAX if non-seekable output. */
|
---|
| 141 | uint64_t offData;
|
---|
| 142 | /** The current I/O stream position (relative to offData). */
|
---|
| 143 | uint64_t offCurrent;
|
---|
[67166] | 144 | /** The expected size amount of file content, or max file size if open-ended. */
|
---|
[67149] | 145 | uint64_t cbExpected;
|
---|
| 146 | /** The current amount of file content written. */
|
---|
| 147 | uint64_t cbCurrent;
|
---|
| 148 | /** Object info copy for rtZipTarWriterPush_QueryInfo. */
|
---|
| 149 | RTFSOBJINFO ObjInfo;
|
---|
[67166] | 150 | /** Set if open-ended file size requiring a tar header update when done. */
|
---|
| 151 | bool fOpenEnded;
|
---|
[67149] | 152 | } RTZIPTARFSSTREAMWRITERPUSH;
|
---|
| 153 | /** Pointer to a push I/O instance. */
|
---|
| 154 | typedef RTZIPTARFSSTREAMWRITERPUSH *PRTZIPTARFSSTREAMWRITERPUSH;
|
---|
| 155 |
|
---|
| 156 |
|
---|
| 157 | /**
|
---|
[34002] | 158 | * Tar filesystem stream private data.
|
---|
| 159 | */
|
---|
[67116] | 160 | typedef struct RTZIPTARFSSTREAMWRITER
|
---|
[34002] | 161 | {
|
---|
[67116] | 162 | /** The output I/O stream. */
|
---|
[34179] | 163 | RTVFSIOSTREAM hVfsIos;
|
---|
[67134] | 164 | /** Non-nil if the output is a file. */
|
---|
| 165 | RTVFSFILE hVfsFile;
|
---|
[34002] | 166 |
|
---|
[67149] | 167 | /** The current push file. NULL if none. */
|
---|
| 168 | PRTZIPTARFSSTREAMWRITERPUSH pPush;
|
---|
| 169 |
|
---|
[67123] | 170 | /** The TAR format. */
|
---|
| 171 | RTZIPTARFORMAT enmFormat;
|
---|
[34002] | 172 | /** Set if we've encountered a fatal error. */
|
---|
[34179] | 173 | int rcFatal;
|
---|
[84192] | 174 | /** Flags, RTZIPTAR_C_XXX. */
|
---|
[67116] | 175 | uint32_t fFlags;
|
---|
[34179] | 176 |
|
---|
[67116] | 177 | /** Number of bytes written. */
|
---|
| 178 | uint64_t cbWritten;
|
---|
| 179 |
|
---|
[67253] | 180 | /** @name Attribute overrides.
|
---|
| 181 | * @{
|
---|
| 182 | */
|
---|
| 183 | RTUID uidOwner; /**< Owner, NIL_RTUID if no change. */
|
---|
| 184 | char *pszOwner; /**< Owner, NULL if no change. */
|
---|
| 185 | RTGID gidGroup; /**< Group, NIL_RTGID if no change. */
|
---|
| 186 | char *pszGroup; /**< Group, NULL if no change. */
|
---|
| 187 | char *pszPrefix; /**< Path prefix, NULL if no change. */
|
---|
| 188 | size_t cchPrefix; /**< The length of pszPrefix. */
|
---|
| 189 | PRTTIMESPEC pModTime; /**< Modification time, NULL of no change. */
|
---|
| 190 | RTTIMESPEC ModTime; /**< pModTime points to this. */
|
---|
| 191 | RTFMODE fFileModeAndMask; /**< File mode AND mask. */
|
---|
| 192 | RTFMODE fFileModeOrMask; /**< File mode OR mask. */
|
---|
| 193 | RTFMODE fDirModeAndMask; /**< Directory mode AND mask. */
|
---|
| 194 | RTFMODE fDirModeOrMask; /**< Directory mode OR mask. */
|
---|
| 195 | /** @} */
|
---|
| 196 |
|
---|
[84192] | 197 | /** When in update mode (RTZIPTAR_C_UPDATE) we have an reader FSS instance,
|
---|
| 198 | * though w/o the RTVFSFSSTREAM bits. (Allocated after this structure.) */
|
---|
[98457] | 199 | PRTZIPTARFSSTREAM pReadTar;
|
---|
| 200 | /** Same when a CPIO archive is used. */
|
---|
| 201 | /** @todo Possible to merge it with the tar reader maybe? */
|
---|
| 202 | PRTZIPCPIOFSSTREAM pReadCpio;
|
---|
[84192] | 203 | /** Set if we're in writing mode and pfnNext shall fail. */
|
---|
| 204 | bool fWriting;
|
---|
[67253] | 205 |
|
---|
[84192] | 206 |
|
---|
[67116] | 207 | /** Number of headers returned by rtZipTarFssWriter_ObjInfoToHdr. */
|
---|
| 208 | uint32_t cHdrs;
|
---|
[98457] | 209 | /** Size of a single header returned by rtZipTarFssWriter_ObjInfoToHdr. */
|
---|
| 210 | uint32_t cbHdr;
|
---|
| 211 | /** Format dependent header data. */
|
---|
| 212 | union
|
---|
| 213 | {
|
---|
| 214 | /** Byte view of the different headers. */
|
---|
| 215 | uint8_t abHdrs[512];
|
---|
| 216 | /** Header buffers returned by rtZipTarFssWriter_ObjInfoToHdrTar. */
|
---|
| 217 | RTZIPTARHDR aHdrsTar[3];
|
---|
| 218 | /** CPIO stuff. */
|
---|
| 219 | struct
|
---|
| 220 | {
|
---|
| 221 | /** CPIO header. */
|
---|
| 222 | CPIOHDR Hdr;
|
---|
| 223 | /** The filepath which comes directly after the header - embedded here
|
---|
| 224 | * to make the code more uniform with the tar code later on. */
|
---|
| 225 | char achFilePath[_1K];
|
---|
| 226 | /** Maximum padding if the file path is completely used. */
|
---|
| 227 | char abPad[3];
|
---|
| 228 | } Cpio;
|
---|
| 229 | };
|
---|
| 230 | /** The fallback I/O buffer if memory allocation fails. */
|
---|
| 231 | uint8_t abIoBuf[512];
|
---|
[67116] | 232 | } RTZIPTARFSSTREAMWRITER;
|
---|
[34002] | 233 |
|
---|
| 234 |
|
---|
[67134] | 235 | /*********************************************************************************************************************************
|
---|
| 236 | * Internal Functions *
|
---|
| 237 | *********************************************************************************************************************************/
|
---|
[67166] | 238 | static DECLCALLBACK(int) rtZipTarWriterPush_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual);
|
---|
[67149] | 239 | static int rtZipTarFssWriter_CompleteCurrentPushFile(PRTZIPTARFSSTREAMWRITER pThis);
|
---|
[67134] | 240 | static int rtZipTarFssWriter_AddFile(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, RTVFSIOSTREAM hVfsIos,
|
---|
| 241 | PCRTFSOBJINFO pObjInfo, const char *pszOwnerNm, const char *pszGroupNm);
|
---|
| 242 |
|
---|
| 243 |
|
---|
[34029] | 244 | /**
|
---|
[67116] | 245 | * Calculates the header checksum and stores it in the chksum field.
|
---|
[34045] | 246 | *
|
---|
| 247 | * @returns IPRT status code.
|
---|
[67116] | 248 | * @param pHdr The header.
|
---|
[34045] | 249 | */
|
---|
[67116] | 250 | static int rtZipTarFssWriter_ChecksumHdr(PRTZIPTARHDR pHdr)
|
---|
[34045] | 251 | {
|
---|
[67116] | 252 | int32_t iUnsignedChksum;
|
---|
| 253 | rtZipTarCalcChkSum(pHdr, &iUnsignedChksum, NULL);
|
---|
[34049] | 254 |
|
---|
[67116] | 255 | int rc = RTStrFormatU32(pHdr->Common.chksum, sizeof(pHdr->Common.chksum), iUnsignedChksum,
|
---|
[67134] | 256 | 8 /*uBase*/, -1 /*cchWidth*/, sizeof(pHdr->Common.chksum) - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67116] | 257 | AssertRCReturn(rc, VERR_TAR_NUM_VALUE_TOO_LARGE);
|
---|
[34049] | 258 | return VINF_SUCCESS;
|
---|
[34045] | 259 | }
|
---|
| 260 |
|
---|
| 261 |
|
---|
[67123] | 262 |
|
---|
[34045] | 263 | /**
|
---|
[67123] | 264 | * Formats a 12 character wide file offset or size field.
|
---|
| 265 | *
|
---|
| 266 | * This is mainly used for RTZIPTARHDR::Common.size, but also for formatting the
|
---|
| 267 | * sparse map.
|
---|
| 268 | *
|
---|
| 269 | * @returns IPRT status code.
|
---|
| 270 | * @param pach12Field The 12 character wide destination field.
|
---|
| 271 | * @param off The offset to set.
|
---|
| 272 | */
|
---|
| 273 | static int rtZipTarFssWriter_FormatOffset(char pach12Field[12], uint64_t off)
|
---|
| 274 | {
|
---|
| 275 | /*
|
---|
| 276 | * Is the size small enough for the standard octal string encoding?
|
---|
| 277 | *
|
---|
| 278 | * Note! We could actually use the terminator character as well if we liked,
|
---|
| 279 | * but let not do that as it's easier to test this way.
|
---|
| 280 | */
|
---|
| 281 | if (off < _4G * 2U)
|
---|
| 282 | {
|
---|
[67134] | 283 | int rc = RTStrFormatU64(pach12Field, 12, off, 8 /*uBase*/, -1 /*cchWidth*/, 12 - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67123] | 284 | AssertRCReturn(rc, rc);
|
---|
| 285 | }
|
---|
| 286 | /*
|
---|
| 287 | * No, use the base 256 extension. Set the highest bit of the left most
|
---|
| 288 | * character. We don't deal with negatives here, cause the size have to
|
---|
| 289 | * be greater than zero.
|
---|
| 290 | *
|
---|
| 291 | * Note! The base-256 extension are never used by gtar or libarchive
|
---|
| 292 | * with the "ustar \0" format version, only the later
|
---|
| 293 | * "ustar\000" version. However, this shouldn't cause much
|
---|
| 294 | * trouble as they are not picky about what they read.
|
---|
| 295 | */
|
---|
[67134] | 296 | /** @todo above note is wrong: GNU tar only uses base-256 with the GNU tar
|
---|
| 297 | * format, i.e. "ustar \0", see create.c line 303 in v1.29. */
|
---|
[67123] | 298 | else
|
---|
| 299 | {
|
---|
| 300 | size_t cchField = 12 - 1;
|
---|
| 301 | unsigned char *puchField = (unsigned char *)pach12Field;
|
---|
| 302 | puchField[0] = 0x80;
|
---|
| 303 | do
|
---|
| 304 | {
|
---|
| 305 | puchField[cchField--] = off & 0xff;
|
---|
| 306 | off >>= 8;
|
---|
| 307 | } while (cchField);
|
---|
| 308 | }
|
---|
| 309 |
|
---|
| 310 | return VINF_SUCCESS;
|
---|
| 311 | }
|
---|
| 312 |
|
---|
| 313 |
|
---|
| 314 | /**
|
---|
[98457] | 315 | * Returns a flag whether the writer is writing a tar archive, false if CPIO.
|
---|
| 316 | *
|
---|
| 317 | * @returns Flag whether the writer is in tar mode, true for tar and false for CPIO.
|
---|
| 318 | * @param pThis The TAR writer instance.
|
---|
| 319 | */
|
---|
| 320 | DECLINLINE(bool) rtZipTarFssWrite_IsTar(PRTZIPTARFSSTREAMWRITER pThis)
|
---|
| 321 | {
|
---|
| 322 | return pThis->enmFormat != RTZIPTARFORMAT_CPIO_ASCII_NEW;
|
---|
| 323 | }
|
---|
| 324 |
|
---|
| 325 |
|
---|
| 326 | /**
|
---|
| 327 | * Returns the block size of the given archive format.
|
---|
| 328 | *
|
---|
| 329 | * @returns Block size in bytes.
|
---|
| 330 | * @param pThis The TAR writer instance.
|
---|
| 331 | */
|
---|
| 332 | DECLINLINE(size_t) rtZipTarFssWrite_GetBlockSize(PRTZIPTARFSSTREAMWRITER pThis)
|
---|
| 333 | {
|
---|
| 334 | if (!rtZipTarFssWrite_IsTar(pThis))
|
---|
| 335 | return sizeof(uint32_t);
|
---|
| 336 |
|
---|
| 337 | return RTZIPTAR_BLOCKSIZE;
|
---|
| 338 | }
|
---|
| 339 |
|
---|
| 340 |
|
---|
| 341 | /**
|
---|
[67116] | 342 | * Creates one or more tar headers for the object.
|
---|
[34049] | 343 | *
|
---|
[98457] | 344 | * Returns RTZIPTARFSSTREAMWRITER::aHdrsTar and RTZIPTARFSSTREAMWRITER::cHdrs.
|
---|
[34049] | 345 | *
|
---|
[67116] | 346 | * @returns IPRT status code.
|
---|
| 347 | * @param pThis The TAR writer instance.
|
---|
| 348 | * @param pszPath The path to the file.
|
---|
| 349 | * @param hVfsIos The I/O stream of the file.
|
---|
| 350 | * @param fFlags The RTVFSFSSTREAMOPS::pfnAdd flags.
|
---|
| 351 | * @param pObjInfo The object information.
|
---|
| 352 | * @param pszOwnerNm The owner name.
|
---|
| 353 | * @param pszGroupNm The group name.
|
---|
| 354 | * @param chType The tar record type, UINT8_MAX for default.
|
---|
[34049] | 355 | */
|
---|
[98457] | 356 | static int rtZipTarFssWriter_ObjInfoToHdrTar(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, PCRTFSOBJINFO pObjInfo,
|
---|
| 357 | const char *pszOwnerNm, const char *pszGroupNm, uint8_t chType)
|
---|
[34049] | 358 | {
|
---|
[67116] | 359 | pThis->cHdrs = 0;
|
---|
[98457] | 360 | RT_ZERO(pThis->aHdrsTar[0]);
|
---|
[34049] | 361 |
|
---|
| 362 | /*
|
---|
[67116] | 363 | * The path name first. Make sure to flip DOS slashes.
|
---|
[34049] | 364 | */
|
---|
[67116] | 365 | size_t cchPath = strlen(pszPath);
|
---|
[98457] | 366 | if (cchPath < sizeof(pThis->aHdrsTar[0].Common.name))
|
---|
[34049] | 367 | {
|
---|
[98457] | 368 | memcpy(pThis->aHdrsTar[0].Common.name, pszPath, cchPath + 1);
|
---|
[67253] | 369 | #if RTPATH_STYLE != RTPATH_STR_F_STYLE_UNIX
|
---|
[98457] | 370 | char *pszDosSlash = strchr(pThis->aHdrsTar[0].Common.name, '\\');
|
---|
[67116] | 371 | while (pszDosSlash)
|
---|
| 372 | {
|
---|
| 373 | *pszDosSlash = '/';
|
---|
| 374 | pszDosSlash = strchr(pszDosSlash + 1, '\\');
|
---|
| 375 | }
|
---|
| 376 | #endif
|
---|
| 377 | }
|
---|
| 378 | else
|
---|
| 379 | {
|
---|
| 380 | /** @todo implement gnu and pax long name extensions. */
|
---|
| 381 | return VERR_TAR_NAME_TOO_LONG;
|
---|
| 382 | }
|
---|
[34049] | 383 |
|
---|
| 384 | /*
|
---|
[67116] | 385 | * File mode. ASSUME that the unix part of the IPRT mode mask is
|
---|
| 386 | * compatible with the TAR/Unix world.
|
---|
[34049] | 387 | */
|
---|
[67253] | 388 | uint32_t uValue = pObjInfo->Attr.fMode & RTFS_UNIX_MASK;
|
---|
| 389 | if (RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
|
---|
| 390 | uValue = (uValue & pThis->fDirModeAndMask) | pThis->fDirModeOrMask;
|
---|
| 391 | else
|
---|
| 392 | uValue = (uValue & pThis->fFileModeAndMask) | pThis->fFileModeOrMask;
|
---|
[98457] | 393 | int rc = RTStrFormatU32(pThis->aHdrsTar[0].Common.mode, sizeof(pThis->aHdrsTar[0].Common.mode), uValue, 8 /*uBase*/,
|
---|
| 394 | -1 /*cchWidth*/, sizeof(pThis->aHdrsTar[0].Common.mode) - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67116] | 395 | AssertRCReturn(rc, VERR_TAR_NUM_VALUE_TOO_LARGE);
|
---|
[34049] | 396 |
|
---|
| 397 | /*
|
---|
[67116] | 398 | * uid & gid. Just guard against NIL values as they won't fit.
|
---|
[34049] | 399 | */
|
---|
[67253] | 400 | uValue = pThis->uidOwner != NIL_RTUID ? pThis->uidOwner
|
---|
| 401 | : pObjInfo->Attr.u.Unix.uid != NIL_RTUID ? pObjInfo->Attr.u.Unix.uid : 0;
|
---|
[98457] | 402 | rc = RTStrFormatU32(pThis->aHdrsTar[0].Common.uid, sizeof(pThis->aHdrsTar[0].Common.uid), uValue,
|
---|
| 403 | 8 /*uBase*/, -1 /*cchWidth*/, sizeof(pThis->aHdrsTar[0].Common.uid) - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67116] | 404 | AssertRCReturn(rc, VERR_TAR_NUM_VALUE_TOO_LARGE);
|
---|
[34049] | 405 |
|
---|
[67253] | 406 | uValue = pThis->gidGroup != NIL_RTGID ? pThis->gidGroup
|
---|
| 407 | : pObjInfo->Attr.u.Unix.gid != NIL_RTGID ? pObjInfo->Attr.u.Unix.gid : 0;
|
---|
[98457] | 408 | rc = RTStrFormatU32(pThis->aHdrsTar[0].Common.gid, sizeof(pThis->aHdrsTar[0].Common.gid), uValue,
|
---|
| 409 | 8 /*uBase*/, -1 /*cchWidth*/, sizeof(pThis->aHdrsTar[0].Common.gid) - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67116] | 410 | AssertRCReturn(rc, VERR_TAR_NUM_VALUE_TOO_LARGE);
|
---|
| 411 |
|
---|
[34049] | 412 | /*
|
---|
[67123] | 413 | * The file size.
|
---|
[34049] | 414 | */
|
---|
[98457] | 415 | rc = rtZipTarFssWriter_FormatOffset(pThis->aHdrsTar[0].Common.size, pObjInfo->cbObject);
|
---|
[67123] | 416 | AssertRCReturn(rc, rc);
|
---|
[34049] | 417 |
|
---|
[34060] | 418 | /*
|
---|
[67116] | 419 | * Modification time relative to unix epoc.
|
---|
[34060] | 420 | */
|
---|
[98457] | 421 | rc = RTStrFormatU64(pThis->aHdrsTar[0].Common.mtime, sizeof(pThis->aHdrsTar[0].Common.mtime),
|
---|
[67253] | 422 | RTTimeSpecGetSeconds(pThis->pModTime ? pThis->pModTime : &pObjInfo->ModificationTime),
|
---|
[98457] | 423 | 8 /*uBase*/, -1 /*cchWidth*/, sizeof(pThis->aHdrsTar[0].Common.mtime) - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67116] | 424 | AssertRCReturn(rc, rc);
|
---|
[34179] | 425 |
|
---|
[67116] | 426 | /* Skipping checksum for now */
|
---|
[34179] | 427 |
|
---|
[67116] | 428 | /*
|
---|
| 429 | * The type flag.
|
---|
| 430 | */
|
---|
| 431 | if (chType == UINT8_MAX)
|
---|
| 432 | switch (pObjInfo->Attr.fMode & RTFS_TYPE_MASK)
|
---|
| 433 | {
|
---|
| 434 | case RTFS_TYPE_FIFO: chType = RTZIPTAR_TF_FIFO; break;
|
---|
| 435 | case RTFS_TYPE_DEV_CHAR: chType = RTZIPTAR_TF_CHR; break;
|
---|
| 436 | case RTFS_TYPE_DIRECTORY: chType = RTZIPTAR_TF_DIR; break;
|
---|
| 437 | case RTFS_TYPE_DEV_BLOCK: chType = RTZIPTAR_TF_BLK; break;
|
---|
| 438 | case RTFS_TYPE_FILE: chType = RTZIPTAR_TF_NORMAL; break;
|
---|
| 439 | case RTFS_TYPE_SYMLINK: chType = RTZIPTAR_TF_SYMLINK; break;
|
---|
| 440 | case RTFS_TYPE_SOCKET: chType = RTZIPTAR_TF_FIFO; break;
|
---|
| 441 | case RTFS_TYPE_WHITEOUT: AssertFailedReturn(VERR_WRONG_TYPE);
|
---|
| 442 | }
|
---|
[98457] | 443 | pThis->aHdrsTar[0].Common.typeflag = chType;
|
---|
[34179] | 444 |
|
---|
[67116] | 445 | /* No link name, at least not for now. Caller might set it. */
|
---|
[34179] | 446 |
|
---|
[67116] | 447 | /*
|
---|
| 448 | * Set TAR record magic and version.
|
---|
| 449 | */
|
---|
[67134] | 450 | if (pThis->enmFormat == RTZIPTARFORMAT_GNU)
|
---|
[98457] | 451 | memcpy(pThis->aHdrsTar[0].Gnu.magic, RTZIPTAR_GNU_MAGIC, sizeof(pThis->aHdrsTar[0].Gnu.magic));
|
---|
[67134] | 452 | else if ( pThis->enmFormat == RTZIPTARFORMAT_USTAR
|
---|
| 453 | || pThis->enmFormat == RTZIPTARFORMAT_PAX)
|
---|
| 454 | {
|
---|
[98457] | 455 | memcpy(pThis->aHdrsTar[0].Common.magic, RTZIPTAR_USTAR_MAGIC, sizeof(pThis->aHdrsTar[0].Common.magic));
|
---|
| 456 | memcpy(pThis->aHdrsTar[0].Common.version, RTZIPTAR_USTAR_VERSION, sizeof(pThis->aHdrsTar[0].Common.version));
|
---|
[67134] | 457 | }
|
---|
| 458 | else
|
---|
| 459 | AssertFailedReturn(VERR_INTERNAL_ERROR_4);
|
---|
[34179] | 460 |
|
---|
[67116] | 461 | /*
|
---|
| 462 | * Owner and group names. Silently truncate them for now.
|
---|
| 463 | */
|
---|
[98457] | 464 | RTStrCopy(pThis->aHdrsTar[0].Common.uname, sizeof(pThis->aHdrsTar[0].Common.uname), pThis->pszOwner ? pThis->pszOwner : pszOwnerNm);
|
---|
| 465 | RTStrCopy(pThis->aHdrsTar[0].Common.gname, sizeof(pThis->aHdrsTar[0].Common.uname), pThis->pszGroup ? pThis->pszGroup : pszGroupNm);
|
---|
[67116] | 466 |
|
---|
| 467 | /*
|
---|
| 468 | * Char/block device numbers.
|
---|
| 469 | */
|
---|
| 470 | if ( RTFS_IS_DEV_BLOCK(pObjInfo->Attr.fMode)
|
---|
| 471 | || RTFS_IS_DEV_CHAR(pObjInfo->Attr.fMode) )
|
---|
| 472 | {
|
---|
[98457] | 473 | rc = RTStrFormatU32(pThis->aHdrsTar[0].Common.devmajor, sizeof(pThis->aHdrsTar[0].Common.devmajor),
|
---|
[67116] | 474 | RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device),
|
---|
[98457] | 475 | 8 /*uBase*/, -1 /*cchWidth*/, sizeof(pThis->aHdrsTar[0].Common.devmajor) - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67116] | 476 | AssertRCReturn(rc, VERR_TAR_NUM_VALUE_TOO_LARGE);
|
---|
| 477 |
|
---|
[98457] | 478 | rc = RTStrFormatU32(pThis->aHdrsTar[0].Common.devminor, sizeof(pThis->aHdrsTar[0].Common.devmajor),
|
---|
[67116] | 479 | RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device),
|
---|
[98457] | 480 | 8 /*uBase*/, -1 /*cchWidth*/, sizeof(pThis->aHdrsTar[0].Common.devmajor) - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67116] | 481 | AssertRCReturn(rc, VERR_TAR_NUM_VALUE_TOO_LARGE);
|
---|
[34179] | 482 | }
|
---|
| 483 |
|
---|
[67134] | 484 | #if 0 /** @todo why doesn't this work? */
|
---|
[67116] | 485 | /*
|
---|
[67134] | 486 | * Set GNU specific stuff.
|
---|
| 487 | */
|
---|
| 488 | if (pThis->enmFormat == RTZIPTARFORMAT_GNU)
|
---|
| 489 | {
|
---|
[98457] | 490 | rc = RTStrFormatU64(pThis->aHdrsTar[0].Gnu.ctime, sizeof(pThis->aHdrsTar[0].Gnu.ctime),
|
---|
[67134] | 491 | RTTimeSpecGetSeconds(&pObjInfo->ChangeTime),
|
---|
[98457] | 492 | 8 /*uBase*/, -1 /*cchWidth*/, sizeof(pThis->aHdrsTar[0].Gnu.ctime) - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67134] | 493 | AssertRCReturn(rc, rc);
|
---|
| 494 |
|
---|
[98457] | 495 | rc = RTStrFormatU64(pThis->aHdrsTar[0].Gnu.atime, sizeof(pThis->aHdrsTar[0].Gnu.atime),
|
---|
[67134] | 496 | RTTimeSpecGetSeconds(&pObjInfo->ChangeTime),
|
---|
[98457] | 497 | 8 /*uBase*/, -1 /*cchWidth*/, sizeof(pThis->aHdrsTar[0].Gnu.atime) - 1, RTSTR_F_ZEROPAD | RTSTR_F_PRECISION);
|
---|
[67134] | 498 | AssertRCReturn(rc, rc);
|
---|
| 499 | }
|
---|
| 500 | #endif
|
---|
| 501 |
|
---|
| 502 | /*
|
---|
[67116] | 503 | * Finally the checksum.
|
---|
| 504 | */
|
---|
[67134] | 505 | pThis->cHdrs = 1;
|
---|
[98457] | 506 | pThis->cbHdr = sizeof(pThis->aHdrsTar[0]);
|
---|
| 507 | return rtZipTarFssWriter_ChecksumHdr(&pThis->aHdrsTar[0]);
|
---|
[34179] | 508 | }
|
---|
| 509 |
|
---|
| 510 |
|
---|
[98457] | 511 | /**
|
---|
| 512 | * Formats a given 32-bit value into a CPIO header field.
|
---|
| 513 | *
|
---|
| 514 | * @param pach8Field The field to format the value into.
|
---|
| 515 | * @param u32 The value to format.
|
---|
| 516 | */
|
---|
| 517 | static void rtZipTarFssWriter_CpioFmtU32(char pach8Field[8], uint32_t u32)
|
---|
| 518 | {
|
---|
| 519 | static const char s_achHex[] = "0123456789abcdef";
|
---|
| 520 | size_t cchField = 7;
|
---|
| 521 | unsigned char *puchField = (unsigned char *)pach8Field;
|
---|
| 522 | do
|
---|
| 523 | {
|
---|
| 524 | puchField[cchField--] = s_achHex[u32 & 0xf];
|
---|
| 525 | u32 >>= 4;
|
---|
| 526 | } while (cchField);
|
---|
[67149] | 527 |
|
---|
[98457] | 528 | /* Last one. */
|
---|
| 529 | puchField[0] = s_achHex[u32 & 0xf];
|
---|
| 530 | }
|
---|
[67149] | 531 |
|
---|
[98457] | 532 |
|
---|
[34179] | 533 | /**
|
---|
[98457] | 534 | * Creates one or more CPIO headers for the object.
|
---|
| 535 | *
|
---|
| 536 | * Returns RTZIPTARFSSTREAMWRITER::Cpio::Hdr and RTZIPTARFSSTREAMWRITER::cHdrs.
|
---|
| 537 | *
|
---|
| 538 | * @returns IPRT status code.
|
---|
| 539 | * @param pThis The TAR writer instance.
|
---|
| 540 | * @param pszPath The path to the file.
|
---|
| 541 | * @param hVfsIos The I/O stream of the file.
|
---|
| 542 | * @param fFlags The RTVFSFSSTREAMOPS::pfnAdd flags.
|
---|
| 543 | * @param pObjInfo The object information.
|
---|
| 544 | * @param pszOwnerNm The owner name.
|
---|
| 545 | * @param pszGroupNm The group name.
|
---|
| 546 | */
|
---|
| 547 | static int rtZipTarFssWriter_ObjInfoToHdrCpio(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, PCRTFSOBJINFO pObjInfo,
|
---|
| 548 | const char *pszOwnerNm, const char *pszGroupNm)
|
---|
| 549 | {
|
---|
| 550 | RT_NOREF(pszOwnerNm, pszGroupNm);
|
---|
| 551 | AssertReturn(!rtZipTarFssWrite_IsTar(pThis), VERR_INTERNAL_ERROR_3);
|
---|
| 552 |
|
---|
| 553 | pThis->cHdrs = 0;
|
---|
| 554 | RT_ZERO(pThis->Cpio.Hdr);
|
---|
| 555 | RT_ZERO(pThis->Cpio.achFilePath);
|
---|
| 556 |
|
---|
| 557 | /*
|
---|
| 558 | * The path name first. Make sure to flip DOS slashes.
|
---|
| 559 | */
|
---|
| 560 | size_t cchPath = strlen(pszPath) + 1;
|
---|
| 561 | if (cchPath < sizeof(pThis->Cpio.achFilePath))
|
---|
| 562 | {
|
---|
| 563 | memcpy(&pThis->Cpio.achFilePath[0], pszPath, cchPath);
|
---|
| 564 | #if RTPATH_STYLE != RTPATH_STR_F_STYLE_UNIX
|
---|
| 565 | char *pszDosSlash = strchr(&pThis->Cpio.achFilePath[0], '\\');
|
---|
| 566 | while (pszDosSlash)
|
---|
| 567 | {
|
---|
| 568 | *pszDosSlash = '/';
|
---|
| 569 | pszDosSlash = strchr(pszDosSlash + 1, '\\');
|
---|
| 570 | }
|
---|
| 571 | #endif
|
---|
| 572 | }
|
---|
| 573 | else
|
---|
| 574 | return VERR_TAR_NAME_TOO_LONG;
|
---|
| 575 |
|
---|
| 576 | if (pObjInfo->cbObject != (uint32_t)pObjInfo->cbObject)
|
---|
| 577 | return VERR_FILE_TOO_BIG;
|
---|
| 578 |
|
---|
| 579 | /*
|
---|
| 580 | * Set CPIO record magic and version.
|
---|
| 581 | */
|
---|
| 582 | if (pThis->enmFormat == RTZIPTARFORMAT_CPIO_ASCII_NEW)
|
---|
| 583 | memcpy(pThis->Cpio.Hdr.AsciiNew.achMagic, CPIO_HDR_NEW_MAGIC, sizeof(pThis->Cpio.Hdr.AsciiNew.achMagic));
|
---|
| 584 | else
|
---|
| 585 | AssertFailedReturn(VERR_INTERNAL_ERROR_4);
|
---|
| 586 |
|
---|
| 587 | /*
|
---|
| 588 | * File mode. ASSUME that the unix part of the IPRT mode mask is
|
---|
| 589 | * compatible with the TAR/Unix world.
|
---|
| 590 | */
|
---|
| 591 | uint32_t uValue = pObjInfo->Attr.fMode & RTFS_UNIX_MASK;
|
---|
| 592 | if (pObjInfo->Attr.fMode) /* Don't want to modify the EOS record here. */
|
---|
| 593 | {
|
---|
| 594 | if (RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
|
---|
| 595 | uValue = (uValue & pThis->fDirModeAndMask) | pThis->fDirModeOrMask;
|
---|
| 596 | else
|
---|
| 597 | uValue = (uValue & pThis->fFileModeAndMask) | pThis->fFileModeOrMask;
|
---|
| 598 | }
|
---|
| 599 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achMode, uValue);
|
---|
| 600 |
|
---|
| 601 | /*
|
---|
| 602 | * Inode id.
|
---|
| 603 | */
|
---|
| 604 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achInode, pObjInfo->Attr.u.Unix.INodeId);
|
---|
| 605 |
|
---|
| 606 | /*
|
---|
| 607 | * Number of hardlinks.
|
---|
| 608 | */
|
---|
| 609 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achNLinks, pObjInfo->Attr.u.Unix.cHardlinks ? pObjInfo->Attr.u.Unix.cHardlinks : 1);
|
---|
| 610 |
|
---|
| 611 | /*
|
---|
| 612 | * uid & gid. Just guard against NIL values as they won't fit.
|
---|
| 613 | */
|
---|
| 614 | uValue = pThis->uidOwner != NIL_RTUID ? pThis->uidOwner
|
---|
| 615 | : pObjInfo->Attr.u.Unix.uid != NIL_RTUID ? pObjInfo->Attr.u.Unix.uid : 0;
|
---|
| 616 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achUid, uValue);
|
---|
| 617 |
|
---|
| 618 | uValue = pThis->gidGroup != NIL_RTGID ? pThis->gidGroup
|
---|
| 619 | : pObjInfo->Attr.u.Unix.gid != NIL_RTGID ? pObjInfo->Attr.u.Unix.gid : 0;
|
---|
| 620 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achGid, uValue);
|
---|
| 621 |
|
---|
| 622 | /*
|
---|
| 623 | * The file size.
|
---|
| 624 | */
|
---|
| 625 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achFileSize, (uint32_t)pObjInfo->cbObject);
|
---|
| 626 |
|
---|
| 627 | /*
|
---|
| 628 | * Modification time relative to unix epoc.
|
---|
| 629 | */
|
---|
| 630 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achMTime,
|
---|
| 631 | RTTimeSpecGetSeconds(pThis->pModTime ? pThis->pModTime : &pObjInfo->ModificationTime));
|
---|
| 632 |
|
---|
| 633 | /*
|
---|
| 634 | * Char/block device numbers.
|
---|
| 635 | */
|
---|
| 636 | if ( RTFS_IS_DEV_BLOCK(pObjInfo->Attr.fMode)
|
---|
| 637 | || RTFS_IS_DEV_CHAR(pObjInfo->Attr.fMode) )
|
---|
| 638 | {
|
---|
| 639 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achDevMajor, RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device));
|
---|
| 640 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achDevMajor, RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device));
|
---|
| 641 | }
|
---|
| 642 |
|
---|
| 643 | /*
|
---|
| 644 | * File path size including the terminator.
|
---|
| 645 | */
|
---|
[98458] | 646 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achNameSize, (uint32_t)cchPath);
|
---|
[98457] | 647 |
|
---|
| 648 | pThis->cHdrs = 1;
|
---|
| 649 | pThis->cbHdr = RT_ALIGN_32(sizeof(pThis->Cpio.Hdr) + cchPath, 4);
|
---|
| 650 | return VINF_SUCCESS;
|
---|
| 651 | }
|
---|
| 652 |
|
---|
| 653 |
|
---|
| 654 | /**
|
---|
| 655 | * Creates one or more headers for the object.
|
---|
| 656 | *
|
---|
| 657 | * Returns RTZIPTARFSSTREAMWRITER::cbHdrs and RTZIPTARFSSTREAMWRITER::cHdrs.
|
---|
| 658 | *
|
---|
| 659 | * @returns IPRT status code.
|
---|
| 660 | * @param pThis The TAR writer instance.
|
---|
| 661 | * @param pszPath The path to the file.
|
---|
| 662 | * @param hVfsIos The I/O stream of the file.
|
---|
| 663 | * @param fFlags The RTVFSFSSTREAMOPS::pfnAdd flags.
|
---|
| 664 | * @param pObjInfo The object information.
|
---|
| 665 | * @param pszOwnerNm The owner name.
|
---|
| 666 | * @param pszGroupNm The group name.
|
---|
| 667 | * @param chType The tar record type, UINT8_MAX for default.
|
---|
| 668 | */
|
---|
| 669 | static int rtZipTarFssWriter_ObjInfoToHdr(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, PCRTFSOBJINFO pObjInfo,
|
---|
| 670 | const char *pszOwnerNm, const char *pszGroupNm, uint8_t chType)
|
---|
| 671 | {
|
---|
| 672 | if (!rtZipTarFssWrite_IsTar(pThis))
|
---|
| 673 | return rtZipTarFssWriter_ObjInfoToHdrCpio(pThis, pszPath, pObjInfo, pszOwnerNm, pszGroupNm);
|
---|
| 674 |
|
---|
| 675 | return rtZipTarFssWriter_ObjInfoToHdrTar(pThis, pszPath, pObjInfo, pszOwnerNm, pszGroupNm, chType);
|
---|
| 676 | }
|
---|
| 677 |
|
---|
| 678 |
|
---|
| 679 |
|
---|
| 680 |
|
---|
| 681 | /**
|
---|
[67149] | 682 | * @interface_method_impl{RTVFSOBJOPS,pfnClose}
|
---|
| 683 | */
|
---|
| 684 | static DECLCALLBACK(int) rtZipTarWriterPush_Close(void *pvThis)
|
---|
| 685 | {
|
---|
| 686 | PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis;
|
---|
| 687 | PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent;
|
---|
| 688 | if (pParent)
|
---|
| 689 | {
|
---|
| 690 | if (pParent->pPush == pPush)
|
---|
| 691 | rtZipTarFssWriter_CompleteCurrentPushFile(pParent);
|
---|
| 692 | else
|
---|
| 693 | AssertFailedStmt(pPush->pParent = NULL);
|
---|
| 694 | }
|
---|
| 695 | return VINF_SUCCESS;
|
---|
| 696 | }
|
---|
| 697 |
|
---|
| 698 |
|
---|
| 699 | /**
|
---|
| 700 | * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
|
---|
| 701 | */
|
---|
| 702 | static DECLCALLBACK(int) rtZipTarWriterPush_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
|
---|
| 703 | {
|
---|
| 704 | PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis;
|
---|
| 705 |
|
---|
| 706 | /* Basic info (w/ additional unix attribs). */
|
---|
| 707 | *pObjInfo = pPush->ObjInfo;
|
---|
| 708 | pObjInfo->cbObject = pPush->cbCurrent;
|
---|
[98457] | 709 | pObjInfo->cbAllocated = RT_ALIGN_64(pPush->cbCurrent, rtZipTarFssWrite_GetBlockSize(pPush->pParent));
|
---|
[67149] | 710 |
|
---|
| 711 | /* Additional info. */
|
---|
| 712 | switch (enmAddAttr)
|
---|
| 713 | {
|
---|
| 714 | case RTFSOBJATTRADD_NOTHING:
|
---|
| 715 | case RTFSOBJATTRADD_UNIX:
|
---|
| 716 | Assert(pObjInfo->Attr.enmAdditional == RTFSOBJATTRADD_UNIX);
|
---|
| 717 | break;
|
---|
| 718 |
|
---|
| 719 | case RTFSOBJATTRADD_UNIX_OWNER:
|
---|
| 720 | pObjInfo->Attr.u.UnixOwner.uid = pPush->ObjInfo.Attr.u.Unix.uid;
|
---|
[98457] | 721 | if ( pPush->pParent
|
---|
| 722 | && rtZipTarFssWrite_IsTar(pPush->pParent))
|
---|
| 723 | strcpy(pObjInfo->Attr.u.UnixOwner.szName, pPush->pParent->aHdrsTar[0].Common.uname);
|
---|
[67149] | 724 | else
|
---|
| 725 | pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
|
---|
| 726 | pObjInfo->Attr.enmAdditional = enmAddAttr;
|
---|
| 727 | break;
|
---|
| 728 |
|
---|
| 729 | case RTFSOBJATTRADD_UNIX_GROUP:
|
---|
| 730 | pObjInfo->Attr.u.UnixGroup.gid = pPush->ObjInfo.Attr.u.Unix.gid;
|
---|
[98457] | 731 | if ( pPush->pParent
|
---|
| 732 | && rtZipTarFssWrite_IsTar(pPush->pParent))
|
---|
| 733 | strcpy(pObjInfo->Attr.u.UnixGroup.szName, pPush->pParent->aHdrsTar[0].Common.uname);
|
---|
[67149] | 734 | else
|
---|
| 735 | pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
|
---|
| 736 | pObjInfo->Attr.enmAdditional = enmAddAttr;
|
---|
| 737 | break;
|
---|
| 738 |
|
---|
| 739 | case RTFSOBJATTRADD_EASIZE:
|
---|
| 740 | pObjInfo->Attr.u.EASize.cb = 0;
|
---|
| 741 | pObjInfo->Attr.enmAdditional = enmAddAttr;
|
---|
| 742 | break;
|
---|
| 743 |
|
---|
| 744 | default:
|
---|
| 745 | AssertFailed();
|
---|
| 746 | }
|
---|
| 747 |
|
---|
| 748 | return VINF_SUCCESS;
|
---|
| 749 | }
|
---|
| 750 |
|
---|
| 751 |
|
---|
| 752 | /**
|
---|
| 753 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
|
---|
| 754 | */
|
---|
[100908] | 755 | static DECLCALLBACK(int) rtZipTarWriterPush_Read(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
|
---|
[67149] | 756 | {
|
---|
| 757 | /* No read support, sorry. */
|
---|
| 758 | RT_NOREF(pvThis, off, pSgBuf, fBlocking, pcbRead);
|
---|
| 759 | AssertFailed();
|
---|
| 760 | return VERR_ACCESS_DENIED;
|
---|
| 761 | }
|
---|
| 762 |
|
---|
| 763 |
|
---|
| 764 | /**
|
---|
| 765 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
|
---|
| 766 | */
|
---|
[100908] | 767 | static DECLCALLBACK(int) rtZipTarWriterPush_Write(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
|
---|
[67149] | 768 | {
|
---|
| 769 | PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis;
|
---|
| 770 | PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent;
|
---|
| 771 | AssertPtrReturn(pParent, VERR_WRONG_ORDER);
|
---|
| 772 |
|
---|
| 773 | int rc = pParent->rcFatal;
|
---|
| 774 | AssertRCReturn(rc, rc);
|
---|
| 775 |
|
---|
| 776 | /*
|
---|
| 777 | * Single segment at a time.
|
---|
| 778 | */
|
---|
| 779 | Assert(pSgBuf->cSegs == 1);
|
---|
| 780 | size_t cbToWrite = pSgBuf->paSegs[0].cbSeg;
|
---|
| 781 | void const *pvToWrite = pSgBuf->paSegs[0].pvSeg;
|
---|
| 782 |
|
---|
| 783 | /*
|
---|
[67166] | 784 | * Hopefully we don't need to seek. But if we do, let the seek method do
|
---|
| 785 | * it as it's not entirely trivial.
|
---|
[67149] | 786 | */
|
---|
| 787 | if ( off < 0
|
---|
| 788 | || (uint64_t)off == pPush->offCurrent)
|
---|
[67166] | 789 | rc = VINF_SUCCESS;
|
---|
| 790 | else
|
---|
| 791 | rc = rtZipTarWriterPush_Seek(pvThis, off, RTFILE_SEEK_BEGIN, NULL);
|
---|
| 792 | if (RT_SUCCESS(rc))
|
---|
[67149] | 793 | {
|
---|
[67166] | 794 | Assert(pPush->offCurrent <= pPush->cbExpected);
|
---|
| 795 | Assert(pPush->offCurrent <= pPush->cbCurrent);
|
---|
[67149] | 796 | AssertMsgReturn(cbToWrite <= pPush->cbExpected - pPush->offCurrent,
|
---|
| 797 | ("offCurrent=%#RX64 + cbToWrite=%#zx = %#RX64; cbExpected=%RX64\n",
|
---|
| 798 | pPush->offCurrent, cbToWrite, pPush->offCurrent + cbToWrite, pPush->cbExpected),
|
---|
| 799 | VERR_DISK_FULL);
|
---|
[67166] | 800 | size_t cbWritten = 0;
|
---|
[67149] | 801 | rc = RTVfsIoStrmWrite(pParent->hVfsIos, pvToWrite, cbToWrite, fBlocking, &cbWritten);
|
---|
| 802 | if (RT_SUCCESS(rc))
|
---|
| 803 | {
|
---|
| 804 | pPush->offCurrent += cbWritten;
|
---|
| 805 | if (pPush->offCurrent > pPush->cbCurrent)
|
---|
| 806 | {
|
---|
| 807 | pParent->cbWritten = pPush->offCurrent - pPush->cbCurrent;
|
---|
| 808 | pPush->cbCurrent = pPush->offCurrent;
|
---|
| 809 | }
|
---|
[67166] | 810 | if (pcbWritten)
|
---|
| 811 | *pcbWritten = cbWritten;
|
---|
[100908] | 812 | RTSgBufAdvance(pSgBuf, cbWritten);
|
---|
[67149] | 813 | }
|
---|
| 814 | }
|
---|
| 815 |
|
---|
| 816 | /*
|
---|
| 817 | * Fatal errors get down here, non-fatal ones returns earlier.
|
---|
| 818 | */
|
---|
| 819 | if (RT_SUCCESS(rc))
|
---|
| 820 | return VINF_SUCCESS;
|
---|
| 821 | pParent->rcFatal = rc;
|
---|
| 822 | return rc;
|
---|
| 823 | }
|
---|
| 824 |
|
---|
| 825 |
|
---|
| 826 | /**
|
---|
| 827 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
|
---|
| 828 | */
|
---|
| 829 | static DECLCALLBACK(int) rtZipTarWriterPush_Flush(void *pvThis)
|
---|
| 830 | {
|
---|
| 831 | PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis;
|
---|
| 832 | PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent;
|
---|
| 833 | AssertPtrReturn(pParent, VERR_WRONG_ORDER);
|
---|
| 834 | int rc = pParent->rcFatal;
|
---|
| 835 | if (RT_SUCCESS(rc))
|
---|
| 836 | pParent->rcFatal = rc = RTVfsIoStrmFlush(pParent->hVfsIos);
|
---|
| 837 | return rc;
|
---|
| 838 | }
|
---|
| 839 |
|
---|
| 840 |
|
---|
| 841 | /**
|
---|
| 842 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
|
---|
| 843 | */
|
---|
| 844 | static DECLCALLBACK(int) rtZipTarWriterPush_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
|
---|
| 845 | uint32_t *pfRetEvents)
|
---|
| 846 | {
|
---|
| 847 | PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis;
|
---|
| 848 | PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent;
|
---|
| 849 | AssertPtrReturn(pParent, VERR_WRONG_ORDER);
|
---|
| 850 | return RTVfsIoStrmPoll(pParent->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
|
---|
| 851 | }
|
---|
| 852 |
|
---|
| 853 |
|
---|
| 854 | /**
|
---|
| 855 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
|
---|
| 856 | */
|
---|
| 857 | static DECLCALLBACK(int) rtZipTarWriterPush_Tell(void *pvThis, PRTFOFF poffActual)
|
---|
| 858 | {
|
---|
| 859 | PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis;
|
---|
| 860 | *poffActual = (RTFOFF)pPush->offCurrent;
|
---|
| 861 | return VINF_SUCCESS;
|
---|
| 862 | }
|
---|
| 863 |
|
---|
| 864 |
|
---|
| 865 | /**
|
---|
| 866 | * @interface_method_impl{RTVFSIOSTREAMOPS,pfnSkip}
|
---|
| 867 | */
|
---|
| 868 | static DECLCALLBACK(int) rtZipTarWriterPush_Skip(void *pvThis, RTFOFF cb)
|
---|
| 869 | {
|
---|
| 870 | RT_NOREF(pvThis, cb);
|
---|
| 871 | AssertFailed();
|
---|
| 872 | return VERR_ACCESS_DENIED;
|
---|
| 873 | }
|
---|
| 874 |
|
---|
| 875 |
|
---|
| 876 | /**
|
---|
| 877 | * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
|
---|
| 878 | */
|
---|
| 879 | static DECLCALLBACK(int) rtZipTarWriterPush_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
|
---|
| 880 | {
|
---|
| 881 | RT_NOREF(pvThis, fMode, fMask);
|
---|
| 882 | AssertFailed();
|
---|
| 883 | return VERR_ACCESS_DENIED;
|
---|
| 884 | }
|
---|
| 885 |
|
---|
| 886 |
|
---|
| 887 | /**
|
---|
| 888 | * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
|
---|
| 889 | */
|
---|
| 890 | static DECLCALLBACK(int) rtZipTarWriterPush_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
|
---|
| 891 | PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
|
---|
| 892 | {
|
---|
| 893 | RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
|
---|
| 894 | AssertFailed();
|
---|
| 895 | return VERR_ACCESS_DENIED;
|
---|
| 896 | }
|
---|
| 897 |
|
---|
| 898 |
|
---|
| 899 | /**
|
---|
| 900 | * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
|
---|
| 901 | */
|
---|
| 902 | static DECLCALLBACK(int) rtZipTarWriterPush_SetOwner(void *pvThis, RTUID uid, RTGID gid)
|
---|
| 903 | {
|
---|
| 904 | RT_NOREF(pvThis, uid, gid);
|
---|
| 905 | AssertFailed();
|
---|
| 906 | return VERR_ACCESS_DENIED;
|
---|
| 907 | }
|
---|
| 908 |
|
---|
| 909 |
|
---|
| 910 | /**
|
---|
| 911 | * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
|
---|
| 912 | */
|
---|
| 913 | static DECLCALLBACK(int) rtZipTarWriterPush_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
|
---|
| 914 | {
|
---|
| 915 | PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis;
|
---|
| 916 | PRTZIPTARFSSTREAMWRITER pParent = pPush->pParent;
|
---|
| 917 | AssertPtrReturn(pParent, VERR_WRONG_ORDER);
|
---|
| 918 |
|
---|
| 919 | int rc = pParent->rcFatal;
|
---|
| 920 | AssertRCReturn(rc, rc);
|
---|
[67166] | 921 | Assert(pPush->offCurrent <= pPush->cbCurrent);
|
---|
[67149] | 922 |
|
---|
| 923 | /*
|
---|
| 924 | * Calculate the new file offset.
|
---|
| 925 | */
|
---|
[67166] | 926 | RTFOFF offNewSigned;
|
---|
[67149] | 927 | switch (uMethod)
|
---|
| 928 | {
|
---|
| 929 | case RTFILE_SEEK_BEGIN:
|
---|
[67166] | 930 | offNewSigned = offSeek;
|
---|
[67149] | 931 | break;
|
---|
| 932 | case RTFILE_SEEK_CURRENT:
|
---|
[67166] | 933 | offNewSigned = pPush->offCurrent + offSeek;
|
---|
[67149] | 934 | break;
|
---|
| 935 | case RTFILE_SEEK_END:
|
---|
[67166] | 936 | offNewSigned = pPush->cbCurrent + offSeek;
|
---|
[67149] | 937 | break;
|
---|
| 938 | default:
|
---|
[67166] | 939 | AssertFailedReturn(VERR_INVALID_PARAMETER);
|
---|
[67149] | 940 | }
|
---|
| 941 |
|
---|
| 942 | /*
|
---|
| 943 | * Check the new file offset against expectations.
|
---|
| 944 | */
|
---|
[67166] | 945 | AssertMsgReturn(offNewSigned >= 0, ("offNewSigned=%RTfoff\n", offNewSigned), VERR_NEGATIVE_SEEK);
|
---|
| 946 |
|
---|
| 947 | uint64_t offNew = (uint64_t)offNewSigned;
|
---|
[67149] | 948 | AssertMsgReturn(offNew <= pPush->cbExpected, ("offNew=%#RX64 cbExpected=%#Rx64\n", offNew, pPush->cbExpected), VERR_SEEK);
|
---|
| 949 |
|
---|
| 950 | /*
|
---|
| 951 | * Any change at all? We can always hope...
|
---|
| 952 | */
|
---|
| 953 | if (offNew == pPush->offCurrent)
|
---|
| 954 | { }
|
---|
| 955 | /*
|
---|
| 956 | * Gap that needs zero filling?
|
---|
| 957 | */
|
---|
| 958 | else if (offNew > pPush->cbCurrent)
|
---|
| 959 | {
|
---|
| 960 | if (pPush->offCurrent != pPush->cbCurrent)
|
---|
| 961 | {
|
---|
| 962 | AssertReturn(pParent->hVfsFile != NIL_RTVFSFILE, VERR_NOT_A_FILE);
|
---|
| 963 | rc = RTVfsFileSeek(pParent->hVfsFile, pPush->offData + pPush->cbCurrent, RTFILE_SEEK_BEGIN, NULL);
|
---|
| 964 | if (RT_FAILURE(rc))
|
---|
| 965 | return pParent->rcFatal = rc;
|
---|
| 966 | pPush->offCurrent = pPush->cbCurrent;
|
---|
| 967 | }
|
---|
| 968 |
|
---|
| 969 | uint64_t cbToZero = offNew - pPush->cbCurrent;
|
---|
| 970 | rc = RTVfsIoStrmZeroFill(pParent->hVfsIos, cbToZero);
|
---|
| 971 | if (RT_FAILURE(rc))
|
---|
| 972 | return pParent->rcFatal = rc;
|
---|
| 973 | pParent->cbWritten += cbToZero;
|
---|
| 974 | pPush->cbCurrent = pPush->offCurrent = offNew;
|
---|
| 975 | }
|
---|
| 976 | /*
|
---|
[67166] | 977 | * Just change the file position to somewhere we've already written.
|
---|
[67149] | 978 | */
|
---|
| 979 | else
|
---|
| 980 | {
|
---|
| 981 | AssertReturn(pParent->hVfsFile != NIL_RTVFSFILE, VERR_NOT_A_FILE);
|
---|
| 982 | rc = RTVfsFileSeek(pParent->hVfsFile, pPush->offData + offNew, RTFILE_SEEK_BEGIN, NULL);
|
---|
| 983 | if (RT_FAILURE(rc))
|
---|
| 984 | return pParent->rcFatal = rc;
|
---|
| 985 | pPush->offCurrent = offNew;
|
---|
| 986 | }
|
---|
[67166] | 987 | Assert(pPush->offCurrent <= pPush->cbCurrent);
|
---|
[67149] | 988 |
|
---|
[67279] | 989 | if (poffActual)
|
---|
| 990 | *poffActual = pPush->offCurrent;
|
---|
[67149] | 991 | return VINF_SUCCESS;
|
---|
| 992 | }
|
---|
| 993 |
|
---|
| 994 |
|
---|
| 995 | /**
|
---|
| 996 | * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
|
---|
| 997 | */
|
---|
| 998 | static DECLCALLBACK(int) rtZipTarWriterPush_QuerySize(void *pvThis, uint64_t *pcbFile)
|
---|
| 999 | {
|
---|
| 1000 | PRTZIPTARFSSTREAMWRITERPUSH pPush = (PRTZIPTARFSSTREAMWRITERPUSH)pvThis;
|
---|
| 1001 | *pcbFile = pPush->cbCurrent;
|
---|
| 1002 | return VINF_SUCCESS;
|
---|
| 1003 | }
|
---|
| 1004 |
|
---|
| 1005 |
|
---|
| 1006 | /**
|
---|
| 1007 | * TAR writer push I/O stream operations.
|
---|
| 1008 | */
|
---|
| 1009 | DECL_HIDDEN_CONST(const RTVFSIOSTREAMOPS) g_rtZipTarWriterIoStrmOps =
|
---|
| 1010 | {
|
---|
| 1011 | { /* Obj */
|
---|
| 1012 | RTVFSOBJOPS_VERSION,
|
---|
| 1013 | RTVFSOBJTYPE_IO_STREAM,
|
---|
| 1014 | "TAR push I/O Stream",
|
---|
| 1015 | rtZipTarWriterPush_Close,
|
---|
| 1016 | rtZipTarWriterPush_QueryInfo,
|
---|
[94291] | 1017 | NULL,
|
---|
[67149] | 1018 | RTVFSOBJOPS_VERSION
|
---|
| 1019 | },
|
---|
| 1020 | RTVFSIOSTREAMOPS_VERSION,
|
---|
| 1021 | RTVFSIOSTREAMOPS_FEAT_NO_SG,
|
---|
| 1022 | rtZipTarWriterPush_Read,
|
---|
| 1023 | rtZipTarWriterPush_Write,
|
---|
| 1024 | rtZipTarWriterPush_Flush,
|
---|
| 1025 | rtZipTarWriterPush_PollOne,
|
---|
| 1026 | rtZipTarWriterPush_Tell,
|
---|
| 1027 | rtZipTarWriterPush_Skip,
|
---|
| 1028 | NULL /*ZeroFill*/,
|
---|
| 1029 | RTVFSIOSTREAMOPS_VERSION,
|
---|
| 1030 | };
|
---|
| 1031 |
|
---|
| 1032 |
|
---|
| 1033 | /**
|
---|
| 1034 | * TAR writer push file operations.
|
---|
| 1035 | */
|
---|
| 1036 | DECL_HIDDEN_CONST(const RTVFSFILEOPS) g_rtZipTarWriterFileOps =
|
---|
| 1037 | {
|
---|
| 1038 | { /* Stream */
|
---|
| 1039 | { /* Obj */
|
---|
| 1040 | RTVFSOBJOPS_VERSION,
|
---|
| 1041 | RTVFSOBJTYPE_FILE,
|
---|
| 1042 | "TAR push file",
|
---|
| 1043 | rtZipTarWriterPush_Close,
|
---|
| 1044 | rtZipTarWriterPush_QueryInfo,
|
---|
[94291] | 1045 | NULL,
|
---|
[67149] | 1046 | RTVFSOBJOPS_VERSION
|
---|
| 1047 | },
|
---|
| 1048 | RTVFSIOSTREAMOPS_VERSION,
|
---|
| 1049 | RTVFSIOSTREAMOPS_FEAT_NO_SG,
|
---|
| 1050 | rtZipTarWriterPush_Read,
|
---|
| 1051 | rtZipTarWriterPush_Write,
|
---|
| 1052 | rtZipTarWriterPush_Flush,
|
---|
| 1053 | rtZipTarWriterPush_PollOne,
|
---|
| 1054 | rtZipTarWriterPush_Tell,
|
---|
| 1055 | rtZipTarWriterPush_Skip,
|
---|
| 1056 | NULL /*ZeroFill*/,
|
---|
| 1057 | RTVFSIOSTREAMOPS_VERSION,
|
---|
| 1058 | },
|
---|
| 1059 | RTVFSFILEOPS_VERSION,
|
---|
| 1060 | 0,
|
---|
| 1061 | { /* ObjSet */
|
---|
| 1062 | RTVFSOBJSETOPS_VERSION,
|
---|
[73097] | 1063 | RT_UOFFSETOF(RTVFSFILEOPS, ObjSet) - RT_UOFFSETOF(RTVFSFILEOPS, Stream.Obj),
|
---|
[67149] | 1064 | rtZipTarWriterPush_SetMode,
|
---|
| 1065 | rtZipTarWriterPush_SetTimes,
|
---|
| 1066 | rtZipTarWriterPush_SetOwner,
|
---|
| 1067 | RTVFSOBJSETOPS_VERSION
|
---|
| 1068 | },
|
---|
| 1069 | rtZipTarWriterPush_Seek,
|
---|
| 1070 | rtZipTarWriterPush_QuerySize,
|
---|
[69977] | 1071 | NULL /*SetSize*/,
|
---|
| 1072 | NULL /*QueryMaxSize*/,
|
---|
[67149] | 1073 | RTVFSFILEOPS_VERSION
|
---|
| 1074 | };
|
---|
| 1075 |
|
---|
| 1076 |
|
---|
| 1077 |
|
---|
| 1078 | /**
|
---|
| 1079 | * Checks rcFatal and completes any current push file.
|
---|
| 1080 | *
|
---|
| 1081 | * On return the output stream position will be at the next header location.
|
---|
| 1082 | *
|
---|
| 1083 | * After this call, the push object no longer can write anything.
|
---|
| 1084 | *
|
---|
| 1085 | * @returns IPRT status code.
|
---|
| 1086 | * @param pThis The TAR writer instance.
|
---|
| 1087 | */
|
---|
| 1088 | static int rtZipTarFssWriter_CompleteCurrentPushFile(PRTZIPTARFSSTREAMWRITER pThis)
|
---|
| 1089 | {
|
---|
| 1090 | /*
|
---|
| 1091 | * Check if there is a push file pending, remove it if there is.
|
---|
| 1092 | * We also check for fatal errors at this point so the caller doesn't need to.
|
---|
| 1093 | */
|
---|
| 1094 | PRTZIPTARFSSTREAMWRITERPUSH pPush = pThis->pPush;
|
---|
| 1095 | if (!pPush)
|
---|
| 1096 | {
|
---|
| 1097 | AssertRC(pThis->rcFatal);
|
---|
| 1098 | return pThis->rcFatal;
|
---|
| 1099 | }
|
---|
| 1100 |
|
---|
| 1101 | pThis->pPush = NULL;
|
---|
| 1102 | pPush->pParent = NULL;
|
---|
| 1103 |
|
---|
| 1104 | int rc = pThis->rcFatal;
|
---|
| 1105 | AssertRCReturn(rc, rc);
|
---|
| 1106 |
|
---|
| 1107 | /*
|
---|
[98457] | 1108 | * Do we need to update the header. pThis->aHdrsTar[0] will retain the current
|
---|
[67149] | 1109 | * content at pPush->offHdr and we only need to update the size.
|
---|
| 1110 | */
|
---|
[67166] | 1111 | if (pPush->fOpenEnded)
|
---|
[67149] | 1112 | {
|
---|
[98457] | 1113 | if (rtZipTarFssWrite_IsTar(pThis))
|
---|
| 1114 | {
|
---|
| 1115 | rc = rtZipTarFssWriter_FormatOffset(pThis->aHdrsTar[0].Common.size, pPush->cbCurrent);
|
---|
| 1116 | if (RT_SUCCESS(rc))
|
---|
| 1117 | rc = rtZipTarFssWriter_ChecksumHdr(&pThis->aHdrsTar[0]);
|
---|
| 1118 | }
|
---|
| 1119 | else
|
---|
| 1120 | {
|
---|
| 1121 | if (pPush->cbCurrent == (uint32_t)pPush->cbCurrent)
|
---|
| 1122 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achFileSize, (uint32_t)pPush->cbCurrent);
|
---|
| 1123 | else
|
---|
| 1124 | rc = VERR_FILE_TOO_BIG;
|
---|
| 1125 | }
|
---|
| 1126 |
|
---|
[67149] | 1127 | if (RT_SUCCESS(rc))
|
---|
| 1128 | {
|
---|
[98457] | 1129 | rc = RTVfsFileWriteAt(pThis->hVfsFile, pPush->offHdr, &pThis->abHdrs[0], pThis->cbHdr, NULL);
|
---|
[67149] | 1130 | if (RT_SUCCESS(rc))
|
---|
| 1131 | rc = RTVfsFileSeek(pThis->hVfsFile, pPush->offData + pPush->cbCurrent, RTFILE_SEEK_BEGIN, NULL);
|
---|
| 1132 | }
|
---|
| 1133 | }
|
---|
| 1134 | /*
|
---|
| 1135 | * Check that we've received all the data we were promissed in the PushFile
|
---|
| 1136 | * call, fail if we weren't.
|
---|
| 1137 | */
|
---|
| 1138 | else
|
---|
| 1139 | AssertMsgStmt(pPush->cbCurrent == pPush->cbExpected,
|
---|
| 1140 | ("cbCurrent=%#RX64 cbExpected=%#RX64\n", pPush->cbCurrent, pPush->cbExpected),
|
---|
| 1141 | rc = VERR_BUFFER_UNDERFLOW);
|
---|
| 1142 | if (RT_SUCCESS(rc))
|
---|
| 1143 | {
|
---|
| 1144 | /*
|
---|
| 1145 | * Do zero padding if necessary.
|
---|
| 1146 | */
|
---|
[98457] | 1147 | size_t cbBlock = rtZipTarFssWrite_GetBlockSize(pThis);
|
---|
| 1148 | if (pPush->cbCurrent & (cbBlock - 1))
|
---|
[67149] | 1149 | {
|
---|
[98457] | 1150 | size_t cbToZero = cbBlock - (pPush->cbCurrent & (cbBlock - 1));
|
---|
[67149] | 1151 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, g_abRTZero4K, cbToZero, true /*fBlocking*/, NULL);
|
---|
| 1152 | if (RT_SUCCESS(rc))
|
---|
| 1153 | pThis->cbWritten += cbToZero;
|
---|
| 1154 | }
|
---|
| 1155 | }
|
---|
| 1156 |
|
---|
| 1157 | if (RT_SUCCESS(rc))
|
---|
| 1158 | return VINF_SUCCESS;
|
---|
| 1159 | pThis->rcFatal = rc;
|
---|
| 1160 | return rc;
|
---|
| 1161 | }
|
---|
| 1162 |
|
---|
| 1163 |
|
---|
| 1164 | /**
|
---|
[84192] | 1165 | * Does the actual work for rtZipTarFssWriter_SwitchToWriteMode().
|
---|
| 1166 | *
|
---|
| 1167 | * @note We won't be here if we've truncate the tar file. Truncation
|
---|
| 1168 | * switches it into write mode.
|
---|
| 1169 | */
|
---|
| 1170 | DECL_NO_INLINE(static, int) rtZipTarFssWriter_SwitchToWriteModeSlow(PRTZIPTARFSSTREAMWRITER pThis)
|
---|
| 1171 | {
|
---|
| 1172 | /* Always go thru rtZipTarFssWriter_SwitchToWriteMode(). */
|
---|
| 1173 | AssertRCReturn(pThis->rcFatal, pThis->rcFatal);
|
---|
| 1174 | AssertReturn(!pThis->fWriting, VINF_SUCCESS);
|
---|
| 1175 | AssertReturn(pThis->fFlags & RTZIPTAR_C_UPDATE, VERR_INTERNAL_ERROR_3);
|
---|
| 1176 |
|
---|
| 1177 | /*
|
---|
| 1178 | * If we're not at the end, locate the end of the tar file.
|
---|
| 1179 | * Because I'm lazy, we do that using rtZipTarFss_Next. This isn't entirely
|
---|
| 1180 | * optimial as it involves VFS object instantations and such.
|
---|
| 1181 | */
|
---|
| 1182 | /** @todo Optimize skipping to end of tar file in update mode. */
|
---|
[98457] | 1183 | while (!pThis->pReadTar->fEndOfStream)
|
---|
[84192] | 1184 | {
|
---|
[98457] | 1185 | int rc = rtZipTarFss_Next(pThis->pReadTar, NULL, NULL, NULL);
|
---|
[84192] | 1186 | if (rc == VERR_EOF)
|
---|
| 1187 | break;
|
---|
| 1188 | AssertRCReturn(rc, rc);
|
---|
| 1189 | }
|
---|
| 1190 |
|
---|
| 1191 | /*
|
---|
| 1192 | * Seek to the desired cut-off point and indicate that we've switched to writing.
|
---|
| 1193 | */
|
---|
[98457] | 1194 | Assert(pThis->pReadTar->offNextHdr == pThis->pReadTar->offCurHdr);
|
---|
| 1195 | int rc = RTVfsFileSeek(pThis->hVfsFile, pThis->pReadTar->offNextHdr, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
|
---|
[84192] | 1196 | if (RT_SUCCESS(rc))
|
---|
| 1197 | pThis->fWriting = true;
|
---|
| 1198 | else
|
---|
| 1199 | pThis->rcFatal = rc;
|
---|
| 1200 |
|
---|
| 1201 | return rc;
|
---|
| 1202 | }
|
---|
| 1203 |
|
---|
| 1204 |
|
---|
| 1205 | /**
|
---|
| 1206 | * Switches the stream into writing mode if necessary.
|
---|
| 1207 | *
|
---|
| 1208 | * @returns VBox status code.
|
---|
| 1209 | * @param pThis The TAR writer instance.
|
---|
| 1210 | *
|
---|
| 1211 | */
|
---|
| 1212 | DECLINLINE(int) rtZipTarFssWriter_SwitchToWriteMode(PRTZIPTARFSSTREAMWRITER pThis)
|
---|
| 1213 | {
|
---|
| 1214 | if (pThis->fWriting)
|
---|
| 1215 | return VINF_SUCCESS; /* ASSUMES caller already checked pThis->rcFatal. */
|
---|
| 1216 | return rtZipTarFssWriter_SwitchToWriteModeSlow(pThis);
|
---|
| 1217 | }
|
---|
| 1218 |
|
---|
| 1219 |
|
---|
| 1220 | /**
|
---|
[67134] | 1221 | * Allocates a buffer for transfering file data.
|
---|
[34179] | 1222 | *
|
---|
[67134] | 1223 | * @note Will use the 3rd TAR header as fallback buffer if we're out of
|
---|
| 1224 | * memory!
|
---|
| 1225 | *
|
---|
| 1226 | * @returns Pointer to buffer (won't ever fail).
|
---|
[67116] | 1227 | * @param pThis The TAR writer instance.
|
---|
[67134] | 1228 | * @param pcbBuf Where to return the buffer size. This will be a
|
---|
| 1229 | * multiple of the TAR block size.
|
---|
| 1230 | * @param ppvFree Where to return the pointer to pass to RTMemTmpFree
|
---|
| 1231 | * when done with the buffer.
|
---|
| 1232 | * @param cbFile The file size. Used as a buffer size hint.
|
---|
[34179] | 1233 | */
|
---|
[84192] | 1234 | static uint8_t *rtZipTarFssWriter_AllocBuf(PRTZIPTARFSSTREAMWRITER pThis, size_t *pcbBuf, void **ppvFree, uint64_t cbObject)
|
---|
[34179] | 1235 | {
|
---|
[67134] | 1236 | uint8_t *pbBuf;
|
---|
| 1237 |
|
---|
[34179] | 1238 | /*
|
---|
[67134] | 1239 | * If this is a large file, try for a large buffer with 16KB alignment.
|
---|
[34179] | 1240 | */
|
---|
[67134] | 1241 | if (cbObject >= _64M)
|
---|
| 1242 | {
|
---|
| 1243 | pbBuf = (uint8_t *)RTMemTmpAlloc(_2M + _16K - 1);
|
---|
| 1244 | if (pbBuf)
|
---|
| 1245 | {
|
---|
| 1246 | *pcbBuf = _2M;
|
---|
| 1247 | *ppvFree = pbBuf;
|
---|
| 1248 | return RT_ALIGN_PT(pbBuf, _16K, uint8_t *);
|
---|
| 1249 | }
|
---|
| 1250 | }
|
---|
| 1251 | /*
|
---|
| 1252 | * 4KB aligned 512KB buffer if larger 512KB or larger.
|
---|
| 1253 | */
|
---|
| 1254 | else if (cbObject >= _512K)
|
---|
| 1255 | {
|
---|
| 1256 | pbBuf = (uint8_t *)RTMemTmpAlloc(_512K + _4K - 1);
|
---|
| 1257 | if (pbBuf)
|
---|
| 1258 | {
|
---|
| 1259 | *pcbBuf = _512K;
|
---|
| 1260 | *ppvFree = pbBuf;
|
---|
| 1261 | return RT_ALIGN_PT(pbBuf, _4K, uint8_t *);
|
---|
| 1262 | }
|
---|
| 1263 | }
|
---|
| 1264 | /*
|
---|
| 1265 | * Otherwise a 4KB aligned 128KB buffer.
|
---|
| 1266 | */
|
---|
| 1267 | else
|
---|
| 1268 | {
|
---|
| 1269 | pbBuf = (uint8_t *)RTMemTmpAlloc(_128K + _4K - 1);
|
---|
| 1270 | if (pbBuf)
|
---|
| 1271 | {
|
---|
| 1272 | *pcbBuf = _128K;
|
---|
| 1273 | *ppvFree = pbBuf;
|
---|
| 1274 | return RT_ALIGN_PT(pbBuf, _4K, uint8_t *);
|
---|
| 1275 | }
|
---|
| 1276 | }
|
---|
| 1277 |
|
---|
| 1278 | /*
|
---|
| 1279 | * If allocation failed, fallback on a 16KB buffer without any extra alignment.
|
---|
| 1280 | */
|
---|
| 1281 | pbBuf = (uint8_t *)RTMemTmpAlloc(_16K);
|
---|
| 1282 | if (pbBuf)
|
---|
| 1283 | {
|
---|
| 1284 | *pcbBuf = _16K;
|
---|
| 1285 | *ppvFree = pbBuf;
|
---|
| 1286 | return pbBuf;
|
---|
| 1287 | }
|
---|
| 1288 |
|
---|
| 1289 | /*
|
---|
[98457] | 1290 | * Final fallback, 512B buffer using the fallback buffer.
|
---|
[67134] | 1291 | */
|
---|
[98457] | 1292 | *pcbBuf = sizeof(pThis->abIoBuf);
|
---|
[67134] | 1293 | *ppvFree = NULL;
|
---|
[98457] | 1294 | return &pThis->abIoBuf[0];
|
---|
[67134] | 1295 | }
|
---|
| 1296 |
|
---|
| 1297 |
|
---|
| 1298 | /**
|
---|
| 1299 | * Frees the sparse info for a TAR file.
|
---|
| 1300 | *
|
---|
| 1301 | * @param pSparse The sparse info to free.
|
---|
| 1302 | */
|
---|
| 1303 | static void rtZipTarFssWriter_SparseInfoDestroy(PRTZIPTARSPARSE pSparse)
|
---|
| 1304 | {
|
---|
| 1305 | PRTZIPTARSPARSECHUNK pCur;
|
---|
| 1306 | PRTZIPTARSPARSECHUNK pNext;
|
---|
| 1307 | RTListForEachSafe(&pSparse->ChunkHead, pCur, pNext, RTZIPTARSPARSECHUNK, Entry)
|
---|
| 1308 | RTMemTmpFree(pCur);
|
---|
| 1309 | RTMemTmpFree(pSparse);
|
---|
| 1310 | }
|
---|
| 1311 |
|
---|
| 1312 |
|
---|
| 1313 | /**
|
---|
| 1314 | * Adds a data span to the sparse info.
|
---|
| 1315 | *
|
---|
| 1316 | * @returns VINF_SUCCESS or VINF_NO_TMP_MEMORY.
|
---|
| 1317 | * @param pSparse The sparse info to free.
|
---|
| 1318 | * @param offSpan Offset of the span.
|
---|
| 1319 | * @param cbSpan Number of bytes.
|
---|
| 1320 | */
|
---|
| 1321 | static int rtZipTarFssWriter_SparseInfoAddSpan(PRTZIPTARSPARSE pSparse, uint64_t offSpan, uint64_t cbSpan)
|
---|
| 1322 | {
|
---|
| 1323 | /*
|
---|
| 1324 | * Get the chunk we're adding it to.
|
---|
| 1325 | */
|
---|
| 1326 | PRTZIPTARSPARSECHUNK pChunk;
|
---|
| 1327 | if (pSparse->iNextSpan != 0)
|
---|
| 1328 | {
|
---|
| 1329 | pChunk = RTListGetLast(&pSparse->ChunkHead, RTZIPTARSPARSECHUNK, Entry);
|
---|
| 1330 | Assert(pSparse->iNextSpan < RT_ELEMENTS(pChunk->aSpans));
|
---|
| 1331 | }
|
---|
| 1332 | else
|
---|
| 1333 | {
|
---|
| 1334 | pChunk = (PRTZIPTARSPARSECHUNK)RTMemTmpAllocZ(sizeof(*pChunk));
|
---|
| 1335 | if (!pChunk)
|
---|
| 1336 | return VERR_NO_TMP_MEMORY;
|
---|
| 1337 | RTListAppend(&pSparse->ChunkHead, &pChunk->Entry);
|
---|
| 1338 | }
|
---|
| 1339 |
|
---|
| 1340 | /*
|
---|
| 1341 | * Append it.
|
---|
| 1342 | */
|
---|
| 1343 | pSparse->cDataSpans += 1;
|
---|
| 1344 | pSparse->cbDataSpans += cbSpan;
|
---|
| 1345 | pChunk->aSpans[pSparse->iNextSpan].cb = cbSpan;
|
---|
| 1346 | pChunk->aSpans[pSparse->iNextSpan].off = offSpan;
|
---|
| 1347 | if (++pSparse->iNextSpan >= RT_ELEMENTS(pChunk->aSpans))
|
---|
| 1348 | pSparse->iNextSpan = 0;
|
---|
| 1349 | return VINF_SUCCESS;
|
---|
| 1350 | }
|
---|
| 1351 |
|
---|
| 1352 |
|
---|
| 1353 | /**
|
---|
| 1354 | * Scans the input stream recording non-zero blocks.
|
---|
| 1355 | */
|
---|
| 1356 | static int rtZipTarFssWriter_ScanSparseFile(PRTZIPTARFSSTREAMWRITER pThis, RTVFSFILE hVfsFile, uint64_t cbFile,
|
---|
| 1357 | size_t cbBuf, uint8_t *pbBuf, PRTZIPTARSPARSE *ppSparse)
|
---|
| 1358 | {
|
---|
| 1359 | RT_NOREF(pThis);
|
---|
| 1360 |
|
---|
| 1361 | /*
|
---|
| 1362 | * Create an empty sparse info bundle.
|
---|
| 1363 | */
|
---|
| 1364 | PRTZIPTARSPARSE pSparse = (PRTZIPTARSPARSE)RTMemTmpAlloc(sizeof(*pSparse));
|
---|
| 1365 | AssertReturn(pSparse, VERR_NO_MEMORY);
|
---|
| 1366 | pSparse->cbDataSpans = 0;
|
---|
| 1367 | pSparse->cDataSpans = 0;
|
---|
| 1368 | pSparse->iNextSpan = 0;
|
---|
| 1369 | RTListInit(&pSparse->ChunkHead);
|
---|
| 1370 |
|
---|
| 1371 | /*
|
---|
| 1372 | * Scan the file from the start.
|
---|
| 1373 | */
|
---|
| 1374 | int rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
|
---|
[67116] | 1375 | if (RT_SUCCESS(rc))
|
---|
[34179] | 1376 | {
|
---|
[67134] | 1377 | bool fZeroSpan = false;
|
---|
| 1378 | uint64_t offSpan = 0;
|
---|
| 1379 | uint64_t cbSpan = 0;
|
---|
| 1380 |
|
---|
| 1381 | for (uint64_t off = 0; off < cbFile;)
|
---|
[34179] | 1382 | {
|
---|
[67134] | 1383 | uint64_t cbLeft = cbFile - off;
|
---|
| 1384 | size_t cbToRead = cbLeft >= cbBuf ? cbBuf : (size_t)cbLeft;
|
---|
| 1385 | rc = RTVfsFileRead(hVfsFile, pbBuf, cbToRead, NULL);
|
---|
| 1386 | if (RT_FAILURE(rc))
|
---|
| 1387 | break;
|
---|
| 1388 | size_t cBlocks = cbToRead / RTZIPTAR_BLOCKSIZE;
|
---|
[34179] | 1389 |
|
---|
[67134] | 1390 | /* Zero pad the final buffer to a multiple of the blocksize. */
|
---|
| 1391 | if (!(cbToRead & (RTZIPTAR_BLOCKSIZE - 1)))
|
---|
| 1392 | { /* likely */ }
|
---|
| 1393 | else
|
---|
| 1394 | {
|
---|
| 1395 | AssertBreakStmt(cbLeft == cbToRead, rc = VERR_INTERNAL_ERROR_3);
|
---|
| 1396 | RT_BZERO(&pbBuf[cbToRead], RTZIPTAR_BLOCKSIZE - (cbToRead & (RTZIPTAR_BLOCKSIZE - 1)));
|
---|
| 1397 | cBlocks++;
|
---|
| 1398 | }
|
---|
| 1399 |
|
---|
[34179] | 1400 | /*
|
---|
[67134] | 1401 | * Process the blocks we've just read one by one.
|
---|
[34179] | 1402 | */
|
---|
[67134] | 1403 | uint8_t const *pbBlock = pbBuf;
|
---|
| 1404 | for (size_t iBlock = 0; iBlock < cBlocks; iBlock++)
|
---|
[34179] | 1405 | {
|
---|
[67134] | 1406 | bool fZeroBlock = ASMMemIsZero(pbBlock, RTZIPTAR_BLOCKSIZE);
|
---|
| 1407 | if (fZeroBlock == fZeroSpan)
|
---|
| 1408 | cbSpan += RTZIPTAR_BLOCKSIZE;
|
---|
| 1409 | else
|
---|
[34179] | 1410 | {
|
---|
[67134] | 1411 | if (!fZeroSpan && cbSpan)
|
---|
| 1412 | {
|
---|
| 1413 | rc = rtZipTarFssWriter_SparseInfoAddSpan(pSparse, offSpan, cbSpan);
|
---|
| 1414 | if (RT_FAILURE(rc))
|
---|
| 1415 | break;
|
---|
| 1416 | }
|
---|
| 1417 | fZeroSpan = fZeroBlock;
|
---|
| 1418 | offSpan = off;
|
---|
| 1419 | cbSpan = RTZIPTAR_BLOCKSIZE;
|
---|
[34179] | 1420 | }
|
---|
[67134] | 1421 |
|
---|
| 1422 | /* next block. */
|
---|
| 1423 | pbBlock += RTZIPTAR_BLOCKSIZE;
|
---|
| 1424 | off += RTZIPTAR_BLOCKSIZE;
|
---|
[34179] | 1425 | }
|
---|
[67134] | 1426 | }
|
---|
[34049] | 1427 |
|
---|
[67134] | 1428 | /*
|
---|
| 1429 | * Deal with the final span. If we've got zeros thowards the end, we
|
---|
| 1430 | * must add a zero byte data span at the end.
|
---|
| 1431 | */
|
---|
| 1432 | if (RT_SUCCESS(rc))
|
---|
| 1433 | {
|
---|
| 1434 | if (!fZeroSpan && cbSpan)
|
---|
| 1435 | {
|
---|
| 1436 | if (cbFile & (RTZIPTAR_BLOCKSIZE - 1))
|
---|
| 1437 | {
|
---|
| 1438 | Assert(!(cbSpan & (RTZIPTAR_BLOCKSIZE - 1)));
|
---|
| 1439 | cbSpan -= RTZIPTAR_BLOCKSIZE;
|
---|
| 1440 | cbSpan |= cbFile & (RTZIPTAR_BLOCKSIZE - 1);
|
---|
| 1441 | }
|
---|
| 1442 | rc = rtZipTarFssWriter_SparseInfoAddSpan(pSparse, offSpan, cbSpan);
|
---|
| 1443 | }
|
---|
| 1444 | if (RT_SUCCESS(rc))
|
---|
| 1445 | rc = rtZipTarFssWriter_SparseInfoAddSpan(pSparse, cbFile, 0);
|
---|
| 1446 | }
|
---|
| 1447 | }
|
---|
| 1448 |
|
---|
| 1449 | if (RT_SUCCESS(rc))
|
---|
| 1450 | {
|
---|
| 1451 | /*
|
---|
| 1452 | * Return the file back to the start position before we return so that we
|
---|
| 1453 | * can segue into the regular rtZipTarFssWriter_AddFile without further ado.
|
---|
| 1454 | */
|
---|
| 1455 | rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
|
---|
| 1456 | if (RT_SUCCESS(rc))
|
---|
| 1457 | {
|
---|
| 1458 | *ppSparse = pSparse;
|
---|
| 1459 | return VINF_SUCCESS;
|
---|
| 1460 | }
|
---|
| 1461 | }
|
---|
| 1462 |
|
---|
| 1463 | rtZipTarFssWriter_SparseInfoDestroy(pSparse);
|
---|
| 1464 | *ppSparse = NULL;
|
---|
| 1465 | return rc;
|
---|
| 1466 | }
|
---|
| 1467 |
|
---|
| 1468 |
|
---|
| 1469 | /**
|
---|
| 1470 | * Writes GNU the sparse file headers.
|
---|
| 1471 | *
|
---|
| 1472 | * @returns IPRT status code.
|
---|
| 1473 | * @param pThis The TAR writer instance.
|
---|
| 1474 | * @param pszPath The path to the file.
|
---|
| 1475 | * @param pObjInfo The object information.
|
---|
| 1476 | * @param pszOwnerNm The owner name.
|
---|
| 1477 | * @param pszGroupNm The group name.
|
---|
| 1478 | * @param pSparse The sparse file info.
|
---|
| 1479 | */
|
---|
| 1480 | static int rtZipTarFssWriter_WriteGnuSparseHeaders(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, PCRTFSOBJINFO pObjInfo,
|
---|
| 1481 | const char *pszOwnerNm, const char *pszGroupNm, PCRTZIPTARSPARSE pSparse)
|
---|
| 1482 | {
|
---|
| 1483 | /*
|
---|
| 1484 | * Format the first header.
|
---|
| 1485 | */
|
---|
[98457] | 1486 | int rc = rtZipTarFssWriter_ObjInfoToHdrTar(pThis, pszPath, pObjInfo, pszOwnerNm, pszGroupNm, RTZIPTAR_TF_GNU_SPARSE);
|
---|
[67134] | 1487 | AssertRCReturn(rc, rc);
|
---|
| 1488 | AssertReturn(pThis->cHdrs == 1, VERR_INTERNAL_ERROR_2);
|
---|
| 1489 |
|
---|
| 1490 | /* data size. */
|
---|
[98457] | 1491 | rc = rtZipTarFssWriter_FormatOffset(pThis->aHdrsTar[0].Common.size, pSparse->cbDataSpans);
|
---|
[67134] | 1492 | AssertRCReturn(rc, rc);
|
---|
| 1493 |
|
---|
| 1494 | /* realsize. */
|
---|
[98457] | 1495 | rc = rtZipTarFssWriter_FormatOffset(pThis->aHdrsTar[0].Gnu.realsize, pObjInfo->cbObject);
|
---|
[67134] | 1496 | AssertRCReturn(rc, rc);
|
---|
| 1497 |
|
---|
[98457] | 1498 | Assert(pThis->aHdrsTar[0].Gnu.isextended == 0);
|
---|
[67206] | 1499 |
|
---|
[67134] | 1500 | /*
|
---|
| 1501 | * Walk the sparse spans, fill and write headers one by one.
|
---|
| 1502 | */
|
---|
[98457] | 1503 | PRTZIPTARGNUSPARSE paSparse = &pThis->aHdrsTar[0].Gnu.sparse[0];
|
---|
| 1504 | uint32_t cSparse = RT_ELEMENTS(pThis->aHdrsTar[0].Gnu.sparse);
|
---|
[67134] | 1505 | uint32_t iSparse = 0;
|
---|
| 1506 |
|
---|
| 1507 | PRTZIPTARSPARSECHUNK const pLastChunk = RTListGetLast(&pSparse->ChunkHead, RTZIPTARSPARSECHUNK, Entry);
|
---|
| 1508 | PRTZIPTARSPARSECHUNK pChunk;
|
---|
| 1509 | RTListForEach(&pSparse->ChunkHead, pChunk, RTZIPTARSPARSECHUNK, Entry)
|
---|
| 1510 | {
|
---|
| 1511 | uint32_t cSpans = pChunk != pLastChunk || pSparse->iNextSpan == 0
|
---|
| 1512 | ? RT_ELEMENTS(pChunk->aSpans) : pSparse->iNextSpan;
|
---|
| 1513 | for (uint32_t iSpan = 0; iSpan < cSpans; iSpan++)
|
---|
| 1514 | {
|
---|
| 1515 | /* Flush the header? */
|
---|
| 1516 | if (iSparse >= cSparse)
|
---|
| 1517 | {
|
---|
[98457] | 1518 | if (cSparse != RT_ELEMENTS(pThis->aHdrsTar[0].Gnu.sparse))
|
---|
| 1519 | pThis->aHdrsTar[0].GnuSparse.isextended = 1; /* more headers to come */
|
---|
[67206] | 1520 | else
|
---|
| 1521 | {
|
---|
[98457] | 1522 | pThis->aHdrsTar[0].Gnu.isextended = 1; /* more headers to come */
|
---|
| 1523 | rc = rtZipTarFssWriter_ChecksumHdr(&pThis->aHdrsTar[0]);
|
---|
[67206] | 1524 | }
|
---|
[67134] | 1525 | if (RT_SUCCESS(rc))
|
---|
[98457] | 1526 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, &pThis->aHdrsTar[0], sizeof(pThis->aHdrsTar[0]), true /*fBlocking*/, NULL);
|
---|
[67134] | 1527 | if (RT_FAILURE(rc))
|
---|
| 1528 | return rc;
|
---|
[98457] | 1529 | RT_ZERO(pThis->aHdrsTar[0]);
|
---|
| 1530 | cSparse = RT_ELEMENTS(pThis->aHdrsTar[0].GnuSparse.sp);
|
---|
[67134] | 1531 | iSparse = 0;
|
---|
[98457] | 1532 | paSparse = &pThis->aHdrsTar[0].GnuSparse.sp[0];
|
---|
[67134] | 1533 | }
|
---|
| 1534 |
|
---|
| 1535 | /* Append sparse data segment. */
|
---|
| 1536 | rc = rtZipTarFssWriter_FormatOffset(paSparse[iSparse].offset, pChunk->aSpans[iSpan].off);
|
---|
| 1537 | AssertRCReturn(rc, rc);
|
---|
| 1538 | rc = rtZipTarFssWriter_FormatOffset(paSparse[iSparse].numbytes, pChunk->aSpans[iSpan].cb);
|
---|
| 1539 | AssertRCReturn(rc, rc);
|
---|
| 1540 | iSparse++;
|
---|
| 1541 | }
|
---|
| 1542 | }
|
---|
| 1543 |
|
---|
| 1544 | /*
|
---|
| 1545 | * The final header.
|
---|
| 1546 | */
|
---|
| 1547 | if (iSparse != 0)
|
---|
| 1548 | {
|
---|
[98457] | 1549 | if (cSparse != RT_ELEMENTS(pThis->aHdrsTar[0].Gnu.sparse))
|
---|
| 1550 | Assert(pThis->aHdrsTar[0].GnuSparse.isextended == 0);
|
---|
[67220] | 1551 | else
|
---|
| 1552 | {
|
---|
[98457] | 1553 | Assert(pThis->aHdrsTar[0].Gnu.isextended == 0);
|
---|
| 1554 | rc = rtZipTarFssWriter_ChecksumHdr(&pThis->aHdrsTar[0]);
|
---|
[67220] | 1555 | }
|
---|
| 1556 | if (RT_SUCCESS(rc))
|
---|
[98457] | 1557 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, &pThis->aHdrsTar[0], sizeof(pThis->aHdrsTar[0]), true /*fBlocking*/, NULL);
|
---|
[67134] | 1558 | }
|
---|
| 1559 | pThis->cHdrs = 0;
|
---|
| 1560 | return rc;
|
---|
| 1561 | }
|
---|
| 1562 |
|
---|
| 1563 |
|
---|
| 1564 | /**
|
---|
| 1565 | * Adds a potentially sparse file to the output.
|
---|
| 1566 | *
|
---|
| 1567 | * @returns IPRT status code.
|
---|
| 1568 | * @param pThis The TAR writer instance.
|
---|
| 1569 | * @param pszPath The path to the file.
|
---|
| 1570 | * @param hVfsFile The potentially sparse file.
|
---|
| 1571 | * @param hVfsIos The I/O stream of the file. Same as @a hVfsFile.
|
---|
| 1572 | * @param pObjInfo The object information.
|
---|
| 1573 | * @param pszOwnerNm The owner name.
|
---|
| 1574 | * @param pszGroupNm The group name.
|
---|
| 1575 | */
|
---|
| 1576 | static int rtZipTarFssWriter_AddFileSparse(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, RTVFSFILE hVfsFile,
|
---|
| 1577 | RTVFSIOSTREAM hVfsIos, PCRTFSOBJINFO pObjInfo,
|
---|
| 1578 | const char *pszOwnerNm, const char *pszGroupNm)
|
---|
| 1579 | {
|
---|
[98457] | 1580 | AssertReturn(rtZipTarFssWrite_IsTar(pThis), VERR_INTERNAL_ERROR_2);
|
---|
| 1581 |
|
---|
[67134] | 1582 | /*
|
---|
| 1583 | * Scan the input file to locate all zero blocks.
|
---|
| 1584 | */
|
---|
| 1585 | void *pvBufFree;
|
---|
| 1586 | size_t cbBuf;
|
---|
[84192] | 1587 | uint8_t *pbBuf = rtZipTarFssWriter_AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject);
|
---|
[67134] | 1588 |
|
---|
| 1589 | PRTZIPTARSPARSE pSparse;
|
---|
| 1590 | int rc = rtZipTarFssWriter_ScanSparseFile(pThis, hVfsFile, pObjInfo->cbObject, cbBuf, pbBuf, &pSparse);
|
---|
| 1591 | if (RT_SUCCESS(rc))
|
---|
| 1592 | {
|
---|
| 1593 | /*
|
---|
| 1594 | * If there aren't at least 2 zero blocks in the file, don't bother
|
---|
| 1595 | * doing the sparse stuff and store it as a normal file.
|
---|
| 1596 | */
|
---|
| 1597 | if (pSparse->cbDataSpans + RTZIPTAR_BLOCKSIZE > (uint64_t)pObjInfo->cbObject)
|
---|
| 1598 | {
|
---|
| 1599 | rtZipTarFssWriter_SparseInfoDestroy(pSparse);
|
---|
| 1600 | RTMemTmpFree(pvBufFree);
|
---|
| 1601 | return rtZipTarFssWriter_AddFile(pThis, pszPath, hVfsIos, pObjInfo, pszOwnerNm, pszGroupNm);
|
---|
| 1602 | }
|
---|
| 1603 |
|
---|
| 1604 | /*
|
---|
| 1605 | * Produce and write the headers.
|
---|
| 1606 | */
|
---|
| 1607 | if (pThis->enmFormat == RTZIPTARFORMAT_GNU)
|
---|
| 1608 | rc = rtZipTarFssWriter_WriteGnuSparseHeaders(pThis, pszPath, pObjInfo, pszOwnerNm, pszGroupNm, pSparse);
|
---|
| 1609 | else
|
---|
| 1610 | AssertStmt(pThis->enmFormat != RTZIPTARFORMAT_GNU, rc = VERR_NOT_IMPLEMENTED);
|
---|
| 1611 | if (RT_SUCCESS(rc))
|
---|
| 1612 | {
|
---|
[34179] | 1613 | /*
|
---|
[67134] | 1614 | * Write the file bytes.
|
---|
[34179] | 1615 | */
|
---|
[67134] | 1616 | PRTZIPTARSPARSECHUNK const pLastChunk = RTListGetLast(&pSparse->ChunkHead, RTZIPTARSPARSECHUNK, Entry);
|
---|
| 1617 | PRTZIPTARSPARSECHUNK pChunk;
|
---|
| 1618 | RTListForEach(&pSparse->ChunkHead, pChunk, RTZIPTARSPARSECHUNK, Entry)
|
---|
[34179] | 1619 | {
|
---|
[67134] | 1620 | uint32_t cSpans = pChunk != pLastChunk || pSparse->iNextSpan == 0
|
---|
| 1621 | ? RT_ELEMENTS(pChunk->aSpans) : pSparse->iNextSpan;
|
---|
| 1622 | for (uint32_t iSpan = 0; iSpan < cSpans; iSpan++)
|
---|
[67123] | 1623 | {
|
---|
[67134] | 1624 | rc = RTVfsFileSeek(hVfsFile, pChunk->aSpans[iSpan].off, RTFILE_SEEK_BEGIN, NULL);
|
---|
[67123] | 1625 | if (RT_FAILURE(rc))
|
---|
| 1626 | break;
|
---|
[67134] | 1627 | uint64_t cbLeft = pChunk->aSpans[iSpan].cb;
|
---|
| 1628 | Assert( !(cbLeft & (RTZIPTAR_BLOCKSIZE - 1))
|
---|
| 1629 | || (iSpan + 1 == cSpans && pChunk == pLastChunk));
|
---|
| 1630 | while (cbLeft > 0)
|
---|
[67123] | 1631 | {
|
---|
[67134] | 1632 | size_t cbToRead = cbLeft >= cbBuf ? cbBuf : (size_t)cbLeft;
|
---|
| 1633 | rc = RTVfsFileRead(hVfsFile, pbBuf, cbToRead, NULL);
|
---|
| 1634 | if (RT_SUCCESS(rc))
|
---|
| 1635 | {
|
---|
| 1636 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pbBuf, cbToRead, true /*fBlocking*/, NULL);
|
---|
| 1637 | if (RT_SUCCESS(rc))
|
---|
| 1638 | {
|
---|
| 1639 | pThis->cbWritten += cbToRead;
|
---|
| 1640 | cbLeft -= cbToRead;
|
---|
| 1641 | continue;
|
---|
| 1642 | }
|
---|
| 1643 | }
|
---|
| 1644 | break;
|
---|
[67123] | 1645 | }
|
---|
| 1646 | if (RT_FAILURE(rc))
|
---|
| 1647 | break;
|
---|
| 1648 | }
|
---|
| 1649 | }
|
---|
[67134] | 1650 |
|
---|
[67123] | 1651 | /*
|
---|
[67134] | 1652 | * Do the zero padding.
|
---|
[67123] | 1653 | */
|
---|
[67134] | 1654 | if ( RT_SUCCESS(rc)
|
---|
| 1655 | && (pSparse->cbDataSpans & (RTZIPTAR_BLOCKSIZE - 1)))
|
---|
[67123] | 1656 | {
|
---|
[67134] | 1657 | size_t cbToZero = RTZIPTAR_BLOCKSIZE - (pSparse->cbDataSpans & (RTZIPTAR_BLOCKSIZE - 1));
|
---|
| 1658 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, g_abRTZero4K, cbToZero, true /*fBlocking*/, NULL);
|
---|
| 1659 | if (RT_SUCCESS(rc))
|
---|
| 1660 | pThis->cbWritten += cbToZero;
|
---|
| 1661 | }
|
---|
| 1662 | }
|
---|
| 1663 |
|
---|
| 1664 | if (RT_FAILURE(rc))
|
---|
| 1665 | pThis->rcFatal = rc;
|
---|
| 1666 | rtZipTarFssWriter_SparseInfoDestroy(pSparse);
|
---|
| 1667 | }
|
---|
| 1668 | RTMemTmpFree(pvBufFree);
|
---|
| 1669 | return rc;
|
---|
| 1670 | }
|
---|
| 1671 |
|
---|
| 1672 |
|
---|
| 1673 | /**
|
---|
| 1674 | * Adds an I/O stream of indeterminate length to the TAR file.
|
---|
| 1675 | *
|
---|
| 1676 | * This requires the output to be seekable, i.e. a file, because we need to go
|
---|
| 1677 | * back and update @c size field of the TAR header after pumping all the data
|
---|
| 1678 | * bytes thru and establishing the file length.
|
---|
| 1679 | *
|
---|
| 1680 | * @returns IPRT status code.
|
---|
| 1681 | * @param pThis The TAR writer instance.
|
---|
| 1682 | * @param pszPath The path to the file.
|
---|
| 1683 | * @param hVfsIos The I/O stream of the file.
|
---|
| 1684 | * @param pObjInfo The object information.
|
---|
| 1685 | * @param pszOwnerNm The owner name.
|
---|
| 1686 | * @param pszGroupNm The group name.
|
---|
| 1687 | */
|
---|
| 1688 | static int rtZipTarFssWriter_AddFileStream(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, RTVFSIOSTREAM hVfsIos,
|
---|
| 1689 | PCRTFSOBJINFO pObjInfo, const char *pszOwnerNm, const char *pszGroupNm)
|
---|
| 1690 | {
|
---|
| 1691 | AssertReturn(pThis->hVfsFile != NIL_RTVFSFILE, VERR_NOT_A_FILE);
|
---|
| 1692 |
|
---|
| 1693 | /*
|
---|
| 1694 | * Append the header.
|
---|
| 1695 | */
|
---|
| 1696 | int rc = rtZipTarFssWriter_ObjInfoToHdr(pThis, pszPath, pObjInfo, pszOwnerNm, pszGroupNm, UINT8_MAX);
|
---|
| 1697 | if (RT_SUCCESS(rc))
|
---|
| 1698 | {
|
---|
| 1699 | RTFOFF const offHdr = RTVfsFileTell(pThis->hVfsFile);
|
---|
| 1700 | if (offHdr >= 0)
|
---|
| 1701 | {
|
---|
[98457] | 1702 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pThis->abHdrs, pThis->cHdrs * pThis->cbHdr, true /*fBlocking*/, NULL);
|
---|
[67134] | 1703 | if (RT_SUCCESS(rc))
|
---|
| 1704 | {
|
---|
[98457] | 1705 | pThis->cbWritten += pThis->cHdrs * pThis->cbHdr;
|
---|
[67134] | 1706 |
|
---|
| 1707 | /*
|
---|
| 1708 | * Transfer the bytes.
|
---|
| 1709 | */
|
---|
| 1710 | void *pvBufFree;
|
---|
| 1711 | size_t cbBuf;
|
---|
[84192] | 1712 | uint8_t *pbBuf = rtZipTarFssWriter_AllocBuf(pThis, &cbBuf, &pvBufFree,
|
---|
| 1713 | pObjInfo->cbObject > 0 && pObjInfo->cbObject != RTFOFF_MAX
|
---|
| 1714 | ? pObjInfo->cbObject : _1G);
|
---|
[67134] | 1715 |
|
---|
[67123] | 1716 | uint64_t cbReadTotal = 0;
|
---|
| 1717 | for (;;)
|
---|
| 1718 | {
|
---|
| 1719 | size_t cbRead = 0;
|
---|
| 1720 | int rc2 = rc = RTVfsIoStrmRead(hVfsIos, pbBuf, cbBuf, true /*fBlocking*/, &cbRead);
|
---|
| 1721 | if (RT_SUCCESS(rc))
|
---|
| 1722 | {
|
---|
| 1723 | cbReadTotal += cbRead;
|
---|
| 1724 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pbBuf, cbRead, true /*fBlocking*/, NULL);
|
---|
| 1725 | if (RT_SUCCESS(rc))
|
---|
| 1726 | {
|
---|
| 1727 | pThis->cbWritten += cbRead;
|
---|
| 1728 | if (rc2 != VINF_EOF)
|
---|
| 1729 | continue;
|
---|
| 1730 | }
|
---|
| 1731 | }
|
---|
| 1732 | Assert(rc != VERR_EOF /* expecting VINF_EOF! */);
|
---|
[67116] | 1733 | break;
|
---|
[67123] | 1734 | }
|
---|
[67116] | 1735 |
|
---|
[67134] | 1736 | RTMemTmpFree(pvBufFree);
|
---|
| 1737 |
|
---|
| 1738 | /*
|
---|
| 1739 | * Do the zero padding.
|
---|
| 1740 | */
|
---|
[98457] | 1741 | size_t cbBlock = rtZipTarFssWrite_GetBlockSize(pThis);
|
---|
| 1742 | if ((cbReadTotal & (cbBlock - 1)) && RT_SUCCESS(rc))
|
---|
[34179] | 1743 | {
|
---|
[98457] | 1744 | size_t cbToZero = cbBlock - (cbReadTotal & (cbBlock - 1));
|
---|
[67123] | 1745 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, g_abRTZero4K, cbToZero, true /*fBlocking*/, NULL);
|
---|
| 1746 | if (RT_SUCCESS(rc))
|
---|
| 1747 | pThis->cbWritten += cbToZero;
|
---|
[34179] | 1748 | }
|
---|
[67116] | 1749 |
|
---|
[67123] | 1750 | /*
|
---|
| 1751 | * Update the header. We ASSUME that aHdr[0] is unmodified
|
---|
| 1752 | * from before the data pumping above and just update the size.
|
---|
| 1753 | */
|
---|
[67134] | 1754 | if ((RTFOFF)cbReadTotal != pObjInfo->cbObject && RT_SUCCESS(rc))
|
---|
[67123] | 1755 | {
|
---|
[67134] | 1756 | RTFOFF const offRestore = RTVfsFileTell(pThis->hVfsFile);
|
---|
| 1757 | if (offRestore >= 0)
|
---|
[67123] | 1758 | {
|
---|
[98457] | 1759 | if (rtZipTarFssWrite_IsTar(pThis))
|
---|
| 1760 | {
|
---|
| 1761 | rc = rtZipTarFssWriter_FormatOffset(pThis->aHdrsTar[0].Common.size, cbReadTotal);
|
---|
| 1762 | if (RT_SUCCESS(rc))
|
---|
| 1763 | rc = rtZipTarFssWriter_ChecksumHdr(&pThis->aHdrsTar[0]);
|
---|
| 1764 | }
|
---|
| 1765 | else
|
---|
| 1766 | {
|
---|
| 1767 | if (pObjInfo->cbObject == (uint32_t)pObjInfo->cbObject)
|
---|
| 1768 | rtZipTarFssWriter_CpioFmtU32(pThis->Cpio.Hdr.AsciiNew.achFileSize, (uint32_t)pObjInfo->cbObject);
|
---|
| 1769 | else
|
---|
| 1770 | rc = VERR_FILE_TOO_BIG;
|
---|
| 1771 | }
|
---|
| 1772 |
|
---|
[67134] | 1773 | if (RT_SUCCESS(rc))
|
---|
[67123] | 1774 | {
|
---|
[98457] | 1775 | rc = RTVfsFileWriteAt(pThis->hVfsFile, offHdr, &pThis->abHdrs[0], pThis->cbHdr, NULL);
|
---|
[67123] | 1776 | if (RT_SUCCESS(rc))
|
---|
[67134] | 1777 | rc = RTVfsFileSeek(pThis->hVfsFile, offRestore, RTFILE_SEEK_BEGIN, NULL);
|
---|
[67123] | 1778 | }
|
---|
| 1779 | }
|
---|
| 1780 | else
|
---|
[67134] | 1781 | rc = (int)offRestore;
|
---|
[67123] | 1782 | }
|
---|
[67134] | 1783 |
|
---|
| 1784 | if (RT_SUCCESS(rc))
|
---|
| 1785 | return VINF_SUCCESS;
|
---|
[34179] | 1786 | }
|
---|
[67134] | 1787 | }
|
---|
| 1788 | else
|
---|
| 1789 | rc = (int)offHdr;
|
---|
| 1790 | pThis->rcFatal = rc;
|
---|
| 1791 | }
|
---|
| 1792 | return rc;
|
---|
| 1793 | }
|
---|
[34049] | 1794 |
|
---|
[67134] | 1795 |
|
---|
| 1796 | /**
|
---|
| 1797 | * Adds a file to the stream.
|
---|
| 1798 | *
|
---|
| 1799 | * @returns IPRT status code.
|
---|
| 1800 | * @param pThis The TAR writer instance.
|
---|
| 1801 | * @param pszPath The path to the file.
|
---|
| 1802 | * @param hVfsIos The I/O stream of the file.
|
---|
| 1803 | * @param fFlags The RTVFSFSSTREAMOPS::pfnAdd flags.
|
---|
| 1804 | * @param pObjInfo The object information.
|
---|
| 1805 | * @param pszOwnerNm The owner name.
|
---|
| 1806 | * @param pszGroupNm The group name.
|
---|
| 1807 | */
|
---|
| 1808 | static int rtZipTarFssWriter_AddFile(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, RTVFSIOSTREAM hVfsIos,
|
---|
| 1809 | PCRTFSOBJINFO pObjInfo, const char *pszOwnerNm, const char *pszGroupNm)
|
---|
| 1810 | {
|
---|
| 1811 | /*
|
---|
| 1812 | * Append the header.
|
---|
| 1813 | */
|
---|
| 1814 | int rc = rtZipTarFssWriter_ObjInfoToHdr(pThis, pszPath, pObjInfo, pszOwnerNm, pszGroupNm, UINT8_MAX);
|
---|
| 1815 | if (RT_SUCCESS(rc))
|
---|
| 1816 | {
|
---|
[98457] | 1817 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pThis->abHdrs, pThis->cHdrs * pThis->cbHdr, true /*fBlocking*/, NULL);
|
---|
[67134] | 1818 | if (RT_SUCCESS(rc))
|
---|
| 1819 | {
|
---|
[98457] | 1820 | pThis->cbWritten += pThis->cHdrs * pThis->cbHdr;
|
---|
[67134] | 1821 |
|
---|
| 1822 | /*
|
---|
[98457] | 1823 | * Copy the bytes. Padding the last buffer to a multiple of the block size.
|
---|
[67134] | 1824 | */
|
---|
| 1825 | void *pvBufFree;
|
---|
| 1826 | size_t cbBuf;
|
---|
[84192] | 1827 | uint8_t *pbBuf = rtZipTarFssWriter_AllocBuf(pThis, &cbBuf, &pvBufFree, pObjInfo->cbObject);
|
---|
[67134] | 1828 |
|
---|
| 1829 | uint64_t cbLeft = pObjInfo->cbObject;
|
---|
[98457] | 1830 | size_t cbBlock = rtZipTarFssWrite_GetBlockSize(pThis);
|
---|
[67134] | 1831 | while (cbLeft > 0)
|
---|
| 1832 | {
|
---|
| 1833 | size_t cbRead = cbLeft > cbBuf ? cbBuf : (size_t)cbLeft;
|
---|
| 1834 | rc = RTVfsIoStrmRead(hVfsIos, pbBuf, cbRead, true /*fBlocking*/, NULL);
|
---|
| 1835 | if (RT_FAILURE(rc))
|
---|
| 1836 | break;
|
---|
| 1837 |
|
---|
| 1838 | size_t cbToWrite = cbRead;
|
---|
[98457] | 1839 | if (cbRead & (cbBlock - 1))
|
---|
[67134] | 1840 | {
|
---|
[98457] | 1841 | size_t cbToZero = cbBlock - (cbRead & (cbBlock - 1));
|
---|
[67134] | 1842 | memset(&pbBuf[cbRead], 0, cbToZero);
|
---|
| 1843 | cbToWrite += cbToZero;
|
---|
| 1844 | }
|
---|
| 1845 |
|
---|
| 1846 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pbBuf, cbToWrite, true /*fBlocking*/, NULL);
|
---|
| 1847 | if (RT_FAILURE(rc))
|
---|
| 1848 | break;
|
---|
| 1849 | pThis->cbWritten += cbToWrite;
|
---|
| 1850 | cbLeft -= cbRead;
|
---|
| 1851 | }
|
---|
| 1852 |
|
---|
| 1853 | RTMemTmpFree(pvBufFree);
|
---|
| 1854 |
|
---|
[67116] | 1855 | if (RT_SUCCESS(rc))
|
---|
| 1856 | return VINF_SUCCESS;
|
---|
[34179] | 1857 | }
|
---|
[67116] | 1858 | pThis->rcFatal = rc;
|
---|
[34049] | 1859 | }
|
---|
[67116] | 1860 | return rc;
|
---|
[34049] | 1861 | }
|
---|
| 1862 |
|
---|
[34181] | 1863 |
|
---|
[34179] | 1864 | /**
|
---|
[67116] | 1865 | * Adds a symbolic link to the stream.
|
---|
[34179] | 1866 | *
|
---|
| 1867 | * @returns IPRT status code.
|
---|
[67116] | 1868 | * @param pThis The TAR writer instance.
|
---|
| 1869 | * @param pszPath The path to the object.
|
---|
| 1870 | * @param hVfsSymlink The symbolic link object to add.
|
---|
| 1871 | * @param pObjInfo The object information.
|
---|
| 1872 | * @param pszOwnerNm The owner name.
|
---|
| 1873 | * @param pszGroupNm The group name.
|
---|
[34179] | 1874 | */
|
---|
[67116] | 1875 | static int rtZipTarFssWriter_AddSymlink(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, RTVFSSYMLINK hVfsSymlink,
|
---|
| 1876 | PCRTFSOBJINFO pObjInfo, const char *pszOwnerNm, const char *pszGroupNm)
|
---|
[34179] | 1877 | {
|
---|
[34049] | 1878 | /*
|
---|
[67116] | 1879 | * Read the symlink target first and check that it's not too long.
|
---|
| 1880 | * Flip DOS slashes.
|
---|
[34049] | 1881 | */
|
---|
[67116] | 1882 | char szTarget[RTPATH_MAX];
|
---|
| 1883 | int rc = RTVfsSymlinkRead(hVfsSymlink, szTarget, sizeof(szTarget));
|
---|
| 1884 | if (RT_SUCCESS(rc))
|
---|
[34049] | 1885 | {
|
---|
[67253] | 1886 | #if RTPATH_STYLE != RTPATH_STR_F_STYLE_UNIX
|
---|
[67116] | 1887 | char *pszDosSlash = strchr(szTarget, '\\');
|
---|
| 1888 | while (pszDosSlash)
|
---|
[34179] | 1889 | {
|
---|
[67116] | 1890 | *pszDosSlash = '/';
|
---|
| 1891 | pszDosSlash = strchr(pszDosSlash + 1, '\\');
|
---|
[34179] | 1892 | }
|
---|
| 1893 | #endif
|
---|
[67116] | 1894 | size_t cchTarget = strlen(szTarget);
|
---|
[98457] | 1895 | if (rtZipTarFssWrite_IsTar(pThis))
|
---|
[67116] | 1896 | {
|
---|
[98457] | 1897 | if (cchTarget < sizeof(pThis->aHdrsTar[0].Common.linkname))
|
---|
[34179] | 1898 | {
|
---|
[98457] | 1899 | /*
|
---|
| 1900 | * Create a header, add the link target and push it out.
|
---|
| 1901 | */
|
---|
| 1902 | rc = rtZipTarFssWriter_ObjInfoToHdrTar(pThis, pszPath, pObjInfo, pszOwnerNm, pszGroupNm, UINT8_MAX);
|
---|
[67116] | 1903 | if (RT_SUCCESS(rc))
|
---|
| 1904 | {
|
---|
[98457] | 1905 | memcpy(pThis->aHdrsTar[0].Common.linkname, szTarget, cchTarget + 1);
|
---|
| 1906 | rc = rtZipTarFssWriter_ChecksumHdr(&pThis->aHdrsTar[0]);
|
---|
[67116] | 1907 | if (RT_SUCCESS(rc))
|
---|
| 1908 | {
|
---|
[98457] | 1909 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pThis->abHdrs, pThis->cHdrs * pThis->cbHdr,
|
---|
| 1910 | true /*fBlocking*/, NULL);
|
---|
| 1911 | if (RT_SUCCESS(rc))
|
---|
| 1912 | {
|
---|
| 1913 | pThis->cbWritten += pThis->cHdrs * pThis->cbHdr;
|
---|
| 1914 | return VINF_SUCCESS;
|
---|
| 1915 | }
|
---|
| 1916 | pThis->rcFatal = rc;
|
---|
[67116] | 1917 | }
|
---|
| 1918 | }
|
---|
[34179] | 1919 | }
|
---|
[98457] | 1920 | else
|
---|
| 1921 | {
|
---|
| 1922 | /** @todo implement gnu and pax long name extensions. */
|
---|
| 1923 | rc = VERR_TAR_NAME_TOO_LONG;
|
---|
| 1924 | }
|
---|
[67116] | 1925 | }
|
---|
| 1926 | else
|
---|
| 1927 | {
|
---|
[98457] | 1928 | /* CPIO stores the target path as file data after the header, without any zero terminator. */
|
---|
| 1929 | rc = rtZipTarFssWriter_ObjInfoToHdrCpio(pThis, pszPath, pObjInfo, pszOwnerNm, pszGroupNm);
|
---|
| 1930 | if (RT_SUCCESS(rc))
|
---|
| 1931 | {
|
---|
| 1932 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pThis->abHdrs, pThis->cHdrs * pThis->cbHdr,
|
---|
| 1933 | true /*fBlocking*/, NULL);
|
---|
| 1934 | if (RT_SUCCESS(rc))
|
---|
| 1935 | {
|
---|
| 1936 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, szTarget, cchTarget, true /*fBlocking*/, NULL);
|
---|
| 1937 | if (RT_SUCCESS(rc))
|
---|
| 1938 | {
|
---|
| 1939 | /* Need to pad the entry to a 4 byte aligned boundary. */
|
---|
| 1940 | size_t cbPad = RT_ALIGN_32(cchTarget, 4) - cchTarget;
|
---|
| 1941 | if (cbPad)
|
---|
| 1942 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, &pThis->Cpio.abPad[0], cbPad, true /*fBlocking*/, NULL);
|
---|
| 1943 | if (RT_SUCCESS(rc))
|
---|
| 1944 | {
|
---|
| 1945 | pThis->cbWritten += pThis->cHdrs * pThis->cbHdr + cbPad;
|
---|
| 1946 | return VINF_SUCCESS;
|
---|
| 1947 | }
|
---|
| 1948 | }
|
---|
| 1949 | }
|
---|
| 1950 | pThis->rcFatal = rc;
|
---|
| 1951 | }
|
---|
[67116] | 1952 | }
|
---|
[34049] | 1953 | }
|
---|
[67116] | 1954 | return rc;
|
---|
[34029] | 1955 | }
|
---|
| 1956 |
|
---|
| 1957 |
|
---|
[34179] | 1958 | /**
|
---|
[67116] | 1959 | * Adds a simple object to the stream.
|
---|
[34179] | 1960 | *
|
---|
[67116] | 1961 | * Simple objects only contains metadata, no actual data bits. Directories,
|
---|
| 1962 | * devices, fifos, sockets and such.
|
---|
[34179] | 1963 | *
|
---|
[67116] | 1964 | * @returns IPRT status code.
|
---|
| 1965 | * @param pThis The TAR writer instance.
|
---|
| 1966 | * @param pszPath The path to the object.
|
---|
| 1967 | * @param pObjInfo The object information.
|
---|
| 1968 | * @param pszOwnerNm The owner name.
|
---|
| 1969 | * @param pszGroupNm The group name.
|
---|
[34179] | 1970 | */
|
---|
[67116] | 1971 | static int rtZipTarFssWriter_AddSimpleObject(PRTZIPTARFSSTREAMWRITER pThis, const char *pszPath, PCRTFSOBJINFO pObjInfo,
|
---|
| 1972 | const char *pszOwnerNm, const char *pszGroupNm)
|
---|
[34179] | 1973 | {
|
---|
[67116] | 1974 | int rc = rtZipTarFssWriter_ObjInfoToHdr(pThis, pszPath, pObjInfo, pszOwnerNm, pszGroupNm, UINT8_MAX);
|
---|
| 1975 | if (RT_SUCCESS(rc))
|
---|
[34002] | 1976 | {
|
---|
[98457] | 1977 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pThis->abHdrs, pThis->cHdrs * pThis->cbHdr, true /*fBlocking*/, NULL);
|
---|
[67116] | 1978 | if (RT_SUCCESS(rc))
|
---|
| 1979 | {
|
---|
[98457] | 1980 | pThis->cbWritten += pThis->cHdrs * pThis->cbHdr;
|
---|
[67116] | 1981 | return VINF_SUCCESS;
|
---|
| 1982 | }
|
---|
| 1983 | pThis->rcFatal = rc;
|
---|
[34002] | 1984 | }
|
---|
[67116] | 1985 | return rc;
|
---|
[34002] | 1986 | }
|
---|
| 1987 |
|
---|
| 1988 |
|
---|
| 1989 | /**
|
---|
| 1990 | * @interface_method_impl{RTVFSOBJOPS,pfnClose}
|
---|
| 1991 | */
|
---|
[67116] | 1992 | static DECLCALLBACK(int) rtZipTarFssWriter_Close(void *pvThis)
|
---|
[34002] | 1993 | {
|
---|
[67116] | 1994 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis;
|
---|
[34045] | 1995 |
|
---|
[67149] | 1996 | rtZipTarFssWriter_CompleteCurrentPushFile(pThis);
|
---|
| 1997 |
|
---|
[34045] | 1998 | RTVfsIoStrmRelease(pThis->hVfsIos);
|
---|
| 1999 | pThis->hVfsIos = NIL_RTVFSIOSTREAM;
|
---|
| 2000 |
|
---|
[67134] | 2001 | if (pThis->hVfsFile != NIL_RTVFSFILE)
|
---|
| 2002 | {
|
---|
| 2003 | RTVfsFileRelease(pThis->hVfsFile);
|
---|
| 2004 | pThis->hVfsFile = NIL_RTVFSFILE;
|
---|
| 2005 | }
|
---|
| 2006 |
|
---|
[67253] | 2007 | if (pThis->pszOwner)
|
---|
| 2008 | {
|
---|
| 2009 | RTStrFree(pThis->pszOwner);
|
---|
| 2010 | pThis->pszOwner = NULL;
|
---|
| 2011 | }
|
---|
| 2012 | if (pThis->pszGroup)
|
---|
| 2013 | {
|
---|
| 2014 | RTStrFree(pThis->pszGroup);
|
---|
| 2015 | pThis->pszGroup = NULL;
|
---|
| 2016 | }
|
---|
| 2017 | if (pThis->pszPrefix)
|
---|
| 2018 | {
|
---|
| 2019 | RTStrFree(pThis->pszPrefix);
|
---|
| 2020 | pThis->pszPrefix = NULL;
|
---|
| 2021 | }
|
---|
| 2022 |
|
---|
[34002] | 2023 | return VINF_SUCCESS;
|
---|
| 2024 | }
|
---|
| 2025 |
|
---|
| 2026 |
|
---|
| 2027 | /**
|
---|
[34029] | 2028 | * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
|
---|
| 2029 | */
|
---|
[67116] | 2030 | static DECLCALLBACK(int) rtZipTarFssWriter_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
|
---|
[34029] | 2031 | {
|
---|
[67116] | 2032 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis;
|
---|
[34002] | 2033 | /* Take the lazy approach here, with the sideffect of providing some info
|
---|
| 2034 | that is actually kind of useful. */
|
---|
| 2035 | return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
|
---|
| 2036 | }
|
---|
| 2037 |
|
---|
| 2038 |
|
---|
| 2039 | /**
|
---|
[84192] | 2040 | * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
|
---|
| 2041 | */
|
---|
| 2042 | static DECLCALLBACK(int) rtZipTarFssWriter_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
|
---|
| 2043 | {
|
---|
| 2044 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis;
|
---|
| 2045 |
|
---|
| 2046 | /*
|
---|
| 2047 | * This only works in update mode and up to the point where
|
---|
| 2048 | * modifications takes place (truncating the archive or appending files).
|
---|
| 2049 | */
|
---|
[98457] | 2050 | AssertReturn(pThis->pReadTar || pThis->pReadCpio, VERR_ACCESS_DENIED);
|
---|
[84192] | 2051 | AssertReturn(pThis->fFlags & RTZIPTAR_C_UPDATE, VERR_ACCESS_DENIED);
|
---|
| 2052 |
|
---|
| 2053 | AssertReturn(!pThis->fWriting, VERR_WRONG_ORDER);
|
---|
| 2054 |
|
---|
[98457] | 2055 | if (rtZipTarFssWrite_IsTar(pThis))
|
---|
| 2056 | return rtZipTarFss_Next(pThis->pReadTar, ppszName, penmType, phVfsObj);
|
---|
| 2057 | else
|
---|
| 2058 | return rtZipCpioFss_Next(pThis->pReadCpio, ppszName, penmType, phVfsObj);
|
---|
[84192] | 2059 | }
|
---|
| 2060 |
|
---|
| 2061 |
|
---|
| 2062 | /**
|
---|
[67116] | 2063 | * @interface_method_impl{RTVFSFSSTREAMOPS,pfnAdd}
|
---|
[34002] | 2064 | */
|
---|
[67116] | 2065 | static DECLCALLBACK(int) rtZipTarFssWriter_Add(void *pvThis, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags)
|
---|
[34002] | 2066 | {
|
---|
[67116] | 2067 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis;
|
---|
[34002] | 2068 |
|
---|
| 2069 | /*
|
---|
[67149] | 2070 | * Before we continue we must complete any current push file and check rcFatal.
|
---|
[34002] | 2071 | */
|
---|
[67149] | 2072 | int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis);
|
---|
[84192] | 2073 | AssertRCReturn(rc, rc);
|
---|
[34002] | 2074 |
|
---|
| 2075 | /*
|
---|
[67116] | 2076 | * Query information about the object.
|
---|
[34002] | 2077 | */
|
---|
[67116] | 2078 | RTFSOBJINFO ObjInfo;
|
---|
[67149] | 2079 | rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_UNIX);
|
---|
[67116] | 2080 | AssertRCReturn(rc, rc);
|
---|
[34002] | 2081 |
|
---|
[67116] | 2082 | RTFSOBJINFO ObjOwnerName;
|
---|
| 2083 | rc = RTVfsObjQueryInfo(hVfsObj, &ObjOwnerName, RTFSOBJATTRADD_UNIX_OWNER);
|
---|
| 2084 | if (RT_FAILURE(rc) || ObjOwnerName.Attr.u.UnixOwner.szName[0] == '\0')
|
---|
| 2085 | strcpy(ObjOwnerName.Attr.u.UnixOwner.szName, "someone");
|
---|
[34002] | 2086 |
|
---|
[67116] | 2087 | RTFSOBJINFO ObjGrpName;
|
---|
| 2088 | rc = RTVfsObjQueryInfo(hVfsObj, &ObjGrpName, RTFSOBJATTRADD_UNIX_GROUP);
|
---|
| 2089 | if (RT_FAILURE(rc) || ObjGrpName.Attr.u.UnixGroup.szName[0] == '\0')
|
---|
| 2090 | strcpy(ObjGrpName.Attr.u.UnixGroup.szName, "somegroup");
|
---|
[34002] | 2091 |
|
---|
| 2092 | /*
|
---|
[84192] | 2093 | * Switch the stream into write mode if necessary.
|
---|
| 2094 | */
|
---|
| 2095 | rc = rtZipTarFssWriter_SwitchToWriteMode(pThis);
|
---|
| 2096 | AssertRCReturn(rc, rc);
|
---|
| 2097 |
|
---|
| 2098 | /*
|
---|
[67134] | 2099 | * Do type specific handling. File have several options and variations to
|
---|
| 2100 | * take into account, thus the mess.
|
---|
[34002] | 2101 | */
|
---|
[67116] | 2102 | if (RTFS_IS_FILE(ObjInfo.Attr.fMode))
|
---|
[34002] | 2103 | {
|
---|
[67116] | 2104 | RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
|
---|
| 2105 | AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_WRONG_TYPE);
|
---|
[67134] | 2106 |
|
---|
| 2107 | if (fFlags & RTVFSFSSTRM_ADD_F_STREAM)
|
---|
| 2108 | rc = rtZipTarFssWriter_AddFileStream(pThis, pszPath, hVfsIos, &ObjInfo,
|
---|
| 2109 | ObjOwnerName.Attr.u.UnixOwner.szName, ObjGrpName.Attr.u.UnixOwner.szName);
|
---|
| 2110 | else if ( !(pThis->fFlags & RTZIPTAR_C_SPARSE)
|
---|
[98457] | 2111 | || ObjInfo.cbObject < RTZIPTAR_MIN_SPARSE
|
---|
| 2112 | || !rtZipTarFssWrite_IsTar(pThis))
|
---|
[67134] | 2113 | rc = rtZipTarFssWriter_AddFile(pThis, pszPath, hVfsIos, &ObjInfo,
|
---|
| 2114 | ObjOwnerName.Attr.u.UnixOwner.szName, ObjGrpName.Attr.u.UnixOwner.szName);
|
---|
| 2115 | else
|
---|
| 2116 | {
|
---|
| 2117 | RTVFSFILE hVfsFile = RTVfsObjToFile(hVfsObj);
|
---|
| 2118 | if (hVfsFile != NIL_RTVFSFILE)
|
---|
| 2119 | {
|
---|
| 2120 | rc = rtZipTarFssWriter_AddFileSparse(pThis, pszPath, hVfsFile, hVfsIos, &ObjInfo,
|
---|
| 2121 | ObjOwnerName.Attr.u.UnixOwner.szName, ObjGrpName.Attr.u.UnixOwner.szName);
|
---|
| 2122 | RTVfsFileRelease(hVfsFile);
|
---|
| 2123 | }
|
---|
| 2124 | else
|
---|
| 2125 | rc = rtZipTarFssWriter_AddFile(pThis, pszPath, hVfsIos, &ObjInfo,
|
---|
| 2126 | ObjOwnerName.Attr.u.UnixOwner.szName, ObjGrpName.Attr.u.UnixOwner.szName);
|
---|
| 2127 | }
|
---|
[67116] | 2128 | RTVfsIoStrmRelease(hVfsIos);
|
---|
[34029] | 2129 | }
|
---|
[67116] | 2130 | else if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
|
---|
[34029] | 2131 | {
|
---|
[67116] | 2132 | RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
|
---|
| 2133 | AssertReturn(hVfsSymlink != NIL_RTVFSSYMLINK, VERR_WRONG_TYPE);
|
---|
| 2134 | rc = rtZipTarFssWriter_AddSymlink(pThis, pszPath, hVfsSymlink, &ObjInfo,
|
---|
| 2135 | ObjOwnerName.Attr.u.UnixOwner.szName, ObjGrpName.Attr.u.UnixOwner.szName);
|
---|
| 2136 | RTVfsSymlinkRelease(hVfsSymlink);
|
---|
[34029] | 2137 | }
|
---|
[67116] | 2138 | else
|
---|
| 2139 | rc = rtZipTarFssWriter_AddSimpleObject(pThis, pszPath, &ObjInfo,
|
---|
| 2140 | ObjOwnerName.Attr.u.UnixOwner.szName, ObjGrpName.Attr.u.UnixOwner.szName);
|
---|
[34029] | 2141 |
|
---|
[67116] | 2142 | return rc;
|
---|
[34002] | 2143 | }
|
---|
| 2144 |
|
---|
| 2145 |
|
---|
[67123] | 2146 | /**
|
---|
[67149] | 2147 | * @interface_method_impl{RTVFSFSSTREAMOPS,pfnPushFile}
|
---|
| 2148 | */
|
---|
| 2149 | static DECLCALLBACK(int) rtZipTarFssWriter_PushFile(void *pvThis, const char *pszPath, uint64_t cbFile, PCRTFSOBJINFO paObjInfo,
|
---|
| 2150 | uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)
|
---|
| 2151 | {
|
---|
| 2152 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis;
|
---|
| 2153 |
|
---|
| 2154 | /*
|
---|
| 2155 | * We can only deal with output of indeterminate length if the output is
|
---|
| 2156 | * seekable (see also rtZipTarFssWriter_AddFileStream).
|
---|
| 2157 | */
|
---|
| 2158 | AssertReturn(cbFile != UINT64_MAX || pThis->hVfsFile != NIL_RTVFSFILE, VERR_NOT_A_FILE);
|
---|
| 2159 | AssertReturn(RT_BOOL(cbFile == UINT64_MAX) == RT_BOOL(fFlags & RTVFSFSSTRM_ADD_F_STREAM), VERR_INVALID_FLAGS);
|
---|
| 2160 |
|
---|
| 2161 | /*
|
---|
| 2162 | * Before we continue we must complete any current push file and check rcFatal.
|
---|
| 2163 | */
|
---|
| 2164 | int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis);
|
---|
[84192] | 2165 | AssertRCReturn(rc, rc);
|
---|
[67149] | 2166 |
|
---|
| 2167 | /*
|
---|
| 2168 | * If no object info was provideded, fake up some.
|
---|
| 2169 | */
|
---|
| 2170 | const char *pszOwnerNm = "someone";
|
---|
| 2171 | const char *pszGroupNm = "somegroup";
|
---|
[98457] | 2172 | const size_t cbBlock = rtZipTarFssWrite_GetBlockSize(pThis);
|
---|
[67149] | 2173 | RTFSOBJINFO ObjInfo;
|
---|
| 2174 | if (cObjInfo == 0)
|
---|
| 2175 | {
|
---|
| 2176 | /* Fake up a info. */
|
---|
| 2177 | RT_ZERO(ObjInfo);
|
---|
| 2178 | ObjInfo.cbObject = cbFile != UINT64_MAX ? cbFile : 0;
|
---|
[98457] | 2179 | ObjInfo.cbAllocated = cbFile != UINT64_MAX ? RT_ALIGN_64(cbFile, cbBlock) : UINT64_MAX;
|
---|
[67149] | 2180 | RTTimeNow(&ObjInfo.ModificationTime);
|
---|
| 2181 | ObjInfo.BirthTime = ObjInfo.ModificationTime;
|
---|
| 2182 | ObjInfo.ChangeTime = ObjInfo.ModificationTime;
|
---|
| 2183 | ObjInfo.AccessTime = ObjInfo.ModificationTime;
|
---|
| 2184 | ObjInfo.Attr.fMode = RTFS_TYPE_FILE | 0666;
|
---|
| 2185 | ObjInfo.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
|
---|
| 2186 | ObjInfo.Attr.u.Unix.uid = NIL_RTUID;
|
---|
| 2187 | ObjInfo.Attr.u.Unix.gid = NIL_RTGID;
|
---|
| 2188 | ObjInfo.Attr.u.Unix.cHardlinks = 1;
|
---|
| 2189 | //ObjInfo.Attr.u.Unix.INodeIdDevice = 0;
|
---|
| 2190 | //ObjInfo.Attr.u.Unix.INodeId = 0;
|
---|
| 2191 | //ObjInfo.Attr.u.Unix.fFlags = 0;
|
---|
| 2192 | //ObjInfo.Attr.u.Unix.GenerationId = 0;
|
---|
| 2193 | //ObjInfo.Attr.u.Unix.Device = 0;
|
---|
| 2194 | }
|
---|
| 2195 | else
|
---|
| 2196 | {
|
---|
| 2197 | /* Make a copy of the object info and adjust the size, if necessary. */
|
---|
| 2198 | ObjInfo = paObjInfo[0];
|
---|
| 2199 | Assert(ObjInfo.Attr.enmAdditional == RTFSOBJATTRADD_UNIX);
|
---|
| 2200 | Assert(RTFS_IS_FILE(ObjInfo.Attr.fMode));
|
---|
| 2201 | if ((uint64_t)ObjInfo.cbObject != cbFile)
|
---|
| 2202 | {
|
---|
| 2203 | ObjInfo.cbObject = cbFile != UINT64_MAX ? cbFile : 0;
|
---|
[98457] | 2204 | ObjInfo.cbAllocated = cbFile != UINT64_MAX ? RT_ALIGN_64(cbFile, cbBlock) : UINT64_MAX;
|
---|
[67149] | 2205 | }
|
---|
| 2206 |
|
---|
| 2207 | /* Lookup the group and user names. */
|
---|
| 2208 | for (uint32_t i = 0; i < cObjInfo; i++)
|
---|
| 2209 | if ( paObjInfo[i].Attr.enmAdditional == RTFSOBJATTRADD_UNIX_OWNER
|
---|
| 2210 | && paObjInfo[i].Attr.u.UnixOwner.szName[0] != '\0')
|
---|
| 2211 | pszOwnerNm = paObjInfo[i].Attr.u.UnixOwner.szName;
|
---|
| 2212 | else if ( paObjInfo[i].Attr.enmAdditional == RTFSOBJATTRADD_UNIX_GROUP
|
---|
| 2213 | && paObjInfo[i].Attr.u.UnixGroup.szName[0] != '\0')
|
---|
| 2214 | pszGroupNm = paObjInfo[i].Attr.u.UnixGroup.szName;
|
---|
| 2215 | }
|
---|
| 2216 |
|
---|
| 2217 | /*
|
---|
[84192] | 2218 | * Switch the stream into write mode if necessary.
|
---|
| 2219 | */
|
---|
| 2220 | rc = rtZipTarFssWriter_SwitchToWriteMode(pThis);
|
---|
| 2221 | AssertRCReturn(rc, rc);
|
---|
| 2222 |
|
---|
| 2223 | /*
|
---|
[67149] | 2224 | * Create an I/O stream object for the caller to use.
|
---|
| 2225 | */
|
---|
[67166] | 2226 | RTFOFF const offHdr = RTVfsIoStrmTell(pThis->hVfsIos);
|
---|
| 2227 | AssertReturn(offHdr >= 0, (int)offHdr);
|
---|
| 2228 |
|
---|
[67149] | 2229 | PRTZIPTARFSSTREAMWRITERPUSH pPush;
|
---|
| 2230 | RTVFSIOSTREAM hVfsIos;
|
---|
| 2231 | if (pThis->hVfsFile == NIL_RTVFSFILE)
|
---|
| 2232 | {
|
---|
| 2233 | rc = RTVfsNewIoStream(&g_rtZipTarWriterIoStrmOps, sizeof(*pPush), RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
|
---|
| 2234 | &hVfsIos, (void **)&pPush);
|
---|
| 2235 | if (RT_FAILURE(rc))
|
---|
| 2236 | return rc;
|
---|
| 2237 | }
|
---|
| 2238 | else
|
---|
| 2239 | {
|
---|
| 2240 | RTVFSFILE hVfsFile;
|
---|
| 2241 | rc = RTVfsNewFile(&g_rtZipTarWriterFileOps, sizeof(*pPush), RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
|
---|
| 2242 | &hVfsFile, (void **)&pPush);
|
---|
| 2243 | if (RT_FAILURE(rc))
|
---|
| 2244 | return rc;
|
---|
| 2245 | hVfsIos = RTVfsFileToIoStream(hVfsFile);
|
---|
| 2246 | RTVfsFileRelease(hVfsFile);
|
---|
| 2247 | }
|
---|
| 2248 | pPush->pParent = NULL;
|
---|
| 2249 | pPush->cbExpected = cbFile;
|
---|
[67166] | 2250 | pPush->offHdr = (uint64_t)offHdr;
|
---|
[67149] | 2251 | pPush->offData = 0;
|
---|
| 2252 | pPush->offCurrent = 0;
|
---|
| 2253 | pPush->cbCurrent = 0;
|
---|
| 2254 | pPush->ObjInfo = ObjInfo;
|
---|
[67166] | 2255 | pPush->fOpenEnded = cbFile == UINT64_MAX;
|
---|
[67149] | 2256 |
|
---|
| 2257 | /*
|
---|
| 2258 | * Produce and write file headers.
|
---|
| 2259 | */
|
---|
| 2260 | rc = rtZipTarFssWriter_ObjInfoToHdr(pThis, pszPath, &ObjInfo, pszOwnerNm, pszGroupNm, RTZIPTAR_TF_NORMAL);
|
---|
| 2261 | if (RT_SUCCESS(rc))
|
---|
| 2262 | {
|
---|
[98457] | 2263 | size_t cbHdrs = pThis->cHdrs * pThis->cbHdr;
|
---|
| 2264 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pThis->abHdrs, cbHdrs, true /*fBlocking*/, NULL);
|
---|
[67149] | 2265 | if (RT_SUCCESS(rc))
|
---|
| 2266 | {
|
---|
[67166] | 2267 | pThis->cbWritten += cbHdrs;
|
---|
[67149] | 2268 |
|
---|
| 2269 | /*
|
---|
| 2270 | * Complete the object and return.
|
---|
| 2271 | */
|
---|
[67166] | 2272 | pPush->offData = pPush->offHdr + cbHdrs;
|
---|
| 2273 | if (cbFile == UINT64_MAX)
|
---|
| 2274 | pPush->cbExpected = (uint64_t)(RTFOFF_MAX - _4K) - pPush->offData;
|
---|
[67149] | 2275 | pPush->pParent = pThis;
|
---|
| 2276 | pThis->pPush = pPush;
|
---|
| 2277 |
|
---|
| 2278 | *phVfsIos = hVfsIos;
|
---|
| 2279 | return VINF_SUCCESS;
|
---|
| 2280 | }
|
---|
| 2281 | pThis->rcFatal = rc;
|
---|
| 2282 | }
|
---|
| 2283 |
|
---|
| 2284 | RTVfsIoStrmRelease(hVfsIos);
|
---|
| 2285 | return rc;
|
---|
| 2286 | }
|
---|
| 2287 |
|
---|
| 2288 |
|
---|
| 2289 | /**
|
---|
[67123] | 2290 | * @interface_method_impl{RTVFSFSSTREAMOPS,pfnEnd}
|
---|
| 2291 | */
|
---|
| 2292 | static DECLCALLBACK(int) rtZipTarFssWriter_End(void *pvThis)
|
---|
| 2293 | {
|
---|
| 2294 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)pvThis;
|
---|
[67149] | 2295 |
|
---|
| 2296 | /*
|
---|
| 2297 | * Make sure to complete any pending push file and that rcFatal is fine.
|
---|
| 2298 | */
|
---|
| 2299 | int rc = rtZipTarFssWriter_CompleteCurrentPushFile(pThis);
|
---|
[67134] | 2300 | if (RT_SUCCESS(rc))
|
---|
[67123] | 2301 | {
|
---|
[98457] | 2302 | if (rtZipTarFssWrite_IsTar(pThis))
|
---|
| 2303 | {
|
---|
| 2304 | /*
|
---|
| 2305 | * There are supposed to be two zero headers at the end of the archive.
|
---|
| 2306 | * GNU tar may write more because of the way it does buffering,
|
---|
| 2307 | * libarchive OTOH writes exactly two.
|
---|
| 2308 | */
|
---|
| 2309 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, g_abRTZero4K, RTZIPTAR_BLOCKSIZE * 2, true /*fBlocking*/, NULL);
|
---|
| 2310 | if (RT_SUCCESS(rc))
|
---|
| 2311 | pThis->cbWritten += RTZIPTAR_BLOCKSIZE * 2;
|
---|
| 2312 | }
|
---|
| 2313 | else
|
---|
| 2314 | {
|
---|
| 2315 | /* CPIO has a special trailer marker. */
|
---|
| 2316 | RTFSOBJINFO ObjInfoEos; RT_ZERO(ObjInfoEos);
|
---|
| 2317 | rc = rtZipTarFssWriter_ObjInfoToHdrCpio(pThis, CPIO_EOS_FILE_NAME, &ObjInfoEos, NULL, NULL);
|
---|
| 2318 | if (RT_SUCCESS(rc))
|
---|
| 2319 | rc = RTVfsIoStrmWrite(pThis->hVfsIos, pThis->abHdrs, pThis->cbHdr, true /*fBlocking*/, NULL);
|
---|
| 2320 | if (RT_SUCCESS(rc))
|
---|
| 2321 | pThis->cbWritten += pThis->cbHdr;
|
---|
| 2322 | }
|
---|
[67134] | 2323 | if (RT_SUCCESS(rc))
|
---|
| 2324 | {
|
---|
| 2325 | /*
|
---|
| 2326 | * Flush the output.
|
---|
| 2327 | */
|
---|
| 2328 | rc = RTVfsIoStrmFlush(pThis->hVfsIos);
|
---|
[84192] | 2329 |
|
---|
| 2330 | /*
|
---|
| 2331 | * If we're in update mode, set the end-of-file here to make sure
|
---|
| 2332 | * unwanted bytes are really discarded.
|
---|
| 2333 | */
|
---|
| 2334 | if (RT_SUCCESS(rc) && (pThis->fFlags & RTZIPTAR_C_UPDATE))
|
---|
| 2335 | {
|
---|
| 2336 | RTFOFF cbTarFile = RTVfsFileTell(pThis->hVfsFile);
|
---|
| 2337 | if (cbTarFile >= 0)
|
---|
| 2338 | rc = RTVfsFileSetSize(pThis->hVfsFile, (uint64_t)cbTarFile, RTVFSFILE_SIZE_F_NORMAL);
|
---|
| 2339 | else
|
---|
| 2340 | rc = (int)cbTarFile;
|
---|
| 2341 | }
|
---|
| 2342 |
|
---|
| 2343 | /*
|
---|
| 2344 | * Success?
|
---|
| 2345 | */
|
---|
[67134] | 2346 | if (RT_SUCCESS(rc))
|
---|
| 2347 | return rc;
|
---|
| 2348 | }
|
---|
| 2349 | pThis->rcFatal = rc;
|
---|
[67123] | 2350 | }
|
---|
[67134] | 2351 | return rc;
|
---|
[67123] | 2352 | }
|
---|
[34002] | 2353 |
|
---|
[67123] | 2354 |
|
---|
[34002] | 2355 | /**
|
---|
| 2356 | * Tar filesystem stream operations.
|
---|
| 2357 | */
|
---|
[67253] | 2358 | static const RTVFSFSSTREAMOPS g_rtZipTarFssOps =
|
---|
[34002] | 2359 | {
|
---|
| 2360 | { /* Obj */
|
---|
| 2361 | RTVFSOBJOPS_VERSION,
|
---|
| 2362 | RTVFSOBJTYPE_FS_STREAM,
|
---|
[67116] | 2363 | "TarFsStreamWriter",
|
---|
| 2364 | rtZipTarFssWriter_Close,
|
---|
| 2365 | rtZipTarFssWriter_QueryInfo,
|
---|
[94291] | 2366 | NULL,
|
---|
[34002] | 2367 | RTVFSOBJOPS_VERSION
|
---|
| 2368 | },
|
---|
| 2369 | RTVFSFSSTREAMOPS_VERSION,
|
---|
| 2370 | 0,
|
---|
[84192] | 2371 | rtZipTarFssWriter_Next,
|
---|
[67116] | 2372 | rtZipTarFssWriter_Add,
|
---|
[67149] | 2373 | rtZipTarFssWriter_PushFile,
|
---|
[67123] | 2374 | rtZipTarFssWriter_End,
|
---|
[34002] | 2375 | RTVFSFSSTREAMOPS_VERSION
|
---|
| 2376 | };
|
---|
| 2377 |
|
---|
| 2378 |
|
---|
[67123] | 2379 | RTDECL(int) RTZipTarFsStreamToIoStream(RTVFSIOSTREAM hVfsIosOut, RTZIPTARFORMAT enmFormat,
|
---|
| 2380 | uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
|
---|
[34002] | 2381 | {
|
---|
| 2382 | /*
|
---|
| 2383 | * Input validation.
|
---|
| 2384 | */
|
---|
| 2385 | AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
|
---|
| 2386 | *phVfsFss = NIL_RTVFSFSSTREAM;
|
---|
[67116] | 2387 | AssertPtrReturn(hVfsIosOut, VERR_INVALID_HANDLE);
|
---|
[67123] | 2388 | AssertReturn(enmFormat > RTZIPTARFORMAT_INVALID && enmFormat < RTZIPTARFORMAT_END, VERR_INVALID_PARAMETER);
|
---|
| 2389 | AssertReturn(!(fFlags & ~RTZIPTAR_C_VALID_MASK), VERR_INVALID_FLAGS);
|
---|
[84192] | 2390 | AssertReturn(!(fFlags & RTZIPTAR_C_UPDATE), VERR_NOT_SUPPORTED); /* Must use RTZipTarFsStreamForFile! */
|
---|
[34002] | 2391 |
|
---|
[67123] | 2392 | if (enmFormat == RTZIPTARFORMAT_DEFAULT)
|
---|
| 2393 | enmFormat = RTZIPTARFORMAT_GNU;
|
---|
[67134] | 2394 | AssertReturn( enmFormat == RTZIPTARFORMAT_GNU
|
---|
| 2395 | || enmFormat == RTZIPTARFORMAT_USTAR
|
---|
[98457] | 2396 | || enmFormat == RTZIPTARFORMAT_CPIO_ASCII_NEW
|
---|
[67134] | 2397 | , VERR_NOT_IMPLEMENTED); /* Only implementing GNU and USTAR output at the moment. */
|
---|
[67123] | 2398 |
|
---|
[67116] | 2399 | uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosOut);
|
---|
[34002] | 2400 | AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
|
---|
| 2401 |
|
---|
| 2402 | /*
|
---|
| 2403 | * Retain the input stream and create a new filesystem stream handle.
|
---|
| 2404 | */
|
---|
[67116] | 2405 | PRTZIPTARFSSTREAMWRITER pThis;
|
---|
| 2406 | RTVFSFSSTREAM hVfsFss;
|
---|
[84192] | 2407 | int rc = RTVfsNewFsStream(&g_rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE,
|
---|
[67116] | 2408 | &hVfsFss, (void **)&pThis);
|
---|
[34002] | 2409 | if (RT_SUCCESS(rc))
|
---|
| 2410 | {
|
---|
[67253] | 2411 | pThis->hVfsIos = hVfsIosOut;
|
---|
| 2412 | pThis->hVfsFile = RTVfsIoStrmToFile(hVfsIosOut);
|
---|
[67134] | 2413 |
|
---|
[67253] | 2414 | pThis->enmFormat = enmFormat;
|
---|
| 2415 | pThis->fFlags = fFlags;
|
---|
| 2416 | pThis->rcFatal = VINF_SUCCESS;
|
---|
[34002] | 2417 |
|
---|
[67253] | 2418 | pThis->uidOwner = NIL_RTUID;
|
---|
| 2419 | pThis->pszOwner = NULL;
|
---|
| 2420 | pThis->gidGroup = NIL_RTGID;
|
---|
| 2421 | pThis->pszGroup = NULL;
|
---|
| 2422 | pThis->pszPrefix = NULL;
|
---|
| 2423 | pThis->pModTime = NULL;
|
---|
| 2424 | pThis->fFileModeAndMask = ~(RTFMODE)0;
|
---|
| 2425 | pThis->fFileModeOrMask = 0;
|
---|
| 2426 | pThis->fDirModeAndMask = ~(RTFMODE)0;
|
---|
| 2427 | pThis->fDirModeOrMask = 0;
|
---|
[84192] | 2428 | pThis->fWriting = true;
|
---|
[67253] | 2429 |
|
---|
[34002] | 2430 | *phVfsFss = hVfsFss;
|
---|
| 2431 | return VINF_SUCCESS;
|
---|
| 2432 | }
|
---|
| 2433 |
|
---|
[67116] | 2434 | RTVfsIoStrmRelease(hVfsIosOut);
|
---|
[34002] | 2435 | return rc;
|
---|
| 2436 | }
|
---|
| 2437 |
|
---|
[67253] | 2438 |
|
---|
[84192] | 2439 | RTDECL(int) RTZipTarFsStreamForFile(RTVFSFILE hVfsFile, RTZIPTARFORMAT enmFormat, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
|
---|
| 2440 | {
|
---|
| 2441 | /*
|
---|
| 2442 | * Input validation.
|
---|
| 2443 | */
|
---|
| 2444 | AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
|
---|
| 2445 | *phVfsFss = NIL_RTVFSFSSTREAM;
|
---|
[84207] | 2446 | AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
|
---|
[84192] | 2447 | AssertReturn(enmFormat > RTZIPTARFORMAT_INVALID && enmFormat < RTZIPTARFORMAT_END, VERR_INVALID_PARAMETER);
|
---|
| 2448 | AssertReturn(!(fFlags & ~RTZIPTAR_C_VALID_MASK), VERR_INVALID_FLAGS);
|
---|
| 2449 |
|
---|
| 2450 | if (enmFormat == RTZIPTARFORMAT_DEFAULT)
|
---|
| 2451 | enmFormat = RTZIPTARFORMAT_GNU;
|
---|
| 2452 | AssertReturn( enmFormat == RTZIPTARFORMAT_GNU
|
---|
| 2453 | || enmFormat == RTZIPTARFORMAT_USTAR
|
---|
[98457] | 2454 | || enmFormat == RTZIPTARFORMAT_CPIO_ASCII_NEW
|
---|
| 2455 | , VERR_NOT_IMPLEMENTED); /* Only implementing GNU, USTAR and CPIO output at the moment. */
|
---|
[84192] | 2456 |
|
---|
| 2457 | RTFOFF const offStart = RTVfsFileTell(hVfsFile);
|
---|
| 2458 | AssertReturn(offStart >= 0, (int)offStart);
|
---|
| 2459 |
|
---|
| 2460 | uint32_t cRefs = RTVfsFileRetain(hVfsFile);
|
---|
| 2461 | AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
|
---|
| 2462 |
|
---|
| 2463 | RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hVfsFile);
|
---|
| 2464 | AssertReturnStmt(hVfsIos != NIL_RTVFSIOSTREAM, RTVfsFileRelease(hVfsFile), VERR_INVALID_HANDLE);
|
---|
| 2465 |
|
---|
| 2466 | /*
|
---|
| 2467 | * Retain the input stream and create a new filesystem stream handle.
|
---|
| 2468 | */
|
---|
| 2469 | PRTZIPTARFSSTREAMWRITER pThis;
|
---|
[98457] | 2470 | size_t const cbThis = sizeof(*pThis) + ( fFlags & RTZIPTAR_C_UPDATE
|
---|
| 2471 | ? enmFormat == RTZIPTARFORMAT_CPIO_ASCII_NEW
|
---|
| 2472 | ? sizeof(*pThis->pReadTar)
|
---|
| 2473 | : sizeof(*pThis->pReadCpio)
|
---|
| 2474 | : 0);
|
---|
[84192] | 2475 | RTVFSFSSTREAM hVfsFss;
|
---|
[84207] | 2476 | int rc = RTVfsNewFsStream(&g_rtZipTarFssOps, cbThis, NIL_RTVFS, NIL_RTVFSLOCK,
|
---|
| 2477 | fFlags & RTZIPTAR_C_UPDATE ? RTFILE_O_READWRITE : RTFILE_O_WRITE,
|
---|
[84192] | 2478 | &hVfsFss, (void **)&pThis);
|
---|
| 2479 | if (RT_SUCCESS(rc))
|
---|
| 2480 | {
|
---|
| 2481 | pThis->hVfsIos = hVfsIos;
|
---|
| 2482 | pThis->hVfsFile = hVfsFile;
|
---|
| 2483 |
|
---|
| 2484 | pThis->enmFormat = enmFormat;
|
---|
| 2485 | pThis->fFlags = fFlags;
|
---|
| 2486 | pThis->rcFatal = VINF_SUCCESS;
|
---|
| 2487 |
|
---|
| 2488 | pThis->uidOwner = NIL_RTUID;
|
---|
| 2489 | pThis->pszOwner = NULL;
|
---|
| 2490 | pThis->gidGroup = NIL_RTGID;
|
---|
| 2491 | pThis->pszGroup = NULL;
|
---|
| 2492 | pThis->pszPrefix = NULL;
|
---|
| 2493 | pThis->pModTime = NULL;
|
---|
| 2494 | pThis->fFileModeAndMask = ~(RTFMODE)0;
|
---|
| 2495 | pThis->fFileModeOrMask = 0;
|
---|
| 2496 | pThis->fDirModeAndMask = ~(RTFMODE)0;
|
---|
| 2497 | pThis->fDirModeOrMask = 0;
|
---|
| 2498 | if (!(fFlags & RTZIPTAR_C_UPDATE))
|
---|
| 2499 | pThis->fWriting = true;
|
---|
| 2500 | else
|
---|
| 2501 | {
|
---|
| 2502 | pThis->fWriting = false;
|
---|
[98457] | 2503 | if (rtZipTarFssWrite_IsTar(pThis))
|
---|
| 2504 | {
|
---|
| 2505 | pThis->pReadTar = (PRTZIPTARFSSTREAM)(pThis + 1);
|
---|
| 2506 | rtZipTarReaderInit(pThis->pReadTar, hVfsIos, (uint64_t)offStart);
|
---|
| 2507 | }
|
---|
| 2508 | else
|
---|
| 2509 | {
|
---|
| 2510 | pThis->pReadCpio = (PRTZIPCPIOFSSTREAM)(pThis + 1);
|
---|
| 2511 | rtZipCpioReaderInit(pThis->pReadCpio, hVfsIos, (uint64_t)offStart);
|
---|
| 2512 | }
|
---|
[84192] | 2513 | }
|
---|
| 2514 |
|
---|
| 2515 | *phVfsFss = hVfsFss;
|
---|
| 2516 | return VINF_SUCCESS;
|
---|
| 2517 | }
|
---|
| 2518 |
|
---|
| 2519 | RTVfsIoStrmRelease(hVfsIos);
|
---|
| 2520 | RTVfsFileRelease(hVfsFile);
|
---|
| 2521 | return rc;
|
---|
| 2522 | }
|
---|
| 2523 |
|
---|
| 2524 |
|
---|
[67253] | 2525 | RTDECL(int) RTZipTarFsStreamSetOwner(RTVFSFSSTREAM hVfsFss, RTUID uid, const char *pszOwner)
|
---|
| 2526 | {
|
---|
| 2527 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)RTVfsFsStreamToPrivate(hVfsFss, &g_rtZipTarFssOps);
|
---|
| 2528 | AssertReturn(pThis, VERR_WRONG_TYPE);
|
---|
| 2529 |
|
---|
| 2530 | pThis->uidOwner = uid;
|
---|
| 2531 | if (pThis->pszOwner)
|
---|
| 2532 | {
|
---|
| 2533 | RTStrFree(pThis->pszOwner);
|
---|
| 2534 | pThis->pszOwner = NULL;
|
---|
| 2535 | }
|
---|
| 2536 | if (pszOwner)
|
---|
| 2537 | {
|
---|
| 2538 | pThis->pszOwner = RTStrDup(pszOwner);
|
---|
| 2539 | AssertReturn(pThis->pszOwner, VERR_NO_STR_MEMORY);
|
---|
| 2540 | }
|
---|
| 2541 |
|
---|
| 2542 | return VINF_SUCCESS;
|
---|
| 2543 | }
|
---|
| 2544 |
|
---|
| 2545 |
|
---|
| 2546 | RTDECL(int) RTZipTarFsStreamSetGroup(RTVFSFSSTREAM hVfsFss, RTGID gid, const char *pszGroup)
|
---|
| 2547 | {
|
---|
| 2548 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)RTVfsFsStreamToPrivate(hVfsFss, &g_rtZipTarFssOps);
|
---|
| 2549 | AssertReturn(pThis, VERR_WRONG_TYPE);
|
---|
| 2550 |
|
---|
| 2551 | pThis->gidGroup = gid;
|
---|
| 2552 | if (pThis->pszGroup)
|
---|
| 2553 | {
|
---|
| 2554 | RTStrFree(pThis->pszGroup);
|
---|
| 2555 | pThis->pszGroup = NULL;
|
---|
| 2556 | }
|
---|
| 2557 | if (pszGroup)
|
---|
| 2558 | {
|
---|
| 2559 | pThis->pszGroup = RTStrDup(pszGroup);
|
---|
| 2560 | AssertReturn(pThis->pszGroup, VERR_NO_STR_MEMORY);
|
---|
| 2561 | }
|
---|
| 2562 |
|
---|
| 2563 | return VINF_SUCCESS;
|
---|
| 2564 | }
|
---|
| 2565 |
|
---|
| 2566 |
|
---|
| 2567 | RTDECL(int) RTZipTarFsStreamSetPrefix(RTVFSFSSTREAM hVfsFss, const char *pszPrefix)
|
---|
| 2568 | {
|
---|
| 2569 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)RTVfsFsStreamToPrivate(hVfsFss, &g_rtZipTarFssOps);
|
---|
| 2570 | AssertReturn(pThis, VERR_WRONG_TYPE);
|
---|
| 2571 | AssertReturn(!pszPrefix || *pszPrefix, VERR_INVALID_NAME);
|
---|
| 2572 |
|
---|
| 2573 | if (pThis->pszPrefix)
|
---|
| 2574 | {
|
---|
| 2575 | RTStrFree(pThis->pszPrefix);
|
---|
| 2576 | pThis->pszPrefix = NULL;
|
---|
| 2577 | pThis->cchPrefix = 0;
|
---|
| 2578 | }
|
---|
| 2579 | if (pszPrefix)
|
---|
| 2580 | {
|
---|
| 2581 | /*
|
---|
| 2582 | * Make a copy of the prefix, make sure it ends with a slash,
|
---|
| 2583 | * then flip DOS slashes.
|
---|
| 2584 | */
|
---|
| 2585 | size_t cchPrefix = strlen(pszPrefix);
|
---|
| 2586 | char *pszCopy = RTStrAlloc(cchPrefix + 3);
|
---|
| 2587 | AssertReturn(pszCopy, VERR_NO_STR_MEMORY);
|
---|
| 2588 | memcpy(pszCopy, pszPrefix, cchPrefix + 1);
|
---|
| 2589 |
|
---|
| 2590 | RTPathEnsureTrailingSeparator(pszCopy, cchPrefix + 3);
|
---|
| 2591 |
|
---|
| 2592 | #if RTPATH_STYLE != RTPATH_STR_F_STYLE_UNIX
|
---|
| 2593 | char *pszDosSlash = strchr(pszCopy, '\\');
|
---|
| 2594 | while (pszDosSlash)
|
---|
| 2595 | {
|
---|
| 2596 | *pszDosSlash = '/';
|
---|
| 2597 | pszDosSlash = strchr(pszDosSlash + 1, '\\');
|
---|
| 2598 | }
|
---|
| 2599 | #endif
|
---|
| 2600 |
|
---|
| 2601 | pThis->cchPrefix = cchPrefix + strlen(&pszCopy[cchPrefix]);
|
---|
| 2602 | pThis->pszPrefix = pszCopy;
|
---|
| 2603 | }
|
---|
| 2604 |
|
---|
| 2605 | return VINF_SUCCESS;
|
---|
| 2606 | }
|
---|
| 2607 |
|
---|
| 2608 |
|
---|
| 2609 | RTDECL(int) RTZipTarFsStreamSetModTime(RTVFSFSSTREAM hVfsFss, PCRTTIMESPEC pModificationTime)
|
---|
| 2610 | {
|
---|
| 2611 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)RTVfsFsStreamToPrivate(hVfsFss, &g_rtZipTarFssOps);
|
---|
| 2612 | AssertReturn(pThis, VERR_WRONG_TYPE);
|
---|
| 2613 |
|
---|
| 2614 | if (pModificationTime)
|
---|
| 2615 | {
|
---|
| 2616 | pThis->ModTime = *pModificationTime;
|
---|
| 2617 | pThis->pModTime = &pThis->ModTime;
|
---|
| 2618 | }
|
---|
| 2619 | else
|
---|
| 2620 | pThis->pModTime = NULL;
|
---|
| 2621 |
|
---|
| 2622 | return VINF_SUCCESS;
|
---|
| 2623 | }
|
---|
| 2624 |
|
---|
| 2625 |
|
---|
| 2626 | RTDECL(int) RTZipTarFsStreamSetFileMode(RTVFSFSSTREAM hVfsFss, RTFMODE fAndMode, RTFMODE fOrMode)
|
---|
| 2627 | {
|
---|
| 2628 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)RTVfsFsStreamToPrivate(hVfsFss, &g_rtZipTarFssOps);
|
---|
| 2629 | AssertReturn(pThis, VERR_WRONG_TYPE);
|
---|
| 2630 |
|
---|
| 2631 | pThis->fFileModeAndMask = fAndMode | ~RTFS_UNIX_ALL_PERMS;
|
---|
| 2632 | pThis->fFileModeOrMask = fOrMode & RTFS_UNIX_ALL_PERMS;
|
---|
| 2633 | return VINF_SUCCESS;
|
---|
| 2634 | }
|
---|
| 2635 |
|
---|
| 2636 |
|
---|
| 2637 | RTDECL(int) RTZipTarFsStreamSetDirMode(RTVFSFSSTREAM hVfsFss, RTFMODE fAndMode, RTFMODE fOrMode)
|
---|
| 2638 | {
|
---|
| 2639 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)RTVfsFsStreamToPrivate(hVfsFss, &g_rtZipTarFssOps);
|
---|
| 2640 | AssertReturn(pThis, VERR_WRONG_TYPE);
|
---|
| 2641 |
|
---|
| 2642 | pThis->fDirModeAndMask = fAndMode | ~RTFS_UNIX_ALL_PERMS;
|
---|
| 2643 | pThis->fDirModeOrMask = fOrMode & RTFS_UNIX_ALL_PERMS;
|
---|
| 2644 | return VINF_SUCCESS;
|
---|
| 2645 | }
|
---|
| 2646 |
|
---|
[84192] | 2647 |
|
---|
| 2648 | RTDECL(int) RTZipTarFsStreamTruncate(RTVFSFSSTREAM hVfsFss, RTVFSOBJ hVfsObj, bool fAfter)
|
---|
| 2649 | {
|
---|
| 2650 | /*
|
---|
| 2651 | * Translate and validate the input.
|
---|
| 2652 | */
|
---|
| 2653 | PRTZIPTARFSSTREAMWRITER pThis = (PRTZIPTARFSSTREAMWRITER)RTVfsFsStreamToPrivate(hVfsFss, &g_rtZipTarFssOps);
|
---|
| 2654 | AssertReturn(pThis, VERR_WRONG_TYPE);
|
---|
| 2655 |
|
---|
| 2656 | AssertReturn(hVfsObj != NIL_RTVFSOBJ, VERR_INVALID_HANDLE);
|
---|
[98457] | 2657 | AssertReturn(pThis->pReadTar || pThis->pReadCpio, VERR_ACCESS_DENIED);
|
---|
[84192] | 2658 | AssertReturn(pThis->fFlags & RTZIPTAR_C_UPDATE, VERR_ACCESS_DENIED);
|
---|
| 2659 | AssertReturn(!pThis->fWriting, VERR_WRONG_ORDER);
|
---|
| 2660 |
|
---|
[98457] | 2661 | int rc;
|
---|
| 2662 | if (rtZipTarFssWrite_IsTar(pThis))
|
---|
| 2663 | {
|
---|
| 2664 | PRTZIPTARBASEOBJ pThisObj = rtZipTarFsStreamBaseObjToPrivate(pThis->pReadTar, hVfsObj);
|
---|
| 2665 | AssertReturn(pThisObj, VERR_NOT_OWNER);
|
---|
| 2666 |
|
---|
| 2667 | /*
|
---|
| 2668 | * Seek to the desired cut-off point and indicate that we've switched to writing.
|
---|
| 2669 | */
|
---|
| 2670 | rc = RTVfsFileSeek(pThis->hVfsFile, fAfter ? pThisObj->offNextHdr : pThisObj->offHdr,
|
---|
[84192] | 2671 | RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
|
---|
[98457] | 2672 | }
|
---|
| 2673 | else
|
---|
| 2674 | {
|
---|
| 2675 | PRTZIPCPIOBASEOBJ pThisObj = rtZipCpioFsStreamBaseObjToPrivate(pThis->pReadCpio, hVfsObj);
|
---|
| 2676 | AssertReturn(pThisObj, VERR_NOT_OWNER);
|
---|
| 2677 |
|
---|
| 2678 | /*
|
---|
| 2679 | * Seek to the desired cut-off point and indicate that we've switched to writing.
|
---|
| 2680 | */
|
---|
| 2681 | rc = RTVfsFileSeek(pThis->hVfsFile, fAfter ? pThisObj->offNextHdr : pThisObj->offHdr,
|
---|
| 2682 | RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
|
---|
| 2683 | }
|
---|
[84192] | 2684 | if (RT_SUCCESS(rc))
|
---|
| 2685 | pThis->fWriting = true;
|
---|
| 2686 | else
|
---|
| 2687 | pThis->rcFatal = rc;
|
---|
| 2688 | return rc;
|
---|
| 2689 | }
|
---|
| 2690 |
|
---|