Added silc_file_stat, silc_file_fstat and silc_file_fsize
[runtime.git] / lib / silcutil / silcfileutil.c
1 /*
2
3   silcfileutil.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 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 "silcruntime.h"
21
22 /* Opens a file indicated by the filename `filename' with flags indicated
23    by the `flags'. */
24
25 int silc_file_open(const char *filename, int flags)
26 {
27   return silc_file_open_mode(filename, flags, 0600);
28 }
29
30 /* Opens a file indicated by the filename `filename' with flags indicated
31    by the `flags', and with the specified `mode'. */
32
33 int silc_file_open_mode(const char *filename, int flags, int mode)
34 {
35   int fd = open(filename, flags, mode);
36   if (fd < 0)
37     silc_set_errno_posix(errno);
38   return fd;
39 }
40
41 /* Reads data from file descriptor `fd' to `buf'. */
42
43 int silc_file_read(int fd, unsigned char *buf, SilcUInt32 buf_len)
44 {
45   int ret = read(fd, (void *)buf, buf_len);
46   if (ret < 0)
47     silc_set_errno_posix(errno);
48   return ret;
49 }
50
51 /* Writes `buffer' of length of `len' to file descriptor `fd'. */
52
53 int silc_file_write(int fd, const char *buffer, SilcUInt32 len)
54 {
55   int ret = write(fd, (const void *)buffer, len);
56   if (ret < 0)
57     silc_set_errno_posix(errno);
58   return ret;
59 }
60
61 /* Closes file descriptor */
62
63 int silc_file_close(int fd)
64 {
65   int ret = close(fd);
66   if (ret < 0)
67     silc_set_errno_posix(errno);
68   return ret;
69 }
70
71 /* Writes a buffer to the file. */
72
73 int silc_file_writefile(const char *filename, const char *buffer,
74                         SilcUInt32 len)
75 {
76   int fd;
77   int flags = O_CREAT | O_WRONLY | O_TRUNC;
78
79 #if defined(O_BINARY)
80   flags |= O_BINARY;
81 #endif /* O_BINARY */
82
83   if ((fd = open(filename, flags, 0644)) == -1) {
84     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
85                     silc_errno_string(silc_errno)));
86     return -1;
87   }
88
89   if (silc_file_write(fd, buffer, len) == -1) {
90     SILC_LOG_ERROR(("Cannot write to file %s: %s", filename,
91                     silc_errno_string(silc_errno)));
92     silc_file_close(fd);
93     return -1;
94   }
95
96 #ifdef SILC_UNIX
97   fsync(fd);
98 #endif /* SILC_UNIX */
99
100   return silc_file_close(fd);
101 }
102
103 /* Writes a buffer to the file.  If the file is created specific mode is
104    set to the file. */
105
106 int silc_file_writefile_mode(const char *filename, const char *buffer,
107                              SilcUInt32 len, int mode)
108 {
109   int fd;
110   int flags = O_CREAT | O_WRONLY | O_TRUNC;
111
112 #if defined(O_BINARY)
113   flags |= O_BINARY;
114 #endif /* O_BINARY */
115
116   if ((fd = open(filename, flags, mode)) == -1) {
117     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
118                     silc_errno_string(silc_errno)));
119     return -1;
120   }
121
122   if ((silc_file_write(fd, buffer, len)) == -1) {
123     SILC_LOG_ERROR(("Cannot write to file %s: %s", filename,
124                     silc_errno_string(silc_errno)));
125     silc_file_close(fd);
126     return -1;
127   }
128
129 #ifdef SILC_UNIX
130   fsync(fd);
131 #endif /* SILC_UNIX */
132
133   return silc_file_close(fd);
134 }
135
136 /* Reads a file to a buffer. The allocated buffer is returned. Length of
137    the file read is returned to the return_len argument. */
138
139 char *silc_file_readfile(const char *filename, SilcUInt32 *return_len,
140                          SilcStack stack)
141 {
142   int fd;
143   unsigned char *buffer;
144   int filelen;
145
146   fd = silc_file_open(filename, O_RDONLY);
147   if (fd < 0) {
148     if (silc_errno == SILC_ERR_NO_SUCH_FILE)
149       return NULL;
150     SILC_LOG_ERROR(("Cannot open file %s: %s", filename,
151                     silc_errno_string(silc_errno)));
152     return NULL;
153   }
154
155   filelen = lseek(fd, (off_t)0L, SEEK_END);
156   if (filelen < 0) {
157     silc_set_errno_posix(errno);
158     silc_file_close(fd);
159     return NULL;
160   }
161   if (lseek(fd, (off_t)0L, SEEK_SET) < 0) {
162     silc_set_errno_posix(errno);
163     silc_file_close(fd);
164     return NULL;
165   }
166
167   buffer = silc_calloc(filelen + 1, sizeof(*buffer));
168   if (!buffer) {
169     silc_set_errno_posix(errno);
170     silc_file_close(fd);
171     return NULL;
172   }
173
174   if ((silc_file_read(fd, buffer, filelen)) == -1) {
175     memset(buffer, 0, sizeof(buffer));
176     silc_file_close(fd);
177     SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
178                     silc_errno_string(silc_errno)));
179     return NULL;
180   }
181
182   silc_file_close(fd);
183   buffer[filelen] = EOF;
184
185   if (return_len)
186     *return_len = filelen;
187
188   return (char *)buffer;
189 }
190
191 /* Returns the size of `filename'. */
192
193 SilcUInt64 silc_file_size(const char *filename)
194 {
195   SilcFileStatStruct status;
196
197   if (!silc_file_stat(filename, FALSE, &status))
198     return 0;
199
200   return status.size;
201 }
202
203 /* Return file size */
204
205 SilcUInt64 silc_file_fsize(int fd)
206 {
207   SilcFileStatStruct status;
208
209   if (!silc_file_fstat(fd, &status))
210     return 0;
211
212   return status.size;
213 }
214
215 /* Fill file status context */
216
217 static void silc_file_fill_stat(struct stat *status,
218                                 SilcFileStat return_stat)
219 {
220   memset(return_stat, 0, sizeof(*return_stat));
221
222   silc_time_value(status->st_atime * 1000, &return_stat->last_access);
223   silc_time_value(status->st_mtime * 1000, &return_stat->last_mod);
224   silc_time_value(status->st_ctime * 1000, &return_stat->last_change);
225
226   return_stat->rdev = status->st_rdev;
227   return_stat->dev = status->st_dev;
228   return_stat->nlink = status->st_nlink;
229   return_stat->gid = status->st_gid;
230   return_stat->uid = status->st_uid;
231   return_stat->size = status->st_size;
232
233 #if defined(S_IFSOCK)
234   if (status->st_mode & S_IFSOCK)
235     return_stat->mode |= SILC_FILE_IFSOCK;
236 #endif /* S_IFSOCK */
237 #if defined(S_IFLNK)
238   if (status->st_mode & S_IFLNK)
239     return_stat->mode |= SILC_FILE_IFLNK;
240 #endif /* S_IFLNK */
241 #if defined(S_IFREG)
242   if (status->st_mode & S_IFREG)
243     return_stat->mode |= SILC_FILE_IFREG;
244 #endif /* S_IFREG */
245 #if defined(S_IFBLK)
246   if (status->st_mode & S_IFBLK)
247     return_stat->mode |= SILC_FILE_IFBLK;
248 #endif /* S_IFBLK */
249 #if defined(S_IFDIR)
250   if (status->st_mode & S_IFDIR)
251     return_stat->mode |= SILC_FILE_IFDIR;
252 #endif /* S_IFDIR */
253 #if defined(S_IFCHR)
254   if (status->st_mode & S_IFCHR)
255     return_stat->mode |= SILC_FILE_IFCHR;
256 #endif /* S_IFCHR */
257 #if defined(S_IFIFO)
258   if (status->st_mode & S_IFIFO)
259     return_stat->mode |= SILC_FILE_IFIFO;
260 #endif /* S_IFIFO */
261 #if defined(S_IRUSR)
262   if (status->st_mode & S_IRUSR)
263     return_stat->mode |= SILC_FILE_IRUSR;
264 #endif /* S_IRUSR */
265 #if defined(S_IWUSR)
266   if (status->st_mode & S_IWUSR)
267     return_stat->mode |= SILC_FILE_IWUSR;
268 #endif /* S_IWUSR */
269 #if defined(S_IXUSR)
270   if (status->st_mode & S_IXUSR)
271     return_stat->mode |= SILC_FILE_IXUSR;
272 #endif /* S_IXUSR */
273 #if defined(S_IRGRP)
274   if (status->st_mode & S_IRGRP)
275     return_stat->mode |= SILC_FILE_IRGRP;
276 #endif /* S_IRGRP */
277 #if defined(S_IWGRP)
278   if (status->st_mode & S_IWGRP)
279     return_stat->mode |= SILC_FILE_IWGRP;
280 #endif /* S_IWGRP */
281 #if defined(S_IXGRP)
282   if (status->st_mode & S_IXGRP)
283     return_stat->mode |= SILC_FILE_IXGRP;
284 #endif /* S_IXGRP */
285 #if defined(S_IROTH)
286   if (status->st_mode & S_IROTH)
287     return_stat->mode |= SILC_FILE_IROTH;
288 #endif /* S_IROTH */
289 #if defined(S_IWOTH)
290   if (status->st_mode & S_IWOTH)
291     return_stat->mode |= SILC_FILE_IWOTH;
292 #endif /* S_IWOTH */
293 #if defined(S_IXOTH)
294   if (status->st_mode & S_IXOTH)
295     return_stat->mode |= SILC_FILE_IXOTH;
296 #endif /* S_IXOTH */
297 }
298
299 /* Return file status information */
300
301 SilcBool silc_file_stat(const char *filename, SilcBool follow_symlinks,
302                         SilcFileStat return_stat)
303 {
304   struct stat status;
305
306   if (silc_unlikely(!filename || !return_stat)) {
307     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
308     return FALSE;
309   }
310
311   SILC_LOG_DEBUG(("Get status for file '%s'", filename));
312
313   if (!follow_symlinks) {
314     if (silc_unlikely(stat(filename, &status) != 0)) {
315       silc_set_errno_posix(errno);
316       return FALSE;
317     }
318   } else {
319 #ifdef HAVE_LSTAT
320     if (silc_unlikely(lstat(filename, &status) != 0)) {
321       silc_set_errno_posix(errno);
322       return FALSE;
323     }
324 #else
325     if (silc_unlikely(stat(filename, &status) != 0)) {
326       silc_set_errno_posix(errno);
327       return FALSE;
328     }
329 #endif /* HAVE_LSTAT */
330   }
331
332   silc_file_fill_stat(&status, return_stat);
333
334   return TRUE;
335 }
336
337 /* Return file status information. */
338
339 SilcBool silc_file_fstat(int fd, SilcFileStat return_stat)
340 {
341   struct stat status;
342
343   if (silc_unlikely(!return_stat)) {
344     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
345     return FALSE;
346   }
347
348   if (silc_unlikely(fstat(fd, &status) != 0)) {
349     silc_set_errno_posix(errno);
350     return FALSE;
351   }
352
353   silc_file_fill_stat(&status, return_stat);
354
355   return TRUE;
356 }