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];
namespace Msp {
namespace FS {
-#ifndef WIN32
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.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(st.st_uid, &pw, buf, sizeof(buf), &owner) && owner)
+ if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner)
result.owner = owner->pw_name;
else
- result.owner = format("%d", st.st_uid);
+ result.owner = format("%d", owner_id);
struct group gr;
struct group *group;
- if(!getgrgid_r(st.st_gid, &gr, buf, sizeof(buf), &group) && group)
+ if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group)
result.group = group->gr_name;
else
- result.group = format("%d", st.st_gid);
-
- return result;
-}
+ result.group = format("%d", group_id);
#endif
+}
+
Stat::Stat():
exists(false),
type(UNKNOWN),
size(0),
- alloc_size(0)
+ alloc_size(0),
+ priv(0)
{ }
+Stat::Stat(const Stat &other):
+ exists(other.exists),
+ type(other.type),
+ size(other.type),
+ alloc_size(other.alloc_size),
+ mtime(other.mtime),
+ owner_info(other.owner_info),
+ priv(other.priv ? new Private(*other.priv) : 0)
+{ }
+
+Stat &Stat::operator=(const Stat &other)
+{
+ exists = other.exists;
+ type = other.type;
+ size = other.size;
+ alloc_size = other.alloc_size;
+ mtime = other.mtime;
+ owner_info = other.owner_info;
+ delete priv;
+ priv = (other.priv ? new Private(*other.priv) : 0);
+
+ return *this;
+}
+
+Stat::~Stat()
+{
+ delete priv;
+}
+
Stat Stat::stat(const Path &path)
{
#ifdef WIN32
throw system_error("GetSecurityInfo", err);
}
- if(owner)
- result.owner = get_account_name(owner);
- if(group)
- result.group = get_account_name(group);
+ result.priv = new Private;
+ result.priv->owner_id = copy_sid(owner);
+ result.priv->group_id = copy_sid(group);
LocalFree(sec_desc);
#endif
}
+const std::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
+{
+ if(priv && owner_info.group.empty())
+ priv->fill_owner_info(owner_info);
+ return owner_info.group;
+}
+
Stat Stat::lstat(const Path &path)
{
#ifdef WIN32