Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * @(#)msd_dir.c 1.4 87/11/06	Public Domain.
3
 *
4
 *  A public domain implementation of BSD directory routines for
5
 *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
6
 *  August 1897
7
 *
8
 *  Modified by Ian Stewartson, Data Logic (istewart@datlog.co.uk).
9
 *
10
 *  Updates:  1.  To support OS/2 1.x
11
 *	      2.  To support HPFS long filenames
12
 *	      3.  To support OS/2 2.x
13
 *	      4.  To support TurboC
14
 *	      5.  To support Windows NT
15
 */
16
 
17
#include <sys/types.h>
18
#include <sys/stat.h>
19
#include <stdio.h>
20
#include <stdlib.h>
21
 
22
#ifndef __TURBOC__
23
#  include <malloc.h>
24
#endif
25
 
26
#include <string.h>
27
#include <limits.h>
28
#include <ctype.h>
29
#include <errno.h>
30
#include <dirent.h>
31
 
32
#ifdef __TURBOC__
33
#  include <dir.h>
34
#endif
35
 
36
#if defined (OS2) || defined (__OS2__)
37
#  define INCL_DOSFILEMGR
38
#  define INCL_DOSMISC
39
#  define INCL_DOSERRORS
40
 
41
#  include <os2.h>
42
#  include <bseerr.h>
43
 
44
#  if defined (__OS2__)
45
#    define DISABLE_HARD_ERRORS	DosError (FERR_DISABLEHARDERR)
46
#    define ENABLE_HARD_ERRORS	DosError (FERR_ENABLEHARDERR)
47
#    define FIND_BUFFER		FILEFINDBUF3
48
#  else
49
#    define DISABLE_HARD_ERRORS	DosError (HARDERROR_DISABLE)
50
#    define ENABLE_HARD_ERRORS	DosError (HARDERROR_ENABLE)
51
#    define FIND_BUFFER		FILEFINDBUF
52
#  endif
53
 
54
#  define ERROR_EMPTY_DIR	ERROR_NO_MORE_FILES
55
 
56
#  define FILE_NAME_E		achName
57
#  define OS_CloseFH(a)		DosFindClose (a)
58
 
59
#elif defined (WIN32)
60
#  include <windows.h>
61
#  define FILE_NAME_E		cFileName
62
#  define OS_CloseFH(a)		FindClose (a)
63
#  define FIND_BUFFER		WIN32_FIND_DATA
64
#  define DISABLE_HARD_ERRORS	SetErrorMode (0)
65
#  define ENABLE_HARD_ERRORS	SetErrorMode (SEM_FAILCRITICALERRORS | \
66
					      SEM_NOOPENFILEERRORBOX);
67
 
68
#  define ERROR_EMPTY_DIR	ERROR_FILE_NOT_FOUND
69
 
70
#else
71
#  include <dos.h>
72
#  define DISABLE_HARD_ERRORS
73
#  define ENABLE_HARD_ERRORS
74
#  define OS_CloseFH(a)	
75
 
76
#  define ERROR_EMPTY_DIR	18
77
#define ERROR_NO_MORE_FILES		18
78
 
79
#  if defined (__TURBOC__)
80
#    define FILE_NAME_E		ff_name
81
#    define FIND_BUFFER		struct ffblk
82
#  else
83
#    define FILE_NAME_E		name
84
#    define FIND_BUFFER		struct find_t
85
#  endif
86
#endif
87
 
88
#if defined (OS2) || defined (__OS2__)
89
#  define ATTRIBUTES		(FILE_DIRECTORY | FILE_HIDDEN | FILE_SYSTEM | \
90
				 FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED)
91
#elif defined (__TURBOC__)
92
#  define ATTRIBUTES		(FA_RDONLY | FA_HIDDEN | FA_SYSTEM | \
93
				 FA_DIREC | FA_ARCH)
94
#else
95
#  define ATTRIBUTES		(_A_SUBDIR | _A_HIDDEN | _A_SYSTEM | \
96
				 _A_NORMAL | _A_RDONLY | _A_ARCH)
97
#endif
98
 
99
/*
100
 * OS/2 2.x has these missing
101
 */
102
 
103
#ifndef ENOTDIR
104
#  define ENOTDIR	120	/* Not a directory			*/
105
#endif
106
 
107
#ifndef S_IFMT
108
#  define	S_IFMT	0xf000	/* type of file				*/
109
#endif
110
 
111
#ifndef S_ISDIR
112
#  define S_ISDIR(m)	((((m) & S_IFMT) == S_IFDIR))
113
#endif
114
 
115
/*
116
 * Internals
117
 */
118
 
119
typedef struct _dircontents	DIRCONT;
120
static void			free_dircontents (DIRCONT *);
121
 
122
/*
123
 * Open the directory stream
124
 */
125
 
