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@ build_triplet = @build@
host_triplet = @host@ host_triplet = @host@
subdir = . subdir = .
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/README.in \ $(srcdir)/Makefile.in $(srcdir)/README.in \
$(top_srcdir)/configure ac/config.guess ac/config.sub \ $(top_srcdir)/configure ac/config.guess ac/config.sub \
ac/depcomp ac/install-sh ac/ltmain.sh ac/missing ac/depcomp ac/install-sh ac/ltmain.sh ac/missing

30
qse/configure vendored
View File

@ -15745,6 +15745,36 @@ _ACEOF
fi 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 # 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 # 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" LIBS="$OLDLIBS"
AC_STRUCT_DIRENT_D_TYPE 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 dnl check the size of primitive data types
AC_CHECK_SIZEOF(char,,[[]]) AC_CHECK_SIZEOF(char,,[[]])

View File

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

View File

@ -178,6 +178,15 @@
/* Define to 1 if `d_type' is a member of `struct dirent'. */ /* Define to 1 if `d_type' is a member of `struct dirent'. */
#undef HAVE_STRUCT_DIRENT_D_TYPE #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. */ /* Define to 1 if you have the `sysconf' function. */
#undef HAVE_SYSCONF #undef HAVE_SYSCONF

View File

@ -23,6 +23,7 @@
#include <qse/types.h> #include <qse/types.h>
#include <qse/macros.h> #include <qse/macros.h>
#include <qse/cmn/time.h>
enum qse_dir_errnum_t enum qse_dir_errnum_t
{ {
@ -38,20 +39,46 @@ enum qse_dir_errnum_t
}; };
typedef enum qse_dir_errnum_t 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 struct qse_dir_ent_t
{ {
enum int flags;
struct
{ {
QSE_DIR_ENT_UNKNOWN, qse_char_t* base;
QSE_DIR_ENT_DIR, qse_char_t* path;
QSE_DIR_ENT_REG, } name;
QSE_DIR_ENT_FIFO, qse_dir_ent_type_t type;
QSE_DIR_ENT_CHAR, qse_foff_t size;
QSE_DIR_ENT_BLOCK,
QSE_DIR_ENT_LINK struct
} type; {
qse_char_t* name; qse_ntime_t create;
qse_foff_t size; 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; 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 enum qse_dir_option_t
{ {
/**< don't follow a symbolic link in qse_dir_change() */ /**< 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() */ /**< check directories against file system in qse_dir_change() */
QSE_DIR_REALPATH = (1 << 1) QSE_DIR_REALPATH = (1 << 2)
}; };
#ifdef __cplusplus #ifdef __cplusplus
@ -109,7 +136,8 @@ const qse_char_t* qse_dir_geterrmsg (
); );
qse_dir_ent_t* qse_dir_read ( qse_dir_ent_t* qse_dir_read (
qse_dir_t* dir qse_dir_t* dir,
int flags
); );
int qse_dir_change ( 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++; len++;
qse_mbstowcs (name, info->name.ptr, &len); qse_mbstowcs (name, info->name.ptr, &len);
#endif #endif
dir->ent.name = info->name.ptr;
dir->ent.name.base = info->name.ptr;
dir->ent.flags |= QSE_DIR_ENT_NAME;
return 0; 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) #if defined(_WIN32)
info_t* info; 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 /* call set_entry_name before changing other fields
* in dir->ent not to pollute it in case set_entry_name fails */ * 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 (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; if (info->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
dir->ent.type = QSE_DIR_ENT_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; ULARGE_INTEGER li;
dir->ent.type = QSE_DIR_ENT_LINK;
}
else
{
LARGE_INTEGER li;
li.LowPart = info->wfd.nFileSizeLow; li.LowPart = info->wfd.nFileSizeLow;
li.HighPart = info->wfd.nFileSizeHigh; li.HighPart = info->wfd.nFileSizeHigh;
dir->ent.size = li.QuadPart; 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__) #elif defined(__OS2__)
@ -486,13 +577,13 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir)
info_t* info; info_t* info;
struct dirent* ent; struct dirent* ent;
int x; int x;
#if defined(QSE_LSTAT64)
int stat_needed;
#if defined(QSE_LSTAT64)
struct stat64 st; struct stat64 st;
#else #else
struct stat st; struct stat st;
#endif #endif
qse_mchar_t* tmp_name[4];
qse_mchar_t* mfname;
info = dir->info; info = dir->info;
if (info == QSE_NULL) if (info == QSE_NULL)
@ -509,48 +600,138 @@ qse_dir_ent_t* qse_dir_read (qse_dir_t* dir)
return QSE_NULL; return QSE_NULL;
} }
#if defined(HAVE_STRUCT_DIRENT_D_TYPE) QSE_MEMSET (&dir->ent, 0, QSE_SIZEOF(dir->ent));
/* 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;
}
if (set_entry_name (dir, ent->d_name) <= -1) return QSE_NULL; 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) if (x == -1)
dir->ent.type = IS_TYPE(st,S_IFDIR)? QSE_DIR_ENT_DIR: {
IS_TYPE(st,S_IFCHR)? QSE_DIR_ENT_CHAR: dir->errnum = syserr_to_errnum (errno);
IS_TYPE(st,S_IFBLK)? QSE_DIR_ENT_BLOCK: return QSE_NULL;
QSE_DIR_ENT_UNKNOWN; }
}
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 #endif
return &dir->ent; return &dir->ent;

View File

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