inline std::optional get_file_owner()

in utils/include/utils/file/FileUtils.h [437:547]


inline std::optional<std::string> get_file_owner(const std::filesystem::path& file_path) {
#ifndef WIN32
  struct stat info = {};
  if (stat(file_path.c_str(), &info) != 0) {
    return std::nullopt;
  }

  struct passwd pw = {};
  pw.pw_name = nullptr;
  struct passwd *result = nullptr;
  char localbuf[1024] = {};
  if (getpwuid_r(info.st_uid, &pw, localbuf, sizeof(localbuf), &result) != 0 || pw.pw_name == nullptr) {
    return std::nullopt;
  }

  return std::string(pw.pw_name);
#else
  DWORD return_code = 0;
  PSID sid_owner = NULL;
  BOOL bool_return = TRUE;
  LPTSTR account_name = NULL;
  LPTSTR domain_name = NULL;
  DWORD account_name_dword = 1;
  DWORD domain_name_dword = 1;
  SID_NAME_USE sid_type = SidTypeUnknown;
  HANDLE file_handle;
  PSECURITY_DESCRIPTOR sec_descriptor = NULL;

  // Get the handle of the file object.
  file_handle = CreateFile(
    TEXT(file_path.string().c_str()),
    GENERIC_READ,
    FILE_SHARE_READ,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL);

  // Check GetLastError for CreateFile error code.
  if (file_handle == INVALID_HANDLE_VALUE) {
    return std::nullopt;
  }

  auto close_file_handle = gsl::finally([&file_handle] { CloseHandle(file_handle); });

  // Get the owner SID of the file.
  return_code = GetSecurityInfo(
    file_handle,
    SE_FILE_OBJECT,
    OWNER_SECURITY_INFORMATION,
    &sid_owner,
    NULL,
    NULL,
    NULL,
    &sec_descriptor);

  // Check GetLastError for GetSecurityInfo error condition.
  if (return_code != ERROR_SUCCESS) {
    return std::nullopt;
  }

  // First call to LookupAccountSid to get the buffer sizes.
  bool_return = LookupAccountSid(
    NULL,
    sid_owner,
    account_name,
    (LPDWORD)&account_name_dword,
    domain_name,
    (LPDWORD)&domain_name_dword,
    &sid_type);

  // Reallocate memory for the buffers.
  account_name = (LPTSTR)GlobalAlloc(
    GMEM_FIXED,
    account_name_dword);

  // Check GetLastError for GlobalAlloc error condition.
  if (account_name == NULL) {
    return std::nullopt;
  }
  auto cleanup_account_name = gsl::finally([&account_name] { GlobalFree(account_name); });

  domain_name = (LPTSTR)GlobalAlloc(
    GMEM_FIXED,
    domain_name_dword);

  // Check GetLastError for GlobalAlloc error condition.
  if (domain_name == NULL) {
    return std::nullopt;
  }
  auto cleanup_domain_name = gsl::finally([&domain_name] { GlobalFree(domain_name); });

  // Second call to LookupAccountSid to get the account name.
  bool_return = LookupAccountSid(
    NULL,                   // name of local or remote computer
    sid_owner,              // security identifier
    account_name,               // account name buffer
    (LPDWORD)&account_name_dword,   // size of account name buffer
    domain_name,             // domain name
    (LPDWORD)&domain_name_dword,  // size of domain name buffer
    &sid_type);                 // SID type

  // Check GetLastError for LookupAccountSid error condition.
  if (bool_return == FALSE) {
    return std::nullopt;
  }

  auto result = std::string(account_name);
  return result;
#endif
}