1 | /* $Id: isomakerimport.cpp 67511 2017-06-20 14:30:30Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * IPRT - ISO Image Maker, Import Existing Image.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2017 Oracle Corporation
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
12 | * General Public License (GPL) as published by the Free Software
|
---|
13 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
16 | *
|
---|
17 | * The contents of this file may alternatively be used under the terms
|
---|
18 | * of the Common Development and Distribution License Version 1.0
|
---|
19 | * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
|
---|
20 | * VirtualBox OSE distribution, in which case the provisions of the
|
---|
21 | * CDDL are applicable instead of those of the GPL.
|
---|
22 | *
|
---|
23 | * You may elect to license modified versions of this file under the
|
---|
24 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
25 | */
|
---|
26 |
|
---|
27 |
|
---|
28 | /*********************************************************************************************************************************
|
---|
29 | * Header Files *
|
---|
30 | *********************************************************************************************************************************/
|
---|
31 | #define LOG_GROUP RTLOGGROUP_FS
|
---|
32 | #include "internal/iprt.h"
|
---|
33 | #include <iprt/fsisomaker.h>
|
---|
34 |
|
---|
35 | #include <iprt/avl.h>
|
---|
36 | #include <iprt/asm.h>
|
---|
37 | #include <iprt/assert.h>
|
---|
38 | #include <iprt/err.h>
|
---|
39 | #include <iprt/ctype.h>
|
---|
40 | #include <iprt/file.h>
|
---|
41 | #include <iprt/list.h>
|
---|
42 | #include <iprt/log.h>
|
---|
43 | #include <iprt/mem.h>
|
---|
44 | #include <iprt/string.h>
|
---|
45 | #include <iprt/vfs.h>
|
---|
46 | #include <iprt/formats/iso9660.h>
|
---|
47 |
|
---|
48 |
|
---|
49 | /*********************************************************************************************************************************
|
---|
50 | * Defined Constants And Macros *
|
---|
51 | *********************************************************************************************************************************/
|
---|
52 | /** Max directory depth. */
|
---|
53 | #define RTFSISOMK_IMPORT_MAX_DEPTH 32
|
---|
54 |
|
---|
55 |
|
---|
56 | /*********************************************************************************************************************************
|
---|
57 | * Structures and Typedefs *
|
---|
58 | *********************************************************************************************************************************/
|
---|
59 | /**
|
---|
60 | * Block to file translation node.
|
---|
61 | */
|
---|
62 | typedef struct RTFSISOMKIMPBLOCK2FILE
|
---|
63 | {
|
---|
64 | /** AVL tree node containing the first block number of the file.
|
---|
65 | * Block number is relative to the start of the import image. */
|
---|
66 | AVLU32NODECORE Core;
|
---|
67 | /** The configuration index of the file. */
|
---|
68 | uint32_t idxObj;
|
---|
69 | } RTFSISOMKIMPBLOCK2FILE;
|
---|
70 | /** Pointer to a block-2-file translation node. */
|
---|
71 | typedef RTFSISOMKIMPBLOCK2FILE *PRTFSISOMKIMPBLOCK2FILE;
|
---|
72 |
|
---|
73 |
|
---|
74 | /**
|
---|
75 | * Directory todo list entry.
|
---|
76 | */
|
---|
77 | typedef struct RTFSISOMKIMPDIR
|
---|
78 | {
|
---|
79 | /** List stuff. */
|
---|
80 | RTLISTNODE Entry;
|
---|
81 | /** The directory configuration index with hIsoMaker. */
|
---|
82 | uint32_t idxObj;
|
---|
83 | /** The directory data block number. */
|
---|
84 | uint32_t offDirBlock;
|
---|
85 | /** The directory size (in bytes). */
|
---|
86 | uint32_t cbDir;
|
---|
87 | /** The depth of this directory. */
|
---|
88 | uint8_t cDepth;
|
---|
89 | } RTFSISOMKIMPDIR;
|
---|
90 | /** Pointer to a directory todo list entry. */
|
---|
91 | typedef RTFSISOMKIMPDIR *PRTFSISOMKIMPDIR;
|
---|
92 |
|
---|
93 |
|
---|
94 | /**
|
---|
95 | * ISO maker ISO importer state.
|
---|
96 | */
|
---|
97 | typedef struct RTFSISOMKIMPORTER
|
---|
98 | {
|
---|
99 | /** The destination ISO maker. */
|
---|
100 | RTFSISOMAKER hIsoMaker;
|
---|
101 | /** RTFSISOMK_IMPORT_F_XXX. */
|
---|
102 | uint32_t fFlags;
|
---|
103 | /** The status code of the whole import.
|
---|
104 | * This notes down the first error status. */
|
---|
105 | int rc;
|
---|
106 | /** Pointer to error info return structure. */
|
---|
107 | PRTERRINFO pErrInfo;
|
---|
108 |
|
---|
109 | /** The source file. */
|
---|
110 | RTVFSFILE hSrcFile;
|
---|
111 | /** The import source index of hSrcFile in hIsoMaker. UINT32_MAX till adding
|
---|
112 | * the first file. */
|
---|
113 | uint32_t idxSrcFile;
|
---|
114 |
|
---|
115 | /** The root of the tree for converting data block numbers to files
|
---|
116 | * (PRTFSISOMKIMPBLOCK2FILE). This is essential when importing boot files and
|
---|
117 | * the 2nd namespace (joliet, udf, hfs) so that we avoid duplicating data. */
|
---|
118 | AVLU32TREE Block2FileRoot;
|
---|
119 |
|
---|
120 | /** The primary volume space size in blocks. */
|
---|
121 | uint32_t cBlocksInPrimaryVolumeSpace;
|
---|
122 | /** The primary volume space size in bytes. */
|
---|
123 | uint64_t cbPrimaryVolumeSpace;
|
---|
124 | /** The number of volumes in the set. */
|
---|
125 | uint32_t cVolumesInSet;
|
---|
126 | /** The primary volume sequence ID. */
|
---|
127 | uint32_t idPrimaryVol;
|
---|
128 |
|
---|
129 | /** Set if we've already seen a joliet volume descriptor. */
|
---|
130 | bool fSeenJoliet;
|
---|
131 |
|
---|
132 | /** Pointer to the import results structure (output). */
|
---|
133 | PRTFSISOMAKERIMPORTRESULTS pResults;
|
---|
134 |
|
---|
135 | /** Sector buffer for volume descriptors and such. */
|
---|
136 | union
|
---|
137 | {
|
---|
138 | uint8_t ab[ISO9660_SECTOR_SIZE];
|
---|
139 | ISO9660VOLDESCHDR VolDescHdr;
|
---|
140 | ISO9660PRIMARYVOLDESC PrimVolDesc;
|
---|
141 | ISO9660SUPVOLDESC SupVolDesc;
|
---|
142 | ISO9660BOOTRECORDELTORITO ElToritoDesc;
|
---|
143 | } uSectorBuf;
|
---|
144 |
|
---|
145 | /** Name buffer. */
|
---|
146 | char szNameBuf[_2K];
|
---|
147 |
|
---|
148 | /** A somewhat larger buffer. */
|
---|
149 | uint8_t abBuf[_64K];
|
---|
150 | } RTFSISOMKIMPORTER;
|
---|
151 | /** Pointer to an ISO maker ISO importer state. */
|
---|
152 | typedef RTFSISOMKIMPORTER *PRTFSISOMKIMPORTER;
|
---|
153 |
|
---|
154 |
|
---|
155 | /** Requested to import an unknown ISO format. */
|
---|
156 | #define VERR_ISOMK_IMPORT_UNKNOWN_FORMAT (-24906)
|
---|
157 | /** Too many volume descriptors in the import ISO. */
|
---|
158 | #define VERR_ISOMK_IMPORT_TOO_MANY_VOL_DESCS (-24907)
|
---|
159 | /** Import ISO contains a bad volume descriptor header. */
|
---|
160 | #define VERR_ISOMK_IMPORT_INVALID_VOL_DESC_HDR (-24907)
|
---|
161 | /** Import ISO contains more than one primary volume descriptor. */
|
---|
162 | #define VERR_ISOMK_IMPORT_MULTIPLE_PRIMARY_VOL_DESCS (-24908)
|
---|
163 | /** Import ISO contains more than one el torito descriptor. */
|
---|
164 | #define VERR_ISOMK_IMPORT_MULTIPLE_EL_TORITO_DESCS (-24909)
|
---|
165 | /** Import ISO contains more than one joliet volume descriptor. */
|
---|
166 | #define VERR_ISOMK_IMPORT_MULTIPLE_JOLIET_VOL_DESCS (-24908)
|
---|
167 | /** Import ISO starts with supplementary volume descriptor before any
|
---|
168 | * primary ones. */
|
---|
169 | #define VERR_ISOMK_IMPORT_SUPPLEMENTARY_BEFORE_PRIMARY (-24909)
|
---|
170 | /** Import ISO contains an unsupported primary volume descriptor version. */
|
---|
171 | #define VERR_IOSMK_IMPORT_PRIMARY_VOL_DESC_VER (-24909)
|
---|
172 | /** Import ISO contains a bad primary volume descriptor. */
|
---|
173 | #define VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC (-24910)
|
---|
174 | /** Import ISO contains an unsupported supplementary volume descriptor
|
---|
175 | * version. */
|
---|
176 | #define VERR_IOSMK_IMPORT_SUP_VOL_DESC_VER (-24909)
|
---|
177 | /** Import ISO contains a bad supplementary volume descriptor. */
|
---|
178 | #define VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC (-24910)
|
---|
179 | /** Import ISO uses a logical block size other than 2KB. */
|
---|
180 | #define VERR_ISOMK_IMPORT_LOGICAL_BLOCK_SIZE_NOT_2KB (-24911)
|
---|
181 | /** Import ISO contains more than volume. */
|
---|
182 | #define VERR_ISOMK_IMPORT_MORE_THAN_ONE_VOLUME_IN_SET (-24912)
|
---|
183 | /** Import ISO uses invalid volume sequence number. */
|
---|
184 | #define VERR_ISOMK_IMPORT_INVALID_VOLUMNE_SEQ_NO (-24913)
|
---|
185 | /** Import ISO has different volume space sizes of primary and supplementary
|
---|
186 | * volume descriptors. */
|
---|
187 | #define VERR_ISOMK_IMPORT_VOLUME_SPACE_SIZE_MISMATCH (-24913)
|
---|
188 | /** Import ISO has different volume set sizes of primary and supplementary
|
---|
189 | * volume descriptors. */
|
---|
190 | #define VERR_ISOMK_IMPORT_VOLUME_IN_SET_MISMATCH (-24913)
|
---|
191 | /** Import ISO contains a bad root directory record. */
|
---|
192 | #define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC (-24914)
|
---|
193 | /** Import ISO contains a zero sized root directory. */
|
---|
194 | #define VERR_ISOMK_IMPORT_ZERO_SIZED_ROOT_DIR (-24915)
|
---|
195 | /** Import ISO contains a root directory with a mismatching volume sequence
|
---|
196 | * number. */
|
---|
197 | #define VERR_ISOMK_IMPORT_ROOT_VOLUME_SEQ_NO (-24916)
|
---|
198 | /** Import ISO contains a root directory with an out of bounds data extent. */
|
---|
199 | #define VERR_ISOMK_IMPORT_ROOT_DIR_EXTENT_OUT_OF_BOUNDS (-24917)
|
---|
200 | /** Import ISO contains a root directory with a bad record length. */
|
---|
201 | #define VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC_LENGTH (-24918)
|
---|
202 | /** Import ISO contains a root directory without the directory flag set. */
|
---|
203 | #define VERR_ISOMK_IMPORT_ROOT_DIR_WITHOUT_DIR_FLAG (-24919)
|
---|
204 | /** Import ISO contains a root directory with multiple extents. */
|
---|
205 | #define VERR_ISOMK_IMPORT_ROOT_DIR_IS_MULTI_EXTENT (-24920)
|
---|
206 | /** Import ISO contains a too deep directory subtree. */
|
---|
207 | #define VERR_ISOMK_IMPORT_TOO_DEEP_DIR_TREE (-24921)
|
---|
208 |
|
---|
209 | /** Import ISO contains a bad directory record. */
|
---|
210 | #define VERR_ISOMK_IMPORT_BAD_DIR_REC (-24922)
|
---|
211 | /** Import ISO directory record with a mismatching volume sequence number. */
|
---|
212 | #define VERR_ISOMK_IMPORT_DIR_REC_VOLUME_SEQ_NO (-24923)
|
---|
213 | /** Import ISO directory with an extent that is out of bounds. */
|
---|
214 | #define VERR_ISOMK_IMPORT_DIR_REC_EXTENT_OUT_OF_BOUNDS (-24924)
|
---|
215 | /** Import ISO directory with a bad record length. */
|
---|
216 | #define VERR_ISOMK_IMPORT_BAD_DIR_REC_LENGTH (-24925)
|
---|
217 | /** Import ISO directory with a bad name length. */
|
---|
218 | #define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME_LENGTH (-24926)
|
---|
219 | /** Import ISO directory with a bad name. */
|
---|
220 | #define VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME (-24927)
|
---|
221 |
|
---|
222 |
|
---|
223 |
|
---|
224 | /**
|
---|
225 | * Wrapper around RTErrInfoSetV.
|
---|
226 | *
|
---|
227 | * @returns rc
|
---|
228 | * @param pThis The importer instance.
|
---|
229 | * @param rc The status code to set.
|
---|
230 | * @param pszFormat The format string detailing the error.
|
---|
231 | * @param va Argument to the format string.
|
---|
232 | */
|
---|
233 | static int rtFsIsoImpErrorV(PRTFSISOMKIMPORTER pThis, int rc, const char *pszFormat, va_list va)
|
---|
234 | {
|
---|
235 | va_list vaCopy;
|
---|
236 | va_copy(vaCopy, va);
|
---|
237 | LogRel(("RTFsIsoMkImport error %Rrc: %N\n", rc, pszFormat, &vaCopy));
|
---|
238 | va_end(vaCopy);
|
---|
239 |
|
---|
240 | if (RT_SUCCESS(pThis->rc))
|
---|
241 | {
|
---|
242 | pThis->rc = rc;
|
---|
243 | rc = RTErrInfoSetV(pThis->pErrInfo, rc, pszFormat, va);
|
---|
244 | }
|
---|
245 |
|
---|
246 | pThis->pResults->cErrors++;
|
---|
247 | return rc;
|
---|
248 | }
|
---|
249 |
|
---|
250 |
|
---|
251 | /**
|
---|
252 | * Wrapper around RTErrInfoSetF.
|
---|
253 | *
|
---|
254 | * @returns rc
|
---|
255 | * @param pThis The importer instance.
|
---|
256 | * @param rc The status code to set.
|
---|
257 | * @param pszFormat The format string detailing the error.
|
---|
258 | * @param ... Argument to the format string.
|
---|
259 | */
|
---|
260 | static int rtFsIsoImpError(PRTFSISOMKIMPORTER pThis, int rc, const char *pszFormat, ...)
|
---|
261 | {
|
---|
262 | va_list va;
|
---|
263 | va_start(va, pszFormat);
|
---|
264 | rc = rtFsIsoImpErrorV(pThis, rc, pszFormat, va);
|
---|
265 | va_end(va);
|
---|
266 | return rc;
|
---|
267 | }
|
---|
268 |
|
---|
269 |
|
---|
270 | /**
|
---|
271 | * Callback for destroying a RTFSISOMKIMPBLOCK2FILE node.
|
---|
272 | *
|
---|
273 | * @returns VINF_SUCCESS
|
---|
274 | * @param pNode The node to destroy.
|
---|
275 | * @param pvUser Ignored.
|
---|
276 | */
|
---|
277 | static DECLCALLBACK(int) rtFsIsoMakerImportDestroyData2File(PAVLU32NODECORE pNode, void *pvUser)
|
---|
278 | {
|
---|
279 | RT_NOREF(pvUser);
|
---|
280 | RTMemFree(pNode);
|
---|
281 | return VINF_SUCCESS;
|
---|
282 | }
|
---|
283 |
|
---|
284 |
|
---|
285 | /**
|
---|
286 | * Validates a directory record.
|
---|
287 | *
|
---|
288 | * @returns IPRT status code (safe to ignore, see pThis->rc).
|
---|
289 | * @param pThis The importer instance.
|
---|
290 | * @param pDirRec The root directory record to validate.
|
---|
291 | * @param cbMax The maximum size.
|
---|
292 | */
|
---|
293 | static int rtFsIsoImportValidateDirRec(PRTFSISOMKIMPORTER pThis, PCISO9660DIRREC pDirRec, uint32_t cbMax)
|
---|
294 | {
|
---|
295 | /*
|
---|
296 | * Validate dual fields.
|
---|
297 | */
|
---|
298 | if (RT_LE2H_U32(pDirRec->cbData.le) != RT_BE2H_U32(pDirRec->cbData.be))
|
---|
299 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_DIR_REC,
|
---|
300 | "Invalid dir rec size field: {%#RX32,%#RX32}",
|
---|
301 | RT_BE2H_U32(pDirRec->cbData.be), RT_LE2H_U32(pDirRec->cbData.le));
|
---|
302 |
|
---|
303 | if (RT_LE2H_U32(pDirRec->offExtent.le) != RT_BE2H_U32(pDirRec->offExtent.be))
|
---|
304 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_DIR_REC,
|
---|
305 | "Invalid dir rec extent field: {%#RX32,%#RX32}",
|
---|
306 | RT_BE2H_U32(pDirRec->offExtent.be), RT_LE2H_U32(pDirRec->offExtent.le));
|
---|
307 |
|
---|
308 | if (RT_LE2H_U16(pDirRec->VolumeSeqNo.le) != RT_BE2H_U16(pDirRec->VolumeSeqNo.be))
|
---|
309 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_DIR_REC,
|
---|
310 | "Invalid dir rec volume sequence ID field: {%#RX16,%#RX16}",
|
---|
311 | RT_BE2H_U16(pDirRec->VolumeSeqNo.be), RT_LE2H_U16(pDirRec->VolumeSeqNo.le));
|
---|
312 |
|
---|
313 | /*
|
---|
314 | * Check values.
|
---|
315 | */
|
---|
316 | if (ISO9660_GET_ENDIAN(&pDirRec->VolumeSeqNo) != pThis->idPrimaryVol)
|
---|
317 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_DIR_REC_VOLUME_SEQ_NO,
|
---|
318 | "Expected dir rec to have same volume sequence number as primary volume: %#x, expected %#x",
|
---|
319 | ISO9660_GET_ENDIAN(&pDirRec->VolumeSeqNo), pThis->idPrimaryVol);
|
---|
320 |
|
---|
321 | if (ISO9660_GET_ENDIAN(&pDirRec->offExtent) >= pThis->cBlocksInPrimaryVolumeSpace)
|
---|
322 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_DIR_REC_EXTENT_OUT_OF_BOUNDS,
|
---|
323 | "Invalid dir rec extent: %#RX32, max %#RX32",
|
---|
324 | ISO9660_GET_ENDIAN(&pDirRec->offExtent), pThis->cBlocksInPrimaryVolumeSpace);
|
---|
325 |
|
---|
326 | if (pDirRec->cbDirRec < RT_OFFSETOF(ISO9660DIRREC, achFileId) + pDirRec->bFileIdLength)
|
---|
327 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_DIR_REC_LENGTH,
|
---|
328 | "Root dir record size is too small: %#x (min %#x)",
|
---|
329 | pDirRec->cbDirRec, RT_OFFSETOF(ISO9660DIRREC, achFileId) + pDirRec->bFileIdLength);
|
---|
330 | if (pDirRec->cbDirRec > cbMax)
|
---|
331 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_DIR_REC_LENGTH,
|
---|
332 | "Root dir record size is too big: %#x (max %#x)", pDirRec->cbDirRec, cbMax);
|
---|
333 | return VINF_SUCCESS;
|
---|
334 | }
|
---|
335 |
|
---|
336 |
|
---|
337 | /**
|
---|
338 | * Validates a dot or dot-dot directory record.
|
---|
339 | *
|
---|
340 | * @returns IPRT status code (safe to ignore, see pThis->rc).
|
---|
341 | * @param pThis The importer instance.
|
---|
342 | * @param pDirRec The root directory record to validate.
|
---|
343 | * @param cbMax The maximum size.
|
---|
344 | * @param bName The name byte (0x00: '.', 0x01: '..').
|
---|
345 | */
|
---|
346 | static int rtFsIsoImportValidateDotDirRec(PRTFSISOMKIMPORTER pThis, PCISO9660DIRREC pDirRec, uint32_t cbMax, uint8_t bName)
|
---|
347 | {
|
---|
348 | int rc = rtFsIsoImportValidateDirRec(pThis, pDirRec, cbMax);
|
---|
349 | if (RT_SUCCESS(rc))
|
---|
350 | {
|
---|
351 | if (pDirRec->bFileIdLength != 1)
|
---|
352 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME_LENGTH,
|
---|
353 | "Invalid dot dir rec file id length: %u", pDirRec->bFileIdLength);
|
---|
354 | if ((uint8_t)pDirRec->achFileId[0] != bName)
|
---|
355 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_DOT_DIR_REC_BAD_NAME,
|
---|
356 | "Invalid dot dir rec file id: %#x, expected %#x", pDirRec->achFileId[0], bName);
|
---|
357 | }
|
---|
358 | return rc;
|
---|
359 | }
|
---|
360 |
|
---|
361 |
|
---|
362 | static int rtFsIsoImportProcessIso9660TreeWorker(PRTFSISOMKIMPORTER pThis, uint32_t idxDir,
|
---|
363 | uint32_t offDirBlock, uint32_t cbDir, uint8_t cDepth, bool fUnicode,
|
---|
364 | PRTLISTANCHOR pTodoList)
|
---|
365 | {
|
---|
366 | /*
|
---|
367 | * Restrict the depth to try avoid loops.
|
---|
368 | */
|
---|
369 | if (cDepth > RTFSISOMK_IMPORT_MAX_DEPTH)
|
---|
370 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_TOO_DEEP_DIR_TREE, "Dir at %#x LB %#x is too deep", offDirBlock, cbDir);
|
---|
371 |
|
---|
372 | /*
|
---|
373 | * Read the first chunk into the big buffer.
|
---|
374 | */
|
---|
375 | uint32_t cbChunk = RT_MIN(cbDir, sizeof(pThis->abBuf));
|
---|
376 | uint64_t off = (uint64_t)offDirBlock * ISO9660_SECTOR_SIZE;
|
---|
377 | int rc = RTVfsFileReadAt(pThis->hSrcFile, off, pThis->abBuf, cbChunk, NULL);
|
---|
378 | if (RT_FAILURE(rc))
|
---|
379 | return rtFsIsoImpError(pThis, rc, "Error reading directory at %#RX64 (%#RX32 / %#RX32): %Rrc", off, cbChunk, cbDir);
|
---|
380 |
|
---|
381 | cbDir -= cbChunk;
|
---|
382 | off += cbChunk;
|
---|
383 |
|
---|
384 | /*
|
---|
385 | * Skip the current and parent directory entries.
|
---|
386 | */
|
---|
387 | PCISO9660DIRREC pDirRec = (PCISO9660DIRREC)&pThis->abBuf[0];
|
---|
388 | rc = rtFsIsoImportValidateDotDirRec(pThis, pDirRec, cbChunk, 0x00);
|
---|
389 | if (RT_FAILURE(rc))
|
---|
390 | return rc;
|
---|
391 |
|
---|
392 | cbChunk -= pDirRec->cbDirRec;
|
---|
393 | pDirRec = (PCISO9660DIRREC)((uintptr_t)pDirRec + pDirRec->cbDirRec);
|
---|
394 | rc = rtFsIsoImportValidateDotDirRec(pThis, pDirRec, cbChunk, 0x01);
|
---|
395 | if (RT_FAILURE(rc))
|
---|
396 | return rc;
|
---|
397 |
|
---|
398 | cbChunk -= pDirRec->cbDirRec;
|
---|
399 | pDirRec = (PCISO9660DIRREC)((uintptr_t)pDirRec + pDirRec->cbDirRec);
|
---|
400 |
|
---|
401 | /*
|
---|
402 | * Work our way thru all the directory records.
|
---|
403 | */
|
---|
404 | Log3(("rtFsIsoImportProcessIso9660TreeWorker: Starting at @%#RX64 LB %#RX32 (out of %#RX32) in %#x\n",
|
---|
405 | off - cbChunk, cbChunk, cbChunk + cbDir, idxDir));
|
---|
406 | while (cbChunk > 0)
|
---|
407 | {
|
---|
408 | /*
|
---|
409 | * Do we need to read some more?
|
---|
410 | */
|
---|
411 | if ( cbChunk > UINT8_MAX
|
---|
412 | || cbDir == 0)
|
---|
413 | { /* No, we don't. */ }
|
---|
414 | else
|
---|
415 | {
|
---|
416 | pDirRec = (PCISO9660DIRREC)memmove(&pThis->abBuf[ISO9660_SECTOR_SIZE - cbChunk], pDirRec, cbChunk);
|
---|
417 |
|
---|
418 | Assert(!(off & (ISO9660_SECTOR_SIZE - 1)));
|
---|
419 | uint32_t cbToRead = RT_MIN(cbDir, sizeof(pThis->abBuf) - ISO9660_SECTOR_SIZE);
|
---|
420 | rc = RTVfsFileReadAt(pThis->hSrcFile, off, &pThis->abBuf[ISO9660_SECTOR_SIZE], cbToRead, NULL);
|
---|
421 | if (RT_FAILURE(rc))
|
---|
422 | return rtFsIsoImpError(pThis, rc, "Error reading %#RX32 bytes at %#RX64 (dir): %Rrc", off, cbToRead);
|
---|
423 |
|
---|
424 | Log3(("rtFsIsoImportProcessIso9660TreeWorker: Read %#zx more bytes @%#RX64, now got @%#RX64 LB %#RX32\n",
|
---|
425 | cbToRead, off, off - cbChunk, cbChunk + cbToRead));
|
---|
426 | off += cbToRead;
|
---|
427 | cbDir -= cbToRead;
|
---|
428 | cbChunk += cbToRead;
|
---|
429 | }
|
---|
430 |
|
---|
431 | /* If null length, skip to the next sector. May have to read some then. */
|
---|
432 | if (pDirRec->cbDirRec == 0)
|
---|
433 | {
|
---|
434 | uint64_t offChunk = off - cbChunk;
|
---|
435 | uint32_t cbSkip = ISO9660_SECTOR_SIZE - ((uint32_t)offChunk & (ISO9660_SECTOR_SIZE - 1));
|
---|
436 | if (cbSkip < cbChunk)
|
---|
437 | {
|
---|
438 | pDirRec = (PCISO9660DIRREC)((uintptr_t)pDirRec + cbSkip);
|
---|
439 | cbChunk -= cbSkip;
|
---|
440 | if ( cbChunk <= UINT8_MAX
|
---|
441 | && cbDir == 0)
|
---|
442 | {
|
---|
443 | Log3(("rtFsIsoImportProcessIso9660TreeWorker: cbDirRec=0 --> Restart loop\n"));
|
---|
444 | continue;
|
---|
445 | }
|
---|
446 | Log3(("rtFsIsoImportProcessIso9660TreeWorker: cbDirRec=0 --> jumped %#RX32 to @%#RX64 LB %#RX32\n",
|
---|
447 | cbSkip, off - cbChunk, cbChunk));
|
---|
448 | }
|
---|
449 | /* ASSUMES we're working in multiples of sectors! */
|
---|
450 | else if (cbDir == 0)
|
---|
451 | break;
|
---|
452 | else
|
---|
453 | {
|
---|
454 | Assert(!(off & (ISO9660_SECTOR_SIZE - 1)));
|
---|
455 | uint32_t cbToRead = RT_MIN(cbDir, sizeof(pThis->abBuf));
|
---|
456 | rc = RTVfsFileReadAt(pThis->hSrcFile, off, pThis->abBuf, cbToRead, NULL);
|
---|
457 | if (RT_FAILURE(rc))
|
---|
458 | return rtFsIsoImpError(pThis, rc, "Error reading %#RX32 bytes at %#RX64 (dir): %Rrc", off, cbToRead);
|
---|
459 |
|
---|
460 | Log3(("rtFsIsoImportProcessIso9660TreeWorker: cbDirRec=0 --> Read %#zx more bytes @%#RX64, now got @%#RX64 LB %#RX32\n",
|
---|
461 | cbToRead, off, off - cbChunk, cbChunk + cbToRead));
|
---|
462 | off += cbToRead;
|
---|
463 | cbDir -= cbToRead;
|
---|
464 | cbChunk += cbToRead;
|
---|
465 | pDirRec = (PCISO9660DIRREC)&pThis->abBuf[0];
|
---|
466 | }
|
---|
467 | }
|
---|
468 |
|
---|
469 | /*
|
---|
470 | * Validate the directory record. Give up if not valid since we're
|
---|
471 | * likely to get error with subsequent record too.
|
---|
472 | */
|
---|
473 | uint8_t const cbSys = pDirRec->cbDirRec - RT_UOFFSETOF(ISO9660DIRREC, achFileId)
|
---|
474 | - pDirRec->bFileIdLength - !(pDirRec->bFileIdLength & 1);
|
---|
475 | uint8_t const * const pbSys = (uint8_t const *)&pDirRec->achFileId[pDirRec->bFileIdLength + !(pDirRec->bFileIdLength & 1)];
|
---|
476 | Log3(("pDirRec=&abBuf[%#07zx]: @%#010RX64 cb=%#04x ff=%#04x off=%#010RX32 cb=%#010RX32 cbSys=%#x id=%.*Rhxs\n",
|
---|
477 | (uintptr_t)pDirRec - (uintptr_t)&pThis->abBuf[0], off - cbChunk, pDirRec->cbDirRec, pDirRec->fFileFlags,
|
---|
478 | ISO9660_GET_ENDIAN(&pDirRec->offExtent), ISO9660_GET_ENDIAN(&pDirRec->cbData), cbSys,
|
---|
479 | pDirRec->bFileIdLength, pDirRec->achFileId));
|
---|
480 | rc = rtFsIsoImportValidateDirRec(pThis, pDirRec, cbChunk);
|
---|
481 | if (RT_FAILURE(rc))
|
---|
482 | return rc;
|
---|
483 |
|
---|
484 | /*
|
---|
485 | * Convert the name into the name buffer (szNameBuf).
|
---|
486 | */
|
---|
487 | if (!fUnicode)
|
---|
488 | {
|
---|
489 | memcpy(pThis->szNameBuf, pDirRec->achFileId, pDirRec->bFileIdLength);
|
---|
490 | pThis->szNameBuf[pDirRec->bFileIdLength] = '\0';
|
---|
491 | rc = RTStrValidateEncoding(pThis->szNameBuf);
|
---|
492 | }
|
---|
493 | else
|
---|
494 | {
|
---|
495 | char *pszDst = pThis->szNameBuf;
|
---|
496 | rc = RTUtf16BigToUtf8Ex((PRTUTF16)pDirRec->achFileId, pDirRec->bFileIdLength / sizeof(RTUTF16),
|
---|
497 | &pszDst, sizeof(pThis->szNameBuf), NULL);
|
---|
498 | }
|
---|
499 | if (RT_SUCCESS(rc))
|
---|
500 | {
|
---|
501 | /* Drop the version from the name. */
|
---|
502 | /** @todo preserve the file version on import. */
|
---|
503 | size_t cchName = strlen(pThis->szNameBuf);
|
---|
504 | if ( !(pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY)
|
---|
505 | && cchName > 2
|
---|
506 | && RT_C_IS_DIGIT(pThis->szNameBuf[cchName - 1]))
|
---|
507 | {
|
---|
508 | uint32_t offName = 2;
|
---|
509 | while ( offName <= 5
|
---|
510 | && offName + 1 < cchName
|
---|
511 | && RT_C_IS_DIGIT(pThis->szNameBuf[cchName - offName]))
|
---|
512 | offName++;
|
---|
513 | if ( offName + 1 < cchName
|
---|
514 | && pThis->szNameBuf[cchName - offName] == ';')
|
---|
515 | pThis->szNameBuf[cchName - offName] = '\0';
|
---|
516 | }
|
---|
517 | Log3((" --> name='%s'\n", pThis->szNameBuf));
|
---|
518 |
|
---|
519 | /** @todo rock ridge. */
|
---|
520 | if (cbSys > 0)
|
---|
521 | {
|
---|
522 | RT_NOREF(pbSys);
|
---|
523 | }
|
---|
524 | /*
|
---|
525 | * Add the object and enter it into the namespace.
|
---|
526 | */
|
---|
527 | PRTFSISOMKIMPBLOCK2FILE pBlock2File = NULL;
|
---|
528 | uint32_t idxObj = UINT32_MAX;
|
---|
529 | if (pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY)
|
---|
530 | {
|
---|
531 | rc = RTFsIsoMakerAddUnnamedDir(pThis->hIsoMaker, &idxObj);
|
---|
532 | Log3((" --> added directory #%#x'\n", idxObj));
|
---|
533 | if (RT_SUCCESS(rc))
|
---|
534 | pThis->pResults->cAddedDirs++;
|
---|
535 | }
|
---|
536 | else
|
---|
537 | {
|
---|
538 | /* Add the common source file if we haven't done that already. */
|
---|
539 | if (pThis->idxSrcFile != UINT32_MAX)
|
---|
540 | { /* likely */ }
|
---|
541 | else
|
---|
542 | {
|
---|
543 | rc = RTFsIsoMakerAddCommonSourceFile(pThis->hIsoMaker, pThis->hSrcFile, &pThis->idxSrcFile);
|
---|
544 | if (RT_FAILURE(rc))
|
---|
545 | return rtFsIsoImpError(pThis, rc, "RTFsIsoMakerAddCommonSourceFile failed: %Rrc", rc);
|
---|
546 | Assert(pThis->idxSrcFile != UINT32_MAX);
|
---|
547 | }
|
---|
548 |
|
---|
549 | pBlock2File = (PRTFSISOMKIMPBLOCK2FILE)RTAvlU32Get(&pThis->Block2FileRoot, ISO9660_GET_ENDIAN(&pDirRec->offExtent));
|
---|
550 | if (!pBlock2File)
|
---|
551 | {
|
---|
552 | rc = RTFsIsoMakerAddUnnamedFileWithCommonSrc(pThis->hIsoMaker, pThis->idxSrcFile,
|
---|
553 | ISO9660_GET_ENDIAN(&pDirRec->offExtent) * (uint64_t)ISO9660_SECTOR_SIZE,
|
---|
554 | ISO9660_GET_ENDIAN(&pDirRec->cbData), NULL /*pObjInfo*/, &idxObj);
|
---|
555 | Log3((" --> added new file #%#x\n", idxObj));
|
---|
556 | if (RT_SUCCESS(rc))
|
---|
557 | {
|
---|
558 | pThis->pResults->cAddedFiles++;
|
---|
559 | pThis->pResults->cbAddedDataBlocks += RT_ALIGN_32(ISO9660_GET_ENDIAN(&pDirRec->cbData), ISO9660_SECTOR_SIZE);
|
---|
560 | }
|
---|
561 | }
|
---|
562 | else
|
---|
563 | {
|
---|
564 | idxObj = pBlock2File->idxObj;
|
---|
565 | Log3((" --> existing file #%#x'\n", idxObj));
|
---|
566 | rc = VINF_SUCCESS;
|
---|
567 | }
|
---|
568 | }
|
---|
569 | if (RT_SUCCESS(rc))
|
---|
570 | {
|
---|
571 | rc = RTFsIsoMakerObjSetNameAndParent(pThis->hIsoMaker, idxObj, idxDir,
|
---|
572 | !fUnicode ? RTFSISOMAKER_NAMESPACE_ISO_9660 : RTFSISOMAKER_NAMESPACE_JOLIET,
|
---|
573 | pThis->szNameBuf);
|
---|
574 | if (RT_SUCCESS(rc))
|
---|
575 | {
|
---|
576 | pThis->pResults->cAddedNames++;
|
---|
577 |
|
---|
578 | /*
|
---|
579 | * Remember the data location if this is a file, if it's a
|
---|
580 | * directory push it onto the traversal stack.
|
---|
581 | */
|
---|
582 | if (pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY)
|
---|
583 | {
|
---|
584 | PRTFSISOMKIMPDIR pImpDir = (PRTFSISOMKIMPDIR)RTMemAlloc(sizeof(*pImpDir));
|
---|
585 | AssertReturn(pImpDir, rtFsIsoImpError(pThis, VERR_NO_MEMORY, "Could not allocate RTFSISOMKIMPDIR"));
|
---|
586 | pImpDir->cbDir = ISO9660_GET_ENDIAN(&pDirRec->cbData);
|
---|
587 | pImpDir->offDirBlock = ISO9660_GET_ENDIAN(&pDirRec->offExtent);
|
---|
588 | pImpDir->idxObj = idxObj;
|
---|
589 | pImpDir->cDepth = cDepth + 1;
|
---|
590 | RTListAppend(pTodoList, &pImpDir->Entry);
|
---|
591 | }
|
---|
592 | else if (!pBlock2File)
|
---|
593 | {
|
---|
594 | pBlock2File = (PRTFSISOMKIMPBLOCK2FILE)RTMemAlloc(sizeof(*pBlock2File));
|
---|
595 | AssertReturn(pBlock2File, rtFsIsoImpError(pThis, VERR_NO_MEMORY, "Could not allocate RTFSISOMKIMPBLOCK2FILE"));
|
---|
596 | pBlock2File->idxObj = idxObj;
|
---|
597 | pBlock2File->Core.Key = ISO9660_GET_ENDIAN(&pDirRec->offExtent);
|
---|
598 | bool fRc = RTAvlU32Insert(&pThis->Block2FileRoot, &pBlock2File->Core);
|
---|
599 | Assert(fRc); RT_NOREF(fRc);
|
---|
600 | }
|
---|
601 | }
|
---|
602 | else
|
---|
603 | rtFsIsoImpError(pThis, rc, "Invalid name at %#RX64: %.Rhxs",
|
---|
604 | off - cbChunk, pDirRec->bFileIdLength, pDirRec->achFileId);
|
---|
605 | }
|
---|
606 | else
|
---|
607 | rtFsIsoImpError(pThis, rc, "Error adding '%s' (fFileFlags=%#x): %Rrc",
|
---|
608 | pThis->szNameBuf, pDirRec->fFileFlags, rc);
|
---|
609 | }
|
---|
610 | else
|
---|
611 | rtFsIsoImpError(pThis, rc, "Invalid name at %#RX64: %.Rhxs",
|
---|
612 | off - cbChunk, pDirRec->bFileIdLength, pDirRec->achFileId);
|
---|
613 |
|
---|
614 | /*
|
---|
615 | * Advance to the next directory record.
|
---|
616 | */
|
---|
617 | cbChunk -= pDirRec->cbDirRec;
|
---|
618 | pDirRec = (PCISO9660DIRREC)((uintptr_t)pDirRec + pDirRec->cbDirRec);
|
---|
619 | }
|
---|
620 |
|
---|
621 | return VINF_SUCCESS;
|
---|
622 | }
|
---|
623 |
|
---|
624 |
|
---|
625 | static int rtFsIsoImportProcessIso9660Tree(PRTFSISOMKIMPORTER pThis, uint32_t offDirBlock, uint32_t cbDir, bool fUnicode)
|
---|
626 | {
|
---|
627 | /*
|
---|
628 | * Make sure we've got a root in the namespace.
|
---|
629 | */
|
---|
630 | uint32_t idxDir = RTFsIsoMakerGetObjIdxForPath(pThis->hIsoMaker,
|
---|
631 | !fUnicode ? RTFSISOMAKER_NAMESPACE_ISO_9660 : RTFSISOMAKER_NAMESPACE_JOLIET,
|
---|
632 | "/");
|
---|
633 | if (idxDir == UINT32_MAX)
|
---|
634 | {
|
---|
635 | idxDir = RTFSISOMAKER_CFG_IDX_ROOT;
|
---|
636 | int rc = RTFsIsoMakerObjSetPath(pThis->hIsoMaker, RTFSISOMAKER_CFG_IDX_ROOT,
|
---|
637 | !fUnicode ? RTFSISOMAKER_NAMESPACE_ISO_9660 : RTFSISOMAKER_NAMESPACE_JOLIET, "/");
|
---|
638 | if (RT_FAILURE(rc))
|
---|
639 | return rtFsIsoImpError(pThis, rc, "RTFsIsoMakerObjSetPath failed on root dir: %Rrc", rc);
|
---|
640 | }
|
---|
641 | Assert(idxDir == RTFSISOMAKER_CFG_IDX_ROOT);
|
---|
642 |
|
---|
643 | /*
|
---|
644 | * Directories.
|
---|
645 | */
|
---|
646 | int rc = VINF_SUCCESS;
|
---|
647 | uint8_t cDepth = 0;
|
---|
648 | RTLISTANCHOR TodoList;
|
---|
649 | RTListInit(&TodoList);
|
---|
650 | for (;;)
|
---|
651 | {
|
---|
652 | int rc2 = rtFsIsoImportProcessIso9660TreeWorker(pThis, idxDir, offDirBlock, cbDir, cDepth, fUnicode, &TodoList);
|
---|
653 | if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
|
---|
654 | rc = rc2;
|
---|
655 |
|
---|
656 | /*
|
---|
657 | * Pop the next directory.
|
---|
658 | */
|
---|
659 | PRTFSISOMKIMPDIR pNext = RTListRemoveLast(&TodoList, RTFSISOMKIMPDIR, Entry);
|
---|
660 | if (!pNext)
|
---|
661 | break;
|
---|
662 | idxDir = pNext->idxObj;
|
---|
663 | offDirBlock = pNext->offDirBlock;
|
---|
664 | cbDir = pNext->cbDir;
|
---|
665 | cDepth = pNext->cDepth;
|
---|
666 | RTMemFree(pNext);
|
---|
667 | }
|
---|
668 |
|
---|
669 | return rc;
|
---|
670 | }
|
---|
671 |
|
---|
672 |
|
---|
673 | /**
|
---|
674 | * Validates a root directory record.
|
---|
675 | *
|
---|
676 | * @returns IPRT status code (safe to ignore, see pThis->rc).
|
---|
677 | * @param pThis The importer instance.
|
---|
678 | * @param pDirRec The root directory record to validate.
|
---|
679 | */
|
---|
680 | static int rtFsIsoImportValidateRootDirRec(PRTFSISOMKIMPORTER pThis, PCISO9660DIRREC pDirRec)
|
---|
681 | {
|
---|
682 | /*
|
---|
683 | * Validate dual fields.
|
---|
684 | */
|
---|
685 | if (RT_LE2H_U32(pDirRec->cbData.le) != RT_BE2H_U32(pDirRec->cbData.be))
|
---|
686 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC,
|
---|
687 | "Invalid root dir size: {%#RX32,%#RX32}",
|
---|
688 | RT_BE2H_U32(pDirRec->cbData.be), RT_LE2H_U32(pDirRec->cbData.le));
|
---|
689 |
|
---|
690 | if (RT_LE2H_U32(pDirRec->offExtent.le) != RT_BE2H_U32(pDirRec->offExtent.be))
|
---|
691 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC,
|
---|
692 | "Invalid root dir extent: {%#RX32,%#RX32}",
|
---|
693 | RT_BE2H_U32(pDirRec->offExtent.be), RT_LE2H_U32(pDirRec->offExtent.le));
|
---|
694 |
|
---|
695 | if (RT_LE2H_U16(pDirRec->VolumeSeqNo.le) != RT_BE2H_U16(pDirRec->VolumeSeqNo.be))
|
---|
696 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC,
|
---|
697 | "Invalid root dir volume sequence ID: {%#RX16,%#RX16}",
|
---|
698 | RT_BE2H_U16(pDirRec->VolumeSeqNo.be), RT_LE2H_U16(pDirRec->VolumeSeqNo.le));
|
---|
699 |
|
---|
700 | /*
|
---|
701 | * Check values.
|
---|
702 | */
|
---|
703 | if (ISO9660_GET_ENDIAN(&pDirRec->VolumeSeqNo) != pThis->idPrimaryVol)
|
---|
704 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_ROOT_VOLUME_SEQ_NO,
|
---|
705 | "Expected root dir to have same volume sequence number as primary volume: %#x, expected %#x",
|
---|
706 | ISO9660_GET_ENDIAN(&pDirRec->VolumeSeqNo), pThis->idPrimaryVol);
|
---|
707 |
|
---|
708 | if (ISO9660_GET_ENDIAN(&pDirRec->cbData) == 0)
|
---|
709 | return RTErrInfoSet(pThis->pErrInfo, VERR_ISOMK_IMPORT_ZERO_SIZED_ROOT_DIR, "Zero sized root dir");
|
---|
710 |
|
---|
711 | if (ISO9660_GET_ENDIAN(&pDirRec->offExtent) >= pThis->cBlocksInPrimaryVolumeSpace)
|
---|
712 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_ROOT_DIR_EXTENT_OUT_OF_BOUNDS,
|
---|
713 | "Invalid root dir extent: %#RX32, max %#RX32",
|
---|
714 | ISO9660_GET_ENDIAN(&pDirRec->offExtent), pThis->cBlocksInPrimaryVolumeSpace);
|
---|
715 |
|
---|
716 | if (pDirRec->cbDirRec < RT_OFFSETOF(ISO9660DIRREC, achFileId))
|
---|
717 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_ROOT_DIR_REC_LENGTH,
|
---|
718 | "Root dir record size is too small: %#x (min %#x)",
|
---|
719 | pDirRec->cbDirRec, RT_OFFSETOF(ISO9660DIRREC, achFileId));
|
---|
720 |
|
---|
721 | if (!(pDirRec->fFileFlags & ISO9660_FILE_FLAGS_DIRECTORY))
|
---|
722 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_ROOT_DIR_WITHOUT_DIR_FLAG,
|
---|
723 | "Root dir is not flagged as directory: %#x", pDirRec->fFileFlags);
|
---|
724 | if (pDirRec->fFileFlags & ISO9660_FILE_FLAGS_MULTI_EXTENT)
|
---|
725 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_ROOT_DIR_IS_MULTI_EXTENT,
|
---|
726 | "Root dir is cannot be multi-extent: %#x", pDirRec->fFileFlags);
|
---|
727 |
|
---|
728 | return VINF_SUCCESS;
|
---|
729 | }
|
---|
730 |
|
---|
731 |
|
---|
732 | /**
|
---|
733 | * Processes a primary volume descriptor, importing all files described by its
|
---|
734 | * namespace.
|
---|
735 | *
|
---|
736 | * @returns IPRT status code (safe to ignore, see pThis->rc).
|
---|
737 | * @param pThis The importer instance.
|
---|
738 | * @param pVolDesc The primary volume descriptor.
|
---|
739 | */
|
---|
740 | static int rtFsIsoImportProcessPrimaryDesc(PRTFSISOMKIMPORTER pThis, PISO9660PRIMARYVOLDESC pVolDesc)
|
---|
741 | {
|
---|
742 | /*
|
---|
743 | * Validate dual fields first.
|
---|
744 | */
|
---|
745 | if (pVolDesc->bFileStructureVersion != ISO9660_FILE_STRUCTURE_VERSION)
|
---|
746 | return rtFsIsoImpError(pThis, VERR_IOSMK_IMPORT_PRIMARY_VOL_DESC_VER,
|
---|
747 | "Unsupported file structure version: %#x", pVolDesc->bFileStructureVersion);
|
---|
748 |
|
---|
749 | if (RT_LE2H_U16(pVolDesc->cbLogicalBlock.le) != RT_BE2H_U16(pVolDesc->cbLogicalBlock.be))
|
---|
750 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC,
|
---|
751 | "Mismatching logical block size: {%#RX16,%#RX16}",
|
---|
752 | RT_BE2H_U16(pVolDesc->cbLogicalBlock.be), RT_LE2H_U16(pVolDesc->cbLogicalBlock.le));
|
---|
753 | if (RT_LE2H_U32(pVolDesc->VolumeSpaceSize.le) != RT_BE2H_U32(pVolDesc->VolumeSpaceSize.be))
|
---|
754 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC,
|
---|
755 | "Mismatching volume space size: {%#RX32,%#RX32}",
|
---|
756 | RT_BE2H_U32(pVolDesc->VolumeSpaceSize.be), RT_LE2H_U32(pVolDesc->VolumeSpaceSize.le));
|
---|
757 | if (RT_LE2H_U16(pVolDesc->cVolumesInSet.le) != RT_BE2H_U16(pVolDesc->cVolumesInSet.be))
|
---|
758 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC,
|
---|
759 | "Mismatching volumes in set: {%#RX16,%#RX16}",
|
---|
760 | RT_BE2H_U16(pVolDesc->cVolumesInSet.be), RT_LE2H_U16(pVolDesc->cVolumesInSet.le));
|
---|
761 | if (RT_LE2H_U16(pVolDesc->VolumeSeqNo.le) != RT_BE2H_U16(pVolDesc->VolumeSeqNo.be))
|
---|
762 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC,
|
---|
763 | "Mismatching volume sequence no.: {%#RX16,%#RX16}",
|
---|
764 | RT_BE2H_U16(pVolDesc->VolumeSeqNo.be), RT_LE2H_U16(pVolDesc->VolumeSeqNo.le));
|
---|
765 | if (RT_LE2H_U32(pVolDesc->cbPathTable.le) != RT_BE2H_U32(pVolDesc->cbPathTable.be))
|
---|
766 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_PRIMARY_VOL_DESC,
|
---|
767 | "Mismatching path table size: {%#RX32,%#RX32}",
|
---|
768 | RT_BE2H_U32(pVolDesc->cbPathTable.be), RT_LE2H_U32(pVolDesc->cbPathTable.le));
|
---|
769 |
|
---|
770 | /*
|
---|
771 | * Validate field values against our expectations.
|
---|
772 | */
|
---|
773 | if (ISO9660_GET_ENDIAN(&pVolDesc->cbLogicalBlock) != ISO9660_SECTOR_SIZE)
|
---|
774 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_LOGICAL_BLOCK_SIZE_NOT_2KB,
|
---|
775 | "Unsupported block size: %#x", ISO9660_GET_ENDIAN(&pVolDesc->cbLogicalBlock));
|
---|
776 |
|
---|
777 | if (ISO9660_GET_ENDIAN(&pVolDesc->cVolumesInSet) != 1)
|
---|
778 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_MORE_THAN_ONE_VOLUME_IN_SET,
|
---|
779 | "Volumes in set: %#x", ISO9660_GET_ENDIAN(&pVolDesc->cVolumesInSet));
|
---|
780 |
|
---|
781 | if (ISO9660_GET_ENDIAN(&pVolDesc->VolumeSeqNo) != 1)
|
---|
782 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_INVALID_VOLUMNE_SEQ_NO,
|
---|
783 | "Unexpected volume sequence number: %#x", ISO9660_GET_ENDIAN(&pVolDesc->VolumeSeqNo));
|
---|
784 |
|
---|
785 | /*
|
---|
786 | * Gather info we need.
|
---|
787 | */
|
---|
788 | pThis->cBlocksInPrimaryVolumeSpace = ISO9660_GET_ENDIAN(&pVolDesc->VolumeSpaceSize);
|
---|
789 | pThis->cbPrimaryVolumeSpace = pThis->cBlocksInPrimaryVolumeSpace * (uint64_t)ISO9660_SECTOR_SIZE;
|
---|
790 | pThis->cVolumesInSet = ISO9660_GET_ENDIAN(&pVolDesc->cVolumesInSet);
|
---|
791 | pThis->idPrimaryVol = ISO9660_GET_ENDIAN(&pVolDesc->VolumeSeqNo);
|
---|
792 |
|
---|
793 | /*
|
---|
794 | * Validate the root directory record.
|
---|
795 | */
|
---|
796 | int rc = rtFsIsoImportValidateRootDirRec(pThis, &pVolDesc->RootDir.DirRec);
|
---|
797 | if (RT_SUCCESS(rc))
|
---|
798 | {
|
---|
799 | /*
|
---|
800 | * Process the directory tree. Start by establishing a root directory.
|
---|
801 | */
|
---|
802 | if (!(pThis->fFlags & RTFSISOMK_IMPORT_F_NO_PRIMARY_ISO))
|
---|
803 | rc = rtFsIsoImportProcessIso9660Tree(pThis, ISO9660_GET_ENDIAN(&pVolDesc->RootDir.DirRec.offExtent),
|
---|
804 | ISO9660_GET_ENDIAN(&pVolDesc->RootDir.DirRec.cbData), false /*fUnicode*/);
|
---|
805 | }
|
---|
806 |
|
---|
807 | return rc;
|
---|
808 | }
|
---|
809 |
|
---|
810 |
|
---|
811 | static int rtFsIsoImportProcessSupplementaryDesc(PRTFSISOMKIMPORTER pThis, PISO9660SUPVOLDESC pVolDesc)
|
---|
812 | {
|
---|
813 | /*
|
---|
814 | * Validate dual fields first.
|
---|
815 | */
|
---|
816 | if (pVolDesc->bFileStructureVersion != ISO9660_FILE_STRUCTURE_VERSION)
|
---|
817 | return rtFsIsoImpError(pThis, VERR_IOSMK_IMPORT_SUP_VOL_DESC_VER,
|
---|
818 | "Unsupported file structure version: %#x", pVolDesc->bFileStructureVersion);
|
---|
819 |
|
---|
820 | if (RT_LE2H_U16(pVolDesc->cbLogicalBlock.le) != RT_BE2H_U16(pVolDesc->cbLogicalBlock.be))
|
---|
821 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC,
|
---|
822 | "Mismatching logical block size: {%#RX16,%#RX16}",
|
---|
823 | RT_BE2H_U16(pVolDesc->cbLogicalBlock.be), RT_LE2H_U16(pVolDesc->cbLogicalBlock.le));
|
---|
824 | if (RT_LE2H_U32(pVolDesc->VolumeSpaceSize.le) != RT_BE2H_U32(pVolDesc->VolumeSpaceSize.be))
|
---|
825 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC,
|
---|
826 | "Mismatching volume space size: {%#RX32,%#RX32}",
|
---|
827 | RT_BE2H_U32(pVolDesc->VolumeSpaceSize.be), RT_LE2H_U32(pVolDesc->VolumeSpaceSize.le));
|
---|
828 | if (RT_LE2H_U16(pVolDesc->cVolumesInSet.le) != RT_BE2H_U16(pVolDesc->cVolumesInSet.be))
|
---|
829 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC,
|
---|
830 | "Mismatching volumes in set: {%#RX16,%#RX16}",
|
---|
831 | RT_BE2H_U16(pVolDesc->cVolumesInSet.be), RT_LE2H_U16(pVolDesc->cVolumesInSet.le));
|
---|
832 | if (RT_LE2H_U16(pVolDesc->VolumeSeqNo.le) != RT_BE2H_U16(pVolDesc->VolumeSeqNo.be))
|
---|
833 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC,
|
---|
834 | "Mismatching volume sequence no.: {%#RX16,%#RX16}",
|
---|
835 | RT_BE2H_U16(pVolDesc->VolumeSeqNo.be), RT_LE2H_U16(pVolDesc->VolumeSeqNo.le));
|
---|
836 | if (RT_LE2H_U32(pVolDesc->cbPathTable.le) != RT_BE2H_U32(pVolDesc->cbPathTable.be))
|
---|
837 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_BAD_SUP_VOL_DESC,
|
---|
838 | "Mismatching path table size: {%#RX32,%#RX32}",
|
---|
839 | RT_BE2H_U32(pVolDesc->cbPathTable.be), RT_LE2H_U32(pVolDesc->cbPathTable.le));
|
---|
840 |
|
---|
841 | /*
|
---|
842 | * Validate field values against our expectations.
|
---|
843 | */
|
---|
844 | if (ISO9660_GET_ENDIAN(&pVolDesc->cbLogicalBlock) != ISO9660_SECTOR_SIZE)
|
---|
845 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_LOGICAL_BLOCK_SIZE_NOT_2KB,
|
---|
846 | "Unsupported block size: %#x", ISO9660_GET_ENDIAN(&pVolDesc->cbLogicalBlock));
|
---|
847 |
|
---|
848 | if (ISO9660_GET_ENDIAN(&pVolDesc->cVolumesInSet) != pThis->cVolumesInSet)
|
---|
849 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_VOLUME_IN_SET_MISMATCH, "Volumes in set: %#x, expected %#x",
|
---|
850 | ISO9660_GET_ENDIAN(&pVolDesc->cVolumesInSet), pThis->cVolumesInSet);
|
---|
851 |
|
---|
852 | if (ISO9660_GET_ENDIAN(&pVolDesc->VolumeSeqNo) != pThis->idPrimaryVol)
|
---|
853 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_INVALID_VOLUMNE_SEQ_NO,
|
---|
854 | "Unexpected volume sequence number: %#x (expected %#x)",
|
---|
855 | ISO9660_GET_ENDIAN(&pVolDesc->VolumeSeqNo), pThis->idPrimaryVol);
|
---|
856 |
|
---|
857 | if (ISO9660_GET_ENDIAN(&pVolDesc->VolumeSpaceSize) != pThis->cBlocksInPrimaryVolumeSpace)
|
---|
858 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_INVALID_VOLUMNE_SEQ_NO,
|
---|
859 | "Volume space size differs between primary and supplementary descriptors: %#x, primary %#x",
|
---|
860 | ISO9660_GET_ENDIAN(&pVolDesc->VolumeSpaceSize), pThis->cBlocksInPrimaryVolumeSpace);
|
---|
861 |
|
---|
862 | /*
|
---|
863 | * Validate the root directory record.
|
---|
864 | */
|
---|
865 | int rc = rtFsIsoImportValidateRootDirRec(pThis, &pVolDesc->RootDir.DirRec);
|
---|
866 | if (RT_FAILURE(rc))
|
---|
867 | return rc;
|
---|
868 |
|
---|
869 | /*
|
---|
870 | * Is this a joliet descriptor? Ignore if not.
|
---|
871 | */
|
---|
872 | uint8_t uJolietLevel = 0;
|
---|
873 | if ( pVolDesc->abEscapeSequences[0] == ISO9660_JOLIET_ESC_SEQ_0
|
---|
874 | && pVolDesc->abEscapeSequences[1] == ISO9660_JOLIET_ESC_SEQ_1)
|
---|
875 | switch (pVolDesc->abEscapeSequences[2])
|
---|
876 | {
|
---|
877 | case ISO9660_JOLIET_ESC_SEQ_2_LEVEL_1: uJolietLevel = 1; break;
|
---|
878 | case ISO9660_JOLIET_ESC_SEQ_2_LEVEL_2: uJolietLevel = 2; break;
|
---|
879 | case ISO9660_JOLIET_ESC_SEQ_2_LEVEL_3: uJolietLevel = 3; break;
|
---|
880 | default: Log(("rtFsIsoImportProcessSupplementaryDesc: last joliet escape sequence byte doesn't match: %#x\n",
|
---|
881 | pVolDesc->abEscapeSequences[2]));
|
---|
882 | }
|
---|
883 | if (uJolietLevel == 0)
|
---|
884 | return VINF_SUCCESS;
|
---|
885 |
|
---|
886 | /*
|
---|
887 | * Only one joliet descriptor.
|
---|
888 | */
|
---|
889 | if (pThis->fSeenJoliet)
|
---|
890 | return rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_MULTIPLE_JOLIET_VOL_DESCS,
|
---|
891 | "More than one Joliet volume descriptor is not supported");
|
---|
892 | pThis->fSeenJoliet = true;
|
---|
893 |
|
---|
894 | /*
|
---|
895 | * Process the directory tree.
|
---|
896 | */
|
---|
897 | if (!(pThis->fFlags & RTFSISOMK_IMPORT_F_NO_JOLIET))
|
---|
898 | return rtFsIsoImportProcessIso9660Tree(pThis, ISO9660_GET_ENDIAN(&pVolDesc->RootDir.DirRec.offExtent),
|
---|
899 | ISO9660_GET_ENDIAN(&pVolDesc->RootDir.DirRec.cbData), true /*fUnicode*/);
|
---|
900 | return VINF_SUCCESS;
|
---|
901 | }
|
---|
902 |
|
---|
903 |
|
---|
904 | static int rtFsIsoImportProcessElToritoDesc(PRTFSISOMKIMPORTER pThis, PISO9660BOOTRECORDELTORITO pElTorito)
|
---|
905 | {
|
---|
906 | RT_NOREF(pThis, pElTorito);
|
---|
907 | return VINF_SUCCESS;
|
---|
908 | }
|
---|
909 |
|
---|
910 |
|
---|
911 | /**
|
---|
912 | * Imports an existing ISO.
|
---|
913 | *
|
---|
914 | * Just like other source files, the existing image must remain present and
|
---|
915 | * unmodified till the ISO maker is done with it.
|
---|
916 | *
|
---|
917 | * @returns IRPT status code.
|
---|
918 | * @param hIsoMaker The ISO maker handle.
|
---|
919 | * @param pszIso Path to the existing image to import / clone.
|
---|
920 | * This is fed to RTVfsChainOpenFile.
|
---|
921 | * @param fFlags Reserved for the future, MBZ.
|
---|
922 | * @param poffError Where to return the position in @a pszIso
|
---|
923 | * causing trouble when opening it for reading.
|
---|
924 | * Optional.
|
---|
925 | * @param pErrInfo Where to return additional error information.
|
---|
926 | * Optional.
|
---|
927 | */
|
---|
928 | RTDECL(int) RTFsIsoMakerImport(RTFSISOMAKER hIsoMaker, const char *pszIso, uint32_t fFlags,
|
---|
929 | PRTFSISOMAKERIMPORTRESULTS pResults, PRTERRINFO pErrInfo)
|
---|
930 | {
|
---|
931 | /*
|
---|
932 | * Validate input.
|
---|
933 | */
|
---|
934 | AssertPtrReturn(pResults, VERR_INVALID_POINTER);
|
---|
935 | pResults->cAddedNames = 0;
|
---|
936 | pResults->cAddedDirs = 0;
|
---|
937 | pResults->cbAddedDataBlocks = 0;
|
---|
938 | pResults->cAddedFiles = 0;
|
---|
939 | pResults->cBootCatEntries = UINT32_MAX;
|
---|
940 | pResults->cbSysArea = 0;
|
---|
941 | pResults->cErrors = 0;
|
---|
942 | pResults->offError = UINT32_MAX;
|
---|
943 | AssertReturn(!(fFlags & ~RTFSISOMK_IMPORT_F_VALID_MASK), VERR_INVALID_FLAGS);
|
---|
944 |
|
---|
945 | /*
|
---|
946 | * Open the input file and start working on it.
|
---|
947 | */
|
---|
948 | RTVFSFILE hSrcFile;
|
---|
949 | int rc = RTVfsChainOpenFile(pszIso, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE,
|
---|
950 | &hSrcFile, &pResults->offError, pErrInfo);
|
---|
951 | if (RT_FAILURE(rc))
|
---|
952 | return rc;
|
---|
953 | pResults->offError = UINT32_MAX;
|
---|
954 |
|
---|
955 |
|
---|
956 | /*
|
---|
957 | * Allocate and init the importer state.
|
---|
958 | */
|
---|
959 | PRTFSISOMKIMPORTER pThis = (PRTFSISOMKIMPORTER)RTMemAllocZ(sizeof(*pThis));
|
---|
960 | if (pThis)
|
---|
961 | {
|
---|
962 | pThis->hIsoMaker = hIsoMaker;
|
---|
963 | pThis->fFlags = fFlags;
|
---|
964 | pThis->rc = VINF_SUCCESS;
|
---|
965 | pThis->pErrInfo = pErrInfo;
|
---|
966 | pThis->hSrcFile = hSrcFile;
|
---|
967 | pThis->idxSrcFile = UINT32_MAX;
|
---|
968 | //pThis->Block2FileRoot = NULL;
|
---|
969 | //pThis->cBlocksInPrimaryVolumeSpace = 0;
|
---|
970 | //pThis->cbPrimaryVolumeSpace = 0
|
---|
971 | //pThis->cVolumesInSet = 0;
|
---|
972 | //pThis->idPrimaryVol = 0;
|
---|
973 | //pThis->fSeenJoliet = false;
|
---|
974 | pThis->pResults = pResults;
|
---|
975 |
|
---|
976 | /*
|
---|
977 | * Check if this looks like a plausible ISO by checking out the first volume descriptor.
|
---|
978 | */
|
---|
979 | rc = RTVfsFileReadAt(hSrcFile, _32K, &pThis->uSectorBuf.PrimVolDesc, sizeof(pThis->uSectorBuf.PrimVolDesc), NULL);
|
---|
980 | if (RT_SUCCESS(rc))
|
---|
981 | {
|
---|
982 | if ( pThis->uSectorBuf.VolDescHdr.achStdId[0] == ISO9660VOLDESC_STD_ID_0
|
---|
983 | && pThis->uSectorBuf.VolDescHdr.achStdId[1] == ISO9660VOLDESC_STD_ID_1
|
---|
984 | && pThis->uSectorBuf.VolDescHdr.achStdId[2] == ISO9660VOLDESC_STD_ID_2
|
---|
985 | && pThis->uSectorBuf.VolDescHdr.achStdId[3] == ISO9660VOLDESC_STD_ID_3
|
---|
986 | && pThis->uSectorBuf.VolDescHdr.achStdId[4] == ISO9660VOLDESC_STD_ID_4
|
---|
987 | && ( pThis->uSectorBuf.VolDescHdr.bDescType == ISO9660VOLDESC_TYPE_PRIMARY
|
---|
988 | || pThis->uSectorBuf.VolDescHdr.bDescType == ISO9660VOLDESC_TYPE_BOOT_RECORD) )
|
---|
989 | {
|
---|
990 | /*
|
---|
991 | * Process the volume descriptors using the sector buffer, starting
|
---|
992 | * with the one we've already got sitting there. We postpone processing
|
---|
993 | * the el torito one till after the others, so we can name files and size
|
---|
994 | * referenced in it.
|
---|
995 | */
|
---|
996 | uint32_t cPrimaryVolDescs = 0;
|
---|
997 | uint32_t iElTorito = UINT32_MAX;
|
---|
998 | uint32_t iVolDesc = 0;
|
---|
999 | for (;;)
|
---|
1000 | {
|
---|
1001 | switch (pThis->uSectorBuf.VolDescHdr.bDescType)
|
---|
1002 | {
|
---|
1003 | case ISO9660VOLDESC_TYPE_PRIMARY:
|
---|
1004 | cPrimaryVolDescs++;
|
---|
1005 | if (cPrimaryVolDescs == 1)
|
---|
1006 | rtFsIsoImportProcessPrimaryDesc(pThis, &pThis->uSectorBuf.PrimVolDesc);
|
---|
1007 | else
|
---|
1008 | rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_MULTIPLE_PRIMARY_VOL_DESCS,
|
---|
1009 | "Only a single primary volume descriptor is currently supported");
|
---|
1010 | break;
|
---|
1011 |
|
---|
1012 | case ISO9660VOLDESC_TYPE_SUPPLEMENTARY:
|
---|
1013 | if (cPrimaryVolDescs > 0)
|
---|
1014 | rtFsIsoImportProcessSupplementaryDesc(pThis, &pThis->uSectorBuf.SupVolDesc);
|
---|
1015 | else
|
---|
1016 | rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_SUPPLEMENTARY_BEFORE_PRIMARY,
|
---|
1017 | "Primary volume descriptor expected before any supplementary descriptors!");
|
---|
1018 | break;
|
---|
1019 |
|
---|
1020 | case ISO9660VOLDESC_TYPE_BOOT_RECORD:
|
---|
1021 | if (strcmp(pThis->uSectorBuf.ElToritoDesc.achBootSystemId,
|
---|
1022 | ISO9660BOOTRECORDELTORITO_BOOT_SYSTEM_ID) == 0)
|
---|
1023 | {
|
---|
1024 | if (iElTorito == UINT32_MAX)
|
---|
1025 | iElTorito = iVolDesc;
|
---|
1026 | else
|
---|
1027 | rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_MULTIPLE_EL_TORITO_DESCS,
|
---|
1028 | "Only a single El Torito descriptor exepcted!");
|
---|
1029 | }
|
---|
1030 | break;
|
---|
1031 |
|
---|
1032 | case ISO9660VOLDESC_TYPE_PARTITION:
|
---|
1033 | /* ignore for now */
|
---|
1034 | break;
|
---|
1035 |
|
---|
1036 | case ISO9660VOLDESC_TYPE_TERMINATOR:
|
---|
1037 | AssertFailed();
|
---|
1038 | break;
|
---|
1039 | }
|
---|
1040 |
|
---|
1041 |
|
---|
1042 | /*
|
---|
1043 | * Read the next volume descriptor and check the signature.
|
---|
1044 | */
|
---|
1045 | iVolDesc++;
|
---|
1046 | if (iVolDesc >= 32)
|
---|
1047 | {
|
---|
1048 | rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_TOO_MANY_VOL_DESCS, "Parses at most 32 volume descriptors");
|
---|
1049 | break;
|
---|
1050 | }
|
---|
1051 |
|
---|
1052 | rc = RTVfsFileReadAt(hSrcFile, _32K + iVolDesc * ISO9660_SECTOR_SIZE,
|
---|
1053 | &pThis->uSectorBuf, sizeof(pThis->uSectorBuf), NULL);
|
---|
1054 | if (RT_FAILURE(rc))
|
---|
1055 | {
|
---|
1056 | rtFsIsoImpError(pThis, rc, "Error reading the volume descriptor #%u at %#RX32: %Rrc",
|
---|
1057 | iVolDesc, _32K + iVolDesc * ISO9660_SECTOR_SIZE, rc);
|
---|
1058 | break;
|
---|
1059 | }
|
---|
1060 |
|
---|
1061 | if ( pThis->uSectorBuf.VolDescHdr.achStdId[0] != ISO9660VOLDESC_STD_ID_0
|
---|
1062 | || pThis->uSectorBuf.VolDescHdr.achStdId[1] != ISO9660VOLDESC_STD_ID_1
|
---|
1063 | || pThis->uSectorBuf.VolDescHdr.achStdId[2] != ISO9660VOLDESC_STD_ID_2
|
---|
1064 | || pThis->uSectorBuf.VolDescHdr.achStdId[3] != ISO9660VOLDESC_STD_ID_3
|
---|
1065 | || pThis->uSectorBuf.VolDescHdr.achStdId[4] != ISO9660VOLDESC_STD_ID_4)
|
---|
1066 | {
|
---|
1067 | rtFsIsoImpError(pThis, VERR_ISOMK_IMPORT_INVALID_VOL_DESC_HDR,
|
---|
1068 | "Invalid volume descriptor header #%u at %#RX32: %.*Rhxs",
|
---|
1069 | iVolDesc, _32K + iVolDesc * ISO9660_SECTOR_SIZE,
|
---|
1070 | (int)sizeof(pThis->uSectorBuf.VolDescHdr), &pThis->uSectorBuf.VolDescHdr);
|
---|
1071 | break;
|
---|
1072 | }
|
---|
1073 | /** @todo UDF support. */
|
---|
1074 | if (pThis->uSectorBuf.VolDescHdr.bDescType == ISO9660VOLDESC_TYPE_TERMINATOR)
|
---|
1075 | break;
|
---|
1076 | }
|
---|
1077 |
|
---|
1078 | /*
|
---|
1079 | * Process the system area.
|
---|
1080 | */
|
---|
1081 | if (RT_SUCCESS(pThis->rc) || pThis->idxSrcFile != UINT32_MAX)
|
---|
1082 | {
|
---|
1083 | rc = RTVfsFileReadAt(hSrcFile, 0, pThis->abBuf, _32K, NULL);
|
---|
1084 | if (RT_SUCCESS(rc))
|
---|
1085 | {
|
---|
1086 | if (!ASMMemIsAllU8(pThis->abBuf, _32K, 0))
|
---|
1087 | {
|
---|
1088 | /* Drop zero sectors from the end. */
|
---|
1089 | uint32_t cbSysArea = _32K;
|
---|
1090 | while ( cbSysArea >= ISO9660_SECTOR_SIZE
|
---|
1091 | && ASMMemIsAllU8(&pThis->abBuf[cbSysArea - ISO9660_SECTOR_SIZE], ISO9660_SECTOR_SIZE, 0))
|
---|
1092 | cbSysArea -= ISO9660_SECTOR_SIZE;
|
---|
1093 |
|
---|
1094 | /** @todo HFS */
|
---|
1095 | pThis->pResults->cbSysArea = cbSysArea;
|
---|
1096 | rc = RTFsIsoMakerSetSysAreaContent(hIsoMaker, pThis->abBuf, cbSysArea, 0);
|
---|
1097 | if (RT_FAILURE(rc))
|
---|
1098 | rtFsIsoImpError(pThis, rc, "RTFsIsoMakerSetSysAreaContent failed: %Rrc", rc);
|
---|
1099 | }
|
---|
1100 | }
|
---|
1101 | else
|
---|
1102 | rtFsIsoImpError(pThis, rc, "Error reading the system area (0..32KB): %Rrc", rc);
|
---|
1103 | }
|
---|
1104 |
|
---|
1105 | /*
|
---|
1106 | * Do the El Torito descriptor.
|
---|
1107 | */
|
---|
1108 | if ( iElTorito != UINT32_MAX
|
---|
1109 | && !(pThis->fFlags & RTFSISOMK_IMPORT_F_NO_BOOT)
|
---|
1110 | && (RT_SUCCESS(pThis->rc) || pThis->idxSrcFile != UINT32_MAX))
|
---|
1111 | {
|
---|
1112 | rc = RTVfsFileReadAt(hSrcFile, _32K + iElTorito * ISO9660_SECTOR_SIZE,
|
---|
1113 | &pThis->uSectorBuf, sizeof(pThis->uSectorBuf), NULL);
|
---|
1114 | if (RT_SUCCESS(rc))
|
---|
1115 | rtFsIsoImportProcessElToritoDesc(pThis, &pThis->uSectorBuf.ElToritoDesc);
|
---|
1116 | else
|
---|
1117 | rtFsIsoImpError(pThis, rc, "Error reading the El Torito volume descriptor at %#RX32: %Rrc",
|
---|
1118 | _32K + iElTorito * ISO9660_SECTOR_SIZE, rc);
|
---|
1119 | }
|
---|
1120 |
|
---|
1121 | /*
|
---|
1122 | * Return the first error status.
|
---|
1123 | */
|
---|
1124 | rc = pThis->rc;
|
---|
1125 | }
|
---|
1126 | else
|
---|
1127 | rc = RTErrInfoSetF(pErrInfo, VERR_ISOMK_IMPORT_UNKNOWN_FORMAT, "Invalid volume descriptor header: %.*Rhxs",
|
---|
1128 | (int)sizeof(pThis->uSectorBuf.VolDescHdr), &pThis->uSectorBuf.VolDescHdr);
|
---|
1129 | }
|
---|
1130 |
|
---|
1131 | /*
|
---|
1132 | * Destroy the state.
|
---|
1133 | */
|
---|
1134 | RTAvlU32Destroy(&pThis->Block2FileRoot, rtFsIsoMakerImportDestroyData2File, NULL);
|
---|
1135 | RTMemFree(pThis);
|
---|
1136 | }
|
---|
1137 | else
|
---|
1138 | rc = VERR_NO_MEMORY;
|
---|
1139 | RTVfsFileRelease(hSrcFile);
|
---|
1140 | return rc;
|
---|
1141 |
|
---|
1142 | }
|
---|
1143 |
|
---|