126
DIR		*opendir (name)
127
const char	*name;
128
{
129
    struct stat		statb;
130
    DIR			*dirp;
131
    char		*last;
132
    DIRCONT		*dp;
133
    char		*nbuf;
134
    int			len = strlen (name);
135
    unsigned long	rc;
136
    FIND_BUFFER		dtabuf;
137
#if defined (__OS2__)
138
    HDIR		d_handle = HDIR_SYSTEM;
139
    ULONG		d_count = 1;
140
    bool		HPFS = FALSE;
141
#elif defined (OS2)
142
    HDIR		d_handle = HDIR_SYSTEM;
143
    USHORT		d_count = 1;
144
    bool		HPFS = FALSE;
145
#elif defined (WIN32)
146
    HANDLE		d_handle;
147
    bool		HPFS = FALSE;
148
#endif
149
 
150
    if (!len)
151
    {
152
	errno = ENOTDIR;
153
	return (DIR *)NULL;
154
    }
155
 
156
    if ((nbuf = malloc (len + 5)) == (char *)NULL)
157
	return (DIR *) NULL;
158
 
159
    strcpy (nbuf, name);
160
    last = &nbuf[len - 1];
161
 
162
/* Ok, DOS is very picky about its directory names.  The following are
163
 * valid.
164
 *
165
 *  c:/
166
 *  c:.
167
 *  c:name/name1
168
 *
169
 *  c:name/ is not valid
170
 */
171
 
172
    if (((*last == '\\') || (*last == '/')) && (len > 1) &&
173
	(!((len == 3) && (name[1] == ':'))))
174
	*(last--) = 0;
175
 
176
/* Check its a directory */
177
 
178
    DISABLE_HARD_ERRORS;
179
    rc = stat (nbuf, &statb);
180
    ENABLE_HARD_ERRORS;
181
 
182
    if (rc)
183
    {
184
	free (nbuf);
185
	return (DIR *) NULL;
186
    }
187
 
188
    if (!S_ISDIR (statb.st_mode))
189
    {
190
	free (nbuf);
191
	errno = ENOTDIR;
192
	return (DIR *)NULL;
193
    }
194
 
195
    if ((dirp = (DIR *) malloc (sizeof (DIR))) == (DIR *) NULL)
196
    {
197
	free (nbuf);
198
	return (DIR *) NULL;
199
    }
200
 
201
/* Set up to find everything */
202
 
203
    if ((*last != '\\') && (*last != '/'))
204
	strcat (last, "/");
205
 
206
    strcat (last, "*.*");
207
 
208
/* For OS/2, find the file system type */
209
 
210
#if defined (OS2) || defined (__OS2__) || defined (WIN32)
211
    HPFS = IsHPFSFileSystem (nbuf);
212
#endif
213
 
214
    dirp->dd_loc      = 0;
215
    dirp->dd_cp       = (DIRCONT *) NULL;
216
    dirp->dd_contents = (DIRCONT *) NULL;
217
 
218
    DISABLE_HARD_ERRORS;
219
 
220
#if defined (__OS2__)
221
    rc = DosFindFirst (nbuf, &d_handle, ATTRIBUTES, &dtabuf,
222
		       sizeof (FILEFINDBUF3), &d_count, FIL_STANDARD);
223
#elif defined (OS2)
224
    rc = DosFindFirst (nbuf, &d_handle, ATTRIBUTES, &dtabuf,
225
		       sizeof (FILEFINDBUF), &d_count, (ULONG)0);
226
#elif defined (WIN32)
227
    d_handle = FindFirstFile (nbuf, &dtabuf);
228
    rc = (d_handle == INVALID_HANDLE_VALUE) ? GetLastError () : 0;
229
#elif defined (__TURBOC__)
230
    rc = findfirst (nbuf, &dtabuf, ATTRIBUTES);
231
#else
232
    rc = _dos_findfirst (nbuf, ATTRIBUTES, &dtabuf);
233
#endif
234
 
235
    ENABLE_HARD_ERRORS;
236
 
237
/* Check for errors */
238
 
239
    if (rc)
240
    {
241
	free (nbuf);
242
 
243
/* Empty directory */
244
 
245
#if defined (ERROR_EMPTY_DIR)
246
	if (rc == ERROR_EMPTY_DIR)
247
	    return dirp;
248
#endif
249
 
250
	free (dirp);
251
	return (DIR *) NULL;
252
    }
253
 
254
/* Process the directory */
255
 
256
    do
257
    {
258
	if (((dp = (DIRCONT *) malloc (sizeof (DIRCONT))) == (DIRCONT *)NULL) ||
259
	    ((dp->_d_entry = strdup (dtabuf.FILE_NAME_E)) == (char *) NULL))
260
	{
261
	    if (dp->_d_entry != (char *)NULL)
262
		free ((char *)dp);
263
 
264
	    free (nbuf);
265
	    free_dircontents (dirp->dd_contents);
266
 
267
	    OS_CloseFH (d_handle);
268
	    return (DIR *) NULL;
269
	}
270
 
271
#if defined (OS2) || defined (__OS2__) || defined (WIN32)
272
	if (!HPFS)
273
	    strlwr (dp->_d_entry);
274
#else
275
	strlwr (dp->_d_entry);
276
#endif
277
 
278
	if (dirp->dd_contents != (DIRCONT *) NULL)
279
	    dirp->dd_cp = dirp->dd_cp->_d_next = dp;
280
 
281
	else
282
	    dirp->dd_contents = dirp->dd_cp = dp;
283
 
284
	dp->_d_next = (DIRCONT *) NULL;
285
 
286
#if defined (OS2) || defined (__OS2__)
287
	d_count = 1;
288
    } while (DosFindNext (d_handle, &dtabuf, sizeof (FILEFINDBUF),
289
			  &d_count) == 0);
290
#elif defined (WIN32)
291
    } while (FindNextFile (d_handle, &dtabuf));
