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