enhanded qse_dir_read()

This commit is contained in:
hyung-hwan 2011-10-28 01:05:19 +00:00
parent 1b600ee20c
commit e5a9693411
8 changed files with 336 additions and 77 deletions

View File

@ -34,7 +34,7 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = .
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/README.in \
$(top_srcdir)/configure ac/config.guess ac/config.sub \
ac/depcomp ac/install-sh ac/ltmain.sh ac/missing

30
qse/configure vendored
View File

@ -15745,6 +15745,36 @@ _ACEOF
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtime" "ac_cv_member_struct_stat_st_birthtime" "$ac_includes_default"
if test "x$ac_cv_member_struct_stat_st_birthtime" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
_ACEOF
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim.tv_nsec" "ac_cv_member_struct_stat_st_mtim_tv_nsec" "$ac_includes_default"
if test "x$ac_cv_member_struct_stat_st_mtim_tv_nsec" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1
_ACEOF
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimespec.tv_nsec" "ac_cv_member_struct_stat_st_mtimespec_tv_nsec" "$ac_includes_default"
if test "x$ac_cv_member_struct_stat_st_mtimespec_tv_nsec" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
_ACEOF
fi
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects

View File

@ -109,6 +109,9 @@ AC_CHECK_FUNCS([powf fmodf sinf cosf tanf atanf atan2f logf expf sqrtf])
LIBS="$OLDLIBS"
AC_STRUCT_DIRENT_D_TYPE
AC_CHECK_MEMBERS([struct stat.st_birthtime])
AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec])
AC_CHECK_MEMBERS([struct stat.st_mtimespec.tv_nsec])
dnl check the size of primitive data types
AC_CHECK_SIZEOF(char,,[[]])

View File

