1 /*
2 * Copyright 2001-2004 Brandon Long
3 * All Rights Reserved.
4 *
5 * ClearSilver Templating System
6 *
7 * This code is made available under the terms of the ClearSilver License.
8 * http://www.clearsilver.net/license.hdf
9 *
10 */
11
12 #include "cs_config.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <limits.h>
22 #include <dirent.h>
23 #include <sys/stat.h>
24
25 #include "neo_misc.h"
26 #include "neo_err.h"
27 #include "neo_files.h"
28 #include "wildmat.h"
29
ne_mkdirs(const char * path,mode_t mode)30 NEOERR *ne_mkdirs (const char *path, mode_t mode)
31 {
32 char mypath[_POSIX_PATH_MAX];
33 int x;
34 int r;
35
36 strncpy (mypath, path, sizeof(mypath));
37 x = strlen(mypath);
38 if ((x < sizeof(mypath)) && (mypath[x-1] != '/'))
39 {
40 mypath[x] = '/';
41 mypath[x+1] = '\0';
42 }
43
44 for (x = 1; mypath[x]; x++)
45 {
46 if (mypath[x] == '/')
47 {
48 mypath[x] = '\0';
49 #ifdef __MINGW32__
50 /* Braindead MINGW32 doesn't just have a dummy argument for mode */
51 r = mkdir (mypath);
52 #else
53 r = mkdir (mypath, mode);
54 #endif
55
56 if (r == -1 && errno != EEXIST)
57 {
58 return nerr_raise_errno(NERR_SYSTEM, "ne_mkdirs: mkdir(%s, %x) failed", mypath, mode);
59 }
60 mypath[x] = '/';
61 }
62 }
63 return STATUS_OK;
64 }
65
ne_load_file_len(const char * path,char ** str,int * out_len)66 NEOERR *ne_load_file_len (const char *path, char **str, int *out_len)
67 {
68 struct stat s;
69 int fd;
70 int len;
71 int bytes_read;
72
73 *str = NULL;
74 if (out_len) *out_len = 0;
75
76 if (stat(path, &s) == -1)
77 {
78 if (errno == ENOENT)
79 return nerr_raise (NERR_NOT_FOUND, "File %s not found", path);
80 return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path);
81 }
82
83 fd = open (path, O_RDONLY);
84 if (fd == -1)
85 {
86 return nerr_raise_errno (NERR_SYSTEM, "Unable to open file %s", path);
87 }
88 len = s.st_size;
89 *str = (char *) malloc (len + 1);
90
91 if (*str == NULL)
92 {
93 close(fd);
94 return nerr_raise (NERR_NOMEM,
95 "Unable to allocate memory (%d) to load file %s", len + 1, path);
96 }
97 if ((bytes_read = read (fd, *str, len)) == -1)
98 {
99 close(fd);
100 free(*str);
101 return nerr_raise_errno (NERR_SYSTEM, "Unable to read file %s", path);
102 }
103
104 (*str)[bytes_read] = '\0';
105 close(fd);
106 if (out_len) *out_len = bytes_read;
107
108 return STATUS_OK;
109 }
110
ne_load_file(const char * path,char ** str)111 NEOERR *ne_load_file (const char *path, char **str) {
112 return ne_load_file_len (path, str, NULL);
113 }
114
ne_save_file(const char * path,char * str)115 NEOERR *ne_save_file (const char *path, char *str)
116 {
117 NEOERR *err;
118 int fd;
119 int w, l;
120
121 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP );
122 if (fd == -1)
123 {
124 return nerr_raise_errno (NERR_IO, "Unable to create file %s", path);
125 }
126 l = strlen(str);
127 w = write (fd, str, l);
128 if (w != l)
129 {
130 err = nerr_raise_errno (NERR_IO, "Unable to write file %s", path);
131 close (fd);
132 return err;
133 }
134 close (fd);
135
136 return STATUS_OK;
137 }
138
ne_remove_dir(const char * path)139 NEOERR *ne_remove_dir (const char *path)
140 {
141 NEOERR *err;
142 DIR *dp;
143 struct stat s;
144 struct dirent *de;
145 char npath[_POSIX_PATH_MAX];
146
147 if (stat(path, &s) == -1)
148 {
149 if (errno == ENOENT) return STATUS_OK;
150 return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", path);
151 }
152 if (!S_ISDIR(s.st_mode))
153 {
154 return nerr_raise (NERR_ASSERT, "Path %s is not a directory", path);
155 }
156 dp = opendir(path);
157 if (dp == NULL)
158 return nerr_raise_errno (NERR_IO, "Unable to open directory %s", path);
159 while ((de = readdir (dp)) != NULL)
160 {
161 if (strcmp(de->d_name, ".") && strcmp(de->d_name, ".."))
162 {
163 snprintf (npath, sizeof(npath), "%s/%s", path, de->d_name);
164 if (stat(npath, &s) == -1)
165 {
166 if (errno == ENOENT) continue;
167 closedir(dp);
168 return nerr_raise_errno (NERR_SYSTEM, "Unable to stat file %s", npath);
169 }
170 if (S_ISDIR(s.st_mode))
171 {
172 err = ne_remove_dir(npath);
173 if (err) break;
174 }
175 else
176 {
177 if (unlink(npath) == -1)
178 {
179 if (errno == ENOENT) continue;
180 closedir(dp);
181 return nerr_raise_errno (NERR_SYSTEM, "Unable to unlink file %s",
182 npath);
183 }
184 }
185 }
186 }
187 closedir(dp);
188 if (rmdir(path) == -1)
189 {
190 return nerr_raise_errno (NERR_SYSTEM, "Unable to rmdir %s", path);
191 }
192 return STATUS_OK;
193 }
194
ne_listdir(const char * path,ULIST ** files)195 NEOERR *ne_listdir(const char *path, ULIST **files)
196 {
197 return nerr_pass(ne_listdir_fmatch(path, files, NULL, NULL));
198 }
199
_glob_match(void * rock,const char * filename)200 static int _glob_match(void *rock, const char *filename)
201 {
202 return wildmat(filename, rock);
203 }
204
ne_listdir_match(const char * path,ULIST ** files,const char * match)205 NEOERR *ne_listdir_match(const char *path, ULIST **files, const char *match)
206 {
207 return nerr_pass(ne_listdir_fmatch(path, files, _glob_match, (void *)match));
208 }
209
ne_listdir_fmatch(const char * path,ULIST ** files,MATCH_FUNC fmatch,void * rock)210 NEOERR *ne_listdir_fmatch(const char *path, ULIST **files, MATCH_FUNC fmatch,
211 void *rock)
212 {
213 DIR *dp;
214 struct dirent *de;
215 ULIST *myfiles = NULL;
216 NEOERR *err = STATUS_OK;
217
218 if (files == NULL)
219 return nerr_raise(NERR_ASSERT, "Invalid call to ne_listdir_fmatch");
220
221 if (*files == NULL)
222 {
223 err = uListInit(&myfiles, 10, 0);
224 if (err) return nerr_pass(err);
225 }
226 else
227 {
228 myfiles = *files;
229 }
230
231 if ((dp = opendir (path)) == NULL)
232 {
233 return nerr_raise_errno(NERR_IO, "Unable to opendir %s", path);
234 }
235 while ((de = readdir (dp)) != NULL)
236 {
237 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
238 continue;
239
240 if (fmatch != NULL && !fmatch(rock, de->d_name))
241 continue;
242
243 err = uListAppend(myfiles, strdup(de->d_name));
244 if (err) break;
245 }
246 closedir(dp);
247 if (err && *files == NULL)
248 {
249 uListDestroy(&myfiles, ULIST_FREE);
250 }
251 else if (*files == NULL)
252 {
253 *files = myfiles;
254 }
255 return nerr_pass(err);
256 }
257