sd: remove 'ssd' driver support
[unleashed/tickless.git] / usr / src / lib / libtecla / common / direader.c
blobeb4e29a3e7562decc7eaca66c44a9ba3c50c628d
1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
3 *
4 * All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, and/or sell copies of the Software, and to permit persons
11 * to whom the Software is furnished to do so, provided that the above
12 * copyright notice(s) and this permission notice appear in all copies of
13 * the Software and that both the above copyright notice(s) and this
14 * permission notice appear in supporting documentation.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
19 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
21 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
22 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
23 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
24 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 * Except as contained in this notice, the name of a copyright holder
27 * shall not be used in advertising or otherwise to promote the sale, use
28 * or other dealings in this Software without prior written authorization
29 * of the copyright holder.
32 #pragma ident "%Z%%M% %I% %E% SMI"
35 * If file-system access is to be excluded, this module has no function,
36 * so all of its code should be excluded.
38 #ifndef WITHOUT_FILE_SYSTEM
41 * Standard includes.
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <errno.h>
49 * Operating system includes.
51 #include <unistd.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <dirent.h>
56 #include "direader.h"
57 #include "errmsg.h"
60 * Use the reentrant POSIX threads version of readdir()?
62 #if defined(PREFER_REENTRANT) && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199506L
63 #define USE_READDIR_R 1
64 #endif
67 * Objects of the following type are used to maintain the resources
68 * needed to read directories.
70 struct DirReader {
71 ErrMsg *err; /* The error reporting buffer */
72 DIR *dir; /* The directory stream (if open, NULL otherwise) */
73 struct dirent *file; /* The latest directory entry */
74 #ifdef USE_READDIR_R
75 struct dirent *buffer; /* A buffer used by the threaded version of */
76 /* readdir() */
77 int buffer_dim; /* The allocated size of buffer[] */
78 #endif
81 static int _dr_path_is_dir(const char *pathname);
83 /*.......................................................................
84 * Create a new DirReader object.
86 * Output:
87 * return DirReader * The new object, or NULL on error.
89 DirReader *_new_DirReader(void)
91 DirReader *dr; /* The object to be returned */
93 * Allocate the container.
95 dr = (DirReader *) malloc(sizeof(DirReader));
96 if(!dr) {
97 errno = ENOMEM;
98 return NULL;
101 * Before attempting any operation that might fail, initialize the
102 * container at least up to the point at which it can safely be passed
103 * to _del_DirReader().
105 dr->err = NULL;
106 dr->dir = NULL;
107 dr->file = NULL;
108 #ifdef USE_READDIR_R
109 dr->buffer = NULL;
110 dr->buffer_dim = 0;
111 #endif
113 * Allocate a place to record error messages.
115 dr->err = _new_ErrMsg();
116 if(!dr->err)
117 return _del_DirReader(dr);
118 return dr;
121 /*.......................................................................
122 * Delete a DirReader object.
124 * Input:
125 * dr DirReader * The object to be deleted.
126 * Output:
127 * return DirReader * The deleted object (always NULL).
129 DirReader *_del_DirReader(DirReader *dr)
131 if(dr) {
132 _dr_close_dir(dr);
133 #ifdef USE_READDIR_R
134 free(dr->buffer);
135 #endif
136 dr->err = _del_ErrMsg(dr->err);
137 free(dr);
139 return NULL;
142 /*.......................................................................
143 * Open a new directory.
145 * Input:
146 * dr DirReader * The directory reader resource object.
147 * path const char * The directory to be opened.
148 * Input/Output:
149 * errmsg char ** If an error occurs and errmsg isn't NULL, a
150 * pointer to an error description will be assigned
151 * to *errmsg.
152 * Output:
153 * return int 0 - OK.
154 * 1 - Error (see *errmsg for a description).
156 int _dr_open_dir(DirReader *dr, const char *path, char **errmsg)
158 DIR *dir = NULL; /* The directory stream */
160 * If a directory is already open, close it first.
162 (void) _dr_close_dir(dr);
164 * Is the path a directory?
166 if(!_dr_path_is_dir(path)) {
167 if(errmsg) {
168 _err_record_msg(dr->err, "Can't open directory: ", path, END_ERR_MSG);
169 *errmsg = _err_get_msg(dr->err);
171 return 1;
174 * Attempt to open the directory.
176 dir = opendir(path);
177 if(!dir) {
178 if(errmsg) {
179 _err_record_msg(dr->err, "Can't open directory: ", path, END_ERR_MSG);
180 *errmsg = _err_get_msg(dr->err);
182 return 1;
185 * If using POSIX threads, allocate a buffer for readdir_r().
187 #ifdef USE_READDIR_R
189 size_t size;
190 int name_max = pathconf(path, _PC_NAME_MAX);
191 #ifdef NAME_MAX
192 if(name_max < 0)
193 name_max = NAME_MAX;
194 #endif
195 if(name_max < 0) {
196 if(errmsg) {
197 _err_record_msg(dr->err, "Unable to deduce readdir() buffer size.",
198 END_ERR_MSG);
199 *errmsg = _err_get_msg(dr->err);
201 closedir(dir);
202 return 1;
205 * How big a buffer do we need to allocate?
207 size = sizeof(struct dirent) + name_max;
209 * Extend the buffer?
211 if(size > dr->buffer_dim || !dr->buffer) {
212 struct dirent *buffer = (struct dirent *) (dr->buffer ?
213 realloc(dr->buffer, size) :
214 malloc(size));
215 if(!buffer) {
216 if(errmsg) {
217 _err_record_msg(dr->err, "Insufficient memory for readdir() buffer.",
218 END_ERR_MSG);
219 *errmsg = _err_get_msg(dr->err);
221 closedir(dir);
222 errno = ENOMEM;
223 return 1;
225 dr->buffer = buffer;
226 dr->buffer_dim = size;
229 #endif
231 * Record the successfully opened directory.
233 dr->dir = dir;
234 return 0;
237 /*.......................................................................
238 * If the DirReader object is currently contains an open directory,
239 * close it.
241 * Input:
242 * dr DirReader * The directory reader resource object.
244 void _dr_close_dir(DirReader *dr)
246 if(dr && dr->dir) {
247 closedir(dr->dir);
248 dr->dir = NULL;
249 dr->file = NULL;
250 _err_clear_msg(dr->err);
254 /*.......................................................................
255 * Read the next file from the directory opened with _dr_open_dir().
257 * Input:
258 * dr DirReader * The directory reader resource object.
259 * Output:
260 * return char * The name of the new file, or NULL if we reached
261 * the end of the directory.
263 char *_dr_next_file(DirReader *dr)
266 * Are we currently reading a directory?
268 if(dr->dir) {
270 * Read the next directory entry.
272 #ifdef USE_READDIR_R
273 if(readdir_r(dr->dir, dr->buffer, &dr->file) == 0 && dr->file)
274 return dr->file->d_name;
275 #else
276 dr->file = readdir(dr->dir);
277 if(dr->file)
278 return dr->file->d_name;
279 #endif
282 * When the end of a directory is reached, close it.
284 _dr_close_dir(dr);
285 return NULL;
288 /*.......................................................................
289 * Return 1 if the specified pathname refers to a directory.
291 * Input:
292 * pathname const char * The path to test.
293 * Output:
294 * return int 0 - Not a directory.
295 * 1 - pathname[] refers to a directory.
297 static int _dr_path_is_dir(const char *pathname)
299 struct stat statbuf; /* The file-statistics return buffer */
301 * Look up the file attributes.
303 if(stat(pathname, &statbuf) < 0)
304 return 0;
306 * Is the file a directory?
308 return S_ISDIR(statbuf.st_mode) != 0;
311 #endif /* ifndef WITHOUT_FILE_SYSTEM */