]> git.tdb.fi Git - libs/core.git/blob - source/fs/stat.cpp
716a7d6a4f82707587aed2a9b452aa4bde87715c
[libs/core.git] / source / fs / stat.cpp
1 #ifdef WIN32
2 #include <windows.h>
3 #include <aclapi.h>
4 #else
5 #define _FILE_OFFSET_BITS 64
6 #include <cerrno>
7 #include <sys/stat.h>
8 #include <grp.h>
9 #include <pwd.h>
10 #endif
11 #include <msp/core/systemerror.h>
12 #include <msp/strings/format.h>
13 #include <msp/time/rawtime_private.h>
14 #include "path.h"
15 #include "stat.h"
16
17 using namespace std;
18
19 namespace {
20
21 #ifdef WIN32
22 string get_account_name(PSID sid)
23 {
24         char name[1024];
25         DWORD nlen = sizeof(name);
26         char domain[1024];
27         DWORD dlen = sizeof(domain);
28         SID_NAME_USE use;
29         if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use))
30                 throw Msp::system_error("LookupAccountSid");
31         return Msp::format("%s/%s", name, domain);
32 }
33 #endif
34
35 }
36
37
38 namespace Msp {
39 namespace FS {
40
41 #ifndef WIN32
42 struct Stat::Private
43 {
44         static Stat from_struct_stat(const struct stat &);
45 };
46
47 Stat Stat::Private::from_struct_stat(const struct stat &st)
48 {
49         Stat result;
50         result.exists = true;
51         if(S_ISREG(st.st_mode))
52                 result.type = REGULAR;
53         else if(S_ISDIR(st.st_mode))
54                 result.type = DIRECTORY;
55         else if(S_ISLNK(st.st_mode))
56                 result.type = SYMLINK;
57         else
58                 result.type = UNKNOWN;
59         result.size = st.st_size;
60         result.alloc_size = st.st_blocks*512;
61         result.mtime = Time::TimeStamp::from_unixtime(st.st_mtime);
62
63         char buf[1024];
64
65         struct passwd pw;
66         struct passwd *owner;
67         if(!getpwuid_r(st.st_uid, &pw, buf, sizeof(buf), &owner) && owner)
68                 result.owner = owner->pw_name;
69         else
70                 result.owner = format("%d", st.st_uid);
71
72         struct group gr;
73         struct group *group;
74         if(!getgrgid_r(st.st_gid, &gr, buf, sizeof(buf), &group) && group)
75                 result.group = group->gr_name;
76         else
77                 result.group = format("%d", st.st_gid);
78
79         return result;
80 }
81 #endif
82
83 Stat::Stat():
84         exists(false),
85         type(UNKNOWN),
86         size(0),
87         alloc_size(0)
88 { }
89
90 Stat Stat::stat(const Path &path)
91 {
92 #ifdef WIN32
93         HANDLE handle;
94         handle = CreateFile(path.str().c_str(), 0, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
95         if(handle==INVALID_HANDLE_VALUE)
96                 throw system_error("CreateFile");
97
98         BY_HANDLE_FILE_INFORMATION info;
99         if(!GetFileInformationByHandle(handle, &info))
100         {
101                 CloseHandle(handle);
102                 throw system_error("GetFileInformationByHandle");
103         }
104
105         Stat result;
106         if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
107                 result.type = DIRECTORY;
108         else
109                 result.type = REGULAR;
110
111         result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow;
112         result.alloc_size = (result.size+511)&~511;
113         result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime));
114
115         PSECURITY_DESCRIPTOR sec_desc;
116         PSID owner = 0;
117         PSID group = 0;
118         if(!GetSecurityInfo(handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION, &owner, &group, 0, 0, &sec_desc))
119         {
120                 CloseHandle(handle);
121                 throw system_error("GetSecurityInfo");
122         }
123
124         if(owner)
125                 result.owner = get_account_name(owner);
126         if(group)
127                 result.group = get_account_name(group);
128
129         LocalFree(sec_desc);
130
131         CloseHandle(handle);
132
133         return result;
134 #else
135         struct stat st;
136         int ret = ::stat(path.str().c_str(), &st);
137         if(ret==-1)
138         {
139                 if(errno==ENOENT)
140                         return Stat();
141                 else
142                         throw system_error("stat");
143         }
144
145         return Private::from_struct_stat(st);
146 #endif
147 }
148
149 Stat Stat::lstat(const Path &path)
150 {
151 #ifdef WIN32
152         return stat(path);
153 #else
154         struct stat st;
155         int ret = ::lstat(path.str().c_str(), &st);
156         if(ret==-1)
157         {
158                 if(errno==ENOENT)
159                         return Stat();
160                 else
161                         throw system_error("lstat");
162         }
163
164         return Private::from_struct_stat(st);
165 #endif
166 }
167
168 bool exists(const Path &path)
169 {
170 #ifdef WIN32
171         return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES;
172 #else
173         return access(path.str().c_str(), F_OK)==0;
174 #endif
175 }
176
177 } // namespace FS
178 } // namespace Msp