1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997,2008 Oracle.  All rights reserved.
5 *
6 * $Id: os_dir.c,v 12.18 2008/01/31 17:34:17 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#define	__INCLUDE_DIRECTORY	1
12#include "db_int.h"
13
14/*
15 * __os_dirlist --
16 *	Return a list of the files in a directory.
17 *
18 * PUBLIC: int __os_dirlist __P((ENV *, const char *, int, char ***, int *));
19 */
20int
21__os_dirlist(env, dir, returndir, namesp, cntp)
22	ENV *env;
23	const char *dir;
24	int returndir, *cntp;
25	char ***namesp;
26{
27	DB_ENV *dbenv;
28	struct dirent *dp;
29	DIR *dirp;
30	struct stat sb;
31	int arraysz, cnt, ret;
32	char **names, buf[DB_MAXPATHLEN];
33
34	*namesp = NULL;
35	*cntp = 0;
36
37	dbenv = env == NULL ? NULL : env->dbenv;
38
39	if (dbenv != NULL &&
40	    FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
41		__db_msg(env, "fileops: directory list %s", dir);
42
43	if (DB_GLOBAL(j_dirlist) != NULL)
44		return (DB_GLOBAL(j_dirlist)(dir, namesp, cntp));
45
46	if ((dirp = opendir(CHAR_STAR_CAST dir)) == NULL)
47		return (__os_get_errno());
48	names = NULL;
49	for (arraysz = cnt = 0; (dp = readdir(dirp)) != NULL;) {
50		snprintf(buf, sizeof(buf), "%s/%s", dir, dp->d_name);
51
52		RETRY_CHK(stat(buf, &sb), ret);
53		if (ret != 0) {
54			ret = __os_posix_err(ret);
55			goto err;
56		}
57
58		/*
59		 * We return regular files, and optionally return directories
60		 * (except for dot and dot-dot).
61		 *
62		 * Shared memory files are of a different type on QNX, and we
63		 * return those as well.
64		 */
65#ifdef HAVE_QNX
66		if (!S_ISREG(sb.st_mode) && !S_TYPEISSHM(&sb)) {
67#else
68		if (!S_ISREG(sb.st_mode)) {
69#endif
70			if (!returndir || !S_ISDIR(sb.st_mode))
71				continue;
72			if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
73			    (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
74				continue;
75		}
76
77		if (cnt >= arraysz) {
78			arraysz += 100;
79			if ((ret = __os_realloc(env,
80			    (u_int)arraysz * sizeof(names[0]), &names)) != 0)
81				goto err;
82		}
83		if ((ret = __os_strdup(env, dp->d_name, &names[cnt])) != 0)
84			goto err;
85		cnt++;
86	}
87	(void)closedir(dirp);
88
89	*namesp = names;
90	*cntp = cnt;
91	return (0);
92
93err:	if (names != NULL)
94		__os_dirfree(env, names, cnt);
95	if (dirp != NULL)
96		(void)closedir(dirp);
97	return (ret);
98}
99
100/*
101 * __os_dirfree --
102 *	Free the list of files.
103 *
104 * PUBLIC: void __os_dirfree __P((ENV *, char **, int));
105 */
106void
107__os_dirfree(env, names, cnt)
108	ENV *env;
109	char **names;
110	int cnt;
111{
112	if (DB_GLOBAL(j_dirfree) != NULL)
113		DB_GLOBAL(j_dirfree)(names, cnt);
114	else {
115		while (cnt > 0)
116			__os_free(env, names[--cnt]);
117		__os_free(env, names);
118	}
119}
120