@@ -42,8 +42,54 @@ struct DIR_ {
42
42
intptr_t hFile ;
43
43
struct _wfinddata_t c_file ;
44
44
int first ;
45
+ wchar_t * nextdisk ;
45
46
};
46
47
48
+ #define ATTR_ROOTDIR UINT_MAX
49
+
50
+ /* Enumerate all devices which have drive name.
51
+ Return a DIR stream on the root directory, or NULL if it could not be enumerated. */
52
+ DIR *
53
+ openrootdir (const char * name )
54
+ {
55
+ int hr = 0 ;
56
+ DWORD dw ;
57
+ DIR * pdir ;
58
+ struct _wfinddata_t c_file = {0 };
59
+ wchar_t * p ;
60
+
61
+ dw = GetLogicalDriveStringsW (_countof (c_file .name ) - 2 , c_file .name );
62
+ if (!dw ) {
63
+ errno = ENODEV ;
64
+ return NULL ;
65
+ }
66
+ c_file .attrib = ATTR_ROOTDIR ;
67
+ c_file .size = 0 ;
68
+ p = c_file .name ;
69
+ while (* p ) {
70
+ size_t len = wcslen (p );
71
+ if (len == 0 )
72
+ break ;
73
+ p += len + 1 ;
74
+ c_file .size ++ ;
75
+ }
76
+ if (c_file .size == 0 ) {
77
+ errno = ENODEV ;
78
+ return NULL ;
79
+ }
80
+ pdir = malloc (sizeof (DIR ));
81
+ if (!pdir ) {
82
+ errno = ENOMEM ;
83
+ return NULL ;
84
+ }
85
+ memset (pdir , 0 , sizeof (DIR ));
86
+ pdir -> hFile = 0 ;
87
+ memcpy (& pdir -> c_file , & c_file , sizeof (c_file ));
88
+ pdir -> first = 1 ;
89
+
90
+ return pdir ;
91
+ }
92
+
47
93
/* Open a directory stream on NAME.
48
94
Return a DIR stream on the directory, or NULL if it could not be opened. */
49
95
DIR *
@@ -55,14 +101,31 @@ opendir(const char *name)
55
101
wchar_t searchstr [PATH_MAX ];
56
102
wchar_t * wname = NULL ;
57
103
int needed ;
104
+ size_t len ;
105
+
106
+ /* Detect root dir */
107
+ if (name && strcmp (name , "/" ) == 0 )
108
+ return openrootdir (name );
58
109
59
110
if ((wname = utf8_to_utf16 (sanitized_path (name ))) == NULL ) {
60
111
errno = ENOMEM ;
61
112
return NULL ;
62
113
}
63
114
115
+ convertToBackslashW (wname );
116
+ len = wcslen (wname );
117
+ if (len && wname [len - 1 ] == L'\\' ) {
118
+ len -- ;
119
+ wname [len ] = 0 ;
120
+ }
121
+ if (len >= PATH_MAX ) {
122
+ free (wname );
123
+ errno = ENAMETOOLONG ;
124
+ return NULL ;
125
+ }
126
+
64
127
/* add *.* for Windows _findfirst() search pattern */
65
- swprintf_s (searchstr , PATH_MAX , L"%s\\*.*" , wname );
128
+ swprintf_s (searchstr , _countof ( searchstr ) - 1 , L"%s\\*.*" , wname );
66
129
free (wname );
67
130
68
131
if ((hFile = _wfindfirst (searchstr , & c_file )) == -1L )
@@ -92,13 +155,69 @@ closedir(DIR *dirp)
92
155
93
156
if (dirp && (dirp -> hFile )) {
94
157
_findclose (dirp -> hFile );
95
- dirp -> hFile = 0 ;
96
- free (dirp );
97
158
}
159
+ free (dirp );
98
160
99
161
return 0 ;
100
162
}
101
163
164
+ /* Read a root directory entry from DIRP.
165
+ Return a pointer to a `struct dirent' describing the entry,
166
+ or NULL for EOF or error. The storage returned may be overwritten
167
+ by a later readdir call on the same DIR stream. */
168
+ struct dirent *
169
+ readrootdir (DIR * dirp )
170
+ {
171
+ wchar_t * p ;
172
+ size_t len = 0 ;
173
+ struct dirent * pdirentry ;
174
+ UINT dt ;
175
+ ULARGE_INTEGER totalNumberOfBytes ;
176
+ BOOL x ;
177
+
178
+ if (dirp -> c_file .size <= 0 ) {
179
+ errno = ENODATA ;
180
+ return NULL ;
181
+ }
182
+ if (dirp -> first ) {
183
+ dirp -> first = 0 ;
184
+ dirp -> nextdisk = dirp -> c_file .name ;
185
+ }
186
+
187
+ p = dirp -> nextdisk ;
188
+
189
+ for ( ; ; p += len + 1 ) {
190
+ len = wcslen (p );
191
+ if (len == 0 ) {
192
+ dirp -> nextdisk = p ;
193
+ errno = ENODATA ;
194
+ return NULL ; /* end of multi-string */
195
+ }
196
+
197
+ dt = GetDriveTypeW (p );
198
+ if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR || dt == DRIVE_RAMDISK )
199
+ continue ;
200
+
201
+ x = GetDiskFreeSpaceExW (p , NULL , & totalNumberOfBytes , NULL );
202
+ if (!x || totalNumberOfBytes .QuadPart == 0 )
203
+ continue ;
204
+
205
+ break ; // process filtered disk
206
+ }
207
+ dirp -> nextdisk = p + len + 1 ;
208
+
209
+ if ((pdirentry = malloc (sizeof (struct dirent ))) == NULL ) {
210
+ errno = ENOMEM ;
211
+ return NULL ;
212
+ }
213
+ pdirentry -> d_name [0 ] = (char )p [0 ];
214
+ pdirentry -> d_name [1 ] = ':' ;
215
+ pdirentry -> d_name [2 ] = 0 ;
216
+
217
+ pdirentry -> d_ino = 1 ; // a fictious one like UNIX to say it is nonzero
218
+ return pdirentry ;
219
+ }
220
+
102
221
/* Read a directory entry from DIRP.
103
222
Return a pointer to a `struct dirent' describing the entry,
104
223
or NULL for EOF or error. The storage returned may be overwritten
@@ -113,6 +232,9 @@ readdir(void *avp)
113
232
DIR * dirp = (DIR * )avp ;
114
233
char * tmp = NULL ;
115
234
235
+ if (dirp -> hFile == 0 && dirp -> c_file .attrib == ATTR_ROOTDIR )
236
+ return readrootdir (dirp );
237
+
116
238
for (;;) {
117
239
if (dirp -> first ) {
118
240
memcpy (& c_file , & dirp -> c_file , sizeof (c_file ));
@@ -128,7 +250,7 @@ readdir(void *avp)
128
250
return NULL ;
129
251
}
130
252
131
- strncpy (pdirentry .d_name , tmp , strlen ( tmp ) + 1 );
253
+ strncpy (pdirentry .d_name , tmp , sizeof ( pdirentry . d_name ) );
132
254
free (tmp );
133
255
134
256
pdirentry .d_ino = 1 ; /* a fictious one like UNIX to say it is nonzero */
0 commit comments