Commit | Line | Data |
---|---|---|
5e002034 | 1 | /*- |
ba5e8546 KB |
2 | * Copyright (c) 1991, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
5e002034 KB |
4 | * |
5 | * This code is derived from software contributed to Berkeley by | |
a08a4cd0 KB |
6 | * Keith Muller of the University of California, San Diego and Lance |
7 | * Visser of Convex Computer Corporation. | |
5e002034 KB |
8 | * |
9 | * %sccs.include.redist.c% | |
10 | */ | |
11 | ||
12 | #ifndef lint | |
ba5e8546 | 13 | static char sccsid[] = "@(#)position.c 8.1 (Berkeley) %G%"; |
5e002034 KB |
14 | #endif /* not lint */ |
15 | ||
16 | #include <sys/types.h> | |
17 | #include <sys/stat.h> | |
18 | #include <sys/ioctl.h> | |
19 | #include <sys/mtio.h> | |
20 | #include <errno.h> | |
21 | #include <unistd.h> | |
22 | #include <string.h> | |
23 | #include "dd.h" | |
24 | #include "extern.h" | |
25 | ||
26 | /* | |
27 | * Position input/output data streams before starting the copy. Device type | |
28 | * dependent. Seekable devices use lseek, and the rest position by reading. | |
29 | * Seeking past the end of file can cause null blocks to be written to the | |
30 | * output. | |
31 | */ | |
32 | void | |
33 | pos_in() | |
34 | { | |
35 | register int bcnt, cnt, nr, warned; | |
36 | ||
37 | /* If not a character, pipe or tape device, try to seek on it. */ | |
38 | if (!(in.flags & (ISCHR|ISPIPE|ISTAPE))) { | |
39 | if (lseek(in.fd, (off_t)(in.offset * in.dbsz), SEEK_CUR) == -1) | |
40 | err("%s: %s", in.name, strerror(errno)); | |
41 | return; | |
42 | } | |
43 | ||
44 | /* | |
45 | * Read the data. If a pipe, read until satisfy the number of bytes | |
46 | * being skipped. No differentiation for reading complete and partial | |
47 | * blocks for other devices. | |
48 | */ | |
49 | for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { | |
5928f285 | 50 | if ((nr = read(in.fd, in.db, bcnt)) > 0) { |
5e002034 KB |
51 | if (in.flags & ISPIPE) { |
52 | if (!(bcnt -= nr)) { | |
53 | bcnt = in.dbsz; | |
54 | --cnt; | |
55 | } | |
5e002034 KB |
56 | } else |
57 | --cnt; | |
5928f285 KB |
58 | continue; |
59 | } | |
5e002034 KB |
60 | |
61 | if (nr == 0) { | |
62 | if (files_cnt > 1) { | |
63 | --files_cnt; | |
64 | continue; | |
65 | } | |
66 | err("skip reached end of input"); | |
67 | } | |
68 | ||
69 | /* | |
70 | * Input error -- either EOF with no more files, or I/O error. | |
71 | * If noerror not set die. POSIX requires that the warning | |
72 | * message be followed by an I/O display. | |
73 | */ | |
74 | if (ddflags & C_NOERROR) { | |
75 | if (!warned) { | |
76 | warn("%s: %s", in.name, strerror(errno)); | |
77 | warned = 1; | |
78 | summary(0); | |
79 | } | |
80 | continue; | |
81 | } | |
82 | err("%s: %s", in.name, strerror(errno)); | |
83 | } | |
84 | } | |
85 | ||
86 | void | |
87 | pos_out() | |
88 | { | |
89 | register int cnt, n; | |
90 | struct mtop t_op; | |
91 | ||
92 | /* | |
93 | * If not a tape, try seeking on the file. Seeking on a pipe is | |
94 | * going to fail, but don't protect the user -- they shouldn't | |
95 | * have specified the seek operand. | |
96 | */ | |
97 | if (!(out.flags & ISTAPE)) { | |
98 | if (lseek(out.fd, | |
99 | (off_t)out.offset * out.dbsz, SEEK_SET) == -1) | |
100 | err("%s: %s", out.name, strerror(errno)); | |
101 | return; | |
102 | } | |
103 | ||
104 | /* If no read access, try using mtio. */ | |
105 | if (out.flags & NOREAD) { | |
106 | t_op.mt_op = MTFSR; | |
107 | t_op.mt_count = out.offset; | |
108 | ||
109 | if (ioctl(out.fd, MTIOCTOP, &t_op) < 0) | |
110 | err("%s: %s", out.name, strerror(errno)); | |
111 | return; | |
112 | } | |
113 | ||
114 | /* Read it. */ | |
115 | for (cnt = 0; cnt < out.offset; ++cnt) { | |
116 | if ((n = read(out.fd, out.db, out.dbsz)) > 0) | |
117 | continue; | |
118 | ||
119 | if (n < 0) | |
120 | err("%s: %s", out.name, strerror(errno)); | |
121 | ||
122 | /* | |
123 | * If reach EOF, fill with NUL characters; first, back up over | |
124 | * the EOF mark. Note, cnt has not yet been incremented, so | |
125 | * the EOF read does not count as a seek'd block. | |
126 | */ | |
127 | t_op.mt_op = MTBSR; | |
128 | t_op.mt_count = 1; | |
129 | if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) | |
130 | err("%s: %s", out.name, strerror(errno)); | |
131 | ||
132 | while (cnt++ < out.offset) | |
133 | if ((n = write(out.fd, out.db, out.dbsz)) != out.dbsz) | |
134 | err("%s: %s", out.name, strerror(errno)); | |
135 | break; | |
136 | } | |
137 | } |