5 #define _FILE_OFFSET_BITS 64
12 #include <msp/core/systemerror.h>
13 #include <msp/strings/format.h>
14 #include <msp/time/rawtime_private.h>
23 PSID copy_sid(PSID sid)
25 if(!sid || !IsValidSid(sid))
27 DWORD len = GetLengthSid(sid);
28 PSID copy = reinterpret_cast<PSID>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len));
29 if(!CopySid(len, copy, sid))
31 DWORD err = GetLastError();
32 HeapFree(GetProcessHeap(), 0, copy);
33 throw Msp::system_error("CopySid", err);
38 string get_account_name(PSID sid)
41 DWORD nlen = sizeof(name);
43 DWORD dlen = sizeof(domain);
45 if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use))
46 throw Msp::system_error("LookupAccountSid");
47 return Msp::format("%s/%s", name, domain);
68 Private(const Private &);
72 /* This is here because it needs access to private members of Stat, but we
73 can't expose the system stat struct in the public header */
74 static Stat from_struct_stat(const struct stat &);
77 void fill_owner_info(Stat::OwnerInfo &);
80 Stat::Private::Private():
85 Stat::Private::Private(const Private &other):
87 owner_id(copy_sid(other.owner_id)),
88 group_id(copy_sid(other.group_id))
90 owner_id(other.owner_id),
91 group_id(other.group_id)
95 Stat::Private::~Private()
99 HeapFree(GetProcessHeap(), 0, owner_id);
101 HeapFree(GetProcessHeap(), 0, group_id);
106 Stat Stat::Private::from_struct_stat(const struct stat &st)
109 result.exists = true;
110 if(S_ISREG(st.st_mode))
111 result.type = REGULAR;
112 else if(S_ISDIR(st.st_mode))
113 result.type = DIRECTORY;
114 else if(S_ISLNK(st.st_mode))
115 result.type = SYMLINK;
117 result.type = UNKNOWN;
118 result.size = st.st_size;
119 result.alloc_size = st.st_blocks*512;
120 result.mtime = Time::TimeStamp::from_unixtime(st.st_mtime);
122 result.priv = new Private;
123 result.priv->owner_id = st.st_uid;
124 result.priv->group_id = st.st_gid;
130 void Stat::Private::fill_owner_info(Stat::OwnerInfo &result)
134 result.owner = get_account_name(owner_id);
136 result.owner = "None";
139 result.group = get_account_name(group_id);
141 result.group = "None";
146 struct passwd *owner;
147 if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner)
148 result.owner = owner->pw_name;
150 result.owner = format("%d", owner_id);
154 if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group)
155 result.group = group->gr_name;
157 result.group = format("%d", group_id);
170 Stat::Stat(const Stat &other):
171 exists(other.exists),
174 alloc_size(other.alloc_size),
176 owner_info(other.owner_info),
177 priv(other.priv ? new Private(*other.priv) : 0)
180 Stat &Stat::operator=(const Stat &other)
182 exists = other.exists;
185 alloc_size = other.alloc_size;
187 owner_info = other.owner_info;
189 priv = (other.priv ? new Private(*other.priv) : 0);
199 Stat Stat::stat(const Path &path)
203 handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 0);
204 if(handle==INVALID_HANDLE_VALUE)
206 DWORD err = GetLastError();
207 if(err==ERROR_FILE_NOT_FOUND)
210 throw system_error("CreateFile", err);
213 BY_HANDLE_FILE_INFORMATION info;
214 if(!GetFileInformationByHandle(handle, &info))
217 throw system_error("GetFileInformationByHandle");
221 if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
222 result.type = DIRECTORY;
224 result.type = REGULAR;
226 result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow;
227 result.alloc_size = (result.size+511)&~511;
228 result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime));
230 PSECURITY_DESCRIPTOR sec_desc;
233 const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION;
234 DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, 0, 0, &sec_desc);
238 throw system_error("GetSecurityInfo", err);
241 result.priv = new Private;
242 result.priv->owner_id = copy_sid(owner);
243 result.priv->group_id = copy_sid(group);
252 int ret = ::stat(path.str().c_str(), &st);
258 throw system_error("stat");
261 return Private::from_struct_stat(st);
265 const std::string &Stat::get_owner() const
267 if(priv && owner_info.owner.empty())
268 priv->fill_owner_info(owner_info);
269 return owner_info.owner;
272 const std::string &Stat::get_group() const
274 if(priv && owner_info.group.empty())
275 priv->fill_owner_info(owner_info);
276 return owner_info.group;
279 Stat Stat::lstat(const Path &path)
285 int ret = ::lstat(path.str().c_str(), &st);
291 throw system_error("lstat");
294 return Private::from_struct_stat(st);
298 bool exists(const Path &path)
301 return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES;
303 return access(path.str().c_str(), F_OK)==0;