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