xref: /PHP-5.6/win32/readdir.c (revision 960b4e81)
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 	TSRMLS_FETCH();
30 
31 	if (!VCWD_REALPATH(dir, resolved_path_buff)) {
32 		return NULL;
33 	}
34 
35 	filespec = (char *)malloc(strlen(resolved_path_buff) + 2 + 1);
36 	if (filespec == NULL) {
37 		return NULL;
38 	}
39 	strcpy(filespec, resolved_path_buff);
40 	index = strlen(filespec) - 1;
41 	if (index >= 0 && (filespec[index] == '/' ||
42 	   (filespec[index] == '\\' && (index == 0 || !IsDBCSLeadByte(filespec[index-1])))))
43 		filespec[index] = '\0';
44 	strcat(filespec, "\\*");
45 
46 	dp = (DIR *) malloc(sizeof(DIR));
47 	if (dp == NULL) {
48 		free(filespec);
49 		return NULL;
50 	}
51 	dp->offset = 0;
52 	dp->finished = 0;
53 
54 	if ((handle = FindFirstFile(filespec, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) {
55 		DWORD err = GetLastError();
56 		if (err == ERROR_NO_MORE_FILES || err == ERROR_FILE_NOT_FOUND) {
57 			dp->finished = 1;
58 		} else {
59 			free(dp);
60 			free(filespec);
61 			return NULL;
62 		}
63 	}
64 	dp->dir = strdup(resolved_path_buff);
65 	dp->handle = handle;
66 	free(filespec);
67 
68 	return dp;
69 }
70 
readdir(DIR * dp)71 struct dirent *readdir(DIR *dp)
72 {
73 	if (!dp || dp->finished)
74 		return NULL;
75 
76 	if (dp->offset != 0) {
77 		if (FindNextFile(dp->handle, &(dp->fileinfo)) == 0) {
78 			dp->finished = 1;
79 			return NULL;
80 		}
81 	}
82 	dp->offset++;
83 
84 	strlcpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME+1);
85 	dp->dent.d_ino = 1;
86 	dp->dent.d_reclen = strlen(dp->dent.d_name);
87 	dp->dent.d_off = dp->offset;
88 
89 	return &(dp->dent);
90 }
91 
readdir_r(DIR * dp,struct dirent * entry,struct dirent ** result)92 int readdir_r(DIR *dp, struct dirent *entry, struct dirent **result)
93 {
94 	if (!dp || dp->finished) {
95 		*result = NULL;
96 		return 0;
97 	}
98 
99 	if (dp->offset != 0) {
100 		if (FindNextFile(dp->handle, &(dp->fileinfo)) == 0) {
101 			dp->finished = 1;
102 			*result = NULL;
103 			return 0;
104 		}
105 	}
106 	dp->offset++;
107 
108 	strlcpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME+1);
109 	dp->dent.d_ino = 1;
110 	dp->dent.d_reclen = strlen(dp->dent.d_name);
111 	dp->dent.d_off = dp->offset;
112 
113 	memcpy(entry, &dp->dent, sizeof(*entry));
114 
115 	*result = &dp->dent;
116 
117 	return 0;
118 }
119 
closedir(DIR * dp)120 int closedir(DIR *dp)
121 {
122 	if (!dp)
123 		return 0;
124 	/* It is valid to scan an empty directory but we have an invalid
125 	   handle in this case (no first file found). */
126 	if (dp->handle != INVALID_HANDLE_VALUE) {
127 		FindClose(dp->handle);
128 	}
129 	if (dp->dir)
130 		free(dp->dir);
131 	if (dp)
132 		free(dp);
133 
134 	return 0;
135 }
136 
rewinddir(DIR * dp)137 int rewinddir(DIR *dp)
138 {
139 	/* Re-set to the beginning */
140 	char *filespec;
141 	HANDLE handle;
142 	int index;
143 
144 	FindClose(dp->handle);
145 
146 	dp->offset = 0;
147 	dp->finished = 0;
148 
149 	filespec = (char *)malloc(strlen(dp->dir) + 2 + 1);
150 	if (filespec == NULL) {
151 		return -1;
152 	}
153 
154 	strcpy(filespec, dp->dir);
155 	index = strlen(filespec) - 1;
156 	if (index >= 0 && (filespec[index] == '/' ||
157 	   (filespec[index] == '\\' && (index == 0 || !IsDBCSLeadByte(filespec[index-1])))))
158 		filespec[index] = '\0';
159 	strcat(filespec, "/*");
160 
161 	if ((handle = FindFirstFile(filespec, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) {
162 		dp->finished = 1;
163 	}
164 
165 	dp->handle = handle;
166 	free(filespec);
167 
168 	return 0;
169 }
170