+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>
Don't expose implementation detail for opaque DIRENT structures.
2002-09-17 Danny Smith <dannysmith@users.sourceforge.net>
* 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>
long d_ino; /* Always zero. */
unsigned short d_reclen; /* Always zero. */
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. */
};
* This opaque data type represents the private structure
* through which a directory stream is referenced.
*/
-typedef struct __dirstream_t DIR;
+typedef union __dirstream_t DIR;
DIR* __cdecl __MINGW_NOTHROW opendir (const char*);
struct dirent* __cdecl __MINGW_NOTHROW readdir (DIR*);
long d_ino; /* Always zero. */
unsigned short d_reclen; /* Always zero. */
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. */
};
* This opaque data type represents the private structure
* 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*);
struct _wdirent* __cdecl __MINGW_NOTHROW _wreaddir (_WDIR*);
}
#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
+
+/* 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 /* Not _DIRENT_H_ */
+#endif /* !defined _DIRENT_H_ */
#define SUFFIX _T("*")
#define SLASH _T("\\")
-struct __dirstream_t
+union __dirstream_t
{
/* Actual (private) declaration for opaque data type "DIR". */
- /* disk transfer area for this dir */
- struct _finddata_t dd_dta;
+ /* dirent struct to return from dir (NOTE: this makes this thread
+ * safe as long as only one thread uses a particular DIR struct at
+ * a time) */
+ struct dirent dd_dir;
+
+ struct __dirstream_private_t
+ {
+ /* Three padding fields, matching the head of dd_dir...
+ */
+ long dd_ino; /* Always zero. */
+ unsigned short dd_reclen; /* Always zero. */
+ unsigned short dd_namlen; /* Length of name in d_name. */
- /* dirent struct to return from dir (NOTE: this makes this thread
- * safe as long as only one thread uses a particular DIR struct at
- * a time) */
- struct dirent dd_dir;
+ /* ...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 */
intptr_t dd_handle;
- /*
- * Status of search:
+ /* Status of search:
* (type is now int -- was short in older versions).
* 0 = not started yet (next entry to read is first entry)
* -1 = off the end
/* given path for dir with search pattern (struct is extended) */
char dd_name[1];
+
+ } dd_private;
};
-struct __wdirstream_t
+union __wdirstream_t
{
/* Actual (private) declaration for opaque data type "_WDIR". */
- /* disk transfer area for this dir */
- struct _wfinddata_t dd_dta;
+ /* dirent struct to return from dir (NOTE: this makes this thread
+ * safe as long as only one thread uses a particular DIR struct at
+ * a time) */
+ struct _wdirent dd_dir;
+
+ struct __wdirstream_private_t
+ {
+ /* Three padding fields, matching the head of dd_dir...
+ */
+ long dd_ino; /* Always zero. */
+ unsigned short dd_reclen; /* Always zero. */
+ unsigned short dd_namlen; /* Length of name in d_name. */
- /* dirent struct to return from dir (NOTE: this makes this thread
- * safe as long as only one thread uses a particular DIR struct at
- * a time) */
- struct _wdirent dd_dir;
+ /* ...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 */
intptr_t dd_handle;
- /*
- * Status of search:
+ /* Status of search:
* 0 = not started yet (next entry to read is first entry)
* -1 = off the end
* positive = 0 based index of next entry
/* given path for dir with search pattern (struct is extended) */
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(). */
static inline unsigned _tGetFileAttributes (const _TCHAR * tPath)
{
}
/* 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. */
- if (nd->dd_name[0] != _T('\0')
- && _tcsrchr (nd->dd_name, _T('/')) != nd->dd_name
- + _tcslen (nd->dd_name) - 1
- && _tcsrchr (nd->dd_name, _T('\\')) != nd->dd_name
- + _tcslen (nd->dd_name) - 1)
+ if (nd->dd_private.dd_name[0] != _T('\0')
+ && _tcsrchr (nd->dd_private.dd_name, _T('/')) != nd->dd_private.dd_name
+ + _tcslen (nd->dd_private.dd_name) - 1
+ && _tcsrchr (nd->dd_private.dd_name, _T('\\')) != nd->dd_private.dd_name
+ + _tcslen (nd->dd_private.dd_name) - 1)
{
- _tcscat (nd->dd_name, SLASH);
+ _tcscat (nd->dd_private.dd_name, SLASH);
}
/* 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
* to call _findclose on it. */
- nd->dd_handle = -1;
+ nd->dd_private.dd_handle = -1;
/* Initialize the status. */
- nd->dd_stat = 0;
+ nd->dd_private.dd_stat = 0;
/* Initialize the dirent structure. ino and reclen are invalid under
* Win32, and name simply points at the appropriate part of the
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
* (or the structure has an invalid dd_stat). */
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. */
/* 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
* directory. */
- dirp->dd_stat = -1;
+ dirp->dd_private.dd_stat = -1;
}
else
{
- dirp->dd_stat = 1;
+ dirp->dd_private.dd_stat = 1;
}
}
else
{
/* 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.
_findnext sets errno to ENOENT if no more file
DWORD winerr = GetLastError ();
if (winerr == ERROR_NO_MORE_FILES)
errno = 0;
- _findclose (dirp->dd_handle);
- dirp->dd_handle = -1;
- dirp->dd_stat = -1;
+ _findclose (dirp->dd_private.dd_handle);
+ dirp->dd_private.dd_handle = -1;
+ dirp->dd_private.dd_stat = -1;
}
else
{
/* Update the status to indicate the correct
* 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
* already appropriately filled in except the length of the
- * file name. */
- dirp->dd_dir.d_namlen = _tcslen (dirp->dd_dta.name);
- _tcscpy (dirp->dd_dir.d_name, dirp->dd_dta.name);
+ * file 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 -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. */
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_stat = 0;
+ dirp->dd_private.dd_handle = -1;
+ dirp->dd_private.dd_stat = 0;
}
/*
errno = EFAULT;
return -1;
}
- return dirp->dd_stat;
+ return dirp->dd_private.dd_stat;
}
/*
else if (lPos == -1)
{
/* 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_stat = -1;
+ dirp->dd_private.dd_handle = -1;
+ dirp->dd_private.dd_stat = -1;
}
else
{
/* Rewind and read forward to the appropriate index. */
_trewinddir (dirp);
- while ((dirp->dd_stat < lPos) && _treaddir (dirp))
+ while ((dirp->dd_private.dd_stat < lPos) && _treaddir (dirp))
;
}
}