-/* $Id$
-
-This file is part of libmspfs
-Copyright © 2006-2008 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-
-#include <cerrno>
#ifdef WIN32
-#include <io.h>
+#include <windows.h>
+#include <aclapi.h>
+#else
+#define _FILE_OFFSET_BITS 64
+#include <cerrno>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <pwd.h>
#endif
-#include <msp/core/except.h>
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include <msp/time/rawtime_private.h>
#include "path.h"
#include "stat.h"
-namespace Msp {
-namespace FS {
+using namespace std;
-int stat(const Path &fn, struct stat &st)
-{
- return ::stat(fn.str().c_str(), &st);
-}
+namespace {
-struct stat stat(const Path &fn)
+#ifdef WIN32
+string get_account_name(PSID sid)
{
- struct stat st;
- if(stat(fn, st)==-1)
- throw SystemError("stat failed", errno);
- return st;
+ char name[1024];
+ DWORD nlen = sizeof(name);
+ char domain[1024];
+ DWORD dlen = sizeof(domain);
+ SID_NAME_USE use;
+ if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use))
+ throw Msp::system_error("LookupAccountSid");
+ return Msp::format("%s/%s", name, domain);
}
-
-int lstat(const Path &fn, struct stat &st)
-{
-#ifdef WIN32
- return stat(fn, st);
-#else
- return ::lstat(fn.str().c_str(), &st);
#endif
+
}
-struct stat lstat(const Path &fn)
+
+namespace Msp {
+namespace FS {
+
+#ifndef WIN32
+struct Stat::Private
{
- struct stat st;
- if(lstat(fn, st)==-1)
- throw SystemError("lstat failed", errno);
- return st;
-}
+ static Stat from_struct_stat(const struct stat &);
+};
-bool exists(const Path &path)
+Stat Stat::Private::from_struct_stat(const struct stat &st)
{
- return access(path.str().c_str(), F_OK)==0;
+ Stat result;
+ result.exists = true;
+ if(S_ISREG(st.st_mode))
+ result.type = REGULAR;
+ else if(S_ISDIR(st.st_mode))
+ result.type = DIRECTORY;
+ else if(S_ISLNK(st.st_mode))
+ result.type = SYMLINK;
+ else
+ result.type = UNKNOWN;
+ result.size = st.st_size;
+ result.alloc_size = st.st_blocks*512;
+ result.mtime = Time::TimeStamp::from_unixtime(st.st_mtime);
+
+ char buf[1024];
+
+ struct passwd pw;
+ struct passwd *owner;
+ if(!getpwuid_r(st.st_uid, &pw, buf, sizeof(buf), &owner) && owner)
+ result.owner = owner->pw_name;
+ else
+ result.owner = format("%d", st.st_uid);
+
+ struct group gr;
+ struct group *group;
+ if(!getgrgid_r(st.st_gid, &gr, buf, sizeof(buf), &group) && group)
+ result.group = group->gr_name;
+ else
+ result.group = format("%d", st.st_gid);
+
+ return result;
}
+#endif
+
+Stat::Stat():
+ exists(false),
+ type(UNKNOWN),
+ size(0),
+ alloc_size(0)
+{ }
-bool is_reg(const Path &path)
+Stat Stat::stat(const Path &path)
{
+#ifdef WIN32
+ HANDLE handle;
+ handle = CreateFile(path.str().c_str(), 0, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if(handle==INVALID_HANDLE_VALUE)
+ throw system_error("CreateFile");
+
+ BY_HANDLE_FILE_INFORMATION info;
+ if(!GetFileInformationByHandle(handle, &info))
+ {
+ CloseHandle(handle);
+ throw system_error("GetFileInformationByHandle");
+ }
+
+ Stat result;
+ if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
+ result.type = DIRECTORY;
+ else
+ result.type = REGULAR;
+
+ result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow;
+ result.alloc_size = (result.size+511)&~511;
+ result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime));
+
+ PSECURITY_DESCRIPTOR sec_desc;
+ PSID owner = 0;
+ PSID group = 0;
+ if(!GetSecurityInfo(handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION, &owner, &group, 0, 0, &sec_desc))
+ {
+ CloseHandle(handle);
+ throw system_error("GetSecurityInfo");
+ }
+
+ if(owner)
+ result.owner = get_account_name(owner);
+ if(group)
+ result.group = get_account_name(group);
+
+ LocalFree(sec_desc);
+
+ CloseHandle(handle);
+
+ return result;
+#else
struct stat st;
- if(stat(path, st)==0)
- return S_ISREG(st.st_mode);
- return false;
+ int ret = ::stat(path.str().c_str(), &st);
+ if(ret==-1)
+ {
+ if(errno==ENOENT)
+ return Stat();
+ else
+ throw system_error("stat");
+ }
+
+ return Private::from_struct_stat(st);
+#endif
}
-bool is_dir(const Path &path)
+Stat Stat::lstat(const Path &path)
{
+#ifdef WIN32
+ return stat(path);
+#else
struct stat st;
- if(stat(path, st)==0)
- return S_ISDIR(st.st_mode);
- return false;
+ int ret = ::lstat(path.str().c_str(), &st);
+ if(ret==-1)
+ {
+ if(errno==ENOENT)
+ return Stat();
+ else
+ throw system_error("lstat");
+ }
+
+ return Private::from_struct_stat(st);
+#endif
}
-bool is_link(const Path &path)
+bool exists(const Path &path)
{
#ifdef WIN32
- (void)path;
+ return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES;
#else
- struct stat st;
- if(lstat(path, st)==0)
- return S_ISLNK(st.st_mode);
+ return access(path.str().c_str(), F_OK)==0;
#endif
- return false;
}
} // namespace FS