VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/checksum/manifest2.cpp@ 37187

Last change on this file since 37187 was 34941, checked in by vboxsync, 14 years ago

checksum/manifest: uninitialized variables

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.8 KB
Line 
1/* $Id: manifest2.cpp 34941 2010-12-10 10:58:06Z vboxsync $ */
2/** @file
3 * IPRT - Manifest, the core.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/manifest.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ctype.h>
37#include <iprt/err.h>
38#include <iprt/mem.h>
39#include <iprt/param.h>
40#include <iprt/md5.h>
41#include <iprt/sha.h>
42#include <iprt/string.h>
43#include <iprt/vfs.h>
44
45#include "internal/magics.h"
46
47
48/*******************************************************************************
49* Structures and Typedefs *
50*******************************************************************************/
51/**
52 * Manifest attribute.
53 *
54 * Used both for entries and manifest attributes.
55 */
56typedef struct RTMANIFESTATTR
57{
58 /** The string space core (szName). */
59 RTSTRSPACECORE StrCore;
60 /** The property value. */
61 char *pszValue;
62 /** The attribute type if applicable, RTMANIFEST_ATTR_UNKNOWN if not. */
63 uint32_t fType;
64 /** Whether it was visited by the equals operation or not. */
65 bool fVisited;
66 /** The normalized property name that StrCore::pszString points at. */
67 char szName[1];
68} RTMANIFESTATTR;
69/** Pointer to a manifest attribute. */
70typedef RTMANIFESTATTR *PRTMANIFESTATTR;
71
72
73/**
74 * Manifest entry.
75 */
76typedef struct RTMANIFESTENTRY
77{
78 /** The string space core (szName). */
79 RTSTRSPACECORE StrCore;
80 /** The entry attributes (hashes, checksums, size, etc) -
81 * RTMANIFESTATTR. */
82 RTSTRSPACE Attributes;
83 /** The number of attributes. */
84 uint32_t cAttributes;
85 /** Whether it was visited by the equals operation or not. */
86 bool fVisited;
87 /** The normalized entry name that StrCore::pszString points at. */
88 char szName[1];
89} RTMANIFESTENTRY;
90/** Pointer to a manifest entry. */
91typedef RTMANIFESTENTRY *PRTMANIFESTENTRY;
92
93
94/**
95 * Manifest handle data.
96 */
97typedef struct RTMANIFESTINT
98{
99 /** Magic value (RTMANIFEST_MAGIC). */
100 uint32_t u32Magic;
101 /** The number of references to this manifest. */
102 uint32_t volatile cRefs;
103 /** String space of the entries covered by this manifest -
104 * RTMANIFESTENTRY. */
105 RTSTRSPACE Entries;
106 /** The number of entries. */
107 uint32_t cEntries;
108 /** The entry for the manifest itself. */
109 RTMANIFESTENTRY SelfEntry;
110} RTMANIFESTINT;
111
112/** The value of RTMANIFESTINT::u32Magic. */
113#define RTMANIFEST_MAGIC UINT32_C(0x99998866)
114
115/**
116 * Argument package passed to rtManifestWriteStdAttr by rtManifestWriteStdEntry
117 * and RTManifestWriteStandard.
118 */
119typedef struct RTMANIFESTWRITESTDATTR
120{
121 /** The entry name. */
122 const char *pszEntry;
123 /** The output I/O stream. */
124 RTVFSIOSTREAM hVfsIos;
125} RTMANIFESTWRITESTDATTR;
126
127
128/**
129 * Argument package used by RTManifestEqualsEx to pass it's arguments to the
130 * enumeration callback functions.
131 */
132typedef struct RTMANIFESTEQUALS
133{
134 /** Name of entries to ignore. */
135 const char * const *papszIgnoreEntries;
136 /** Name of attributes to ignore. */
137 const char * const *papszIgnoreAttr;
138 /** Flags governing the comparision. */
139 uint32_t fFlags;
140 /** Where to return an error message (++) on failure. Can be NULL. */
141 char *pszError;
142 /** The size of the buffer pszError points to. Can be 0. */
143 size_t cbError;
144
145 /** Pointer to the 2nd manifest. */
146 RTMANIFESTINT *pThis2;
147
148 /** The number of ignored entries from the 1st manifest. */
149 uint32_t cIgnoredEntries2;
150 /** The number of entries processed from the 2nd manifest. */
151 uint32_t cEntries2;
152
153 /** The number of ignored attributes from the 1st manifest. */
154 uint32_t cIgnoredAttributes1;
155 /** The number of ignored attributes from the 1st manifest. */
156 uint32_t cIgnoredAttributes2;
157 /** The number of attributes processed from the 2nd manifest. */
158 uint32_t cAttributes2;
159 /** Pointer to the string space to get matching attributes from. */
160 PRTSTRSPACE pAttributes2;
161 /** The name of the current entry.
162 * Points to an empty string it's the manifest attributes. */
163 const char *pszCurEntry;
164} RTMANIFESTEQUALS;
165/** Pointer to an RTManifestEqualEx argument packet. */
166typedef RTMANIFESTEQUALS *PRTMANIFESTEQUALS;
167
168
169/**
170 * Creates an empty manifest.
171 *
172 * @returns IPRT status code.
173 * @param fFlags Flags, MBZ.
174 * @param phManifest Where to return the handle to the manifest.
175 */
176RTDECL(int) RTManifestCreate(uint32_t fFlags, PRTMANIFEST phManifest)
177{
178 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
179 AssertPtr(phManifest);
180
181 RTMANIFESTINT *pThis = (RTMANIFESTINT *)RTMemAlloc(sizeof(*pThis));
182 if (!pThis)
183 return VERR_NO_MEMORY;
184
185 pThis->u32Magic = RTMANIFEST_MAGIC;
186 pThis->cRefs = 1;
187 pThis->Entries = NULL;
188 pThis->cEntries = 0;
189 pThis->SelfEntry.StrCore.pszString = "main";
190 pThis->SelfEntry.StrCore.cchString = 4;
191 pThis->SelfEntry.Attributes = NULL;
192 pThis->SelfEntry.cAttributes = 0;
193 pThis->SelfEntry.fVisited = false;
194 pThis->SelfEntry.szName[0] = '\0';
195
196 *phManifest = pThis;
197 return VINF_SUCCESS;
198}
199
200/**
201 * Retains a reference to the manifest handle.
202 *
203 * @returns The new reference count, UINT32_MAX if the handle is invalid.
204 * @param hManifest The handle to retain.
205 */
206RTDECL(uint32_t) RTManifestRetain(RTMANIFEST hManifest)
207{
208 RTMANIFESTINT *pThis = hManifest;
209 AssertPtrReturn(pThis, UINT32_MAX);
210 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, UINT32_MAX);
211
212 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
213 Assert(cRefs > 1 && cRefs < _1M);
214
215 return cRefs;
216}
217
218
219/**
220 * @callback_method_impl{FNRTSTRSPACECALLBACK, Destroys RTMANIFESTATTR.}
221 */
222static DECLCALLBACK(int) rtManifestDestroyAttribute(PRTSTRSPACECORE pStr, void *pvUser)
223{
224 PRTMANIFESTATTR pAttr = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
225 RTStrFree(pAttr->pszValue);
226 pAttr->pszValue = NULL;
227 RTMemFree(pAttr);
228 return 0;
229}
230
231
232/**
233 * @callback_method_impl{FNRTSTRSPACECALLBACK, Destroys RTMANIFESTENTRY.}
234 */
235static DECLCALLBACK(int) rtManifestDestroyEntry(PRTSTRSPACECORE pStr, void *pvUser)
236{
237 PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
238 RTStrSpaceDestroy(&pEntry->Attributes, rtManifestDestroyAttribute, pvUser);
239 RTMemFree(pEntry);
240 return 0;
241}
242
243
244/**
245 * Releases a reference to the manifest handle.
246 *
247 * @returns The new reference count, 0 if free. UINT32_MAX is returned if the
248 * handle is invalid.
249 * @param hManifest The handle to release.
250 * NIL is quietly ignored (returns 0).
251 */
252RTDECL(uint32_t) RTManifestRelease(RTMANIFEST hManifest)
253{
254 RTMANIFESTINT *pThis = hManifest;
255 if (pThis == NIL_RTMANIFEST)
256 return 0;
257 AssertPtrReturn(pThis, UINT32_MAX);
258 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, UINT32_MAX);
259
260 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
261 Assert(cRefs < _1M);
262 if (!cRefs)
263 {
264 ASMAtomicWriteU32(&pThis->u32Magic, ~RTMANIFEST_MAGIC);
265 RTStrSpaceDestroy(&pThis->Entries, rtManifestDestroyEntry,pThis);
266 RTStrSpaceDestroy(&pThis->SelfEntry.Attributes, rtManifestDestroyAttribute, pThis);
267 RTMemFree(pThis);
268 }
269
270 return cRefs;
271}
272
273
274/**
275 * Creates a duplicate of the specified manifest.
276 *
277 * @returns IPRT status code
278 * @param hManifestSrc The manifest to clone.
279 * @param phManifestDst Where to store the handle to the duplicate.
280 */
281RTDECL(int) RTManifestDup(RTMANIFEST hManifestSrc, PRTMANIFEST phManifestDst)
282{
283 RTMANIFESTINT *pThis = hManifestSrc;
284 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
285 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
286 AssertPtr(phManifestDst);
287
288
289 /** @todo implement cloning. */
290
291 return VERR_NOT_IMPLEMENTED;
292}
293
294
295/**
296 * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation.}
297 */
298static DECLCALLBACK(int) rtManifestAttributeClearVisited(PRTSTRSPACECORE pStr, void *pvUser)
299{
300 PRTMANIFESTATTR pAttr = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
301 pAttr->fVisited = false;
302 return 0;
303}
304
305
306/**
307 * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation.}
308 */
309static DECLCALLBACK(int) rtManifestEntryClearVisited(PRTSTRSPACECORE pStr, void *pvUser)
310{
311 PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
312 RTStrSpaceEnumerate(&pEntry->Attributes, rtManifestAttributeClearVisited, NULL);
313 pEntry->fVisited = false;
314 return 0;
315}
316
317
318/**
319 * @callback_method_impl{FNRTSTRSPACECALLBACK, Finds the first missing.}
320 */
321static DECLCALLBACK(int) rtManifestAttributeFindMissing2(PRTSTRSPACECORE pStr, void *pvUser)
322{
323 PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
324 PRTMANIFESTATTR pAttr = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
325
326 /*
327 * Already visited?
328 */
329 if (pAttr->fVisited)
330 return 0;
331
332 /*
333 * Ignore this entry?
334 */
335 char const * const *ppsz = pEquals->papszIgnoreAttr;
336 if (ppsz)
337 {
338 while (*ppsz)
339 {
340 if (!strcmp(*ppsz, pAttr->szName))
341 return 0;
342 ppsz++;
343 }
344 }
345
346 /*
347 * Gotcha!
348 */
349 if (*pEquals->pszCurEntry)
350 RTStrPrintf(pEquals->pszError, pEquals->cbError,
351 "Attribute '%s' on '%s' was not found in the 1st manifest",
352 pAttr->szName, pEquals->pszCurEntry);
353 else
354 RTStrPrintf(pEquals->pszError, pEquals->cbError, "Attribute '%s' was not found in the 1st manifest", pAttr->szName);
355 return VERR_NOT_EQUAL;
356}
357
358
359/**
360 * @callback_method_impl{FNRTSTRSPACECALLBACK, Finds the first missing.}
361 */
362static DECLCALLBACK(int) rtManifestEntryFindMissing2(PRTSTRSPACECORE pStr, void *pvUser)
363{
364 PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
365 PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
366
367 /*
368 * Already visited?
369 */
370 if (pEntry->fVisited)
371 return 0;
372
373 /*
374 * Ignore this entry?
375 */
376 char const * const *ppsz = pEquals->papszIgnoreEntries;
377 if (ppsz)
378 {
379 while (*ppsz)
380 {
381 if (!strcmp(*ppsz, pEntry->StrCore.pszString))
382 return 0;
383 ppsz++;
384 }
385 }
386
387 /*
388 * Gotcha!
389 */
390 RTStrPrintf(pEquals->pszError, pEquals->cbError, "'%s' was not found in the 1st manifest", pEntry->StrCore.pszString);
391 return VERR_NOT_EQUAL;
392}
393
394
395/**
396 * @callback_method_impl{FNRTSTRSPACECALLBACK, Compares attributes.}
397 */
398static DECLCALLBACK(int) rtManifestAttributeCompare(PRTSTRSPACECORE pStr, void *pvUser)
399{
400 PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
401 PRTMANIFESTATTR pAttr1 = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
402 PRTMANIFESTATTR pAttr2;
403
404 Assert(!pAttr1->fVisited);
405 pAttr1->fVisited = true;
406
407 /*
408 * Ignore this entry?
409 */
410 char const * const *ppsz = pEquals->papszIgnoreAttr;
411 if (ppsz)
412 {
413 while (*ppsz)
414 {
415 if (!strcmp(*ppsz, pAttr1->szName))
416 {
417 pAttr2 = (PRTMANIFESTATTR)RTStrSpaceGet(pEquals->pAttributes2, pAttr1->szName);
418 if (pAttr2)
419 {
420 Assert(!pAttr2->fVisited);
421 pAttr2->fVisited = true;
422 pEquals->cIgnoredAttributes2++;
423 }
424 pEquals->cIgnoredAttributes1++;
425 return 0;
426 }
427 ppsz++;
428 }
429 }
430
431 /*
432 * Find the matching attribute.
433 */
434 pAttr2 = (PRTMANIFESTATTR)RTStrSpaceGet(pEquals->pAttributes2, pAttr1->szName);
435 if (!pAttr2)
436 {
437 if (pEquals->fFlags & RTMANIFEST_EQUALS_IGN_MISSING_ATTRS)
438 return 0;
439
440 if (*pEquals->pszCurEntry)
441 RTStrPrintf(pEquals->pszError, pEquals->cbError,
442 "Attribute '%s' on '%s' was not found in the 2nd manifest",
443 pAttr1->szName, pEquals->pszCurEntry);
444 else
445 RTStrPrintf(pEquals->pszError, pEquals->cbError, "Attribute '%s' was not found in the 2nd manifest", pAttr1->szName);
446 return VERR_NOT_EQUAL;
447 }
448
449 Assert(!pAttr2->fVisited);
450 pAttr2->fVisited = true;
451 pEquals->cAttributes2++;
452
453 /*
454 * Compare them.
455 */
456 if (strcmp(pAttr1->pszValue, pAttr2->pszValue))
457 {
458 if (*pEquals->pszCurEntry)
459 RTStrPrintf(pEquals->pszError, pEquals->cbError,
460 "Attribute '%s' on '%s' does not match ('%s' vs. '%s')",
461 pAttr1->szName, pEquals->pszCurEntry, pAttr1->pszValue, pAttr2->pszValue);
462 else
463 RTStrPrintf(pEquals->pszError, pEquals->cbError,
464 "Attribute '%s' does not match ('%s' vs. '%s')",
465 pAttr1->szName, pAttr1->pszValue, pAttr2->pszValue);
466 return VERR_NOT_EQUAL;
467 }
468
469 return 0;
470}
471
472
473/**
474 * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation.}
475 */
476DECLINLINE (int) rtManifestEntryCompare2(PRTMANIFESTEQUALS pEquals, PRTMANIFESTENTRY pEntry1, PRTMANIFESTENTRY pEntry2)
477{
478 /*
479 * Compare the attributes. It's a bit ugly with all this counting, but
480 * how else to efficiently implement RTMANIFEST_EQUALS_IGN_MISSING_ATTRS?
481 */
482 pEquals->cIgnoredAttributes1 = 0;
483 pEquals->cIgnoredAttributes2 = 0;
484 pEquals->cAttributes2 = 0;
485 pEquals->pszCurEntry = &pEntry2->szName[0];
486 pEquals->pAttributes2 = &pEntry2->Attributes;
487 int rc = RTStrSpaceEnumerate(&pEntry1->Attributes, rtManifestAttributeCompare, pEquals);
488 if (RT_SUCCESS(rc))
489 {
490 /*
491 * Check that we matched all that is required.
492 */
493 if ( pEquals->cAttributes2 + pEquals->cIgnoredAttributes2 != pEntry2->cAttributes
494 && ( !(pEquals->fFlags & RTMANIFEST_EQUALS_IGN_MISSING_ATTRS)
495 || pEquals->cIgnoredAttributes1 == pEntry1->cAttributes))
496 rc = RTStrSpaceEnumerate(&pEntry2->Attributes, rtManifestAttributeFindMissing2, pEquals);
497 }
498 return rc;
499}
500
501
502/**
503 * @callback_method_impl{FNRTSTRSPACECALLBACK, Prepare equals operation.}
504 */
505static DECLCALLBACK(int) rtManifestEntryCompare(PRTSTRSPACECORE pStr, void *pvUser)
506{
507 PRTMANIFESTEQUALS pEquals = (PRTMANIFESTEQUALS)pvUser;
508 PRTMANIFESTENTRY pEntry1 = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
509 PRTMANIFESTENTRY pEntry2;
510
511 /*
512 * Ignore this entry.
513 */
514 char const * const *ppsz = pEquals->papszIgnoreEntries;
515 if (ppsz)
516 {
517 while (*ppsz)
518 {
519 if (!strcmp(*ppsz, pStr->pszString))
520 {
521 pEntry2 = (PRTMANIFESTENTRY)RTStrSpaceGet(&pEquals->pThis2->Entries, pStr->pszString);
522 if (pEntry2)
523 {
524 pEntry2->fVisited = true;
525 pEquals->cIgnoredEntries2++;
526 }
527 pEntry1->fVisited = true;
528 return 0;
529 }
530 ppsz++;
531 }
532 }
533
534 /*
535 * Try find the entry in the other manifest.
536 */
537 pEntry2 = (PRTMANIFESTENTRY)RTStrSpaceGet(&pEquals->pThis2->Entries, pEntry1->StrCore.pszString);
538 if (!pEntry2)
539 {
540 RTStrPrintf(pEquals->pszError, pEquals->cbError, "'%s' not found in the 2nd manifest", pEntry1->StrCore.pszString);
541 return VERR_NOT_EQUAL;
542 }
543
544 Assert(!pEntry1->fVisited);
545 Assert(!pEntry2->fVisited);
546 pEntry1->fVisited = true;
547 pEntry2->fVisited = true;
548 pEquals->cEntries2++;
549
550 return rtManifestEntryCompare2(pEquals, pEntry1, pEntry2);
551}
552
553
554
555RTDECL(int) RTManifestEqualsEx(RTMANIFEST hManifest1, RTMANIFEST hManifest2, const char * const *papszIgnoreEntries,
556 const char * const *papszIgnoreAttr, uint32_t fFlags, char *pszError, size_t cbError)
557{
558 /*
559 * Validate input.
560 */
561 AssertPtrNullReturn(pszError, VERR_INVALID_POINTER);
562 if (pszError && cbError)
563 *pszError = '\0';
564 RTMANIFESTINT *pThis1 = hManifest1;
565 RTMANIFESTINT *pThis2 = hManifest2;
566 if (pThis1 != NIL_RTMANIFEST)
567 {
568 AssertPtrReturn(pThis1, VERR_INVALID_HANDLE);
569 AssertReturn(pThis1->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
570 }
571 if (pThis2 != NIL_RTMANIFEST)
572 {
573 AssertPtrReturn(pThis2, VERR_INVALID_HANDLE);
574 AssertReturn(pThis2->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
575 }
576 AssertReturn(!(fFlags & ~(RTMANIFEST_EQUALS_IGN_MISSING_ATTRS)), VERR_INVALID_PARAMETER);
577
578 /*
579 * The simple cases.
580 */
581 if (pThis1 == pThis2)
582 return VINF_SUCCESS;
583 if (pThis1 == NIL_RTMANIFEST || pThis2 == NIL_RTMANIFEST)
584 return VERR_NOT_EQUAL;
585
586 /*
587 * Since we have to use callback style enumeration, we have to mark the
588 * entries and attributes to make sure we've covered them all.
589 */
590 RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryClearVisited, NULL);
591 RTStrSpaceEnumerate(&pThis2->Entries, rtManifestEntryClearVisited, NULL);
592 RTStrSpaceEnumerate(&pThis1->SelfEntry.Attributes, rtManifestAttributeClearVisited, NULL);
593 RTStrSpaceEnumerate(&pThis2->SelfEntry.Attributes, rtManifestAttributeClearVisited, NULL);
594
595 RTMANIFESTEQUALS Equals;
596 Equals.pThis2 = pThis2;
597 Equals.fFlags = fFlags;
598 Equals.papszIgnoreEntries = papszIgnoreEntries;
599 Equals.papszIgnoreAttr = papszIgnoreAttr;
600 Equals.pszError = pszError;
601 Equals.cbError = cbError;
602
603 Equals.cIgnoredEntries2 = 0;
604 Equals.cEntries2 = 0;
605 Equals.cIgnoredAttributes1 = 0;
606 Equals.cIgnoredAttributes2 = 0;
607 Equals.cAttributes2 = 0;
608 Equals.pAttributes2 = NULL;
609 Equals.pszCurEntry = NULL;
610
611 int rc = rtManifestEntryCompare2(&Equals, &pThis1->SelfEntry, &pThis2->SelfEntry);
612 if (RT_SUCCESS(rc))
613 rc = RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryCompare, &Equals);
614 if (RT_SUCCESS(rc))
615 {
616 /*
617 * Did we cover all entries of the 2nd manifest?
618 */
619 if (Equals.cEntries2 + Equals.cIgnoredEntries2 != pThis2->cEntries)
620 rc = RTStrSpaceEnumerate(&pThis1->Entries, rtManifestEntryFindMissing2, &Equals);
621 }
622
623 return rc;
624}
625
626
627RTDECL(int) RTManifestEquals(RTMANIFEST hManifest1, RTMANIFEST hManifest2)
628{
629 return RTManifestEqualsEx(hManifest1, hManifest2,
630 NULL /*papszIgnoreEntries*/, NULL /*papszIgnoreAttrs*/,
631 0 /*fFlags*/, NULL, 0);
632}
633
634
635/**
636 * Worker common to RTManifestSetAttr and RTManifestEntrySetAttr.
637 *
638 * @returns IPRT status code.
639 * @param pEntry Pointer to the entry.
640 * @param pszAttr The name of the attribute to add.
641 * @param pszValue The value string.
642 * @param fType The attribute type type.
643 */
644static int rtManifestSetAttrWorker(PRTMANIFESTENTRY pEntry, const char *pszAttr, const char *pszValue, uint32_t fType)
645{
646 char *pszValueCopy;
647 int rc = RTStrDupEx(&pszValueCopy, pszValue);
648 if (RT_FAILURE(rc))
649 return rc;
650
651 /*
652 * Does the attribute exist already?
653 */
654 AssertCompileMemberOffset(RTMANIFESTATTR, StrCore, 0);
655 PRTMANIFESTATTR pAttr = (PRTMANIFESTATTR)RTStrSpaceGet(&pEntry->Attributes, pszAttr);
656 if (pAttr)
657 {
658 RTStrFree(pAttr->pszValue);
659 pAttr->pszValue = pszValueCopy;
660 pAttr->fType = fType;
661 }
662 else
663 {
664 size_t cbName = strlen(pszAttr) + 1;
665 pAttr = (PRTMANIFESTATTR)RTMemAllocVar(RT_OFFSETOF(RTMANIFESTATTR, szName[cbName]));
666 if (!pAttr)
667 {
668 RTStrFree(pszValueCopy);
669 return VERR_NO_MEMORY;
670 }
671 memcpy(pAttr->szName, pszAttr, cbName);
672 pAttr->StrCore.pszString = pAttr->szName;
673 pAttr->StrCore.cchString = cbName - 1;
674 pAttr->pszValue = pszValueCopy;
675 pAttr->fType = fType;
676 if (RT_UNLIKELY(!RTStrSpaceInsert(&pEntry->Attributes, &pAttr->StrCore)))
677 {
678 AssertFailed();
679 RTStrFree(pszValueCopy);
680 RTMemFree(pAttr);
681 return VERR_INTERNAL_ERROR_4;
682 }
683 pEntry->cAttributes++;
684 }
685
686 return VINF_SUCCESS;
687}
688
689
690/**
691 * Sets a manifest attribute.
692 *
693 * @returns IPRT status code.
694 * @param hManifest The manifest handle.
695 * @param pszAttr The attribute name. If this already exists,
696 * its value will be replaced.
697 * @param pszValue The value string.
698 * @param fType The attribute type, pass
699 * RTMANIFEST_ATTR_UNKNOWN if not known.
700 */
701RTDECL(int) RTManifestSetAttr(RTMANIFEST hManifest, const char *pszAttr, const char *pszValue, uint32_t fType)
702{
703 RTMANIFESTINT *pThis = hManifest;
704 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
705 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
706 AssertPtr(pszAttr);
707 AssertPtr(pszValue);
708 AssertReturn(RT_IS_POWER_OF_TWO(fType) && fType < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
709
710 return rtManifestSetAttrWorker(&pThis->SelfEntry, pszAttr, pszValue, fType);
711}
712
713
714/**
715 * Worker common to RTManifestUnsetAttr and RTManifestEntryUnsetAttr.
716 *
717 * @returns IPRT status code.
718 * @param pEntry Pointer to the entry.
719 * @param pszAttr The name of the attribute to remove.
720 */
721static int rtManifestUnsetAttrWorker(PRTMANIFESTENTRY pEntry, const char *pszAttr)
722{
723 PRTSTRSPACECORE pStrCore = RTStrSpaceRemove(&pEntry->Attributes, pszAttr);
724 if (!pStrCore)
725 return VWRN_NOT_FOUND;
726 pEntry->cAttributes--;
727 rtManifestDestroyAttribute(pStrCore, NULL);
728 return VINF_SUCCESS;
729}
730
731
732/**
733 * Unsets (removes) a manifest attribute if it exists.
734 *
735 * @returns IPRT status code.
736 * @retval VWRN_NOT_FOUND if not found.
737 *
738 * @param hManifest The manifest handle.
739 * @param pszAttr The attribute name.
740 */
741RTDECL(int) RTManifestUnsetAttr(RTMANIFEST hManifest, const char *pszAttr)
742{
743 RTMANIFESTINT *pThis = hManifest;
744 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
745 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
746 AssertPtr(pszAttr);
747
748 return rtManifestUnsetAttrWorker(&pThis->SelfEntry, pszAttr);
749}
750
751
752/**
753 * Validates the name entry.
754 *
755 * @returns IPRT status code.
756 * @param pszEntry The entry name to validate.
757 * @param pfNeedNormalization Where to return whether it needs normalization
758 * or not. Optional.
759 * @param pcchEntry Where to return the length. Optional.
760 */
761static int rtManifestValidateNameEntry(const char *pszEntry, bool *pfNeedNormalization, size_t *pcchEntry)
762{
763 int rc;
764 bool fNeedNormalization = false;
765 const char *pszCur = pszEntry;
766
767 for (;;)
768 {
769 RTUNICP uc;
770 rc = RTStrGetCpEx(&pszCur, &uc);
771 if (RT_FAILURE(rc))
772 return rc;
773 if (!uc)
774 break;
775 if (uc == '\\')
776 fNeedNormalization = true;
777 else if (uc < 32 || uc == ':' || uc == '(' || uc == ')')
778 return VERR_INVALID_NAME;
779 }
780
781 if (pfNeedNormalization)
782 *pfNeedNormalization = fNeedNormalization;
783
784 size_t cchEntry = pszCur - pszEntry - 1;
785 if (!cchEntry)
786 rc = VERR_INVALID_NAME;
787 if (pcchEntry)
788 *pcchEntry = cchEntry;
789
790 return rc;
791}
792
793
794/**
795 * Normalizes a entry name.
796 *
797 * @param pszEntry The entry name to normalize.
798 */
799static void rtManifestNormalizeEntry(char *pszEntry)
800{
801 char ch;
802 while ((ch = *pszEntry))
803 {
804 if (ch == '\\')
805 *pszEntry = '/';
806 pszEntry++;
807 }
808}
809
810
811/**
812 * Gets an entry.
813 *
814 * @returns IPRT status code.
815 * @param pThis The manifest to work with.
816 * @param pszEntry The entry name.
817 * @param fNeedNormalization Whether rtManifestValidateNameEntry said it
818 * needed normalization.
819 * @param cchEntry The length of the name.
820 * @param ppEntry Where to return the entry pointer on success.
821 */
822static int rtManifestGetEntry(RTMANIFESTINT *pThis, const char *pszEntry, bool fNeedNormalization, size_t cchEntry,
823 PRTMANIFESTENTRY *ppEntry)
824{
825 PRTMANIFESTENTRY pEntry;
826
827 AssertCompileMemberOffset(RTMANIFESTATTR, StrCore, 0);
828 if (!fNeedNormalization)
829 pEntry = (PRTMANIFESTENTRY)RTStrSpaceGet(&pThis->Entries, pszEntry);
830 else
831 {
832 char *pszCopy = (char *)RTMemTmpAlloc(cchEntry + 1);
833 if (RT_UNLIKELY(!pszCopy))
834 return VERR_NO_TMP_MEMORY;
835 memcpy(pszCopy, pszEntry, cchEntry + 1);
836 rtManifestNormalizeEntry(pszCopy);
837
838 pEntry = (PRTMANIFESTENTRY)RTStrSpaceGet(&pThis->Entries, pszCopy);
839 RTMemTmpFree(pszCopy);
840 }
841
842 *ppEntry = pEntry;
843 return pEntry ? VINF_SUCCESS : VERR_NOT_FOUND;
844}
845
846
847/**
848 * Sets an attribute of a manifest entry.
849 *
850 * @returns IPRT status code.
851 * @param hManifest The manifest handle.
852 * @param pszEntry The entry name. This will automatically be
853 * added if there was no previous call to
854 * RTManifestEntryAdd for this name. See
855 * RTManifestEntryAdd for the entry name rules.
856 * @param pszAttr The attribute name. If this already exists,
857 * its value will be replaced.
858 * @param pszValue The value string.
859 * @param fType The attribute type, pass
860 * RTMANIFEST_ATTR_UNKNOWN if not known.
861 */
862RTDECL(int) RTManifestEntrySetAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr,
863 const char *pszValue, uint32_t fType)
864{
865 RTMANIFESTINT *pThis = hManifest;
866 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
867 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
868 AssertPtr(pszEntry);
869 AssertPtr(pszAttr);
870 AssertPtr(pszValue);
871 AssertReturn(RT_IS_POWER_OF_TWO(fType) && fType < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER);
872
873 bool fNeedNormalization;
874 size_t cchEntry;
875 int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
876 AssertRCReturn(rc, rc);
877
878 /*
879 * Resolve the entry, adding one if necessary.
880 */
881 PRTMANIFESTENTRY pEntry;
882 rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
883 if (rc == VERR_NOT_FOUND)
884 {
885 pEntry = (PRTMANIFESTENTRY)RTMemAlloc(RT_OFFSETOF(RTMANIFESTENTRY, szName[cchEntry + 1]));
886 if (!pEntry)
887 return VERR_NO_MEMORY;
888
889 pEntry->StrCore.cchString = cchEntry;
890 pEntry->StrCore.pszString = pEntry->szName;
891 pEntry->Attributes = NULL;
892 pEntry->cAttributes = 0;
893 memcpy(pEntry->szName, pszEntry, cchEntry + 1);
894 if (fNeedNormalization)
895 rtManifestNormalizeEntry(pEntry->szName);
896
897 if (!RTStrSpaceInsert(&pThis->Entries, &pEntry->StrCore))
898 {
899 RTMemFree(pEntry);
900 return VERR_INTERNAL_ERROR_4;
901 }
902 pThis->cEntries++;
903 }
904 else if (RT_FAILURE(rc))
905 return rc;
906
907 return rtManifestSetAttrWorker(pEntry, pszAttr, pszValue, fType);
908}
909
910
911/**
912 * Unsets (removes) an attribute of a manifest entry if they both exist.
913 *
914 * @returns IPRT status code.
915 * @retval VWRN_NOT_FOUND if not found.
916 *
917 * @param hManifest The manifest handle.
918 * @param pszEntry The entry name.
919 * @param pszAttr The attribute name.
920 */
921RTDECL(int) RTManifestEntryUnsetAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr)
922{
923 RTMANIFESTINT *pThis = hManifest;
924 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
925 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
926 AssertPtr(pszEntry);
927 AssertPtr(pszAttr);
928
929 bool fNeedNormalization;
930 size_t cchEntry;
931 int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
932 AssertRCReturn(rc, rc);
933
934 /*
935 * Resolve the entry and hand it over to the worker.
936 */
937 PRTMANIFESTENTRY pEntry;
938 rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
939 if (RT_SUCCESS(rc))
940 rc = rtManifestUnsetAttrWorker(pEntry, pszAttr);
941 return rc;
942}
943
944
945/**
946 * Adds a new entry to a manifest.
947 *
948 * The entry name rules:
949 * - The entry name can contain any character defined by unicode, except
950 * control characters, ':', '(' and ')'. The exceptions are mainly there
951 * because of uncertainty around how various formats handles these.
952 * - It is considered case sensitive.
953 * - Forward (unix) and backward (dos) slashes are considered path
954 * separators and converted to forward slashes.
955 *
956 * @returns IPRT status code.
957 * @retval VWRN_ALREADY_EXISTS if the entry already exists.
958 *
959 * @param hManifest The manifest handle.
960 * @param pszEntry The entry name (UTF-8).
961 *
962 * @remarks Some manifest formats will not be able to store an entry without
963 * any attributes. So, this is just here in case it comes in handy
964 * when dealing with formats which can.
965 */
966RTDECL(int) RTManifestEntryAdd(RTMANIFEST hManifest, const char *pszEntry)
967{
968 RTMANIFESTINT *pThis = hManifest;
969 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
970 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
971 AssertPtr(pszEntry);
972
973 bool fNeedNormalization;
974 size_t cchEntry;
975 int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
976 AssertRCReturn(rc, rc);
977
978 /*
979 * Only add one if it does not already exist.
980 */
981 PRTMANIFESTENTRY pEntry;
982 rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
983 if (rc == VERR_NOT_FOUND)
984 {
985 pEntry = (PRTMANIFESTENTRY)RTMemAlloc(RT_OFFSETOF(RTMANIFESTENTRY, szName[cchEntry + 1]));
986 if (pEntry)
987 {
988 pEntry->StrCore.cchString = cchEntry;
989 pEntry->StrCore.pszString = pEntry->szName;
990 pEntry->Attributes = NULL;
991 pEntry->cAttributes = 0;
992 memcpy(pEntry->szName, pszEntry, cchEntry + 1);
993 if (fNeedNormalization)
994 rtManifestNormalizeEntry(pEntry->szName);
995
996 if (RTStrSpaceInsert(&pThis->Entries, &pEntry->StrCore))
997 {
998 pThis->cEntries++;
999 rc = VINF_SUCCESS;
1000 }
1001 else
1002 {
1003 RTMemFree(pEntry);
1004 rc = VERR_INTERNAL_ERROR_4;
1005 }
1006 }
1007 else
1008 rc = VERR_NO_MEMORY;
1009 }
1010 else if (RT_SUCCESS(rc))
1011 rc = VWRN_ALREADY_EXISTS;
1012
1013 return rc;
1014}
1015
1016
1017/**
1018 * Removes an entry.
1019 *
1020 * @returns IPRT status code.
1021 * @param hManifest The manifest handle.
1022 * @param pszEntry The entry name.
1023 */
1024RTDECL(int) RTManifestEntryRemove(RTMANIFEST hManifest, const char *pszEntry)
1025{
1026 RTMANIFESTINT *pThis = hManifest;
1027 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1028 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
1029 AssertPtr(pszEntry);
1030
1031 bool fNeedNormalization;
1032 size_t cchEntry;
1033 int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
1034 AssertRCReturn(rc, rc);
1035
1036 /*
1037 * Look it up before removing it.
1038 */
1039 PRTMANIFESTENTRY pEntry;
1040 rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
1041 if (RT_SUCCESS(rc))
1042 {
1043 PRTSTRSPACECORE pStrCore = RTStrSpaceRemove(&pThis->Entries, pEntry->StrCore.pszString);
1044 AssertReturn(pStrCore, VERR_INTERNAL_ERROR_3);
1045 pThis->cEntries--;
1046 rtManifestDestroyEntry(pStrCore, pThis);
1047 }
1048
1049 return rc;
1050}
1051
1052
1053RTDECL(bool) RTManifestEntryExists(RTMANIFEST hManifest, const char *pszEntry)
1054{
1055 RTMANIFESTINT *pThis = hManifest;
1056 AssertPtrReturn(pThis, false);
1057 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, false);
1058 AssertPtr(pszEntry);
1059
1060 bool fNeedNormalization;
1061 size_t cchEntry;
1062 int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry);
1063 AssertRCReturn(rc, false);
1064
1065 /*
1066 * Check if it exists.
1067 */
1068 PRTMANIFESTENTRY pEntry;
1069 rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry);
1070 return RT_SUCCESS_NP(rc);
1071}
1072
1073
1074/**
1075 * Reads a line from a VFS I/O stream.
1076 *
1077 * @todo Replace this with a buffered I/O stream layer.
1078 *
1079 * @returns IPRT status code. VERR_EOF when trying to read beyond the stream
1080 * end.
1081 * @param hVfsIos The I/O stream to read from.
1082 * @param pszLine Where to store what we've read.
1083 * @param cbLine The number of bytes to read.
1084 */
1085static int rtManifestReadLine(RTVFSIOSTREAM hVfsIos, char *pszLine, size_t cbLine)
1086{
1087 /* This is horribly slow right now, but it's not a biggy as the input is
1088 usually cached in memory somewhere... */
1089 *pszLine = '\0';
1090 while (cbLine > 1)
1091 {
1092 char ch;
1093 int rc = RTVfsIoStrmRead(hVfsIos, &ch, 1, true /*fBLocking*/, NULL);
1094 if (RT_FAILURE(rc))
1095 return rc;
1096
1097 /* \r\n */
1098 if (ch == '\r')
1099 {
1100 if (cbLine <= 2)
1101 {
1102 pszLine[0] = ch;
1103 pszLine[1] = '\0';
1104 return VINF_BUFFER_OVERFLOW;
1105 }
1106
1107 rc = RTVfsIoStrmRead(hVfsIos, &ch, 1, true /*fBLocking*/, NULL);
1108 if (RT_SUCCESS(rc) && ch == '\n')
1109 return VINF_SUCCESS;
1110 pszLine[0] = '\r';
1111 pszLine[1] = ch;
1112 pszLine[2] = '\0';
1113 if (RT_FAILURE(rc))
1114 return rc == VERR_EOF ? VINF_EOF : rc;
1115 }
1116
1117 /* \n */
1118 if (ch == '\n')
1119 return VINF_SUCCESS;
1120
1121 /* add character. */
1122 pszLine[0] = ch;
1123 pszLine[1] = '\0';
1124
1125 /* advance */
1126 pszLine++;
1127 cbLine--;
1128 }
1129
1130 return VINF_BUFFER_OVERFLOW;
1131}
1132
1133
1134RTDECL(int) RTManifestReadStandardEx(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, char *pszErr, size_t cbErr)
1135{
1136 /*
1137 * Validate input.
1138 */
1139 AssertPtrNull(pszErr);
1140 if (pszErr && cbErr)
1141 *pszErr = '\0';
1142 RTMANIFESTINT *pThis = hManifest;
1143 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1144 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
1145
1146 /*
1147 * Process the stream line by line.
1148 */
1149 uint32_t iLine = 0;
1150 for (;;)
1151 {
1152 /*
1153 * Read a line from the input stream.
1154 */
1155 iLine++;
1156 char szLine[RTPATH_MAX + RTSHA512_DIGEST_LEN + 32];
1157 int rc = rtManifestReadLine(hVfsIos, szLine, sizeof(szLine));
1158 if (RT_FAILURE(rc))
1159 {
1160 if (rc == VERR_EOF)
1161 return VINF_SUCCESS;
1162 RTStrPrintf(pszErr, cbErr, "Error reading line #u: %Rrc", iLine, rc);
1163 return rc;
1164 }
1165 if (rc != VINF_SUCCESS)
1166 {
1167 RTStrPrintf(pszErr, cbErr, "Line number %u is too long", iLine);
1168 return VERR_OUT_OF_RANGE;
1169 }
1170
1171 /*
1172 * Strip it and skip if empty.
1173 */
1174 char *psz = RTStrStrip(szLine);
1175 if (!*psz)
1176 continue;
1177
1178 /*
1179 * Read the attribute name.
1180 */
1181 const char * const pszAttr = psz;
1182 do
1183 psz++;
1184 while (!RT_C_IS_BLANK(*psz) && *psz);
1185 if (*psz)
1186 *psz++ = '\0';
1187
1188 /*
1189 * The entry name is enclosed in parenthesis and followed by a '='.
1190 */
1191 psz = RTStrStripL(psz);
1192 if (*psz != '(')
1193 {
1194 RTStrPrintf(pszErr, cbErr, "Expected '(' after %zu on line %u", psz - szLine, iLine);
1195 return VERR_PARSE_ERROR;
1196 }
1197 const char * const pszName = ++psz;
1198 while (*psz)
1199 {
1200 if (*psz == ')')
1201 {
1202 char *psz2 = RTStrStripL(psz + 1);
1203 if (*psz2 == '=')
1204 {
1205 *psz = '\0';
1206 psz = psz2;
1207 break;
1208 }
1209 }
1210 psz++;
1211 }
1212
1213 if (*psz != '=')
1214 {
1215 RTStrPrintf(pszErr, cbErr, "Expected ')=' at %zu on line %u", psz - szLine, iLine);
1216 return VERR_PARSE_ERROR;
1217 }
1218
1219 /*
1220 * The value.
1221 */
1222 psz = RTStrStrip(psz + 1);
1223 const char * const pszValue = psz;
1224 if (!*psz)
1225 {
1226 RTStrPrintf(pszErr, cbErr, "Expected value at %zu on line %u", psz - szLine, iLine);
1227 return VERR_PARSE_ERROR;
1228 }
1229
1230 /*
1231 * Detect attribute type and sanity check the value.
1232 */
1233 uint32_t fType = RTMANIFEST_ATTR_UNKNOWN;
1234 static const struct
1235 {
1236 const char *pszAttr;
1237 uint32_t fType;
1238 unsigned cBits;
1239 unsigned uBase;
1240 } s_aDecAttrs[] =
1241 {
1242 { "SIZE", RTMANIFEST_ATTR_SIZE, 64, 10}
1243 };
1244 for (unsigned i = 0; i < RT_ELEMENTS(s_aDecAttrs); i++)
1245 if (!strcmp(s_aDecAttrs[i].pszAttr, pszAttr))
1246 {
1247 fType = s_aDecAttrs[i].fType;
1248 rc = RTStrToUInt64Full(pszValue, s_aDecAttrs[i].uBase, NULL);
1249 if (rc != VINF_SUCCESS)
1250 {
1251 RTStrPrintf(pszErr, cbErr, "Malformed value ('%s') at %zu on line %u: %Rrc", pszValue, psz - szLine, iLine, rc);
1252 return VERR_PARSE_ERROR;
1253 }
1254 break;
1255 }
1256
1257 if (fType == RTMANIFEST_ATTR_UNKNOWN)
1258 {
1259 static const struct
1260 {
1261 const char *pszAttr;
1262 uint32_t fType;
1263 unsigned cchHex;
1264 } s_aHexAttrs[] =
1265 {
1266 { "MD5", RTMANIFEST_ATTR_MD5, RTMD5_DIGEST_LEN },
1267 { "SHA1", RTMANIFEST_ATTR_SHA1, RTSHA1_DIGEST_LEN },
1268 { "SHA256", RTMANIFEST_ATTR_SHA256, RTSHA256_DIGEST_LEN },
1269 { "SHA512", RTMANIFEST_ATTR_SHA512, RTSHA512_DIGEST_LEN }
1270 };
1271 for (unsigned i = 0; i < RT_ELEMENTS(s_aHexAttrs); i++)
1272 if (!strcmp(s_aHexAttrs[i].pszAttr, pszAttr))
1273 {
1274 fType = s_aHexAttrs[i].fType;
1275 for (unsigned off = 0; off < s_aHexAttrs[i].cchHex; off++)
1276 if (!RT_C_IS_XDIGIT(pszValue[off]))
1277 {
1278 RTStrPrintf(pszErr, cbErr, "Expected hex digit at %zu on line %u (value '%s', pos %u)",
1279 pszValue - szLine + off, iLine, pszValue, off);
1280 return VERR_PARSE_ERROR;
1281 }
1282 break;
1283 }
1284 }
1285
1286 /*
1287 * Finally, add it.
1288 */
1289 rc = RTManifestEntrySetAttr(hManifest, pszName, pszAttr, pszValue, fType);
1290 if (RT_FAILURE(rc))
1291 {
1292 RTStrPrintf(pszErr, cbErr, "RTManifestEntrySetAttr(,'%s','%s', '%s', %#x) failed on line %u: %Rrc",
1293 pszName, pszAttr, pszValue, fType, iLine, rc);
1294 return rc;
1295 }
1296 }
1297}
1298
1299RTDECL(int) RTManifestReadStandard(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos)
1300{
1301 return RTManifestReadStandardEx(hManifest, hVfsIos, NULL, 0);
1302}
1303
1304
1305/**
1306 * @callback_method_impl{FNRTSTRSPACECALLBACK, Writes RTMANIFESTATTR.}
1307 */
1308static DECLCALLBACK(int) rtManifestWriteStdAttr(PRTSTRSPACECORE pStr, void *pvUser)
1309{
1310 PRTMANIFESTATTR pAttr = RT_FROM_MEMBER(pStr, RTMANIFESTATTR, StrCore);
1311 RTMANIFESTWRITESTDATTR *pArgs = (RTMANIFESTWRITESTDATTR *)pvUser;
1312 char szLine[RTPATH_MAX + RTSHA512_DIGEST_LEN + 32];
1313 size_t cchLine = RTStrPrintf(szLine, sizeof(szLine), "%s (%s) = %s\n", pAttr->szName, pArgs->pszEntry, pAttr->pszValue);
1314 if (cchLine >= sizeof(szLine) - 1)
1315 return VERR_BUFFER_OVERFLOW;
1316 return RTVfsIoStrmWrite(pArgs->hVfsIos, szLine, cchLine, true /*fBlocking*/, NULL);
1317}
1318
1319
1320/**
1321 * @callback_method_impl{FNRTSTRSPACECALLBACK, Writes RTMANIFESTENTRY.}
1322 */
1323static DECLCALLBACK(int) rtManifestWriteStdEntry(PRTSTRSPACECORE pStr, void *pvUser)
1324{
1325 PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore);
1326
1327 RTMANIFESTWRITESTDATTR Args;
1328 Args.hVfsIos = (RTVFSIOSTREAM)pvUser;
1329 Args.pszEntry = pStr->pszString;
1330 return RTStrSpaceEnumerate(&pEntry->Attributes, rtManifestWriteStdAttr, &Args);
1331}
1332
1333
1334RTDECL(int) RTManifestWriteStandard(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos)
1335{
1336 RTMANIFESTINT *pThis = hManifest;
1337 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1338 AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);
1339
1340 RTMANIFESTWRITESTDATTR Args;
1341 Args.hVfsIos = hVfsIos;
1342 Args.pszEntry = "main";
1343 int rc = RTStrSpaceEnumerate(&pThis->SelfEntry.Attributes, rtManifestWriteStdAttr, &Args);
1344 if (RT_SUCCESS(rc))
1345 rc = RTStrSpaceEnumerate(&pThis->Entries, rtManifestWriteStdEntry, hVfsIos);
1346 return rc;
1347}
1348
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette