xref: /PHP-7.0/win32/readdir.c (revision a6190359)
1 #include <malloc.h>
2 #include <string.h>
3 #include <errno.h>
4 
5 #include "php.h"
6 #include "readdir.h"
7 #include "TSRM.h"
8 /**********************************************************************
9  * Implement dirent-style opendir/readdir/rewinddir/closedir on Win32
10  *
11  * Functions defined are opendir(), readdir(), rewinddir() and
12  * closedir() with the same prototypes as the normal dirent.h
13  * implementation.
14  *
15  * Does not implement telldir(), seekdir(), or scandir().  The dirent
16  * struct is compatible with Unix, except that d_ino is always 1 and
17  * d_off is made up as we go along.
18  *
19  * The DIR typedef is not compatible with Unix.
20  **********************************************************************/
21 
opendir(const char * dir)22 DIR *opendir(const char *dir)
23 {
24 	DIR *dp;
25 	char *filespec;
26 	HANDLE handle;
27 	int index;
28 	char resolved_path_buff[MAXPATHLEN];
29 
30 	if (!VCWD_REALPATH(dir, resolved_path_buff)) {
31 		return NULL;
32 	}
33 
34 	filespec = (char *)malloc(strlen(resolved_path_buff) + 2 + 1);
35 	if (filespec == NULL) {
36 		return NULL;
37 	}
38 	strcpy(filespec, resolved_path_buff);
39 	index = (int)strlen(filespec) - 1;
40 	if (index >= 0 && (filespec[index] == '/' ||
41 	   (filespec[index] == '\\' && (index == 0 || !IsDBCSLeadByte(filespec[index-1])))))
42 		filespec[index] = '\0';
43 	strcat(filespec, "\\*");
44 
45 	dp = (DIR *) malloc(sizeof(DIR));
46 	if (dp == NULL) {
47 		free(filespec);
48 		return NULL;
49 	}
50 	dp->offset = 0;
51 	dp->finished = 0;
52 
53 	if ((handle = FindFirstFile(filespec, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) {
54 		DWORD err = GetLastError();
55 		if (err == ERROR_NO_MORE_FILES || err == ERROR_FILE_NOT_FOUND) {
56 			dp->finished = 1;
57 		} else {
58 			free(dp);
59 			free(filespec);
60 			return NULL;
61 		}
62 	}
63 	dp->dir = strdup(resolved_path_buff);
64 	dp->handle = handle;
65 	free(filespec);
66 
67 	return dp;
68 }
69 
readdir(DIR * dp)70 struct dirent *readdir(DIR *dp)
71 {
72 	if (!dp || dp->finished)
73 		return NULL;
74 
75 	if (dp->offset != 0) {
76 		if (FindNextFile(dp->handle, &(dp->fileinfo)) == 0) {
77 			dp->finished = 1;
78 			return NULL;
79 		}
80 	}
81 	dp->offset++;
82 
83 	strlcpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME+1);
84 	dp->dent.d_ino = 1;
85 	dp->dent.d_reclen = (unsigned short)strlen(dp->dent.d_name);
86 	dp->dent.d_off = dp->offset;
87 
88 	return &(dp->dent);
89 }
90 
readdir_r(DIR * dp,struct dirent * entry,struct dirent ** result)91 int readdir_r(DIR *dp, struct dirent *entry, struct dirent **result)
92 {
93 	if (!dp || dp->finished) {
94 		*result = NULL;
95 		return 0;
96 	}
97 
98 	if (dp->offset != 0) {
99 		if (FindNextFile(dp->handle, &(dp->fileinfo)) == 0) {
100 			dp->finished = 1;
101 			*result = NULL;
102 			return 0;
103 		}
104 	}
105 	dp->offset++;
106 
107 	strlcpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME+1);
108 	dp->dent.d_ino = 1;
109 	dp->dent.d_reclen = (unsigned short)strlen(dp->dent.d_name);
110 	dp->dent.d_off = dp->offset;
111 
112 	memcpy(entry, &dp->dent, sizeof(*entry));
113 
114 	*result = &dp->dent;
115 
116 	return 0;
117 }
118 
closedir(DIR * dp)119 int closedir(DIR *dp)
120 {
121 	if (!dp)
122 		return 0;
123 	/* It is valid to scan an empty directory but we have an invalid
124 	   handle in this case (no first file found). */
125 	if (dp->handle != INVALID_HANDLE_VALUE) {
126 		FindClose(dp->handle);
127 	}
128 	if (dp->dir)
129 		free(dp->dir);
130 	if (dp)
131 		free(dp);
132 
133 	return 0;
134 }
135 
rewinddir(DIR * dp)136 int rewinddir(DIR *dp)
137 {
138 	/* Re-set to the beginning */
139 	char *filespec;
140 	HANDLE handle;
141 	int index;
142 
143 	FindClose(dp->handle);
144 
145 	dp->offset = 0;
146 	dp->finished = 0;
147 
148 	filespec = (char *)malloc(strlen(dp->dir) + 2 + 1);
149 	if (filespec == NULL) {
150 		return -1;
151 	}
152 
153 	strcpy(filespec, dp->dir);
154 	index = (int)strlen(filespec) - 1;
155 	if (index >= 0 && (filespec[index] == '/' ||
156 	   (filespec[index] == '\\' && (index == 0 || !IsDBCSLeadByte(filespec[index-1])))))
157 		filespec[index] = '\0';
158 	strcat(filespec, "/*");
159 
160 	if ((handle = FindFirstFile(filespec, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) {
161 		dp->finished = 1;
162 	}
163 
164 	dp->handle = handle;
165 	free(filespec);
166 
167 	return 0;
168 }
169 
170 /*
171  * Local variables:
172  * tab-width: 4
173  * c-basic-offset: 4
174  * End:
175  * vim600: sw=4 ts=4 fdm=marker
176  * vim<600: sw=4 ts=4
177  */
178