Rationalise structure layout; add dirent.d_type field.
This commit is contained in:
		| @@ -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> | ||||
|  | ||||
| 	Don't expose implementation detail for opaque DIRENT structures. | ||||
| @@ -3071,7 +3097,7 @@ | ||||
| 2002-09-17 Danny Smith <dannysmith@users.sourceforge.net> | ||||
|  | ||||
| 	* include/time.h (__need_NULL): Define before including | ||||
| 	stddef.h. Thanks to: R<EFBFBD>diger Dehmel <de@lmnet.de>. | ||||
| 	stddef.h. Thanks to: Rüdiger Dehmel <de@lmnet.de>. | ||||
|  | ||||
| 2002-09-16 Ranjit Matthew <rmathew@hotmail.com> | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
| #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_ */ | ||||
|   | ||||
| @@ -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. */ | ||||
|  | ||||
|     /* ...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. */ | ||||
|  | ||||
|     /* ...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)) | ||||
| 	; | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user