dvander@28: /* vim: set ts=4 sw=4 tw=99 et: dvander@28: * dvander@28: * Copyright (C) 2012 David Anderson dvander@28: * dvander@233: * This file is part of SourcePawn. dvander@28: * dvander@233: * SourcePawn is free software: you can redistribute it and/or modify it under dvander@28: * the terms of the GNU General Public License as published by the Free dvander@28: * Software Foundation, either version 3 of the License, or (at your option) dvander@28: * any later version. dvander@28: * dvander@233: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY dvander@28: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@28: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@28: * dvander@28: * You should have received a copy of the GNU General Public License along with dvander@233: * SourcePawn. If not, see http://www.gnu.org/licenses/. dvander@11: */ dvander@11: dvander@11: #define WIN32_LEAN_AND_MEAN dvander@11: #include dvander@251: #include dvander@251: #include dvander@11: #include "Platform.h" dvander@11: dvander@59: using namespace ke; dvander@11: dvander@11: static inline DWORD dvander@11: ToProtBits(OS::Protection prot) dvander@11: { dvander@11: switch (prot) { dvander@28: case OS::Prot_ReadWrite: dvander@11: return PAGE_READWRITE; dvander@11: case OS::Prot_ReadWriteExecute: dvander@11: return PAGE_EXECUTE_READWRITE; dvander@11: default: dvander@11: assert(prot == OS::Prot_ReadExecute); dvander@11: return PAGE_EXECUTE_READ; dvander@11: } dvander@11: } dvander@11: dvander@11: Address dvander@11: OS::MapMemory(size_t amount, MapMode mode, Protection prot_) dvander@11: { dvander@11: DWORD prot = ToProtBits(prot_); dvander@11: DWORD type = MEM_RESERVE; dvander@11: if (mode == Map_Commit) dvander@11: type |= MEM_COMMIT; dvander@11: dvander@11: return (Address)VirtualAlloc(NULL, amount, type, prot); dvander@11: } dvander@11: dvander@11: bool dvander@11: OS::CommitMemory(Address address, size_t amount, Protection prot_) dvander@11: { dvander@11: DWORD prot = ToProtBits(prot_); dvander@11: return !!VirtualAlloc(address, amount, MEM_COMMIT, prot); dvander@11: } dvander@11: dvander@11: void dvander@11: OS::UnmapMemory(Address address, size_t size) dvander@11: { dvander@11: VirtualFree(address, 0, MEM_RELEASE); dvander@11: } dvander@11: dvander@28: static Address dvander@53: MapMemoryAt(Address address, size_t amount, OS::MapMode mode, OS::Protection prot_) dvander@28: { dvander@28: DWORD bits = ToProtBits(prot_); dvander@28: DWORD flags = MEM_RESERVE; dvander@53: if (mode == OS::Map_Commit) dvander@28: flags |= MEM_COMMIT; dvander@28: dvander@69: return (Address)VirtualAlloc((LPVOID)address, amount, flags, bits); dvander@28: } dvander@28: dvander@11: OS::AlignableMapping dvander@11: OS::MapAlignedMemory(size_t amount, size_t alignment, MapMode mode) dvander@11: { dvander@11: Address addr = MapMemory(amount, mode, OS::Prot_ReadWrite); dvander@11: if (!addr) dvander@11: return AlignableMapping(NULL, alignment, 0); dvander@11: dvander@11: if (!IsAligned(addr, alignment)) { dvander@11: UnmapMemory(addr, amount); dvander@11: dvander@11: // Try to grab the next available aligned address. dvander@11: addr = AlignedBase(addr, alignment); dvander@11: addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite); dvander@11: while (!addr) { dvander@11: // Try to over-allocate to get the right region. This can race dvander@11: // with other threads; we expect this to be rare. If this turns dvander@11: // out to be a problem, the API is set up such that we can just dvander@11: // return two pointers: the base, and the aligned address into dvander@11: // the over-allocated region. dvander@11: addr = MapMemory(amount + alignment, mode, OS::Prot_ReadWrite); dvander@11: if (!addr) dvander@11: return AlignableMapping(NULL, alignment, 0); dvander@11: UnmapMemory(addr, amount + alignment); dvander@11: addr = AlignedBase(addr, alignment); dvander@11: addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite); dvander@11: } dvander@11: } dvander@11: dvander@11: return AlignableMapping(addr, alignment, amount); dvander@11: } dvander@11: dvander@11: void dvander@11: OS::UnmapAlignedMemory(Address address, size_t size) dvander@11: { dvander@11: OS::UnmapMemory(address, size); dvander@11: } dvander@251: dvander@251: bool dvander@251: OS::GetAbsolutePath(const char *path, AutoFree &chars) dvander@251: { dvander@251: char try1[MAX_PATH]; dvander@251: DWORD result = GetFullPathName(path, sizeof(try1), try1, NULL); dvander@251: if (result <= 0) dvander@251: return false; dvander@251: dvander@251: // +1 because if result < MAX_PATH, it doesn't include the null terminator. dvander@251: chars = (char *)calloc(result + 1, sizeof(char)); dvander@251: if (!*chars) dvander@251: return false; dvander@251: dvander@251: if (result <= MAX_PATH) { dvander@251: strcpy(*chars, try1); dvander@251: return true; dvander@251: } dvander@251: dvander@251: // We should get the same output on the next try. dvander@251: return GetFullPathName(path, result, *chars, NULL) == result - 1; dvander@251: } dvander@251: dvander@251: bool dvander@251: OS::SplitPath(const char *path, AutoFree &base, AutoFree &name) dvander@251: { dvander@251: size_t len = strlen(path); dvander@251: dvander@251: // Skip trailing slashes. dvander@251: while (len > 1 && (path[len - 1] == '/' || path[len - 1] == '\\')) dvander@251: len--; dvander@251: dvander@251: for (size_t i = len - 1; i < len; i--) { dvander@251: if (path[i] == '\\' || path[i] == '/') { dvander@251: name = (char *)calloc(len - i, sizeof(char)); dvander@251: if (!*name) dvander@251: return false; dvander@251: dvander@251: strcpy(*name, &path[i + 1]); dvander@251: dvander@251: base = (char *)calloc(i + 1, sizeof(char)); dvander@251: if (!*base) dvander@251: return false; dvander@251: dvander@251: memcpy(*base, path, i); dvander@251: (*base)[i] = '\0'; dvander@251: return true; dvander@251: } dvander@251: } dvander@251: dvander@251: // The path should have been absolute, which contains at least one separator. dvander@251: return false; dvander@251: } dvander@251: dvander@251: const char * dvander@251: OS::PathSeparator() dvander@251: { dvander@251: return "\\"; dvander@251: } dvander@251: dvander@251: OS::PathType dvander@251: OS::InspectPath(const char *path) dvander@251: { dvander@251: struct _stat s; dvander@251: int result = _stat(path, &s); dvander@251: if (result != 0) dvander@251: return OS::Path_Invalid; dvander@251: dvander@251: if (s.st_mode & _S_IFDIR) dvander@251: return OS::Path_Folder; dvander@251: if (s.st_mode & _S_IFREG) dvander@251: return OS::Path_File; dvander@251: dvander@251: return OS::Path_Invalid; dvander@251: }