Added SILC Thread Queue API
[silc.git] / lib / silcutil / unix / silcunixdir.c
1 /*
2
3   silcunixdir.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2008 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21
22 /************************** Types and definitions ***************************/
23
24 /* Directory entry context */
25 struct SilcDirEntryStruct {
26   struct dirent *entry;                   /* Entry */
27   SilcDirEntryStatStruct status;          /* Status */
28 };
29
30 /* The directory context */
31 struct SilcDirStruct {
32   DIR *dir;                               /* Directory */
33   char *name;                             /* Directory name */
34   struct SilcDirEntryStruct entry;        /* Current entry */
35 };
36
37 /****************************** SILC Dir API ********************************/
38
39 /* Open directory */
40
41 SilcDir silc_dir_open(const char *name)
42 {
43   SilcDir dir;
44
45   if (!name || !strlen(!name)) {
46     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
47     return NULL;
48   }
49
50   SILC_LOG_DEBUG(("Open directory '%s'", name));
51
52   dir = silc_calloc(1, sizeof(*dir));
53   if (!dir)
54     return NULL;
55
56   dir->name = silc_strdup(name);
57   if (!dir->name) {
58     silc_free(dir);
59     return NULL;
60   }
61
62   if (dir->name[strlen(dir->name) - 1] == '/')
63     dir->name[strlen(dir->name) - 1] = '\0';
64
65   dir->dir = opendir(name);
66   if (!dir->dir) {
67     silc_set_errno_posix(errno);
68     silc_free(dir->name);
69     silc_free(dir);
70     return NULL;
71   }
72
73   return dir;
74 }
75
76 /* Close directory */
77
78 void silc_dir_close(SilcDir dir)
79 {
80   if (!dir)
81     return;
82
83   SILC_LOG_DEBUG(("Close directory '%s'", dir->name));
84
85   closedir(dir->dir);
86   silc_free(dir->name);
87   silc_free(dir);
88 }
89
90 /* Read next entry in the directory */
91
92 SilcDirEntry silc_dir_read(SilcDir dir, SilcDirEntryStat *status)
93 {
94   if (!dir) {
95     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
96     return NULL;
97   }
98
99   SILC_LOG_DEBUG(("Read directory '%s'", dir->name));
100
101   dir->entry.entry = readdir(dir->dir);
102   if (!dir->entry.entry) {
103     if (errno)
104       silc_set_errno_posix(errno);
105     return NULL;
106   }
107
108   if (status)
109     *status = silc_dir_entry_stat(dir, &dir->entry);
110
111   return (SilcDirEntry)&dir->entry;
112 }
113
114 /* Rewind directory */
115
116 void silc_dir_rewind(SilcDir dir)
117 {
118   if (!dir)
119     return;
120
121   SILC_LOG_DEBUG(("Rewind directory '%s'", dir->name));
122
123   rewinddir(dir->dir);
124 }
125
126 /* Return directory name */
127
128 const char *silc_dir_name(SilcDir dir)
129 {
130   if (!dir) {
131     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
132     return NULL;
133   }
134
135   return dir->name;
136 }
137
138 /* Return entry name */
139
140 const char *silc_dir_entry_name(SilcDirEntry entry)
141 {
142   if (!entry) {
143     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
144     return NULL;
145   }
146
147   return (const char *)entry->entry->d_name;
148 }
149
150 /* Return entry status information */
151
152 SilcDirEntryStat silc_dir_entry_stat(SilcDir dir, SilcDirEntry entry)
153 {
154   struct stat status;
155   char *name = NULL;
156
157   if (!dir || !entry) {
158     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
159     return NULL;
160   }
161
162   silc_asprintf(&name, "%s/%s", dir->name, entry->entry->d_name);
163   if (!name)
164     return NULL;
165
166   SILC_LOG_DEBUG(("Get status for entry '%s'", name));
167
168   if (lstat(name, &status) != 0) {
169     silc_set_errno_posix(errno);
170     silc_free(name);
171     return NULL;
172   }
173
174   silc_free(name);
175
176   memset(&entry->status, 0, sizeof(entry->status));
177
178   silc_time_value(status.st_atime * 1000, &entry->status.last_access);
179   silc_time_value(status.st_mtime * 1000, &entry->status.last_mod);
180   silc_time_value(status.st_ctime * 1000, &entry->status.last_change);
181
182   entry->status.dev = status.st_dev;
183   entry->status.nlink = status.st_nlink;
184   entry->status.gid = status.st_gid;
185   entry->status.uid = status.st_uid;
186   entry->status.size = status.st_size;
187
188 #if defined(S_IFSOCK)
189   if (status.st_mode & S_IFSOCK)
190     entry->status.mode |= SILC_DIR_ENTRY_IFSOCK;
191 #endif /* S_IFSOCK */
192 #if defined(S_IFLNK)
193   if (status.st_mode & S_IFLNK)
194     entry->status.mode |= SILC_DIR_ENTRY_IFLNK;
195 #endif /* S_IFLNK */
196 #if defined(S_IFREG)
197   if (status.st_mode & S_IFREG)
198     entry->status.mode |= SILC_DIR_ENTRY_IFREG;
199 #endif /* S_IFREG */
200 #if defined(S_IFBLK)
201   if (status.st_mode & S_IFBLK)
202     entry->status.mode |= SILC_DIR_ENTRY_IFBLK;
203 #endif /* S_IFBLK */
204 #if defined(S_IFDIR)
205   if (status.st_mode & S_IFDIR)
206     entry->status.mode |= SILC_DIR_ENTRY_IFDIR;
207 #endif /* S_IFDIR */
208 #if defined(S_IFCHR)
209   if (status.st_mode & S_IFCHR)
210     entry->status.mode |= SILC_DIR_ENTRY_IFCHR;
211 #endif /* S_IFCHR */
212 #if defined(S_IFIFO)
213   if (status.st_mode & S_IFIFO)
214     entry->status.mode |= SILC_DIR_ENTRY_IFIFO;
215 #endif /* S_IFIFO */
216 #if defined(S_IRUSR)
217   if (status.st_mode & S_IRUSR)
218     entry->status.mode |= SILC_DIR_ENTRY_IRUSR;
219 #endif /* S_IRUSR */
220 #if defined(S_IWUSR)
221   if (status.st_mode & S_IWUSR)
222     entry->status.mode |= SILC_DIR_ENTRY_IWUSR;
223 #endif /* S_IWUSR */
224 #if defined(S_IXUSR)
225   if (status.st_mode & S_IXUSR)
226     entry->status.mode |= SILC_DIR_ENTRY_IXUSR;
227 #endif /* S_IXUSR */
228 #if defined(S_IRGRP)
229   if (status.st_mode & S_IRGRP)
230     entry->status.mode |= SILC_DIR_ENTRY_IRGRP;
231 #endif /* S_IRGRP */
232 #if defined(S_IWGRP)
233   if (status.st_mode & S_IWGRP)
234     entry->status.mode |= SILC_DIR_ENTRY_IWGRP;
235 #endif /* S_IWGRP */
236 #if defined(S_IXGRP)
237   if (status.st_mode & S_IXGRP)
238     entry->status.mode |= SILC_DIR_ENTRY_IXGRP;
239 #endif /* S_IXGRP */
240 #if defined(S_IROTH)
241   if (status.st_mode & S_IROTH)
242     entry->status.mode |= SILC_DIR_ENTRY_IROTH;
243 #endif /* S_IROTH */
244 #if defined(S_IWOTH)
245   if (status.st_mode & S_IWOTH)
246     entry->status.mode |= SILC_DIR_ENTRY_IWOTH;
247 #endif /* S_IWOTH */
248 #if defined(S_IXOTH)
249   if (status.st_mode & S_IXOTH)
250     entry->status.mode |= SILC_DIR_ENTRY_IXOTH;
251 #endif /* S_IXOTH */
252
253   return (SilcDirEntryStat)&entry->status;
254 }