43 |
# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) |
# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) |
44 |
# endif |
# endif |
45 |
|
|
|
# ifndef FILE_SYSTEM_PREFIX_LEN |
|
|
# define FILE_SYSTEM_PREFIX_LEN(Filename) 0 |
|
|
# endif |
|
|
|
|
|
#ifndef SYMLINK_USES_UMASK |
|
|
# define UMASKED_SYMLINK(name1,name2,mode) symlink(name1,name2) |
|
|
#else |
|
|
# define UMASKED_SYMLINK(name1,name2,mode) umasked_symlink(name1,name2,mode) |
|
|
#endif /* SYMLINK_USES_UMASK */ |
|
|
|
|
46 |
/* Return 1 if an array of N objects, each of size S, cannot exist due |
/* Return 1 if an array of N objects, each of size S, cannot exist due |
47 |
to size arithmetic overflow. S must be positive and N must be |
to size arithmetic overflow. S must be positive and N must be |
48 |
nonnegative. This is a macro, not an inline function, so that it |
nonnegative. This is a macro, not an inline function, so that it |
82 |
|
|
83 |
struct new_cpio_header { |
struct new_cpio_header { |
84 |
unsigned short c_magic; |
unsigned short c_magic; |
85 |
unsigned long c_ino; |
union { |
86 |
unsigned long c_mode; |
struct { |
87 |
unsigned long c_uid; |
unsigned long c_ino; |
88 |
unsigned long c_gid; |
unsigned long c_mode; |
89 |
unsigned long c_nlink; |
unsigned long c_uid; |
90 |
unsigned long c_mtime; |
unsigned long c_gid; |
91 |
unsigned long c_filesize; |
unsigned long c_nlink; |
92 |
long c_dev_maj; |
unsigned long c_mtime; |
93 |
long c_dev_min; |
unsigned long c_filesize; |
94 |
long c_rdev_maj; |
long c_dev_maj; |
95 |
long c_rdev_min; |
long c_dev_min; |
96 |
unsigned long c_namesize; |
long c_rdev_maj; |
97 |
unsigned long c_chksum; |
long c_rdev_min; |
98 |
|
unsigned long c_namesize; |
99 |
|
unsigned long c_chksum; |
100 |
|
}; |
101 |
|
unsigned long c_hdr[13]; |
102 |
|
}; |
103 |
char *c_name; |
char *c_name; |
104 |
char *c_tar_linkname; |
char *c_tar_linkname; |
105 |
}; |
}; |
106 |
|
|
107 |
/* Total number of bytes read and written for all files. |
/* Total number of bytes read and written for all files. |
108 |
Now that many tape drives hold more than 4Gb we need more than 32 |
* Now that many tape drives hold more than 4Gb we need more than 32 |
109 |
bits to hold input_bytes and output_bytes. But it's not worth |
* bits to hold input_bytes and output_bytes. |
110 |
the trouble of adding special multi-precision arithmetic if the |
*/ |
|
compiler doesn't support 64 bit ints since input_bytes and |
|
|
output_bytes are only used to print the number of blocks copied. */ |
|
|
#ifdef __GNUC__ |
|
111 |
long long input_bytes, output_bytes; |
long long input_bytes, output_bytes; |
|
#else |
|
|
long input_bytes, output_bytes; |
|
|
#endif |
|
112 |
|
|
113 |
/* Allocate N bytes of memory dynamically, with error checking. */ |
/* Allocate N bytes of memory dynamically, with error checking. */ |
114 |
|
|
115 |
void *xmalloc(size_t n) |
static void *xmalloc(size_t n) |
116 |
{ |
{ |
117 |
void *p; |
void *p; |
118 |
if (xalloc_oversized(n, 1) || (!(p = malloc(n)) && n != 0)) { |
if (xalloc_oversized(n, 1) || (!(p = malloc(n)) && n != 0)) { |
123 |
/* return xnmalloc_inline (n, 1); */ |
/* return xnmalloc_inline (n, 1); */ |
124 |
} |
} |
125 |
|
|
|
/* Change the size of an allocated block of memory P to N bytes, |
|
|
with error checking. */ |
|
|
|
|
|
void *xrealloc(void *p, size_t n) |
|
|
{ |
|
|
if (xalloc_oversized(n, 1) || (!(p = realloc(p, n)) && n != 0)) { |
|
|
fprintf(stderr, "%s: memory exhausted\n", progname); |
|
|
exit(1); |
|
|
} |
|
|
return p; |
|
|
/* return xnrealloc_inline (p, n, 1); */ |
|
|
} |
|
|
|
|
126 |
/* Clone STRING. */ |
/* Clone STRING. */ |
127 |
|
|
128 |
char *xstrdup(char const *string) |
static char *xstrdup(char const *string) |
129 |
{ |
{ |
130 |
size_t s = strlen(string) + 1; |
size_t s = strlen(string) + 1; |
131 |
return memcpy(xmalloc(s), string, s); |
return memcpy(xmalloc(s), string, s); |
157 |
descriptor OUT_DES and reset `output_size' and `out_buff'. |
descriptor OUT_DES and reset `output_size' and `out_buff'. |
158 |
If `swapping_halfwords' or `swapping_bytes' is set, |
If `swapping_halfwords' or `swapping_bytes' is set, |
159 |
do the appropriate swapping first. Our callers have |
do the appropriate swapping first. Our callers have |
160 |
to make sure to only set these flags if `output_size' |
to make sure to only set these flags if `output_size' |
161 |
is appropriate (a multiple of 4 for `swapping_halfwords', |
is appropriate (a multiple of 4 for `swapping_halfwords', |
162 |
2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE |
2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE |
163 |
must always be a multiple of 4 helps us (and our callers) |
must always be a multiple of 4 helps us (and our callers) |
164 |
insure this. */ |
insure this. */ |
165 |
|
|
166 |
void disk_empty_output_buffer(int out_des) |
static void disk_empty_output_buffer(int out_des) |
167 |
{ |
{ |
168 |
int bytes_written; |
int bytes_written; |
169 |
|
|
182 |
/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full. |
/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full. |
183 |
When `out_buff' fills up, flush it to file descriptor OUT_DES. */ |
When `out_buff' fills up, flush it to file descriptor OUT_DES. */ |
184 |
|
|
185 |
void disk_buffered_write(char *in_buf, int out_des, long num_bytes) |
static void disk_buffered_write(char *in_buf, int out_des, long num_bytes) |
186 |
{ |
{ |
187 |
register long bytes_left = num_bytes; /* Bytes needing to be copied. */ |
register long bytes_left = num_bytes; /* Bytes needing to be copied. */ |
188 |
register long space_left; /* Room left in output buffer. */ |
register long space_left; /* Room left in output buffer. */ |
211 |
OUT_DES is the file descriptor for output; |
OUT_DES is the file descriptor for output; |
212 |
NUM_BYTES is the number of bytes to copy. */ |
NUM_BYTES is the number of bytes to copy. */ |
213 |
|
|
214 |
void copy_files_tape_to_disk(int in_des, int out_des, long num_bytes) |
static void copy_files_tape_to_disk(int in_des, int out_des, long num_bytes) |
215 |
{ |
{ |
216 |
long size; |
long size; |
217 |
|
|
227 |
} |
} |
228 |
|
|
229 |
/* if IN_BUF is NULL, Skip the next NUM_BYTES bytes of file descriptor IN_DES. */ |
/* if IN_BUF is NULL, Skip the next NUM_BYTES bytes of file descriptor IN_DES. */ |
230 |
void tape_buffered_read(char *in_buf, int in_des, long num_bytes) |
static void tape_buffered_read(char *in_buf, int in_des, long num_bytes) |
231 |
{ |
{ |
232 |
register long bytes_left = num_bytes; /* Bytes needing to be copied. */ |
register long bytes_left = num_bytes; /* Bytes needing to be copied. */ |
233 |
register long space_left; /* Bytes to copy from input buffer. */ |
register long space_left; /* Bytes to copy from input buffer. */ |
258 |
struct new_cpio_header header; |
struct new_cpio_header header; |
259 |
}; |
}; |
260 |
|
|
261 |
struct deferment *create_deferment(struct new_cpio_header *file_hdr) |
static struct deferment *create_deferment(struct new_cpio_header *file_hdr) |
262 |
{ |
{ |
263 |
struct deferment *d; |
struct deferment *d; |
264 |
d = (struct deferment *)xmalloc(sizeof(struct deferment)); |
d = (struct deferment *)xmalloc(sizeof(struct deferment)); |
268 |
return d; |
return d; |
269 |
} |
} |
270 |
|
|
271 |
void free_deferment(struct deferment *d) |
static void free_deferment(struct deferment *d) |
272 |
{ |
{ |
273 |
free(d->header.c_name); |
free(d->header.c_name); |
274 |
free(d); |
free(d); |
275 |
} |
} |
276 |
|
|
277 |
int link_to_name(char *link_name, char *link_target) |
static int link_to_name(char *link_name, char *link_target) |
278 |
{ |
{ |
279 |
int res = link(link_target, link_name); |
int res = link(link_target, link_name); |
280 |
return res; |
return res; |
328 |
|
|
329 |
/* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */ |
/* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */ |
330 |
|
|
331 |
void |
static void |
332 |
add_inode(unsigned long node_num, char *file_name, unsigned long major_num, |
add_inode(unsigned long node_num, char *file_name, unsigned long major_num, |
333 |
unsigned long minor_num) |
unsigned long minor_num) |
334 |
{ |
{ |
365 |
for (i = 0; i < hash_num; i++) |
for (i = 0; i < hash_num; i++) |
366 |
hash_insert(old_table[i]); |
hash_insert(old_table[i]); |
367 |
|
|
368 |
if (old_table != NULL) |
free(old_table); |
|
free(old_table); |
|
369 |
} |
} |
370 |
|
|
371 |
/* Insert the new record and increment the count of elements in the |
/* Insert the new record and increment the count of elements in the |
374 |
hash_num++; |
hash_num++; |
375 |
} |
} |
376 |
|
|
377 |
char *find_inode_file(unsigned long node_num, unsigned long major_num, |
static char *find_inode_file(unsigned long node_num, unsigned long major_num, |
378 |
unsigned long minor_num) |
unsigned long minor_num) |
379 |
{ |
{ |
380 |
int start; /* Initial hash location. */ |
int start; /* Initial hash location. */ |
406 |
return NULL; |
return NULL; |
407 |
} |
} |
408 |
|
|
409 |
/* Try and create a hard link from FILE_NAME to another file |
/* Try and create a hard link from FILE_NAME to another file |
410 |
with the given major/minor device number and inode. If no other |
with the given major/minor device number and inode. If no other |
411 |
file with the same major/minor/inode numbers is known, add this file |
file with the same major/minor/inode numbers is known, add this file |
412 |
to the list of known files and associated major/minor/inode numbers |
to the list of known files and associated major/minor/inode numbers |
414 |
numbers is found, try and create another link to it using |
numbers is found, try and create another link to it using |
415 |
link_to_name, and return 0 for success and -1 for failure. */ |
link_to_name, and return 0 for success and -1 for failure. */ |
416 |
|
|
417 |
int |
static int |
418 |
link_to_maj_min_ino(char *file_name, int st_dev_maj, int st_dev_min, int st_ino) |
link_to_maj_min_ino(char *file_name, int st_dev_maj, int st_dev_min, int st_ino) |
419 |
{ |
{ |
420 |
int link_res; |
int link_res; |
432 |
static void copyin_regular_file(struct new_cpio_header *file_hdr, |
static void copyin_regular_file(struct new_cpio_header *file_hdr, |
433 |
int in_file_des); |
int in_file_des); |
434 |
|
|
435 |
void warn_junk_bytes(long bytes_skipped) |
static void warn_junk_bytes(long bytes_skipped) |
436 |
{ |
{ |
437 |
fprintf(stderr, "%s: warning: skipped %ld byte(s) of junk\n", |
fprintf(stderr, "%s: warning: skipped %ld byte(s) of junk\n", |
438 |
progname, bytes_skipped); |
progname, bytes_skipped); |
481 |
return 0; |
return 0; |
482 |
} |
} |
483 |
|
|
484 |
/* The newc and crc formats store multiply linked copies of the same file |
/* The newc and crc formats store multiply linked copies of the same file |
485 |
in the archive only once. The actual data is attached to the last link |
in the archive only once. The actual data is attached to the last link |
486 |
in the archive, and the other links all have a filesize of 0. When a |
in the archive, and the other links all have a filesize of 0. When a |
487 |
file in the archive has multiple links and a filesize of 0, its data is |
file in the archive has multiple links and a filesize of 0, its data is |
488 |
probably "attatched" to another file in the archive, so we can't create |
probably "attatched" to another file in the archive, so we can't create |
489 |
it right away. We have to "defer" creating it until we have created |
it right away. We have to "defer" creating it until we have created |
490 |
the file that has the data "attatched" to it. We keep a list of the |
the file that has the data "attatched" to it. We keep a list of the |
553 |
we are done reading the whole archive. Write out all of these |
we are done reading the whole archive. Write out all of these |
554 |
empty links that are still on the deferments list. */ |
empty links that are still on the deferments list. */ |
555 |
|
|
556 |
static void create_final_defers() |
static void create_final_defers(void) |
557 |
{ |
{ |
558 |
struct deferment *d; |
struct deferment *d; |
559 |
int link_res; |
int link_res; |
679 |
|
|
680 |
tape_skip_padding(in_file_des, file_hdr->c_filesize); |
tape_skip_padding(in_file_des, file_hdr->c_filesize); |
681 |
if (file_hdr->c_nlink > 1) { |
if (file_hdr->c_nlink > 1) { |
682 |
/* (see comment above for how the newc and crc formats |
/* (see comment above for how the newc and crc formats |
683 |
store multiple links). Now that we have the data |
store multiple links). Now that we have the data |
684 |
for this file, create any other links to it which |
for this file, create any other links to it which |
685 |
we defered. */ |
we defered. */ |
686 |
create_defered_links(file_hdr); |
create_defered_links(file_hdr); |
695 |
NAME has no file name components because it is all slashes, return |
NAME has no file name components because it is all slashes, return |
696 |
NAME if it is empty, the address of its last slash otherwise. */ |
NAME if it is empty, the address of its last slash otherwise. */ |
697 |
|
|
698 |
char *base_name(char const *name) |
static char *base_name(char const *name) |
699 |
{ |
{ |
700 |
char const *base = name + FILE_SYSTEM_PREFIX_LEN(name); |
char const *base = name; |
701 |
char const *p; |
char const *p; |
702 |
|
|
703 |
for (p = base; *p; p++) { |
for (p = base; *p; p++) { |
727 |
value returned by base_name. Act like strlen (NAME), except omit |
value returned by base_name. Act like strlen (NAME), except omit |
728 |
redundant trailing slashes. */ |
redundant trailing slashes. */ |
729 |
|
|
730 |
size_t base_len(char const *name) |
static size_t base_len(char const *name) |
731 |
{ |
{ |
732 |
size_t len; |
size_t len; |
733 |
|
|
744 |
the Unix rename and rmdir system calls return an "Invalid argument" error |
the Unix rename and rmdir system calls return an "Invalid argument" error |
745 |
when given a path that ends in "/" (except for the root directory). */ |
when given a path that ends in "/" (except for the root directory). */ |
746 |
|
|
747 |
bool strip_trailing_slashes(char *path) |
static bool strip_trailing_slashes(char *path) |
748 |
{ |
{ |
749 |
char *base = base_name(path); |
char *base = base_name(path); |
750 |
char *base_lim = base + base_len(base); |
char *base_lim = base + base_len(base); |
844 |
tape_buffered_read(link_name, in_file_des, file_hdr->c_filesize); |
tape_buffered_read(link_name, in_file_des, file_hdr->c_filesize); |
845 |
tape_skip_padding(in_file_des, file_hdr->c_filesize); |
tape_skip_padding(in_file_des, file_hdr->c_filesize); |
846 |
|
|
847 |
res = UMASKED_SYMLINK(link_name, file_hdr->c_name, file_hdr->c_mode); |
res = symlink(link_name, file_hdr->c_name); |
848 |
if (res < 0) { |
if (res < 0) { |
849 |
fprintf(stderr, "%s: UMASKED_SYMLINK %s: %s\n", |
fprintf(stderr, "%s: symlink %s: %s\n", |
850 |
progname, file_hdr->c_name, strerror(errno)); |
progname, file_hdr->c_name, strerror(errno)); |
851 |
free(link_name); |
free(link_name); |
852 |
return; |
return; |
878 |
|
|
879 |
case S_IFCHR: |
case S_IFCHR: |
880 |
case S_IFBLK: |
case S_IFBLK: |
|
#ifdef S_IFSOCK |
|
881 |
case S_IFSOCK: |
case S_IFSOCK: |
|
#endif |
|
|
#ifdef S_IFIFO |
|
882 |
case S_IFIFO: |
case S_IFIFO: |
|
#endif |
|
883 |
copyin_device(file_hdr); |
copyin_device(file_hdr); |
884 |
break; |
break; |
885 |
|
|
|
#ifdef S_IFLNK |
|
886 |
case S_IFLNK: |
case S_IFLNK: |
887 |
copyin_link(file_hdr, in_file_des); |
copyin_link(file_hdr, in_file_des); |
888 |
break; |
break; |
|
#endif |
|
889 |
|
|
890 |
default: |
default: |
891 |
fprintf(stderr, "%s: %s: unknown file type\n", |
fprintf(stderr, "%s: %s: unknown file type\n", |
899 |
file descriptor IN_DES, except for the magic number, which is |
file descriptor IN_DES, except for the magic number, which is |
900 |
already filled in. */ |
already filled in. */ |
901 |
|
|
902 |
void read_in_new_ascii(struct new_cpio_header *file_hdr, int in_des) |
static void read_in_new_ascii(struct new_cpio_header *file_hdr, int in_des) |
903 |
{ |
{ |
904 |
char ascii_header[112]; |
char ascii_header[13*8], *ah, hexbuf[9]; |
905 |
|
int i; |
906 |
|
|
907 |
tape_buffered_read(ascii_header, in_des, 104L); |
tape_buffered_read(ascii_header, in_des, 13*8); |
908 |
ascii_header[104] = '\0'; |
ah = ascii_header; |
909 |
sscanf(ascii_header, |
hexbuf[8] = '\0'; |
910 |
"%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx", |
for (i = 0; i < 13; i++) { |
911 |
&file_hdr->c_ino, &file_hdr->c_mode, &file_hdr->c_uid, |
memcpy(hexbuf, ah, 8); |
912 |
&file_hdr->c_gid, &file_hdr->c_nlink, &file_hdr->c_mtime, |
file_hdr->c_hdr[i] = strtoul(hexbuf, NULL, 16); |
913 |
&file_hdr->c_filesize, &file_hdr->c_dev_maj, |
ah += 8; |
914 |
&file_hdr->c_dev_min, &file_hdr->c_rdev_maj, |
} |
|
&file_hdr->c_rdev_min, &file_hdr->c_namesize, |
|
|
&file_hdr->c_chksum); |
|
915 |
/* Read file name from input. */ |
/* Read file name from input. */ |
916 |
if (file_hdr->c_name != NULL) |
free(file_hdr->c_name); |
|
free(file_hdr->c_name); |
|
917 |
file_hdr->c_name = (char *)xmalloc(file_hdr->c_namesize); |
file_hdr->c_name = (char *)xmalloc(file_hdr->c_namesize); |
918 |
tape_buffered_read(file_hdr->c_name, in_des, |
tape_buffered_read(file_hdr->c_name, in_des, |
919 |
(long)file_hdr->c_namesize); |
(long)file_hdr->c_namesize); |
930 |
/* Read the header, including the name of the file, from file |
/* Read the header, including the name of the file, from file |
931 |
descriptor IN_DES into FILE_HDR. */ |
descriptor IN_DES into FILE_HDR. */ |
932 |
|
|
933 |
void read_in_header(struct new_cpio_header *file_hdr, int in_des) |
static void read_in_header(struct new_cpio_header *file_hdr, int in_des) |
934 |
{ |
{ |
935 |
long bytes_skipped = 0; /* Bytes of junk found before magic number. */ |
long bytes_skipped = 0; /* Bytes of junk found before magic number. */ |
936 |
|
|
958 |
/* Read the collection from standard input and create files |
/* Read the collection from standard input and create files |
959 |
in the file system. */ |
in the file system. */ |
960 |
|
|
961 |
void process_copy_in() |
static void process_copy_in(void) |
962 |
{ |
{ |
963 |
char done = false; /* True if trailer reached. */ |
char done = false; /* True if trailer reached. */ |
964 |
struct new_cpio_header file_hdr; /* Output header information. */ |
struct new_cpio_header file_hdr; /* Output header information. */ |
1000 |
initialize all variables associated with the input and output |
initialize all variables associated with the input and output |
1001 |
buffers. */ |
buffers. */ |
1002 |
|
|
1003 |
void initialize_buffers() |
static void initialize_buffers(void) |
1004 |
{ |
{ |
1005 |
int in_buf_size, out_buf_size; |
int in_buf_size, out_buf_size; |
1006 |
|
|