You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
6.0 KiB
217 lines
6.0 KiB
/*
|
|
* Copyright (c) 2020-2021, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2020-2021 NVIDIA CORPORATION
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
|
|
#include "filemapping.hpp"
|
|
#include <assert.h>
|
|
|
|
#if defined(LINUX)
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
|
|
inline DWORD HIDWORD(size_t x)
|
|
{
|
|
return (DWORD)(x >> 32);
|
|
}
|
|
inline DWORD LODWORD(size_t x)
|
|
{
|
|
return (DWORD)x;
|
|
}
|
|
#endif
|
|
|
|
|
|
namespace nvh {
|
|
|
|
bool FileMapping::open(const char* fileName, MappingType mappingType, size_t fileSize)
|
|
{
|
|
if(!g_pageSize)
|
|
{
|
|
#if defined(_WIN32)
|
|
SYSTEM_INFO si;
|
|
GetSystemInfo(&si);
|
|
g_pageSize = (size_t)si.dwAllocationGranularity;
|
|
#elif defined(LINUX)
|
|
g_pageSize = (size_t)getpagesize();
|
|
#endif
|
|
}
|
|
|
|
m_mappingType = mappingType;
|
|
|
|
if(mappingType == MAPPING_READOVERWRITE)
|
|
{
|
|
assert(fileSize);
|
|
m_fileSize = fileSize;
|
|
m_mappingSize = ((fileSize + g_pageSize - 1) / g_pageSize) * g_pageSize;
|
|
|
|
// check if the current process is allowed to save a file of that size
|
|
#if defined(_WIN32)
|
|
TCHAR dir[MAX_PATH + 1];
|
|
BOOL success = FALSE;
|
|
ULARGE_INTEGER numFreeBytes;
|
|
|
|
DWORD length = GetVolumePathName(fileName, dir, MAX_PATH + 1);
|
|
|
|
if(length > 0)
|
|
{
|
|
success = GetDiskFreeSpaceEx(dir, NULL, NULL, &numFreeBytes);
|
|
}
|
|
|
|
m_isValid = (!!success) && (m_mappingSize <= numFreeBytes.QuadPart);
|
|
#elif defined(LINUX)
|
|
struct rlimit rlim;
|
|
getrlimit(RLIMIT_FSIZE, &rlim);
|
|
m_isValid = (m_mappingSize <= rlim.rlim_cur);
|
|
#endif
|
|
if(!m_isValid)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
m_win32.file = mappingType == MAPPING_READONLY ?
|
|
CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL) :
|
|
CreateFile(fileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
m_isValid = (m_win32.file != INVALID_HANDLE_VALUE);
|
|
if(m_isValid)
|
|
{
|
|
if(mappingType == MAPPING_READONLY)
|
|
{
|
|
DWORD sizeHi = 0;
|
|
DWORD sizeLo = GetFileSize(m_win32.file, &sizeHi);
|
|
m_mappingSize = (static_cast<size_t>(sizeHi) << 32) | sizeLo;
|
|
m_fileSize = m_mappingSize;
|
|
}
|
|
|
|
m_win32.fileMapping = CreateFileMapping(m_win32.file, NULL, mappingType == MAPPING_READONLY ? PAGE_READONLY : PAGE_READWRITE,
|
|
HIDWORD(m_mappingSize), LODWORD(m_mappingSize), NULL);
|
|
|
|
m_isValid = (m_win32.fileMapping != NULL);
|
|
if(m_isValid)
|
|
{
|
|
m_mappingPtr = MapViewOfFile(m_win32.fileMapping, mappingType == MAPPING_READONLY ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
|
|
HIDWORD(0), LODWORD(0), (SIZE_T)0);
|
|
if(!m_mappingPtr)
|
|
{
|
|
#if 0
|
|
DWORD err = GetLastError();
|
|
#endif
|
|
CloseHandle(m_win32.file);
|
|
m_isValid = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(m_win32.file);
|
|
}
|
|
}
|
|
#elif defined(LINUX)
|
|
m_unix.file = mappingType == MAPPING_READONLY ? ::open(fileName, O_RDONLY) : ::open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
|
|
|
m_isValid = (m_unix.file != -1);
|
|
if(m_isValid)
|
|
{
|
|
if(mappingType == MAPPING_READONLY)
|
|
{
|
|
struct stat s;
|
|
m_isValid &= (fstat(m_unix.file, &s) >= 0);
|
|
m_mappingSize = s.st_size;
|
|
}
|
|
else
|
|
{
|
|
// make file large enough to hold the complete scene
|
|
m_isValid &= (lseek(m_unix.file, m_mappingSize - 1, SEEK_SET) >= 0);
|
|
m_isValid &= (write(m_unix.file, "", 1) >= 0);
|
|
m_isValid &= (lseek(m_unix.file, 0, SEEK_SET) >= 0);
|
|
}
|
|
m_fileSize = m_mappingSize;
|
|
if(m_isValid)
|
|
{
|
|
m_mappingPtr = mmap(0, m_mappingSize, mappingType == MAPPING_READONLY ? PROT_READ : (PROT_READ | PROT_WRITE),
|
|
MAP_SHARED, m_unix.file, 0);
|
|
m_isValid = (m_mappingPtr != MAP_FAILED);
|
|
}
|
|
if(!m_isValid)
|
|
{
|
|
::close(m_unix.file);
|
|
m_unix.file = -1;
|
|
}
|
|
}
|
|
#endif
|
|
return m_isValid;
|
|
}
|
|
|
|
void FileMapping::close()
|
|
{
|
|
if(m_isValid)
|
|
{
|
|
#if defined(_WIN32)
|
|
assert((m_win32.file != INVALID_HANDLE_VALUE) && (m_win32.fileMapping != NULL));
|
|
|
|
UnmapViewOfFile(m_mappingPtr);
|
|
CloseHandle(m_win32.fileMapping);
|
|
|
|
if(m_mappingType == MAPPING_READOVERWRITE)
|
|
{
|
|
// truncate file to minimum size
|
|
// To work with 64-bit file pointers, you can declare a LONG, treat it as the upper half
|
|
// of the 64-bit file pointer, and pass its address in lpDistanceToMoveHigh. This means
|
|
// you have to treat two different variables as a logical unit, which is error-prone.
|
|
// The problems can be ameliorated by using the LARGE_INTEGER structure to create a 64-bit
|
|
// value and passing the two 32-bit values by means of the appropriate elements of the union.
|
|
// (see msdn documentation on SetFilePointer)
|
|
LARGE_INTEGER li;
|
|
li.QuadPart = (__int64)m_fileSize;
|
|
SetFilePointer(m_win32.file, li.LowPart, &li.HighPart, FILE_BEGIN);
|
|
|
|
SetEndOfFile(m_win32.file);
|
|
}
|
|
CloseHandle(m_win32.file);
|
|
|
|
m_mappingPtr = nullptr;
|
|
m_win32.fileMapping = nullptr;
|
|
m_win32.file = nullptr;
|
|
|
|
#elif defined(LINUX)
|
|
assert(m_unix.file != -1);
|
|
|
|
munmap(m_mappingPtr, m_mappingSize);
|
|
::close(m_unix.file);
|
|
|
|
m_mappingPtr = nullptr;
|
|
m_unix.file = -1;
|
|
#endif
|
|
|
|
m_isValid = false;
|
|
}
|
|
}
|
|
|
|
size_t FileMapping::g_pageSize = 0;
|
|
|
|
} // namespace nvh
|
|
|