Browse Source

File: Add hasReadAccess()

pull/22/head
reuk 3 years ago
parent
commit
9a12e93f5a
No known key found for this signature in database GPG Key ID: 9ADCD339CFC98A11
5 changed files with 115 additions and 9 deletions
  1. +7
    -0
      modules/juce_core/files/juce_File.cpp
  2. +6
    -0
      modules/juce_core/files/juce_File.h
  3. +2
    -0
      modules/juce_core/native/juce_BasicNativeHeaders.h
  4. +6
    -0
      modules/juce_core/native/juce_posix_SharedCode.h
  5. +94
    -9
      modules/juce_core/native/juce_win32_Files.cpp

+ 7
- 0
modules/juce_core/files/juce_File.cpp View File

@@ -1146,11 +1146,18 @@ public:
expect (home.getChildFile ("./../xyz") == home.getParentDirectory().getChildFile ("xyz"));
expect (home.getChildFile ("a1/a2/a3/./../../a4") == home.getChildFile ("a1/a4"));
expect (! File().hasReadAccess());
expect (! File().hasWriteAccess());
expect (! tempFile.hasReadAccess());
{
FileOutputStream fo (tempFile);
fo.write ("0123456789", 10);
}
expect (tempFile.hasReadAccess());
expect (tempFile.exists());
expect (tempFile.getSize() == 10);
expect (std::abs ((int) (tempFile.getLastModificationTime().toMilliseconds() - Time::getCurrentTime().toMilliseconds())) < 3000);


+ 6
- 0
modules/juce_core/files/juce_File.h View File

@@ -342,6 +342,12 @@ public:
*/
bool hasWriteAccess() const;
/** Checks whether a file can be read.
@returns true if it's possible to read this file.
*/
bool hasReadAccess() const;
/** Changes the write-permission of a file or directory.
@param shouldBeReadOnly whether to add or remove write-permission


+ 2
- 0
modules/juce_core/native/juce_BasicNativeHeaders.h View File

@@ -154,6 +154,8 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <accctrl.h>
#include <aclapi.h>
#if ! JUCE_CXX17_IS_AVAILABLE
#pragma push_macro ("WIN_NOEXCEPT")


+ 6
- 0
modules/juce_core/native/juce_posix_SharedCode.h View File

@@ -288,6 +288,12 @@ bool File::hasWriteAccess() const
return false;
}
bool File::hasReadAccess() const
{
return fullPath.isNotEmpty()
&& access (fullPath.toUTF8(), R_OK) == 0;
}
static bool setFileModeFlags (const String& fullPath, mode_t flags, bool shouldSet) noexcept
{
juce_statStruct info;


+ 94
- 9
modules/juce_core/native/juce_win32_Files.cpp View File

@@ -159,6 +159,83 @@ namespace WindowsFileHelpers
return Result::fail (String (messageBuffer));
}
// The docs for the Windows security API aren't very clear. Some parts of the following
// function (the flags passed to GetNamedSecurityInfo, duplicating the primary access token)
// were guided by the example at https://blog.aaronballman.com/2011/08/how-to-check-access-rights/
static bool hasFileAccess (const File& file, DWORD accessType)
{
const auto& path = file.getFullPathName();
if (path.isEmpty())
return false;
struct PsecurityDescriptorGuard
{
~PsecurityDescriptorGuard() { if (psecurityDescriptor != nullptr) LocalFree (psecurityDescriptor); }
PSECURITY_DESCRIPTOR psecurityDescriptor = nullptr;
};
PsecurityDescriptorGuard descriptorGuard;
if (GetNamedSecurityInfo (path.toWideCharPointer(),
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
nullptr,
nullptr,
nullptr,
nullptr,
&descriptorGuard.psecurityDescriptor) != ERROR_SUCCESS)
{
return false;
}
struct HandleGuard
{
~HandleGuard() { if (handle != INVALID_HANDLE_VALUE) CloseHandle (handle); }
HANDLE handle = nullptr;
};
HandleGuard primaryTokenGuard;
if (! OpenProcessToken (GetCurrentProcess(),
TOKEN_IMPERSONATE | TOKEN_DUPLICATE | TOKEN_QUERY | STANDARD_RIGHTS_READ,
&primaryTokenGuard.handle))
{
return false;
}
HandleGuard duplicatedTokenGuard;
if (! DuplicateToken (primaryTokenGuard.handle,
SecurityImpersonation,
&duplicatedTokenGuard.handle))
{
return false;
}
GENERIC_MAPPING mapping { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
MapGenericMask (&accessType, &mapping);
DWORD allowed = 0;
BOOL granted = false;
PRIVILEGE_SET set;
DWORD setSize = sizeof (set);
if (! AccessCheck (descriptorGuard.psecurityDescriptor,
duplicatedTokenGuard.handle,
accessType,
&mapping,
&set,
&setSize,
&allowed,
&granted))
{
return false;
}
return granted != FALSE;
}
} // namespace WindowsFileHelpers
//==============================================================================
@@ -199,17 +276,25 @@ bool File::isDirectory() const
bool File::hasWriteAccess() const
{
if (fullPath.isEmpty())
return true;
if (exists())
{
const auto attr = WindowsFileHelpers::getAtts (fullPath);
auto attr = WindowsFileHelpers::getAtts (fullPath);
return WindowsFileHelpers::hasFileAccess (*this, GENERIC_WRITE)
&& (attr == INVALID_FILE_ATTRIBUTES
|| (attr & FILE_ATTRIBUTE_DIRECTORY) != 0
|| (attr & FILE_ATTRIBUTE_READONLY) == 0);
}
if ((! isDirectory()) && fullPath.containsChar (getSeparatorChar()))
return getParentDirectory().hasWriteAccess();
// NB: According to MS, the FILE_ATTRIBUTE_READONLY attribute doesn't work for
// folders, and can be incorrectly set for some special folders, so we'll just say
// that folders are always writable.
return attr == INVALID_FILE_ATTRIBUTES
|| (attr & FILE_ATTRIBUTE_DIRECTORY) != 0
|| (attr & FILE_ATTRIBUTE_READONLY) == 0;
return false;
}
bool File::hasReadAccess() const
{
return WindowsFileHelpers::hasFileAccess (*this, GENERIC_READ);
}
bool File::setFileReadOnlyInternal (bool shouldBeReadOnly) const


Loading…
Cancel
Save