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