/ [cpio] / cpio / src / util.c
To checkout: cvs -d:pserver:anonymous@cvs.gnu.org.ua:/cvsmirror/cpio co cpio/src/util.c
Puszcza

Contents of /cpio/src/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.31 - (show annotations)
Sat Feb 9 10:31:53 2008 UTC (13 years, 9 months ago) by gray
Branch: MAIN
CVS Tags: HEAD
Changes since 1.30: +3 -3 lines
File MIME type: text/plain
* NEWS, configure.ac: Raise the patchlevel number.
* THANKS: Update

* doc/cpio.texi: Fix a typo.
* src/extern.h (warn_if_file_changed): Fix type of the 2nd
argument.
* src/tar.c (write_out_tar_header): Stylistic change.
* src/util.c (copy_files_disk_to_disk): Fix types of automatic
variables.
(warn_if_file_changed): Fix type of the 2nd argument.

Patches supplied by Ladislav Michnovic.

1 /* util.c - Several utility routines for cpio.
2 Copyright (C) 1990, 1991, 1992, 2001, 2004,
3 2006, 2007 Free Software Foundation, Inc.
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 3, or (at your option)
8 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
16 License along with this program; if not, write to the Free
17 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA. */
19
20 #include <system.h>
21
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include "cpiohdr.h"
26 #include "dstring.h"
27 #include "extern.h"
28 #include <paxlib.h>
29 #include "filetypes.h"
30 #include <safe-read.h>
31 #include <full-write.h>
32 #include <rmt.h>
33 #include <hash.h>
34 #include <utimens.h>
35
36 #ifdef HAVE_SYS_IOCTL_H
37 # include <sys/ioctl.h>
38 #endif
39
40 #ifdef HAVE_SYS_MTIO_H
41 # ifdef HAVE_SYS_IO_TRIOCTL_H
42 # include <sys/io/trioctl.h>
43 # endif
44 # include <sys/mtio.h>
45 #endif
46
47 #if !HAVE_DECL_ERRNO
48 extern int errno;
49 #endif
50
51 /* Write `output_size' bytes of `output_buffer' to file
52 descriptor OUT_DES and reset `output_size' and `out_buff'. */
53
54 void
55 tape_empty_output_buffer (int out_des)
56 {
57 int bytes_written;
58
59 #ifdef BROKEN_LONG_TAPE_DRIVER
60 static long output_bytes_before_lseek = 0;
61
62 /* Some tape drivers seem to have a signed internal seek pointer and
63 they lose if it overflows and becomes negative (e.g. when writing
64 tapes > 2Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
65 seek pointer and prevent it from overflowing. */
66 if (output_is_special
67 && ( (output_bytes_before_lseek += output_size) >= 1073741824L) )
68 {
69 lseek(out_des, 0L, SEEK_SET);
70 output_bytes_before_lseek = 0;
71 }
72 #endif
73
74 bytes_written = rmtwrite (out_des, output_buffer, output_size);
75 if (bytes_written != output_size)
76 {
77 int rest_bytes_written;
78 int rest_output_size;
79
80 if (output_is_special
81 && (bytes_written >= 0
82 || (bytes_written < 0
83 && (errno == ENOSPC || errno == EIO || errno == ENXIO))))
84 {
85 get_next_reel (out_des);
86 if (bytes_written > 0)
87 rest_output_size = output_size - bytes_written;
88 else
89 rest_output_size = output_size;
90 rest_bytes_written = rmtwrite (out_des, output_buffer,
91 rest_output_size);
92 if (rest_bytes_written != rest_output_size)
93 error (1, errno, _("write error"));
94 }
95 else
96 error (1, errno, _("write error"));
97 }
98 output_bytes += output_size;
99 out_buff = output_buffer;
100 output_size = 0;
101 }
102
103 static int sparse_write (int fildes, char *buf, unsigned int nbyte);
104
105 /* Write `output_size' bytes of `output_buffer' to file
106 descriptor OUT_DES and reset `output_size' and `out_buff'.
107 If `swapping_halfwords' or `swapping_bytes' is set,
108 do the appropriate swapping first. Our callers have
109 to make sure to only set these flags if `output_size'
110 is appropriate (a multiple of 4 for `swapping_halfwords',
111 2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE
112 must always be a multiple of 4 helps us (and our callers)
113 insure this. */
114
115 void
116 disk_empty_output_buffer (int out_des)
117 {
118 int bytes_written;
119
120 if (swapping_halfwords || swapping_bytes)
121 {
122 if (swapping_halfwords)
123 {
124 int complete_words;
125 complete_words = output_size / 4;
126 swahw_array (output_buffer, complete_words);
127 if (swapping_bytes)
128 swab_array (output_buffer, 2 * complete_words);
129 }
130 else
131 {
132 int complete_halfwords;
133 complete_halfwords = output_size /2;
134 swab_array (output_buffer, complete_halfwords);
135 }
136 }
137
138 if (sparse_flag)
139 bytes_written = sparse_write (out_des, output_buffer, output_size);
140 else
141 bytes_written = write (out_des, output_buffer, output_size);
142
143 if (bytes_written != output_size)
144 {
145 error (1, errno, _("write error"));
146 }
147 output_bytes += output_size;
148 out_buff = output_buffer;
149 output_size = 0;
150 }
151
152 /* Exchange the halfwords of each element of the array of COUNT longs
153 starting at PTR. PTR does not have to be aligned at a word
154 boundary. */
155
156 void
157 swahw_array (char *ptr, int count)
158 {
159 char tmp;
160
161 for (; count > 0; --count)
162 {
163 tmp = *ptr;
164 *ptr = *(ptr + 2);
165 *(ptr + 2) = tmp;
166 ++ptr;
167 tmp = *ptr;
168 *ptr = *(ptr + 2);
169 *(ptr + 2) = tmp;
170 ptr += 3;
171 }
172 }
173
174 /* Read at most NUM_BYTES or `io_block_size' bytes, whichever is smaller,
175 into the start of `input_buffer' from file descriptor IN_DES.
176 Set `input_size' to the number of bytes read and reset `in_buff'.
177 Exit with an error if end of file is reached. */
178
179 #ifdef BROKEN_LONG_TAPE_DRIVER
180 static long input_bytes_before_lseek = 0;
181 #endif
182
183 static void
184 tape_fill_input_buffer (int in_des, int num_bytes)
185 {
186 #ifdef BROKEN_LONG_TAPE_DRIVER
187 /* Some tape drivers seem to have a signed internal seek pointer and
188 they lose if it overflows and becomes negative (e.g. when writing
189 tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
190 seek pointer and prevent it from overflowing. */
191 if (input_is_special
192 && ( (input_bytes_before_lseek += num_bytes) >= 1073741824L) )
193 {
194 lseek(in_des, 0L, SEEK_SET);
195 input_bytes_before_lseek = 0;
196 }
197 #endif
198 in_buff = input_buffer;
199 num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size;
200 input_size = rmtread (in_des, input_buffer, num_bytes);
201 if (input_size == 0 && input_is_special)
202 {
203 get_next_reel (in_des);
204 input_size = rmtread (in_des, input_buffer, num_bytes);
205 }
206 if (input_size < 0)
207 error (1, errno, _("read error"));
208 if (input_size == 0)
209 {
210 error (0, 0, _("premature end of file"));
211 exit (1);
212 }
213 input_bytes += input_size;
214 }
215
216 /* Read at most NUM_BYTES or `DISK_IO_BLOCK_SIZE' bytes, whichever is smaller,
217 into the start of `input_buffer' from file descriptor IN_DES.
218 Set `input_size' to the number of bytes read and reset `in_buff'.
219 Exit with an error if end of file is reached. */
220
221 static int
222 disk_fill_input_buffer (int in_des, off_t num_bytes)
223 {
224 in_buff = input_buffer;
225 num_bytes = (num_bytes < DISK_IO_BLOCK_SIZE) ? num_bytes : DISK_IO_BLOCK_SIZE;
226 input_size = read (in_des, input_buffer, num_bytes);
227 if (input_size < 0)
228 {
229 input_size = 0;
230 return (-1);
231 }
232 else if (input_size == 0)
233 return (1);
234 input_bytes += input_size;
235 return (0);
236 }
237
238 /* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
239 When `out_buff' fills up, flush it to file descriptor OUT_DES. */
240
241 void
242 tape_buffered_write (char *in_buf, int out_des, off_t num_bytes)
243 {
244 off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
245 off_t space_left; /* Room left in output buffer. */
246
247 while (bytes_left > 0)
248 {
249 space_left = io_block_size - output_size;
250 if (space_left == 0)
251 tape_empty_output_buffer (out_des);
252 else
253 {
254 if (bytes_left < space_left)
255 space_left = bytes_left;
256 memcpy (out_buff, in_buf, (unsigned) space_left);
257 out_buff += space_left;
258 output_size += space_left;
259 in_buf += space_left;
260 bytes_left -= space_left;
261 }
262 }
263 }
264
265 /* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
266 When `out_buff' fills up, flush it to file descriptor OUT_DES. */
267
268 void
269 disk_buffered_write (char *in_buf, int out_des, off_t num_bytes)
270 {
271 off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
272 off_t space_left; /* Room left in output buffer. */
273
274 while (bytes_left > 0)
275 {
276 space_left = DISK_IO_BLOCK_SIZE - output_size;
277 if (space_left == 0)
278 disk_empty_output_buffer (out_des);
279 else
280 {
281 if (bytes_left < space_left)
282 space_left = bytes_left;
283 memcpy (out_buff, in_buf, (unsigned) space_left);
284 out_buff += space_left;
285 output_size += space_left;
286 in_buf += space_left;
287 bytes_left -= space_left;
288 }
289 }
290 }
291
292 /* Copy NUM_BYTES of buffer `in_buff' into IN_BUF.
293 `in_buff' may be partly full.
294 When `in_buff' is exhausted, refill it from file descriptor IN_DES. */
295
296 void
297 tape_buffered_read (char *in_buf, int in_des, off_t num_bytes)
298 {
299 off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
300 off_t space_left; /* Bytes to copy from input buffer. */
301
302 while (bytes_left > 0)
303 {
304 if (input_size == 0)
305 tape_fill_input_buffer (in_des, io_block_size);
306 if (bytes_left < input_size)
307 space_left = bytes_left;
308 else
309 space_left = input_size;
310 memcpy (in_buf, in_buff, (unsigned) space_left);
311 in_buff += space_left;
312 in_buf += space_left;
313 input_size -= space_left;
314 bytes_left -= space_left;
315 }
316 }
317
318 /* Copy the the next NUM_BYTES bytes of `input_buffer' into PEEK_BUF.
319 If NUM_BYTES bytes are not available, read the next `io_block_size' bytes
320 into the end of `input_buffer' and update `input_size'.
321
322 Return the number of bytes copied into PEEK_BUF.
323 If the number of bytes returned is less than NUM_BYTES,
324 then EOF has been reached. */
325
326 int
327 tape_buffered_peek (char *peek_buf, int in_des, int num_bytes)
328 {
329 long tmp_input_size;
330 long got_bytes;
331 char *append_buf;
332
333 #ifdef BROKEN_LONG_TAPE_DRIVER
334 /* Some tape drivers seem to have a signed internal seek pointer and
335 they lose if it overflows and becomes negative (e.g. when writing
336 tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
337 seek pointer and prevent it from overflowing. */
338 if (input_is_special
339 && ( (input_bytes_before_lseek += num_bytes) >= 1073741824L) )
340 {
341 lseek(in_des, 0L, SEEK_SET);
342 input_bytes_before_lseek = 0;
343 }
344 #endif
345
346 while (input_size < num_bytes)
347 {
348 append_buf = in_buff + input_size;
349 if ( (append_buf - input_buffer) >= input_buffer_size)
350 {
351 /* We can keep up to 2 "blocks" (either the physical block size
352 or 512 bytes(the size of a tar record), which ever is
353 larger) in the input buffer when we are peeking. We
354 assume that our caller will never be interested in peeking
355 ahead at more than 512 bytes, so we know that by the time
356 we need a 3rd "block" in the buffer we can throw away the
357 first block to make room. */
358 int half;
359 half = input_buffer_size / 2;
360 memmove (input_buffer, input_buffer + half, half);
361 in_buff = in_buff - half;
362 append_buf = append_buf - half;
363 }
364 tmp_input_size = rmtread (in_des, append_buf, io_block_size);
365 if (tmp_input_size == 0)
366 {
367 if (input_is_special)
368 {
369 get_next_reel (in_des);
370 tmp_input_size = rmtread (in_des, append_buf, io_block_size);
371 }
372 else
373 break;
374 }
375 if (tmp_input_size < 0)
376 error (1, errno, _("read error"));
377 input_bytes += tmp_input_size;
378 input_size += tmp_input_size;
379 }
380 if (num_bytes <= input_size)
381 got_bytes = num_bytes;
382 else
383 got_bytes = input_size;
384 memcpy (peek_buf, in_buff, (unsigned) got_bytes);
385 return got_bytes;
386 }
387
388 /* Skip the next NUM_BYTES bytes of file descriptor IN_DES. */
389
390 void
391 tape_toss_input (int in_des, off_t num_bytes)
392 {
393 off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
394 off_t space_left; /* Bytes to copy from input buffer. */
395
396 while (bytes_left > 0)
397 {
398 if (input_size == 0)
399 tape_fill_input_buffer (in_des, io_block_size);
400 if (bytes_left < input_size)
401 space_left = bytes_left;
402 else
403 space_left = input_size;
404
405 if (crc_i_flag && only_verify_crc_flag)
406 {
407 int k;
408 for (k = 0; k < space_left; ++k)
409 crc += in_buff[k] & 0xff;
410 }
411
412 in_buff += space_left;
413 input_size -= space_left;
414 bytes_left -= space_left;
415 }
416 }
417
418 void
419 write_nuls_to_file (off_t num_bytes, int out_des,
420 void (*writer) (char *in_buf, int out_des, off_t num_bytes))
421 {
422 off_t blocks;
423 off_t extra_bytes;
424 off_t i;
425 static char zeros_512[512];
426
427 blocks = num_bytes / sizeof zeros_512;
428 extra_bytes = num_bytes % sizeof zeros_512;
429 for (i = 0; i < blocks; ++i)
430 writer (zeros_512, out_des, sizeof zeros_512);
431 if (extra_bytes)
432 writer (zeros_512, out_des, extra_bytes);
433 }
434
435 /* Copy a file using the input and output buffers, which may start out
436 partly full. After the copy, the files are not closed nor the last
437 block flushed to output, and the input buffer may still be partly
438 full. If `crc_i_flag' is set, add each byte to `crc'.
439 IN_DES is the file descriptor for input;
440 OUT_DES is the file descriptor for output;
441 NUM_BYTES is the number of bytes to copy. */
442
443 void
444 copy_files_tape_to_disk (int in_des, int out_des, off_t num_bytes)
445 {
446 off_t size;
447 off_t k;
448
449 while (num_bytes > 0)
450 {
451 if (input_size == 0)
452 tape_fill_input_buffer (in_des, io_block_size);
453 size = (input_size < num_bytes) ? input_size : num_bytes;
454 if (crc_i_flag)
455 {
456 for (k = 0; k < size; ++k)
457 crc += in_buff[k] & 0xff;
458 }
459 disk_buffered_write (in_buff, out_des, size);
460 num_bytes -= size;
461 input_size -= size;
462 in_buff += size;
463 }
464 }
465 /* Copy a file using the input and output buffers, which may start out
466 partly full. After the copy, the files are not closed nor the last
467 block flushed to output, and the input buffer may still be partly
468 full. If `crc_i_flag' is set, add each byte to `crc'.
469 IN_DES is the file descriptor for input;
470 OUT_DES is the file descriptor for output;
471 NUM_BYTES is the number of bytes to copy. */
472
473 void
474 copy_files_disk_to_tape (int in_des, int out_des, off_t num_bytes,
475 char *filename)
476 {
477 off_t size;
478 off_t k;
479 int rc;
480 off_t original_num_bytes;
481
482 original_num_bytes = num_bytes;
483
484 while (num_bytes > 0)
485 {
486 if (input_size == 0)
487 if (rc = disk_fill_input_buffer (in_des,
488 num_bytes < DISK_IO_BLOCK_SIZE ?
489 num_bytes : DISK_IO_BLOCK_SIZE))
490 {
491 if (rc > 0)
492 {
493 char buf[UINTMAX_STRSIZE_BOUND];
494 error (0, 0,
495 ngettext ("File %s shrunk by %s byte, padding with zeros",
496 "File %s shrunk by %s bytes, padding with zeros",
497 num_bytes),
498 filename, STRINGIFY_BIGINT (num_bytes, buf));
499 }
500 else
501 error (0, 0, _("Read error at byte %lld in file %s, padding with zeros"),
502 original_num_bytes - num_bytes, filename);
503 write_nuls_to_file (num_bytes, out_des, tape_buffered_write);
504 break;
505 }
506 size = (input_size < num_bytes) ? input_size : num_bytes;
507 if (crc_i_flag)
508 {
509 for (k = 0; k < size; ++k)
510 crc += in_buff[k] & 0xff;
511 }
512 tape_buffered_write (in_buff, out_des, size);
513 num_bytes -= size;
514 input_size -= size;
515 in_buff += size;
516 }
517 }
518 /* Copy a file using the input and output buffers, which may start out
519 partly full. After the copy, the files are not closed nor the last
520 block flushed to output, and the input buffer may still be partly
521 full. If `crc_i_flag' is set, add each byte to `crc'.
522 IN_DES is the file descriptor for input;
523 OUT_DES is the file descriptor for output;
524 NUM_BYTES is the number of bytes to copy. */
525
526 void
527 copy_files_disk_to_disk (int in_des, int out_des, off_t num_bytes,
528 char *filename)
529 {
530 off_t size;
531 off_t k;
532 off_t original_num_bytes;
533 int rc;
534
535 original_num_bytes = num_bytes;
536 while (num_bytes > 0)
537 {
538 if (input_size == 0)
539 if (rc = disk_fill_input_buffer (in_des, num_bytes))
540 {
541 if (rc > 0)
542 {
543 char buf[UINTMAX_STRSIZE_BOUND];
544 error (0, 0,
545 ngettext ("File %s shrunk by %s byte, padding with zeros",
546 "File %s shrunk by %s bytes, padding with zeros",
547 num_bytes),
548 filename, STRINGIFY_BIGINT (num_bytes, buf));
549 }
550 else
551 error (0, 0, _("Read error at byte %lld in file %s, padding with zeros"),
552 original_num_bytes - num_bytes, filename);
553 write_nuls_to_file (num_bytes, out_des, disk_buffered_write);
554 break;
555 }
556 size = (input_size < num_bytes) ? input_size : num_bytes;
557 if (crc_i_flag)
558 {
559 for (k = 0; k < size; ++k)
560 crc += in_buff[k] & 0xff;
561 }
562 disk_buffered_write (in_buff, out_des, size);
563 num_bytes -= size;
564 input_size -= size;
565 in_buff += size;
566 }
567 }
568
569 /* Warn if file changed while it was being copied. */
570
571 void
572 warn_if_file_changed (char *file_name, off_t old_file_size,
573 time_t old_file_mtime)
574 {
575 struct stat new_file_stat;
576 if ((*xstat) (file_name, &new_file_stat) < 0)
577 {
578 stat_error (file_name);
579 return;
580 }
581
582 /* Only check growth, shrinkage detected in copy_files_disk_to_{disk,tape}()
583 */
584 if (new_file_stat.st_size > old_file_size)
585 error (0, 0,
586 ngettext ("File %s grew, %"PRIuMAX" new byte not copied",
587 "File %s grew, %"PRIuMAX" new bytes not copied",
588 (long)(new_file_stat.st_size - old_file_size)),
589 file_name, (uintmax_t) (new_file_stat.st_size - old_file_size));
590
591 else if (new_file_stat.st_mtime != old_file_mtime)
592 error (0, 0, _("File %s was modified while being copied"), file_name);
593 }
594
595 /* Create all directories up to but not including the last part of NAME.
596 Do not destroy any nondirectories while creating directories. */
597
598 void
599 create_all_directories (char *name)
600 {
601 char *dir;
602 int mode;
603 #ifdef HPUX_CDF
604 int cdf;
605 #endif
606
607 dir = dir_name (name);
608 mode = 0700;
609 #ifdef HPUX_CDF
610 cdf = islastparentcdf (name);
611 if (cdf)
612 {
613 dir [strlen (dir) - 1] = '\0'; /* remove final + */
614 mode = 04700;
615 }
616
617 #endif
618
619 if (dir == NULL)
620 error (2, 0, _("virtual memory exhausted"));
621
622 if (dir[0] != '.' || dir[1] != '\0')
623 {
624 const char *fmt;
625 if (warn_option & CPIO_WARN_INTERDIR)
626 fmt = _("Creating intermediate directory `%s'");
627 else
628 fmt = NULL;
629 make_path (dir, -1, -1, fmt);
630 }
631
632 free (dir);
633 }
634
635 /* Prepare to append to an archive. We have been in
636 process_copy_in, keeping track of the position where
637 the last header started in `last_header_start'. Now we
638 have the starting position of the last header (the TRAILER!!!
639 header, or blank record for tar archives) and we want to start
640 writing (appending) over the last header. The last header may
641 be in the middle of a block, so to keep the buffering in sync
642 we lseek back to the start of the block, read everything up
643 to but not including the last header, lseek back to the start
644 of the block, and then do a copy_buf_out of what we read.
645 Actually, we probably don't have to worry so much about keeping the
646 buffering perfect since you can only append to archives that
647 are disk files. */
648
649 void
650 prepare_append (int out_file_des)
651 {
652 int start_of_header;
653 int start_of_block;
654 int useful_bytes_in_block;
655 char *tmp_buf;
656
657 start_of_header = last_header_start;
658 /* Figure out how many bytes we will rewrite, and where they start. */
659 useful_bytes_in_block = start_of_header % io_block_size;
660 start_of_block = start_of_header - useful_bytes_in_block;
661
662 if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
663 error (1, errno, _("cannot seek on output"));
664 if (useful_bytes_in_block > 0)
665 {
666 tmp_buf = (char *) xmalloc (useful_bytes_in_block);
667 read (out_file_des, tmp_buf, useful_bytes_in_block);
668 if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
669 error (1, errno, _("cannot seek on output"));
670 /* fix juo -- is this copy_tape_buf_out? or copy_disk? */
671 tape_buffered_write (tmp_buf, out_file_des, useful_bytes_in_block);
672 free (tmp_buf);
673 }
674
675 /* We are done reading the archive, so clear these since they
676 will now be used for reading in files that we are appending
677 to the archive. */
678 input_size = 0;
679 input_bytes = 0;
680 in_buff = input_buffer;
681 }
682
683 /* Support for remembering inodes with multiple links. Used in the
684 "copy in" and "copy pass" modes for making links instead of copying
685 the file. */
686
687 struct inode_val
688 {
689 unsigned long inode;
690 unsigned long major_num;
691 unsigned long minor_num;
692 char *file_name;
693 };
694
695 /* Inode hash table. Allocated by first call to add_inode. */
696 static Hash_table *hash_table = NULL;
697
698 static size_t
699 inode_val_hasher (const void *val, size_t n_buckets)
700 {
701 const struct inode_val *ival = val;
702 return ival->inode % n_buckets;
703 }
704
705 static bool
706 inode_val_compare (const void *val1, const void *val2)
707 {
708 const struct inode_val *ival1 = val1;
709 const struct inode_val *ival2 = val2;
710 return ival1->inode == ival2->inode
711 && ival1->major_num == ival2->major_num
712 && ival1->minor_num == ival2->minor_num;
713 }
714
715 char *
716 find_inode_file (unsigned long node_num, unsigned long major_num,
717 unsigned long minor_num)
718 {
719 struct inode_val sample;
720 struct inode_val *ival;
721
722 if (!hash_table)
723 return NULL;
724
725 sample.inode = node_num;
726 sample.major_num = major_num;
727 sample.minor_num = minor_num;
728 ival = hash_lookup (hash_table, &sample);
729 return ival ? ival->file_name : NULL;
730 }
731
732 /* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */
733
734 void
735 add_inode (unsigned long node_num, char *file_name, unsigned long major_num,
736 unsigned long minor_num)
737 {
738 struct inode_val *temp;
739 struct inode_val *e;
740
741 /* Create new inode record. */
742 temp = (struct inode_val *) xmalloc (sizeof (struct inode_val));
743 temp->inode = node_num;
744 temp->major_num = major_num;
745 temp->minor_num = minor_num;
746 temp->file_name = xstrdup (file_name);
747
748 if (!((hash_table
749 || (hash_table = hash_initialize (0, 0, inode_val_hasher,
750 inode_val_compare, 0)))
751 && (e = hash_insert (hash_table, temp))))
752 xalloc_die ();
753 /* FIXME: e is not used */
754 }
755
756
757 /* Open FILE in the mode specified by the command line options
758 and return an open file descriptor for it,
759 or -1 if it can't be opened. */
760
761 int
762 open_archive (char *file)
763 {
764 int fd;
765 void (*copy_in) (); /* Workaround for pcc bug. */
766
767 copy_in = process_copy_in;
768
769 if (copy_function == copy_in)
770 fd = rmtopen (file, O_RDONLY | O_BINARY, MODE_RW, rsh_command_option);
771 else
772 {
773 if (!append_flag)
774 fd = rmtopen (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, MODE_RW,
775 rsh_command_option);
776 else
777 fd = rmtopen (file, O_RDWR | O_BINARY, MODE_RW, rsh_command_option);
778 }
779
780 return fd;
781 }
782
783 /* Attempt to rewind the tape drive on file descriptor TAPE_DES
784 and take it offline. */
785
786 void
787 tape_offline (int tape_des)
788 {
789 #if defined(MTIOCTOP) && defined(MTOFFL)
790 struct mtop control;
791
792 control.mt_op = MTOFFL;
793 control.mt_count = 1;
794 rmtioctl (tape_des, MTIOCTOP, (char*) &control); /* Don't care if it fails. */
795 #endif
796 }
797
798 /* The file on file descriptor TAPE_DES is assumed to be magnetic tape
799 (or floppy disk or other device) and the end of the medium
800 has been reached. Ask the user for to mount a new "tape" to continue
801 the processing. If the user specified the device name on the
802 command line (with the -I, -O, -F or --file options), then we can
803 automatically re-open the same device to use the next medium. If the
804 user did not specify the device name, then we have to ask them which
805 device to use. */
806
807 void
808 get_next_reel (int tape_des)
809 {
810 static int reel_number = 1;
811 FILE *tty_in; /* File for interacting with user. */
812 FILE *tty_out; /* File for interacting with user. */
813 int old_tape_des;
814 char *next_archive_name;
815 dynamic_string new_name;
816 char *str_res;
817
818 ds_init (&new_name, 128);
819
820 /* Open files for interactive communication. */
821 tty_in = fopen (TTY_NAME, "r");
822 if (tty_in == NULL)
823 error (2, errno, TTY_NAME);
824 tty_out = fopen (TTY_NAME, "w");
825 if (tty_out == NULL)
826 error (2, errno, TTY_NAME);
827
828 old_tape_des = tape_des;
829 tape_offline (tape_des);
830 rmtclose (tape_des);
831
832 /* Give message and wait for carrage return. User should hit carrage return
833 only after loading the next tape. */
834 ++reel_number;
835 if (new_media_message)
836 fprintf (tty_out, "%s", new_media_message);
837 else if (new_media_message_with_number)
838 fprintf (tty_out, "%s%d%s", new_media_message_with_number, reel_number,
839 new_media_message_after_number);
840 else if (archive_name)
841 fprintf (tty_out, _("Found end of tape. Load next tape and press RETURN. "));
842 else
843 fprintf (tty_out, _("Found end of tape. To continue, type device/file name when ready.\n"));
844
845 fflush (tty_out);
846
847 if (archive_name)
848 {
849 int c;
850
851 do
852 c = getc (tty_in);
853 while (c != EOF && c != '\n');
854
855 tape_des = open_archive (archive_name);
856 if (tape_des == -1)
857 open_error (archive_name);
858 }
859 else
860 {
861 do
862 {
863 if (tape_des < 0)
864 {
865 fprintf (tty_out,
866 _("To continue, type device/file name when ready.\n"));
867 fflush (tty_out);
868 }
869
870 str_res = ds_fgets (tty_in, &new_name);
871 if (str_res == NULL || str_res[0] == '\0')
872 exit (1);
873 next_archive_name = str_res;
874
875 tape_des = open_archive (next_archive_name);
876 if (tape_des == -1)
877 open_error (next_archive_name);
878 }
879 while (tape_des < 0);
880 }
881
882 /* We have to make sure that `tape_des' has not changed its value even
883 though we closed it and reopened it, since there are local
884 copies of it in other routines. This works fine on Unix (even with
885 rmtread and rmtwrite) since open will always return the lowest
886 available file descriptor and we haven't closed any files (e.g.,
887 stdin, stdout or stderr) that were opened before we originally opened
888 the archive. */
889
890 if (tape_des != old_tape_des)
891 error (1, 0, _("internal error: tape descriptor changed from %d to %d"),
892 old_tape_des, tape_des);
893
894 free (new_name.ds_string);
895 fclose (tty_in);
896 fclose (tty_out);
897 }
898
899 /* If MESSAGE does not contain the string "%d", make `new_media_message'
900 a copy of MESSAGE. If MESSAGES does contain the string "%d", make
901 `new_media_message_with_number' a copy of MESSAGE up to, but
902 not including, the string "%d", and make `new_media_message_after_number'
903 a copy of MESSAGE after the string "%d". */
904
905 void
906 set_new_media_message (char *message)
907 {
908 char *p;
909 int prev_was_percent;
910
911 p = message;
912 prev_was_percent = 0;
913 while (*p != '\0')
914 {
915 if (*p == 'd' && prev_was_percent)
916 break;
917 prev_was_percent = (*p == '%');
918 ++p;
919 }
920 if (*p == '\0')
921 {
922 new_media_message = xstrdup (message);
923 }
924 else
925 {
926 int length = p - message - 1;
927
928 new_media_message_with_number = xmalloc (length + 1);
929 strncpy (new_media_message_with_number, message, length);
930 new_media_message_with_number[length] = '\0';
931 length = strlen (p + 1);
932 new_media_message_after_number = xmalloc (length + 1);
933 strcpy (new_media_message_after_number, p + 1);
934 }
935 }
936
937 #ifdef SYMLINK_USES_UMASK
938 /* Most machines always create symlinks with rwxrwxrwx protection,
939 but some (HP/UX 8.07; maybe DEC's OSF on MIPS, too?) use the
940 umask when creating symlinks, so if your umask is 022 you end
941 up with rwxr-xr-x symlinks (although HP/UX seems to completely
942 ignore the protection). There doesn't seem to be any way to
943 manipulate the modes once the symlinks are created (e.g.
944 a hypothetical "lchmod"), so to create them with the right
945 modes we have to set the umask first. */
946
947 int
948 umasked_symlink (char *name1, char *name2, int mode)
949 {
950 int old_umask;
951 int rc;
952 mode = ~(mode & 0777) & 0777;
953 old_umask = umask (mode);
954 rc = symlink (name1, name2);
955 umask (old_umask);
956 return rc;
957 }
958 #endif /* SYMLINK_USES_UMASK */
959
960 #ifdef HPUX_CDF
961 /* When we create a cpio archive we mark CDF's by putting an extra `/'
962 after their component name so we can distinguish the CDF's when we
963 extract the archive (in case the "hidden" directory's files appear
964 in the archive before the directory itself). E.g., in the path
965 "a/b+/c", if b+ is a CDF, we will write this path as "a/b+//c" in
966 the archive so when we extract the archive we will know that b+
967 is actually a CDF, and not an ordinary directory whose name happens
968 to end in `+'. We also do the same thing internally in copypass.c. */
969
970
971 /* Take an input pathname and check it for CDF's. Insert an extra
972 `/' in the pathname after each "hidden" directory. If we add
973 any `/'s, return a malloced string instead of the original input
974 string.
975 FIXME: This creates a memory leak.
976 */
977
978 char *
979 add_cdf_double_slashes (char *input_name)
980 {
981 static char *ret_name = NULL; /* re-usuable return buffer (malloc'ed) */
982 static int ret_size = -1; /* size of return buffer. */
983 char *p;
984 char *q;
985 int n;
986 struct stat dir_stat;
987
988 /* Search for a `/' preceeded by a `+'. */
989
990 for (p = input_name; *p != '\0'; ++p)
991 {
992 if ( (*p == '+') && (*(p + 1) == '/') )
993 break;
994 }
995
996 /* If we didn't find a `/' preceeded by a `+' then there are
997 no CDF's in this pathname. Return the original pathname. */
998
999 if (*p == '\0')
1000 return input_name;
1001
1002 /* There was a `/' preceeded by a `+' in the pathname. If it is a CDF
1003 then we will need to copy the input pathname to our return
1004 buffer so we can insert the extra `/'s. Since we can't tell
1005 yet whether or not it is a CDF we will just always copy the
1006 string to the return buffer. First we have to make sure the
1007 buffer is large enough to hold the string and any number of
1008 extra `/'s we might add. */
1009
1010 n = 2 * (strlen (input_name) + 1);
1011 if (n >= ret_size)
1012 {
1013 if (ret_size < 0)
1014 ret_name = (char *) malloc (n);
1015 else
1016 ret_name = (char *)realloc (ret_name, n);
1017 ret_size = n;
1018 }
1019
1020 /* Clear the `/' after this component, so we can stat the pathname
1021 up to and including this component. */
1022 ++p;
1023 *p = '\0';
1024 if ((*xstat) (input_name, &dir_stat) < 0)
1025 {
1026 stat_error (input_name);
1027 return input_name;
1028 }
1029
1030 /* Now put back the `/' after this component and copy the pathname up to
1031 and including this component and its trailing `/' to the return
1032 buffer. */
1033 *p++ = '/';
1034 strncpy (ret_name, input_name, p - input_name);
1035 q = ret_name + (p - input_name);
1036
1037 /* If it was a CDF, add another `/'. */
1038 if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) )
1039 *q++ = '/';
1040
1041 /* Go through the rest of the input pathname, copying it to the
1042 return buffer, and adding an extra `/' after each CDF. */
1043 while (*p != '\0')
1044 {
1045 if ( (*p == '+') && (*(p + 1) == '/') )
1046 {
1047 *q++ = *p++;
1048
1049 *p = '\0';
1050 if ((*xstat) (input_name, &dir_stat) < 0)
1051 {
1052 stat_error (input_name);
1053 return input_name;
1054 }
1055 *p = '/';
1056
1057 if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) )
1058 *q++ = '/';
1059 }
1060 *q++ = *p++;
1061 }
1062 *q = '\0';
1063
1064 return ret_name;
1065 }
1066
1067 /* Is the last parent directory (e.g., c in a/b/c/d) a CDF? If the
1068 directory name ends in `+' and is followed by 2 `/'s instead of 1
1069 then it is. This is only the case for cpio archives, but we don't
1070 have to worry about tar because tar always has the directory before
1071 its files (or else we lose). */
1072 int
1073 islastparentcdf (char *path)
1074 {
1075 char *newpath;
1076 char *slash;
1077 int slash_count;
1078 int length; /* Length of result, not including NUL. */
1079
1080 slash = strrchr (path, '/');
1081 if (slash == 0)
1082 return 0;
1083 else
1084 {
1085 slash_count = 0;
1086 while (slash > path && *slash == '/')
1087 {
1088 ++slash_count;
1089 --slash;
1090 }
1091
1092
1093 if ( (*slash == '+') && (slash_count >= 2) )
1094 return 1;
1095 }
1096 return 0;
1097 }
1098 #endif
1099
1100 #define DISKBLOCKSIZE (512)
1101
1102 static int
1103 buf_all_zeros (char *buf, int bufsize)
1104 {
1105 int i;
1106 for (i = 0; i < bufsize; ++i)
1107 {
1108 if (*buf++ != '\0')
1109 return 0;
1110 }
1111 return 1;
1112 }
1113
1114 int delayed_seek_count = 0;
1115
1116 /* Write NBYTE bytes from BUF to remote tape connection FILDES.
1117 Return the number of bytes written on success, -1 on error. */
1118
1119 static int
1120 sparse_write (int fildes, char *buf, unsigned int nbyte)
1121 {
1122 int complete_block_count;
1123 int leftover_bytes_count;
1124 int seek_count;
1125 int write_count;
1126 char *cur_write_start;
1127 int lseek_rc;
1128 int write_rc;
1129 int i;
1130 enum { begin, in_zeros, not_in_zeros } state;
1131
1132 complete_block_count = nbyte / DISKBLOCKSIZE;
1133 leftover_bytes_count = nbyte % DISKBLOCKSIZE;
1134
1135 if (delayed_seek_count != 0)
1136 state = in_zeros;
1137 else
1138 state = begin;
1139
1140 seek_count = delayed_seek_count;
1141
1142 for (i = 0; i < complete_block_count; ++i)
1143 {
1144 switch (state)
1145 {
1146 case begin :
1147 if (buf_all_zeros (buf, DISKBLOCKSIZE))
1148 {
1149 seek_count = DISKBLOCKSIZE;
1150 state = in_zeros;
1151 }
1152 else
1153 {
1154 cur_write_start = buf;
1155 write_count = DISKBLOCKSIZE;
1156 state = not_in_zeros;
1157 }
1158 buf += DISKBLOCKSIZE;
1159 break;
1160
1161 case in_zeros :
1162 if (buf_all_zeros (buf, DISKBLOCKSIZE))
1163 {
1164 seek_count += DISKBLOCKSIZE;
1165 }
1166 else
1167 {
1168 lseek (fildes, seek_count, SEEK_CUR);
1169 cur_write_start = buf;
1170 write_count = DISKBLOCKSIZE;
1171 state = not_in_zeros;
1172 }
1173 buf += DISKBLOCKSIZE;
1174 break;
1175
1176 case not_in_zeros :
1177 if (buf_all_zeros (buf, DISKBLOCKSIZE))
1178 {
1179 write_rc = write (fildes, cur_write_start, write_count);
1180 seek_count = DISKBLOCKSIZE;
1181 state = in_zeros;
1182 }
1183 else
1184 {
1185 write_count += DISKBLOCKSIZE;
1186 }
1187 buf += DISKBLOCKSIZE;
1188 break;
1189 }
1190 }
1191
1192 switch (state)
1193 {
1194 case begin :
1195 case in_zeros :
1196 delayed_seek_count = seek_count;
1197 break;
1198
1199 case not_in_zeros :
1200 write_rc = write (fildes, cur_write_start, write_count);
1201 delayed_seek_count = 0;
1202 break;
1203 }
1204
1205 if (leftover_bytes_count != 0)
1206 {
1207 if (delayed_seek_count != 0)
1208 {
1209 lseek_rc = lseek (fildes, delayed_seek_count, SEEK_CUR);
1210 delayed_seek_count = 0;
1211 }
1212 write_rc = write (fildes, buf, leftover_bytes_count);
1213 }
1214 return nbyte;
1215 }
1216
1217 #define CPIO_UID(uid) (set_owner_flag ? set_owner : (uid))
1218 #define CPIO_GID(gid) (set_group_flag ? set_group : (gid))
1219
1220 void
1221 stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st)
1222 {
1223 hdr->c_dev_maj = major (st->st_dev);
1224 hdr->c_dev_min = minor (st->st_dev);
1225 hdr->c_ino = st->st_ino;
1226 /* For POSIX systems that don't define the S_IF macros,
1227 we can't assume that S_ISfoo means the standard Unix
1228 S_IFfoo bit(s) are set. So do it manually, with a
1229 different name. Bleah. */
1230 hdr->c_mode = (st->st_mode & 07777);
1231 if (S_ISREG (st->st_mode))
1232 hdr->c_mode |= CP_IFREG;
1233 else if (S_ISDIR (st->st_mode))
1234 hdr->c_mode |= CP_IFDIR;
1235 #ifdef S_ISBLK
1236 else if (S_ISBLK (st->st_mode))
1237 hdr->c_mode |= CP_IFBLK;
1238 #endif
1239 #ifdef S_ISCHR
1240 else if (S_ISCHR (st->st_mode))
1241 hdr->c_mode |= CP_IFCHR;
1242 #endif
1243 #ifdef S_ISFIFO
1244 else if (S_ISFIFO (st->st_mode))
1245 hdr->c_mode |= CP_IFIFO;
1246 #endif
1247 #ifdef S_ISLNK
1248 else if (S_ISLNK (st->st_mode))
1249 hdr->c_mode |= CP_IFLNK;
1250 #endif
1251 #ifdef S_ISSOCK
1252 else if (S_ISSOCK (st->st_mode))
1253 hdr->c_mode |= CP_IFSOCK;
1254 #endif
1255 #ifdef S_ISNWK
1256 else if (S_ISNWK (st->st_mode))
1257 hdr->c_mode |= CP_IFNWK;
1258 #endif
1259 hdr->c_uid = CPIO_UID (st->st_uid);
1260 hdr->c_gid = CPIO_GID (st->st_gid);
1261 hdr->c_nlink = st->st_nlink;
1262 hdr->c_rdev_maj = major (st->st_rdev);
1263 hdr->c_rdev_min = minor (st->st_rdev);
1264 hdr->c_mtime = st->st_mtime;
1265 hdr->c_filesize = st->st_size;
1266 hdr->c_chksum = 0;
1267 hdr->c_tar_linkname = NULL;
1268 }
1269
1270 #ifndef HAVE_FCHOWN
1271 # define HAVE_FCHOWN 0
1272 #endif
1273 #ifndef HAVE_FCHMOD
1274 # define HAVE_FCHMOD 0
1275 #endif
1276
1277 int
1278 fchown_or_chown (int fd, const char *name, uid_t uid, uid_t gid)
1279 {
1280 if (HAVE_FCHOWN && fd != -1)
1281 return fchown (fd, uid, gid);
1282 else
1283 return chown (name, uid, gid);
1284 }
1285
1286 int
1287 fchmod_or_chmod (int fd, const char *name, mode_t mode)
1288 {
1289 if (HAVE_FCHMOD && fd != -1)
1290 return fchmod (fd, mode);
1291 else
1292 return chmod(name, mode);
1293 }
1294
1295 void
1296 set_perms (int fd, struct cpio_file_stat *header)
1297 {
1298 if (!no_chown_flag)
1299 {
1300 uid_t uid = CPIO_UID (header->c_uid);
1301 gid_t gid = CPIO_GID (header->c_gid);
1302 if ((fchown_or_chown (fd, header->c_name, uid, gid) < 0)
1303 && errno != EPERM)
1304 chown_error_details (header->c_name, uid, gid);
1305 }
1306 /* chown may have turned off some permissions we wanted. */
1307 if (fchmod_or_chmod (fd, header->c_name, header->c_mode) < 0)
1308 chmod_error_details (header->c_name, header->c_mode);
1309 #ifdef HPUX_CDF
1310 if ((header->c_mode & CP_IFMT) && cdf_flag)
1311 /* Once we "hide" the directory with the chmod(),
1312 we have to refer to it using name+ instead of name. */
1313 file_hdr->c_name [cdf_char] = '+';
1314 #endif
1315 if (retain_time_flag)
1316 set_file_times (fd, header->c_name, header->c_mtime, header->c_mtime);
1317 }
1318
1319 void
1320 set_file_times (int fd,
1321 const char *name, unsigned long atime, unsigned long mtime)
1322 {
1323 struct timespec ts[2];
1324
1325 memset (&ts, 0, sizeof ts);
1326
1327 ts[0].tv_sec = atime;
1328 ts[1].tv_sec = mtime;
1329
1330 /* Silently ignore EROFS because reading the file won't have upset its
1331 timestamp if it's on a read-only filesystem. */
1332 if (gl_futimens (fd, name, ts) < 0 && errno != EROFS)
1333 utime_error (name);
1334 }
1335
1336 /* Do we have to ignore absolute paths, and if so, does the filename
1337 have an absolute path? */
1338 void
1339 cpio_safer_name_suffix (char *name, bool link_target, bool absolute_names,
1340 bool strip_leading_dots)
1341 {
1342 char *p = safer_name_suffix (name, link_target, absolute_names);
1343 if (strip_leading_dots && strcmp (p, "./"))
1344 /* strip leading `./' from the filename. */
1345 while (*p == '.' && *(p + 1) == '/')
1346 {
1347 ++p;
1348 while (*p == '/')
1349 ++p;
1350 }
1351 if (p != name)
1352 memmove (name, p, (size_t)(strlen (p) + 1));
1353 }
1354
1355
1356 /* This is a simplified form of delayed set_stat used by GNU tar.
1357 With the time, both forms will merge and pass to paxutils
1358
1359 List of directories whose statuses we need to extract after we've
1360 finished extracting their subsidiary files. If you consider each
1361 contiguous subsequence of elements of the form [D]?[^D]*, where [D]
1362 represents an element where AFTER_LINKS is nonzero and [^D]
1363 represents an element where AFTER_LINKS is zero, then the head
1364 of the subsequence has the longest name, and each non-head element
1365 in the prefix is an ancestor (in the directory hierarchy) of the
1366 preceding element. */
1367
1368 struct delayed_set_stat
1369 {
1370 struct delayed_set_stat *next;
1371 struct cpio_file_stat stat;
1372 mode_t invert_permissions;
1373 };
1374
1375 static struct delayed_set_stat *delayed_set_stat_head;
1376
1377 void
1378 delay_set_stat (char const *file_name, struct stat *st,
1379 mode_t invert_permissions)
1380 {
1381 size_t file_name_len = strlen (file_name);
1382 struct delayed_set_stat *data =
1383 xmalloc (sizeof (struct delayed_set_stat) + file_name_len + 1);
1384 data->next = delayed_set_stat_head;
1385 memset (&data->stat, 0, sizeof data->stat);
1386 stat_to_cpio (&data->stat, st);
1387 data->stat.c_name = (char*) (data + 1);
1388 strcpy (data->stat.c_name, file_name);
1389 data->invert_permissions = invert_permissions;
1390 delayed_set_stat_head = data;
1391 }
1392
1393 /* Update the delayed_set_stat info for an intermediate directory
1394 created within the file name of DIR. The intermediate directory turned
1395 out to be the same as this directory, e.g. due to ".." or symbolic
1396 links. *DIR_STAT_INFO is the status of the directory. */
1397 void
1398 repair_delayed_set_stat (char const *dir,
1399 struct stat *dir_stat_info)
1400 {
1401 struct delayed_set_stat *data;
1402 for (data = delayed_set_stat_head; data; data = data->next)
1403 {
1404 struct stat st;
1405 if (stat (data->stat.c_name, &st) != 0)
1406 {
1407 stat_error (data->stat.c_name);
1408 return;
1409 }
1410
1411 if (st.st_dev == dir_stat_info->st_dev
1412 && st.st_ino == dir_stat_info->st_ino)
1413 {
1414 stat_to_cpio (&data->stat, dir_stat_info);
1415 data->invert_permissions =
1416 ((dir_stat_info->st_mode ^ st.st_mode)
1417 & MODE_RWX & ~ newdir_umask);
1418 return;
1419 }
1420 }
1421
1422 ERROR ((0, 0, _("%s: Unexpected inconsistency when making directory"),
1423 quotearg_colon (dir)));
1424 }
1425
1426 void
1427 apply_delayed_set_stat ()
1428 {
1429 while (delayed_set_stat_head)
1430 {
1431 struct delayed_set_stat *data = delayed_set_stat_head;
1432 if (data->invert_permissions)
1433 {
1434 data->stat.c_mode ^= data->invert_permissions;
1435 }
1436 set_perms (-1, &data->stat);
1437 delayed_set_stat_head = data->next;
1438 free (data);
1439 }
1440 }

Send suggestions and bug reports to Sergey Poznyakoff
ViewVC Help
Powered by ViewVC 1.1.20