Added and implemented Silc DIR API.
[crypto.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   SILC_LOG_DEBUG(("Open directory '%s'", name));
46
47   dir = silc_calloc(1, sizeof(*dir));
48   if (!dir)
49     return NULL;
50
51   dir->name = silc_strdup(name);
52   if (!dir->name) {
53     silc_free(dir);
54     return NULL;
55   }
56
57   if (dir->name[strlen(dir->name) - 1] == '/')
58     dir->name[strlen(dir->name) - 1] = '\0';
59
60   dir->dir = opendir(name);
61   if (!dir->dir) {
62     silc_set_errno_posix(errno);
63     silc_free(dir->name);
64     silc_free(dir);
65     return NULL;
66   }
67
68   return dir;
69 }
70
71 /* Close directory */
72
73 void silc_dir_close(SilcDir dir)
74 {
75   if (!dir)
76     return;
77
78   SILC_LOG_DEBUG(("Close directory '%s'", dir->name));
79
80   closedir(dir->dir);
81   silc_free(dir->name);
82   silc_free(dir);
83 }
84
85 /* Read next entry in the directory */
86
87 SilcDirEntry silc_dir_read(SilcDir dir, SilcDirEntryStat *status)
88 {
89   if (!dir) {
90     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
91     return NULL;
92   }
93
94   SILC_LOG_DEBUG(("Read directory '%s'", dir->name));
95
96   dir->entry.entry = readdir(dir->dir);
97   if (!dir->entry.entry) {
98     if (errno)
99       silc_set_errno_posix(errno);
100     return NULL;
101   }
102
103   if (status)
104     *status = silc_dir_entry_stat(dir, &dir->entry);
105
106   return (SilcDirEntry)&dir->entry;
107 }
108
109 /* Rewind directory */
110
111 void silc_dir_rewind(SilcDir dir)
112 {
113   if (!dir)
114     return;
115
116   SILC_LOG_DEBUG(("Rewind directory '%s'", dir->name));
117
118   rewinddir(dir->dir);
119 }
120
121 /* Return directory name */
122
123 const char *silc_dir_name(SilcDir dir)
124 {
125   if (!dir) {
126     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
127     return NULL;
128   }
129
130   return dir->name;
131 }
132
133 /* Return entry name */
134
135 const char *silc_dir_entry_name(SilcDirEntry entry)
136 {
137   if (!entry) {
138     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
139     return NULL;
140   }
141
142   return (const char *)entry->entry->d_name;
143 }
144
145 /* Return entry status information */
146
147 SilcDirEntryStat silc_dir_entry_stat(SilcDir dir, SilcDirEntry entry)
148 {
149   struct stat status;
150   char *name = NULL;
151
152   if (!dir || !entry) {
153     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
154     return NULL;
155   }
156
157   silc_asprintf(&name, "%s/%s", dir->name, entry->entry->d_name);
158   if (!name)
159     return NULL;
160
161   SILC_LOG_DEBUG(("Get status for entry '%s'", name));
162
163   if (lstat(name, &status) != 0) {
164     silc_set_errno_posix(errno);
165     silc_free(name);
166     return NULL;
167   }
168
169   silc_free(name);
170
171   memset(&entry->status, 0, sizeof(entry->status));
172
173   silc_time_value(status.st_atime * 1000, &entry->status.last_access);
174   silc_time_value(status.st_mtime * 1000, &entry->status.last_mod);
175   silc_time_value(status.st_ctime * 1000, &entry->status.last_change);
176
177   entry->status.dev = status.st_dev;
178   entry->status.nlink = status.st_nlink;
179   entry->status.gid = status.st_gid;
180   entry->status.uid = status.st_uid;
181   entry->status.size = status.st_size;
182
183 #if defined(S_IFSOCK)
184   if (status.st_mode & S_IFSOCK)
185     entry->status.mode |= SILC_DIR_ENTRY_IFSOCK;
186 #endif /* S_IFSOCK */
187 #if defined(S_IFLNK)
188   if (status.st_mode & S_IFLNK)
189     entry->status.mode |= SILC_DIR_ENTRY_IFLNK;
190 #endif /* S_IFLNK */
191 #if defined(S_IFREG)
192   if (status.st_mode & S_IFREG)
193     entry->status.mode |= SILC_DIR_ENTRY_IFREG;
194 #endif /* S_IFREG */
195 #if defined(S_IFBLK)
196   if (status.st_mode & S_IFBLK)
197     entry->status.mode |= SILC_DIR_ENTRY_IFBLK;
198 #endif /* S_IFBLK */
199 #if defined(S_IFDIR)
200   if (status.st_mode & S_IFDIR)
201     entry->status.mode |= SILC_DIR_ENTRY_IFDIR;
202 #endif /* S_IFDIR */
203 #if defined(S_IFCHR)
204   if (status.st_mode & S_IFCHR)
205     entry->status.mode |= SILC_DIR_ENTRY_IFCHR;
206 #endif /* S_IFCHR */
207 #if defined(S_IFIFO)
208   if (status.st_mode & S_IFIFO)
209     entry->status.mode |= SILC_DIR_ENTRY_IFIFO;
210 #endif /* S_IFIFO */
211 #if defined(S_IRUSR)
212   if (status.st_mode & S_IRUSR)
213     entry->status.mode |= SILC_DIR_ENTRY_IRUSR;
214 #endif /* S_IRUSR */
215 #if defined(S_IWUSR)
216   if (status.st_mode & S_IWUSR)
217     entry->status.mode |= SILC_DIR_ENTRY_IWUSR;
218 #endif /* S_IWUSR */
219 #if defined(S_IXUSR)
220   if (status.st_mode & S_IXUSR)
221     entry->status.mode |= SILC_DIR_ENTRY_IXUSR;
222 #endif /* S_IXUSR */
223 #if defined(S_IRGRP)
224   if (status.st_mode & S_IRGRP)
225     entry->status.mode |= SILC_DIR_ENTRY_IRGRP;
226 #endif /* S_IRGRP */
227 #if defined(S_IWGRP)
228   if (status.st_mode & S_IWGRP)
229     entry->status.mode |= SILC_DIR_ENTRY_IWGRP;
230 #endif /* S_IWGRP */
231 #if defined(S_IXGRP)
232   if (status.st_mode & S_IXGRP)
233     entry->status.mode |= SILC_DIR_ENTRY_IXGRP;
234 #endif /* S_IXGRP */
235 #if defined(S_IROTH)
236   if (status.st_mode & S_IROTH)
237     entry->status.mode |= SILC_DIR_ENTRY_IROTH;
238 #endif /* S_IROTH */
239 #if defined(S_IWOTH)
240   if (status.st_mode & S_IWOTH)
241     entry->status.mode |= SILC_DIR_ENTRY_IWOTH;
242 #endif /* S_IWOTH */
243 #if defined(S_IXOTH)
244   if (status.st_mode & S_IXOTH)
245     entry->status.mode |= SILC_DIR_ENTRY_IXOTH;
246 #endif /* S_IXOTH */
247
248   return (SilcDirEntryStat)&entry->status;
249 }