X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=blobdiff_plain;f=source%2Ffs%2Fstat.cpp;h=77564f0ecd2d6c49b3297db2733686423de870bb;hp=1dc46db78289dce316ffb36bee60b3a9539066e2;hb=330373a422c3b75d117e1a0eed72ca868bccb5b9;hpb=af94bc926e301e9b871dc18662b4fa6e5614fdbf diff --git a/source/fs/stat.cpp b/source/fs/stat.cpp index 1dc46db..77564f0 100644 --- a/source/fs/stat.cpp +++ b/source/fs/stat.cpp @@ -1,82 +1,186 @@ -/* $Id$ - -This file is part of libmspfs -Copyright © 2006-2008 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include #ifdef WIN32 -#include +#include +#include +#else +#define _FILE_OFFSET_BITS 64 +#include +#include +#include +#include +#include #endif -#include +#include +#include +#include #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(), 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); + } + + 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