2 * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
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
49 * Operating system includes.
52 #include <sys/types.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
67 * Objects of the following type are used to maintain the resources
68 * needed to read directories.
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 */
75 struct dirent
*buffer
; /* A buffer used by the threaded version of */
77 int buffer_dim
; /* The allocated size of buffer[] */
81 static int _dr_path_is_dir(const char *pathname
);
83 /*.......................................................................
84 * Create a new DirReader object.
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
));
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().
113 * Allocate a place to record error messages.
115 dr
->err
= _new_ErrMsg();
117 return _del_DirReader(dr
);
121 /*.......................................................................
122 * Delete a DirReader object.
125 * dr DirReader * The object to be deleted.
127 * return DirReader * The deleted object (always NULL).
129 DirReader
*_del_DirReader(DirReader
*dr
)
136 dr
->err
= _del_ErrMsg(dr
->err
);
142 /*.......................................................................
143 * Open a new directory.
146 * dr DirReader * The directory reader resource object.
147 * path const char * The directory to be opened.
149 * errmsg char ** If an error occurs and errmsg isn't NULL, a
150 * pointer to an error description will be assigned
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
)) {
168 _err_record_msg(dr
->err
, "Can't open directory: ", path
, END_ERR_MSG
);
169 *errmsg
= _err_get_msg(dr
->err
);
174 * Attempt to open the directory.
179 _err_record_msg(dr
->err
, "Can't open directory: ", path
, END_ERR_MSG
);
180 *errmsg
= _err_get_msg(dr
->err
);
185 * If using POSIX threads, allocate a buffer for readdir_r().
190 int name_max
= pathconf(path
, _PC_NAME_MAX
);
197 _err_record_msg(dr
->err
, "Unable to deduce readdir() buffer size.",
199 *errmsg
= _err_get_msg(dr
->err
);
205 * How big a buffer do we need to allocate?
207 size
= sizeof(struct dirent
) + name_max
;
211 if(size
> dr
->buffer_dim
|| !dr
->buffer
) {
212 struct dirent
*buffer
= (struct dirent
*) (dr
->buffer
?
213 realloc(dr
->buffer
, size
) :
217 _err_record_msg(dr
->err
, "Insufficient memory for readdir() buffer.",
219 *errmsg
= _err_get_msg(dr
->err
);
226 dr
->buffer_dim
= size
;
231 * Record the successfully opened directory.
237 /*.......................................................................
238 * If the DirReader object is currently contains an open directory,
242 * dr DirReader * The directory reader resource object.
244 void _dr_close_dir(DirReader
*dr
)
250 _err_clear_msg(dr
->err
);
254 /*.......................................................................
255 * Read the next file from the directory opened with _dr_open_dir().
258 * dr DirReader * The directory reader resource object.
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?
270 * Read the next directory entry.
273 if(readdir_r(dr
->dir
, dr
->buffer
, &dr
->file
) == 0 && dr
->file
)
274 return dr
->file
->d_name
;
276 dr
->file
= readdir(dr
->dir
);
278 return dr
->file
->d_name
;
282 * When the end of a directory is reached, close it.
288 /*.......................................................................
289 * Return 1 if the specified pathname refers to a directory.
292 * pathname const char * The path to test.
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)
306 * Is the file a directory?
308 return S_ISDIR(statbuf
.st_mode
) != 0;
311 #endif /* ifndef WITHOUT_FILE_SYSTEM */