]> git.tdb.fi Git - libs/core.git/blob - source/fs/windows/stat.cpp
Move most platform-specific code into overlay directories
[libs/core.git] / source / 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 0;
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(0, 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)
54                 HeapFree(GetProcessHeap(), 0, owner_id);
55         if(group_id)
56                 HeapFree(GetProcessHeap(), 0, group_id);
57 }
58
59 void Stat::Private::fill_owner_info(Stat::OwnerInfo &result)
60 {
61         if(owner_id)
62                 result.owner = get_account_name(owner_id);
63         else
64                 result.owner = "None";
65
66         if(group_id)
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, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 0);
77         if(handle==INVALID_HANDLE_VALUE)
78         {
79                 DWORD err = GetLastError();
80                 if(err==ERROR_FILE_NOT_FOUND)
81                         return Stat();
82                 else
83                         throw system_error("CreateFile", 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         if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
95                 result.type = DIRECTORY;
96         else
97                 result.type = REGULAR;
98
99         result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow;
100         result.alloc_size = (result.size+511)&~511;
101         result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime));
102
103         PSECURITY_DESCRIPTOR sec_desc;
104         PSID owner = 0;
105         PSID group = 0;
106         const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION;
107         DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, 0, 0, &sec_desc);
108         if(err)
109         {
110                 CloseHandle(handle);
111                 throw system_error("GetSecurityInfo", err);
112         }
113
114         result.priv = new Private;
115         result.priv->owner_id = copy_sid(owner);
116         result.priv->group_id = copy_sid(group);
117
118         LocalFree(sec_desc);
119
120         CloseHandle(handle);
121
122         return result;
123 }
124
125 Stat Stat::lstat(const Path &path)
126 {
127         return stat(path);
128 }
129
130 bool exists(const Path &path)
131 {
132         return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES;
133 }
134
135 } // namespace FS
136 } // namespace Msp