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