1 /*
2 
3     Implementation of POSIX directory browsing functions and types for Win32.
4 
5     Author:  Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
6     History: Created March 1997. Updated June 2003 and July 2012.
7 
8     Copyright Kevlin Henney, 1997, 2003. All rights reserved.
9 
10     Permission to use, copy, modify, and distribute this software and its
11     documentation for any purpose is hereby granted without fee, provided
12     that this copyright and permissions notice appear in all copies and
13     derivatives.
14 
15     This software is supplied "as is" without express or implied warranty.
16 
17     But that said, if there are any problems please get in touch.
18 */
19 
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <dirent.h>
25 #include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
26 
27 #ifdef __cplusplus
28 extern "C"
29 {
30 #endif
31 
32 typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
33 
34 struct DIR
35 {
36     handle_type         handle; /* -1 for failed rewind */
37     struct _finddata_t  info;
38     struct dirent       result; /* d_name null iff first time */
39     char                *name;  /* null-terminated char string */
40 };
41 
opendir(const char * name)42 DIR *opendir(const char *name)
43 {
44     DIR *dir = 0;
45 
46     if(name && name[0])
47     {
48         size_t base_length = strlen(name);
49         const char *all = /* search pattern must end with suitable wildcard */
50             strchr("/\\", name[base_length - 1]) ? "*" : "/*";
51 
52         if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
53            (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
54         {
55             strcat(strcpy(dir->name, name), all);
56 
57             if ((dir->handle = (handle_type)_findfirst(dir->name, &dir->info)) != -1)
58             {
59                 dir->result.d_name = 0;
60                 dir->result.d_type = 0;
61             }
62             else /* rollback */
63             {
64                 free(dir->name);
65                 free(dir);
66                 dir = 0;
67             }
68         }
69         else /* rollback */
70         {
71             free(dir);
72             dir   = 0;
73             errno = ENOMEM;
74         }
75     }
76     else
77     {
78         errno = EINVAL;
79     }
80 
81     return dir;
82 }
83 
closedir(DIR * dir)84 int closedir(DIR *dir)
85 {
86     int result = -1;
87 
88     if(dir)
89     {
90         if(dir->handle != -1)
91         {
92             result = _findclose(dir->handle);
93         }
94 
95         free(dir->name);
96         free(dir);
97     }
98 
99     if(result == -1) /* map all errors to EBADF */
100     {
101         errno = EBADF;
102     }
103 
104     return result;
105 }
106 
readdir(DIR * dir)107 struct dirent *readdir(DIR *dir)
108 {
109     struct dirent *result = 0;
110 
111     if(dir && dir->handle != -1)
112     {
113         if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
114         {
115             result         = &dir->result;
116             result->d_name = dir->info.name;
117             result->d_type = (dir->info.attrib == _A_SUBDIR) ? DT_DIR : DT_UNKNOWN;
118         }
119     }
120     else
121     {
122         errno = EBADF;
123     }
124 
125     return result;
126 }
127 
rewinddir(DIR * dir)128 void rewinddir(DIR *dir)
129 {
130     if(dir && dir->handle != -1)
131     {
132         _findclose(dir->handle);
133         dir->handle = (handle_type)_findfirst(dir->name, &dir->info);
134         dir->result.d_name = 0;
135         dir->result.d_type = 0;
136     }
137     else
138     {
139         errno = EBADF;
140     }
141 }
142 
143 #ifdef __cplusplus
144 }
145 #endif
146