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