fixed typo
[rxpd] / src / rxpd_file.c
1 /*
2     rxpd_file.c - regex policy daemon
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "rxpd.h"
23
24 struct rxpd_file*
25 rxpd_file_new (struct rxpd_base* base, const char* filename)
26 {
27   struct rxpd_file* self = NULL;
28
29   while (*filename == '/')
30     ++filename;
31
32   if (!filename ||
33       strcspn (filename, RXPD_FILE_ILG_CHARS) != strlen (filename) ||
34       strstr (filename, "../") ||
35       strstr (filename, "/./") ||
36       filename[strlen (filename) - 1] == '/' ||
37       strlen (filename) + strlen (base->basedir) > 4095)
38     {
39       rxpd_log (base, LOG_ERR, "illegal filename: '%s'\n", filename?filename:"");
40       return NULL;
41     }
42
43   self = rxpd_malloc (sizeof (struct rxpd_file));
44   self->base = base;
45   pth_rwlock_init (&self->lock);
46
47   psplay_init (&self->node, rxpd_strdup (filename));
48   llist_init (&self->rules);
49
50   psplay_insert (&base->files, &self->node);
51
52   rxpd_log (base, LOG_INFO, "new file: '%s'\n", filename);
53   return self;
54 }
55
56 void
57 rxpd_file_delete (struct rxpd_file* self)
58 {
59   if (self)
60     {
61       /* psplay remove does not preempt, no locking needed */
62       /* pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RW, FALSE, NULL); */
63       psplay_remove (&self->base->files, &self->node);
64       /* pth_rwlock_release (&self->lock); */
65
66       rxpd_file_rules_delete (self);
67
68       free ((void*)self->node.key);
69       free (self);
70     }
71 }
72
73 void
74 rxpd_file_remove (struct rxpd_file* self)
75 {
76   if (self)
77     {
78       /* psplay remove does not preempt, no locking needed */
79       /* pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RW, FALSE, NULL); */
80       psplay_remove (&self->base->files, &self->node);
81       /* pth_rwlock_release (&self->lock); */
82
83       rxpd_file_rules_delete (self);
84
85       while (1)
86         {
87           rxpd_log (self->base, LOG_INFO, "delete file: '%s'\n", (char*)self->node.key);
88           remove ((char*)self->node.key);
89           char* slash = strrchr ((char*)self->node.key, '/');
90           if (slash)
91             *slash = '\0';
92           else
93             break;
94         }
95
96       free ((void*)self->node.key);
97       free (self);
98     }
99 }
100
101 struct rxpd_file*
102 rxpd_file_rules_delete (struct rxpd_file* self)
103 {
104   if (self)
105     {
106       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RW, FALSE, NULL);
107       LLIST_WHILE_HEAD (&self->rules, n)
108         {
109           struct rxpd_rule* node = (struct rxpd_rule*)n;
110           rxpd_rule_delete (node);
111         }
112       pth_rwlock_release (&self->lock);
113     }
114   return self;
115 }
116
117 int
118 rxpd_file_load (struct rxpd_file* self)
119 {
120   FILE* f = fopen (self->node.key, "r");
121   if (f)
122     {
123       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RW, FALSE, NULL);
124
125       /* First purge old rules */
126       LLIST_WHILE_HEAD (&self->rules, n)
127         {
128           struct rxpd_rule* node = (struct rxpd_rule*)n;
129           rxpd_rule_delete (node);
130         }
131
132       // TODO test excess line length = error
133       char buf[4096];
134
135       rxpd_log (self->base, LOG_NOTICE, "loading '%s'\n", self->node.key);
136
137       while (fgets (buf, 4096, f))
138         {
139           size_t last = strlen(buf);
140           if (buf[last-1] == '\n')
141             buf[last-1] = '\0';
142
143           struct rxpd_rule* rule;
144           rule = rxpd_rule_new (buf, self->base);
145           rxpd_log (self->base, LOG_DEBUG, "new rule '%s'\n", rule->string);
146
147           llist_insert_tail (&self->rules, &rule->node);
148         }
149
150       pth_rwlock_release (&self->lock);
151       fclose (f);
152       return 1;
153     }
154   else
155     {
156       rxpd_log (self->base, LOG_ERR, "failed loading '%s'\n", self->node.key);
157       return 0;
158     }
159 }
160
161
162 int
163 rxpd_file_save (struct rxpd_file* self, int force)
164 {
165   char* filename = strdupa (self->node.key);
166
167   if (!force && access (filename, F_OK))
168     {
169       rxpd_log (self->base, LOG_NOTICE, "not saving non existent file '%s'\n", filename);
170       return 0;
171     }
172
173   char* slash = filename;
174
175   while ((slash = strchr (slash+1, '/')))
176     {
177       *slash = '\0';
178       mkdir (filename, 0777);
179       *slash = '/';
180     }
181
182   FILE* f = fopen (filename, "w");
183   if (f)
184     {
185       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RD, FALSE, NULL);
186
187       LLIST_FOREACH (&self->rules, n)
188         {
189           struct rxpd_rule* node = (struct rxpd_rule*)n;
190           if (node->atime != (time_t)-1)
191             fprintf (f, "%ld:%s\n", node->atime, node->string);
192           else if (*node->string != '#')
193             fprintf (f, ":%s\n", node->string);
194           else
195             fprintf (f, "%s\n", node->string);
196         }
197
198       pth_rwlock_release (&self->lock);
199       fclose (f);
200       rxpd_log (self->base, LOG_NOTICE, "saved '%s'\n", filename);
201       return 1;
202     }
203   else
204     {
205       rxpd_log (self->base, LOG_ERR, "failed saving '%s'\n", filename);
206       return 0;
207     }
208 }
209
210 struct rxpd_file*
211 rxpd_file_dump (struct rxpd_file* self, struct rxpd_buffer* out, const char* fmt)
212 {
213   if (self)
214     {
215       if (llist_is_empty (&self->rules))
216         rxpd_buffer_printf (out, "#OK:\n");
217       else
218         {
219           pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RD, FALSE, NULL);
220
221           LLIST_FOREACH (&self->rules, n)
222             {
223               struct rxpd_rule* rule = (struct rxpd_rule*)n;
224               if (rule->atime != (time_t)-1)
225                 {
226                   if (fmt)
227                     {
228                       char buf[64];
229                       struct tm *time;
230
231                       time = gmtime(&rule->atime);
232                       strftime(buf, sizeof(buf)-1, fmt, time);
233                       rxpd_buffer_printf (out, "%s:%s\n", buf, rule->string);
234                     }
235                   else
236                     rxpd_buffer_printf (out, "%ld:%s\n", rule->atime, rule->string);
237                 }
238               else if (*rule->string != '#')
239                 rxpd_buffer_printf (out, ":%s\n", rule->string);
240               else
241                 rxpd_buffer_printf (out, "%s\n", rule->string);
242             }
243           pth_rwlock_release (&self->lock);
244         }
245     }
246
247   return self;
248 }
249
250 int
251 rxpd_file_cmp (const void* A, const void* B)
252 {
253   return strcmp (A, B);
254 }
255
256