816 lines
21 KiB
C
816 lines
21 KiB
C
/*
|
|
* Copyright (c) 2004-2005, 2007-2008 Hyperic, Inc.
|
|
* Copyright (c) 2009 SpringSource, Inc.
|
|
* Copyright (c) 2010 VMware, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/* ====================================================================
|
|
* The Apache Software License, Version 1.1
|
|
*
|
|
* Copyright (c) 2000-2003 The Apache Software Foundation. All rights
|
|
* reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* 3. The end-user documentation included with the redistribution,
|
|
* if any, must include the following acknowledgment:
|
|
* "This product includes software developed by the
|
|
* Apache Software Foundation (http://www.apache.org/)."
|
|
* Alternately, this acknowledgment may appear in the software itself,
|
|
* if and wherever such third-party acknowledgments normally appear.
|
|
*
|
|
* 4. The names "Apache" and "Apache Software Foundation" must
|
|
* not be used to endorse or promote products derived from this
|
|
* software without prior written permission. For written
|
|
* permission, please contact apache@apache.org.
|
|
*
|
|
* 5. Products derived from this software may not be called "Apache",
|
|
* nor may "Apache" appear in their name, without prior written
|
|
* permission of the Apache Software Foundation.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
* ====================================================================
|
|
*
|
|
* This software consists of voluntary contributions made by many
|
|
* individuals on behalf of the Apache Software Foundation. For more
|
|
* information on the Apache Software Foundation, please see
|
|
* <http://www.apache.org/>.
|
|
*/
|
|
|
|
#ifndef WIN32
|
|
# ifdef _AIX
|
|
# define _LARGE_FILES
|
|
# else
|
|
# define _FILE_OFFSET_BITS 64
|
|
# define _LARGEFILE64_SOURCE
|
|
# endif
|
|
#endif
|
|
|
|
#include "sigar.h"
|
|
|
|
#ifndef WIN32
|
|
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
|
# include <sys/param.h>
|
|
# include <sys/mount.h>
|
|
#else
|
|
# include <sys/statvfs.h>
|
|
# define HAVE_STATVFS
|
|
#endif
|
|
#include <errno.h>
|
|
|
|
#define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1)
|
|
|
|
int sigar_statvfs(sigar_t *sigar,
|
|
const char *dirname,
|
|
sigar_file_system_usage_t *fsusage)
|
|
{
|
|
sigar_uint64_t val, bsize;
|
|
#ifdef HAVE_STATVFS
|
|
struct statvfs buf;
|
|
int status =
|
|
# if defined(__sun) && !defined(_LP64)
|
|
/* http://bugs.opensolaris.org/view_bug.do?bug_id=4462986 */
|
|
statvfs(dirname, (void *)&buf);
|
|
# else
|
|
statvfs(dirname, &buf);
|
|
# endif
|
|
#else
|
|
struct statfs buf;
|
|
int status = statfs(dirname, &buf);
|
|
#endif
|
|
|
|
if (status != 0) {
|
|
return errno;
|
|
}
|
|
|
|
#ifdef HAVE_STATVFS
|
|
bsize = buf.f_frsize / 512;
|
|
#else
|
|
bsize = buf.f_bsize / 512;
|
|
#endif
|
|
val = buf.f_blocks;
|
|
fsusage->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize);
|
|
val = buf.f_bfree;
|
|
fsusage->free = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize);
|
|
val = buf.f_bavail;
|
|
fsusage->avail = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize);
|
|
fsusage->used = fsusage->total - fsusage->free;
|
|
fsusage->files = buf.f_files;
|
|
fsusage->free_files = buf.f_ffree;
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* whittled down version of apr/file_info/{unix,win32}/filestat.c
|
|
* to fillin sigar_fileattrs_t
|
|
*/
|
|
#include "sigar_fileinfo.h"
|
|
#include "sigar_log.h"
|
|
|
|
#ifndef SIGAR_ZERO
|
|
#define SIGAR_ZERO(s) \
|
|
memset(s, '\0', sizeof(*(s)))
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft);
|
|
#else
|
|
#include <string.h>
|
|
#endif
|
|
|
|
static const char* types[] = {
|
|
"none",
|
|
"regular",
|
|
"directory",
|
|
"character device",
|
|
"block device",
|
|
"pipe",
|
|
"symbolic link",
|
|
"socket",
|
|
"unknown"
|
|
};
|
|
|
|
SIGAR_DECLARE(const char *)
|
|
sigar_file_attrs_type_string_get(sigar_file_type_e type)
|
|
{
|
|
if ((type < SIGAR_FILETYPE_NOFILE) ||
|
|
(type > SIGAR_FILETYPE_UNKFILE))
|
|
{
|
|
type = SIGAR_FILETYPE_UNKFILE;
|
|
}
|
|
|
|
return types[type];
|
|
}
|
|
|
|
static const sigar_uint64_t perm_modes[] = {
|
|
SIGAR_UREAD, SIGAR_UWRITE, SIGAR_UEXECUTE,
|
|
SIGAR_GREAD, SIGAR_GWRITE, SIGAR_GEXECUTE,
|
|
SIGAR_WREAD, SIGAR_WWRITE, SIGAR_WEXECUTE
|
|
};
|
|
|
|
static const char perm_chars[] = "rwx";
|
|
|
|
SIGAR_DECLARE(char *)
|
|
sigar_file_attrs_permissions_string_get(sigar_uint64_t permissions,
|
|
char *str)
|
|
{
|
|
char *ptr = str;
|
|
int i=0, j=0;
|
|
|
|
for (i=0; i<9; i+=3) {
|
|
for (j=0; j<3; j++) {
|
|
if (permissions & perm_modes[i+j]) {
|
|
*ptr = perm_chars[j];
|
|
}
|
|
else {
|
|
*ptr = '-';
|
|
}
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
*ptr = '\0';
|
|
return str;
|
|
}
|
|
|
|
static const int perm_int[] = {
|
|
400, 200, 100,
|
|
40, 20, 10,
|
|
4, 2, 1
|
|
};
|
|
|
|
SIGAR_DECLARE(int)sigar_file_attrs_mode_get(sigar_uint64_t permissions)
|
|
{
|
|
int i=0;
|
|
int perms = 0;
|
|
|
|
/* no doubt there is some fancy bitshifting
|
|
* to convert, but this works fine.
|
|
*/
|
|
for (i=0; i<9; i++) {
|
|
if (permissions & perm_modes[i]) {
|
|
perms += perm_int[i];
|
|
}
|
|
}
|
|
|
|
return perms;
|
|
}
|
|
|
|
#define IS_DOTDIR(dir) \
|
|
((dir[0] == '.') && (!dir[1] || ((dir[1] == '.') && !dir[2])))
|
|
|
|
#define DIR_STAT_WARN() \
|
|
sigar_log_printf(sigar, SIGAR_LOG_WARN, \
|
|
"dir_stat: cannot stat `%s': %s", \
|
|
name, \
|
|
sigar_strerror(sigar, status))
|
|
|
|
#if defined(NETWARE)
|
|
|
|
int sigar_dir_stat_get(sigar_t *sigar,
|
|
const char *dir,
|
|
sigar_dir_stat_t *dirstats)
|
|
{
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
int sigar_file_attrs_get(sigar_t *sigar,
|
|
const char *file,
|
|
sigar_file_attrs_t *fileattrs)
|
|
{
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
int sigar_link_attrs_get(sigar_t *sigar,
|
|
const char *file,
|
|
sigar_file_attrs_t *fileattrs)
|
|
{
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
#elif defined(WIN32)
|
|
|
|
#include <accctrl.h>
|
|
#include <aclapi.h>
|
|
|
|
static void fillin_fileattrs(sigar_file_attrs_t *finfo,
|
|
WIN32_FILE_ATTRIBUTE_DATA *wininfo,
|
|
int linkinfo)
|
|
{
|
|
DWORD *sizes = &wininfo->nFileSizeHigh;
|
|
|
|
finfo->atime = sigar_FileTimeToTime(&wininfo->ftLastAccessTime) / 1000;
|
|
finfo->ctime = sigar_FileTimeToTime(&wininfo->ftCreationTime) / 1000;
|
|
finfo->mtime = sigar_FileTimeToTime(&wininfo->ftLastWriteTime) / 1000;
|
|
|
|
finfo->size =
|
|
(sigar_uint64_t)sizes[1] | ((sigar_uint64_t)sizes[0] << 32);
|
|
|
|
if (linkinfo &&
|
|
(wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
|
finfo->type = SIGAR_FILETYPE_LNK;
|
|
}
|
|
else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
finfo->type = SIGAR_FILETYPE_DIR;
|
|
}
|
|
else {
|
|
finfo->type = SIGAR_FILETYPE_REG;
|
|
}
|
|
}
|
|
|
|
static sigar_uint64_t convert_perms(ACCESS_MASK acc, sigar_uint64_t scope)
|
|
{
|
|
sigar_uint64_t perms = 0;
|
|
if (acc & FILE_EXECUTE) {
|
|
perms |= SIGAR_WEXECUTE;
|
|
}
|
|
if (acc & FILE_WRITE_DATA) {
|
|
perms |= SIGAR_WWRITE;
|
|
}
|
|
if (acc & FILE_READ_DATA) {
|
|
perms |= SIGAR_WREAD;
|
|
}
|
|
|
|
return (perms << scope);
|
|
}
|
|
|
|
static int get_security_info(sigar_t *sigar,
|
|
const char *file,
|
|
sigar_file_attrs_t *fileattrs)
|
|
{
|
|
DWORD retval;
|
|
PSID user = NULL, group = NULL, world = NULL;
|
|
PACL dacl = NULL;
|
|
PSECURITY_DESCRIPTOR pdesc = NULL;
|
|
SECURITY_INFORMATION sinfo =
|
|
OWNER_SECURITY_INFORMATION |
|
|
GROUP_SECURITY_INFORMATION |
|
|
DACL_SECURITY_INFORMATION;
|
|
TRUSTEE ident = {NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID};
|
|
ACCESS_MASK acc;
|
|
SID_IDENTIFIER_AUTHORITY auth = SECURITY_WORLD_SID_AUTHORITY;
|
|
|
|
retval = GetNamedSecurityInfo((char *)file,
|
|
SE_FILE_OBJECT,
|
|
sinfo,
|
|
&user,
|
|
&group,
|
|
&dacl,
|
|
NULL,
|
|
&pdesc);
|
|
|
|
if (retval != ERROR_SUCCESS) {
|
|
return retval;
|
|
}
|
|
|
|
if (!AllocateAndInitializeSid(&auth, 1, SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0, &world))
|
|
{
|
|
world = NULL;
|
|
}
|
|
|
|
ident.TrusteeType = TRUSTEE_IS_USER;
|
|
ident.ptstrName = user;
|
|
if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) {
|
|
fileattrs->permissions |= convert_perms(acc, 8);
|
|
}
|
|
|
|
ident.TrusteeType = TRUSTEE_IS_GROUP;
|
|
ident.ptstrName = group;
|
|
if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) {
|
|
fileattrs->permissions |= convert_perms(acc, 4);
|
|
}
|
|
|
|
if (world) {
|
|
ident.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
|
|
ident.ptstrName = world;
|
|
if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) {
|
|
fileattrs->permissions |= convert_perms(acc, 0);
|
|
}
|
|
}
|
|
|
|
if (world) {
|
|
FreeSid(world);
|
|
}
|
|
|
|
LocalFree(pdesc);
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
static int fileattrs_get(sigar_t *sigar,
|
|
const char *file,
|
|
sigar_file_attrs_t *fileattrs,
|
|
int linkinfo)
|
|
{
|
|
BY_HANDLE_FILE_INFORMATION info;
|
|
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
|
HANDLE handle;
|
|
DWORD flags;
|
|
|
|
SIGAR_ZERO(fileattrs);
|
|
|
|
if (!GetFileAttributesExA(file,
|
|
GetFileExInfoStandard,
|
|
&attrs))
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
fillin_fileattrs(fileattrs, &attrs, linkinfo);
|
|
|
|
flags = fileattrs->type == SIGAR_FILETYPE_DIR ?
|
|
FILE_FLAG_BACKUP_SEMANTICS :
|
|
FILE_ATTRIBUTE_NORMAL;
|
|
|
|
/**
|
|
* We need to set dwDesiredAccess to 0 to work in cases where GENERIC_READ can fail.
|
|
*
|
|
* see: http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
|
|
*/
|
|
handle = CreateFile(file,
|
|
0,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
flags,
|
|
NULL);
|
|
|
|
if (handle != INVALID_HANDLE_VALUE) {
|
|
if (GetFileInformationByHandle(handle, &info)) {
|
|
fileattrs->inode =
|
|
info.nFileIndexLow |
|
|
(info.nFileIndexHigh << 32);
|
|
fileattrs->device = info.dwVolumeSerialNumber;
|
|
fileattrs->nlink = info.nNumberOfLinks;
|
|
}
|
|
CloseHandle(handle);
|
|
}
|
|
|
|
get_security_info(sigar, file, fileattrs);
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
SIGAR_DECLARE(int) sigar_file_attrs_get(sigar_t *sigar,
|
|
const char *file,
|
|
sigar_file_attrs_t *fileattrs)
|
|
{
|
|
return fileattrs_get(sigar, file, fileattrs, 0);
|
|
}
|
|
|
|
SIGAR_DECLARE(int) sigar_link_attrs_get(sigar_t *sigar,
|
|
const char *file,
|
|
sigar_file_attrs_t *fileattrs)
|
|
{
|
|
return fileattrs_get(sigar, file, fileattrs, 1);
|
|
}
|
|
|
|
static __inline int file_type(char *file)
|
|
{
|
|
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
|
|
|
if (!GetFileAttributesExA(file,
|
|
GetFileExInfoStandard,
|
|
&attrs))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (attrs.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
|
return SIGAR_FILETYPE_LNK;
|
|
}
|
|
else if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
return SIGAR_FILETYPE_DIR;
|
|
}
|
|
else {
|
|
return SIGAR_FILETYPE_REG;
|
|
}
|
|
}
|
|
|
|
static int dir_stat_get(sigar_t *sigar,
|
|
const char *dir,
|
|
sigar_dir_stat_t *dirstats,
|
|
int recurse)
|
|
{
|
|
int status;
|
|
char name[SIGAR_PATH_MAX+1];
|
|
int len = strlen(dir);
|
|
int max = sizeof(name)-len-1;
|
|
char *ptr = name;
|
|
WIN32_FIND_DATA data;
|
|
HANDLE handle;
|
|
DWORD error;
|
|
char delim;
|
|
|
|
if (file_type((char *)dir) != SIGAR_FILETYPE_DIR) {
|
|
return ERROR_NO_MORE_FILES;
|
|
}
|
|
|
|
strncpy(name, dir, sizeof(name));
|
|
ptr += len;
|
|
if (strchr(dir, '/')) {
|
|
delim = '/';
|
|
}
|
|
else {
|
|
delim = '\\';
|
|
}
|
|
if (name[len] != delim) {
|
|
*ptr++ = delim;
|
|
len++;
|
|
max--;
|
|
}
|
|
|
|
/* e.g. "C:\sigar\*" */
|
|
name[len] = '*';
|
|
name[len+1] = '\0';
|
|
|
|
handle = FindFirstFile(name, &data);
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
return GetLastError();
|
|
}
|
|
|
|
do {
|
|
/* skip '.' and '..' */
|
|
if (IS_DOTDIR(data.cFileName)) {
|
|
continue;
|
|
}
|
|
|
|
dirstats->disk_usage +=
|
|
(data.nFileSizeHigh * (MAXDWORD+1)) +
|
|
data.nFileSizeLow;
|
|
|
|
/* e.g. "C:\sigar\lib" */
|
|
strncpy(ptr, data.cFileName, max);
|
|
ptr[max] = '\0';
|
|
|
|
switch (file_type(name)) {
|
|
case -1:
|
|
break;
|
|
case SIGAR_FILETYPE_REG:
|
|
++dirstats->files;
|
|
break;
|
|
case SIGAR_FILETYPE_DIR:
|
|
++dirstats->subdirs;
|
|
if (recurse) {
|
|
status =
|
|
dir_stat_get(sigar, name,
|
|
dirstats, recurse);
|
|
if (status != SIGAR_OK) {
|
|
DIR_STAT_WARN();
|
|
}
|
|
}
|
|
break;
|
|
case SIGAR_FILETYPE_LNK:
|
|
++dirstats->symlinks;
|
|
break;
|
|
case SIGAR_FILETYPE_CHR:
|
|
++dirstats->chrdevs;
|
|
break;
|
|
case SIGAR_FILETYPE_BLK:
|
|
++dirstats->blkdevs;
|
|
break;
|
|
case SIGAR_FILETYPE_SOCK:
|
|
++dirstats->sockets;
|
|
break;
|
|
default:
|
|
++dirstats->total;
|
|
}
|
|
} while (FindNextFile(handle, &data));
|
|
|
|
error = GetLastError();
|
|
|
|
FindClose(handle);
|
|
|
|
if (error != ERROR_NO_MORE_FILES) {
|
|
return error;
|
|
}
|
|
|
|
dirstats->total =
|
|
dirstats->files +
|
|
dirstats->subdirs +
|
|
dirstats->symlinks +
|
|
dirstats->chrdevs +
|
|
dirstats->blkdevs +
|
|
dirstats->sockets;
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#else
|
|
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
static sigar_file_type_e filetype_from_mode(mode_t mode)
|
|
{
|
|
sigar_file_type_e type;
|
|
|
|
switch (mode & S_IFMT) {
|
|
case S_IFREG:
|
|
type = SIGAR_FILETYPE_REG; break;
|
|
case S_IFDIR:
|
|
type = SIGAR_FILETYPE_DIR; break;
|
|
case S_IFLNK:
|
|
type = SIGAR_FILETYPE_LNK; break;
|
|
case S_IFCHR:
|
|
type = SIGAR_FILETYPE_CHR; break;
|
|
case S_IFBLK:
|
|
type = SIGAR_FILETYPE_BLK; break;
|
|
#if defined(S_IFFIFO)
|
|
case S_IFFIFO:
|
|
type = SIGAR_FILETYPE_PIPE; break;
|
|
#endif
|
|
#if !defined(BEOS) && defined(S_IFSOCK)
|
|
case S_IFSOCK:
|
|
type = SIGAR_FILETYPE_SOCK; break;
|
|
#endif
|
|
|
|
default:
|
|
/* Work around missing S_IFxxx values above
|
|
* for Linux et al.
|
|
*/
|
|
#if !defined(S_IFFIFO) && defined(S_ISFIFO)
|
|
if (S_ISFIFO(mode)) {
|
|
type = SIGAR_FILETYPE_PIPE;
|
|
} else
|
|
#endif
|
|
#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK)
|
|
if (S_ISSOCK(mode)) {
|
|
type = SIGAR_FILETYPE_SOCK;
|
|
} else
|
|
#endif
|
|
type = SIGAR_FILETYPE_UNKFILE;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
static sigar_uint64_t sigar_unix_mode2perms(mode_t mode)
|
|
{
|
|
sigar_uint64_t perms = 0;
|
|
|
|
if (mode & S_IRUSR)
|
|
perms |= SIGAR_UREAD;
|
|
if (mode & S_IWUSR)
|
|
perms |= SIGAR_UWRITE;
|
|
if (mode & S_IXUSR)
|
|
perms |= SIGAR_UEXECUTE;
|
|
|
|
if (mode & S_IRGRP)
|
|
perms |= SIGAR_GREAD;
|
|
if (mode & S_IWGRP)
|
|
perms |= SIGAR_GWRITE;
|
|
if (mode & S_IXGRP)
|
|
perms |= SIGAR_GEXECUTE;
|
|
|
|
if (mode & S_IROTH)
|
|
perms |= SIGAR_WREAD;
|
|
if (mode & S_IWOTH)
|
|
perms |= SIGAR_WWRITE;
|
|
if (mode & S_IXOTH)
|
|
perms |= SIGAR_WEXECUTE;
|
|
|
|
return perms;
|
|
}
|
|
|
|
static void copy_stat_info(sigar_file_attrs_t *fileattrs,
|
|
struct stat *info)
|
|
{
|
|
fileattrs->permissions = sigar_unix_mode2perms(info->st_mode);
|
|
fileattrs->type = filetype_from_mode(info->st_mode);
|
|
fileattrs->uid = info->st_uid;
|
|
fileattrs->gid = info->st_gid;
|
|
fileattrs->size = info->st_size;
|
|
fileattrs->inode = info->st_ino;
|
|
fileattrs->device = info->st_dev;
|
|
fileattrs->nlink = info->st_nlink;
|
|
fileattrs->atime = info->st_atime;
|
|
fileattrs->mtime = info->st_mtime;
|
|
fileattrs->ctime = info->st_ctime;
|
|
fileattrs->atime *= 1000;
|
|
fileattrs->mtime *= 1000;
|
|
fileattrs->ctime *= 1000;
|
|
}
|
|
|
|
int sigar_file_attrs_get(sigar_t *sigar,
|
|
const char *file,
|
|
sigar_file_attrs_t *fileattrs)
|
|
{
|
|
struct stat info;
|
|
|
|
if (stat(file, &info) == 0) {
|
|
copy_stat_info(fileattrs, &info);
|
|
return SIGAR_OK;
|
|
}
|
|
else {
|
|
return errno;
|
|
}
|
|
}
|
|
|
|
int sigar_link_attrs_get(sigar_t *sigar,
|
|
const char *file,
|
|
sigar_file_attrs_t *fileattrs)
|
|
{
|
|
struct stat info;
|
|
|
|
if (lstat(file, &info) == 0) {
|
|
copy_stat_info(fileattrs, &info);
|
|
return SIGAR_OK;
|
|
}
|
|
else {
|
|
return errno;
|
|
}
|
|
}
|
|
|
|
static int dir_stat_get(sigar_t *sigar,
|
|
const char *dir,
|
|
sigar_dir_stat_t *dirstats,
|
|
int recurse)
|
|
{
|
|
int status;
|
|
char name[SIGAR_PATH_MAX+1];
|
|
int len = strlen(dir);
|
|
int max = sizeof(name)-len-1;
|
|
char *ptr = name;
|
|
DIR *dirp = opendir(dir);
|
|
struct dirent *ent;
|
|
struct stat info;
|
|
#ifdef HAVE_READDIR_R
|
|
struct dirent dbuf;
|
|
#endif
|
|
|
|
if (!dirp) {
|
|
return errno;
|
|
}
|
|
|
|
strncpy(name, dir, sizeof(name));
|
|
ptr += len;
|
|
if (name[len] != '/') {
|
|
*ptr++ = '/';
|
|
len++;
|
|
max--;
|
|
}
|
|
|
|
#ifdef HAVE_READDIR_R
|
|
while (readdir_r(dirp, &dbuf, &ent) == 0) {
|
|
if (ent == NULL) {
|
|
break;
|
|
}
|
|
#else
|
|
while ((ent = readdir(dirp))) {
|
|
#endif
|
|
/* skip '.' and '..' */
|
|
if (IS_DOTDIR(ent->d_name)) {
|
|
continue;
|
|
}
|
|
|
|
strncpy(ptr, ent->d_name, max);
|
|
ptr[max] = '\0';
|
|
|
|
if (lstat(name, &info) != 0) {
|
|
continue;
|
|
}
|
|
|
|
dirstats->disk_usage += info.st_size;
|
|
|
|
switch (filetype_from_mode(info.st_mode)) {
|
|
case SIGAR_FILETYPE_REG:
|
|
++dirstats->files;
|
|
break;
|
|
case SIGAR_FILETYPE_DIR:
|
|
++dirstats->subdirs;
|
|
if (recurse) {
|
|
status =
|
|
dir_stat_get(sigar, name,
|
|
dirstats, recurse);
|
|
if (status != SIGAR_OK) {
|
|
DIR_STAT_WARN();
|
|
}
|
|
}
|
|
break;
|
|
case SIGAR_FILETYPE_LNK:
|
|
++dirstats->symlinks;
|
|
break;
|
|
case SIGAR_FILETYPE_CHR:
|
|
++dirstats->chrdevs;
|
|
break;
|
|
case SIGAR_FILETYPE_BLK:
|
|
++dirstats->blkdevs;
|
|
break;
|
|
case SIGAR_FILETYPE_SOCK:
|
|
++dirstats->sockets;
|
|
break;
|
|
default:
|
|
++dirstats->total;
|
|
}
|
|
}
|
|
|
|
dirstats->total =
|
|
dirstats->files +
|
|
dirstats->subdirs +
|
|
dirstats->symlinks +
|
|
dirstats->chrdevs +
|
|
dirstats->blkdevs +
|
|
dirstats->sockets;
|
|
|
|
closedir(dirp);
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
SIGAR_DECLARE(int) sigar_dir_stat_get(sigar_t *sigar,
|
|
const char *dir,
|
|
sigar_dir_stat_t *dirstats)
|
|
{
|
|
SIGAR_ZERO(dirstats);
|
|
return dir_stat_get(sigar, dir, dirstats, 0);
|
|
}
|
|
|
|
SIGAR_DECLARE(int) sigar_dir_usage_get(sigar_t *sigar,
|
|
const char *dir,
|
|
sigar_dir_usage_t *dirusage)
|
|
{
|
|
SIGAR_ZERO(dirusage);
|
|
return dir_stat_get(sigar, dir, dirusage, 1);
|
|
}
|