@ -53,12 +53,16 @@
#define QSE_USECS_PER_MSEC (1000)
#define QSE_NSECS_PER_USEC (1000)
#define QSE_NSECS_PER_MSEC (QSE_NSECS_PER_USEC*QSE_USECS_PER_MSEC)
#define QSE_USECS_PER_SEC (QSE_USECS_PER_MSEC*QSE_MSECS_PER_SEC)
#define QSE_IS_LEAPYEAR(year) ((!((year)%4) && ((year)%100)) || !((year)%400))
#define QSE_DAYS_PER_YEAR(year) \
(QSE_IS_LEAPYEAR(year)? QSE_DAYS_PER_LEAPYEAR: QSE_DAYS_PER_NORMYEAR)
#define QSE_SECNSEC_TO_MSEC(sec,nsec) \
(((qse_ntime_t)(sec) * QSE_MSECS_PER_SEC) + ((qse_ntime_t)(nsec) / QSE_NSECS_PER_MSEC))
/* number of milliseconds since the Epoch (00:00:00 UTC, Jan 1, 1970) */
typedef qse_long_t qse_ntime_t;
typedef struct qse_btime_t qse_btime_t;
@ -95,7 +99,6 @@ int qse_gettime (
int qse_settime (
qse_ntime_t nt
);
/******/
/**
@ -137,7 +140,7 @@ int qse_timelocal (
* The qse_strftime() functions formats time.
*/
qse_size_t qse_strftime (
qse_char_t* buf,
qse_char_t* buf,
qse_size_t size,
const qse_char_t* fmt,
qse_btime_t* bt

View File

@ -178,6 +178,15 @@
/* Define to 1 if `d_type' is a member of `struct dirent'. */
#undef HAVE_STRUCT_DIRENT_D_TYPE
/* Define to 1 if `st_birthtime' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BIRTHTIME
/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
/* Define to 1 if you have the `sysconf' function. */
#undef HAVE_SYSCONF

View File

@ -23,6 +23,7 @@
#include <qse/types.h>
#include <qse/macros.h>
#include <qse/cmn/time.h>
enum qse_dir_errnum_t
{
@ -38,20 +39,46 @@ enum qse_dir_errnum_t
};
typedef enum qse_dir_errnum_t qse_dir_errnum_t;
enum qse_dir_ent_flag_t
{
QSE_DIR_ENT_NAME = (1 << 0),
QSE_DIR_ENT_TYPE = (1 << 1),
QSE_DIR_ENT_SIZE = (1 << 2),
QSE_DIR_ENT_TIME = (1 << 3)
};
enum qse_dir_ent_type_t
{
QSE_DIR_ENT_UNKNOWN,
QSE_DIR_ENT_SUBDIR,
QSE_DIR_ENT_REGULAR,
QSE_DIR_ENT_CHRDEV,
QSE_DIR_ENT_BLKDEV,
QSE_DIR_ENT_SYMLINK,
QSE_DIR_ENT_PIPE
};
typedef enum qse_dir_ent_type_t qse_dir_ent_type_t;
struct qse_dir_ent_t
{
enum
int flags;
struct
{
QSE_DIR_ENT_UNKNOWN,
QSE_DIR_ENT_DIR,
QSE_DIR_ENT_REG,
QSE_DIR_ENT_FIFO,
QSE_DIR_ENT_CHAR,
QSE_DIR_ENT_BLOCK,
QSE_DIR_ENT_LINK
} type;
qse_char_t* name;
qse_foff_t size;
qse_char_t* base;
qse_char_t* path;
} name;
qse_dir_ent_type_t type;
qse_foff_t size;
struct
{
qse_ntime_t create;
qse_ntime_t access;
qse_ntime_t modify;
qse_ntime_t change; /* inode status change */
} time;
};
typedef struct qse_dir_ent_t qse_dir_ent_t;
@ -70,10 +97,10 @@ typedef struct qse_dir_t qse_dir_t;
enum qse_dir_option_t
{
/**< don't follow a symbolic link in qse_dir_change() */
QSE_DIR_NOFOLLOW = (1 << 0),
QSE_DIR_NOFOLLOW = (1 << 1),
/**< check directories against file system in qse_dir_change() */
QSE_DIR_REALPATH = (1 << 1)
QSE_DIR_REALPATH = (1 << 2)
};
#ifdef __cplusplus
@ -109,7 +136,8 @@ const qse_char_t* qse_dir_geterrmsg (
);
qse_dir_ent_t* qse_dir_read (
qse_dir_t* dir
qse_dir_t* dir,
int flags
);
int qse_dir_change (

View File

@ -415,11 +415,35 @@ static int set_entry_name (qse_dir_t* dir, const qse_mchar_t* name)
len++;
qse_mbstowcs (name, info->name.ptr, &len);
#endif
dir->ent.name = info->name.ptr;
dir->ent.name.base = info->name.ptr;
dir->ent.flags |= QSE_DIR_ENT_NAME;
return 0;
}
qse_dir_ent_t* qse_dir_read (qse_dir_t* dir)
#if defined(_WIN32)
static QSE_INLINE qse_ntime_t filetime_to_ntime (const FILETIME* ft)
{
/* reverse of http://support.microsoft.com/kb/167296/en-us */
ULARGE_INTEGER li;
li.LowPart = ft->dwLowDateTime;
li.HighPart = ft->dwHighDateTime;
#if (QSE_SIZEOF_LONG_LONG>=8)
li.QuadPart -= 116444736000000000ull;
#elif (QSE_SIZEOF___INT64>=8)
li.QuadPart -= 116444736000000000ui64;
#else
# error Unsupported 64bit integer type
#endif
/*li.QuadPart /= 10000000;*/
li.QuadPart /= 10000;
return li.QuadPart;
}
#endif
qse_dir_ent_t* qse_dir_read (qse_dir_t* dir, int flags)
{
#if defined(_WIN32)
info_t* info;
@ -455,26 +479,93 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir)
/* call set_entry_name before changing other fields
* in dir->ent not to pollute it in case set_entry_name fails */
QSE_MEMSET (&dir->ent, 0, QSE_SIZEOF(dir->ent));
if (set_entry_name (dir, info->wfd.cFileName) <= -1) return QSE_NULL;
if (info->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
if (flags & QSE_DIR_ENT_TYPE)
{
dir->ent.size = 0;
dir->ent.type = QSE_DIR_ENT_DIRECTORY;
if (info->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
dir->ent.type = QSE_DIR_ENT_SUBDIR;
}
else if ((info->wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
(info->wfd.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
{
dir->ent.type = QSE_DIR_ENT_SYMLINK;
}
else
{
HANDLE h;
qse_char_t* tmp_name[4];
qse_char_t* fname;
/* TODO: use a buffer in info... instead of allocating an deallocating every time */
tmp_name[0] = dir->curdir;
tmp_name[1] = QSE_T("\\");
tmp_name[2] = info->wfd.cFileName;
tmp_name[3] = QSE_NULL;
fname = qse_stradup (tmp_name, dir->mmgr);
if (fname == QSE_NULL)
{
dir->errnum = QSE_DIR_ENOMEM;
return QSE_NULL;
}
h = CreateFile (
fname,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
QSE_NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
);
QSE_MMGR_FREE (dir->mmgr, fname);
if (h != INVALID_HANDLE_VALUE)
{
DWORD t = GetFileType (h);
switch (t)
{
case FILE_TYPE_CHAR:
dir->ent.type = QSE_DIR_ENT_CHRDEV;
break;
case FILE_TYPE_DISK:
dir->ent.type = QSE_DIR_ENT_BLKDEV;
break;
case FILE_TYPE_PIPE:
dir->ent.type = QSE_DIR_ENT_PIPE;
break;
default:
dir->ent.type = QSE_DIR_ENT_UNKNOWN;
break;
}
CloseHandle (h);
}
else
{
dir->ent.type = QSE_DIR_ENT_UNKNOWN;
}
}
dir->ent.type |= QSE_DIR_ENT_TYPE;
}
else if ((info->wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
(info->wfd.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
if (flags & QSE_DIR_ENT_SIZE)
{
dir->ent.size = 0;
dir->ent.type = QSE_DIR_ENT_LINK;
}
else
{
LARGE_INTEGER li;
ULARGE_INTEGER li;
li.LowPart = info->wfd.nFileSizeLow;
li.HighPart = info->wfd.nFileSizeHigh;
dir->ent.size = li.QuadPart;
dir->ent.type = QSE_DIR_ENT_UNKNOWN;
dir->ent.type |= QSE_DIR_ENT_SIZE;
}
if (flags & QSE_DIR_ENT_TIME)
{
dir->ent.time.create = filetime_to_ntime (&info->wfd.ftCreationTime);
dir->ent.time.access = filetime_to_ntime (&info->wfd.ftLastAccessTime);
dir->ent.time.modify = filetime_to_ntime (&info->wfd.ftLastWriteTime);
dir->ent.type |= QSE_DIR_ENT_TIME;
}
#elif defined(__OS2__)
@ -486,13 +577,13 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir)
info_t* info;
struct dirent* ent;
int x;
#if defined(QSE_LSTAT64)
int stat_needed;
#if defined(QSE_LSTAT64)
struct stat64 st;
#else
#else
struct stat st;
#endif
qse_mchar_t* tmp_name[4];
qse_mchar_t* mfname;
#endif
info = dir->info;
if (info == QSE_NULL)
@ -509,48 +600,138 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir)
return QSE_NULL;
}
#if defined(HAVE_STRUCT_DIRENT_D_TYPE)
/* end->d_type */
#endif
/* TODO: use a buffer in info... instead of allocating an deallocating every time */
tmp_name[0] = info->mcurdir;
tmp_name[1] = QSE_MT("/");
tmp_name[2] = ent->d_name;
tmp_name[3] = QSE_NULL;
mfname = qse_mbsadup (tmp_name, dir->mmgr);
if (mfname == QSE_NULL)
{
dir->errnum = QSE_DIR_ENOMEM;
return QSE_NULL;
}
#if defined(QSE_LSTAT64)
x = QSE_LSTAT64 (mfname, &st);
#else
x = QSE_LSTAT (mfname, &st);
#endif
QSE_MMGR_FREE (dir->mmgr, mfname);
if (x == -1)
{
dir->errnum = syserr_to_errnum (errno);
return QSE_NULL;
}
QSE_MEMSET (&dir->ent, 0, QSE_SIZEOF(dir->ent));
if (set_entry_name (dir, ent->d_name) <= -1) return QSE_NULL;
stat_needed =
#if !defined(HAVE_STRUCT_DIRENT_D_TYPE)
(flags & QSE_DIR_ENT_TYPE) ||
#endif
(flags & QSE_DIR_ENT_SIZE) ||
(flags & QSE_DIR_ENT_TIME);
if (stat_needed)
{
qse_mchar_t* tmp_name[4];
qse_mchar_t* mfname;
dir->ent.size = st.st_size;
/* TODO: use a buffer in info... instead of allocating an deallocating every time */
tmp_name[0] = info->mcurdir;
tmp_name[1] = QSE_MT("/");
tmp_name[2] = ent->d_name;
tmp_name[3] = QSE_NULL;
mfname = qse_mbsadup (tmp_name, dir->mmgr);
if (mfname == QSE_NULL)
{
dir->errnum = QSE_DIR_ENOMEM;
return QSE_NULL;
}
#if defined(QSE_LSTAT64)
x = QSE_LSTAT64 (mfname, &st);
#else
x = QSE_LSTAT (mfname, &st);
#endif
QSE_MMGR_FREE (dir->mmgr, mfname);
#define IS_TYPE(st,type) ((st.st_mode & S_IFMT) == S_IFDIR)
dir->ent.type = IS_TYPE(st,S_IFDIR)? QSE_DIR_ENT_DIR:
IS_TYPE(st,S_IFCHR)? QSE_DIR_ENT_CHAR:
IS_TYPE(st,S_IFBLK)? QSE_DIR_ENT_BLOCK:
QSE_DIR_ENT_UNKNOWN;
if (x == -1)
{
dir->errnum = syserr_to_errnum (errno);
return QSE_NULL;
}
}
if (flags & QSE_DIR_ENT_TYPE)
{
#if defined(HAVE_STRUCT_DIRENT_D_TYPE)
switch (ent->d_type)
{
case DT_DIR:
dir->ent.type = QSE_DIR_ENT_SUBDIR;
break;
case DT_REG:
dir->ent.type = QSE_DIR_ENT_REGULAR;
break;
case DT_LNK:
dir->ent.type = QSE_DIR_ENT_SYMLINK;
break;
case DT_BLK:
dir->ent.type = QSE_DIR_ENT_BLKDEV;
break;
case DT_CHR:
dir->ent.type = QSE_DIR_ENT_CHRDEV;
break;
case DT_FIFO:
#if defined(DT_SOCK)
case DT_SOCK:
#endif
dir->ent.type = QSE_DIR_ENT_PIPE;
break;
default:
dir->ent.type = QSE_DIR_ENT_UNKNOWN;
break;
}
#else
#define IS_TYPE(st,type) ((st.st_mode & S_IFMT) == S_IFDIR)
dir->ent.type = IS_TYPE(st,S_IFDIR)? QSE_DIR_ENT_SUBDIR:
IS_TYPE(st,S_IFREG)? QSE_DIR_ENT_REGULAR:
IS_TYPE(st,S_IFLNK)? QSE_DIR_ENT_SYMLINK:
IS_TYPE(st,S_IFCHR)? QSE_DIR_ENT_CHRDEV:
IS_TYPE(st,S_IFBLK)? QSE_DIR_ENT_BLKDEV:
IS_TYPE(st,S_IFIFO)? QSE_DIR_ENT_PIPE:
IS_TYPE(st,S_IFSOCK)? QSE_DIR_ENT_PIPE:
QSE_DIR_ENT_UNKNOWN;
#undef IS_TYPE
#endif
dir->ent.flags |= QSE_DIR_ENT_TYPE;
}
if (flags & QSE_DIR_ENT_SIZE)
{
dir->ent.size = st.st_size;
dir->ent.flags |= QSE_DIR_ENT_SIZE;
}
if (flags & QSE_DIR_ENT_TIME)
{
#if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
dir->ent.time.create =
QSE_SECNSEC_TO_MSEC(st.st_birthtim.tv_sec,st.st_birthtim.tv_nsec);
#endif
dir->ent.time.access =
QSE_SECNSEC_TO_MSEC(st.st_atim.tv_sec,st.st_atim.tv_nsec);
dir->ent.time.modify =
QSE_SECNSEC_TO_MSEC(st.st_mtim.tv_sec,st.st_mtim.tv_nsec);
dir->ent.time.change =
QSE_SECNSEC_TO_MSEC(st.st_ctim.tv_sec,st.st_ctim.tv_nsec);
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
dir->ent.time.create = st.st_birthtime;
QSE_SECNSEC_TO_MSEC(st.st_birthtimespec.tv_sec,st.st_birthtimespec.tv_nsec);
#endif
dir->ent.time.access =
QSE_SECNSEC_TO_MSEC(st.st_atimespec.tv_sec,st.st_atimespec.tv_nsec);
dir->ent.time.modify =
QSE_SECNSEC_TO_MSEC(st.st_mtimespec.tv_sec,st.st_mtimespec.tv_nsec);
dir->ent.time.change =
QSE_SECNSEC_TO_MSEC(st.st_ctimespec.tv_sec,st.st_ctimespec.tv_nsec);
#else
#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
dir->ent.time.create = st.st_birthtime * QSE_MSEC_PER_SEC;
#endif
dir->ent.time.access = st.st_atime * QSE_MSEC_PER_SEC;
dir->ent.time.modify = st.st_mtime * QSE_MSEC_PER_SEC;
dir->ent.time.change = st.st_ctime * QSE_MSEC_PER_SEC;
#endif
dir->ent.flags |= QSE_DIR_ENT_TIME;
}
#endif
return &dir->ent;

View File

@ -19,7 +19,9 @@ static void list (qse_dir_t* dir, const qse_char_t* name)
do
{
ent = qse_dir_read (dir);
qse_btime_t bt;
ent = qse_dir_read (dir, QSE_DIR_ENT_SIZE | QSE_DIR_ENT_TYPE | QSE_DIR_ENT_TIME);
if (ent == QSE_NULL)
{
qse_dir_errnum_t e = qse_dir_geterrnum(dir);
@ -28,10 +30,13 @@ static void list (qse_dir_t* dir, const qse_char_t* name)
break;
}
if (ent->type == QSE_DIR_ENT_DIRECTORY)
qse_printf (QSE_T("<DIR> %16lu %s\n"), (unsigned long)ent->size, ent->name);
else
qse_printf (QSE_T(" %16lu %s\n"), (unsigned long)ent->size, ent->name);
qse_localtime (ent->time.modify, &bt);
qse_printf (QSE_T("%s %16lu %04d-%02d-%02d %02d:%02d %s\n"),
((ent->type == QSE_DIR_ENT_SUBDIR)? QSE_T("<D>"): QSE_T(" ")),
(unsigned long)ent->size,
bt.year + 1900, bt.mon+1, bt.mday, bt.hour, bt.min,
ent->name.base
);
}
while (1);