xref: /haiku/src/add-ons/kernel/file_systems/packagefs/package/PackageFile.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
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 "PackageFile.h"
8 
9 #include <algorithm>
10 #include <new>
11 
12 #include <fs_cache.h>
13 
14 #include <DataIO.h>
15 #include <package/hpkg/DataReader.h>
16 #include <package/hpkg/PackageDataReader.h>
17 
18 #include <AutoDeleter.h>
19 #include <util/AutoLock.h>
20 
21 #include "DebugSupport.h"
22 #include "ClassCache.h"
23 #include "Package.h"
24 
25 
26 using namespace BPackageKit::BHPKG;
27 
28 
29 // #pragma mark - class cache
30 
31 
32 CLASS_CACHE(PackageFile);
33 
34 
35 // #pragma mark - DataAccessor
36 
37 
38 struct PackageFile::IORequestOutput : BDataIO {
39 public:
40 	IORequestOutput(io_request* request)
41 		:
42 		fRequest(request)
43 	{
44 	}
45 
46 	virtual ssize_t Write(const void* buffer, size_t size)
47 	{
48 		status_t error = write_to_io_request(fRequest, buffer, size);
49 		RETURN_ERROR(error == B_OK ? (ssize_t)size : (ssize_t)error);
50 	}
51 
52 private:
53 	io_request*	fRequest;
54 };
55 
56 
57 struct PackageFile::DataAccessor {
58 	DataAccessor(Package* package, PackageData* data)
59 		:
60 		fPackage(package),
61 		fData(data),
62 		fReader(NULL),
63 		fFileCache(NULL)
64 	{
65 	}
66 
67 	~DataAccessor()
68 	{
69 		file_cache_delete(fFileCache);
70 		delete fReader;
71 	}
72 
73 	status_t Init(dev_t deviceID, ino_t nodeID, int fd)
74 	{
75 		// create a reader for the data
76 		status_t error = fPackage->CreateDataReader(*fData, fReader);
77 		if (error != B_OK)
78 			return error;
79 
80 		// create a file cache
81 		fFileCache = file_cache_create(deviceID, nodeID,
82 			fData->UncompressedSize());
83 		if (fFileCache == NULL)
84 			RETURN_ERROR(B_NO_MEMORY);
85 
86 		return B_OK;
87 	}
88 
89 	status_t ReadData(off_t offset, void* buffer, size_t* bufferSize)
90 	{
91 		return file_cache_read(fFileCache, NULL, offset, buffer, bufferSize);
92 	}
93 
94 	status_t ReadData(io_request* request)
95 	{
96 		off_t offset = io_request_offset(request);
97 		size_t size = io_request_length(request);
98 
99 		if (offset < 0 || (uint64)offset > fData->UncompressedSize())
100 			RETURN_ERROR(B_BAD_VALUE);
101 
102 		size_t toRead = std::min((uint64)size,
103 			fData->UncompressedSize() - offset);
104 
105 		if (toRead > 0) {
106 			IORequestOutput output(request);
107 			status_t error = fReader->ReadDataToOutput(offset, toRead, &output);
108 			if (error != B_OK)
109 				RETURN_ERROR(error);
110 		}
111 
112 		return B_OK;
113 	}
114 
115 private:
116 	Package*						fPackage;
117 	PackageData*					fData;
118 	BAbstractBufferedDataReader*	fReader;
119 	void*							fFileCache;
120 };
121 
122 
123 // #pragma mark - PackageFile
124 
125 
126 PackageFile::PackageFile(Package* package, mode_t mode, const PackageData& data)
127 	:
128 	PackageLeafNode(package, mode),
129 	fData(data),
130 	fDataAccessor(NULL)
131 {
132 }
133 
134 
135 PackageFile::~PackageFile()
136 {
137 }
138 
139 
140 status_t
141 PackageFile::VFSInit(dev_t deviceID, ino_t nodeID)
142 {
143 	status_t error = PackageNode::VFSInit(deviceID, nodeID);
144 	if (error != B_OK)
145 		return error;
146 	MethodDeleter<PackageNode, void, &PackageNode::NonVirtualVFSUninit>
147 		baseClassUninit(this);
148 
149 	// open the package -- that's already done by PackageNode::VFSInit(), so it
150 	// shouldn't fail here. We only need to do it again, since we need the FD.
151 	BReference<Package> package(GetPackage());
152 	int fd = package->Open();
153 	if (fd < 0)
154 		RETURN_ERROR(fd);
155 	PackageCloser packageCloser(package);
156 
157 	// create the data accessor
158 	fDataAccessor = new(std::nothrow) DataAccessor(package, &fData);
159 	if (fDataAccessor == NULL)
160 		RETURN_ERROR(B_NO_MEMORY);
161 
162 	error = fDataAccessor->Init(deviceID, nodeID, fd);
163 	if (error != B_OK) {
164 		delete fDataAccessor;
165 		fDataAccessor = NULL;
166 		return error;
167 	}
168 
169 	baseClassUninit.Detach();
170 	return B_OK;
171 }
172 
173 
174 void
175 PackageFile::VFSUninit()
176 {
177 	if (fDataAccessor != NULL) {
178 		delete fDataAccessor;
179 		fDataAccessor = NULL;
180 	}
181 
182 	PackageNode::VFSUninit();
183 }
184 
185 
186 off_t
187 PackageFile::FileSize() const
188 {
189 	return fData.UncompressedSize();
190 }
191 
192 
193 status_t
194 PackageFile::Read(off_t offset, void* buffer, size_t* bufferSize)
195 {
196 	if (fDataAccessor == NULL)
197 		return B_BAD_VALUE;
198 	return fDataAccessor->ReadData(offset, buffer, bufferSize);
199 }
200 
201 
202 status_t
203 PackageFile::Read(io_request* request)
204 {
205 	if (fDataAccessor == NULL)
206 		return B_BAD_VALUE;
207 	return fDataAccessor->ReadData(request);
208 }
209