1
|
1 /*****************************************************************************/
|
|
2 /* cache.c - contains the cache routines */
|
122
|
3 /* Copyright (C) 1998-2003 Brian Masney <masneyb@gftp.org> */
|
1
|
4 /* */
|
|
5 /* This program is free software; you can redistribute it and/or modify */
|
|
6 /* it under the terms of the GNU General Public License as published by */
|
|
7 /* the Free Software Foundation; either version 2 of the License, or */
|
|
8 /* (at your option) any later version. */
|
|
9 /* */
|
|
10 /* This program is distributed in the hope that it will be useful, */
|
|
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
|
13 /* GNU General Public License for more details. */
|
|
14 /* */
|
|
15 /* You should have received a copy of the GNU General Public License */
|
|
16 /* along with this program; if not, write to the Free Software */
|
|
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */
|
|
18 /*****************************************************************************/
|
|
19
|
|
20 #include "gftp.h"
|
33
|
21 static const char cvsid[] = "$Id$";
|
1
|
22
|
114
|
23 struct gftp_cache_entry_tag
|
|
24 {
|
|
25 char *url,
|
|
26 *file;
|
|
27 int server_type;
|
222
|
28 time_t expiration_date;
|
114
|
29
|
|
30 char *pos1,
|
222
|
31 *pos2,
|
|
32 *pos3;
|
114
|
33 };
|
|
34
|
|
35 typedef struct gftp_cache_entry_tag gftp_cache_entry;
|
|
36
|
|
37
|
|
38 static int
|
|
39 gftp_parse_cache_line (gftp_request * request, gftp_cache_entry * centry,
|
|
40 char *line)
|
|
41 {
|
|
42 char *pos;
|
|
43
|
|
44 memset (centry, 0, sizeof (*centry));
|
|
45
|
|
46 if ((pos = strchr (line, '\t')) == NULL || *(pos + 1) == '\0')
|
|
47 {
|
|
48 if (request != NULL)
|
186
|
49 request->logging_function (gftp_logging_error, request,
|
114
|
50 _("Error: Invalid line %s in cache index file\n"),
|
|
51 line);
|
|
52 return (-1);
|
|
53 }
|
|
54
|
|
55 centry->pos1 = pos;
|
|
56 *pos++ = '\0';
|
|
57 centry->url = line;
|
|
58 centry->file = pos;
|
|
59
|
|
60 if ((pos = strchr (pos, '\t')) == NULL || *(pos + 1) == '\0')
|
|
61 {
|
|
62 if (request != NULL)
|
186
|
63 request->logging_function (gftp_logging_error, request,
|
114
|
64 _("Error: Invalid line %s in cache index file\n"),
|
|
65 line);
|
|
66 return (-1);
|
|
67 }
|
|
68
|
|
69 centry->pos2 = pos;
|
|
70 *pos++ = '\0';
|
|
71 centry->server_type = strtol (pos, NULL, 10);
|
|
72
|
222
|
73 if ((pos = strchr (pos, '\t')) == NULL || *(pos + 1) == '\0')
|
|
74 {
|
|
75 if (request != NULL)
|
|
76 request->logging_function (gftp_logging_error, request,
|
|
77 _("Error: Invalid line %s in cache index file\n"),
|
|
78 line);
|
|
79 return (-1);
|
|
80 }
|
|
81
|
|
82 centry->pos3 = pos;
|
|
83 *pos++ = '\0';
|
|
84 centry->expiration_date = strtol (pos, NULL, 10);
|
|
85
|
114
|
86 return (0);
|
|
87 }
|
|
88
|
|
89
|
182
|
90 static void
|
114
|
91 gftp_restore_cache_line (gftp_cache_entry * centry, char *line)
|
|
92 {
|
|
93 if (centry->pos1 != NULL)
|
|
94 *centry->pos1 = '\t';
|
|
95
|
|
96 if (centry->pos2 != NULL)
|
|
97 *centry->pos2 = '\t';
|
222
|
98
|
|
99 if (centry->pos3 != NULL)
|
|
100 *centry->pos3 = '\t';
|
114
|
101 }
|
|
102
|
1
|
103
|
182
|
104 void
|
|
105 gftp_generate_cache_description (gftp_request * request, char *description,
|
|
106 size_t len, int ignore_directory)
|
|
107 {
|
|
108 g_snprintf (description, len, "%s://%s@%s:%d%s",
|
|
109 request->url_prefix,
|
|
110 request->username == NULL ? "" : request->username,
|
|
111 request->hostname == NULL ? "" : request->hostname,
|
|
112 request->port,
|
|
113 ignore_directory || request->directory == NULL ? "" : request->directory);
|
|
114 }
|
|
115
|
|
116
|
58
|
117 int
|
1
|
118 gftp_new_cache_entry (gftp_request * request)
|
|
119 {
|
58
|
120 char *cachedir, *tempstr, *temp1str;
|
325
|
121 int cache_fd, fd;
|
|
122 intptr_t cache_ttl;
|
58
|
123 ssize_t ret;
|
222
|
124 time_t t;
|
|
125
|
|
126 gftp_lookup_request_option (request, "cache_ttl", &cache_ttl);
|
|
127 time (&t);
|
|
128 t += cache_ttl;
|
1
|
129
|
|
130 cachedir = expand_path (BASE_CONF_DIR "/cache");
|
|
131 if (access (cachedir, F_OK) == -1)
|
|
132 {
|
58
|
133 if (mkdir (cachedir, S_IRUSR | S_IWUSR | S_IXUSR) < 0)
|
|
134 {
|
|
135 if (request != NULL)
|
186
|
136 request->logging_function (gftp_logging_error, request,
|
58
|
137 _("Error: Could not make directory %s: %s\n"),
|
|
138 cachedir, g_strerror (errno));
|
|
139
|
|
140 return (-1);
|
|
141 }
|
1
|
142 }
|
|
143
|
58
|
144 tempstr = g_strdup_printf ("%s/index.db", cachedir);
|
182
|
145 if ((fd = gftp_fd_open (request, tempstr, O_WRONLY | O_APPEND | O_CREAT,
|
|
146 S_IRUSR | S_IWUSR)) == -1)
|
1
|
147 {
|
58
|
148 g_free (tempstr);
|
1
|
149 g_free (cachedir);
|
58
|
150 return (-1);
|
1
|
151 }
|
182
|
152
|
58
|
153 g_free (tempstr);
|
1
|
154
|
58
|
155 tempstr = g_strdup_printf ("%s/cache.XXXXXX", cachedir);
|
1
|
156 if ((cache_fd = mkstemp (tempstr)) < 0)
|
58
|
157 {
|
|
158 g_free (tempstr);
|
|
159 if (request != NULL)
|
186
|
160 request->logging_function (gftp_logging_error, request,
|
58
|
161 _("Error: Cannot create temporary file: %s\n"),
|
|
162 g_strerror (errno));
|
|
163 return (-1);
|
|
164 }
|
1
|
165 g_free (cachedir);
|
|
166
|
58
|
167 lseek (fd, 0, SEEK_END);
|
222
|
168 temp1str = g_strdup_printf ("%s://%s@%s:%d%s\t%s\t%d\t%ld\n",
|
87
|
169 request->url_prefix,
|
58
|
170 request->username == NULL ? "" : request->username,
|
|
171 request->hostname == NULL ? "" : request->hostname,
|
|
172 request->port,
|
|
173 request->directory == NULL ? "" : request->directory,
|
222
|
174 tempstr, request->server_type, t);
|
58
|
175 g_free (tempstr);
|
168
|
176 ret = gftp_fd_write (NULL, temp1str, strlen (temp1str), fd);
|
58
|
177 g_free (temp1str);
|
1
|
178
|
58
|
179 if (close (fd) != 0 || ret < 0)
|
1
|
180 {
|
58
|
181 if (request != NULL)
|
186
|
182 request->logging_function (gftp_logging_error, request,
|
58
|
183 _("Error closing file descriptor: %s\n"),
|
|
184 g_strerror (errno));
|
|
185
|
1
|
186 close (cache_fd);
|
58
|
187 return (-1);
|
1
|
188 }
|
|
189
|
58
|
190 return (cache_fd);
|
1
|
191 }
|
|
192
|
|
193
|
58
|
194 int
|
1
|
195 gftp_find_cache_entry (gftp_request * request)
|
|
196 {
|
114
|
197 char *indexfile, buf[BUFSIZ], description[BUFSIZ];
|
58
|
198 gftp_getline_buffer * rbuf;
|
114
|
199 gftp_cache_entry centry;
|
58
|
200 int indexfd, cachefd;
|
222
|
201 time_t now;
|
|
202
|
|
203 time (&now);
|
1
|
204
|
182
|
205 gftp_generate_cache_description (request, description, sizeof (description),
|
|
206 0);
|
1
|
207
|
|
208 indexfile = expand_path (BASE_CONF_DIR "/cache/index.db");
|
190
|
209 if ((indexfd = gftp_fd_open (NULL, indexfile, O_RDONLY, 0)) == -1)
|
1
|
210 {
|
|
211 g_free (indexfile);
|
58
|
212 return (-1);
|
1
|
213 }
|
|
214 g_free (indexfile);
|
|
215
|
58
|
216 rbuf = NULL;
|
60
|
217 while (gftp_get_line (NULL, &rbuf, buf, sizeof (buf), indexfd) > 0)
|
1
|
218 {
|
114
|
219 if (gftp_parse_cache_line (request, ¢ry, buf) < 0)
|
1
|
220 continue;
|
|
221
|
222
|
222 /* See if this entry is still valid... */
|
|
223 if (centry.expiration_date < now)
|
|
224 continue;
|
|
225
|
114
|
226 if (strcmp (description, centry.url) == 0)
|
1
|
227 {
|
58
|
228 if (close (indexfd) != 0)
|
|
229 {
|
|
230 if (request != NULL)
|
186
|
231 request->logging_function (gftp_logging_error, request,
|
58
|
232 _("Error closing file descriptor: %s\n"),
|
|
233 g_strerror (errno));
|
|
234 return (-1);
|
|
235 }
|
1
|
236
|
182
|
237 if ((cachefd = gftp_fd_open (request, centry.file, O_RDONLY, 0)) == -1)
|
|
238 return (-1);
|
58
|
239
|
|
240 if (lseek (cachefd, 0, SEEK_END) == 0)
|
1
|
241 {
|
58
|
242 close (cachefd);
|
|
243 return (-1);
|
1
|
244 }
|
58
|
245
|
|
246 if (lseek (cachefd, 0, SEEK_SET) == -1)
|
|
247 {
|
|
248 if (request != NULL)
|
186
|
249 request->logging_function (gftp_logging_error, request,
|
58
|
250 _("Error: Cannot seek on file %s: %s\n"),
|
114
|
251 centry.file, g_strerror (errno));
|
58
|
252
|
|
253 }
|
|
254
|
114
|
255 request->server_type = centry.server_type;
|
1
|
256 return (cachefd);
|
|
257 }
|
|
258 }
|
58
|
259 close (indexfd);
|
|
260 return (-1);
|
1
|
261 }
|
|
262
|
|
263
|
|
264 void
|
|
265 gftp_clear_cache_files (void)
|
|
266 {
|
114
|
267 char *indexfile, buf[BUFSIZ];
|
58
|
268 gftp_getline_buffer * rbuf;
|
114
|
269 gftp_cache_entry centry;
|
58
|
270 int indexfd;
|
1
|
271
|
|
272 indexfile = expand_path (BASE_CONF_DIR "/cache/index.db");
|
182
|
273 if ((indexfd = gftp_fd_open (NULL, indexfile, O_RDONLY, 0)) == -1)
|
1
|
274 {
|
|
275 g_free (indexfile);
|
|
276 return;
|
|
277 }
|
|
278
|
58
|
279 rbuf = NULL;
|
60
|
280 while (gftp_get_line (NULL, &rbuf, buf, sizeof (buf), indexfd) > 0)
|
1
|
281 {
|
114
|
282 if (gftp_parse_cache_line (NULL, ¢ry, buf) < 0)
|
|
283 continue;
|
1
|
284
|
114
|
285 unlink (centry.file);
|
1
|
286 }
|
|
287
|
58
|
288 close (indexfd);
|
1
|
289 unlink (indexfile);
|
|
290 g_free (indexfile);
|
|
291 }
|
|
292
|
|
293
|
|
294 void
|
253
|
295 gftp_delete_cache_entry (gftp_request * request, char *descr,
|
|
296 int ignore_directory)
|
1
|
297 {
|
114
|
298 char *oldindexfile, *newindexfile, buf[BUFSIZ], description[BUFSIZ];
|
58
|
299 gftp_getline_buffer * rbuf;
|
114
|
300 gftp_cache_entry centry;
|
58
|
301 int indexfd, newfd;
|
460
|
302 size_t len;
|
222
|
303 time_t now;
|
47
|
304 int remove;
|
222
|
305
|
253
|
306 g_return_if_fail (request != NULL || descr != NULL);
|
|
307
|
222
|
308 time (&now);
|
182
|
309 if (request != NULL)
|
|
310 {
|
|
311 gftp_generate_cache_description (request, description, sizeof (description),
|
|
312 ignore_directory);
|
|
313 }
|
|
314 else if (descr != NULL)
|
|
315 {
|
|
316 strncpy (description, descr, sizeof (description));
|
249
|
317 description[sizeof (description) - 1] = '\0';
|
182
|
318 }
|
|
319 else
|
|
320 return;
|
1
|
321
|
|
322 oldindexfile = expand_path (BASE_CONF_DIR "/cache/index.db");
|
190
|
323 if ((indexfd = gftp_fd_open (NULL, oldindexfile, O_RDONLY, 0)) == -1)
|
1
|
324 {
|
|
325 g_free (oldindexfile);
|
|
326 return;
|
|
327 }
|
|
328
|
|
329 newindexfile = expand_path (BASE_CONF_DIR "/cache/index.db.new");
|
182
|
330 if ((newfd = gftp_fd_open (request, newindexfile, O_WRONLY | O_CREAT,
|
|
331 S_IRUSR | S_IWUSR)) == -1)
|
1
|
332 {
|
|
333 g_free (oldindexfile);
|
|
334 g_free (newindexfile);
|
|
335 return;
|
|
336 }
|
|
337
|
58
|
338 rbuf = NULL;
|
114
|
339 while (gftp_get_line (NULL, &rbuf, buf, sizeof (buf) - 1, indexfd) > 0)
|
1
|
340 {
|
114
|
341 if (gftp_parse_cache_line (request, ¢ry, buf) < 0)
|
|
342 continue;
|
1
|
343
|
47
|
344 remove = 0;
|
222
|
345 if (centry.expiration_date < now)
|
|
346 remove = 1;
|
|
347 else if (ignore_directory)
|
47
|
348 {
|
114
|
349 if (strncmp (centry.url, description, strlen (description)) == 0)
|
47
|
350 remove = 1;
|
|
351 }
|
|
352 else
|
|
353 {
|
114
|
354 if (strcmp (centry.url, description) == 0)
|
47
|
355 remove = 1;
|
|
356 }
|
|
357
|
|
358
|
|
359 if (remove)
|
114
|
360 unlink (centry.file);
|
1
|
361 else
|
|
362 {
|
114
|
363 /* Make sure we put the tabs back in the line. I do it this way
|
|
364 so that I don't have to allocate memory again for each line
|
|
365 as we read it */
|
|
366 gftp_restore_cache_line (¢ry, buf);
|
|
367
|
179
|
368 /* Make sure when we call gftp_get_line() that we pass the read size
|
|
369 as sizeof(buf) - 1 so that we'll have room to put the newline */
|
460
|
370 len = strlen (buf);
|
|
371 buf[len--] = '\n';
|
179
|
372
|
460
|
373 if (gftp_fd_write (NULL, buf, len, newfd) < 0)
|
58
|
374 break;
|
1
|
375 }
|
|
376 }
|
|
377
|
58
|
378 close (indexfd);
|
|
379 close (newfd);
|
1
|
380
|
|
381 unlink (oldindexfile);
|
|
382 rename (newindexfile, oldindexfile);
|
|
383
|
|
384 g_free (oldindexfile);
|
|
385 g_free (newindexfile);
|
|
386 }
|
|
387
|