-#ifdef WIN32
-#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/systemerror.h>
-#include <msp/strings/format.h>
-#include <msp/time/rawtime_private.h>
#include "path.h"
#include "stat.h"
+#include "stat_private.h"
using namespace std;
-namespace {
-
-#ifdef WIN32
-PSID copy_sid(PSID sid)
-{
- if(!sid || !IsValidSid(sid))
- return 0;
- DWORD len = GetLengthSid(sid);
- PSID copy = reinterpret_cast<PSID>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len));
- if(!CopySid(len, copy, sid))
- {
- DWORD err = GetLastError();
- HeapFree(GetProcessHeap(), 0, copy);
- throw Msp::system_error("CopySid", err);
- }
- return copy;
-}
-
-string get_account_name(PSID sid)
-{
- 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);
-}
-#endif
-
-}
-
-
namespace Msp {
namespace FS {
-struct Stat::Private
-{
-#ifdef WIN32
- PSID owner_id;
- PSID group_id;
-#else
- uid_t owner_id;
- gid_t group_id;
-#endif
-
- Private();
- Private(const Private &);
- ~Private();
-
-#ifndef WIN32
- /* This is here because it needs access to private members of Stat, but we
- can't expose the system stat struct in the public header */
- static Stat from_struct_stat(const struct stat &);
-#endif
-
- void fill_owner_info(Stat::OwnerInfo &);
-};
-
-Stat::Private::Private():
- owner_id(0),
- group_id(0)
-{ }
-
-Stat::Private::Private(const Private &other):
-#ifdef WIN32
- owner_id(copy_sid(other.owner_id)),
- group_id(copy_sid(other.group_id))
-#else
- owner_id(other.owner_id),
- group_id(other.group_id)
-#endif
-{ }
-
-Stat::Private::~Private()
-{
-#ifdef WIN32
- if(owner_id)
- HeapFree(GetProcessHeap(), 0, owner_id);
- if(group_id)
- HeapFree(GetProcessHeap(), 0, group_id);
-#endif
-}
-
-#ifndef WIN32
-Stat Stat::Private::from_struct_stat(const struct stat &st)
-{
- 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);
-
- result.priv = new Private;
- result.priv->owner_id = st.st_uid;
- result.priv->group_id = st.st_gid;
-
- return result;
-}
-#endif
-
-void Stat::Private::fill_owner_info(Stat::OwnerInfo &result)
-{
-#ifdef WIN32
- if(owner_id)
- result.owner = get_account_name(owner_id);
- else
- result.owner = "None";
-
- if(group_id)
- result.group = get_account_name(group_id);
- else
- result.group = "None";
-#else
- char buf[1024];
-
- struct passwd pw;
- struct passwd *owner;
- if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner)
- result.owner = owner->pw_name;
- else
- result.owner = format("%d", owner_id);
-
- struct group gr;
- struct group *group;
- if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group)
- result.group = group->gr_name;
- else
- result.group = format("%d", group_id);
-#endif
-}
-
-
-Stat::Stat():
- exists(false),
- type(UNKNOWN),
- size(0),
- alloc_size(0),
- priv(0)
-{ }
-
Stat::Stat(const Stat &other):
exists(other.exists),
type(other.type),
alloc_size(other.alloc_size),
mtime(other.mtime),
owner_info(other.owner_info),
- priv(other.priv ? new Private(*other.priv) : 0)
+ priv(other.priv ? new Private(*other.priv) : nullptr)
{ }
Stat &Stat::operator=(const Stat &other)
{
+ if(&other==this)
+ return *this;
+
exists = other.exists;
type = other.type;
size = other.size;
mtime = other.mtime;
owner_info = other.owner_info;
delete priv;
- priv = (other.priv ? new Private(*other.priv) : 0);
+ priv = (other.priv ? new Private(*other.priv) : nullptr);
return *this;
}
delete priv;
}
-Stat Stat::stat(const Path &path)
-{
-#ifdef WIN32
- HANDLE handle;
- handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 0);
- if(handle==INVALID_HANDLE_VALUE)
- {
- DWORD err = GetLastError();
- if(err==ERROR_FILE_NOT_FOUND)
- return Stat();
- else
- throw system_error("CreateFile", err);
- }
-
- 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;
- const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION;
- DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, 0, 0, &sec_desc);
- if(err)
- {
- CloseHandle(handle);
- throw system_error("GetSecurityInfo", err);
- }
-
- result.priv = new Private;
- result.priv->owner_id = copy_sid(owner);
- result.priv->group_id = copy_sid(group);
-
- LocalFree(sec_desc);
-
- CloseHandle(handle);
-
- return result;
-#else
- struct stat st;
- 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
-}
-
-const std::string &Stat::get_owner() const
+const string &Stat::get_owner() const
{
if(priv && owner_info.owner.empty())
priv->fill_owner_info(owner_info);
return owner_info.owner;
}
-const std::string &Stat::get_group() const
+const string &Stat::get_group() const
{
if(priv && owner_info.group.empty())
priv->fill_owner_info(owner_info);
return owner_info.group;
}
-Stat Stat::lstat(const Path &path)
-{
-#ifdef WIN32
- return stat(path);
-#else
- struct stat st;
- 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 exists(const Path &path)
-{
-#ifdef WIN32
- return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES;
-#else
- return access(path.str().c_str(), F_OK)==0;
-#endif
-}
-
} // namespace FS
} // namespace Msp