292
#elif defined (__TURBOC__)
293
    } while (findnext (&dtabuf) == 0);
294
#else
295
    } while (_dos_findnext (&dtabuf) == 0);
296
#endif
297
 
298
    dirp->dd_cp = dirp->dd_contents;
299
    free (nbuf);
300
 
301
    OS_CloseFH (d_handle);
302
    return dirp;
303
}
304
 
305
 
306
/*
307
 * Close the directory stream
308
 */
309
 
310
int	closedir (dirp)
311
DIR	*dirp;
312
{
313
    if (dirp != (DIR *)NULL)
314
    {
315
	free_dircontents (dirp->dd_contents);
316
	free ((char *)dirp);
317
    }
318
 
319
    return 0;
320
}
321
 
322
/*
323
 * Read the next record from the stream
324
 */
325
 
326
struct dirent	*readdir (dirp)
327
DIR		*dirp;
328
{
329
    static struct dirent	dp;
330
 
331
    if ((dirp == (DIR *)NULL) || (dirp->dd_cp == (DIRCONT *) NULL))
332
	return (struct dirent *) NULL;
333
 
334
    dp.d_reclen = strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
335
    dp.d_off    = dirp->dd_loc * 32;
336
    dp.d_ino    = (ino_t)++dirp->dd_loc;
337
    dirp->dd_cp = dirp->dd_cp->_d_next;
338
 
339
    return &dp;
340
}
341
 
342
/*
343
 * Restart the directory stream
344
 */
345
 
346
void	rewinddir (dirp)
347
DIR	*dirp;
348
{
349
    seekdir (dirp, (off_t)0);
350
}
351
 
352
/*
353
 * Move to a know position in the stream
354
 */
355
 
356
void	seekdir (dirp, off)
357
DIR	*dirp;
358
off_t	off;
359
{
360
    long	i = off;
361
    DIRCONT	*dp;
362
 
363
    if ((dirp == (DIR *)NULL) || (off < 0L))
364
	return;
365
 
366
    for (dp = dirp->dd_contents; (--i >= 0) && (dp != (DIRCONT *)NULL);
367
	 dp = dp->_d_next)
368
	;
369
 
370
    dirp->dd_loc = off - (i + 1);
371
    dirp->dd_cp = dp;
372
}
373
 
374
/*
375
 * Get the current position
376
 */
377
 
378
off_t	telldir(dirp)
379
DIR	*dirp;
380
{
381
    return (dirp == (DIR *)NULL) ? (off_t) -1 : dirp->dd_loc;
382
}
383
 
384
/*
385
 * Release the internal structure
386
 */
387
 
388
static void	free_dircontents (dp)
389
DIRCONT		*dp;
390
{
391
    DIRCONT	*odp;
392
 
393
    while ((odp = dp) != (DIRCONT *)NULL)
394
    {
395
	if (dp->_d_entry != (char *)NULL)
396
	    free (dp->_d_entry);
397
 
398
	dp = dp->_d_next;
399
	free ((char *)odp);
400
    }
401
}
402
 
403
/*
404
 * For OS/2, we need to know if we have to convert to lower case.  This
405
 * only applies to non-HPFS (FAT, NETWARE etc) file systems.
406
 */
407
 
408
#if defined (OS2) || defined (__OS2__)
409
 
410
/*
411
 * Define the know FAT systems
412
 */
413
 
414
static char	*FATSystems[] = {"FAT", "NETWARE", (char *)NULL};
415
 
416
/*
417
 * Check for Long filenames
418
 */
419
 
