Rationalise structure layout; add dirent.d_type field.

This commit is contained in:
Keith Marshall 2011-10-01 20:18:10 +00:00
parent 341bf73d6d
commit 35ddfc9e28
3 changed files with 215 additions and 60 deletions

View File

@ -1,3 +1,29 @@
2011-10-01 Keith Marshall <keithmarshall@users.sourceforge.net>
Rationalise structure layout; add dirent.d_type field.
* include/dirent.h (struct dirent): Rearrange; add d_type field.
Add extra padding fields between d_type and d_name, to represent a
union with a _finddata_t struct, aligned at the d_type field.
(struct _wdirent): Likewise, with _wfinddata_t aligned at d_type.
(DT_REG, DT_DIR): New macros; define them to be equivalent to...
(_A_NORMAL, _A_SUBDIR): ...these Microsoft attributes respectively.
(DT_BLK, DT_CHR, DT_FIFO, DT_LNK, DT_SOCK): New macros; define them.
They have little relevance on Win32, so don't use them, substitute...
(DT_UNKNOWN): ...this new catch-all macro instead; define it.
(struct __dirstream_t): Change declaration; replace by opaque union.
(struct __wdirstream_t): Likewise.
* mingwex/dirent.c (struct __dirstream_t): Redefine as union; map...
(struct dirent, struct __dirstream_private_t): ...these to a common
address; the latter encapsulates the private data into...
(dd_private): ...this new member; update all references accordingly.
Adjust field layout to align with corresponding dirent fields.
(struct __wdirstream_t): Similarly redefine as union, mapping...
(struct _wdirent, struct __wdirstream_private_t): ...these.
(_treaddir): Set dirent.d_type to appropriate selection from...
(DT_REG, DT_DIR, DT_UNKNOWN): ...these.
2011-08-27 Keith Marshall <keithmarshall@users.sourceforge.net> 2011-08-27 Keith Marshall <keithmarshall@users.sourceforge.net>
Don't expose implementation detail for opaque DIRENT structures. Don't expose implementation detail for opaque DIRENT structures.
@ -3071,7 +3097,7 @@
2002-09-17 Danny Smith <dannysmith@users.sourceforge.net> 2002-09-17 Danny Smith <dannysmith@users.sourceforge.net>
* include/time.h (__need_NULL): Define before including * include/time.h (__need_NULL): Define before including
stddef.h. Thanks to: Rüdiger Dehmel <de@lmnet.de>. stddef.h. Thanks to: Rüdiger Dehmel <de@lmnet.de>.
2002-09-16 Ranjit Matthew <rmathew@hotmail.com> 2002-09-16 Ranjit Matthew <rmathew@hotmail.com>

View File

