Investigating leaks in bug 463263, backout bug 453403.
[wine-gecko.git] / security / dbm / src / dirent.c
blob001a48c5c27247713745201735f62f69be11c0dd
1 #ifdef OS2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ctype.h>
8 #include <dirent.h>
9 #include <errno.h>
11 /*#ifndef __EMX__
12 #include <libx.h>
13 #endif */
15 #define INCL_DOSFILEMGR
16 #define INCL_DOSERRORS
17 #include <os2.h>
19 #if OS2 >= 2
20 # define FFBUF FILEFINDBUF3
21 # define Word ULONG
23 * LS20 recommends a request count of 100, but according to the
24 * APAR text it does not lead to missing files, just to funny
25 * numbers of returned entries.
27 * LS30 HPFS386 requires a count greater than 2, or some files
28 * are missing (those starting with a character less that '.').
30 * Novell looses entries which overflow the buffer. In previous
31 * versions of dirent2, this could have lead to missing files
32 * when the average length of 100 directory entries was 40 bytes
33 * or more (quite unlikely for files on a Novell server).
35 * Conclusion: Make sure that the entries all fit into the buffer
36 * and that the buffer is large enough for more than 2 entries
37 * (each entry is at most 300 bytes long). And ignore the LS20
38 * effect.
40 # define Count 25
41 # define BufSz (25 * (sizeof(FILEFINDBUF3)+1))
42 #else
43 # define FFBUF FILEFINDBUF
44 # define Word USHORT
45 # define BufSz 1024
46 # define Count 3
47 #endif
49 #if defined(__IBMC__) || defined(__IBMCPP__)
50 #define error(rc) _doserrno = rc, errno = EOS2ERR
51 #elif defined(MICROSOFT)
52 #define error(rc) _doserrno = rc, errno = 255
53 #else
54 #define error(rc) errno = 255
55 #endif
57 struct _dirdescr {
58 HDIR handle; /* DosFindFirst handle */
59 char fstype; /* filesystem type */
60 Word count; /* valid entries in <ffbuf> */
61 long number; /* absolute number of next entry */
62 int index; /* relative number of next entry */
63 FFBUF * next; /* pointer to next entry */
64 char name[MAXPATHLEN+3]; /* directory name */
65 unsigned attrmask; /* attribute mask for seekdir */
66 struct dirent entry; /* buffer for directory entry */
67 BYTE ffbuf[BufSz];
71 * Return first char of filesystem type, or 0 if unknown.
73 static char
74 getFSType(const char *path)
76 static char cache[1+26];
77 char drive[3], info[512];
78 Word unit, infolen;
79 char r;
81 if (isalpha(path[0]) && path[1] == ':') {
82 unit = toupper(path[0]) - '@';
83 path += 2;
84 } else {
85 ULONG driveMap;
86 #if OS2 >= 2
87 if (DosQueryCurrentDisk(&unit, &driveMap))
88 #else
89 if (DosQCurDisk(&unit, &driveMap))
90 #endif
91 return 0;
94 if ((path[0] == '\\' || path[0] == '/')
95 && (path[1] == '\\' || path[1] == '/'))
96 return 0;
98 if (cache [unit])
99 return cache [unit];
101 drive[0] = '@' + unit;
102 drive[1] = ':';
103 drive[2] = '\0';
104 infolen = sizeof info;
105 #if OS2 >= 2
106 if (DosQueryFSAttach(drive, 0, FSAIL_QUERYNAME, (PVOID)info, &infolen))
107 return 0;
108 if (infolen >= sizeof(FSQBUFFER2)) {
109 FSQBUFFER2 *p = (FSQBUFFER2 *)info;
110 r = p->szFSDName[p->cbName];
111 } else
112 #else
113 if (DosQFSAttach((PSZ)drive, 0, FSAIL_QUERYNAME, (PVOID)info, &infolen, 0))
114 return 0;
115 if (infolen >= 9) {
116 char *p = info + sizeof(USHORT);
117 p += sizeof(USHORT) + *(USHORT *)p + 1 + sizeof(USHORT);
118 r = *p;
119 } else
120 #endif
121 r = 0;
122 return cache [unit] = r;
125 char *
126 abs_path(const char *name, char *buffer, int len)
128 char buf[4];
129 if (isalpha(name[0]) && name[1] == ':' && name[2] == '\0') {
130 buf[0] = name[0];
131 buf[1] = name[1];
132 buf[2] = '.';
133 buf[3] = '\0';
134 name = buf;
136 #if OS2 >= 2
137 if (DosQueryPathInfo((PSZ)name, FIL_QUERYFULLNAME, buffer, len))
138 #else
139 if (DosQPathInfo((PSZ)name, FIL_QUERYFULLNAME, (PBYTE)buffer, len, 0L))
140 #endif
141 return NULL;
142 return buffer;
145 DIR *
146 openxdir(const char *path, unsigned att_mask)
148 DIR *dir;
149 char name[MAXPATHLEN+3];
150 Word rc;
152 dir = malloc(sizeof(DIR));
153 if (dir == NULL) {
154 errno = ENOMEM;
155 return NULL;
158 strncpy(name, path, MAXPATHLEN);
159 name[MAXPATHLEN] = '\0';
160 switch (name[strlen(name)-1]) {
161 default:
162 strcat(name, "\\");
163 case '\\':
164 case '/':
165 case ':':
168 strcat(name, ".");
169 if (!abs_path(name, dir->name, MAXPATHLEN+1))
170 strcpy(dir->name, name);
171 if (dir->name[strlen(dir->name)-1] == '\\')
172 strcat(dir->name, "*");
173 else
174 strcat(dir->name, "\\*");
176 dir->fstype = getFSType(dir->name);
177 dir->attrmask = att_mask | A_DIR;
179 dir->handle = HDIR_CREATE;
180 dir->count = 100;
181 #if OS2 >= 2
182 rc = DosFindFirst(dir->name, &dir->handle, dir->attrmask,
183 dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD);
184 #else
185 rc = DosFindFirst((PSZ)dir->name, &dir->handle, dir->attrmask,
186 (PFILEFINDBUF)dir->ffbuf, sizeof dir->ffbuf, &dir->count, 0);
187 #endif
188 switch (rc) {
189 default:
190 free(dir);
191 error(rc);
192 return NULL;
193 case NO_ERROR:
194 case ERROR_NO_MORE_FILES:
198 dir->number = 0;
199 dir->index = 0;
200 dir->next = (FFBUF *)dir->ffbuf;
202 return (DIR *)dir;
205 DIR *
206 opendir(const char *pathname)
208 return openxdir(pathname, 0);
211 struct dirent *
212 readdir(DIR *dir)
214 static int dummy_ino = 2;
216 if (dir->index == dir->count) {
217 Word rc;
218 dir->count = 100;
219 #if OS2 >= 2
220 rc = DosFindNext(dir->handle, dir->ffbuf,
221 sizeof dir->ffbuf, &dir->count);
222 #else
223 rc = DosFindNext(dir->handle, (PFILEFINDBUF)dir->ffbuf,
224 sizeof dir->ffbuf, &dir->count);
225 #endif
226 if (rc) {
227 error(rc);
228 return NULL;
231 dir->index = 0;
232 dir->next = (FFBUF *)dir->ffbuf;
235 if (dir->index == dir->count)
236 return NULL;
238 memcpy(dir->entry.d_name, dir->next->achName, dir->next->cchName);
239 dir->entry.d_name[dir->next->cchName] = '\0';
240 dir->entry.d_ino = dummy_ino++;
241 dir->entry.d_reclen = dir->next->cchName;
242 dir->entry.d_namlen = dir->next->cchName;
243 dir->entry.d_size = dir->next->cbFile;
244 dir->entry.d_attribute = dir->next->attrFile;
245 dir->entry.d_time = *(USHORT *)&dir->next->ftimeLastWrite;
246 dir->entry.d_date = *(USHORT *)&dir->next->fdateLastWrite;
248 switch (dir->fstype) {
249 case 'F': /* FAT */
250 case 'C': /* CDFS */
251 if (dir->next->attrFile & FILE_DIRECTORY)
252 strupr(dir->entry.d_name);
253 else
254 strlwr(dir->entry.d_name);
257 #if OS2 >= 2
258 dir->next = (FFBUF *)((BYTE *)dir->next + dir->next->oNextEntryOffset);
259 #else
260 dir->next = (FFBUF *)((BYTE *)dir->next->achName + dir->next->cchName + 1);
261 #endif
262 ++dir->number;
263 ++dir->index;
265 return &dir->entry;
268 long
269 telldir(DIR *dir)
271 return dir->number;
274 void
275 seekdir(DIR *dir, long off)
277 if (dir->number > off) {
278 char name[MAXPATHLEN+2];
279 Word rc;
281 DosFindClose(dir->handle);
283 strcpy(name, dir->name);
284 strcat(name, "*");
286 dir->handle = HDIR_CREATE;
287 dir->count = 32767;
288 #if OS2 >= 2
289 rc = DosFindFirst(name, &dir->handle, dir->attrmask,
290 dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD);
291 #else
292 rc = DosFindFirst((PSZ)name, &dir->handle, dir->attrmask,
293 (PFILEFINDBUF)dir->ffbuf, sizeof dir->ffbuf, &dir->count, 0);
294 #endif
295 switch (rc) {
296 default:
297 error(rc);
298 return;
299 case NO_ERROR:
300 case ERROR_NO_MORE_FILES:
304 dir->number = 0;
305 dir->index = 0;
306 dir->next = (FFBUF *)dir->ffbuf;
309 while (dir->number < off && readdir(dir))
313 void
314 closedir(DIR *dir)
316 DosFindClose(dir->handle);
317 free(dir);
320 /*****************************************************************************/
322 #ifdef TEST
324 main(int argc, char **argv)
326 int i;
327 DIR *dir;
328 struct dirent *ep;
330 for (i = 1; i < argc; ++i) {
331 dir = opendir(argv[i]);
332 if (!dir)
333 continue;
334 while (ep = readdir(dir))
335 if (strchr("\\/:", argv[i] [strlen(argv[i]) - 1]))
336 printf("%s%s\n", argv[i], ep->d_name);
337 else
338 printf("%s/%s\n", argv[i], ep->d_name);
339 closedir(dir);
342 return 0;
345 #endif
347 #endif /* OS2 */