Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * Filename:    dirent.c
3
 *
4
 * Purpose:     UNIX directory services
5
 *
6
 * Routines:    opendir
7
 *              closedir
8
 *              readdir
9
 *              seekdir
10
 *              rewindir
11
 *              telldir
12
 *              freedirlist       s
13
 *
14
 *              * = Routines called by function pointer.
15
 *              s = Static functions.
16
 *
17
 *  Modification History:
18
       25/08/95      - WATCOMC, and extended DIR to include
19
                       d_size, d_attr, d_time and d_date fields.
20
       29/05/96      - Documentation
21
                     - Rewinddir
22
                     - Modified readdir() to return a directory
23
                       based structure.
24
       12/06/00      - Skip volume labels
25
       19/07/00      - Changed search attribute from 0Xff to
26
                       explicit attributes, as 0XFF returns
27
                       only the share name under Win9x.
28
       01/07/01      WIN32
29
*
30
* $Name:  $Source: /cvsroot/device/DEVL/UTILS/LIBWIN32/dirent.c,v $
31
* $Revision: 1.2 $ $Date: 2004/05/10 09:35:02 $ $State: Exp $
32
* $Author: ayoung $ $Locker:  $
33
*.........................................................................*/
34
/*
35
*     Include files
36
*     -------------
37
*/
38
#include <sys/types.h>
39
#include <sys/stat.h>
40
#include <stdio.h>
41
#include <stdlib.h>
42
#include <string.h>
43
#include <errno.h>
44
 
45
#define  _DIRENT_SOURCE
46
#include <unistd.h>
47
#include "dirent.h"
48
#include <windows.h>
49
 
50
#define DISABLE_HARD_ERRORS     SetErrorMode (0)
51
#define ENABLE_HARD_ERRORS      SetErrorMode (SEM_FAILCRITICALERRORS | \
52
                                        SEM_NOOPENFILEERRORBOX)
53
 
54
static void                     freedirlist(struct _dirlist *);
55
 
56
 