@ -24,6 +24,20 @@ struct dirent
long d_ino; /* Always zero. */ long d_ino; /* Always zero. */
unsigned short d_reclen; /* Always zero. */ unsigned short d_reclen; /* Always zero. */
unsigned short d_namlen; /* Length of name in d_name. */ unsigned short d_namlen; /* Length of name in d_name. */
/* The following exactly mimic the layout of _finddata_t ...
*/
unsigned d_type; /* File attributes */
time_t d_time_create;
time_t d_time_access; /* always midnight local time */
time_t d_time_write;
_fsize_t d_size;
/*
* ...so that we may map a union of _finddata_t at the
* location of d_type (corresponding to _finddata_t.attrib),
* and thus map this directly to the _findfirst/_findnext
* returned field.
*/
char d_name[FILENAME_MAX]; /* File name. */ char d_name[FILENAME_MAX]; /* File name. */
}; };
@ -31,7 +45,7 @@ struct dirent
* This opaque data type represents the private structure * This opaque data type represents the private structure
* through which a directory stream is referenced. * through which a directory stream is referenced.
*/ */
typedef struct __dirstream_t DIR; typedef union __dirstream_t DIR;
DIR* __cdecl __MINGW_NOTHROW opendir (const char*); DIR* __cdecl __MINGW_NOTHROW opendir (const char*);
struct dirent* __cdecl __MINGW_NOTHROW readdir (DIR*); struct dirent* __cdecl __MINGW_NOTHROW readdir (DIR*);
@ -48,6 +62,20 @@ struct _wdirent
long d_ino; /* Always zero. */ long d_ino; /* Always zero. */
unsigned short d_reclen; /* Always zero. */ unsigned short d_reclen; /* Always zero. */
unsigned short d_namlen; /* Length of name in d_name. */ unsigned short d_namlen; /* Length of name in d_name. */
/* The following exactly mimic the layout of _wfinddata_t ...
*/
unsigned d_type; /* File attributes */
time_t d_time_create; /* -1 for FAT file systems */
time_t d_time_access; /* -1 for FAT file systems */
time_t d_time_write;
_fsize_t d_size;
/*
* ...so that we may map a union of _wfinddata_t at the
* location of d_type (corresponding to _wfinddata_t.attrib),
* and thus map this directly to the _wfindfirst/_wfindnext
* returned field.
*/
wchar_t d_name[FILENAME_MAX]; /* File name. */ wchar_t d_name[FILENAME_MAX]; /* File name. */
}; };
@ -55,7 +83,7 @@ struct _wdirent
* This opaque data type represents the private structure * This opaque data type represents the private structure
* through which a wide directory stream is referenced. * through which a wide directory stream is referenced.
*/ */
typedef struct __wdirstream_t _WDIR; typedef union __wdirstream_t _WDIR;
_WDIR* __cdecl __MINGW_NOTHROW _wopendir (const wchar_t*); _WDIR* __cdecl __MINGW_NOTHROW _wopendir (const wchar_t*);
struct _wdirent* __cdecl __MINGW_NOTHROW _wreaddir (_WDIR*); struct _wdirent* __cdecl __MINGW_NOTHROW _wreaddir (_WDIR*);
@ -69,6 +97,47 @@ void __cdecl __MINGW_NOTHROW _wseekdir (_WDIR*, long);
} }
#endif #endif
#endif /* Not RC_INVOKED */ #if defined(_BSD_SOURCE) || defined(_WIN32)
/*
* BSD-ish systems define manifest constants for the d_type field;
* although probably only DT_REG and DT_DIR are useful on Win32, we
* try to map them as best we can from the _finddata.attrib field.
*
* The relevant Microsoft manifest values are:
*
* _A_NORMAL (0x0000) normal file: best fit for DT_REG
* _A_RDONLY (0x0001) read-only: no BSD d_type equivalent
* _A_HIDDEN (0x0002) hidden entity: no BSD equivalent
* _A_SYSTEM (0x0004) system entity: no BSD equivalent
* _A_VOLID (0x0008) volume label: no BSD equivalent
* _A_SUBDIR (0x0010) directory: best fit for DT_DIR
* _A_ARCH (0x0020) "dirty": no BSD equivalent
*
* Thus, we may immediately define:
*/
#define DT_REG _A_NORMAL
#define DT_DIR _A_SUBDIR
#endif /* Not _DIRENT_H_ */ /* The remaining BSD d_type manifest values have no Win32 equivalents;
* we will define them artificially, and then we will ensure that our
* opendir()/readdir() implementation will never assign them; (we will
* substitute DT_UNKNOWN, but it would be unwise to simply make these
* equivalent to that, since an application is likely to simply check
* for d_type equal to any one of these defined types, and thus could
* mistakenly identify DT_UNKNOWN as being of the tested type):
*/
#define DT_BLK (((_A_SUBDIR) << 4) | DT_UNKNOWN)
#define DT_CHR (((_A_SUBDIR) << 5) | DT_UNKNOWN)
#define DT_FIFO (((_A_SUBDIR) << 6) | DT_UNKNOWN)
#define DT_LNK (((_A_SUBDIR) << 7) | DT_UNKNOWN)
#define DT_SOCK (((_A_SUBDIR) << 8) | DT_UNKNOWN)
/* No file system entity can ever be simultaneously a volume label
* and a directory; we will exploit this to unambiguously define:
*/
#define DT_UNKNOWN (_A_VOLID | _A_SUBDIR)
#endif /* _BSD_SOURCE */
#endif /* ! RC_INVOKED */
#endif /* !defined _DIRENT_H_ */

