]>
Commit | Line | Data |
---|---|---|
234967c9 | 1 | /* $Id: disk.cc,v 1.12 1996/05/01 22:36:27 wessels Exp $ */ |
1d30b295 | 2 | |
3 | /* DEBUG: Section 6 disk: disk I/O routines */ | |
ed43818f | 4 | |
44a47c6e | 5 | #include "squid.h" |
090089c4 | 6 | |
7 | #define DISK_LINE_LEN 1024 | |
8 | #define MAX_FILE_NAME_LEN 256 | |
9 | ||
10 | typedef struct _dread_ctrl { | |
11 | int fd; | |
12 | off_t offset; | |
13 | int req_len; | |
14 | char *buf; | |
15 | int cur_len; | |
16 | int end_of_file; | |
2318883b | 17 | int (*handler) _PARAMS((int fd, char *buf, int size, int errflag, void *data, |
090089c4 | 18 | int offset)); |
2318883b | 19 | void *client_data; |
090089c4 | 20 | } dread_ctrl; |
21 | ||
22 | typedef struct _dwalk_ctrl { | |
23 | int fd; | |
24 | off_t offset; | |
25 | char *buf; /* line buffer */ | |
26 | int cur_len; /* line len */ | |
2318883b | 27 | int (*handler) _PARAMS((int fd, int errflag, void *data)); |
28 | void *client_data; | |
29 | int (*line_handler) _PARAMS((int fd, char *buf, int size, void *line_data)); | |
30 | void *line_data; | |
090089c4 | 31 | } dwalk_ctrl; |
32 | ||
33 | typedef struct _dwrite_q { | |
51496678 | 34 | char *buf; |
090089c4 | 35 | int len; |
36 | int cur_offset; | |
37 | struct _dwrite_q *next; | |
38 | } dwrite_q; | |
39 | ||
40 | typedef struct _FileEntry { | |
41 | char filename[MAX_FILE_NAME_LEN]; | |
42 | enum { | |
43 | NO, YES | |
44 | } at_eof; | |
45 | enum { | |
46 | NOT_OPEN, OPEN | |
47 | } open_stat; | |
48 | enum { | |
49 | NOT_REQUEST, REQUEST | |
50 | } close_request; | |
51 | enum { | |
52 | NOT_PRESENT, PRESENT | |
53 | } write_daemon; | |
54 | enum { | |
55 | UNLOCK, LOCK | |
56 | } write_lock; | |
57 | int access_code; /* use to verify write lock */ | |
58 | enum { | |
59 | NO_WRT_PENDING, WRT_PENDING | |
60 | } write_pending; | |
61 | void (*wrt_handle) (); | |
62 | void *wrt_handle_data; | |
63 | dwrite_q *write_q; | |
64 | dwrite_q *write_q_tail; | |
65 | } FileEntry; | |
66 | ||
67 | ||
68 | /* table for FILE variable, write lock and queue. Indexed by fd. */ | |
69 | FileEntry *file_table; | |
090089c4 | 70 | |
71 | extern int getMaxFD(); | |
72 | extern void fatal_dump _PARAMS((char *)); | |
73 | ||
74 | /* initialize table */ | |
75 | int disk_init() | |
76 | { | |
77 | int fd, max_fd = getMaxFD(); | |
78 | ||
090089c4 | 79 | file_table = (FileEntry *) xmalloc(sizeof(FileEntry) * max_fd); |
80 | memset(file_table, '\0', sizeof(FileEntry) * max_fd); | |
81 | ||
82 | for (fd = 0; fd < max_fd; fd++) { | |
83 | file_table[fd].filename[0] = '\0'; | |
84 | file_table[fd].at_eof = NO; | |
85 | file_table[fd].open_stat = NOT_OPEN; | |
86 | file_table[fd].close_request = NOT_REQUEST; | |
87 | file_table[fd].write_daemon = NOT_PRESENT; | |
88 | file_table[fd].write_lock = UNLOCK; | |
89 | file_table[fd].access_code = 0; | |
90 | file_table[fd].write_pending = NO_WRT_PENDING; | |
91 | file_table[fd].write_q = file_table[fd].write_q_tail = NULL; | |
92 | } | |
090089c4 | 93 | return 0; |
94 | } | |
95 | ||
96 | /* Open a disk file. Return a file descriptor */ | |
97 | int file_open(path, handler, mode) | |
98 | char *path; /* path to file */ | |
99 | int (*handler) (); /* Interrupt handler. */ | |
100 | int mode; | |
101 | { | |
102 | FD_ENTRY *conn; | |
103 | int fd; | |
104 | ||
090089c4 | 105 | /* Open file */ |
106 | if ((fd = open(path, mode | O_NDELAY, 0644)) < 0) { | |
1d30b295 | 107 | debug(6, 0, "file_open: error opening file %s: %s\n", |
090089c4 | 108 | path, xstrerror()); |
109 | return (DISK_ERROR); | |
110 | } | |
111 | /* update fdstat */ | |
112 | fdstat_open(fd, File); | |
113 | ||
114 | /* init table */ | |
115 | strncpy(file_table[fd].filename, path, MAX_FILE_NAME_LEN); | |
116 | file_table[fd].at_eof = NO; | |
117 | file_table[fd].open_stat = OPEN; | |
118 | file_table[fd].close_request = NOT_REQUEST; | |
119 | file_table[fd].write_lock = UNLOCK; | |
120 | file_table[fd].write_pending = NO_WRT_PENDING; | |
121 | file_table[fd].write_daemon = NOT_PRESENT; | |
122 | file_table[fd].access_code = 0; | |
123 | file_table[fd].write_q = NULL; | |
124 | ||
125 | conn = &fd_table[fd]; | |
126 | memset(conn, 0, sizeof(FD_ENTRY)); | |
127 | ||
128 | conn->port = 0; | |
129 | conn->handler = NULL; | |
130 | ||
131 | /* set non-blocking mode */ | |
ed43818f | 132 | #if defined(O_NONBLOCK) && !defined(_SQUID_SUNOS_) && !defined(_SQUID_SOLARIS_) |
090089c4 | 133 | if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { |
1d30b295 | 134 | debug(6, 0, "file_open: FD %d: Failure to set O_NONBLOCK: %s\n", |
090089c4 | 135 | fd, xstrerror()); |
136 | return DISK_ERROR; | |
137 | } | |
138 | #else | |
d519f482 | 139 | if (fcntl(fd, F_SETFL, O_NDELAY) < 0) { |
1d30b295 | 140 | debug(6, 0, "file_open: FD %d: Failure to set O_NDELAY: %s\n", |
090089c4 | 141 | fd, xstrerror()); |
142 | return DISK_ERROR; | |
143 | } | |
144 | #endif /* O_NONBLOCK */ | |
145 | conn->comm_type = COMM_NONBLOCKING; | |
146 | ||
147 | return fd; | |
148 | } | |
149 | ||
150 | int file_update_open(fd, path) | |
151 | int fd; | |
152 | char *path; /* path to file */ | |
153 | { | |
154 | FD_ENTRY *conn; | |
155 | ||
090089c4 | 156 | /* update fdstat */ |
157 | fdstat_open(fd, File); | |
158 | ||
159 | /* init table */ | |
160 | strncpy(file_table[fd].filename, path, MAX_FILE_NAME_LEN); | |
161 | file_table[fd].at_eof = NO; | |
162 | file_table[fd].open_stat = OPEN; | |
163 | file_table[fd].close_request = NOT_REQUEST; | |
164 | file_table[fd].write_lock = UNLOCK; | |
165 | file_table[fd].write_pending = NO_WRT_PENDING; | |
166 | file_table[fd].write_daemon = NOT_PRESENT; | |
167 | file_table[fd].access_code = 0; | |
168 | file_table[fd].write_q = NULL; | |
169 | ||
170 | conn = &fd_table[fd]; | |
171 | memset(conn, 0, sizeof(FD_ENTRY)); | |
172 | ||
173 | conn->port = 0; | |
174 | conn->handler = NULL; | |
175 | ||
176 | conn->comm_type = COMM_NONBLOCKING; | |
177 | ||
178 | return fd; | |
179 | } | |
180 | ||
181 | ||
182 | /* close a disk file. */ | |
183 | int file_close(fd) | |
184 | int fd; /* file descriptor */ | |
185 | { | |
186 | FD_ENTRY *conn = NULL; | |
187 | ||
188 | /* we might have to flush all the write back queue before we can | |
189 | * close it */ | |
190 | /* save it for later */ | |
191 | ||
eaf73e50 | 192 | if (file_table[fd].open_stat == NOT_OPEN) { |
193 | debug(6, 3, "file_close: FD %d is not OPEN\n", fd); | |
194 | } else if (file_table[fd].write_daemon == PRESENT) { | |
195 | debug(6, 3, "file_close: FD %d has a write daemon PRESENT\n", fd); | |
196 | } else if (file_table[fd].write_pending == WRT_PENDING) { | |
197 | debug(6, 3, "file_close: FD %d has a write PENDING\n", fd); | |
198 | } else { | |
090089c4 | 199 | file_table[fd].open_stat = NOT_OPEN; |
200 | file_table[fd].write_lock = UNLOCK; | |
201 | file_table[fd].write_daemon = NOT_PRESENT; | |
202 | file_table[fd].filename[0] = '\0'; | |
203 | ||
204 | if (fdstat_type(fd) == Socket) { | |
1d30b295 | 205 | debug(6, 0, "FD %d: Someone called file_close() on a socket\n", fd); |
090089c4 | 206 | fatal_dump(NULL); |
207 | } | |
208 | /* update fdstat */ | |
209 | fdstat_close(fd); | |
210 | conn = &fd_table[fd]; | |
211 | memset(conn, '\0', sizeof(FD_ENTRY)); | |
212 | comm_set_fd_lifetime(fd, -1); /* invalidate the lifetime */ | |
213 | close(fd); | |
214 | return DISK_OK; | |
090089c4 | 215 | } |
eaf73e50 | 216 | |
217 | /* refused to close file if there is a daemon running */ | |
218 | /* have pending flag set */ | |
219 | file_table[fd].close_request = REQUEST; | |
220 | return DISK_ERROR; | |
090089c4 | 221 | } |
222 | ||
223 | ||
224 | /* return a opened fd associate with given path name. */ | |
225 | /* return DISK_FILE_NOT_FOUND if not found. */ | |
226 | int file_get_fd(filename) | |
227 | char *filename; | |
228 | { | |
229 | int fd, max_fd = getMaxFD(); | |
230 | for (fd = 1; fd < max_fd; fd++) { | |
231 | if (file_table[fd].open_stat == OPEN) { | |
232 | if (strncmp(file_table[fd].filename, filename, MAX_FILE_NAME_LEN) == 0) { | |
233 | return fd; | |
234 | } | |
235 | } | |
236 | } | |
237 | return DISK_FILE_NOT_FOUND; | |
238 | } | |
239 | ||
240 | /* grab a writing lock for file */ | |
241 | int file_write_lock(fd) | |
242 | int fd; | |
243 | { | |
244 | if (file_table[fd].write_lock == LOCK) { | |
1d30b295 | 245 | debug(6, 0, "trying to lock a locked file\n"); |
090089c4 | 246 | return DISK_WRT_LOCK_FAIL; |
247 | } else { | |
248 | file_table[fd].write_lock = LOCK; | |
249 | file_table[fd].access_code += 1; | |
250 | file_table[fd].access_code %= 65536; | |
251 | return file_table[fd].access_code; | |
252 | } | |
253 | } | |
254 | ||
255 | ||
256 | /* release a writing lock for file */ | |
257 | int file_write_unlock(fd, access_code) | |
258 | int fd; | |
259 | int access_code; | |
260 | { | |
261 | if (file_table[fd].access_code == access_code) { | |
262 | file_table[fd].write_lock = UNLOCK; | |
263 | return DISK_OK; | |
264 | } else { | |
1d30b295 | 265 | debug(6, 0, "trying to unlock the file with the wrong access code\n"); |
090089c4 | 266 | return DISK_WRT_WRONG_CODE; |
267 | } | |
268 | } | |
269 | ||
270 | ||
271 | /* write handler */ | |
272 | int diskHandleWrite(fd, entry) | |
273 | int fd; | |
274 | FileEntry *entry; | |
275 | { | |
276 | int len; | |
277 | dwrite_q *q; | |
278 | int block_complete = 0; | |
279 | ||
280 | if (file_table[fd].at_eof == NO) | |
281 | lseek(fd, 0, SEEK_END); | |
282 | ||
283 | for (;;) { | |
51496678 | 284 | len = write(fd, (entry->write_q->buf) + entry->write_q->cur_offset, |
090089c4 | 285 | entry->write_q->len - entry->write_q->cur_offset); |
286 | ||
287 | file_table[fd].at_eof = YES; | |
288 | ||
289 | if (len < 0) { | |
290 | switch (errno) { | |
291 | #if EAGAIN != EWOULDBLOCK | |
292 | case EAGAIN: | |
293 | #endif | |
294 | case EWOULDBLOCK: | |
295 | /* just reschedule itself, try again */ | |
296 | comm_set_select_handler(fd, | |
297 | COMM_SELECT_WRITE, | |
298 | (PF) diskHandleWrite, | |
51496678 | 299 | (void *) entry); |
090089c4 | 300 | entry->write_daemon = PRESENT; |
301 | return DISK_OK; | |
302 | default: | |
303 | /* disk i/o failure--flushing all outstanding writes */ | |
1d30b295 | 304 | debug(6, 1, "diskHandleWrite: disk write error %s\n", |
090089c4 | 305 | xstrerror()); |
306 | entry->write_daemon = NOT_PRESENT; | |
307 | entry->write_pending = NO_WRT_PENDING; | |
308 | /* call finish handler */ | |
309 | do { | |
310 | q = entry->write_q; | |
311 | entry->write_q = q->next; | |
312 | if (!entry->wrt_handle) { | |
313 | safe_free(q->buf); | |
314 | } else { | |
315 | /* XXXXXX | |
316 | * Notice we call the handler multiple times but | |
317 | * the write handler (in page mode) doesn't know | |
318 | * the buf ptr so it'll be hard to deallocate | |
319 | * memory. | |
320 | * XXXXXX */ | |
321 | entry->wrt_handle(fd, | |
322 | errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR, | |
323 | entry->wrt_handle_data); | |
324 | } | |
325 | safe_free(q); | |
326 | } while (entry->write_q); | |
327 | return DISK_ERROR; | |
328 | } | |
329 | } | |
330 | entry->write_q->cur_offset += len; | |
331 | block_complete = (entry->write_q->cur_offset >= entry->write_q->len); | |
332 | ||
333 | if (block_complete && (!entry->write_q->next)) { | |
334 | /* No more data */ | |
335 | if (!entry->wrt_handle) | |
336 | safe_free(entry->write_q->buf); | |
337 | safe_free(entry->write_q); | |
338 | entry->write_q = entry->write_q_tail = NULL; | |
339 | entry->write_pending = NO_WRT_PENDING; | |
340 | entry->write_daemon = NOT_PRESENT; | |
341 | /* call finish handle */ | |
342 | if (entry->wrt_handle) { | |
343 | entry->wrt_handle(fd, DISK_OK, entry->wrt_handle_data); | |
344 | } | |
345 | /* Close it if requested */ | |
346 | if (file_table[fd].close_request == REQUEST) { | |
347 | file_close(fd); | |
348 | } | |
349 | return DISK_OK; | |
350 | } else if ((block_complete) && (entry->write_q->next)) { | |
351 | /* Do next block */ | |
352 | ||
353 | /* XXXXX THESE PRIMITIVES ARE WEIRD XXXXX | |
354 | * If we have multiple blocks to send, we | |
355 | * only call the completion handler once, | |
356 | * so it becomes our job to free buffer space | |
357 | */ | |
358 | ||
359 | q = entry->write_q; | |
360 | entry->write_q = entry->write_q->next; | |
361 | if (!entry->wrt_handle) | |
362 | safe_free(q->buf); | |
363 | safe_free(q); | |
364 | /* Schedule next write | |
365 | * comm_set_select_handler(fd, COMM_SELECT_WRITE, (PF) diskHandleWrite, | |
51496678 | 366 | * (void *) entry); |
090089c4 | 367 | */ |
368 | entry->write_daemon = PRESENT; | |
369 | /* Repeat loop */ | |
370 | } else { /* !Block_completed; block incomplete */ | |
371 | /* reschedule */ | |
372 | comm_set_select_handler(fd, COMM_SELECT_WRITE, (PF) diskHandleWrite, | |
51496678 | 373 | (void *) entry); |
090089c4 | 374 | entry->write_daemon = PRESENT; |
375 | return DISK_OK; | |
376 | } | |
377 | } | |
378 | } | |
379 | ||
380 | ||
381 | ||
382 | /* write block to a file */ | |
383 | /* write back queue. Only one writer at a time. */ | |
384 | /* call a handle when writing is complete. */ | |
385 | int file_write(fd, ptr_to_buf, len, access_code, handle, handle_data) | |
386 | int fd; | |
2318883b | 387 | char *ptr_to_buf; |
090089c4 | 388 | int len; |
389 | int access_code; | |
390 | void (*handle) (); | |
391 | void *handle_data; | |
392 | { | |
393 | dwrite_q *wq; | |
394 | ||
395 | if (file_table[fd].open_stat != OPEN) { | |
396 | return DISK_ERROR; | |
397 | } | |
398 | if ((file_table[fd].write_lock == LOCK) && | |
399 | (file_table[fd].access_code != access_code)) { | |
9215c1da | 400 | debug(6, 0, "file write: FD %d access code checked failed.\n", fd); |
090089c4 | 401 | return DISK_WRT_WRONG_CODE; |
402 | } | |
403 | /* if we got here. Caller is eligible to write. */ | |
404 | wq = (dwrite_q *) xcalloc(1, sizeof(dwrite_q)); | |
405 | ||
406 | wq->buf = ptr_to_buf; | |
407 | ||
408 | wq->len = len; | |
409 | wq->cur_offset = 0; | |
410 | wq->next = NULL; | |
411 | file_table[fd].wrt_handle = handle; | |
412 | file_table[fd].wrt_handle_data = handle_data; | |
413 | ||
414 | /* add to queue */ | |
415 | file_table[fd].write_pending = WRT_PENDING; | |
416 | if (!(file_table[fd].write_q)) { | |
417 | /* empty queue */ | |
418 | file_table[fd].write_q = file_table[fd].write_q_tail = wq; | |
419 | ||
420 | } else { | |
421 | file_table[fd].write_q_tail->next = wq; | |
422 | file_table[fd].write_q_tail = wq; | |
423 | } | |
424 | ||
425 | if (file_table[fd].write_daemon == NOT_PRESENT) { | |
426 | /* got to start write routine for this fd */ | |
427 | comm_set_select_handler(fd, COMM_SELECT_WRITE, (PF) diskHandleWrite, | |
2318883b | 428 | (void *) &file_table[fd]); |
090089c4 | 429 | } |
430 | return DISK_OK; | |
431 | } | |
432 | ||
433 | ||
434 | ||
435 | /* Read from FD */ | |
436 | int diskHandleRead(fd, ctrl_dat) | |
437 | int fd; | |
438 | dread_ctrl *ctrl_dat; | |
439 | { | |
440 | int len; | |
441 | ||
442 | /* go to requested position. */ | |
443 | lseek(fd, ctrl_dat->offset, SEEK_SET); | |
444 | file_table[fd].at_eof = NO; | |
445 | len = read(fd, ctrl_dat->buf + ctrl_dat->cur_len, | |
446 | ctrl_dat->req_len - ctrl_dat->cur_len); | |
447 | ||
448 | if (len < 0) | |
449 | switch (errno) { | |
450 | #if EAGAIN != EWOULDBLOCK | |
451 | case EAGAIN: | |
452 | #endif | |
453 | case EWOULDBLOCK: | |
454 | break; | |
455 | default: | |
1d30b295 | 456 | debug(6, 1, "diskHandleRead: FD %d: error reading: %s\n", |
090089c4 | 457 | fd, xstrerror()); |
458 | ctrl_dat->handler(fd, ctrl_dat->buf, | |
459 | ctrl_dat->cur_len, DISK_ERROR, | |
460 | ctrl_dat->client_data, ctrl_dat->offset); | |
461 | safe_free(ctrl_dat); | |
462 | return DISK_ERROR; | |
463 | } else if (len == 0) { | |
464 | /* EOF */ | |
465 | ctrl_dat->end_of_file = 1; | |
466 | /* call handler */ | |
467 | ctrl_dat->handler(fd, ctrl_dat->buf, ctrl_dat->cur_len, DISK_EOF, | |
468 | ctrl_dat->client_data, ctrl_dat->offset); | |
469 | safe_free(ctrl_dat); | |
470 | return DISK_OK; | |
471 | } | |
472 | ctrl_dat->cur_len += len; | |
473 | ctrl_dat->offset = lseek(fd, 0L, SEEK_CUR); | |
474 | ||
475 | /* reschedule if need more data. */ | |
476 | if (ctrl_dat->cur_len < ctrl_dat->req_len) { | |
234967c9 | 477 | comm_set_select_handler(fd, |
478 | COMM_SELECT_READ, | |
479 | (PF) diskHandleRead, | |
51496678 | 480 | (void *) ctrl_dat); |
090089c4 | 481 | return DISK_OK; |
482 | } else { | |
483 | /* all data we need is here. */ | |
484 | /* calll handler */ | |
485 | ctrl_dat->handler(fd, ctrl_dat->buf, ctrl_dat->cur_len, DISK_OK, | |
486 | ctrl_dat->client_data, ctrl_dat->offset); | |
487 | safe_free(ctrl_dat); | |
488 | return DISK_OK; | |
489 | } | |
490 | } | |
491 | ||
492 | ||
493 | /* start read operation */ | |
494 | /* buffer must be allocated from the caller. | |
495 | * It must have at least req_len space in there. | |
496 | * call handler when a reading is complete. */ | |
497 | int file_read(fd, buf, req_len, offset, handler, client_data) | |
498 | int fd; | |
51496678 | 499 | char *buf; |
090089c4 | 500 | int req_len; |
501 | int offset; | |
502 | FILE_READ_HD handler; | |
2318883b | 503 | void *client_data; |
090089c4 | 504 | { |
505 | dread_ctrl *ctrl_dat; | |
506 | ||
507 | ctrl_dat = (dread_ctrl *) xmalloc(sizeof(dread_ctrl)); | |
508 | memset(ctrl_dat, '\0', sizeof(dread_ctrl)); | |
509 | ctrl_dat->fd = fd; | |
510 | ctrl_dat->offset = offset; | |
511 | ctrl_dat->req_len = req_len; | |
512 | ctrl_dat->buf = buf; | |
513 | ctrl_dat->cur_len = 0; | |
514 | ctrl_dat->end_of_file = 0; | |
515 | ctrl_dat->handler = handler; | |
516 | ctrl_dat->client_data = client_data; | |
517 | ||
234967c9 | 518 | comm_set_select_handler(fd, |
519 | COMM_SELECT_READ, | |
520 | (PF) diskHandleRead, | |
51496678 | 521 | (void *) ctrl_dat); |
090089c4 | 522 | |
523 | return DISK_OK; | |
524 | } | |
525 | ||
526 | ||
527 | /* Read from FD and pass a line to routine. Walk to EOF. */ | |
528 | int diskHandleWalk(fd, walk_dat) | |
529 | int fd; | |
530 | dwalk_ctrl *walk_dat; | |
531 | { | |
532 | int len; | |
533 | int end_pos; | |
534 | int st_pos; | |
535 | int used_bytes; | |
536 | char temp_line[DISK_LINE_LEN]; | |
537 | ||
538 | lseek(fd, walk_dat->offset, SEEK_SET); | |
539 | file_table[fd].at_eof = NO; | |
540 | len = read(fd, walk_dat->buf, DISK_LINE_LEN - 1); | |
541 | ||
542 | if (len < 0) | |
543 | switch (errno) { | |
544 | #if EAGAIN != EWOULDBLOCK | |
545 | case EAGAIN: | |
546 | #endif | |
547 | case EWOULDBLOCK: | |
548 | break; | |
549 | default: | |
1d30b295 | 550 | debug(6, 1, "diskHandleWalk: FD %d: error readingd: %s\n", |
090089c4 | 551 | fd, xstrerror()); |
552 | walk_dat->handler(fd, DISK_ERROR, walk_dat->client_data); | |
553 | safe_free(walk_dat->buf); | |
554 | safe_free(walk_dat); | |
555 | return DISK_ERROR; | |
556 | } else if (len == 0) { | |
557 | /* EOF */ | |
558 | walk_dat->handler(fd, DISK_EOF, walk_dat->client_data); | |
559 | safe_free(walk_dat->buf); | |
560 | safe_free(walk_dat); | |
561 | return DISK_OK; | |
562 | } | |
563 | /* emulate fgets here. Cut the into separate line. newline is excluded */ | |
564 | /* it throws last partial line, if exist, away. */ | |
565 | used_bytes = st_pos = end_pos = 0; | |
566 | while (end_pos < len) { | |
567 | if (walk_dat->buf[end_pos] == '\n') { | |
568 | /* new line found */ | |
569 | strncpy(temp_line, walk_dat->buf + st_pos, end_pos - st_pos); | |
570 | temp_line[end_pos - st_pos] = '\0'; | |
571 | used_bytes += end_pos - st_pos + 1; | |
572 | ||
573 | /* invoke line handler */ | |
574 | walk_dat->line_handler(fd, temp_line, strlen(temp_line), | |
575 | walk_dat->line_data); | |
576 | ||
577 | /* skip to next line */ | |
578 | st_pos = end_pos + 1; | |
579 | } | |
580 | end_pos++; | |
581 | } | |
582 | ||
583 | /* update file pointer to the next to be read character */ | |
584 | walk_dat->offset += used_bytes; | |
585 | ||
586 | /* reschedule it for next line. */ | |
587 | comm_set_select_handler(fd, COMM_SELECT_READ, (PF) diskHandleWalk, | |
51496678 | 588 | (void *) walk_dat); |
090089c4 | 589 | return DISK_OK; |
590 | } | |
591 | ||
592 | ||
593 | /* start walk through whole file operation | |
594 | * read one block and chop it to a line and pass it to provided | |
595 | * handler one line at a time. | |
596 | * call a completion handler when done. */ | |
597 | int file_walk(fd, handler, client_data, line_handler, line_data) | |
598 | int fd; | |
599 | FILE_WALK_HD handler; | |
2318883b | 600 | void *client_data; |
090089c4 | 601 | FILE_WALK_LHD line_handler; |
2318883b | 602 | void *line_data; |
090089c4 | 603 | |
604 | { | |
605 | dwalk_ctrl *walk_dat; | |
606 | ||
607 | walk_dat = (dwalk_ctrl *) xmalloc(sizeof(dwalk_ctrl)); | |
608 | memset(walk_dat, '\0', sizeof(dwalk_ctrl)); | |
609 | walk_dat->fd = fd; | |
610 | walk_dat->offset = 0; | |
51496678 | 611 | walk_dat->buf = (void *) xcalloc(1, DISK_LINE_LEN); |
090089c4 | 612 | walk_dat->cur_len = 0; |
613 | walk_dat->handler = handler; | |
614 | walk_dat->client_data = client_data; | |
615 | walk_dat->line_handler = line_handler; | |
616 | walk_dat->line_data = line_data; | |
617 | ||
618 | comm_set_select_handler(fd, COMM_SELECT_READ, (PF) diskHandleWalk, | |
51496678 | 619 | (void *) walk_dat); |
090089c4 | 620 | return DISK_OK; |
621 | } | |
622 | ||
623 | char *diskFileName(fd) | |
624 | int fd; | |
625 | { | |
626 | if (file_table[fd].filename[0]) | |
627 | return (file_table[fd].filename); | |
628 | else | |
629 | return (0); | |
630 | } |