vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / file_systems / packagefs / package_links / PackageLinkDirectory.cpp
blobd3bc55ef980490e3f58ed0a53b57f8ed58111fb0
1 /*
2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "PackageLinkDirectory.h"
9 #include <new>
11 #include <NodeMonitor.h>
13 #include <AutoDeleter.h>
15 #include "AutoPackageAttributeDirectoryCookie.h"
16 #include "DebugSupport.h"
17 #include "PackageLinksListener.h"
18 #include "StringConstants.h"
19 #include "Utils.h"
20 #include "Version.h"
21 #include "Volume.h"
24 PackageLinkDirectory::PackageLinkDirectory()
26 Directory(0),
27 // the ID needs to be assigned later, when added to a volume
28 fSelfLink(NULL),
29 fSettingsLink(NULL)
31 get_real_time(fModifiedTime);
35 PackageLinkDirectory::~PackageLinkDirectory()
37 if (fSelfLink != NULL)
38 fSelfLink->ReleaseReference();
39 if (fSettingsLink != NULL)
40 fSettingsLink->ReleaseReference();
42 while (DependencyLink* link = fDependencyLinks.RemoveHead())
43 link->ReleaseReference();
47 status_t
48 PackageLinkDirectory::Init(Directory* parent, Package* package)
50 // init the directory/node
51 status_t error = Init(parent, package->VersionedName());
52 if (error != B_OK)
53 RETURN_ERROR(error);
55 // add the package
56 AddPackage(package, NULL);
58 return B_OK;
62 status_t
63 PackageLinkDirectory::Init(Directory* parent, const String& name)
65 return Directory::Init(parent, name);
69 timespec
70 PackageLinkDirectory::ModifiedTime() const
72 return fModifiedTime;
76 status_t
77 PackageLinkDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
79 Package* package = fPackages.Head();
80 if (package == NULL)
81 return B_ENTRY_NOT_FOUND;
83 AutoPackageAttributeDirectoryCookie* cookie = new(std::nothrow)
84 AutoPackageAttributeDirectoryCookie();
85 if (cookie == NULL)
86 return B_NO_MEMORY;
88 _cookie = cookie;
89 return B_OK;
93 status_t
94 PackageLinkDirectory::OpenAttribute(const StringKey& name, int openMode,
95 AttributeCookie*& _cookie)
97 Package* package = fPackages.Head();
98 if (package == NULL)
99 return B_ENTRY_NOT_FOUND;
101 return AutoPackageAttributes::OpenCookie(package, name, openMode, _cookie);
105 void
106 PackageLinkDirectory::AddPackage(Package* package,
107 PackageLinksListener* listener)
109 NodeWriteLocker writeLocker(this);
111 // Find the insertion point in the list. We sort by mount type -- the more
112 // specific the higher the priority.
113 MountType mountType = package->Volume()->MountType();
114 Package* otherPackage = NULL;
115 for (PackageList::Iterator it = fPackages.GetIterator();
116 (otherPackage = it.Next()) != NULL;) {
117 if (otherPackage->Volume()->MountType() <= mountType)
118 break;
121 fPackages.InsertBefore(otherPackage, package);
122 package->SetLinkDirectory(this);
124 if (package == fPackages.Head())
125 _Update(listener);
129 void
130 PackageLinkDirectory::RemovePackage(Package* package,
131 PackageLinksListener* listener)
133 ASSERT(package->LinkDirectory() == this);
135 NodeWriteLocker writeLocker(this);
137 bool firstPackage = package == fPackages.Head();
139 package->SetLinkDirectory(NULL);
140 fPackages.Remove(package);
142 if (firstPackage)
143 _Update(listener);
147 void
148 PackageLinkDirectory::UpdatePackageDependencies(Package* package,
149 PackageLinksListener* listener)
151 ASSERT(package->LinkDirectory() == this);
153 NodeWriteLocker writeLocker(this);
155 // We only need to update, if that head package is affected.
156 if (package != fPackages.Head())
157 return;
159 _UpdateDependencies(listener);
163 status_t
164 PackageLinkDirectory::_Update(PackageLinksListener* listener)
166 // Always remove all dependency links -- if there's still a package, they
167 // will be re-created below.
168 while (DependencyLink* link = fDependencyLinks.RemoveHead())
169 _RemoveLink(link, listener);
171 // check, if empty
172 Package* package = fPackages.Head();
173 if (package == NULL) {
174 // remove self and settings link
175 _RemoveLink(fSelfLink, listener);
176 fSelfLink = NULL;
178 _RemoveLink(fSettingsLink, listener);
179 fSettingsLink = NULL;
181 return B_OK;
184 // create/update self and settings link
185 status_t error = _CreateOrUpdateLink(fSelfLink, package,
186 Link::TYPE_INSTALLATION_LOCATION, StringConstants::Get().kSelfLinkName,
187 listener);
188 if (error != B_OK)
189 RETURN_ERROR(error);
191 error = _CreateOrUpdateLink(fSettingsLink, package, Link::TYPE_SETTINGS,
192 StringConstants::Get().kSettingsLinkName, listener);
193 if (error != B_OK)
194 RETURN_ERROR(error);
196 // update the dependency links
197 return _UpdateDependencies(listener);
201 status_t
202 PackageLinkDirectory::_UpdateDependencies(PackageLinksListener* listener)
204 Package* package = fPackages.Head();
205 if (package == NULL)
206 return B_OK;
208 // Iterate through the package's dependencies
209 for (DependencyList::ConstIterator it
210 = package->Dependencies().GetIterator();
211 Dependency* dependency = it.Next();) {
212 Resolvable* resolvable = dependency->Resolvable();
213 Package* resolvablePackage = resolvable != NULL
214 ? resolvable->Package() : NULL;
216 Node* node = FindChild(dependency->FileName());
217 if (node != NULL) {
218 // link already exists -- update
219 DependencyLink* link = static_cast<DependencyLink*>(node);
221 NodeWriteLocker linkLocker(link);
222 link->Update(resolvablePackage, listener);
223 } else {
224 // no link for the dependency yet -- create one
225 DependencyLink* link = new(std::nothrow) DependencyLink(
226 resolvablePackage);
227 if (link == NULL)
228 return B_NO_MEMORY;
230 status_t error = link->Init(this, dependency->FileName());
231 if (error != B_OK) {
232 delete link;
233 RETURN_ERROR(error);
236 AddChild(link);
237 fDependencyLinks.Add(link);
239 if (listener != NULL) {
240 NodeWriteLocker linkLocker(link);
241 listener->PackageLinkNodeAdded(link);
246 return B_OK;
250 void
251 PackageLinkDirectory::_RemoveLink(Link* link, PackageLinksListener* listener)
253 if (link != NULL) {
254 NodeWriteLocker linkLocker(link);
255 if (listener != NULL)
256 listener->PackageLinkNodeRemoved(link);
258 RemoveChild(link);
259 linkLocker.Unlock();
260 link->ReleaseReference();
265 status_t
266 PackageLinkDirectory::_CreateOrUpdateLink(Link*& link, Package* package,
267 Link::Type type, const String& name, PackageLinksListener* listener)
269 if (link == NULL) {
270 link = new(std::nothrow) Link(package, type);
271 if (link == NULL)
272 return B_NO_MEMORY;
274 status_t error = link->Init(this, name);
275 if (error != B_OK)
276 RETURN_ERROR(error);
278 AddChild(link);
280 if (listener != NULL) {
281 NodeWriteLocker lLinkLocker(link);
282 listener->PackageLinkNodeAdded(link);
284 } else {
285 NodeWriteLocker lLinkLocker(link);
286 link->Update(package, listener);
290 return B_OK;