1/*
2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "PackageLinkSymlink.h"
8
9#include <algorithm>
10
11#include <NodeMonitor.h>
12
13#include "AutoPackageAttributeDirectoryCookie.h"
14#include "DebugSupport.h"
15#include "NodeListener.h"
16#include "PackageLinksListener.h"
17#include "Utils.h"
18#include "Volume.h"
19
20
21static const char* const kUnknownLinkTarget = "?";
22
23static const char* const kLinkPaths[PackageLinkSymlink::TYPE_ENUM_COUNT]
24		[PACKAGE_FS_MOUNT_TYPE_ENUM_COUNT] = {
25	{
26		"../..",
27		"../../../home/config",
28		kUnknownLinkTarget
29	},
30	{
31		"../../../system/settings",
32		"../../../home/config/settings",
33		kUnknownLinkTarget
34	}
35};
36
37
38static const char*
39link_path_for_mount_type(MountType mountType, PackageLinkSymlink::Type linkType)
40{
41	if (mountType < 0 || mountType >= PACKAGE_FS_MOUNT_TYPE_ENUM_COUNT
42		|| linkType < 0 || linkType >= PackageLinkSymlink::TYPE_ENUM_COUNT) {
43		return kUnknownLinkTarget;
44	}
45
46	return kLinkPaths[linkType][mountType];
47}
48
49
50// #pragma mark - OldAttributes
51
52
53struct PackageLinkSymlink::OldAttributes : OldNodeAttributes {
54	OldAttributes(const timespec& modifiedTime, off_t fileSize)
55		:
56		fModifiedTime(modifiedTime),
57		fFileSize(fileSize)
58	{
59	}
60
61	virtual timespec ModifiedTime() const
62	{
63		return fModifiedTime;
64	}
65
66	virtual off_t FileSize() const
67	{
68		return fFileSize;
69	}
70
71private:
72	timespec	fModifiedTime;
73	off_t		fFileSize;
74};
75
76
77// #pragma mark - PackageLinkSymlink
78
79
80PackageLinkSymlink::PackageLinkSymlink(Package* package, Type type)
81	:
82	Node(0),
83	fPackage(),
84	fLinkPath(kUnknownLinkTarget),
85	fType(type)
86{
87	Update(package, NULL);
88}
89
90
91PackageLinkSymlink::~PackageLinkSymlink()
92{
93}
94
95
96void
97PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener)
98{
99	OldAttributes oldAttributes(fModifiedTime, FileSize());
100
101	fPackage = package;
102
103	if (package != NULL) {
104		fLinkPath = package->InstallPath();
105		if (fLinkPath[0] != '\0') {
106			if (fType == TYPE_SETTINGS)
107				fLinkPath = ".self/settings";
108		} else {
109			fLinkPath = link_path_for_mount_type(
110				package->Volume()->MountType(), fType);
111		}
112	} else
113		fLinkPath = kUnknownLinkTarget;
114
115	get_real_time(fModifiedTime);
116
117	if (listener != NULL) {
118		listener->PackageLinkNodeChanged(this,
119			B_STAT_SIZE | B_STAT_MODIFICATION_TIME, oldAttributes);
120	}
121}
122
123
124mode_t
125PackageLinkSymlink::Mode() const
126{
127	return S_IFLNK | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
128}
129
130
131timespec
132PackageLinkSymlink::ModifiedTime() const
133{
134	return fModifiedTime;
135}
136
137
138off_t
139PackageLinkSymlink::FileSize() const
140{
141	return strlen(fLinkPath);
142}
143
144
145status_t
146PackageLinkSymlink::Read(off_t offset, void* buffer, size_t* bufferSize)
147{
148	return B_BAD_VALUE;
149}
150
151
152status_t
153PackageLinkSymlink::Read(io_request* request)
154{
155	return B_BAD_VALUE;
156}
157
158
159status_t
160PackageLinkSymlink::ReadSymlink(void* buffer, size_t* bufferSize)
161{
162	size_t linkLength = strnlen(fLinkPath, B_PATH_NAME_LENGTH);
163
164	size_t bytesToCopy = std::min(linkLength, *bufferSize);
165
166	*bufferSize = linkLength;
167
168	memcpy(buffer, fLinkPath, bytesToCopy);
169	return B_OK;
170}
171
172
173status_t
174PackageLinkSymlink::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
175{
176	AutoPackageAttributeDirectoryCookie* cookie = new(std::nothrow)
177		AutoPackageAttributeDirectoryCookie();
178	if (cookie == NULL)
179		return B_NO_MEMORY;
180
181	_cookie = cookie;
182	return B_OK;
183}
184
185
186status_t
187PackageLinkSymlink::OpenAttribute(const StringKey& name, int openMode,
188	AttributeCookie*& _cookie)
189{
190	if (!fPackage.IsSet())
191		return B_ENTRY_NOT_FOUND;
192
193	return AutoPackageAttributes::OpenCookie(fPackage, name, openMode, _cookie);
194}
195