xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/roken/dirent.c (revision 288bb96063654ec504ca8732afc683d3ebc514b5)
1 /*	$NetBSD: dirent.c,v 1.1.1.1 2011/04/13 18:15:40 elric Exp $	*/
2 
3 /***********************************************************************
4  * Copyright (c) 2009, Secure Endpoints Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * - Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  *
14  * - Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  **********************************************************************/
33 
34 #include<config.h>
35 
36 #include <stdlib.h>
37 #include <io.h>
38 #include <string.h>
39 #include <errno.h>
40 #include "dirent.h"
41 
42 #ifndef _WIN32
43 #error Only implemented for Win32
44 #endif
45 
46 struct _dirent_dirinfo {
47     int             magic;
48     long            n_entries;
49     long            nc_entries;
50     long            cursor;
51     struct dirent **entries;
52 };
53 #define DIRINFO_MAGIC 0xf8c0639d
54 #define IS_DP(p) ((p) && ((DIR *)(p))->magic == DIRINFO_MAGIC)
55 
56 #define INITIAL_ENTRIES 16
57 
58 /**
59  * Create a filespec for use with _findfirst() using a path spec
60  *
61  * If the last component of the path spec contains wildcards, we let
62  * it be.  If the last component doesn't end with a slash, we add one.
63  */
64 static const char *
65 filespec_from_dir_path(const char * path, char * buffer, size_t cch_buffer)
66 {
67     char *comp, *t;
68     size_t pos;
69 
70     if (strcpy_s(buffer, cch_buffer, path) != 0)
71         return NULL;
72 
73     comp = strrchr(buffer, '\\');
74     if (comp == NULL)
75         comp = buffer;
76 
77     t = strrchr(comp, '/');
78     if (t != NULL)
79         comp = t;
80 
81     comp++;
82 
83     pos = strcspn(comp, "*?");
84     if (comp[pos] != '\0')
85         return buffer;
86 
87     /* We don't append a slash if pos == 0 because that changes the
88      * meaning:
89      *
90      * "*.*" is all files in the current directory.
91      * "\*.*" is all files in the root directory of the current drive.
92      */
93     if (pos > 0 && comp[pos - 1] != '\\' &&
94         comp[pos - 1] != '/') {
95         strcat_s(comp, cch_buffer - (comp - buffer), "\\");
96     }
97 
98     strcat_s(comp, cch_buffer - (comp - buffer), "*.*");
99 
100     return buffer;
101 }
102 
103 ROKEN_LIB_FUNCTION DIR * ROKEN_LIB_CALL
104 opendir(const char * path)
105 {
106     DIR *              dp;
107     struct _finddata_t fd;
108     intptr_t           fd_handle;
109     const char         *filespec;
110     char               path_buffer[1024];
111 
112     memset(&fd, 0, sizeof(fd));
113 
114     filespec = filespec_from_dir_path(path, path_buffer, sizeof(path_buffer)/sizeof(char));
115     if (filespec == NULL)
116         return NULL;
117 
118     fd_handle = _findfirst(filespec, &fd);
119 
120     if (fd_handle == -1)
121         return NULL;
122 
123     dp = malloc(sizeof(*dp));
124     if (dp == NULL)
125         goto done;
126 
127     memset(dp, 0, sizeof(*dp));
128     dp->magic      = DIRINFO_MAGIC;
129     dp->cursor     = 0;
130     dp->n_entries  = 0;
131     dp->nc_entries = INITIAL_ENTRIES;
132     dp->entries    = calloc(dp->nc_entries, sizeof(dp->entries[0]));
133 
134     if (dp->entries == NULL) {
135         closedir(dp);
136         dp = NULL;
137         goto done;
138     }
139 
140     do {
141         size_t len = strlen(fd.name);
142         struct dirent * e;
143 
144         if (dp->n_entries == dp->nc_entries) {
145 	    struct dirent ** ne;
146 
147             dp->nc_entries *= 2;
148             ne = realloc(dp->entries, sizeof(dp->entries[0]) * dp->nc_entries);
149 
150             if (ne == NULL) {
151                 closedir(dp);
152                 dp = NULL;
153                 goto done;
154             }
155 
156 	    dp->entries = ne;
157         }
158 
159         e = malloc(sizeof(*e) + len * sizeof(char));
160         if (e == NULL) {
161             closedir(dp);
162             dp = NULL;
163             goto done;
164         }
165 
166         e->d_ino = 0;           /* no inodes :( */
167         strcpy_s(e->d_name, len + 1, fd.name);
168 
169         dp->entries[dp->n_entries++] = e;
170 
171     } while (_findnext(fd_handle, &fd) == 0);
172 
173  done:
174     if (fd_handle != -1)
175         _findclose(fd_handle);
176 
177     return dp;
178 }
179 
180 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
181 closedir(DIR * dp)
182 {
183     if (!IS_DP(dp))
184         return EINVAL;
185 
186     if (dp->entries) {
187         long i;
188 
189         for (i=0; i < dp->n_entries; i++) {
190             free(dp->entries[i]);
191         }
192 
193         free(dp->entries);
194     }
195 
196     free(dp);
197 
198     return 0;
199 }
200 
201 ROKEN_LIB_FUNCTION struct dirent * ROKEN_LIB_CALL
202 readdir(DIR * dp)
203 {
204     if (!IS_DP(dp) ||
205         dp->cursor < 0 ||
206         dp->cursor >= dp->n_entries)
207 
208         return NULL;
209 
210     return dp->entries[dp->cursor++];
211 }
212 
213 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
214 rewinddir(DIR * dp)
215 {
216     if (IS_DP(dp))
217         dp->cursor = 0;
218 }
219 
220 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
221 seekdir(DIR * dp, long offset)
222 {
223     if (IS_DP(dp) && offset >= 0 && offset < dp->n_entries)
224         dp->cursor = offset;
225 }
226 
227 ROKEN_LIB_FUNCTION long ROKEN_LIB_CALL
228 telldir(DIR * dp)
229 {
230     return dp->cursor;
231 }
232