]> git.tdb.fi Git - libs/core.git/blob - fs/windows/stat.cpp
Check errors from CreateSemaphore
[libs/core.git] / fs / windows / stat.cpp
1 #include <windows.h>
2 #include <aclapi.h>
3 #include <msp/core/systemerror.h>
4 #include <msp/strings/format.h>
5 #include <msp/time/rawtime_private.h>
6 #include "stat.h"
7 #include "stat_private.h"
8
9 using namespace std;
10
11 namespace {
12
13 PSID copy_sid(PSID sid)
14 {
15         if(!sid || !IsValidSid(sid))
16                 return nullptr;
17         DWORD len = GetLengthSid(sid);
18         PSID copy = reinterpret_cast<PSID>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len));
19         if(!CopySid(len, copy, sid))
20         {
21                 DWORD err = GetLastError();
22                 HeapFree(GetProcessHeap(), 0, copy);
23                 throw Msp::system_error("CopySid", err);
24         }
25         return copy;
26 }
27
28 string get_account_name(PSID sid)
29 {
30         char name[1024];
31         DWORD nlen = sizeof(name);
32         char domain[1024];
33         DWORD dlen = sizeof(domain);
34         SID_NAME_USE use;
35         if(!LookupAccountSid(nullptr, sid, name, &nlen, domain, &dlen, &use))
36                 throw Msp::system_error("LookupAccountSid");
37         return Msp::format("%s/%s", name, domain);
38 }
39
40 }
41
42
43 namespace Msp {
44 namespace FS {
45
46 Stat::Private::Private(const Private &other):
47         owner_id(copy_sid(other.owner_id)),
48         group_id(copy_sid(other.group_id))
49 { }
50
51 Stat::Private::~Private()
52 {
53         if(owner_id!=INVALID_UID)
54                 HeapFree(GetProcessHeap(), 0, owner_id);
55         if(group_id!=INVALID_GID)
56                 HeapFree(GetProcessHeap(), 0, group_id);
57 }
58
59 void Stat::Private::fill_owner_info(Stat::OwnerInfo &result)
60 {
61         if(owner_id!=INVALID_UID)
62                 result.owner = get_account_name(owner_id);
63         else
64                 result.owner = "None";
65
66         if(group_id!=INVALID_GID)
67                 result.group = get_account_name(group_id);
68         else
69                 result.group = "None";
70 }
71
72
73 Stat Stat::stat(const Path &path)
74 {
75         HANDLE handle;
76         handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, nullptr);
77         if(handle==INVALID_HANDLE_VALUE)
78         {
79                 DWORD err = GetLastError();
80                 if(err==ERROR_FILE_NOT_FOUND || err==ERROR_PATH_NOT_FOUND)
81                         return Stat();
82                 else
83                         throw system_error(format("CreateFile(%s)", path), err);
84         }
85
86         BY_HANDLE_FILE_INFORMATION info;
87         if(!GetFileInformationByHandle(handle, &info))
88         {
89                 CloseHandle(handle);
90                 throw system_error("GetFileInformationByHandle");
91         }
92
93         Stat result;
94         result.exists = true;
95         if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
96                 result.type = DIRECTORY;
97         else
98                 result.type = REGULAR;
99
100         result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow;
101         result.alloc_size = (result.size+511)&~511;
102         result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime));
103
104         PSECURITY_DESCRIPTOR sec_desc;
105         PSID owner = nullptr;
106         PSID group = nullptr;
107         const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION;
108         DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, nullptr, nullptr, &sec_desc);
109         if(err)
110         {
111                 CloseHandle(handle);
112                 throw system_error("GetSecurityInfo", err);
113         }
114
115         result.priv = new Private;
116         result.priv->owner_id = copy_sid(owner);
117         result.priv->group_id = copy_sid(group);
118
119         LocalFree(sec_desc);
120
121         CloseHandle(handle);
122
123         return result;
124 }
125
126 Stat Stat::lstat(const Path &path)
127 {
128         return stat(path);
129 }
130
131 bool exists(const Path &path)
132 {
133         return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES;
134 }
135
136 } // namespace FS
137 } // namespace Msp