From: Keith Marshall Date: Sat, 1 Oct 2011 20:18:10 +0000 (+0000) Subject: Rationalise structure layout; add dirent.d_type field. X-Git-Tag: gdb_7_4-2011-12-13-branchpoint~154 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=35ddfc9e28dd27ce87fdc584544658cd729a2b78;p=newlib-cygwin.git Rationalise structure layout; add dirent.d_type field. --- diff --git a/winsup/mingw/ChangeLog b/winsup/mingw/ChangeLog index d8a9d4e1a..5f1e9a59f 100644 --- a/winsup/mingw/ChangeLog +++ b/winsup/mingw/ChangeLog @@ -1,3 +1,29 @@ +2011-10-01 Keith Marshall + + 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 Don't expose implementation detail for opaque DIRENT structures. @@ -3071,7 +3097,7 @@ 2002-09-17 Danny Smith * include/time.h (__need_NULL): Define before including - stddef.h. Thanks to: Rüdiger Dehmel . + stddef.h. Thanks to: Rüdiger Dehmel . 2002-09-16 Ranjit Matthew diff --git a/winsup/mingw/include/dirent.h b/winsup/mingw/include/dirent.h index 7d2af2b19..3abedfafc 100644 --- a/winsup/mingw/include/dirent.h +++ b/winsup/mingw/include/dirent.h @@ -24,6 +24,20 @@ struct dirent 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. */ }; @@ -31,7 +45,7 @@ struct dirent * 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*); @@ -48,6 +62,20 @@ struct _wdirent 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. */ }; @@ -55,7 +83,7 @@ struct _wdirent * 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*); @@ -69,6 +97,47 @@ void __cdecl __MINGW_NOTHROW _wseekdir (_WDIR*, long); } #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_ */ diff --git a/winsup/mingw/mingwex/dirent.c b/winsup/mingw/mingwex/dirent.c index 0d3e54a09..f35a88db7 100644 --- a/winsup/mingw/mingwex/dirent.c +++ b/winsup/mingw/mingwex/dirent.c @@ -28,23 +28,32 @@ #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 @@ -54,25 +63,36 @@ struct __dirstream_t /* 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 @@ -81,8 +101,27 @@ struct __wdirstream_t /* 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) { @@ -161,27 +200,27 @@ _topendir (const _TCHAR *szPath) } /* 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 @@ -213,33 +252,33 @@ _treaddir (_TDIR * dirp) 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 @@ -247,25 +286,46 @@ _treaddir (_TDIR * dirp) 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; } @@ -292,9 +352,9 @@ _tclosedir (_TDIR * dirp) 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. */ @@ -320,13 +380,13 @@ _trewinddir (_TDIR * dirp) 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; } /* @@ -345,7 +405,7 @@ _ttelldir (_TDIR * dirp) errno = EFAULT; 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) { /* 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)) ; } }