/* Copyright (c) 2013 Stanislaw Halik * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "shm.h" #if defined(_WIN32) #if !defined __WINE__ # include #endif #include #include #include #include struct secattr { bool success; SECURITY_DESCRIPTOR* pSD; SECURITY_ATTRIBUTES attrs; PSID pEveryoneSID; PACL pACL; void cleanup() { if (pEveryoneSID) FreeSid(pEveryoneSID); if (pACL) LocalFree(pACL); if (pSD) LocalFree(pSD); success = false; pSD = nullptr; pEveryoneSID = nullptr; pACL = nullptr; } secattr(DWORD perms) : success(true), pSD(nullptr), pEveryoneSID(nullptr), pACL(nullptr) { SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; EXPLICIT_ACCESS ea; if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID)) { fprintf(stderr, "AllocateAndInitializeSid: %d\n", (int) GetLastError()); goto cleanup; } memset(&ea, 0, sizeof(ea)); ea.grfAccessPermissions = perms; ea.grfAccessMode = SET_ACCESS; ea.grfInheritance = NO_INHERITANCE; ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea.Trustee.ptstrName = (LPTSTR) pEveryoneSID; if (SetEntriesInAcl(1, &ea, NULL, &pACL) != ERROR_SUCCESS) { fprintf(stderr, "SetEntriesInAcl: %d\n", (int) GetLastError()); goto cleanup; } pSD = (SECURITY_DESCRIPTOR*) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (pSD == nullptr) { fprintf(stderr, "LocalAlloc: %d\n", (int) GetLastError()); goto cleanup; } if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { fprintf(stderr, "InitializeSecurityDescriptor: %d\n", (int) GetLastError()); goto cleanup; } if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) { fprintf(stderr, "SetSecurityDescriptorDacl: %d\n", (int) GetLastError()); goto cleanup; } attrs.bInheritHandle = false; attrs.lpSecurityDescriptor = pSD; attrs.nLength = sizeof(SECURITY_ATTRIBUTES); return; cleanup: cleanup(); } ~secattr() { cleanup(); } }; PortableLockedShm::PortableLockedShm(const char* shmName, const char* mutexName, int mapSize) { secattr sa(GENERIC_ALL|SYNCHRONIZE); hMutex = CreateMutexA(sa.success ? &sa.attrs : nullptr, false, mutexName); if (!hMutex) { #if !defined __WINE__ qDebug() << "CreateMutexA:" << (int) GetLastError(); #endif return; } hMapFile = CreateFileMappingA( INVALID_HANDLE_VALUE, sa.success ? &sa.attrs : nullptr, PAGE_READWRITE, 0, mapSize, shmName); if (!hMapFile) { #if !defined __WINE__ qDebug() << "CreateFileMappingA:", (int) GetLastError(); #endif return; } mem = MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, mapSize); if (!mem) { #if !defined __WINE__ qDebug() << "MapViewOfFile:" << (int) GetLastError(); #endif } } PortableLockedShm::~PortableLockedShm() { if(!UnmapViewOfFile(mem)) goto fail; if (!CloseHandle(hMapFile)) goto fail; if (!CloseHandle(hMutex)) goto fail; return; fail: (void)0; #if !defined __WINE__ qDebug() << "failed to close mapping"; #endif } bool PortableLockedShm::lock() { return WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0; } bool PortableLockedShm::unlock() { return ReleaseMutex(hMutex); } #else #include #pragma GCC diagnostic ignored "-Wunused-result" PortableLockedShm::PortableLockedShm(const char *shmName, const char* /*mutexName*/, int mapSize) : size(mapSize) { char filename[PATH_MAX+2] {}; strcpy(filename, "/"); strcat(filename, shmName); fd = shm_open(filename, O_RDWR | O_CREAT, 0600); (void) ftruncate(fd, mapSize); mem = mmap(NULL, mapSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t)0); } PortableLockedShm::~PortableLockedShm() { (void) munmap(mem, size); (void) close(fd); } bool PortableLockedShm::lock() { return flock(fd, LOCK_EX) == 0; } bool PortableLockedShm::unlock() { return flock(fd, LOCK_UN) == 0; } #endif bool PortableLockedShm::success() { #ifndef _WIN32 return mem != (void*) -1; #else return mem != NULL; #endif }