]> git.ipfire.org Git - thirdparty/squid.git/blame - src/disk.cc
add bogus value detection to parse_cachedir()
[thirdparty/squid.git] / src / disk.cc
CommitLineData
b224ea98 1
30a4f2a8 2/*
0e473d70 3 * $Id: disk.cc,v 1.98 1998/02/02 21:16:21 wessels Exp $
30a4f2a8 4 *
5 * DEBUG: section 6 Disk I/O Routines
6 * AUTHOR: Harvest Derived
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
30a4f2a8 9 * --------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by
14 * the National Science Foundation.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 */
31
32/*
33 * Copyright (c) 1994, 1995. All rights reserved.
34 *
35 * The Harvest software was developed by the Internet Research Task
36 * Force Research Group on Resource Discovery (IRTF-RD):
37 *
38 * Mic Bowman of Transarc Corporation.
39 * Peter Danzig of the University of Southern California.
40 * Darren R. Hardy of the University of Colorado at Boulder.
41 * Udi Manber of the University of Arizona.
42 * Michael F. Schwartz of the University of Colorado at Boulder.
43 * Duane Wessels of the University of Colorado at Boulder.
44 *
45 * This copyright notice applies to software in the Harvest
46 * ``src/'' directory only. Users should consult the individual
47 * copyright notices in the ``components/'' subdirectories for
48 * copyright information about other software bundled with the
49 * Harvest source code distribution.
50 *
51 * TERMS OF USE
52 *
53 * The Harvest software may be used and re-distributed without
54 * charge, provided that the software origin and research team are
55 * cited in any use of the system. Most commonly this is
56 * accomplished by including a link to the Harvest Home Page
57 * (http://harvest.cs.colorado.edu/) from the query page of any
58 * Broker you deploy, as well as in the query result pages. These
59 * links are generated automatically by the standard Broker
60 * software distribution.
61 *
62 * The Harvest software is provided ``as is'', without express or
63 * implied warranty, and with no support nor obligation to assist
64 * in its use, correction, modification or enhancement. We assume
65 * no liability with respect to the infringement of copyrights,
66 * trade secrets, or any patents, and are not responsible for
67 * consequential damages. Proper use of the Harvest software is
68 * entirely the responsibility of the user.
69 *
70 * DERIVATIVE WORKS
71 *
72 * Users may make derivative works from the Harvest software, subject
73 * to the following constraints:
74 *
75 * - You must include the above copyright notice and these
76 * accompanying paragraphs in all forms of derivative works,
77 * and any documentation and other materials related to such
78 * distribution and use acknowledge that the software was
79 * developed at the above institutions.
80 *
81 * - You must notify IRTF-RD regarding your distribution of
82 * the derivative work.
83 *
84 * - You must clearly notify users that your are distributing
85 * a modified version and not the original Harvest software.
86 *
87 * - Any derivative product is also subject to these copyright
88 * and use restrictions.
89 *
90 * Note that the Harvest software is NOT in the public domain. We
91 * retain copyright, as specified above.
92 *
93 * HISTORY OF FREE SOFTWARE STATUS
94 *
95 * Originally we required sites to license the software in cases
96 * where they were going to build commercial products/services
97 * around Harvest. In June 1995 we changed this policy. We now
98 * allow people to use the core Harvest software (the code found in
99 * the Harvest ``src/'' directory) for free. We made this change
100 * in the interest of encouraging the widest possible deployment of
101 * the technology. The Harvest software is really a reference
102 * implementation of a set of protocols and formats, some of which
103 * we intend to standardize. We encourage commercial
104 * re-implementations of code complying to this set of standards.
105 */
ed43818f 106
44a47c6e 107#include "squid.h"
090089c4 108
109#define DISK_LINE_LEN 1024
090089c4 110
0a0bf5db 111typedef struct disk_ctrl_t {
112 int fd;
113 void *data;
114} disk_ctrl_t;
115
116
117typedef struct open_ctrl_t {
f17936ab 118 FOCB *callback;
0a0bf5db 119 void *callback_data;
120 char *path;
121} open_ctrl_t;
122
de866d20 123static AIOCB diskHandleWriteComplete;
124static AIOCB diskHandleReadComplete;
95d15928 125static PF diskHandleRead;
126static PF diskHandleWrite;
f5b8bbc4 127static void file_open_complete(void *, int, int);
24382924 128
090089c4 129/* initialize table */
b8d8561b 130int
0673c0ba 131disk_init(void)
090089c4 132{
090089c4 133 return 0;
134}
135
136/* Open a disk file. Return a file descriptor */
684c2720 137int
6cf028ab 138file_open(const char *path, int mode, FOCB * callback, void *callback_data, void *tag)
090089c4 139{
090089c4 140 int fd;
0a0bf5db 141 open_ctrl_t *ctrlp;
142
143 ctrlp = xmalloc(sizeof(open_ctrl_t));
144 ctrlp->path = xstrdup(path);
145 ctrlp->callback = callback;
146 ctrlp->callback_data = callback_data;
090089c4 147
b59c7120 148 if (mode & O_WRONLY)
149 mode |= O_APPEND;
4f92c80c 150 mode |= SQUID_NONBLOCK;
b59c7120 151
090089c4 152 /* Open file */
0a0bf5db 153#if USE_ASYNC_IO
f17936ab 154 if (callback != NULL) {
6cf028ab 155 aioOpen(path, mode, 0644, file_open_complete, ctrlp, tag);
9e4ad609 156 return DISK_OK;
0a0bf5db 157 }
f17936ab 158#endif
0a0bf5db 159 fd = open(path, mode, 0644);
160 file_open_complete(ctrlp, fd, errno);
161 if (fd < 0)
162 return DISK_ERROR;
163 return fd;
0a0bf5db 164}
165
166
167static void
95d15928 168file_open_complete(void *data, int fd, int errcode)
0a0bf5db 169{
170 open_ctrl_t *ctrlp = (open_ctrl_t *) data;
6cf028ab 171
0e473d70 172 if (fd == -2 && errcode == -2) { /* Cancelled - clean up */
6cf028ab 173 if (ctrlp->callback)
174 (ctrlp->callback) (ctrlp->callback_data, fd, errcode);
175 xfree(ctrlp->path);
176 xfree(ctrlp);
177 return;
178 }
0a0bf5db 179 if (fd < 0) {
180 errno = errcode;
a3d5953d 181 debug(50, 0) ("file_open: error opening file %s: %s\n", ctrlp->path,
0a0bf5db 182 xstrerror());
183 if (ctrlp->callback)
6cf028ab 184 (ctrlp->callback) (ctrlp->callback_data, DISK_ERROR, errcode);
0a0bf5db 185 xfree(ctrlp->path);
186 xfree(ctrlp);
187 return;
090089c4 188 }
365e5b34 189 debug(6, 5) ("file_open: FD %d\n", fd);
3ca60c86 190 commSetCloseOnExec(fd);
5c5783a2 191 fd_open(fd, FD_FILE, ctrlp->path);
0a0bf5db 192 if (ctrlp->callback)
6cf028ab 193 (ctrlp->callback) (ctrlp->callback_data, fd, errcode);
0a0bf5db 194 xfree(ctrlp->path);
195 xfree(ctrlp);
196}
197
090089c4 198/* close a disk file. */
95d15928 199void
b8d8561b 200file_close(int fd)
090089c4 201{
76f87348 202 fde *F = &fd_table[fd];
0e473d70 203 if (fd < 0) {
6cf028ab 204 debug(6, 0) ("file_close: FD less than zero: %d\n", fd);
205 return;
206 }
76f87348 207 assert(F->open);
79a15e0a 208 if (EBIT_TEST(F->flags, FD_WRITE_DAEMON)) {
209 EBIT_SET(F->flags, FD_CLOSE_REQUEST);
95d15928 210 return;
fb247d78 211 }
79a15e0a 212 if (EBIT_TEST(F->flags, FD_WRITE_PENDING)) {
213 EBIT_SET(F->flags, FD_CLOSE_REQUEST);
95d15928 214 return;
215 }
0a0bf5db 216#if USE_ASYNC_IO
95d15928 217 aioClose(fd);
0a0bf5db 218#else
95d15928 219 close(fd);
0a0bf5db 220#endif
6cf028ab 221 debug(6, 5) ("file_close: FD %d\n", fd);
222 fd_close(fd);
090089c4 223}
224
090089c4 225
226/* write handler */
582b6456 227static void
79d39a72 228diskHandleWrite(int fd, void *notused)
090089c4 229{
4a86108c 230 int len = 0;
0a0bf5db 231 disk_ctrl_t *ctrlp;
232 dwrite_q *q = NULL;
233 dwrite_q *wq = NULL;
76f87348 234 fde *F = &fd_table[fd];
235 struct _fde_disk *fdd = &F->disk;
de866d20 236 if (!fdd->write_q)
582b6456 237 return;
0a0bf5db 238 /* We need to combine subsequent write requests after the first */
d377699f 239 /* But only if we don't need to seek() in betwen them, ugh! */
de866d20 240 if (fdd->write_q->next != NULL && fdd->write_q->next->next != NULL) {
241 len = 0;
242 for (q = fdd->write_q->next; q != NULL; q = q->next)
d377699f 243 len += q->len - q->buf_offset;
0a0bf5db 244 wq = xcalloc(1, sizeof(dwrite_q));
245 wq->buf = xmalloc(len);
246 wq->len = 0;
d377699f 247 wq->buf_offset = 0;
0a0bf5db 248 wq->next = NULL;
249 wq->free = xfree;
250 do {
de866d20 251 q = fdd->write_q->next;
d377699f 252 len = q->len - q->buf_offset;
253 xmemcpy(wq->buf + wq->len, q->buf + q->buf_offset, len);
0a0bf5db 254 wq->len += len;
de866d20 255 fdd->write_q->next = q->next;
0a0bf5db 256 if (q->free)
257 (q->free) (q->buf);
258 safe_free(q);
de866d20 259 } while (fdd->write_q->next != NULL);
260 fdd->write_q_tail = wq;
261 fdd->write_q->next = wq;
0a0bf5db 262 }
263 ctrlp = xcalloc(1, sizeof(disk_ctrl_t));
264 ctrlp->fd = fd;
8350fe9b 265 assert(fdd->write_q != NULL);
d377699f 266 assert(fdd->write_q->len > fdd->write_q->buf_offset);
0a0bf5db 267#if USE_ASYNC_IO
268 aioWrite(fd,
d377699f 269 fdd->write_q->buf + fdd->write_q->buf_offset,
270 fdd->write_q->len - fdd->write_q->buf_offset,
0a0bf5db 271 diskHandleWriteComplete,
cd1fb0eb 272 ctrlp);
0a0bf5db 273#else
274 len = write(fd,
d377699f 275 fdd->write_q->buf + fdd->write_q->buf_offset,
276 fdd->write_q->len - fdd->write_q->buf_offset);
582b6456 277 diskHandleWriteComplete(ctrlp, len, errno);
0a0bf5db 278#endif
279}
280
de866d20 281static void
b69f7771 282diskHandleWriteComplete(void *data, int len, int errcode)
0a0bf5db 283{
284 disk_ctrl_t *ctrlp = data;
0a0bf5db 285 int fd = ctrlp->fd;
76f87348 286 fde *F = &fd_table[fd];
287 struct _fde_disk *fdd = &F->disk;
de866d20 288 dwrite_q *q = fdd->write_q;
289 int status = DISK_OK;
0a0bf5db 290 errno = errcode;
6cf028ab 291
0a0bf5db 292 safe_free(data);
de866d20 293 if (q == NULL) /* Someone aborted then write completed */
294 return;
6cf028ab 295
0e473d70 296 if (len == -2 && errcode == -2) { /* Write cancelled - cleanup */
6cf028ab 297 do {
298 fdd->write_q = q->next;
299 if (q->free)
300 (q->free) (q->buf);
301 safe_free(q);
302 } while ((q = fdd->write_q));
303 return;
304 }
6cf028ab 305 fd_bytes(fd, len, FD_WRITE);
0a0bf5db 306 if (len < 0) {
b224ea98 307 if (!ignoreErrno(errno)) {
de866d20 308 status = errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR;
a3d5953d 309 debug(50, 1) ("diskHandleWrite: FD %d: disk write error: %s\n",
0c77d853 310 fd, xstrerror());
6cf028ab 311 if (fdd->wrt_handle == NULL || status != DISK_NO_SPACE_LEFT) {
de866d20 312 /* FLUSH PENDING BUFFERS */
313 do {
314 fdd->write_q = q->next;
315 if (q->free)
316 (q->free) (q->buf);
317 safe_free(q);
318 } while ((q = fdd->write_q));
090089c4 319 }
0c77d853 320 }
de866d20 321 len = 0;
0a0bf5db 322 }
8350fe9b 323 if (q != NULL) {
324 /* q might become NULL from write failure above */
d377699f 325 q->buf_offset += len;
6cf028ab 326 if (q->buf_offset > q->len)
327 debug(50, 1) ("diskHandleWriteComplete: q->buf_offset > q->len (%p,%d, %d, %d FD %d)\n",
328 q, q->buf_offset, q->len, len, fd);
d377699f 329 assert(q->buf_offset <= q->len);
330 if (q->buf_offset == q->len) {
56878878 331 /* complete write */
332 fdd->write_q = q->next;
333 if (q->free)
334 (q->free) (q->buf);
335 safe_free(q);
336 }
090089c4 337 }
de866d20 338 if (fdd->write_q == NULL) {
339 /* no more data */
340 fdd->write_q_tail = NULL;
79a15e0a 341 EBIT_CLR(F->flags, FD_WRITE_PENDING);
342 EBIT_CLR(F->flags, FD_WRITE_DAEMON);
de866d20 343 } else {
0a0bf5db 344 /* another block is queued */
de866d20 345 commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0);
79a15e0a 346 EBIT_SET(F->flags, FD_WRITE_DAEMON);
4a86108c 347 }
de866d20 348 if (fdd->wrt_handle)
d89d1fb6 349 fdd->wrt_handle(fd, status, len, fdd->wrt_handle_data);
79a15e0a 350 if (EBIT_TEST(F->flags, FD_CLOSE_REQUEST))
b59c7120 351 file_close(fd);
090089c4 352}
353
354
090089c4 355/* write block to a file */
356/* write back queue. Only one writer at a time. */
357/* call a handle when writing is complete. */
b8d8561b 358int
3ebcfaa1 359file_write(int fd,
d377699f 360 off_t file_offset,
684c2720 361 char *ptr_to_buf,
362 int len,
d89d1fb6 363 DWCB handle,
684c2720 364 void *handle_data,
9e4ad609 365 FREE * free_func)
090089c4 366{
c6ac7aae 367 dwrite_q *wq = NULL;
48cc3fcf 368 fde *F = &fd_table[fd];
369 assert(fd >= 0);
370 assert(F->open);
090089c4 371 /* if we got here. Caller is eligible to write. */
30a4f2a8 372 wq = xcalloc(1, sizeof(dwrite_q));
d377699f 373 wq->file_offset = file_offset;
090089c4 374 wq->buf = ptr_to_buf;
090089c4 375 wq->len = len;
d377699f 376 wq->buf_offset = 0;
090089c4 377 wq->next = NULL;
86ee2017 378 wq->free = free_func;
76f87348 379 F->disk.wrt_handle = handle;
380 F->disk.wrt_handle_data = handle_data;
090089c4 381 /* add to queue */
79a15e0a 382 EBIT_SET(F->flags, FD_WRITE_PENDING);
48cc3fcf 383 if (F->disk.write_q == NULL) {
090089c4 384 /* empty queue */
76f87348 385 F->disk.write_q = F->disk.write_q_tail = wq;
090089c4 386 } else {
76f87348 387 F->disk.write_q_tail->next = wq;
388 F->disk.write_q_tail = wq;
090089c4 389 }
79a15e0a 390 if (!EBIT_TEST(F->flags, FD_WRITE_DAEMON)) {
0a0bf5db 391#if USE_ASYNC_IO
95d15928 392 diskHandleWrite(fd, NULL);
0a0bf5db 393#else
95d15928 394 commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0);
0a0bf5db 395#endif
79a15e0a 396 EBIT_SET(F->flags, FD_WRITE_DAEMON);
429fdbec 397 }
090089c4 398 return DISK_OK;
399}
400
401
402
403/* Read from FD */
582b6456 404static void
405diskHandleRead(int fd, void *data)
090089c4 406{
582b6456 407 dread_ctrl *ctrl_dat = data;
606bd3b5 408#if !USE_ASYNC_IO
edd2eb63 409 fde *F = &fd_table[fd];
090089c4 410 int len;
606bd3b5 411#endif
412 disk_ctrl_t *ctrlp = xcalloc(1, sizeof(disk_ctrl_t));
0a0bf5db 413 ctrlp->fd = fd;
cd1fb0eb 414 ctrlp->data = ctrl_dat;
0a0bf5db 415#if USE_ASYNC_IO
416 aioRead(fd,
711982d8 417 ctrl_dat->buf,
418 ctrl_dat->req_len,
0a0bf5db 419 diskHandleReadComplete,
cd1fb0eb 420 ctrlp);
0a0bf5db 421#else
711982d8 422 if (F->disk.offset != ctrl_dat->offset) {
f2b30883 423 debug(6, 3) ("diskHandleRead: FD %d seeking to offset %d\n",
343c257b 424 fd, (int) ctrl_dat->offset);
711982d8 425 lseek(fd, ctrl_dat->offset, SEEK_SET); /* XXX ignore return? */
556c33d5 426 F->disk.offset = ctrl_dat->offset;
711982d8 427 }
428 len = read(fd, ctrl_dat->buf, ctrl_dat->req_len);
429 F->disk.offset += len;
582b6456 430 diskHandleReadComplete(ctrlp, len, errno);
090089c4 431#endif
0a0bf5db 432}
433
de866d20 434static void
4f92c80c 435diskHandleReadComplete(void *data, int len, int errcode)
0a0bf5db 436{
437 disk_ctrl_t *ctrlp = data;
438 dread_ctrl *ctrl_dat = ctrlp->data;
439 int fd = ctrlp->fd;
901a2a3c 440 int rc = DISK_OK;
0a0bf5db 441 errno = errcode;
6cf028ab 442
0a0bf5db 443 xfree(data);
6cf028ab 444
0e473d70 445 if (len == -2 && errcode == -2) { /* Read cancelled - cleanup */
6cf028ab 446 cbdataUnlock(ctrl_dat->client_data);
447 safe_free(ctrl_dat);
448 return;
449 }
4f92c80c 450 fd_bytes(fd, len, FD_READ);
0a0bf5db 451 if (len < 0) {
b224ea98 452 if (ignoreErrno(errno)) {
901a2a3c 453 commSetSelect(fd, COMM_SELECT_READ, diskHandleRead, ctrl_dat, 0);
de866d20 454 return;
0a0bf5db 455 }
901a2a3c 456 debug(50, 1) ("diskHandleRead: FD %d: %s\n", fd, xstrerror());
457 len = 0;
458 rc = DISK_ERROR;
090089c4 459 } else if (len == 0) {
901a2a3c 460 rc = DISK_EOF;
090089c4 461 }
901a2a3c 462 if (cbdataValid(ctrl_dat->client_data))
5d86029a 463 ctrl_dat->handler(fd, ctrl_dat->buf, len, rc, ctrl_dat->client_data);
901a2a3c 464 cbdataUnlock(ctrl_dat->client_data);
6a54c60e 465 safe_free(ctrl_dat);
090089c4 466}
467
468
469/* start read operation */
470/* buffer must be allocated from the caller.
471 * It must have at least req_len space in there.
472 * call handler when a reading is complete. */
b8d8561b 473int
d377699f 474file_read(int fd, char *buf, int req_len, off_t offset, DRCB * handler, void *client_data)
090089c4 475{
476 dread_ctrl *ctrl_dat;
711982d8 477 assert(fd >= 0);
30a4f2a8 478 ctrl_dat = xcalloc(1, sizeof(dread_ctrl));
090089c4 479 ctrl_dat->fd = fd;
480 ctrl_dat->offset = offset;
481 ctrl_dat->req_len = req_len;
482 ctrl_dat->buf = buf;
090089c4 483 ctrl_dat->end_of_file = 0;
484 ctrl_dat->handler = handler;
485 ctrl_dat->client_data = client_data;
901a2a3c 486 cbdataLock(client_data);
0a0bf5db 487#if USE_ASYNC_IO
488 diskHandleRead(fd, ctrl_dat);
489#else
b177367b 490 commSetSelect(fd,
234967c9 491 COMM_SELECT_READ,
cd1fb0eb 492 diskHandleRead,
493 ctrl_dat,
b177367b 494 0);
0a0bf5db 495#endif
090089c4 496 return DISK_OK;
497}
498
b8d8561b 499int
500diskWriteIsComplete(int fd)
b59c7120 501{
95d15928 502 return fd_table[fd].disk.write_q ? 0 : 1;
0a21bd84 503}