xref: /haiku/src/add-ons/kernel/file_systems/packagefs/package/Package.cpp (revision 20d9f6e4083b17383500b1e46d705fedf36b08d8)
1 /*
2  * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "Package.h"
8 
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #include <package/hpkg/ErrorOutput.h>
16 #include <package/hpkg/PackageDataReader.h>
17 #include <package/hpkg/PackageEntry.h>
18 #include <package/hpkg/PackageEntryAttribute.h>
19 
20 #include <AutoDeleter.h>
21 #include <FdIO.h>
22 #include <package/hpkg/PackageFileHeapReader.h>
23 #include <package/hpkg/PackageReaderImpl.h>
24 #include <util/AutoLock.h>
25 
26 #include "CachedDataReader.h"
27 #include "DebugSupport.h"
28 #include "PackageDirectory.h"
29 #include "PackageFile.h"
30 #include "PackagesDirectory.h"
31 #include "PackageSettings.h"
32 #include "PackageSymlink.h"
33 #include "Version.h"
34 #include "Volume.h"
35 
36 
37 using namespace BPackageKit;
38 
39 using BPackageKit::BHPKG::BErrorOutput;
40 using BPackageKit::BHPKG::BFDDataReader;
41 using BPackageKit::BHPKG::BPackageInfoAttributeValue;
42 using BPackageKit::BHPKG::BPackageVersionData;
43 using BPackageKit::BHPKG::BPrivate::PackageFileHeapReader;
44 
45 // current format version types
46 typedef BPackageKit::BHPKG::BPackageContentHandler BPackageContentHandler;
47 typedef BPackageKit::BHPKG::BPackageEntry BPackageEntry;
48 typedef BPackageKit::BHPKG::BPackageEntryAttribute BPackageEntryAttribute;
49 typedef BPackageKit::BHPKG::BPrivate::PackageReaderImpl PackageReaderImpl;
50 
51 
52 const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
53 	"any",
54 	"x86",
55 	"x86_gcc2",
56 	"source",
57 	"x86_64",
58 	"ppc",
59 	"arm",
60 	"m68k",
61 	"sparc",
62 	"arm64",
63 	"riscv64"
64 };
65 
66 
67 // #pragma mark - LoaderErrorOutput
68 
69 
70 struct Package::LoaderErrorOutput : BErrorOutput {
LoaderErrorOutputPackage::LoaderErrorOutput71 	LoaderErrorOutput(Package* package)
72 		:
73 		fPackage(package)
74 	{
75 	}
76 
PrintErrorVarArgsPackage::LoaderErrorOutput77 	virtual void PrintErrorVarArgs(const char* format, va_list args)
78 	{
79 		ERRORV(format, args);
80 	}
81 
82 private:
83 	Package*	fPackage;
84 };
85 
86 
87 // #pragma mark - LoaderContentHandler
88 
89 
90 struct Package::LoaderContentHandler : BPackageContentHandler {
LoaderContentHandlerPackage::LoaderContentHandler91 	LoaderContentHandler(Package* package, const PackageSettings& settings)
92 		:
93 		fPackage(package),
94 		fSettings(settings),
95 		fSettingsItem(NULL),
96 		fLastSettingsEntry(NULL),
97 		fLastSettingsEntryEntry(NULL),
98 		fErrorOccurred(false)
99 	{
100 	}
101 
InitPackage::LoaderContentHandler102 	status_t Init()
103 	{
104 		return B_OK;
105 	}
106 
HandleEntryPackage::LoaderContentHandler107 	virtual status_t HandleEntry(BPackageEntry* entry)
108 	{
109 		if (fErrorOccurred
110 			|| (fLastSettingsEntry != NULL
111 				&& fLastSettingsEntry->IsBlocked())) {
112 			return B_OK;
113 		}
114 
115 		PackageDirectory* parentDir = NULL;
116 		if (entry->Parent() != NULL) {
117 			parentDir = dynamic_cast<PackageDirectory*>(
118 				(PackageNode*)entry->Parent()->UserToken());
119 			if (parentDir == NULL)
120 				RETURN_ERROR(B_BAD_DATA);
121 		}
122 
123 		if (fSettingsItem != NULL
124 			&& (parentDir == NULL
125 				|| entry->Parent() == fLastSettingsEntryEntry)) {
126 			PackageSettingsItem::Entry* settingsEntry
127 				= fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name());
128 			if (settingsEntry != NULL) {
129 				fLastSettingsEntry = settingsEntry;
130 				fLastSettingsEntryEntry = entry;
131 				if (fLastSettingsEntry->IsBlocked())
132 					return B_OK;
133 			}
134 		}
135 
136 		// get the file mode -- filter out write permissions
137 		mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
138 
139 		// create the package node
140 		PackageNode* node;
141 		if (S_ISREG(mode)) {
142 			// file
143 			node = new PackageFile(fPackage, mode,
144 				PackageData(entry->Data()));
145 		} else if (S_ISLNK(mode)) {
146 			// symlink
147 			String path;
148 			if (!path.SetTo(entry->SymlinkPath()))
149 				RETURN_ERROR(B_NO_MEMORY);
150 
151 			PackageSymlink* symlink = new PackageSymlink(fPackage, mode);
152 			if (symlink == NULL)
153 				RETURN_ERROR(B_NO_MEMORY);
154 
155 			symlink->SetSymlinkPath(path);
156 			node = symlink;
157 		} else if (S_ISDIR(mode)) {
158 			// directory
159 			node = new PackageDirectory(fPackage, mode);
160 		} else
161 			RETURN_ERROR(B_BAD_DATA);
162 
163 		if (node == NULL)
164 			RETURN_ERROR(B_NO_MEMORY);
165 		BReference<PackageNode> nodeReference(node, true);
166 
167 		String entryName;
168 		if (!entryName.SetTo(entry->Name()))
169 			RETURN_ERROR(B_NO_MEMORY);
170 
171 		status_t error = node->Init(parentDir, entryName);
172 		if (error != B_OK)
173 			RETURN_ERROR(error);
174 
175 		node->SetModifiedTime(entry->ModifiedTime());
176 
177 		// add it to the parent directory
178 		if (parentDir != NULL)
179 			parentDir->AddChild(node);
180 		else
181 			fPackage->AddNode(node);
182 
183 		entry->SetUserToken(node);
184 
185 		return B_OK;
186 	}
187 
HandleEntryAttributePackage::LoaderContentHandler188 	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
189 		BPackageEntryAttribute* attribute)
190 	{
191 		if (fErrorOccurred
192 			|| (fLastSettingsEntry != NULL
193 				&& fLastSettingsEntry->IsBlocked())) {
194 			return B_OK;
195 		}
196 
197 		PackageNode* node = (PackageNode*)entry->UserToken();
198 
199 		String name;
200 		if (!name.SetTo(attribute->Name()))
201 			RETURN_ERROR(B_NO_MEMORY);
202 
203 		PackageNodeAttribute* nodeAttribute = new
204 			PackageNodeAttribute(attribute->Type(),
205 			PackageData(attribute->Data()));
206 		if (nodeAttribute == NULL)
207 			RETURN_ERROR(B_NO_MEMORY)
208 
209 		nodeAttribute->Init(name);
210 		node->AddAttribute(nodeAttribute);
211 
212 		return B_OK;
213 	}
214 
HandleEntryDonePackage::LoaderContentHandler215 	virtual status_t HandleEntryDone(BPackageEntry* entry)
216 	{
217 		if (entry == fLastSettingsEntryEntry) {
218 			fLastSettingsEntryEntry = entry->Parent();
219 			fLastSettingsEntry = fLastSettingsEntry->Parent();
220 		}
221 
222 		return B_OK;
223 	}
224 
HandlePackageAttributePackage::LoaderContentHandler225 	virtual status_t HandlePackageAttribute(
226 		const BPackageInfoAttributeValue& value)
227 	{
228 		switch (value.attributeID) {
229 			case B_PACKAGE_INFO_NAME:
230 			{
231 				String name;
232 				if (!name.SetTo(value.string))
233 					return B_NO_MEMORY;
234 				fPackage->SetName(name);
235 
236 				fSettingsItem = fSettings.PackageItemFor(fPackage->Name());
237 
238 				return B_OK;
239 			}
240 
241 			case B_PACKAGE_INFO_INSTALL_PATH:
242 			{
243 				String path;
244 				if (!path.SetTo(value.string))
245 					return B_NO_MEMORY;
246 				fPackage->SetInstallPath(path);
247 				return B_OK;
248 			}
249 
250 			case B_PACKAGE_INFO_VERSION:
251 			{
252 				::Version* version;
253 				status_t error = Version::Create(value.version.major,
254 					value.version.minor, value.version.micro,
255 					value.version.preRelease, value.version.revision, version);
256 				if (error != B_OK)
257 					RETURN_ERROR(error);
258 
259 				fPackage->SetVersion(version);
260 				break;
261 			}
262 
263 			case B_PACKAGE_INFO_FLAGS:
264 				fPackage->SetFlags(value.unsignedInt);
265 				break;
266 
267 			case B_PACKAGE_INFO_ARCHITECTURE:
268 				if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
269 					RETURN_ERROR(B_BAD_VALUE);
270 
271 				fPackage->SetArchitecture(
272 					(BPackageArchitecture)value.unsignedInt);
273 				break;
274 
275 			case B_PACKAGE_INFO_PROVIDES:
276 			{
277 				// create a version object, if a version is specified
278 				::Version* version = NULL;
279 				if (value.resolvable.haveVersion) {
280 					const BPackageVersionData& versionInfo
281 						= value.resolvable.version;
282 					status_t error = Version::Create(versionInfo.major,
283 						versionInfo.minor, versionInfo.micro,
284 						versionInfo.preRelease, versionInfo.revision, version);
285 					if (error != B_OK)
286 						RETURN_ERROR(error);
287 				}
288 				ObjectDeleter< ::Version> versionDeleter(version);
289 
290 				// create a version object, if a compatible version is specified
291 				::Version* compatibleVersion = NULL;
292 				if (value.resolvable.haveCompatibleVersion) {
293 					const BPackageVersionData& versionInfo
294 						= value.resolvable.compatibleVersion;
295 					status_t error = Version::Create(versionInfo.major,
296 						versionInfo.minor, versionInfo.micro,
297 						versionInfo.preRelease, versionInfo.revision,
298 						compatibleVersion);
299 					if (error != B_OK)
300 						RETURN_ERROR(error);
301 				}
302 				ObjectDeleter< ::Version> compatibleVersionDeleter(
303 					compatibleVersion);
304 
305 				// create the resolvable
306 				Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
307 				if (resolvable == NULL)
308 					RETURN_ERROR(B_NO_MEMORY);
309 				ObjectDeleter<Resolvable> resolvableDeleter(resolvable);
310 
311 				status_t error = resolvable->Init(value.resolvable.name,
312 					versionDeleter.Detach(), compatibleVersionDeleter.Detach());
313 				if (error != B_OK)
314 					RETURN_ERROR(error);
315 
316 				fPackage->AddResolvable(resolvableDeleter.Detach());
317 
318 				break;
319 			}
320 
321 			case B_PACKAGE_INFO_REQUIRES:
322 			{
323 				// create the dependency
324 				Dependency* dependency = new(std::nothrow) Dependency(fPackage);
325 				if (dependency == NULL)
326 					RETURN_ERROR(B_NO_MEMORY);
327 				ObjectDeleter<Dependency> dependencyDeleter(dependency);
328 
329 				status_t error = dependency->Init(
330 					value.resolvableExpression.name);
331 				if (error != B_OK)
332 					RETURN_ERROR(error);
333 
334 				// create a version object, if a version is specified
335 				::Version* version = NULL;
336 				if (value.resolvableExpression.haveOpAndVersion) {
337 					const BPackageVersionData& versionInfo
338 						= value.resolvableExpression.version;
339 					status_t error = Version::Create(versionInfo.major,
340 						versionInfo.minor, versionInfo.micro,
341 						versionInfo.preRelease, versionInfo.revision, version);
342 					if (error != B_OK)
343 						RETURN_ERROR(error);
344 
345 					dependency->SetVersionRequirement(
346 						value.resolvableExpression.op, version);
347 				}
348 
349 				fPackage->AddDependency(dependencyDeleter.Detach());
350 
351 				break;
352 			}
353 
354 			default:
355 				break;
356 		}
357 
358 		return B_OK;
359 	}
360 
HandleErrorOccurredPackage::LoaderContentHandler361 	virtual void HandleErrorOccurred()
362 	{
363 		fErrorOccurred = true;
364 	}
365 
366 private:
367 	Package*					fPackage;
368 	const PackageSettings&		fSettings;
369 	const PackageSettingsItem*	fSettingsItem;
370 	PackageSettingsItem::Entry*	fLastSettingsEntry;
371 	const BPackageEntry*		fLastSettingsEntryEntry;
372 	bool						fErrorOccurred;
373 };
374 
375 
376 // #pragma mark - HeapReader
377 
378 
379 struct Package::HeapReader {
~HeapReaderPackage::HeapReader380 	virtual ~HeapReader()
381 	{
382 	}
383 
384 	virtual void UpdateFD(int fd) = 0;
385 
386 	virtual status_t CreateDataReader(const PackageData& data,
387 		BAbstractBufferedDataReader*& _reader) = 0;
388 };
389 
390 
391 // #pragma mark - HeapReaderV2
392 
393 
394 struct Package::HeapReaderV2 : public HeapReader, public CachedDataReader,
395 	private BErrorOutput, private BFdIO {
396 public:
HeapReaderV2Package::HeapReaderV2397 	HeapReaderV2()
398 		:
399 		fHeapReader(NULL)
400 	{
401 	}
402 
~HeapReaderV2Package::HeapReaderV2403 	~HeapReaderV2()
404 	{
405 		delete fHeapReader;
406 	}
407 
InitPackage::HeapReaderV2408 	status_t Init(const PackageFileHeapReader* heapReader, int fd)
409 	{
410 		fHeapReader = heapReader->Clone();
411 		if (fHeapReader == NULL)
412 			return B_NO_MEMORY;
413 
414 		BFdIO::SetTo(fd, false);
415 
416 		fHeapReader->SetErrorOutput(this);
417 		fHeapReader->SetFile(this);
418 
419 		status_t error = CachedDataReader::Init(fHeapReader,
420 			fHeapReader->UncompressedHeapSize());
421 		if (error != B_OK)
422 			return error;
423 
424 		return B_OK;
425 	}
426 
UpdateFDPackage::HeapReaderV2427 	virtual void UpdateFD(int fd)
428 	{
429 		BFdIO::SetTo(fd, false);
430 	}
431 
CreateDataReaderPackage::HeapReaderV2432 	virtual status_t CreateDataReader(const PackageData& data,
433 		BAbstractBufferedDataReader*& _reader)
434 	{
435 		return BPackageKit::BHPKG::BPackageDataReaderFactory()
436 			.CreatePackageDataReader(this, data.DataV2(), _reader);
437 	}
438 
439 private:
440 	// BErrorOutput
441 
PrintErrorVarArgsPackage::HeapReaderV2442 	virtual void PrintErrorVarArgs(const char* format, va_list args)
443 	{
444 		ERRORV(format, args);
445 	}
446 
447 private:
448 	PackageFileHeapReader*	fHeapReader;
449 };
450 
451 
452 // #pragma mark - Package
453 
454 
455 struct Package::CachingPackageReader : public PackageReaderImpl {
CachingPackageReaderPackage::CachingPackageReader456 	CachingPackageReader(BErrorOutput* errorOutput)
457 		:
458 		PackageReaderImpl(errorOutput),
459 		fCachedHeapReader(NULL),
460 		fFD(-1)
461 	{
462 	}
463 
~CachingPackageReaderPackage::CachingPackageReader464 	~CachingPackageReader()
465 	{
466 	}
467 
InitPackage::CachingPackageReader468 	status_t Init(int fd, bool keepFD, uint32 flags)
469 	{
470 		fFD = fd;
471 		return PackageReaderImpl::Init(fd, keepFD, flags);
472 	}
473 
CreateCachedHeapReaderPackage::CachingPackageReader474 	virtual status_t CreateCachedHeapReader(
475 		PackageFileHeapReader* rawHeapReader,
476 		BAbstractBufferedDataReader*& _cachedReader)
477 	{
478 		fCachedHeapReader = new(std::nothrow) HeapReaderV2;
479 		if (fCachedHeapReader == NULL)
480 			RETURN_ERROR(B_NO_MEMORY);
481 
482 		status_t error = fCachedHeapReader->Init(rawHeapReader, fFD);
483 		if (error != B_OK)
484 			RETURN_ERROR(error);
485 
486 		_cachedReader = fCachedHeapReader;
487 		return B_OK;
488 	}
489 
DetachCachedHeapReaderPackage::CachingPackageReader490 	HeapReaderV2* DetachCachedHeapReader()
491 	{
492 		PackageFileHeapReader* rawHeapReader;
493 		DetachHeapReader(rawHeapReader);
494 
495 		// We don't need the raw heap reader anymore, since the cached reader
496 		// is not a wrapper around it, but completely independent from it.
497 		delete rawHeapReader;
498 
499 		HeapReaderV2* cachedHeapReader = fCachedHeapReader;
500 		fCachedHeapReader = NULL;
501 		return cachedHeapReader;
502 	}
503 
504 private:
505 	HeapReaderV2*	fCachedHeapReader;
506 	int				fFD;
507 };
508 
509 
510 // #pragma mark - Package
511 
512 
Package(::Volume * volume,PackagesDirectory * directory,dev_t deviceID,ino_t nodeID)513 Package::Package(::Volume* volume, PackagesDirectory* directory, dev_t deviceID,
514 	ino_t nodeID)
515 	:
516 	fVolume(volume),
517 	fPackagesDirectory(directory),
518 	fFileName(),
519 	fName(),
520 	fInstallPath(),
521 	fVersionedName(),
522 	fVersion(NULL),
523 	fFlags(0),
524 	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
525 	fLinkDirectory(NULL),
526 	fFD(-1),
527 	fOpenCount(0),
528 	fHeapReader(NULL),
529 	fNodeID(nodeID),
530 	fDeviceID(deviceID)
531 {
532 	mutex_init(&fLock, "packagefs package");
533 
534 	fPackagesDirectory->AcquireReference();
535 }
536 
537 
~Package()538 Package::~Package()
539 {
540 	delete fHeapReader;
541 
542 	while (PackageNode* node = fNodes.RemoveHead())
543 		node->ReleaseReference();
544 
545 	while (Resolvable* resolvable = fResolvables.RemoveHead())
546 		delete resolvable;
547 
548 	while (Dependency* dependency = fDependencies.RemoveHead())
549 		delete dependency;
550 
551 	delete fVersion;
552 
553 	fPackagesDirectory->ReleaseReference();
554 
555 	mutex_destroy(&fLock);
556 }
557 
558 
559 status_t
Init(const char * fileName)560 Package::Init(const char* fileName)
561 {
562 	if (!fFileName.SetTo(fileName))
563 		RETURN_ERROR(B_NO_MEMORY);
564 
565 	return B_OK;
566 }
567 
568 
569 status_t
Load(const PackageSettings & settings)570 Package::Load(const PackageSettings& settings)
571 {
572 	status_t error = _Load(settings);
573 	if (error != B_OK)
574 		return error;
575 
576 	if (!_InitVersionedName())
577 		RETURN_ERROR(B_NO_MEMORY);
578 
579 	return B_OK;
580 }
581 
582 
583 void
SetName(const String & name)584 Package::SetName(const String& name)
585 {
586 	fName = name;
587 }
588 
589 
590 void
SetInstallPath(const String & installPath)591 Package::SetInstallPath(const String& installPath)
592 {
593 	fInstallPath = installPath;
594 }
595 
596 
597 void
SetVersion(::Version * version)598 Package::SetVersion(::Version* version)
599 {
600 	if (fVersion != NULL)
601 		delete fVersion;
602 
603 	fVersion = version;
604 }
605 
606 
607 const char*
ArchitectureName() const608 Package::ArchitectureName() const
609 {
610 	if (fArchitecture < 0
611 		|| fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
612 		return NULL;
613 	}
614 
615 	return kArchitectureNames[fArchitecture];
616 }
617 
618 
619 void
AddNode(PackageNode * node)620 Package::AddNode(PackageNode* node)
621 {
622 	fNodes.Add(node);
623 	node->AcquireReference();
624 }
625 
626 
627 void
AddResolvable(Resolvable * resolvable)628 Package::AddResolvable(Resolvable* resolvable)
629 {
630 	fResolvables.Add(resolvable);
631 }
632 
633 
634 void
AddDependency(Dependency * dependency)635 Package::AddDependency(Dependency* dependency)
636 {
637 	fDependencies.Add(dependency);
638 }
639 
640 
641 int
Open()642 Package::Open()
643 {
644 	MutexLocker locker(fLock);
645 	if (fOpenCount > 0) {
646 		fOpenCount++;
647 		return fFD;
648 	}
649 
650 	// open the file
651 	fFD = openat(fPackagesDirectory->DirectoryFD(), fFileName,
652 		O_RDONLY | O_NOCACHE);
653 	if (fFD < 0) {
654 		ERROR("Failed to open package file \"%s\": %s\n", fFileName.Data(),
655 			strerror(errno));
656 		return errno;
657 	}
658 
659 	// stat it to verify that it's still the same file
660 	struct stat st;
661 	if (fstat(fFD, &st) < 0) {
662 		ERROR("Failed to stat package file \"%s\": %s\n", fFileName.Data(),
663 			strerror(errno));
664 		close(fFD);
665 		fFD = -1;
666 		return errno;
667 	}
668 
669 	if (st.st_dev != fDeviceID || st.st_ino != fNodeID) {
670 		close(fFD);
671 		fFD = -1;
672 		RETURN_ERROR(B_ENTRY_NOT_FOUND);
673 	}
674 
675 	fOpenCount = 1;
676 
677 	if (fHeapReader != NULL)
678 		fHeapReader->UpdateFD(fFD);
679 
680 	return fFD;
681 }
682 
683 
684 void
Close()685 Package::Close()
686 {
687 	MutexLocker locker(fLock);
688 	if (fOpenCount == 0) {
689 		ERROR("Package open count already 0!\n");
690 		return;
691 	}
692 
693 	if (--fOpenCount == 0) {
694 		close(fFD);
695 		fFD = -1;
696 
697 		if (fHeapReader != NULL)
698 			fHeapReader->UpdateFD(fFD);
699 	}
700 }
701 
702 
703 status_t
CreateDataReader(const PackageData & data,BAbstractBufferedDataReader * & _reader)704 Package::CreateDataReader(const PackageData& data,
705 	BAbstractBufferedDataReader*& _reader)
706 {
707 	if (fHeapReader == NULL)
708 		return B_BAD_VALUE;
709 
710 	return fHeapReader->CreateDataReader(data, _reader);
711 }
712 
713 
714 status_t
_Load(const PackageSettings & settings)715 Package::_Load(const PackageSettings& settings)
716 {
717 	// open package file
718 	int fd = Open();
719 	if (fd < 0)
720 		RETURN_ERROR(fd);
721 	PackageCloser packageCloser(this);
722 
723 	// initialize package reader
724 	LoaderErrorOutput errorOutput(this);
725 
726 	// try current package file format version
727 	{
728 		CachingPackageReader packageReader(&errorOutput);
729 		status_t error = packageReader.Init(fd, false,
730 			BHPKG::B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE);
731 		if (error == B_OK) {
732 			// parse content
733 			LoaderContentHandler handler(this, settings);
734 			error = handler.Init();
735 			if (error != B_OK)
736 				RETURN_ERROR(error);
737 
738 			error = packageReader.ParseContent(&handler);
739 			if (error != B_OK)
740 				RETURN_ERROR(error);
741 
742 			// get the heap reader
743 			fHeapReader = packageReader.DetachCachedHeapReader();
744 			return B_OK;
745 		}
746 
747 		if (error != B_MISMATCHED_VALUES)
748 			RETURN_ERROR(error);
749 	}
750 
751 	// we don't support this package file format
752 	RETURN_ERROR(B_BAD_DATA);
753 }
754 
755 
756 bool
_InitVersionedName()757 Package::_InitVersionedName()
758 {
759 	// compute the allocation size needed for the versioned name
760 	size_t nameLength = strlen(fName);
761 	size_t size = nameLength + 1;
762 
763 	if (fVersion != NULL) {
764 		size += 1 + fVersion->ToString(NULL, 0);
765 			// + 1 for the '-'
766 	}
767 
768 	// allocate the name and compose it
769 	char* name = (char*)malloc(size);
770 	if (name == NULL)
771 		return false;
772 	MemoryDeleter nameDeleter(name);
773 
774 	memcpy(name, fName, nameLength + 1);
775 	if (fVersion != NULL) {
776 		name[nameLength] = '-';
777 		fVersion->ToString(name + nameLength + 1, size - nameLength - 1);
778 	}
779 
780 	return fVersionedName.SetTo(name);
781 }
782