1 #ifdef OS2
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ctype.h>
7
8 #include <dirent.h>
9 #include <errno.h>
10
11 /*#ifndef __EMX__
12 #include <libx.h>
13 #endif */
14
15 #define INCL_DOSFILEMGR
16 #define INCL_DOSERRORS
17 #include <os2.h>
18
19 #if OS2 >= 2
20 #define FFBUF FILEFINDBUF3
21 #define Word ULONG
22 /*
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.
26 *
27 * LS30 HPFS386 requires a count greater than 2, or some files
28 * are missing (those starting with a character less that '.').
29 *
30 * Novell loses 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).
34 *
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.
39 */
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
48
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
56
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];
68 };
69
70 /*
71 * Return first char of filesystem type, or 0 if unknown.
72 */
73 static char
getFSType(const char * path)74 getFSType(const char *path)
75 {
76 static char cache[1 + 26];
77 char drive[3], info[512];
78 Word unit, infolen;
79 char r;
80
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;
92 }
93
94 if ((path[0] == '\\' || path[0] == '/') &&
95 (path[1] == '\\' || path[1] == '/'))
96 return 0;
97
98 if (cache[unit])
99 return cache[unit];
100
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;
123 }
124
125 char *
abs_path(const char * name,char * buffer,int len)126 abs_path(const char *name, char *buffer, int len)
127 {
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;
135 }
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;
143 }
144
145 DIR *
openxdir(const char * path,unsigned att_mask)146 openxdir(const char *path, unsigned att_mask)
147 {
148 DIR *dir;
149 char name[MAXPATHLEN + 3];
150 Word rc;
151
152 dir = malloc(sizeof(DIR));
153 if (dir == NULL) {
154 errno = ENOMEM;
155 return NULL;
156 }
157
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 ':':;
166 }
167 strcat(name, ".");
168 if (!abs_path(name, dir->name, MAXPATHLEN + 1))
169 strcpy(dir->name, name);
170 if (dir->name[strlen(dir->name) - 1] == '\\')
171 strcat(dir->name, "*");
172 else
173 strcat(dir->name, "\\*");
174
175 dir->fstype = getFSType(dir->name);
176 dir->attrmask = att_mask | A_DIR;
177
178 dir->handle = HDIR_CREATE;
179 dir->count = 100;
180 #if OS2 >= 2
181 rc = DosFindFirst(dir->name, &dir->handle, dir->attrmask,
182 dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD);
183 #else
184 rc = DosFindFirst((PSZ)dir->name, &dir->handle, dir->attrmask,
185 (PFILEFINDBUF)dir->ffbuf, sizeof dir->ffbuf, &dir->count, 0);
186 #endif
187 switch (rc) {
188 default:
189 free(dir);
190 error(rc);
191 return NULL;
192 case NO_ERROR:
193 case ERROR_NO_MORE_FILES:;
194 }
195
196 dir->number = 0;
197 dir->index = 0;
198 dir->next = (FFBUF *)dir->ffbuf;
199
200 return (DIR *)dir;
201 }
202
203 DIR *
opendir(const char * pathname)204 opendir(const char *pathname)
205 {
206 return openxdir(pathname, 0);
207 }
208
209 struct dirent *
readdir(DIR * dir)210 readdir(DIR *dir)
211 {
212 static int dummy_ino = 2;
213
214 if (dir->index == dir->count) {
215 Word rc;
216 dir->count = 100;
217 #if OS2 >= 2
218 rc = DosFindNext(dir->handle, dir->ffbuf,
219 sizeof dir->ffbuf, &dir->count);
220 #else
221 rc = DosFindNext(dir->handle, (PFILEFINDBUF)dir->ffbuf,
222 sizeof dir->ffbuf, &dir->count);
223 #endif
224 if (rc) {
225 error(rc);
226 return NULL;
227 }
228
229 dir->index = 0;
230 dir->next = (FFBUF *)dir->ffbuf;
231 }
232
233 if (dir->index == dir->count)
234 return NULL;
235
236 memcpy(dir->entry.d_name, dir->next->achName, dir->next->cchName);
237 dir->entry.d_name[dir->next->cchName] = '\0';
238 dir->entry.d_ino = dummy_ino++;
239 dir->entry.d_reclen = dir->next->cchName;
240 dir->entry.d_namlen = dir->next->cchName;
241 dir->entry.d_size = dir->next->cbFile;
242 dir->entry.d_attribute = dir->next->attrFile;
243 dir->entry.d_time = *(USHORT *)&dir->next->ftimeLastWrite;
244 dir->entry.d_date = *(USHORT *)&dir->next->fdateLastWrite;
245
246 switch (dir->fstype) {
247 case 'F': /* FAT */
248 case 'C': /* CDFS */
249 if (dir->next->attrFile & FILE_DIRECTORY)
250 strupr(dir->entry.d_name);
251 else
252 strlwr(dir->entry.d_name);
253 }
254
255 #if OS2 >= 2
256 dir->next = (FFBUF *)((BYTE *)dir->next + dir->next->oNextEntryOffset);
257 #else
258 dir->next = (FFBUF *)((BYTE *)dir->next->achName + dir->next->cchName + 1);
259 #endif
260 ++dir->number;
261 ++dir->index;
262
263 return &dir->entry;
264 }
265
266 long
telldir(DIR * dir)267 telldir(DIR *dir)
268 {
269 return dir->number;
270 }
271
272 void
seekdir(DIR * dir,long off)273 seekdir(DIR *dir, long off)
274 {
275 if (dir->number > off) {
276 char name[MAXPATHLEN + 2];
277 Word rc;
278
279 DosFindClose(dir->handle);
280
281 strcpy(name, dir->name);
282 strcat(name, "*");
283
284 dir->handle = HDIR_CREATE;
285 dir->count = 32767;
286 #if OS2 >= 2
287 rc = DosFindFirst(name, &dir->handle, dir->attrmask,
288 dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD);
289 #else
290 rc = DosFindFirst((PSZ)name, &dir->handle, dir->attrmask,
291 (PFILEFINDBUF)dir->ffbuf, sizeof dir->ffbuf, &dir->count, 0);
292 #endif
293 switch (rc) {
294 default:
295 error(rc);
296 return;
297 case NO_ERROR:
298 case ERROR_NO_MORE_FILES:;
299 }
300
301 dir->number = 0;
302 dir->index = 0;
303 dir->next = (FFBUF *)dir->ffbuf;
304 }
305
306 while (dir->number < off && readdir(dir))
307 ;
308 }
309
310 void
closedir(DIR * dir)311 closedir(DIR *dir)
312 {
313 DosFindClose(dir->handle);
314 free(dir);
315 }
316
317 /*****************************************************************************/
318
319 #ifdef TEST
320
main(int argc,char ** argv)321 main(int argc, char **argv)
322 {
323 int i;
324 DIR *dir;
325 struct dirent *ep;
326
327 for (i = 1; i < argc; ++i) {
328 dir = opendir(argv[i]);
329 if (!dir)
330 continue;
331 while (ep = readdir(dir))
332 if (strchr("\\/:", argv[i][strlen(argv[i]) - 1]))
333 printf("%s%s\n", argv[i], ep->d_name);
334 else
335 printf("%s/%s\n", argv[i], ep->d_name);
336 closedir(dir);
337 }
338
339 return 0;
340 }
341
342 #endif
343
344 #endif /* OS2 */
345