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