APIRET os2APIENTRY DosSetFHState(os2HFILE hFile, ULONG mode) { if(mode&0x077f) return 1; //FixMe: invalid flags APIRET rc; int idx=(int)hFile; FileTable.lock(idx); if(FileTable[idx]) { ULONG oldmode = FileTable[idx]->mode; ULONG newmode = (FileTable[idx]->mode&0x077f)|mode; if((oldmode&OPEN_FLAGS_NOINHERIT)!=(newmode&OPEN_FLAGS_NOINHERIT)) { //inheritance changed - duplicate and change HANDLE target; if(DuplicateHandle(GetCurrentProcess(), FileTable[idx]->ntFileHandle, GetCurrentProcess(), &target, 0, newmode&OPEN_FLAGS_NOINHERIT?FALSE:TRUE, DUPLICATE_SAME_ACCESS )) { CloseHandle(FileTable[idx]->ntFileHandle); FileTable[idx]->ntFileHandle = target; } else rc = (APIRET)GetLastError(); } else rc = 0; FileTable[idx]->mode = newmode; } else rc = 6; //invalid handle FileTable.unlock(idx); return rc; }
APIRET os2APIENTRY DosSetFilePtr(os2HFILE hFile, LONG ib, ULONG method, PULONG ibActual) { int idx=(int)hFile; FileTable.lock(idx); if(FileTable[idx]) { FileTable.unlock(idx); HANDLE hf=FileTable[idx]->ntFileHandle; DWORD dw = SetFilePointer(hf, (DWORD)ib, 0, (LONG)method ); if(dw==(DWORD)-1) return (APIRET)GetLastError(); else { *ibActual = (ULONG)dw; return 0; } } else { FileTable.unlock(idx); return 6; //invalid handle } }
APIRET os2APIENTRY DosQueryHType(os2HFILE hFile, PULONG pType, PULONG pAttr) { int idx=(int)hFile; FileTable.lock(idx); if(FileTable[idx]) { HANDLE hf=FileTable[idx]->ntFileHandle; FileTable.unlock(idx); DWORD t=GetFileType(hf); *pType = 0; switch(t) { case FILE_TYPE_DISK: *pType = 0; break; case FILE_TYPE_CHAR: *pType = 1; break; case FILE_TYPE_PIPE: *pType = 2; break; case FILE_TYPE_UNKNOWN: default: *pType = 3; } //We always set the network bit because we cannot retrieve device attributes *pType |= 0x80; *pAttr = 0; return 0; } else { FileTable.unlock(idx); return 6; //invalid handle } }
APIRET os2APIENTRY DosSetFileInfo(os2HFILE hFile, ULONG ulInfoLevel, PVOID pInfoBuf, ULONG cbInfoBuf) { if(ulInfoLevel!=FIL_STANDARD && ulInfoLevel!=FIL_QUERYEASIZE) return 124; //invalid level APIRET rc; int idx=(int)hFile; FileTable.lock(idx); if(!FileTable[idx]) { rc = 6; //invalid handle goto done; } if(ulInfoLevel==FIL_STANDARD) { FILESTATUS3 *fs3=(FILESTATUS3*)pInfoBuf; FILETIME *lpftCreation=0; FILETIME ftCreation; FILETIME *lpftLastAccess=0; FILETIME ftLastAccess; FILETIME *lpftLastWrite=0; FILETIME ftLastWrite; if(cbInfoBuf>offsetof(FILESTATUS3,ftimeCreation) && (*(USHORT*)(&fs3->fdateCreation)!=0 || *(USHORT*)(&fs3->ftimeCreation)!=0)) { os22ntfiletime(fs3->fdateCreation,fs3->ftimeCreation,&ftCreation); lpftCreation=&ftCreation; } if(cbInfoBuf>offsetof(FILESTATUS3,ftimeLastAccess) && (*(USHORT*)(&fs3->fdateLastAccess)!=0 || *(USHORT*)(&fs3->ftimeLastAccess)!=0)) { os22ntfiletime(fs3->fdateLastAccess,fs3->ftimeCreation,&ftLastAccess); lpftLastAccess=&ftLastAccess; } if(cbInfoBuf>offsetof(FILESTATUS3,ftimeLastWrite) && (*(USHORT*)(&fs3->fdateLastWrite)!=0 || *(USHORT*)(&fs3->ftimeLastWrite)!=0)) { os22ntfiletime(fs3->fdateLastWrite,fs3->ftimeCreation,&ftLastWrite); lpftLastWrite=&ftLastWrite; } if(!SetFileTime(FileTable[idx]->ntFileHandle, lpftCreation, lpftLastAccess, lpftLastWrite )) { rc = (APIRET)GetLastError(); goto done; } //attributes cannot be changed rc = 0; } done: FileTable.unlock(idx); return rc; }
APIRET os2APIENTRY DosCreatePipe(PHFILE phfRead, PHFILE phfWrite, ULONG cb) { if(phfRead==0 || phfWrite==0) return 87; //invalid parameter ntFILE *ntFileR=new ntFILE; if(!ntFileR) return 8; //not enough memory ntFILE *ntFileW=new ntFILE; if(!ntFileW) { delete ntFileR; return 8; //not enough memory } int idxR=FileTable.findAndLockFree(); if(idxR==-1) { delete ntFileR; delete ntFileW; return 4; //too many open files } int idxW=FileTable.findAndLockFree(); if(idxW==-1) { delete ntFileR; delete ntFileW; FileTable.unlock(idxR); return 4; //too many open files } HANDLE hReadPipe,hWritePipe; SECURITY_ATTRIBUTES sa; memset(&sa,0,sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; //os/2 pipes are by default inherited, nt pipes isn't if(CreatePipe(&hReadPipe,&hWritePipe,&sa,(DWORD)cb)) { ntFileR->ntFileHandle = hReadPipe; ntFileR->mode = OPEN_ACCESS_READONLY; ntFileW->ntFileHandle = hWritePipe; ntFileW->mode = OPEN_ACCESS_WRITEONLY; FileTable[idxR] = ntFileR; FileTable[idxW] = ntFileW; FileTable.unlock(idxR); FileTable.unlock(idxW); *phfRead = (os2HFILE)idxR; *phfWrite = (os2HFILE)idxW; return 0; } else { FileTable.unlock(idxR); FileTable.unlock(idxW); delete ntFileR; delete ntFileW; return (APIRET)GetLastError(); } }
APIRET os2APIENTRY DosQueryFHState(os2HFILE hFile, PULONG pMode) { APIRET rc; int idx=(int)hFile; FileTable.lock(idx); if(FileTable[idx]) { rc = 0; *pMode = FileTable[idx]->mode; } else rc = 6; //invalid handle FileTable.unlock(idx); return rc; }
APIRET os2APIENTRY DosResetBuffer(os2HFILE hFile) { int idx=(int)hFile; FileTable.lock(idx); if(FileTable[idx]) { HANDLE hf=FileTable[idx]->ntFileHandle; FileTable.unlock(idx); if(FlushFileBuffers(hf)) return 0; else return (APIRET)GetLastError(); } else { FileTable.unlock(idx); return 6; //invalid handle } }
APIRET os2APIENTRY DosClose(os2HFILE hFile) { int idx=(int)hFile; FileTable.lock(idx); APIRET rc; if(FileTable[idx]) { CloseHandle(FileTable[idx]->ntFileHandle); delete FileTable[idx]; FileTable[idx] = 0; rc = 0; } else { rc = 6; //invalid handle } FileTable.unlock(idx); return rc; }
APIRET os2APIENTRY DosQueryFileInfo(os2HFILE hFile, ULONG ulInfoLevel, PVOID pInfo, ULONG cbInfoBuf) { if(ulInfoLevel!=FIL_STANDARD && ulInfoLevel!=FIL_QUERYEASIZE && ulInfoLevel!=FIL_QUERYEASFROMLIST) return 124; //invalid level APIRET rc; int idx=(int)hFile; FileTable.lock(idx); if(!FileTable[idx]) { rc = 6; //invalid handle goto done; } if(ulInfoLevel==FIL_QUERYEASFROMLIST) { rc = 254; //invalid EA name goto done; } BY_HANDLE_FILE_INFORMATION bhfi; if(!GetFileInformationByHandle(FileTable[idx]->ntFileHandle,&bhfi)) { rc = (APIRET)GetLastError(); goto done; } FILESTATUS4 *fs4; fs4=(FILESTATUS4 *)pInfo; if(cbInfoBuf>offsetof(FILESTATUS4,ftimeCreation)) ntfiletime2os2(bhfi.ftCreationTime, &fs4->fdateCreation, &fs4->ftimeCreation); if(cbInfoBuf>offsetof(FILESTATUS4,ftimeLastAccess)) ntfiletime2os2(bhfi.ftLastAccessTime, &fs4->fdateLastAccess, &fs4->ftimeLastAccess); if(cbInfoBuf>offsetof(FILESTATUS4,ftimeLastWrite)) ntfiletime2os2(bhfi.ftLastWriteTime, &fs4->fdateLastWrite, &fs4->ftimeLastWrite); if(cbInfoBuf>offsetof(FILESTATUS4,cbFile)) fs4->cbFile = (ULONG)bhfi.nFileSizeLow; if(cbInfoBuf>offsetof(FILESTATUS4,cbFileAlloc)) fs4->cbFileAlloc = (ULONG)bhfi.nFileSizeLow; if(cbInfoBuf>offsetof(FILESTATUS4,attrFile)) ntfileattr2os2(bhfi.dwFileAttributes, &fs4->attrFile); if(ulInfoLevel==FIL_QUERYEASIZE) fs4->cbList = 0; done: FileTable.unlock(idx); return rc; }
APIRET os2APIENTRY DosDupHandle(os2HFILE hFile, PHFILE pHfile) { int srcIdx = (int)hFile; FileTable.lock(srcIdx); if(!FileTable[srcIdx]) { FileTable.unlock(srcIdx); return 1; //FixMe } int dstIdx; if(*pHfile==(os2HFILE)-1) { dstIdx = FileTable.findAndLockFree(); if(dstIdx==-1) { FileTable.unlock(srcIdx); return 4; //too many open files } } else { dstIdx = (int)*pHfile; FileTable.lock(dstIdx); } if(srcIdx==dstIdx) { //no-op FileTable.unlock(srcIdx); return 0; } if(FileTable[dstIdx]) { CloseHandle(FileTable[dstIdx]->ntFileHandle); delete FileTable[dstIdx]; FileTable[dstIdx] = 0; } APIRET rc; HANDLE target; if(DuplicateHandle(GetCurrentProcess(), FileTable[srcIdx]->ntFileHandle, GetCurrentProcess(), &target, 0, TRUE, DUPLICATE_SAME_ACCESS )) { rc = 0; FileTable[dstIdx] = new ntFILE; FileTable[dstIdx]->ntFileHandle = target; FileTable[dstIdx]->mode = FileTable[srcIdx]->mode; if(dstIdx==0) SetStdHandle(STD_INPUT_HANDLE,target); else if(dstIdx==1) SetStdHandle(STD_OUTPUT_HANDLE,target); else if(dstIdx==2) SetStdHandle(STD_ERROR_HANDLE,target); } else rc = 6; //invalid handle FileTable.unlock(srcIdx); FileTable.unlock(dstIdx); return rc; }
APIRET os2APIENTRY DosSetFileLocks(os2HFILE hFile, PFILELOCK pflUnlock, PFILELOCK pflLock, ULONG /*timeout*/, ULONG flags) { APIRET rc; int idx=(int)hFile; FileTable.lock(idx); if(FileTable[idx]) { rc=0; if(pflLock) { OVERLAPPED o; memset(&o,0,sizeof(o)); o.Offset = pflLock->lOffset; o.OffsetHigh = 0; if(!LockFileEx(FileTable[idx]->ntFileHandle, flags&1?0:LOCKFILE_EXCLUSIVE_LOCK, 0, pflLock->lRange, 0, 0 )) { rc = (APIRET)GetLastError(); } } if(rc==0 && pflUnlock) { if(!UnlockFile(FileTable[idx]->ntFileHandle, pflUnlock->lOffset, 0, pflUnlock->lRange, 0 )) { UnlockFile(FileTable[idx]->ntFileHandle, pflLock->lOffset,0, pflLock->lRange,0 ); rc = (APIRET)GetLastError(); } } } else rc = 6; //invalid handle FileTable.unlock(idx); return rc; }
APIRET os2APIENTRY DosSetFileSize(os2HFILE hFile, ULONG cbSize) { APIRET rc; int idx=(int)hFile; FileTable.lock(idx); if(FileTable[idx]) { APIRET rc; HANDLE hf=FileTable[idx]->ntFileHandle; DWORD current = SetFilePointer(hf,0,0,1); SetFilePointer(hf,(DWORD)cbSize,0,0); if(SetEndOfFile(hf)) rc = 0; else rc = (APIRET)GetLastError(); SetFilePointer(hf,current,0,0); } else { rc = 6; //invalid handle } FileTable.unlock(idx); return rc; }
APIRET os2APIENTRY DosWrite(os2HFILE hFile, PVOID pBuffer, ULONG cbWrite, PULONG pcbActual) { int idx=(int)hFile; FileTable.lock(idx); if(FileTable[idx]) { HANDLE hf=FileTable[idx]->ntFileHandle; FileTable.unlock(idx); if(WriteFile(hf, (LPVOID)pBuffer, (DWORD)cbWrite, (LPDWORD)pcbActual, 0 )) return 0; else return (APIRET)GetLastError(); } else { FileTable.unlock(idx); return 6; //invalid handle } }
namespace Kernel { unsigned int Object::next_object_id; HandleTable g_handle_table; void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); if (itr == waiting_threads.end()) waiting_threads.push_back(std::move(thread)); } void WaitObject::RemoveWaitingThread(Thread* thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); if (itr != waiting_threads.end()) waiting_threads.erase(itr); } SharedPtr<Thread> WaitObject::WakeupNextThread() { if (waiting_threads.empty()) return nullptr; auto next_thread = std::move(waiting_threads.front()); waiting_threads.erase(waiting_threads.begin()); next_thread->ReleaseWaitObject(this); return next_thread; } void WaitObject::WakeupAllWaitingThreads() { auto waiting_threads_copy = waiting_threads; // We use a copy because ReleaseWaitObject will remove the thread from this object's // waiting_threads list for (auto thread : waiting_threads_copy) thread->ReleaseWaitObject(this); ASSERT_MSG(waiting_threads.empty(), "failed to awaken all waiting threads!"); } HandleTable::HandleTable() { next_generation = 1; Clear(); } ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { DEBUG_ASSERT(obj != nullptr); u16 slot = next_free_slot; if (slot >= generations.size()) { LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); return ERR_OUT_OF_HANDLES; } next_free_slot = generations[slot]; u16 generation = next_generation++; // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. // CTR-OS doesn't use generation 0, so skip straight to 1. if (next_generation >= (1 << 15)) next_generation = 1; generations[slot] = generation; objects[slot] = std::move(obj); Handle handle = generation | (slot << 15); return MakeResult<Handle>(handle); } ResultVal<Handle> HandleTable::Duplicate(Handle handle) { SharedPtr<Object> object = GetGeneric(handle); if (object == nullptr) { LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle); return ERR_INVALID_HANDLE; } return Create(std::move(object)); } ResultCode HandleTable::Close(Handle handle) { if (!IsValid(handle)) return ERR_INVALID_HANDLE; u16 slot = GetSlot(handle); objects[slot] = nullptr; generations[slot] = next_free_slot; next_free_slot = slot; return RESULT_SUCCESS; } bool HandleTable::IsValid(Handle handle) const { size_t slot = GetSlot(handle); u16 generation = GetGeneration(handle); return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; } SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { return GetCurrentThread(); } else if (handle == CurrentProcess) { LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess); return nullptr; } if (!IsValid(handle)) { return nullptr; } return objects[GetSlot(handle)]; } void HandleTable::Clear() { for (u16 i = 0; i < MAX_COUNT; ++i) { generations[i] = i + 1; objects[i] = nullptr; } next_free_slot = 0; } /// Initialize the kernel void Init() { Kernel::ThreadingInit(); Kernel::TimersInit(); Object::next_object_id = 0; } /// Shutdown the kernel void Shutdown() { Kernel::ThreadingShutdown(); Kernel::TimersShutdown(); g_handle_table.Clear(); // Free all kernel objects g_current_process = nullptr; } } // namespace
/// Shutdown the kernel void Shutdown() { Kernel::ThreadingShutdown(); Kernel::TimersShutdown(); g_handle_table.Clear(); // Free all kernel objects g_current_process = nullptr; }
dmz::Handle * dmz::lua_create_handle (lua_State *L, const Handle Value) { LUA_START_VALIDATE (L); Handle *result = 0; if (Value) { HandleTable *ht (get_handle_table (L)); lua_pushlightuserdata (L, (void *)&LuaHandleTableKey); lua_rawget (L, LUA_REGISTRYINDEX); const int Table (lua_gettop (L)); if (lua_istable (L, Table) && ht) { int *indexPtr = ht->lookup (Value); if (indexPtr) { lua_rawgeti (L, Table, *indexPtr); result = (Handle *)lua_touserdata (L, -1); if (!result) { lua_pop (L, 1); } else if (*result != Value) { lua_pop (L, 1); // pop invalid Handle; result = 0; } } if (!result) { if (indexPtr && ht->remove (Value)) { delete indexPtr; indexPtr = 0; } result = (Handle *)lua_newuserdata (L, sizeof (Handle)); if (result) { lua_pushvalue (L, -1); int index = luaL_ref (L, Table); indexPtr = new int (index); if (!ht->store (Value, indexPtr)) { delete indexPtr; indexPtr = 0; } *result = Value; luaL_getmetatable (L, HandleName); lua_setmetatable (L, -2); } } } lua_remove (L, Table); // Remove Table; } if (!result) { lua_pushnil (L); } LUA_END_VALIDATE (L, 1); return result; }
/// Shutdown the kernel void Shutdown() { Kernel::ThreadingShutdown(); Kernel::TimersShutdown(); g_handle_table.Clear(); // Free all kernel objects }
namespace Kernel { SharedPtr<Thread> g_main_thread = nullptr; HandleTable g_handle_table; u64 g_program_id = 0; void WaitObject::AddWaitingThread(Thread* thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); if (itr == waiting_threads.end()) waiting_threads.push_back(thread); } void WaitObject::RemoveWaitingThread(Thread* thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); if (itr != waiting_threads.end()) waiting_threads.erase(itr); } Thread* WaitObject::WakeupNextThread() { if (waiting_threads.empty()) return nullptr; auto next_thread = waiting_threads.front(); waiting_threads.erase(waiting_threads.begin()); next_thread->ReleaseWaitObject(this); return next_thread; } void WaitObject::WakeupAllWaitingThreads() { auto waiting_threads_copy = waiting_threads; // We use a copy because ReleaseWaitObject will remove the thread from this object's // waiting_threads list for (auto thread : waiting_threads_copy) thread->ReleaseWaitObject(this); _assert_msg_(Kernel, waiting_threads.empty(), "failed to awaken all waiting threads!"); } HandleTable::HandleTable() { next_generation = 1; Clear(); } ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { _dbg_assert_(Kernel, obj != nullptr); u16 slot = next_free_slot; if (slot >= generations.size()) { LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); return ERR_OUT_OF_HANDLES; } next_free_slot = generations[slot]; u16 generation = next_generation++; // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. // CTR-OS doesn't use generation 0, so skip straight to 1. if (next_generation >= (1 << 15)) next_generation = 1; Handle handle = generation | (slot << 15); if (obj->handle == INVALID_HANDLE) obj->handle = handle; generations[slot] = generation; objects[slot] = std::move(obj); return MakeResult<Handle>(handle); } ResultVal<Handle> HandleTable::Duplicate(Handle handle) { SharedPtr<Object> object = GetGeneric(handle); if (object == nullptr) { LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle); return ERR_INVALID_HANDLE; } return Create(std::move(object)); } ResultCode HandleTable::Close(Handle handle) { if (!IsValid(handle)) return ERR_INVALID_HANDLE; size_t slot = GetSlot(handle); u16 generation = GetGeneration(handle); objects[slot] = nullptr; generations[generation] = next_free_slot; next_free_slot = slot; return RESULT_SUCCESS; } bool HandleTable::IsValid(Handle handle) const { size_t slot = GetSlot(handle); u16 generation = GetGeneration(handle); return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; } SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { return GetCurrentThread(); } else if (handle == CurrentProcess) { LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess); return nullptr; } if (!IsValid(handle)) { return nullptr; } return objects[GetSlot(handle)]; } void HandleTable::Clear() { for (size_t i = 0; i < MAX_COUNT; ++i) { generations[i] = i + 1; objects[i] = nullptr; } next_free_slot = 0; } /// Initialize the kernel void Init() { Kernel::ThreadingInit(); Kernel::TimersInit(); } /// Shutdown the kernel void Shutdown() { Kernel::ThreadingShutdown(); Kernel::TimersShutdown(); g_handle_table.Clear(); // Free all kernel objects } /** * Loads executable stored at specified address * @entry_point Entry point in memory of loaded executable * @return True on success, otherwise false */ bool LoadExec(u32 entry_point) { Core::g_app_core->SetPC(entry_point); // 0x30 is the typical main thread priority I've seen used so far g_main_thread = Kernel::SetupMainThread(0x30, Kernel::DEFAULT_STACK_SIZE); // Setup the idle thread Kernel::SetupIdleThread(); return true; } } // namespace
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process, HandleTable& src_table) { IPC::Header header{src_cmdbuf[0]}; size_t untranslated_size = 1u + header.normal_params_size; size_t command_size = untranslated_size + header.translate_params_size; ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH); // TODO(yuriks): Return error std::copy_n(src_cmdbuf, untranslated_size, cmd_buf.begin()); size_t i = untranslated_size; while (i < command_size) { u32 descriptor = cmd_buf[i] = src_cmdbuf[i]; i += 1; switch (IPC::GetDescriptorType(descriptor)) { case IPC::DescriptorType::CopyHandle: case IPC::DescriptorType::MoveHandle: { u32 num_handles = IPC::HandleNumberFromDesc(descriptor); ASSERT(i + num_handles <= command_size); // TODO(yuriks): Return error for (u32 j = 0; j < num_handles; ++j) { Handle handle = src_cmdbuf[i]; SharedPtr<Object> object = nullptr; if (handle != 0) { object = src_table.GetGeneric(handle); ASSERT(object != nullptr); // TODO(yuriks): Return error if (descriptor == IPC::DescriptorType::MoveHandle) { src_table.Close(handle); } } cmd_buf[i++] = AddOutgoingHandle(std::move(object)); } break; } case IPC::DescriptorType::CallingPid: { cmd_buf[i++] = src_process.process_id; break; } case IPC::DescriptorType::StaticBuffer: { VAddr source_address = src_cmdbuf[i]; IPC::StaticBufferDescInfo buffer_info{descriptor}; // Copy the input buffer into our own vector and store it. std::vector<u8> data(buffer_info.size); Memory::ReadBlock(src_process, source_address, data.data(), data.size()); AddStaticBuffer(buffer_info.buffer_id, std::move(data)); cmd_buf[i++] = source_address; break; } case IPC::DescriptorType::MappedBuffer: { u32 next_id = static_cast<u32>(request_mapped_buffers.size()); request_mapped_buffers.emplace_back(src_process, descriptor, src_cmdbuf[i], next_id); cmd_buf[i++] = next_id; break; } default: UNIMPLEMENTED_MSG("Unsupported handle translation: {:#010X}", descriptor); } } return RESULT_SUCCESS; }
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, HandleTable& dst_table) const { IPC::Header header{cmd_buf[0]}; size_t untranslated_size = 1u + header.normal_params_size; size_t command_size = untranslated_size + header.translate_params_size; ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH); std::copy_n(cmd_buf.begin(), untranslated_size, dst_cmdbuf); size_t i = untranslated_size; while (i < command_size) { u32 descriptor = dst_cmdbuf[i] = cmd_buf[i]; i += 1; switch (IPC::GetDescriptorType(descriptor)) { case IPC::DescriptorType::CopyHandle: case IPC::DescriptorType::MoveHandle: { // HLE services don't use handles, so we treat both CopyHandle and MoveHandle equally u32 num_handles = IPC::HandleNumberFromDesc(descriptor); ASSERT(i + num_handles <= command_size); for (u32 j = 0; j < num_handles; ++j) { SharedPtr<Object> object = GetIncomingHandle(cmd_buf[i]); Handle handle = 0; if (object != nullptr) { // TODO(yuriks): Figure out the proper error handling for if this fails handle = dst_table.Create(object).Unwrap(); } dst_cmdbuf[i++] = handle; } break; } case IPC::DescriptorType::StaticBuffer: { IPC::StaticBufferDescInfo buffer_info{descriptor}; const auto& data = GetStaticBuffer(buffer_info.buffer_id); // Grab the address that the target thread set up to receive the response static buffer // and write our data there. The static buffers area is located right after the command // buffer area. size_t static_buffer_offset = IPC::COMMAND_BUFFER_LENGTH + 2 * buffer_info.buffer_id; IPC::StaticBufferDescInfo target_descriptor{dst_cmdbuf[static_buffer_offset]}; VAddr target_address = dst_cmdbuf[static_buffer_offset + 1]; ASSERT_MSG(target_descriptor.size >= data.size(), "Static buffer data is too big"); Memory::WriteBlock(dst_process, target_address, data.data(), data.size()); dst_cmdbuf[i++] = target_address; break; } case IPC::DescriptorType::MappedBuffer: { VAddr addr = request_mapped_buffers[cmd_buf[i]].address; dst_cmdbuf[i++] = addr; break; } default: UNIMPLEMENTED_MSG("Unsupported handle translation: {:#010X}", descriptor); } } return RESULT_SUCCESS; }
APIRET os2APIENTRY DosOpen(PCSZ pszFileName, PHFILE pHf, PULONG pulAction, ULONG cbFile, ULONG ulAttribute, ULONG fsOpenFlags, ULONG fsOpenMode, PEAOP2 peaop2) { int idx=FileTable.findAndLockFree(); if(idx==-1) return 4; //too many open files ntFILE *ntFile=new ntFILE; if(!ntFile) return 8; //not enough memory if(peaop2) return 282; //eas not supported char szName[MAX_PATH]; DWORD fdwAccess; DWORD fdwShareMode; LPSECURITY_ATTRIBUTES lpsa; DWORD fdwCreate; DWORD fdwAttrsAndFlags; HANDLE hTemplateFile; //szName, FixMe: named pipe namespace strcpy(szName,pszFileName); //fdwAcess if((fsOpenMode&0x7)==OPEN_ACCESS_READONLY) fdwAccess = GENERIC_READ; else if((fsOpenMode&0x7)==OPEN_ACCESS_WRITEONLY) fdwAccess = GENERIC_WRITE; else if((fsOpenMode&0x7)==OPEN_ACCESS_READWRITE) fdwAccess = GENERIC_READ|GENERIC_WRITE; else return 87; //invalid parameter //fdwShareMode if((fsOpenMode&0x70)==OPEN_SHARE_DENYREADWRITE) fdwShareMode = 0; else if((fsOpenMode&0x70)==OPEN_SHARE_DENYWRITE) fdwShareMode = FILE_SHARE_READ; else if((fsOpenMode&0x70)==OPEN_SHARE_DENYREAD) fdwShareMode = FILE_SHARE_WRITE; else if((fsOpenMode&0x70)==OPEN_SHARE_DENYNONE) fdwShareMode = FILE_SHARE_READ+FILE_SHARE_WRITE; else return 87; //invalid parameter //lpsa SECURITY_ATTRIBUTES sa; if((fsOpenMode&OPEN_FLAGS_NOINHERIT)) lpsa = 0; else { memset(&sa,0,sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; lpsa = &sa; } //fdwCreate switch(fsOpenFlags&0xff) { case OPEN_ACTION_FAIL_IF_NEW|OPEN_ACTION_FAIL_IF_EXISTS: return 1; //FixMe case OPEN_ACTION_FAIL_IF_NEW|OPEN_ACTION_OPEN_IF_EXISTS: fdwCreate = OPEN_EXISTING; break; case OPEN_ACTION_FAIL_IF_NEW|OPEN_ACTION_REPLACE_IF_EXISTS: fdwCreate = TRUNCATE_EXISTING; break; case OPEN_ACTION_CREATE_IF_NEW|OPEN_ACTION_FAIL_IF_EXISTS: fdwCreate = CREATE_NEW; break; case OPEN_ACTION_CREATE_IF_NEW|OPEN_ACTION_OPEN_IF_EXISTS: fdwCreate = OPEN_ALWAYS; break; case OPEN_ACTION_CREATE_IF_NEW|OPEN_ACTION_REPLACE_IF_EXISTS: fdwCreate = CREATE_ALWAYS; break; default: return 87; //invalid parameter, FixMe: is this legal under os/2? } //fdwAttrsAndFlags fdwAttrsAndFlags = 0; if(ulAttribute&FILE_ARCHIVED) fdwAttrsAndFlags |= FILE_ATTRIBUTE_ARCHIVE; if(ulAttribute&FILE_SYSTEM) fdwAttrsAndFlags |= FILE_ATTRIBUTE_SYSTEM; if(ulAttribute&FILE_HIDDEN) fdwAttrsAndFlags |= FILE_ATTRIBUTE_HIDDEN; if(ulAttribute&FILE_READONLY) fdwAttrsAndFlags |= FILE_ATTRIBUTE_READONLY; if(fsOpenMode&OPEN_FLAGS_WRITE_THROUGH) fdwAttrsAndFlags |= FILE_FLAG_WRITE_THROUGH; if(fsOpenMode&OPEN_FLAGS_NO_CACHE) fdwAttrsAndFlags |= FILE_FLAG_WRITE_THROUGH; if((fsOpenMode&0x700)==OPEN_FLAGS_SEQUENTIAL) fdwAttrsAndFlags |= FILE_FLAG_SEQUENTIAL_SCAN; if((fsOpenMode&0x700)==OPEN_FLAGS_RANDOM) fdwAttrsAndFlags |= FILE_FLAG_RANDOM_ACCESS; //hTemplateFile hTemplateFile = 0; HANDLE hf = CreateFile(szName, fdwAccess, fdwShareMode, lpsa, fdwCreate, fdwAttrsAndFlags, hTemplateFile); if(hf==INVALID_HANDLE_VALUE) return (APIRET)GetLastError(); //->pulAction if(fdwCreate==CREATE_ALWAYS || fdwCreate==OPEN_ALWAYS) { if(GetLastError()==183/*ERROR_ALREADY_EXIST*/) *pulAction = fdwCreate==CREATE_ALWAYS?FILE_CREATED:FILE_EXISTED; else *pulAction = FILE_CREATED; } else { *pulAction = FILE_EXISTED; } if((fsOpenFlags&0x0f)==OPEN_ACTION_REPLACE_IF_EXISTS) { //set file size SetFilePointer(hf,cbFile,0,0); SetEndOfFile(hf); //FixMe SetFilePointer(hf,0,0,0); } *pHf = (os2HFILE)idx; ntFile->ntFileHandle = hf; ntFile->mode = fsOpenMode; FileTable[idx] = ntFile; FileTable.unlock(idx); return 0; }