diff --git a/src/kits/app/LinkReceiver.cpp b/src/kits/app/LinkReceiver.cpp index b2929a3250..a695a30de9 100644 --- a/src/kits/app/LinkReceiver.cpp +++ b/src/kits/app/LinkReceiver.cpp @@ -21,7 +21,7 @@ #include #include "link_message.h" - +#include "syscalls.h" //#define DEBUG_BPORTLINK #ifdef DEBUG_BPORTLINK @@ -245,9 +245,11 @@ LinkReceiver::ReadFromPort(bigtime_t timeout) status_t -LinkReceiver::Read(void *data, ssize_t size) +LinkReceiver::Read(void *data, ssize_t passedSize) { // STRACE(("info: LinkReceiver Read()ing %ld bytes...\n", size)); + ssize_t size = passedSize; + if (fReadError < B_OK) return fReadError; @@ -259,13 +261,49 @@ LinkReceiver::Read(void *data, ssize_t size) if (fDataSize == 0 || fReplySize == 0) return B_NO_INIT; // need to call GetNextReply() first + bool useArea = false; + if ((size_t)size >= kMaxBufferSize) { + useArea = true; + size = sizeof(area_id); + } + if (fRecvPosition + size > fRecvStart + fReplySize) { // reading past the end of current message fReadError = B_BAD_VALUE; return B_BAD_VALUE; } - memcpy(data, fRecvBuffer + fRecvPosition, size); + if (useArea) { + area_id sourceArea; + memcpy((void*)&sourceArea, fRecvBuffer + fRecvPosition, size); + + area_info areaInfo; + if (get_area_info(sourceArea, &areaInfo) < B_OK) + fReadError = B_BAD_VALUE; + + if (fReadError >= B_OK) { + thread_info threadInfo; + get_thread_info(find_thread(NULL), &threadInfo); + + void* areaAddress = NULL; + if (areaInfo.team != threadInfo.team) { + sourceArea = _kern_transfer_area(sourceArea, &areaAddress, + B_ANY_ADDRESS, threadInfo.team); + + if (sourceArea < B_OK) + fReadError = sourceArea; + } else { + areaAddress = areaInfo.address; + } + + if (areaAddress && sourceArea >= B_OK) { + memcpy(data, areaAddress, passedSize); + delete_area(sourceArea); + } + } + } else { + memcpy(data, fRecvBuffer + fRecvPosition, size); + } fRecvPosition += size; return fReadError; } diff --git a/src/kits/app/LinkSender.cpp b/src/kits/app/LinkSender.cpp index 18c3de2895..c1f40f625e 100644 --- a/src/kits/app/LinkSender.cpp +++ b/src/kits/app/LinkSender.cpp @@ -129,8 +129,11 @@ LinkSender::CancelMessage() status_t -LinkSender::Attach(const void *data, size_t size) +LinkSender::Attach(const void *passedData, size_t passedSize) { + size_t size = passedSize; + const void* data = passedData; + if (fCurrentStatus < B_OK) return fCurrentStatus; @@ -140,6 +143,12 @@ LinkSender::Attach(const void *data, size_t size) if (fCurrentEnd == fCurrentStart) return B_NO_INIT; // need to call StartMessage() first + bool useArea = false; + if (size >= kMaxBufferSize) { + useArea = true; + size = sizeof(area_id); + } + if (SpaceLeft() < size) { // we have to make space for the data @@ -148,6 +157,20 @@ LinkSender::Attach(const void *data, size_t size) return fCurrentStatus = status; } + area_id senderArea = -1; + if (useArea) { + void* address = NULL; + off_t alignedSize = (passedSize + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1); + senderArea = create_area("LinkSenderArea", &address, B_ANY_ADDRESS, + alignedSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + + if (senderArea < B_OK) + return senderArea; + + data = &senderArea; + memcpy(address, passedData, passedSize); + } + memcpy(fBuffer + fCurrentEnd, data, size); fCurrentEnd += size; diff --git a/src/servers/app/ServerPicture.cpp b/src/servers/app/ServerPicture.cpp index 34ffcf90e7..7c73a6bfbe 100644 --- a/src/servers/app/ServerPicture.cpp +++ b/src/servers/app/ServerPicture.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -976,37 +977,27 @@ ServerPicture::DataLength() const } -#define BUFFER_SIZE 4096 - - status_t ServerPicture::ImportData(BPrivate::LinkReceiver &link) { int32 size = 0; link.Read(&size); - if (size >= 65536) { - //TODO: Pass via an area. - // Ideally the Link** api would allow to write partial messages, - // so that a big picture could be written in chunks of 4096 bytes - // or so - return B_ERROR; - } - off_t oldPosition = fData->Position(); fData->Seek(0, SEEK_SET); - // TODO: Oh yeah... 65kb on the stack... - char buffer[size]; - status_t read = link.Read(buffer, size); - if (read < B_OK) - return (status_t)read; - - fData->Write(buffer, size); + status_t status = B_NO_MEMORY; + char* buffer = new(std::nothrow) char[size]; + if (buffer) { + status = B_OK; + ssize_t read = link.Read(buffer, size); + if (read < B_OK || fData->Write(buffer, size) < B_OK) + status = B_ERROR; + delete [] buffer; + } fData->Seek(oldPosition, SEEK_SET); - - return B_OK; + return status; } @@ -1032,27 +1023,24 @@ ServerPicture::ExportData(BPrivate::PortLink &link) off_t size = 0; fData->GetSize(&size); link.Attach((int32)size); - if (size >= 65536) { - //TODO: Pass via an area + + status_t status = B_NO_MEMORY; + char* buffer = new(std::nothrow) char[size]; + if (buffer) { + status = B_OK; + ssize_t read = fData->Read(buffer, size); + if (read < B_OK || link.Attach(buffer, read) < B_OK) + status = B_ERROR; + delete [] buffer; + } + + if (status < B_OK) { link.CancelMessage(); link.StartMessage(B_ERROR); - return B_ERROR; } - // TODO: Oh yeah... 65kb on the stack... - char buffer[size]; - ssize_t read = fData->Read(buffer, size); - if (read < B_OK) - return (status_t)read; - if (link.Attach(buffer, read) < B_OK) { - // - link.CancelMessage(); - link.StartMessage(B_ERROR); - }; - fData->Seek(oldPosition, SEEK_SET); - - return B_OK; + return status; }