View File

@ -28,23 +28,32 @@
#define SUFFIX _T("*") #define SUFFIX _T("*")
#define SLASH _T("\\") #define SLASH _T("\\")
struct __dirstream_t union __dirstream_t
{ {
/* Actual (private) declaration for opaque data type "DIR". */ /* Actual (private) declaration for opaque data type "DIR". */
/* disk transfer area for this dir */ /* dirent struct to return from dir (NOTE: this makes this thread
struct _finddata_t dd_dta; * safe as long as only one thread uses a particular DIR struct at
* a time) */
struct dirent dd_dir;
/* dirent struct to return from dir (NOTE: this makes this thread struct __dirstream_private_t
* safe as long as only one thread uses a particular DIR struct at {
* a time) */ /* Three padding fields, matching the head of dd_dir...
struct dirent dd_dir; */
long dd_ino; /* Always zero. */
unsigned short dd_reclen; /* Always zero. */
unsigned short dd_namlen; /* Length of name in d_name. */
/* ...to keep the start of this disk transfer area for this dir
* aligned at the offset of the dd_dir.d_type field
*/
struct _finddata_t dd_dta;
/* _findnext handle */ /* _findnext handle */
intptr_t dd_handle; intptr_t dd_handle;
/* /* Status of search:
* Status of search:
* (type is now int -- was short in older versions). * (type is now int -- was short in older versions).
* 0 = not started yet (next entry to read is first entry) * 0 = not started yet (next entry to read is first entry)
* -1 = off the end * -1 = off the end
@ -54,25 +63,36 @@ struct __dirstream_t
/* given path for dir with search pattern (struct is extended) */ /* given path for dir with search pattern (struct is extended) */
char dd_name[1]; char dd_name[1];
} dd_private;
}; };
struct __wdirstream_t union __wdirstream_t
{ {
/* Actual (private) declaration for opaque data type "_WDIR". */ /* Actual (private) declaration for opaque data type "_WDIR". */
/* disk transfer area for this dir */ /* dirent struct to return from dir (NOTE: this makes this thread
struct _wfinddata_t dd_dta; * safe as long as only one thread uses a particular DIR struct at
* a time) */
struct _wdirent dd_dir;
/* dirent struct to return from dir (NOTE: this makes this thread struct __wdirstream_private_t
* safe as long as only one thread uses a particular DIR struct at {
* a time) */ /* Three padding fields, matching the head of dd_dir...
struct _wdirent dd_dir; */
long dd_ino; /* Always zero. */
unsigned short dd_reclen; /* Always zero. */
unsigned short dd_namlen; /* Length of name in d_name. */
/* ...to keep the start of this disk transfer area for this dir
* aligned at the offset of the dd_dir.d_type field
*/
struct _wfinddata_t dd_dta;
/* _findnext handle */ /* _findnext handle */
intptr_t dd_handle; intptr_t dd_handle;
/* /* Status of search:
* Status of search:
* 0 = not started yet (next entry to read is first entry) * 0 = not started yet (next entry to read is first entry)
* -1 = off the end * -1 = off the end
* positive = 0 based index of next entry * positive = 0 based index of next entry
@ -81,8 +101,27 @@ struct __wdirstream_t
/* given path for dir with search pattern (struct is extended) */ /* given path for dir with search pattern (struct is extended) */
wchar_t dd_name[1]; wchar_t dd_name[1];
} dd_private;
}; };
/* We map the BSD d_type field in the returned dirent structure
* from the Microsoft _finddata_t dd_dta.attrib bits, which are:
*
* _A_NORMAL (0x0000) normal file: best fit for DT_REG
* _A_RDONLY (0x0001) read-only: no BSD d_type equivalent
* _A_HIDDEN (0x0002) hidden entity: no BSD equivalent
* _A_SYSTEM (0x0004) system entity: no BSD equivalent
* _A_VOLID (0x0008) volume label: no BSD equivalent
* _A_SUBDIR (0x0010) directory: best fit for DT_DIR
* _A_ARCH (0x0020) "dirty": no BSD equivalent
*
* Of these, _A_RDONLY, _A_HIDDEN, _A_SYSTEM, and _A_ARCH are
* modifier bits, rather than true entity type specifiers; we
* will ignore them in the mapping, by applying this mask:
*/
#define DT_IGNORED (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH)
/* Helper for opendir(). */ /* Helper for opendir(). */
static inline unsigned _tGetFileAttributes (const _TCHAR * tPath) static inline unsigned _tGetFileAttributes (const _TCHAR * tPath)
{ {
@ -161,27 +200,27 @@ _topendir (const _TCHAR *szPath)
} }
/* Create the search expression. */ /* Create the search expression. */
_tcscpy (nd->dd_name, szFullPath); _tcscpy (nd->dd_private.dd_name, szFullPath);
/* Add on a slash if the path does not end with one. */ /* Add on a slash if the path does not end with one. */
if (nd->dd_name[0] != _T('\0') if (nd->dd_private.dd_name[0] != _T('\0')
&& _tcsrchr (nd->dd_name, _T('/')) != nd->dd_name && _tcsrchr (nd->dd_private.dd_name, _T('/')) != nd->dd_private.dd_name
+ _tcslen (nd->dd_name) - 1 + _tcslen (nd->dd_private.dd_name) - 1
&& _tcsrchr (nd->dd_name, _T('\\')) != nd->dd_name && _tcsrchr (nd->dd_private.dd_name, _T('\\')) != nd->dd_private.dd_name
+ _tcslen (nd->dd_name) - 1) + _tcslen (nd->dd_private.dd_name) - 1)
{ {
_tcscat (nd->dd_name, SLASH); _tcscat (nd->dd_private.dd_name, SLASH);
} }
/* Add on the search pattern */ /* Add on the search pattern */
_tcscat (nd->dd_name, SUFFIX); _tcscat (nd->dd_private.dd_name, SUFFIX);
/* Initialize handle to -1 so that a premature closedir doesn't try /* Initialize handle to -1 so that a premature closedir doesn't try
* to call _findclose on it. */ * to call _findclose on it. */
nd->dd_handle = -1; nd->dd_private.dd_handle = -1;
/* Initialize the status. */ /* Initialize the status. */
nd->dd_stat = 0; nd->dd_private.dd_stat = 0;
/* Initialize the dirent structure. ino and reclen are invalid under /* Initialize the dirent structure. ino and reclen are invalid under
* Win32, and name simply points at the appropriate part of the * Win32, and name simply points at the appropriate part of the
@ -213,33 +252,33 @@ _treaddir (_TDIR * dirp)
return (struct _tdirent *) 0; return (struct _tdirent *) 0;
} }
if (dirp->dd_stat < 0) if (dirp->dd_private.dd_stat < 0)
{ {
/* We have already returned all files in the directory /* We have already returned all files in the directory
* (or the structure has an invalid dd_stat). */ * (or the structure has an invalid dd_stat). */
return (struct _tdirent *) 0; return (struct _tdirent *) 0;
} }
else if (dirp->dd_stat == 0) else if (dirp->dd_private.dd_stat == 0)
{ {
/* We haven't started the search yet. */ /* We haven't started the search yet. */
/* Start the search */ /* Start the search */
dirp->dd_handle = _tfindfirst (dirp->dd_name, &(dirp->dd_dta)); dirp->dd_private.dd_handle = _tfindfirst (dirp->dd_private.dd_name, &(dirp->dd_private.dd_dta));
if (dirp->dd_handle == -1) if (dirp->dd_private.dd_handle == -1)
{ {
/* Whoops! Seems there are no files in that /* Whoops! Seems there are no files in that
* directory. */ * directory. */
dirp->dd_stat = -1; dirp->dd_private.dd_stat = -1;
} }
else else
{ {
dirp->dd_stat = 1; dirp->dd_private.dd_stat = 1;
} }
} }
else else
{ {
/* Get the next search entry. */ /* Get the next search entry. */
if (_tfindnext (dirp->dd_handle, &(dirp->dd_dta))) if (_tfindnext (dirp->dd_private.dd_handle, &(dirp->dd_private.dd_dta)))
{ {
/* We are off the end or otherwise error. /* We are off the end or otherwise error.
_findnext sets errno to ENOENT if no more file _findnext sets errno to ENOENT if no more file
@ -247,25 +286,46 @@ _treaddir (_TDIR * dirp)
DWORD winerr = GetLastError (); DWORD winerr = GetLastError ();
if (winerr == ERROR_NO_MORE_FILES) if (winerr == ERROR_NO_MORE_FILES)
errno = 0; errno = 0;
_findclose (dirp->dd_handle); _findclose (dirp->dd_private.dd_handle);
dirp->dd_handle = -1; dirp->dd_private.dd_handle = -1;
dirp->dd_stat = -1; dirp->dd_private.dd_stat = -1;
} }
else else
{ {
/* Update the status to indicate the correct /* Update the status to indicate the correct
* number. */ * number. */
dirp->dd_stat++; dirp->dd_private.dd_stat++;
} }
} }
if (dirp->dd_stat > 0) if (dirp->dd_private.dd_stat > 0)
{ {
/* Successfully got an entry. Everything about the file is /* Successfully got an entry. Everything about the file is
* already appropriately filled in except the length of the * already appropriately filled in except the length of the
* file name. */ * file name...
dirp->dd_dir.d_namlen = _tcslen (dirp->dd_dta.name); */
_tcscpy (dirp->dd_dir.d_name, dirp->dd_dta.name); dirp->dd_dir.d_namlen = _tcslen (dirp->dd_dir.d_name);
/*
* ...and the attributes returned in the dd_dta.attrib field;
* these require adjustment to their BSD equivalents, which are
* returned via the union with the dd_dir.d_type field:
*/
switch( dirp->dd_dir.d_type &= ~DT_IGNORED )
{
case DT_REG:
case DT_DIR:
/* After stripping out the modifier bits in DT_IGNORED,
* (which we ALWAYS ignore), this pair require no further
* adjustment...
*/
break;
default:
/* ...while nothing else has an appropriate equivalent
* in the BSD d_type identification model.
*/
dirp->dd_dir.d_type = DT_UNKNOWN;
}
return &dirp->dd_dir; return &dirp->dd_dir;
} }
@ -292,9 +352,9 @@ _tclosedir (_TDIR * dirp)
return -1; return -1;
} }
if (dirp->dd_handle != -1) if (dirp->dd_private.dd_handle != -1)
{ {
rc = _findclose (dirp->dd_handle); rc = _findclose (dirp->dd_private.dd_handle);
} }
/* Delete the dir structure. */ /* Delete the dir structure. */
@ -320,13 +380,13 @@ _trewinddir (_TDIR * dirp)
return; return;
} }
if (dirp->dd_handle != -1) if (dirp->dd_private.dd_handle != -1)
{ {
_findclose (dirp->dd_handle); _findclose (dirp->dd_private.dd_handle);
} }
dirp->dd_handle = -1; dirp->dd_private.dd_handle = -1;
dirp->dd_stat = 0; dirp->dd_private.dd_stat = 0;
} }
/* /*
@ -345,7 +405,7 @@ _ttelldir (_TDIR * dirp)
errno = EFAULT; errno = EFAULT;
return -1; return -1;
} }
return dirp->dd_stat; return dirp->dd_private.dd_stat;
} }
/* /*
@ -377,19 +437,19 @@ _tseekdir (_TDIR * dirp, long lPos)
else if (lPos == -1) else if (lPos == -1)
{ {
/* Seek past end. */ /* Seek past end. */
if (dirp->dd_handle != -1) if (dirp->dd_private.dd_handle != -1)
{ {
_findclose (dirp->dd_handle); _findclose (dirp->dd_private.dd_handle);
} }
dirp->dd_handle = -1; dirp->dd_private.dd_handle = -1;
dirp->dd_stat = -1; dirp->dd_private.dd_stat = -1;
} }
else else
{ {
/* Rewind and read forward to the appropriate index. */ /* Rewind and read forward to the appropriate index. */
_trewinddir (dirp); _trewinddir (dirp);
while ((dirp->dd_stat < lPos) && _treaddir (dirp)) while ((dirp->dd_private.dd_stat < lPos) && _treaddir (dirp))
; ;
} }
} }