57
/*-Open a directory-----------------------------------------------------------
58
 
59
   Synopsis:
60
         DIR *opendir
61
               (
62
                   const char *pName
63
               )
64
 
65
   Purpose:
66
       The opendir() function opens a directory stream corre-
67
       sponding to the directory name, and returns a pointer to
68
       the directory stream. The stream is positioned at the
69
       first entry in the directory.
70
 
71
   Parameters:
72
       const char *pName,  Specifies the name of directory
73
 
74
   Returns:
75
 
76
       The opendir() function returns a pointer to the  directory
77
       stream or NULL if an error occurred, and 'errno' is set to
78
       one of the following manifest constants.
79
 
80
       Constant      Description
81
       ---------------------------------------------------------------
82
       EACESS        Permission denied.
83
       EMFILE        Too many file descriptors in use by process.
84
       ENFILE        Too many files are currently open in the system.
85
       ENOENT        Directory does not exist.
86
       ENOMEM        Insufficient memory to complete the operation.
87
       ENOTDIR       Name is not a directory.
88
 
89
   Notes:
90
       SVID 3, POSIX, BSD 4.3
91
 
92
   See also:
93
       open(2), readdir(3), closedir(3), rewinddir(3),
94
       seekdir(3), telldir(3), scandir(3)
95
----------------------------------------------------------------------------*/
96
DIR *
97
opendir( char *pName )
98
{
99
   static       int id = 1;     /* singleton */
100
   WIN32_FIND_DATA finddata;
101
   HANDLE       hSearch;
102
   struct       _dirlist *pDirlist;
103
   char         path[ MAX_PATH ];
104
   BOOL         isHPFS;
105
   DIR          *pDir;
106
   int          i, len;
107
   int          rc;
108
 
109
/* Copy to working buffer */
110
   if ((len = strlen(pName)) == 0)
111
   {
112
      errno = ENOTDIR;
113
      return (DIR *)NULL;
114
   }
115
 
116
/* Convert path */
117
   if (_fullpath(path, pName, sizeof(path)) == NULL)
118
   {
119
   /* Unknown, assume DOS */
120
      char *last;
121
 
122
      (void) strcpy(path, pName);
123
      for (i = 0; path[i]; i++)
124
          if (path[i] == '/')
125
              path[i] = '\\';       /* convert */
126
      last = &path[len - 1];
127
 
128
   /* Ok, DOS is very picky about its directory names.
129
    * The following are valid.
130
    *  c:/
131
    *  c:.
132
    *  c:name/name1
133
    *
134
    *  c:name/ is not valid
135
    */
136
       if ((*last == '\\') && (len > 1) &&
137
                (!((len == 3) && (path[1] == ':'))))
138
           *(last--) = 0;
139
   }
140
 
141
/* Is a directory ? */
142
   if (strcmp(path, ".") != 0)
143
   {
144
       struct _stat sb;
145
 
146
       DISABLE_HARD_ERRORS;
147
       rc = _stat (path, &sb);
148
       ENABLE_HARD_ERRORS;
149
       if (rc)
150
          return (DIR *)NULL;
151
       if (!S_ISDIR(sb.st_mode))
152
       {
153
          errno = ENOTDIR;
154
          return (DIR *)NULL;
155
       }
156
   }
157
                                /* extended file system */
158
   isHPFS = IsHPFSFileSystem(path);
159
 
160
/* Strip trailing slashes, so we can append "\*.*" */
161
   len = strlen(path);
162
   while (len > 0)
163
   {
164
      len--;
165
      if (path[len] == '\\')
166
         path[len] = '\0';      /* remove slash */
167
      else {
168
         len++;                 /* end of path */
169
         break;
170
      }
171
   }
172
 
173
   path[len++] = '\\';          /* insert pattern */
174
   path[len++] = '*';
175
   path[len++] = '.';
176
   path[len++] = '*';
177
   path[len++] = 0;
178
 
179
/* Create DIR structure */
180
   if ((pDir = (DIR *)calloc(sizeof(DIR), 1)) == (DIR *)NULL)
181
      return (DIR *)NULL;
182
 
183
   if ((pDir->dd_buf =
184
          (char *)malloc(sizeof(struct dirent))) == (char *)NULL)
185
   {
186
      free(pDir);
187
      return (DIR *)NULL;
188
   }
189
 
190
   pDir->dd_id    = id++;       /* generate unique directory identifier */
191
   pDir->dd_fd    = -1;         /* file descriptor */
192
   pDir->dd_loc   = 0L;
193
   pDir->dd_ddloc = (struct _dirlist *)NULL;
194
 
195
/* Open directory */
196
   DISABLE_HARD_ERRORS;
197
   hSearch = FindFirstFile( path, &finddata );
198
   ENABLE_HARD_ERRORS;
199
 
200
   if (hSearch == 0)
201
   {
202
      rc = GetLastError();
203
#if defined(ERROR_EMPTY_DIR)
204
      if (rc == ERROR_EMPTY_DIR)
205
          return (pDir);        /* entry list */
206
#endif
207
      free(pDir);
208
      errno = ENOENT;
209
      return (DIR *)NULL;
210
   }
211
 
212
/* Create directory entries */
213
   do {
214
#if defined(FILE_ATTRIBUTE_VOLUME)
215
   /* Skip volume labels */
216
      if (finddata.ff_attrib & FILE_ATTRIBUTE_VOLUME)
217
         continue;
218
#endif
219
   /* Skip '.' */
220
      if ( strcmp(finddata.cFileName, ".") == 0 )
221
         continue;
222
 
223
   /* Create new entry */
224
      pDirlist = (struct _dirlist *)calloc(1, sizeof(struct _dirlist));
225
      if (pDirlist == (struct _dirlist *)NULL)
226
      {
227
         freedirlist(pDir->dd_contents);
228
         FindClose(hSearch);
229
         return (DIR *)NULL;
230
      }
231
 
232
      pDirlist->dl_entry   = malloc( strlen(finddata.cFileName)+1 );
233
      if (pDirlist->dl_entry == (char *)NULL)
234
      {
235
         free(pDirlist);
236
         freedirlist(pDir->dd_contents);
237
         FindClose(hSearch);
238
         return (DIR *)NULL;
239
      }
240
 
241
      if (pDir->dd_contents)
242
         pDir->dd_current  = pDir->dd_current->dl_next = pDirlist;
243
      else
244
      {
245
         pDir->dd_contents = pDir->dd_current = pDirlist;
246
      }
247
 
248
      (void) strcpy(pDirlist->dl_entry, finddata.cFileName);
249
      if (!isHPFS)
250
         strlwr(pDirlist->dl_entry);
251
//TODO..
252
//    pDirlist->dl_ctime   = finddata.ftCreationTime;
253
//    pDirlist->dl_mtime   = finddata.ftLastWriteTime;
254
//    pDirlist->dl_qsize   = (finddata.nFileSizeHigh * (MAXDWORD+1)) +
255
//                              finddata.nFileSizeLow;
256
 
257
      pDirlist->dl_size2   = finddata.nFileSizeHigh;
258
      pDirlist->dl_size    = finddata.nFileSizeLow;
259
      pDirlist->dl_attr    = finddata.dwFileAttributes;
260
      pDirlist->dl_next    = (struct _dirlist *)NULL;
261
 
262
   } while ( FindNextFile(hSearch, &finddata) );
263
   FindClose( hSearch );
264
   pDir->dd_current = pDir->dd_contents;
265
 
266
   return (pDir);
267
}
268
 
