vfs: check userland buffers before reading them.
[haiku.git] / src / kits / media / experimental / AdapterIO.cpp
blobbe620c03c45c38eb70affa65ebd6b8fa4e698171
1 /*
2 * Copyright 2016 Dario Casalinuovo. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 */
7 #include "AdapterIO.h"
9 #include <MediaIO.h>
11 #include <string.h>
13 #include "debug.h"
16 #define TIMEOUT_QUANTA 100000
19 class RelativePositionIO : public BPositionIO {
20 public:
21 RelativePositionIO(BAdapterIO* owner, BPositionIO* buffer,
22 bigtime_t timeout)
24 BPositionIO(),
25 fOwner(owner),
26 fBackPosition(0),
27 fStartOffset(0),
28 fBuffer(buffer),
29 fTimeout(timeout)
33 virtual ~RelativePositionIO()
35 delete fBuffer;
38 status_t ResetStartOffset(off_t offset)
40 status_t ret = fBuffer->SetSize(0);
41 if (ret != B_OK)
42 return ret;
44 fBackPosition = 0;
45 fStartOffset = offset;
46 return B_OK;
49 status_t EvaluatePosition(off_t position, off_t totalSize)
51 if (position < 0)
52 return B_ERROR;
54 if (position < fStartOffset)
55 return B_RESOURCE_UNAVAILABLE;
57 if (totalSize > 0 && position > totalSize) {
58 // This is an endless stream, we don't know
59 // how much data will come and when, we could
60 // block on that.
61 if (IsMutable())
62 return B_WOULD_BLOCK;
63 else
64 return B_ERROR;
67 return B_OK;
70 status_t WaitForData(off_t position, off_t size)
72 off_t bufferSize = 0;
73 status_t ret = GetSize(&bufferSize);
74 if (ret != B_OK)
75 return B_ERROR;
77 bigtime_t totalTimeOut = 0;
79 while (bufferSize < position + size) {
80 // We are not running, no luck to receive
81 // more data, let's return and avoid locking.
82 if (!fOwner->IsRunning())
83 return B_NOT_SUPPORTED;
85 if (fTimeout != B_INFINITE_TIMEOUT && totalTimeOut >= fTimeout)
86 return B_TIMED_OUT;
88 snooze(TIMEOUT_QUANTA);
90 totalTimeOut += TIMEOUT_QUANTA;
91 GetSize(&bufferSize);
93 return B_OK;
96 virtual ssize_t ReadAt(off_t position, void* buffer,
97 size_t size)
99 AutoReadLocker _(fLock);
101 return fBuffer->ReadAt(
102 _PositionToRelative(position), buffer, size);
106 virtual ssize_t WriteAt(off_t position,
107 const void* buffer, size_t size)
109 AutoWriteLocker _(fLock);
111 return fBuffer->WriteAt(
112 _PositionToRelative(position), buffer, size);
115 virtual off_t Seek(off_t position, uint32 seekMode)
117 AutoWriteLocker _(fLock);
119 return fBuffer->Seek(_PositionToRelative(position), seekMode);
122 virtual off_t Position() const
124 AutoReadLocker _(fLock);
126 return _RelativeToPosition(fBuffer->Position());
129 virtual status_t SetSize(off_t size)
131 AutoWriteLocker _(fLock);
133 return fBuffer->SetSize(_PositionToRelative(size));
136 virtual status_t GetSize(off_t* size) const
138 AutoReadLocker _(fLock);
140 // We use the backend position to make our buffer
141 // independant of that.
142 *size = _RelativeToPosition(fBackPosition);
144 return B_OK;
147 ssize_t BackWrite(const void* buffer, size_t size)
149 AutoWriteLocker _(fLock);
151 off_t ret = fBuffer->WriteAt(fBackPosition, buffer, size);
152 fBackPosition += ret;
153 return ret;
156 void SetBuffer(BPositionIO* buffer)
158 delete fBuffer;
159 fBuffer = buffer;
162 bool IsStreaming() const
164 int32 flags = 0;
165 fOwner->GetFlags(&flags);
166 return (flags & B_MEDIA_STREAMING) == true;
169 bool IsMutable() const
171 int32 flags = 0;
172 fOwner->GetFlags(&flags);
173 return (flags & B_MEDIA_MUTABLE_SIZE) == true;
176 bool IsSeekable() const
178 int32 flags = 0;
179 fOwner->GetFlags(&flags);
180 return (flags & B_MEDIA_SEEKABLE) == true;
183 private:
185 off_t _PositionToRelative(off_t position) const
187 return position - fStartOffset;
190 off_t _RelativeToPosition(off_t position) const
192 return position + fStartOffset;
195 BAdapterIO* fOwner;
196 off_t fBackPosition;
197 off_t fStartOffset;
199 BPositionIO* fBuffer;
201 mutable RWLocker fLock;
203 bigtime_t fTimeout;
207 BAdapterIO::BAdapterIO(int32 flags, bigtime_t timeout)
209 fFlags(flags),
210 fBuffer(NULL),
211 fTotalSize(0),
212 fOpened(false),
213 fSeekSem(-1),
214 fInputAdapter(NULL)
216 CALLED();
218 fBuffer = new RelativePositionIO(this, new BMallocIO(), timeout);
222 BAdapterIO::BAdapterIO(const BAdapterIO &)
224 // copying not allowed...
228 BAdapterIO::~BAdapterIO()
230 CALLED();
232 delete fInputAdapter;
233 delete fBuffer;
237 void
238 BAdapterIO::GetFlags(int32* flags) const
240 CALLED();
242 *flags = fFlags;
246 ssize_t
247 BAdapterIO::ReadAt(off_t position, void* buffer, size_t size)
249 CALLED();
251 status_t ret = _EvaluateWait(position, size);
252 if (ret != B_OK)
253 return ret;
255 return fBuffer->ReadAt(position, buffer, size);
259 ssize_t
260 BAdapterIO::WriteAt(off_t position, const void* buffer, size_t size)
262 CALLED();
264 return fBuffer->WriteAt(position, buffer, size);
268 off_t
269 BAdapterIO::Seek(off_t position, uint32 seekMode)
271 CALLED();
273 off_t absolutePosition = 0;
274 off_t size = 0;
276 if (seekMode == SEEK_CUR)
277 absolutePosition = Position()+position;
278 else if (seekMode == SEEK_END) {
279 if (GetSize(&size) != B_OK)
280 return B_NOT_SUPPORTED;
282 absolutePosition = size-position;
285 status_t ret = _EvaluateWait(absolutePosition, 0);
287 if (ret == B_RESOURCE_UNAVAILABLE && fBuffer->IsStreaming()
288 && fBuffer->IsSeekable()) {
290 fSeekSem = create_sem(0, "BAdapterIO seek sem");
292 if (SeekRequested(absolutePosition) != B_OK)
293 return B_NOT_SUPPORTED;
295 TRACE("BAdapterIO::Seek: Locking on backend seek\n");
296 acquire_sem(fSeekSem);
297 TRACE("BAdapterIO::Seek: Seek completed!\n");
298 fBuffer->ResetStartOffset(absolutePosition);
299 } else if (ret != B_OK)
300 return B_NOT_SUPPORTED;
302 return fBuffer->Seek(position, seekMode);
306 off_t
307 BAdapterIO::Position() const
309 CALLED();
311 return fBuffer->Position();
315 status_t
316 BAdapterIO::SetSize(off_t size)
318 CALLED();
320 if (!fBuffer->IsMutable()) {
321 fTotalSize = size;
322 return B_OK;
325 return fBuffer->SetSize(size);
329 status_t
330 BAdapterIO::GetSize(off_t* size) const
332 CALLED();
334 if (!fBuffer->IsMutable()) {
335 *size = fTotalSize;
336 return B_OK;
339 return fBuffer->GetSize(size);
343 status_t
344 BAdapterIO::Open()
346 CALLED();
348 fOpened = true;
349 return B_OK;
353 bool
354 BAdapterIO::IsRunning() const
356 return fOpened;
360 void
361 BAdapterIO::SeekCompleted()
363 CALLED();
364 release_sem(fSeekSem);
365 delete_sem(fSeekSem);
366 fSeekSem = -1;
370 status_t
371 BAdapterIO::SetBuffer(BPositionIO* buffer)
373 // We can't change the buffer while we
374 // are running.
375 if (fOpened)
376 return B_ERROR;
378 fBuffer->SetBuffer(buffer);
379 return B_OK;
383 BInputAdapter*
384 BAdapterIO::BuildInputAdapter()
386 if (fInputAdapter != NULL)
387 return fInputAdapter;
389 fInputAdapter = new BInputAdapter(this);
390 return fInputAdapter;
394 status_t
395 BAdapterIO::SeekRequested(off_t position)
397 CALLED();
399 return B_ERROR;
403 ssize_t
404 BAdapterIO::BackWrite(const void* buffer, size_t size)
406 return fBuffer->BackWrite(buffer, size);
410 status_t
411 BAdapterIO::_EvaluateWait(off_t pos, off_t size)
413 CALLED();
415 off_t totalSize = 0;
416 if (GetSize(&totalSize) != B_OK)
417 TRACE("BAdapterIO::ReadAt: Can't get our size!\n");
419 TRACE("BAdapterIO::_EvaluateWait TS %" B_PRId64 " P %" B_PRId64
420 " S %" B_PRId64 "\n", totalSize, pos, size);
422 status_t err = fBuffer->EvaluatePosition(pos, totalSize);
424 TRACE("BAdapterIO::_EvaluateWait: %s\n", strerror(err));
426 if (err != B_OK && err != B_WOULD_BLOCK)
427 return err;
429 TRACE("BAdapterIO::_EvaluateWait: waiting for data\n");
431 return fBuffer->WaitForData(pos, size);
435 BInputAdapter::BInputAdapter(BAdapterIO* io)
437 fIO(io)
442 BInputAdapter::~BInputAdapter()
447 ssize_t
448 BInputAdapter::Write(const void* buffer, size_t size)
450 return fIO->BackWrite(buffer, size);
454 // FBC
455 void BAdapterIO::_ReservedAdapterIO1() {}
456 void BAdapterIO::_ReservedAdapterIO2() {}
457 void BAdapterIO::_ReservedAdapterIO3() {}
458 void BAdapterIO::_ReservedAdapterIO4() {}
459 void BAdapterIO::_ReservedAdapterIO5() {}
461 void BInputAdapter::_ReservedInputAdapter1() {}
462 void BInputAdapter::_ReservedInputAdapter2() {}