]> git.ipfire.org Git - thirdparty/squid.git/blame - src/disk.cc
log them as HIER_FIREWALL_IP_DIRECT
[thirdparty/squid.git] / src / disk.cc
CommitLineData
30a4f2a8 1/*
098be23b 2 * $Id: disk.cc,v 1.52 1997/02/05 04:40:43 wessels Exp $
30a4f2a8 3 *
4 * DEBUG: section 6 Disk I/O Routines
5 * AUTHOR: Harvest Derived
6 *
42c04c16 7 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
30a4f2a8 8 * --------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from the
11 * Internet community. Development is led by Duane Wessels of the
12 * National Laboratory for Applied Network Research and funded by
13 * the National Science Foundation.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 *
29 */
30
31/*
32 * Copyright (c) 1994, 1995. All rights reserved.
33 *
34 * The Harvest software was developed by the Internet Research Task
35 * Force Research Group on Resource Discovery (IRTF-RD):
36 *
37 * Mic Bowman of Transarc Corporation.
38 * Peter Danzig of the University of Southern California.
39 * Darren R. Hardy of the University of Colorado at Boulder.
40 * Udi Manber of the University of Arizona.
41 * Michael F. Schwartz of the University of Colorado at Boulder.
42 * Duane Wessels of the University of Colorado at Boulder.
43 *
44 * This copyright notice applies to software in the Harvest
45 * ``src/'' directory only. Users should consult the individual
46 * copyright notices in the ``components/'' subdirectories for
47 * copyright information about other software bundled with the
48 * Harvest source code distribution.
49 *
50 * TERMS OF USE
51 *
52 * The Harvest software may be used and re-distributed without
53 * charge, provided that the software origin and research team are
54 * cited in any use of the system. Most commonly this is
55 * accomplished by including a link to the Harvest Home Page
56 * (http://harvest.cs.colorado.edu/) from the query page of any
57 * Broker you deploy, as well as in the query result pages. These
58 * links are generated automatically by the standard Broker
59 * software distribution.
60 *
61 * The Harvest software is provided ``as is'', without express or
62 * implied warranty, and with no support nor obligation to assist
63 * in its use, correction, modification or enhancement. We assume
64 * no liability with respect to the infringement of copyrights,
65 * trade secrets, or any patents, and are not responsible for
66 * consequential damages. Proper use of the Harvest software is
67 * entirely the responsibility of the user.
68 *
69 * DERIVATIVE WORKS
70 *
71 * Users may make derivative works from the Harvest software, subject
72 * to the following constraints:
73 *
74 * - You must include the above copyright notice and these
75 * accompanying paragraphs in all forms of derivative works,
76 * and any documentation and other materials related to such
77 * distribution and use acknowledge that the software was
78 * developed at the above institutions.
79 *
80 * - You must notify IRTF-RD regarding your distribution of
81 * the derivative work.
82 *
83 * - You must clearly notify users that your are distributing
84 * a modified version and not the original Harvest software.
85 *
86 * - Any derivative product is also subject to these copyright
87 * and use restrictions.
88 *
89 * Note that the Harvest software is NOT in the public domain. We
90 * retain copyright, as specified above.
91 *
92 * HISTORY OF FREE SOFTWARE STATUS
93 *
94 * Originally we required sites to license the software in cases
95 * where they were going to build commercial products/services
96 * around Harvest. In June 1995 we changed this policy. We now
97 * allow people to use the core Harvest software (the code found in
98 * the Harvest ``src/'' directory) for free. We made this change
99 * in the interest of encouraging the widest possible deployment of
100 * the technology. The Harvest software is really a reference
101 * implementation of a set of protocols and formats, some of which
102 * we intend to standardize. We encourage commercial
103 * re-implementations of code complying to this set of standards.
104 */
ed43818f 105
44a47c6e 106#include "squid.h"
090089c4 107
108#define DISK_LINE_LEN 1024
090089c4 109
110typedef struct _dwalk_ctrl {
111 int fd;
112 off_t offset;
113 char *buf; /* line buffer */
114 int cur_len; /* line len */
a5772f7c 115 FILE_WALK_HD handler;
2318883b 116 void *client_data;
b8d8561b 117 int (*line_handler) (int fd, char *buf, int size, void *line_data);
2318883b 118 void *line_data;
090089c4 119} dwalk_ctrl;
120
090089c4 121/* table for FILE variable, write lock and queue. Indexed by fd. */
122FileEntry *file_table;
090089c4 123
24382924 124static int diskHandleRead _PARAMS((int, dread_ctrl *));
125static int diskHandleWalk _PARAMS((int, dwalk_ctrl *));
126static int diskHandleWrite _PARAMS((int, FileEntry *));
127
090089c4 128/* initialize table */
b8d8561b 129int
0673c0ba 130disk_init(void)
090089c4 131{
30a4f2a8 132 int fd;
090089c4 133
e83892e9 134 file_table = xcalloc(Squid_MaxFD, sizeof(FileEntry));
135 meta_data.misc += Squid_MaxFD * sizeof(FileEntry);
136 for (fd = 0; fd < Squid_MaxFD; fd++) {
090089c4 137 file_table[fd].filename[0] = '\0';
138 file_table[fd].at_eof = NO;
c6ac7aae 139 file_table[fd].open_stat = FILE_NOT_OPEN;
090089c4 140 file_table[fd].close_request = NOT_REQUEST;
141 file_table[fd].write_daemon = NOT_PRESENT;
090089c4 142 file_table[fd].write_pending = NO_WRT_PENDING;
143 file_table[fd].write_q = file_table[fd].write_q_tail = NULL;
144 }
090089c4 145 return 0;
146}
147
148/* Open a disk file. Return a file descriptor */
684c2720 149int
0ee4272b 150file_open(const char *path, int (*handler) _PARAMS((void)), int mode)
090089c4 151{
152 FD_ENTRY *conn;
153 int fd;
154
b59c7120 155 if (mode & O_WRONLY)
156 mode |= O_APPEND;
afb9e9df 157#if defined(O_NONBLOCK) && !defined(_SQUID_SUNOS_) && !defined(_SQUID_SOLARIS_)
158 mode |= O_NONBLOCK;
159#else
24382924 160 mode |= O_NDELAY;
afb9e9df 161#endif
b59c7120 162
090089c4 163 /* Open file */
b59c7120 164 if ((fd = open(path, mode, 0644)) < 0) {
881f7a6c 165 debug(50, 0, "file_open: error opening file %s: %s\n",
090089c4 166 path, xstrerror());
167 return (DISK_ERROR);
168 }
169 /* update fdstat */
30a4f2a8 170 fdstat_open(fd, FD_FILE);
3ca60c86 171 commSetCloseOnExec(fd);
090089c4 172
173 /* init table */
d5aa0e3b 174 xstrncpy(file_table[fd].filename, path, SQUID_MAXPATHLEN);
090089c4 175 file_table[fd].at_eof = NO;
c6ac7aae 176 file_table[fd].open_stat = FILE_OPEN;
090089c4 177 file_table[fd].close_request = NOT_REQUEST;
090089c4 178 file_table[fd].write_pending = NO_WRT_PENDING;
179 file_table[fd].write_daemon = NOT_PRESENT;
090089c4 180 file_table[fd].write_q = NULL;
181
182 conn = &fd_table[fd];
30a4f2a8 183 memset(conn, '\0', sizeof(FD_ENTRY));
090089c4 184 return fd;
185}
186
090089c4 187
188/* close a disk file. */
684c2720 189int
b8d8561b 190file_close(int fd)
090089c4 191{
192 FD_ENTRY *conn = NULL;
fb247d78 193 if (fd < 0) {
194 debug_trap("file_close: bad file number");
195 return DISK_ERROR;
196 }
090089c4 197 /* we might have to flush all the write back queue before we can
198 * close it */
199 /* save it for later */
200
c6ac7aae 201 if (file_table[fd].open_stat == FILE_NOT_OPEN) {
eaf73e50 202 debug(6, 3, "file_close: FD %d is not OPEN\n", fd);
203 } else if (file_table[fd].write_daemon == PRESENT) {
204 debug(6, 3, "file_close: FD %d has a write daemon PRESENT\n", fd);
205 } else if (file_table[fd].write_pending == WRT_PENDING) {
206 debug(6, 3, "file_close: FD %d has a write PENDING\n", fd);
207 } else {
c6ac7aae 208 file_table[fd].open_stat = FILE_NOT_OPEN;
090089c4 209 file_table[fd].write_daemon = NOT_PRESENT;
210 file_table[fd].filename[0] = '\0';
211
555198ac 212 if (fdstatGetType(fd) == FD_SOCKET) {
1d30b295 213 debug(6, 0, "FD %d: Someone called file_close() on a socket\n", fd);
090089c4 214 fatal_dump(NULL);
215 }
216 /* update fdstat */
217 fdstat_close(fd);
218 conn = &fd_table[fd];
219 memset(conn, '\0', sizeof(FD_ENTRY));
220 comm_set_fd_lifetime(fd, -1); /* invalidate the lifetime */
221 close(fd);
222 return DISK_OK;
090089c4 223 }
eaf73e50 224
225 /* refused to close file if there is a daemon running */
226 /* have pending flag set */
227 file_table[fd].close_request = REQUEST;
228 return DISK_ERROR;
090089c4 229}
230
090089c4 231
232/* write handler */
24382924 233static int
b8d8561b 234diskHandleWrite(int fd, FileEntry * entry)
090089c4 235{
236 int len;
b59c7120 237 dwrite_q *q = NULL;
090089c4 238
239 if (file_table[fd].at_eof == NO)
240 lseek(fd, 0, SEEK_END);
b59c7120 241 while (entry->write_q) {
242 len = write(fd,
243 entry->write_q->buf + entry->write_q->cur_offset,
090089c4 244 entry->write_q->len - entry->write_q->cur_offset);
090089c4 245 file_table[fd].at_eof = YES;
090089c4 246 if (len < 0) {
b59c7120 247 if (errno == EAGAIN || errno == EWOULDBLOCK) {
248 /* just reschedule us, try again */
b177367b 249 commSetSelect(fd,
090089c4 250 COMM_SELECT_WRITE,
251 (PF) diskHandleWrite,
b177367b 252 (void *) entry,
85d7ea98 253 0);
090089c4 254 entry->write_daemon = PRESENT;
255 return DISK_OK;
b59c7120 256 } else {
090089c4 257 /* disk i/o failure--flushing all outstanding writes */
881f7a6c 258 debug(50, 1, "diskHandleWrite: FD %d: disk write error: %s\n",
30a4f2a8 259 fd, xstrerror());
090089c4 260 entry->write_daemon = NOT_PRESENT;
261 entry->write_pending = NO_WRT_PENDING;
262 /* call finish handler */
263 do {
264 q = entry->write_q;
265 entry->write_q = q->next;
b59c7120 266 if (q->free)
267 (q->free) (q->buf);
090089c4 268 safe_free(q);
269 } while (entry->write_q);
b59c7120 270 if (entry->wrt_handle) {
271 entry->wrt_handle(fd,
272 errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR,
273 entry->wrt_handle_data);
274 }
090089c4 275 return DISK_ERROR;
276 }
277 }
278 entry->write_q->cur_offset += len;
b59c7120 279 if (entry->write_q->cur_offset < entry->write_q->len) {
280 continue; /* partial write? */
281 } else {
282 /* complete write */
090089c4 283 q = entry->write_q;
b59c7120 284 entry->write_q = q->next;
285 if (q->free)
286 (q->free) (q->buf);
090089c4 287 safe_free(q);
090089c4 288 }
289 }
b59c7120 290 /* no more data */
291 entry->write_q = entry->write_q_tail = NULL;
292 entry->write_pending = NO_WRT_PENDING;
293 entry->write_daemon = NOT_PRESENT;
294 if (entry->wrt_handle)
295 entry->wrt_handle(fd, DISK_OK, entry->wrt_handle_data);
296 if (file_table[fd].close_request == REQUEST)
297 file_close(fd);
298 return DISK_OK;
090089c4 299}
300
301
302
303/* write block to a file */
304/* write back queue. Only one writer at a time. */
305/* call a handle when writing is complete. */
b8d8561b 306int
3ebcfaa1 307file_write(int fd,
684c2720 308 char *ptr_to_buf,
309 int len,
a5772f7c 310 FILE_WRITE_HD handle,
684c2720 311 void *handle_data,
67508012 312 void (*free_func) _PARAMS((void *)))
090089c4 313{
c6ac7aae 314 dwrite_q *wq = NULL;
090089c4 315
c6ac7aae 316 if (file_table[fd].open_stat == FILE_NOT_OPEN)
090089c4 317 return DISK_ERROR;
090089c4 318 /* if we got here. Caller is eligible to write. */
30a4f2a8 319 wq = xcalloc(1, sizeof(dwrite_q));
090089c4 320 wq->buf = ptr_to_buf;
090089c4 321 wq->len = len;
322 wq->cur_offset = 0;
323 wq->next = NULL;
86ee2017 324 wq->free = free_func;
090089c4 325 file_table[fd].wrt_handle = handle;
326 file_table[fd].wrt_handle_data = handle_data;
327
328 /* add to queue */
329 file_table[fd].write_pending = WRT_PENDING;
330 if (!(file_table[fd].write_q)) {
331 /* empty queue */
332 file_table[fd].write_q = file_table[fd].write_q_tail = wq;
090089c4 333 } else {
334 file_table[fd].write_q_tail->next = wq;
335 file_table[fd].write_q_tail = wq;
336 }
337
898f5d1d 338 if (file_table[fd].write_daemon == PRESENT)
339 return DISK_OK;
b177367b 340 commSetSelect(fd,
898f5d1d 341 COMM_SELECT_WRITE,
342 (PF) diskHandleWrite,
b177367b 343 (void *) &file_table[fd],
344 0);
090089c4 345 return DISK_OK;
346}
347
348
349
350/* Read from FD */
24382924 351static int
b8d8561b 352diskHandleRead(int fd, dread_ctrl * ctrl_dat)
090089c4 353{
354 int len;
355
356 /* go to requested position. */
357 lseek(fd, ctrl_dat->offset, SEEK_SET);
358 file_table[fd].at_eof = NO;
5409636c 359 len = read(fd,
360 ctrl_dat->buf + ctrl_dat->cur_len,
090089c4 361 ctrl_dat->req_len - ctrl_dat->cur_len);
362
363 if (len < 0)
364 switch (errno) {
365#if EAGAIN != EWOULDBLOCK
366 case EAGAIN:
367#endif
368 case EWOULDBLOCK:
369 break;
370 default:
881f7a6c 371 debug(50, 1, "diskHandleRead: FD %d: error reading: %s\n",
090089c4 372 fd, xstrerror());
373 ctrl_dat->handler(fd, ctrl_dat->buf,
374 ctrl_dat->cur_len, DISK_ERROR,
098be23b 375 ctrl_dat->client_data);
090089c4 376 safe_free(ctrl_dat);
377 return DISK_ERROR;
378 } else if (len == 0) {
379 /* EOF */
380 ctrl_dat->end_of_file = 1;
381 /* call handler */
382 ctrl_dat->handler(fd, ctrl_dat->buf, ctrl_dat->cur_len, DISK_EOF,
098be23b 383 ctrl_dat->client_data);
090089c4 384 safe_free(ctrl_dat);
385 return DISK_OK;
386 }
387 ctrl_dat->cur_len += len;
388 ctrl_dat->offset = lseek(fd, 0L, SEEK_CUR);
389
390 /* reschedule if need more data. */
391 if (ctrl_dat->cur_len < ctrl_dat->req_len) {
b177367b 392 commSetSelect(fd,
234967c9 393 COMM_SELECT_READ,
394 (PF) diskHandleRead,
b177367b 395 (void *) ctrl_dat,
85d7ea98 396 0);
090089c4 397 return DISK_OK;
398 } else {
399 /* all data we need is here. */
5409636c 400 /* call handler */
401 ctrl_dat->handler(fd,
402 ctrl_dat->buf,
403 ctrl_dat->cur_len,
404 DISK_OK,
098be23b 405 ctrl_dat->client_data);
090089c4 406 safe_free(ctrl_dat);
407 return DISK_OK;
408 }
409}
410
411
412/* start read operation */
413/* buffer must be allocated from the caller.
414 * It must have at least req_len space in there.
415 * call handler when a reading is complete. */
b8d8561b 416int
417file_read(int fd, char *buf, int req_len, int offset, FILE_READ_HD handler, void *client_data)
090089c4 418{
419 dread_ctrl *ctrl_dat;
098be23b 420 if (fd < 0)
421 fatal_dump("file_read: bad FD");
30a4f2a8 422 ctrl_dat = xcalloc(1, sizeof(dread_ctrl));
090089c4 423 ctrl_dat->fd = fd;
424 ctrl_dat->offset = offset;
425 ctrl_dat->req_len = req_len;
426 ctrl_dat->buf = buf;
427 ctrl_dat->cur_len = 0;
428 ctrl_dat->end_of_file = 0;
429 ctrl_dat->handler = handler;
430 ctrl_dat->client_data = client_data;
b177367b 431 commSetSelect(fd,
234967c9 432 COMM_SELECT_READ,
433 (PF) diskHandleRead,
b177367b 434 (void *) ctrl_dat,
435 0);
090089c4 436 return DISK_OK;
437}
438
439
440/* Read from FD and pass a line to routine. Walk to EOF. */
24382924 441static int
b8d8561b 442diskHandleWalk(int fd, dwalk_ctrl * walk_dat)
090089c4 443{
444 int len;
445 int end_pos;
446 int st_pos;
447 int used_bytes;
95d659f0 448 LOCAL_ARRAY(char, temp_line, DISK_LINE_LEN);
090089c4 449
450 lseek(fd, walk_dat->offset, SEEK_SET);
451 file_table[fd].at_eof = NO;
452 len = read(fd, walk_dat->buf, DISK_LINE_LEN - 1);
453
454 if (len < 0)
455 switch (errno) {
456#if EAGAIN != EWOULDBLOCK
457 case EAGAIN:
458#endif
459 case EWOULDBLOCK:
460 break;
461 default:
881f7a6c 462 debug(50, 1, "diskHandleWalk: FD %d: error readingd: %s\n",
090089c4 463 fd, xstrerror());
464 walk_dat->handler(fd, DISK_ERROR, walk_dat->client_data);
465 safe_free(walk_dat->buf);
466 safe_free(walk_dat);
467 return DISK_ERROR;
468 } else if (len == 0) {
469 /* EOF */
470 walk_dat->handler(fd, DISK_EOF, walk_dat->client_data);
471 safe_free(walk_dat->buf);
472 safe_free(walk_dat);
473 return DISK_OK;
474 }
475 /* emulate fgets here. Cut the into separate line. newline is excluded */
476 /* it throws last partial line, if exist, away. */
477 used_bytes = st_pos = end_pos = 0;
478 while (end_pos < len) {
479 if (walk_dat->buf[end_pos] == '\n') {
480 /* new line found */
e94df02d 481 xstrncpy(temp_line, walk_dat->buf + st_pos, end_pos - st_pos + 1);
090089c4 482 used_bytes += end_pos - st_pos + 1;
483
484 /* invoke line handler */
485 walk_dat->line_handler(fd, temp_line, strlen(temp_line),
486 walk_dat->line_data);
487
488 /* skip to next line */
489 st_pos = end_pos + 1;
490 }
491 end_pos++;
492 }
493
494 /* update file pointer to the next to be read character */
495 walk_dat->offset += used_bytes;
496
497 /* reschedule it for next line. */
b177367b 498 commSetSelect(fd, COMM_SELECT_READ, (PF) diskHandleWalk,
499 (void *) walk_dat,
500 0);
090089c4 501 return DISK_OK;
502}
503
504
505/* start walk through whole file operation
506 * read one block and chop it to a line and pass it to provided
507 * handler one line at a time.
508 * call a completion handler when done. */
b8d8561b 509int
510file_walk(int fd,
511 FILE_WALK_HD handler,
512 void *client_data,
513 FILE_WALK_LHD line_handler,
514 void *line_data)
090089c4 515{
516 dwalk_ctrl *walk_dat;
517
30a4f2a8 518 walk_dat = xcalloc(1, sizeof(dwalk_ctrl));
090089c4 519 walk_dat->fd = fd;
520 walk_dat->offset = 0;
30a4f2a8 521 walk_dat->buf = xcalloc(1, DISK_LINE_LEN);
090089c4 522 walk_dat->cur_len = 0;
523 walk_dat->handler = handler;
524 walk_dat->client_data = client_data;
525 walk_dat->line_handler = line_handler;
526 walk_dat->line_data = line_data;
527
b177367b 528 commSetSelect(fd, COMM_SELECT_READ, (PF) diskHandleWalk,
529 (void *) walk_dat,
530 0);
090089c4 531 return DISK_OK;
532}
533
b8d8561b 534char *
535diskFileName(int fd)
090089c4 536{
537 if (file_table[fd].filename[0])
538 return (file_table[fd].filename);
539 else
540 return (0);
541}
b59c7120 542
b8d8561b 543int
544diskWriteIsComplete(int fd)
b59c7120 545{
546 return file_table[fd].write_q ? 0 : 1;
547}
0a21bd84 548
549void
550diskFreeMemory(void)
551{
3ba50d75 552 safe_free(file_table);
0a21bd84 553}