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 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 = 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 = 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 = 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