1/*
2 * Copyright 2009-2011, 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 <util/AutoLock.h>
16
17#include "DebugSupport.h"
18#include "PackageDomain.h"
19#include "Version.h"
20
21
22const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
23	"any",
24	"x86",
25	"x86_gcc2",
26};
27
28
29Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID)
30	:
31	fDomain(domain),
32	fFileName(NULL),
33	fName(NULL),
34	fInstallPath(NULL),
35	fVersion(NULL),
36	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
37	fLinkDirectory(NULL),
38	fFD(-1),
39	fOpenCount(0),
40	fNodeID(nodeID),
41	fDeviceID(deviceID)
42{
43	mutex_init(&fLock, "packagefs package");
44}
45
46
47Package::~Package()
48{
49	while (PackageNode* node = fNodes.RemoveHead())
50		node->ReleaseReference();
51
52	while (Resolvable* resolvable = fResolvables.RemoveHead())
53		delete resolvable;
54
55	while (Dependency* dependency = fDependencies.RemoveHead())
56		delete dependency;
57
58	free(fFileName);
59	free(fName);
60	free(fInstallPath);
61	delete fVersion;
62
63	mutex_destroy(&fLock);
64}
65
66
67status_t
68Package::Init(const char* fileName)
69{
70	fFileName = strdup(fileName);
71	if (fFileName == NULL)
72		RETURN_ERROR(B_NO_MEMORY);
73
74	return B_OK;
75}
76
77
78status_t
79Package::SetName(const char* name)
80{
81	if (fName != NULL)
82		free(fName);
83
84	fName = strdup(name);
85	if (fName == NULL)
86		RETURN_ERROR(B_NO_MEMORY);
87
88	return B_OK;
89}
90
91
92status_t
93Package::SetInstallPath(const char* installPath)
94{
95	if (fInstallPath != NULL)
96		free(fInstallPath);
97
98	fInstallPath = strdup(installPath);
99	if (fInstallPath == NULL)
100		RETURN_ERROR(B_NO_MEMORY);
101
102	return B_OK;
103}
104
105
106void
107Package::SetVersion(::Version* version)
108{
109	if (fVersion != NULL)
110		delete fVersion;
111
112	fVersion = version;
113}
114
115
116const char*
117Package::ArchitectureName() const
118{
119	if (fArchitecture < 0
120		|| fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
121		return NULL;
122	}
123
124	return kArchitectureNames[fArchitecture];
125}
126
127
128void
129Package::AddNode(PackageNode* node)
130{
131	fNodes.Add(node);
132	node->AcquireReference();
133}
134
135
136void
137Package::AddResolvable(Resolvable* resolvable)
138{
139	fResolvables.Add(resolvable);
140}
141
142
143void
144Package::AddDependency(Dependency* dependency)
145{
146	fDependencies.Add(dependency);
147}
148
149
150int
151Package::Open()
152{
153	MutexLocker locker(fLock);
154	if (fOpenCount > 0) {
155		fOpenCount++;
156		return fFD;
157	}
158
159	// open the file
160	fFD = openat(fDomain->DirectoryFD(), fFileName, O_RDONLY);
161	if (fFD < 0) {
162		ERROR("Failed to open package file \"%s\"\n", fFileName);
163		return errno;
164	}
165
166	// stat it to verify that it's still the same file
167	struct stat st;
168	if (fstat(fFD, &st) < 0) {
169		ERROR("Failed to stat package file \"%s\"\n", fFileName);
170		close(fFD);
171		fFD = -1;
172		return errno;
173	}
174
175	if (st.st_dev != fDeviceID || st.st_ino != fNodeID) {
176		close(fFD);
177		fFD = -1;
178		RETURN_ERROR(B_ENTRY_NOT_FOUND);
179	}
180
181	fOpenCount = 1;
182	return fFD;
183}
184
185
186void
187Package::Close()
188{
189	MutexLocker locker(fLock);
190	if (fOpenCount == 0) {
191		ERROR("Package open count already 0!\n");
192		return;
193	}
194
195	if (--fOpenCount == 0) {
196		close(fFD);
197		fFD = -1;
198	}
199}
200