420
bool		IsHPFSFileSystem (char *directory)
421
{
422
    ULONG		lMap;
423
    BYTE		bData[128];
424
    BYTE		bName[3];
425
    int			i;
426
    char		*FName;
427
    unsigned long	rc;
428
#if defined (__OS2__)
429
    ULONG		cbData;
430
    ULONG		nDrive;
431
    PFSQBUFFER2		pFSQ = (PFSQBUFFER2)bData;
432
#else
433
    USHORT		cbData;
434
    USHORT		nDrive;
435
#endif
436
 
437
#ifndef __WATCOMC__
438
    if ( _osmode == DOS_MODE )
439
	return FALSE;
440
#endif
441
 
442
/*
443
 * Mike tells me there are IFS calls to determine this, but he carn't
444
 * remember which.  So we read the partition info and check for HPFS.
445
 */
446
 
447
    if (isalpha (directory[0]) && (directory[1] == ':'))
448
	nDrive = toupper (directory[0]) - '@';
449
 
450
    else
451
	DosQCurDisk (&nDrive, &lMap);
452
 
453
/* Set up the drive name */
454
 
455
    bName[0] = (char) (nDrive + '@');
456
    bName[1] = ':';
457
    bName[2] = 0;
458
 
459
    cbData = sizeof (bData);
460
 
461
/* Read the info, if we fail - assume non-HPFS */
462
 
463
    DISABLE_HARD_ERRORS;
464
 
465
#  ifdef __OS2__
466
    rc = DosQFSAttach (bName, 0, FSAIL_QUERYNAME, pFSQ, &cbData);
467
#  else
468
    rc = DosQFSAttach (bName, 0, FSAIL_QUERYNAME, bData, &cbData, 0L);
469
#  endif
470
 
471
    ENABLE_HARD_ERRORS;
472
 
473
    if (rc)
474
	return FALSE;
475
 
476
#  ifdef __OS2__
477
    FName = pFSQ->szName + pFSQ->cbName + 1;
478
#  else
479
    FName = bData + (*((USHORT *) (bData + 2)) + 7);
480
#  endif
481
 
482
#ifdef TEST
483
    printf ("File System for <%s> = <%s>\n", directory, FName);
484
#endif
485
 
486
    for (i = 0; FATSystems[i] != (char *)NULL; i++)
487
    {
488
        if (stricmp (FName, FATSystems[i]) == 0)
489
	    return FALSE;
490
    }
491
 
492
    return TRUE;
493
}
494
#endif
495
 
496
/*
497
 * Windows NT version
498
 */
499
 
500
#if defined (WIN32) 
501
bool		IsHPFSFileSystem (char *directory)
502
{
503
    char		bName[4];
504
    DWORD		flags;
505
    DWORD		maxname;
506
    BOOL		rc;
507
    unsigned int	nDrive;
508
    char		szCurDir [MAX_PATH];
509
 
510
    if (isalpha (directory[0]) && (directory[1] == ':'))
511
	nDrive = toupper (directory[0]) - '@';
512
 
513
    else
514
    {
515
	GetCurrentDirectory (MAX_PATH, szCurDir);
516
	nDrive = szCurDir[0] - 'A' + 1;
517
    }
518
 
519
/* Set up the drive name */
520
 
521
    strcpy (bName, "x:\\");
522
    bName[0] = (char) (nDrive + '@');
523
 
524
/* Read the volume info, if we fail - assume non-HPFS */
525
 
526
    DISABLE_HARD_ERRORS;
527
 
528
    rc = GetVolumeInformation (bName, (LPTSTR)NULL, 0, (LPDWORD)NULL,
529
			       &maxname, &flags, (LPTSTR)NULL, 0);
530
    ENABLE_HARD_ERRORS;
531
 
532
#ifdef TEST
533
    printf ("File System flags for <%s> = <0x%.8lx> (%d)\n", directory,
534
	    flags, rc);
535
#endif
536
 
537
    return ((rc) && (flags & (FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED)))
538
    		? TRUE : FALSE;
539
}
540
#endif
541
 
542
/*
543
 * Test program
544
 */
545
 
546
#ifdef TEST
547
int	main (int argc, char **argv)
548
{
549
    int			i;
550
    struct dirent	*cdp;
551
    DIR			*dp;
552
 
553
    for (i = 1; i < argc; i++)
554
    {
555
#if defined (OS2) || defined (__OS2__) || defined (WIN32)
556
	printf ("IsHPFSFileSystem returns %d\n", IsHPFSFileSystem (argv[1]));
557
#endif
558
 
559
        if ((dp = opendir (argv[i])) == (DIR *)NULL)
560
	    printf ("Cannot open %s\n", argv[1]);
561
 
562
	else
563
	{
564
	    while ((cdp = readdir (dp)) != (struct dirent *)NULL)
565
		printf ("Found %s\n", cdp->d_name);
566
 
567
	    closedir (dp);
568
	}
569
    }
570
 
571
    return 0;
572
}
573
#endif