Check disk permission
This commit is contained in:
@@ -108,7 +108,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\lib\libwebm;$(ProjectDir)..\..\..\lib\dav1d;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>webm-debug.lib;dav1d-debug.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>webm-debug.lib;dav1d-debug.lib;shell32.lib;user32.lib;advapi32.lib;ole32.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
@@ -117,7 +117,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\lib\libwebm;$(ProjectDir)..\..\..\lib\dav1d;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>webm.lib;dav1d.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>webm.lib;dav1d.lib;shell32.lib;user32.lib;advapi32.lib;ole32.lib</AdditionalDependencies>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
@@ -140,6 +140,7 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Common\VideoTypes.h" />
|
||||
<ClInclude Include="src\Common\FramePool.h" />
|
||||
<ClInclude Include="src\Common\PermissionUtils.h" />
|
||||
<ClInclude Include="src\Decoder\IVideoDecoder.h" />
|
||||
<ClInclude Include="src\Decoder\VideoDecoderFactory.h" />
|
||||
<ClInclude Include="src\Decoder\AV1Decoder.h" />
|
||||
@@ -165,6 +166,7 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Decoder\VideoDecoderFactory.cpp" />
|
||||
<ClCompile Include="src\Common\FramePool.cpp" />
|
||||
<ClCompile Include="src\Common\PermissionUtils.cpp" />
|
||||
<ClCompile Include="src\Decoder\AV1Decoder.cpp" />
|
||||
<ClCompile Include="src\FileIO\WebMFileReader.cpp" />
|
||||
<ClCompile Include="src\Pipeline\FrameBuffer.cpp" />
|
||||
|
||||
253
vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.cpp
Normal file
253
vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
#include "pch.h"
|
||||
#include "PermissionUtils.h"
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <shellapi.h>
|
||||
#include <sddl.h>
|
||||
#include <aclapi.h>
|
||||
#include <fstream>
|
||||
#include <random>
|
||||
|
||||
namespace Vav2Player {
|
||||
|
||||
PermissionUtils::PermissionResult PermissionUtils::CheckDirectoryCreatePermission(const std::filesystem::path& directory_path) {
|
||||
try {
|
||||
// 1. 디렉토리가 이미 존재하면 쓰기 권한 체크
|
||||
if (std::filesystem::exists(directory_path)) {
|
||||
if (TestDirectoryWrite(directory_path)) {
|
||||
OutputDebugStringA(("[PermissionUtils] Directory exists and writable: " + directory_path.string() + "\n").c_str());
|
||||
return PermissionResult::Granted;
|
||||
} else {
|
||||
OutputDebugStringA(("[PermissionUtils] Directory exists but not writable: " + directory_path.string() + "\n").c_str());
|
||||
return PermissionResult::Denied;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 부모 디렉토리에서 생성 권한 체크
|
||||
std::filesystem::path parent_path = directory_path.parent_path();
|
||||
if (!std::filesystem::exists(parent_path)) {
|
||||
// 부모 디렉토리가 없으면 재귀적으로 체크
|
||||
auto parent_result = CheckDirectoryCreatePermission(parent_path);
|
||||
if (parent_result != PermissionResult::Granted) {
|
||||
return parent_result;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 실제로 임시 디렉토리 생성 테스트
|
||||
std::filesystem::path test_dir = parent_path / ("test_permission_" + std::to_string(GetTickCount64()));
|
||||
|
||||
std::error_code ec;
|
||||
bool created = std::filesystem::create_directory(test_dir, ec);
|
||||
|
||||
if (created && !ec) {
|
||||
// 생성 성공, 정리
|
||||
std::filesystem::remove(test_dir, ec);
|
||||
OutputDebugStringA(("[PermissionUtils] Directory creation test successful: " + directory_path.string() + "\n").c_str());
|
||||
return PermissionResult::Granted;
|
||||
} else {
|
||||
OutputDebugStringA(("[PermissionUtils] Directory creation test failed: " + directory_path.string() + ", Error: " + ec.message() + "\n").c_str());
|
||||
return PermissionResult::Denied;
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
OutputDebugStringA(("[PermissionUtils] Exception in CheckDirectoryCreatePermission: " + std::string(e.what()) + "\n").c_str());
|
||||
return PermissionResult::Error;
|
||||
}
|
||||
}
|
||||
|
||||
PermissionUtils::PermissionResult PermissionUtils::CheckFileWritePermission(const std::filesystem::path& file_path) {
|
||||
try {
|
||||
// 1. 디렉토리 존재 확인
|
||||
std::filesystem::path parent_dir = file_path.parent_path();
|
||||
if (!std::filesystem::exists(parent_dir)) {
|
||||
auto dir_result = CheckDirectoryCreatePermission(parent_dir);
|
||||
if (dir_result != PermissionResult::Granted) {
|
||||
return dir_result;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 임시 파일 생성 테스트
|
||||
std::filesystem::path test_file = parent_dir / ("test_write_" + std::to_string(GetTickCount64()) + ".tmp");
|
||||
|
||||
std::ofstream test_stream(test_file, std::ios::binary);
|
||||
if (test_stream.is_open()) {
|
||||
test_stream << "permission test";
|
||||
test_stream.close();
|
||||
|
||||
// 정리
|
||||
std::error_code ec;
|
||||
std::filesystem::remove(test_file, ec);
|
||||
|
||||
OutputDebugStringA(("[PermissionUtils] File write test successful: " + file_path.string() + "\n").c_str());
|
||||
return PermissionResult::Granted;
|
||||
} else {
|
||||
OutputDebugStringA(("[PermissionUtils] File write test failed: " + file_path.string() + "\n").c_str());
|
||||
return PermissionResult::Denied;
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
OutputDebugStringA(("[PermissionUtils] Exception in CheckFileWritePermission: " + std::string(e.what()) + "\n").c_str());
|
||||
return PermissionResult::Error;
|
||||
}
|
||||
}
|
||||
|
||||
bool PermissionUtils::IsRunningAsAdmin() {
|
||||
BOOL is_admin = FALSE;
|
||||
PSID admin_group = nullptr;
|
||||
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
|
||||
|
||||
if (AllocateAndInitializeSid(&nt_authority, 2,
|
||||
SECURITY_BUILTIN_DOMAIN_RID,
|
||||
DOMAIN_ALIAS_RID_ADMINS,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
&admin_group)) {
|
||||
|
||||
if (!::CheckTokenMembership(nullptr, admin_group, &is_admin)) {
|
||||
is_admin = FALSE;
|
||||
}
|
||||
FreeSid(admin_group);
|
||||
}
|
||||
|
||||
OutputDebugStringA(is_admin ? "[PermissionUtils] Running as administrator\n" : "[PermissionUtils] Not running as administrator\n");
|
||||
return is_admin == TRUE;
|
||||
}
|
||||
|
||||
bool PermissionUtils::RequestAdminRestart() {
|
||||
wchar_t exe_path[MAX_PATH];
|
||||
DWORD path_length = GetModuleFileNameW(nullptr, exe_path, MAX_PATH);
|
||||
|
||||
if (path_length == 0 || path_length == MAX_PATH) {
|
||||
OutputDebugStringA("[PermissionUtils] Failed to get executable path for restart\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// ShellExecute로 관리자 권한 요청
|
||||
HINSTANCE result = ShellExecuteW(nullptr, L"runas", exe_path, nullptr, nullptr, SW_SHOWNORMAL);
|
||||
|
||||
bool success = reinterpret_cast<uintptr_t>(result) > 32;
|
||||
if (success) {
|
||||
OutputDebugStringA("[PermissionUtils] Requested admin restart\n");
|
||||
// 현재 프로세스 종료
|
||||
PostQuitMessage(0);
|
||||
} else {
|
||||
OutputDebugStringA("[PermissionUtils] Failed to request admin restart\n");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool PermissionUtils::ShowPermissionDialog(const std::wstring& message, const std::wstring& title) {
|
||||
int result = MessageBoxW(nullptr, message.c_str(), title.c_str(),
|
||||
MB_YESNO | MB_ICONWARNING | MB_TOPMOST);
|
||||
|
||||
return result == IDYES;
|
||||
}
|
||||
|
||||
std::filesystem::path PermissionUtils::GetSafeOutputDirectory() {
|
||||
// 우선순위 순서로 안전한 디렉토리 시도
|
||||
std::vector<std::filesystem::path> safe_directories;
|
||||
|
||||
// 1. 사용자 문서 폴더
|
||||
wchar_t* documents_path = nullptr;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &documents_path))) {
|
||||
safe_directories.push_back(std::filesystem::path(documents_path) / "Vav2Player");
|
||||
CoTaskMemFree(documents_path);
|
||||
}
|
||||
|
||||
// 2. 사용자 임시 폴더
|
||||
wchar_t temp_path[MAX_PATH];
|
||||
if (GetTempPathW(MAX_PATH, temp_path)) {
|
||||
safe_directories.push_back(std::filesystem::path(temp_path) / "Vav2Player");
|
||||
}
|
||||
|
||||
// 3. 현재 사용자 프로필 폴더
|
||||
wchar_t* profile_path = nullptr;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, &profile_path))) {
|
||||
safe_directories.push_back(std::filesystem::path(profile_path) / "Vav2Player");
|
||||
CoTaskMemFree(profile_path);
|
||||
}
|
||||
|
||||
// 4. 실행파일과 같은 디렉토리
|
||||
wchar_t exe_path[MAX_PATH];
|
||||
if (GetModuleFileNameW(nullptr, exe_path, MAX_PATH)) {
|
||||
std::filesystem::path exe_dir = std::filesystem::path(exe_path).parent_path();
|
||||
safe_directories.push_back(exe_dir / "output");
|
||||
}
|
||||
|
||||
// 각 디렉토리 권한 체크
|
||||
for (const auto& dir : safe_directories) {
|
||||
if (CheckDirectoryCreatePermission(dir) == PermissionResult::Granted) {
|
||||
OutputDebugStringA(("[PermissionUtils] Found safe directory: " + dir.string() + "\n").c_str());
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
// 모든 시도 실패 시 기본값
|
||||
OutputDebugStringA("[PermissionUtils] No safe directory found, using fallback\n");
|
||||
return std::filesystem::path("C:\\temp\\Vav2Player");
|
||||
}
|
||||
|
||||
PermissionUtils::PermissionResult PermissionUtils::CheckAndHandlePermissions(const std::filesystem::path& output_directory) {
|
||||
OutputDebugStringA(("[PermissionUtils] Checking permissions for: " + output_directory.string() + "\n").c_str());
|
||||
|
||||
// 1. 기본 권한 체크
|
||||
auto result = CheckDirectoryCreatePermission(output_directory);
|
||||
|
||||
if (result == PermissionResult::Granted) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. 권한 없는 경우 처리
|
||||
std::wstring message;
|
||||
|
||||
if (result == PermissionResult::Denied) {
|
||||
std::wstring dir_path = std::wstring(output_directory.string().begin(), output_directory.string().end());
|
||||
message = L"출력 디렉토리에 쓰기 권한이 없습니다:\n" + dir_path +
|
||||
L"\n\n관리자 권한으로 다시 시작하시겠습니까?\n(아니오를 선택하면 안전한 위치를 사용합니다)";
|
||||
} else {
|
||||
std::wstring dir_path = std::wstring(output_directory.string().begin(), output_directory.string().end());
|
||||
message = L"디렉토리 권한 확인 중 오류가 발생했습니다:\n" + dir_path +
|
||||
L"\n\n관리자 권한으로 다시 시작하시겠습니까?";
|
||||
}
|
||||
|
||||
// 3. 사용자에게 선택 제공
|
||||
if (ShowPermissionDialog(message, L"디렉토리 권한 필요")) {
|
||||
// 관리자 권한으로 재시작 요청
|
||||
if (RequestAdminRestart()) {
|
||||
// 재시작 요청 성공 (앱이 종료될 예정)
|
||||
return PermissionResult::Granted;
|
||||
} else {
|
||||
// 재시작 실패 - 안전한 디렉토리 사용
|
||||
return PermissionResult::Denied;
|
||||
}
|
||||
} else {
|
||||
// 사용자가 관리자 권한 거부 - 안전한 디렉토리 사용
|
||||
return PermissionResult::Denied;
|
||||
}
|
||||
}
|
||||
|
||||
bool PermissionUtils::TestDirectoryWrite(const std::filesystem::path& directory_path) {
|
||||
try {
|
||||
std::filesystem::path test_file = directory_path / ("write_test_" + std::to_string(GetTickCount64()) + ".tmp");
|
||||
|
||||
std::ofstream test_stream(test_file, std::ios::binary);
|
||||
if (!test_stream.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
test_stream << "write permission test";
|
||||
test_stream.close();
|
||||
|
||||
// 정리
|
||||
std::error_code ec;
|
||||
std::filesystem::remove(test_file, ec);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace Vav2Player
|
||||
44
vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.h
Normal file
44
vav2/Vav2Player/Vav2Player/src/Common/PermissionUtils.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
namespace Vav2Player {
|
||||
|
||||
class PermissionUtils {
|
||||
public:
|
||||
// 권한 체크 결과
|
||||
enum class PermissionResult {
|
||||
Granted, // 권한 있음
|
||||
Denied, // 권한 없음
|
||||
Error // 체크 중 오류 발생
|
||||
};
|
||||
|
||||
// 디렉토리 생성 권한 체크
|
||||
static PermissionResult CheckDirectoryCreatePermission(const std::filesystem::path& directory_path);
|
||||
|
||||
// 파일 쓰기 권한 체크
|
||||
static PermissionResult CheckFileWritePermission(const std::filesystem::path& file_path);
|
||||
|
||||
// 관리자 권한으로 실행 중인지 확인
|
||||
static bool IsRunningAsAdmin();
|
||||
|
||||
// 관리자 권한으로 재시작 요청
|
||||
static bool RequestAdminRestart();
|
||||
|
||||
// 사용자에게 권한 관련 메시지 표시
|
||||
static bool ShowPermissionDialog(const std::wstring& message, const std::wstring& title = L"권한 필요");
|
||||
|
||||
// 안전한 출력 디렉토리 제안
|
||||
static std::filesystem::path GetSafeOutputDirectory();
|
||||
|
||||
// 권한 체크 및 처리 (통합 함수)
|
||||
static PermissionResult CheckAndHandlePermissions(const std::filesystem::path& output_directory);
|
||||
|
||||
private:
|
||||
// 디렉토리에 대한 실제 쓰기 테스트
|
||||
static bool TestDirectoryWrite(const std::filesystem::path& directory_path);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Vav2Player
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "pch.h"
|
||||
#include "FileOutput.h"
|
||||
#include "../Common/PermissionUtils.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
@@ -31,6 +32,11 @@ FileOutput::FileOutput(const OutputConfig& config)
|
||||
OutputDebugStringA("[FileOutput] YUV->RGB conversion will use lookup table optimization\n");
|
||||
}
|
||||
|
||||
// 권한 체크 및 설정
|
||||
if (!CheckAndSetupPermissions()) {
|
||||
OutputDebugStringA("[FileOutput] Warning: Failed to setup proper permissions for output directory\n");
|
||||
}
|
||||
|
||||
InitializeCache();
|
||||
}
|
||||
|
||||
@@ -764,4 +770,91 @@ void FileOutput::StoreRGB24_SIMD(uint8_t* dst, __m256i r_vec, __m256i g_vec, __m
|
||||
}
|
||||
}
|
||||
|
||||
bool FileOutput::CheckAndSetupPermissions() {
|
||||
try {
|
||||
std::filesystem::path exe_path = GetProcessPath();
|
||||
std::filesystem::path full_output_path = exe_path / m_config.output_directory;
|
||||
|
||||
OutputDebugStringA(("[FileOutput] Checking permissions for output directory: " + full_output_path.string() + "\n").c_str());
|
||||
|
||||
// 권한 체크 및 처리
|
||||
auto permission_result = PermissionUtils::CheckAndHandlePermissions(full_output_path);
|
||||
|
||||
switch (permission_result) {
|
||||
case PermissionUtils::PermissionResult::Granted:
|
||||
OutputDebugStringA("[FileOutput] Permissions granted for output directory\n");
|
||||
return true;
|
||||
|
||||
case PermissionUtils::PermissionResult::Denied:
|
||||
OutputDebugStringA("[FileOutput] Permissions denied, attempting to use safe directory\n");
|
||||
return HandlePermissionDenied();
|
||||
|
||||
case PermissionUtils::PermissionResult::Error:
|
||||
OutputDebugStringA("[FileOutput] Error checking permissions, attempting to use safe directory\n");
|
||||
return HandlePermissionDenied();
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
OutputDebugStringA(("[FileOutput] Exception in CheckAndSetupPermissions: " + std::string(e.what()) + "\n").c_str());
|
||||
return HandlePermissionDenied();
|
||||
}
|
||||
}
|
||||
|
||||
bool FileOutput::HandlePermissionDenied() {
|
||||
try {
|
||||
// 안전한 출력 디렉토리 찾기
|
||||
std::filesystem::path safe_directory = PermissionUtils::GetSafeOutputDirectory();
|
||||
|
||||
OutputDebugStringA(("[FileOutput] Using safe output directory: " + safe_directory.string() + "\n").c_str());
|
||||
|
||||
// 설정 업데이트
|
||||
m_config.output_directory = safe_directory;
|
||||
|
||||
// 캐시 재초기화
|
||||
InitializeCache();
|
||||
|
||||
// 권한 재체크
|
||||
auto permission_result = PermissionUtils::CheckDirectoryCreatePermission(safe_directory);
|
||||
|
||||
if (permission_result == PermissionUtils::PermissionResult::Granted) {
|
||||
OutputDebugStringA("[FileOutput] Safe directory permissions verified\n");
|
||||
|
||||
// 사용자에게 알림
|
||||
std::wstring safe_dir_wstr = std::wstring(safe_directory.string().begin(), safe_directory.string().end());
|
||||
std::wstring message = L"원래 출력 디렉토리에 권한이 없어 다음 위치를 사용합니다:\n" + safe_dir_wstr;
|
||||
PermissionUtils::ShowPermissionDialog(message, L"출력 디렉토리 변경");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
OutputDebugStringA("[FileOutput] Safe directory also lacks permissions\n");
|
||||
|
||||
// 마지막 수단: 임시 디렉토리
|
||||
wchar_t temp_path[MAX_PATH];
|
||||
if (GetTempPathW(MAX_PATH, temp_path)) {
|
||||
std::filesystem::path temp_dir = std::filesystem::path(temp_path) / "Vav2Player_Emergency";
|
||||
m_config.output_directory = temp_dir;
|
||||
InitializeCache();
|
||||
|
||||
OutputDebugStringA(("[FileOutput] Using emergency temp directory: " + temp_dir.string() + "\n").c_str());
|
||||
|
||||
std::wstring temp_dir_wstr = std::wstring(temp_dir.string().begin(), temp_dir.string().end());
|
||||
std::wstring message = L"안전한 출력 디렉토리를 찾을 수 없어 임시 폴더를 사용합니다:\n" + temp_dir_wstr;
|
||||
PermissionUtils::ShowPermissionDialog(message, L"긴급 출력 디렉토리");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
OutputDebugStringA("[FileOutput] Failed to get temp directory\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
OutputDebugStringA(("[FileOutput] Exception in HandlePermissionDenied: " + std::string(e.what()) + "\n").c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Vav2Player
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "../Common/VideoTypes.h"
|
||||
#include "../Common/PermissionUtils.h"
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
@@ -64,6 +65,10 @@ public:
|
||||
bool CreateOutputDirectory();
|
||||
void ClearOutputDirectory();
|
||||
|
||||
// 권한 체크 및 처리
|
||||
bool CheckAndSetupPermissions();
|
||||
bool HandlePermissionDenied();
|
||||
|
||||
// 통계 정보
|
||||
struct OutputStats {
|
||||
uint64_t frames_saved = 0;
|
||||
|
||||
Reference in New Issue
Block a user