269
 
270
/*-Close a directory----------------------------------------------------------
271
 
272
   Synopsis:
273
         int closedir
274
               (
275
                   DIR *pDir
276
               )
277
 
278
   Purpose:
279
       The  closedir() function closes the directory stream asso-
280
       ciated with dir.  The directory stream descriptor 'pDir' is
281
       not available after this call.
282
 
283
   Parameters:
284
       DIR *pDir,       Specifies the open directory
285
 
286
   Returns:
287
       The  closedir()  function  returns  0  on success or -1 on
288
       failure and 'errno' is set to one of the following manifest
289
       constants.
290
 
291
       Constant      Description
292
       ---------------------------------------------------------------
293
       EBADF         Invalid directory stream descriptor dir.
294
 
295
   Notes:
296
       SVID 3, POSIX, BSD 4.3
297
 
298
   See also
299
       close(2), opendir(3), readdir(3), rewinddir(3),
300
       seekdir(3), telldir(3), scandir(3)
301
----------------------------------------------------------------------------*/
302
int
303
closedir( DIR *pDir )
304
{
305
   if (pDir == (DIR *)NULL)
306
      return 1;                                 /* EBADF */
307
   freedirlist(pDir->dd_contents);
308
   free((char *)pDir->dd_buf);
309
   free((char *)pDir);
310
   return 0;
311
}
312
 
313
 
314
/*-Read a directory-----------------------------------------------------------
315
 
316
   Synopsis:
317
         struct dirent *readdir
318
               (
319
                   DIR  *pDir
320
               )
321
 
322
   Purpose:
323
       The readdir()  function  returns  a  pointer  to a dirent
324
       structure representing the next  directory  entry  in  the
325
       directory  stream  pointed  to be dir.  It returns NULL on
326
       reaching the end-of-file or if an error occurred.
327
 
328
       The data returned by readdir() is overwritten by subse-
329
       quent calls to readdir() for the same directory stream.
330
 
331
   Parameters:
332
       DIR *pDir,    Specifies the open directory
333
 
334
   Returns:
335
       The  readdir()  function  returns  a  pointer  to a dirent
336
       structure, or NULL if an error occurs  or  end-of-file  is
337
       reached, and 'errno' is set to one of the following manifest
338
       constants.
339
 
340
       Constant      Description
341
       ------------------------------------------------------------
342
       EBADF         Invalid directory stream descriptor dir.
343
 
344
   Notes:
345
       SVID 3, POSIX, BSD 4.3
346
 
347
   See also:
348
       read(2), opendir(3), closedir(3), rewinddir(3),
349
       seekdir(3), telldir(3), scandir(3)
350
----------------------------------------------------------------------------*/
351
struct dirent *
352
readdir( DIR *pDir )
353
{
354
   struct _dirlist *pEntry;
355
   struct dirent *pDirent;
356
 
357
/* Retrieve associated fields */
358
   if (pDir->dd_current == (struct _dirlist *)NULL)
359
      return (struct dirent *)NULL;
360
   pEntry  = pDir->dd_current;
361
   pDirent = (struct dirent *)pDir->dd_buf;
362
 
363
/* Standard fields */
364
   strcpy(pDirent->d_name, pEntry->dl_entry);
365
   pDirent->d_namlen = (u_short) strlen(pDirent->d_name);
366
   pDirent->d_reclen = sizeof(struct dirent);
367
   (void)strlwr(pDirent->d_name);
368
   pDirent->d_fileno = 0;
369
 
370
/* The following field are extensions */
371
   pDirent->d_ctime = pEntry->dl_ctime;
372
   pDirent->d_mtime = pEntry->dl_mtime;
373
   pDirent->d_size  = pEntry->dl_size;
374
   pDirent->d_attr  = pEntry->dl_attr;
375
 
376
/* Update current location */
377
   pDir->dd_current = pEntry->dl_next;
378
   pDir->dd_loc++;
379
 
380
   return (pDirent);
381
}
382
 
383
 
