ca6155f090975b8ad9d33e2c2d28e048ae39c4f7
[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   char buf[4096];
28   struct rxpd_file* self = NULL;
29
30   while (*filename == '/')
31     ++filename;
32
33   if (!filename ||
34       strcspn(filename, RXPD_FILE_ILG_CHARS) != strlen (filename) ||
35       strstr (filename, "../") ||
36       strstr (filename, "/./") ||
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   strcpy (buf, base->basedir);
44   strcat (buf, filename);
45   filename = rxpd_strdup (buf);
46
47   self = rxpd_malloc (sizeof (struct rxpd_file));
48   self->filename = filename;
49   self->base = base;
50   pth_rwlock_init (&self->lock);
51
52   psplay_init (&self->node, filename + strlen (base->basedir));
53   llist_init (&self->rules);
54
55   psplay_insert (&base->files, &self->node);
56
57   rxpd_log (base, LOG_INFO, "new file: '%s'\n", filename);
58   return self;
59 }
60
61 void
62 rxpd_file_delete (struct rxpd_file* self)
63 {
64   if (self)
65     {
66       rxpd_file_rules_delete (self);
67       psplay_remove (&self->base->files, &self->node);
68       free ((void*)self->filename);
69       free (self);
70     }
71 }
72
73 struct rxpd_file*
74 rxpd_file_rules_delete (struct rxpd_file* self)
75 {
76   if (self)
77     {
78       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RW, FALSE, NULL);
79       LLIST_WHILE_HEAD (&self->rules, n)
80         {
81           struct rxpd_rule* node = (struct rxpd_rule*)n;
82           rxpd_rule_delete (node);
83         }
84       pth_rwlock_release (&self->lock);
85     }
86   return self;
87 }
88
89 int
90 rxpd_file_load (struct rxpd_file* self)
91 {
92   FILE* f = fopen (self->filename, "r");
93   if (f)
94     {
95       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RW, FALSE, NULL);
96
97       /* First purge old rules */
98       LLIST_WHILE_HEAD (&self->rules, n)
99         {
100           struct rxpd_rule* node = (struct rxpd_rule*)n;
101           rxpd_rule_delete (node);
102         }
103
104       // TODO test excess line length = error
105       char buf[4096];
106
107       rxpd_log (self->base, LOG_NOTICE, "loading '%s'\n", self->filename);
108
109       while (fgets (buf, 4096, f))
110         {
111           size_t last = strlen(buf);
112           if (buf[last-1] == '\n')
113             buf[last-1] = '\0';
114
115           struct rxpd_rule* rule;
116           rule = rxpd_rule_new (buf);
117           rxpd_log (self->base, LOG_DEBUG, "new rule '%s'\n", rule->string);
118
119           llist_insert_tail (&self->rules, &rule->node);
120         }
121
122       pth_rwlock_release (&self->lock);
123       fclose (f);
124       return 1;
125     }
126   else
127     {
128       rxpd_log (self->base, LOG_ERR, "failed loading '%s'\n", self->filename);
129       return 0;
130     }
131 }
132
133
134 int
135 rxpd_file_save (struct rxpd_file* self)
136 {
137   char* filename = strdupa (self->filename);
138
139   char* slash = filename;
140
141   while ((slash = strchr (slash+1, '/')))
142     {
143       *slash = '\0';
144       mkdir(filename, 0777);
145       *slash = '/';
146     }
147
148   FILE* f = fopen (filename, "w");
149   if (f)
150     {
151       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RD, FALSE, NULL);
152
153       LLIST_FOREACH (&self->rules, n)
154         {
155           struct rxpd_rule* node = (struct rxpd_rule*)n;
156           if (node->atime != (time_t)-1)
157             fprintf (f, "%ld:%s\n", node->atime, node->string);
158           else if (*node->string != '#')
159             fprintf (f, ":%s\n", node->string);
160           else
161             fprintf (f, "%s\n", node->string);
162         }
163
164       pth_rwlock_release (&self->lock);
165       fclose (f);
166       rxpd_log (self->base, LOG_NOTICE, "saved '%s'\n", filename);
167       return 1;
168     }
169   else
170     {
171       rxpd_log (self->base, LOG_ERR, "failed saving '%s'\n", filename);
172       return 0;
173     }
174 }
175
176 struct rxpd_file*
177 rxpd_file_dump (struct rxpd_file* self, struct rxpd_buffer* out)
178 {
179   if (self)
180     {
181       if (llist_is_empty (&self->rules))
182         rxpd_buffer_printf (out, "#OK:\n");
183       else
184         {
185           pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RD, FALSE, NULL);
186
187           LLIST_FOREACH (&self->rules, n)
188             {
189               struct rxpd_rule* rule = (struct rxpd_rule*)n;
190               if (rule->atime != (time_t)-1)
191                 rxpd_buffer_printf (out, "%ld:%s\n", rule->atime, rule->string);
192               else if (*rule->string != '#')
193                 rxpd_buffer_printf (out, ":%s\n", rule->string);
194               else
195                 rxpd_buffer_printf (out, "%s\n", rule->string);
196             }
197           pth_rwlock_release (&self->lock);
198         }
199     }
200
201   return self;
202 }
203
204 int
205 rxpd_file_cmp (const void* A, const void* B)
206 {
207   return strcmp (A, B);
208 }
209
210