1 /*!
2 \file lib/db/dbmi_base/dirent.c
3
4 \brief DBMI Library (base) - directory entities management
5
6 (C) 1999-2010 by the GRASS Development Team
7
8 This program is free software under the GNU General Public License
9 (>=v2). Read the file COPYING that comes with GRASS for details.
10
11 \author Joel Jones (CERL/UIUC)
12 \author Upgraded to GRASS 5.7 by Radim Blazek
13 */
14
15 #include <string.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <grass/dbmi.h>
19 /* NOTE: these should come from <unistd.h> or from <sys/file.h> */
20 #define R_OK 4
21 #define W_OK 2
22 #define X_OK 1
23
24 #include <sys/types.h>
25 #ifdef USE_DIRECT
26 # include <sys/dir.h>
27 typedef struct direct dir_entry;
28 #else
29 # include <dirent.h>
30 typedef struct dirent dir_entry;
31 #endif
32
33 extern DIR *opendir();
34 extern dir_entry *readdir();
35
36 static int cmp_dirent(const void *, const void *);
37 static int get_perm(char *);
38 static void sort_dirent(dbDirent *, int);
39
40 /*!
41 \brief Read directory and build an array of dbDirent's
42
43 Append one entry with name = NULL to mark end of array
44
45 \param dirname directory name
46 \param[out] n number of entities
47
48 \return pointer to dbDirent
49 \return NULL on error
50 */
db_dirent(const char * dirname,int * n)51 dbDirent *db_dirent(const char *dirname, int *n)
52 {
53 DIR *dp;
54 dir_entry *entry;
55 dbDirent *dirent;
56 int i, count;
57 char *path;
58 int len, max;
59
60 db_clear_error();
61
62 *n = 0;
63 dp = opendir(dirname);
64 if (dp == NULL) {
65 db_syserror(dirname);
66 return (dbDirent *) NULL;
67 }
68
69
70 /* count the number of entries and get the strlen of the longest name */
71 count = 0;
72 max = 0;
73 while ((entry = readdir(dp))) {
74 count++;
75 len = strlen(entry->d_name);
76 if (len > max)
77 max = len;
78 }
79 rewinddir(dp);
80
81 path = db_malloc(strlen(dirname) + max + 2); /* extra 2 for / and NULL */
82 if (path == NULL) {
83 closedir(dp);
84 return (dbDirent *) NULL;
85 }
86 dirent = db_alloc_dirent_array(count);
87 if (dirent == NULL) {
88 closedir(dp);
89 return (dbDirent *) NULL;
90 }
91 *n = count;
92 for (i = 0; i < count; i++) {
93 entry = readdir(dp);
94 if (entry == NULL) /* this shouldn't happen */
95 break;
96
97 if (DB_OK != db_set_string(&dirent[i].name, entry->d_name))
98 break;
99 sprintf(path, "%s/%s", dirname, entry->d_name);
100 dirent[i].perm = get_perm(path);
101 dirent[i].isdir = (db_isdir(path) == DB_OK);
102 }
103 closedir(dp);
104 db_free(path);
105
106 sort_dirent(dirent, *n);
107
108 return dirent;
109 }
110
111 /*!
112 \brief Free dbDirent
113
114 \param dirent pointer to dbDirent
115 \param count number of entities in the array
116 */
db_free_dirent_array(dbDirent * dirent,int count)117 void db_free_dirent_array(dbDirent * dirent, int count)
118 {
119 int i;
120
121 if (dirent) {
122 for (i = 0; i < count; i++)
123 db_free_string(&dirent[i].name);
124 db_free(dirent);
125 }
126 }
127
get_perm(char * path)128 static int get_perm(char *path)
129 {
130 int perm;
131
132 perm = 0;
133
134 if (access(path, R_OK) == 0)
135 perm |= DB_PERM_R;
136 if (access(path, W_OK) == 0)
137 perm |= DB_PERM_W;
138 if (access(path, X_OK) == 0)
139 perm |= DB_PERM_X;
140
141 return perm;
142 }
143
cmp_dirent(const void * aa,const void * bb)144 static int cmp_dirent(const void *aa, const void *bb)
145 {
146 const dbDirent *a = aa;
147 const dbDirent *b = bb;
148
149 return strcmp(db_get_string((dbString *) & a->name),
150 db_get_string((dbString *) & b->name));
151 }
152
sort_dirent(dbDirent * a,int n)153 static void sort_dirent(dbDirent * a, int n)
154 {
155 qsort(a, n, sizeof(dbDirent), cmp_dirent);
156 }
157
158 /*!
159 \brief Allocate dirent array
160
161 \param count number of entities in the array
162
163 \return pointer to dbDirent array
164 \return NULL on failure
165 */
db_alloc_dirent_array(int count)166 dbDirent *db_alloc_dirent_array(int count)
167 {
168 int i;
169 dbDirent *dirent;
170
171 dirent = (dbDirent *) db_calloc(count, sizeof(dbDirent));
172 if (dirent == NULL)
173 return dirent;
174
175 for (i = 0; i < count; i++)
176 db_init_string(&dirent[i].name);
177
178 return dirent;
179 }
180