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