384
/*-Set the next of next readdir()---------------------------------------------
385
 
386
   Synopsis:
387
       void seekdir
388
               (
389
                   DIR *pDir, off_t off
390
               )
391
 
392
   Purpose:
393
       The seekdir() function sets the location in the  directory
394
       stream  from  which  the  next  readdir() call will start.
395
       seekdir() should  be  used  with  an  offset  returned  by
396
       telldir().
397
 
398
   Parameters:
399
       DIR *pDir,    Specifies the open directory
400
       off_t off     Offset
401
 
402
   Returns:
403
       The seekdir() function returns no value.
404
 
405
   Notes:
406
       BSD 4.3
407
 
408
   See also:
409
       lseek(2), opendir(3), readdir(3), closedir(3),  rewinddir(3),
410
       telldir(3), scandir(3)
411
----------------------------------------------------------------------------*/
412
void
413
seekdir( DIR *pDir, long off )
414
{
415
   struct _dirlist *pDirlist;
416
   long i = off;
417
 
418
   if (off > 0) {
419
      for (pDirlist = pDir->dd_contents;
420
            --i >= 0 && pDirlist;
421
             pDirlist = pDirlist->dl_next
422
          )
423
         ;
424
      pDir->dd_loc = off - (i+1);
425
      pDir->dd_current = pDirlist;
426
   }
427
}
428
 
429
 
430
/*-Reset directory stream-----------------------------------------------------
431
 
432
   Synopsis:
433
       void rewinddir
434
            (
435
               DIR *pDir
436
            )
437
 
438
   Purpose:
439
       The rewinddir() function resets the position of the direc-
440
       tory stream dir to the beginning of the directory.
441
 
442
   Parameters:
443
       DIR *pDir,    Specifies the open directory
444
 
445
   Returns:
446
       The readdir() function returns no value.
447
 
448
   Notes:
449
       SVID 3, POSIX, BSD 4.3
450
 
451
   See also:
452
       opendir(3), readdir(3), closedir(3), seekdir(3),
453
       telldir(3), scandir(3)
454
----------------------------------------------------------------------------*/
455
void
456
rewinddir( DIR *pDir )
457
{
458
   seekdir(pDir, (long)0);
459
}
460
 
461
 
462
/*-Return current location in directory stream-------------------------------
463
 
464
   Synopsis:
465
       long telldir
466
            (
467
               DIR *pDir
468
            )
469
 
470
   Purpose:
471
       The telldir() function returns the current location
472
       associated with the directory stream dir.
473
 
474
   Parameters:
475
       DIR *pDir,    Specifies the open directory
476
 
477
   Returns:
478
       The telldir() function returns the current location in the
479
       directory stream or -1 if an error occurs.
480
 
481
       EBADF         Invalid directory stream descriptor dir.
482
 
483
   Notes:
484
       BSD 4.3
485
 
486
   See also;
487
       opendir(3), readdir(3), closedir(3), rewinddir(3),
488
       seekdir(3), scandir(3)
489
----------------------------------------------------------------------------*/
490
long
491
telldir( DIR *pDir )
492
{
493
   return (pDir->dd_loc);
494
}
495
 
496
 
497
/*
498
 * IsHPFS ---
499
 *      Is High Performance File System
500
 */
501
int
502
IsHPFSFileSystem( const char *directory )
503
{
504
        char             bName[4];
505
        DWORD            flags;
506
        DWORD            maxname;
507
        BOOL             rc;
508
        unsigned int     nDrive;
509
        char             szCurDir [MAX_PATH];
510
 
511
        if (isalpha (directory[0]) && (directory[1] == ':'))
512
                nDrive = toupper (directory[0]) - '@';
513
        else
514
        {
515
                GetCurrentDirectory (MAX_PATH, szCurDir);
516
                nDrive = szCurDir[0] - 'A' + 1;
517
        }
518
 
519
/* Set up the drive name */
520
        strcpy(bName, "x:\\");
521
        bName[0] = (char) (nDrive + '@');
522
 
523
/* Read the volume info, if we fail - assume non-HPFS */
524
        DISABLE_HARD_ERRORS;
525
        rc = GetVolumeInformation (bName, (LPTSTR)NULL, 0,
526
                (LPDWORD)NULL, &maxname, &flags, (LPTSTR)NULL, 0);
527
        ENABLE_HARD_ERRORS;
528
 
529
        return ((rc) && (flags & (FS_CASE_SENSITIVE | \
530
                        FS_CASE_IS_PRESERVED))) ? TRUE : FALSE;
531
}
532
 
533
 
534
/*
535
 * freedirlist ---
536
 *      Dispose of the directory list
537
 */
538
static void
539
freedirlist( struct _dirlist *pDirlist )
540
{
541
   struct _dirlist *opDirlist;
542
 
543
   while (pDirlist)
544
   {
545
      if (pDirlist->dl_entry)
546
         free(pDirlist->dl_entry);
547
      pDirlist = (opDirlist = pDirlist)->dl_next;
548
      free(opDirlist);
549
   }
550
}