1 /*
2  * Copyright (c) 2008-2014 Douglas Gilbert.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 
30 /* ddpt is a utility program for copying files. It broadly follows the syntax
31  * and semantics of the "dd" program found in Unix. ddpt is specialised for
32  * "files" that represent storage devices, especially those that understand
33  * the SCSI command set accessed via a pass-through.
34  */
35 
36 /*
37  * The ddpt utility is a rewritten and extended version of the sg_dd utility
38  * found in the sg3_utils package. sg_dd has a GPL (version 2) which has been
39  * changed to a somewhat freer FreeBSD style license in ddpt.
40  * Both licenses are considered "open source".
41  *
42  * Windows "block" devices, when _not_ accessed via the pass-through, don't
43  * seem to work when POSIX/Unix like IO calls are used (e.g. write()).
44  * So need CreateFile, ReadFile, WriteFile, SetFilePointer and friends.
45  */
46 
47 /* Need _GNU_SOURCE for O_DIRECT */
48 #ifndef _GNU_SOURCE
49 #define _GNU_SOURCE
50 #endif
51 
52 #include <unistd.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <ctype.h>
57 #include <errno.h>
58 #include <limits.h>
59 #include <fcntl.h>
60 #define __STDC_FORMAT_MACROS 1
61 #include <inttypes.h>
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 
65 /* N.B. config.h must precede anything that depends on HAVE_*  */
66 #ifdef HAVE_CONFIG_H
67 #include "config.h"
68 #endif
69 
70 
71 static const char * ddpt_version_str = "0.95 20141226 [svn: r307]";
72 
73 #ifdef SG_LIB_LINUX
74 #include <sys/ioctl.h>
75 #include <sys/sysmacros.h>
76 #include <sys/file.h>
77 #include <linux/major.h>
78 #include <linux/fs.h>   /* <sys/mount.h> */
79 #include <linux/mtio.h> /* For tape ioctls */
80 #ifndef MTWEOFI
81 #define MTWEOFI 35  /* write an end-of-file record (mark) in immediate mode */
82 #endif
83 
84 #ifdef HAVE_FALLOCATE
85 #include <linux/falloc.h>
86 #ifndef FALLOC_FL_KEEP_SIZE
87 #define FALLOC_FL_KEEP_SIZE     0x01    /* from lk 3.1 linux/falloc.h */
88 #endif
89 #endif
90 
91 #endif  /* SG_LIB_LINUX */
92 
93 #ifdef SG_LIB_FREEBSD
94 #include <sys/ioctl.h>
95 #include <libgen.h>
96 #ifndef __DragonFly__
97 #include <sys/disk.h>
98 #endif
99 #include <sys/filio.h>
100 #endif
101 
102 #ifdef SG_LIB_SOLARIS
103 #include <sys/ioctl.h>
104 #include <sys/dkio.h>
105 #endif
106 
107 #ifdef SG_LIB_WIN32
108 #ifndef SG_LIB_MINGW
109 /* cygwin */
110 #include <sys/ioctl.h>
111 #endif
112 #endif
113 
114 #include "ddpt.h"
115 #include "sg_lib.h"
116 
117 #ifndef EREMOTEIO
118 #define EREMOTEIO EIO
119 #endif
120 
121 /* Used for outputting diagnostic messages for oflag=pre-alloc */
122 #define PREALLOC_DEBUG 1
123 
124 
125 
126 /* Returns open input file descriptor (>= 0) or a negative value
127  * (-SG_LIB_FILE_ERROR or -SG_LIB_CAT_OTHER) if error.
128  */
129 static int
open_if(struct opts_t * op)130 open_if(struct opts_t * op)
131 {
132     int flags;
133     int fd = -SG_LIB_FILE_ERROR;
134     char ebuff[EBUFF_SZ];
135     struct flags_t * ifp = op->iflagp;
136     struct dev_info_t * idip = op->idip;
137     const char * ifn = idip->fn;
138 
139     idip->d_type = dd_filetype(ifn, op->verbose);
140     if (FT_ERROR & idip->d_type) {
141         pr2serr("unable to access %s\n", ifn);
142         goto file_err;
143     } else if (((FT_BLOCK | FT_TAPE | FT_OTHER) & idip->d_type) && ifp->pt)
144         idip->d_type |= FT_PT;
145     if (op->verbose)
146         pr2serr(" >> Input file type: %s\n",
147                 dd_filetype_str(idip->d_type, ebuff, EBUFF_SZ, ifn));
148     if (!(FT_PT & idip->d_type) && op->rdprotect)
149         pr2serr("rdprotect ignored on non-pt device\n");
150     if ((FT_FIFO | FT_CHAR | FT_TAPE) & idip->d_type)
151         ++op->reading_fifo;
152 
153     if ((FT_TAPE & idip->d_type) && (FT_PT & idip->d_type)) {
154         pr2serr("SCSI tape device %s not supported via pt\n", ifn);
155         goto file_err;
156     }
157     if (FT_PT & idip->d_type) {
158         fd = pt_open_if(op, NULL);
159         if (-1 == fd)
160             goto file_err;
161         else if (fd < -1)
162             goto other_err;
163     }
164 #ifdef SG_LIB_WIN32
165     else if (FT_BLOCK & idip->d_type) {
166         if (win32_open_if(op, (ifp->excl ? O_EXCL : 0), op->verbose))
167             goto file_err;
168         fd = 0;
169     }
170 #endif
171     else {
172         flags = O_RDONLY;
173         if (ifp->direct)
174             flags |= O_DIRECT;
175         if (ifp->excl)
176             flags |= O_EXCL;
177         if (ifp->sync)
178             flags |= O_SYNC;
179         fd = open(ifn, flags);
180         if (fd < 0) {
181             pr2serr("could not open %s for reading: %s\n", ifn,
182                     safe_strerror(errno));
183             goto file_err;
184         } else {
185             if (sg_set_binary_mode(fd) < 0)
186                 perror("sg_set_binary_mode");
187             if (op->verbose)
188                 pr2serr("        open %s, flags=0x%x\n", ifn, flags);
189 #ifdef HAVE_POSIX_FADVISE
190             if (ifp->nocache) {
191                 int rt;
192 
193                 rt = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
194                 if (rt)
195                     pr2serr("%s: posix_fadvise(SEQUENTIAL), err=%d\n",
196                             __func__, rt);
197             }
198 #endif
199         }
200     }
201 #ifdef SG_LIB_LINUX
202     if (ifp->flock) {
203         int res;
204 
205         res = flock(fd, LOCK_EX | LOCK_NB);
206         if (res < 0) {
207             close(fd);
208             pr2serr("flock(LOCK_EX | LOCK_NB) on %s failed: %s\n",
209                     ifn, safe_strerror(errno));
210             return -SG_LIB_FLOCK_ERR;
211         }
212     }
213 #endif
214     return fd;
215 
216 file_err:
217     return -SG_LIB_FILE_ERROR;
218 other_err:
219     return -SG_LIB_CAT_OTHER;
220 }
221 
222 /* Returns open output file descriptor (>= 0), -1 for don't
223  * bother opening (e.g. /dev/null), or a more negative value
224  * (-SG_LIB_FILE_ERROR or -SG_LIB_CAT_OTHER) if error.
225  */
226 static int
open_of(struct opts_t * op)227 open_of(struct opts_t * op)
228 {
229     int flags;
230     int fd = -SG_LIB_FILE_ERROR;
231     int outf_exists = 0;
232     char ebuff[EBUFF_SZ];
233     struct stat st;
234     struct flags_t * ofp = op->oflagp;
235     struct dev_info_t * odip = op->odip;
236     const char * ofn = odip->fn;
237 
238     odip->d_type = dd_filetype(ofn, op->verbose);
239     if (((FT_BLOCK | FT_TAPE | FT_OTHER) & odip->d_type) && ofp->pt)
240         odip->d_type |= FT_PT;
241     odip->d_type_hold = odip->d_type;
242     if (op->verbose)
243         pr2serr(" >> Output file type: %s\n",
244                 dd_filetype_str(odip->d_type, ebuff, EBUFF_SZ, ofn));
245     if (!(FT_PT & odip->d_type) && op->wrprotect)
246         pr2serr("wrprotect ignored on non-pt device\n");
247 
248     if ((FT_TAPE & odip->d_type) && (FT_PT & odip->d_type)) {
249         pr2serr("SCSI tape device %s not supported via pt\n", ofn);
250         goto file_err;
251     }
252     if (FT_PT & odip->d_type) {
253         fd = pt_open_of(op, NULL);
254         if (-1 == fd)
255             goto file_err;
256         else if (fd < -1)
257             goto other_err;
258     } else if (FT_DEV_NULL & odip->d_type)
259         fd = -1; /* don't bother opening */
260 #ifdef SG_LIB_WIN32
261     else if (FT_BLOCK & odip->d_type) {
262         if (win32_open_of(op, (ofp->excl ? O_EXCL : 0), op->verbose))
263             goto file_err;
264         fd = 0;
265     }
266 #endif
267     else {      /* typically regular file or block device node */
268         int needs_ftruncate = 0;
269         int64_t offset = 0;
270 
271         memset(&st, 0, sizeof(st));
272         if (0 == stat(ofn, &st))
273             outf_exists = 1;
274         else if (ofp->pt) {
275             /* if oflag=pt, then creating a regular file is unhelpful */
276             pr2serr("Cannot create a regular file called %s as a pt\n", ofn);
277             goto other_err;
278         }
279         flags = ofp->sparing ? O_RDWR : O_WRONLY;
280         if (0 == outf_exists)
281             flags |= O_CREAT;
282         if (ofp->direct)
283             flags |= O_DIRECT;
284         if (ofp->excl)
285             flags |= O_EXCL;
286         if (ofp->sync)
287             flags |= O_SYNC;
288         if (ofp->append)
289             flags |= O_APPEND;
290         if ((FT_REG & odip->d_type) && outf_exists && ofp->trunc &&
291             (! ofp->nowrite)) {
292             if (op->seek > 0) {
293                 offset = op->seek * op->obs;
294                 if (st.st_size > offset)
295                     ++needs_ftruncate;  // only truncate to shorten
296             } else
297                 flags |= O_TRUNC;
298         }
299         if ((fd = open(ofn, flags, 0666)) < 0) {
300             pr2serr("could not open %s for writing: %s\n", ofn,
301                     safe_strerror(errno));
302             goto file_err;
303         }
304         if (needs_ftruncate && (offset > 0)) {
305             if (ftruncate(fd, offset) < 0) {
306                 pr2serr("could not ftruncate %s after open (seek): %s\n",
307                         ofn, safe_strerror(errno));
308                 goto file_err;
309             }
310             /* N.B. file offset (pointer) not changed by ftruncate */
311         }
312         if ((! outf_exists) && (FT_ERROR & odip->d_type)) {
313             odip->d_type = FT_REG;   /* exists now */
314             odip->d_type_hold = odip->d_type;
315         }
316         if (sg_set_binary_mode(fd) < 0)
317             perror("sg_set_binary_mode");
318         if (op->verbose) {
319             pr2serr("        %s %s, flags=0x%x\n",
320                     (outf_exists ? "open" : "create"), ofn, flags);
321             if (needs_ftruncate && (offset > 0))
322                 pr2serr("        truncated file at byte offset "
323                         "%" PRId64 " \n", offset);
324         }
325     }
326 #ifdef SG_LIB_LINUX
327     if (ofp->flock) {
328         int res;
329 
330         res = flock(fd, LOCK_EX | LOCK_NB);
331         if (res < 0) {
332             close(fd);
333             pr2serr("flock(LOCK_EX | LOCK_NB) on %s failed: %s\n",
334                     ofn, safe_strerror(errno));
335             return -SG_LIB_FLOCK_ERR;
336         }
337     }
338 #endif
339     return fd;
340 
341 file_err:
342     return -SG_LIB_FILE_ERROR;
343 other_err:
344     return -SG_LIB_CAT_OTHER;
345 }
346 
347 /* Helper for calc_count(). Attempts to size IFILE. Returns 0 if no error
348  * detected. */
349 static int
calc_count_in(struct opts_t * op,int64_t * in_num_blksp)350 calc_count_in(struct opts_t * op, int64_t * in_num_blksp)
351 {
352     int res;
353     struct stat st;
354     int in_blk_sz, in_type;
355 #ifndef SG_LIB_WIN32
356     int64_t num_blks, t;
357     int blk_sz;
358 #endif
359     const char * ifn = op->idip->fn;
360 
361     *in_num_blksp = -1;
362     in_type = op->idip->d_type;
363     if (FT_PT & in_type) {
364         if (op->iflagp->norcap) {
365             if ((FT_BLOCK & in_type) && (0 == op->iflagp->force)) {
366                 pr2serr(">> warning: norcap on input block device "
367                         "accessed via pt is risky.\n");
368                 pr2serr(">> Abort copy, use iflag=force to override.\n");
369                 return -1;
370             }
371             return 0;
372         }
373         res = pt_read_capacity(op, DDPT_ARG_IN, in_num_blksp, &in_blk_sz);
374         if (SG_LIB_CAT_UNIT_ATTENTION == res) {
375             pr2serr("Unit attention (readcap in), continuing\n");
376             res = pt_read_capacity(op, DDPT_ARG_IN, in_num_blksp,
377                                    &in_blk_sz);
378         } else if (SG_LIB_CAT_ABORTED_COMMAND == res) {
379             pr2serr("Aborted command (readcap in), continuing\n");
380             res = pt_read_capacity(op, DDPT_ARG_IN, in_num_blksp,
381                                    &in_blk_sz);
382         }
383         if (0 != res) {
384             if (res == SG_LIB_CAT_INVALID_OP)
385                 pr2serr("read capacity not supported on %s\n", ifn);
386             else if (res == SG_LIB_CAT_NOT_READY)
387                 pr2serr("read capacity failed on %s - not ready\n", ifn);
388             else
389                 pr2serr("Unable to read capacity on %s\n", ifn);
390             *in_num_blksp = -1;
391             return res;
392         } else {
393             if (op->verbose) {
394                 print_blk_sizes(ifn, "readcap", *in_num_blksp, in_blk_sz, 1);
395                 if (op->idip->prot_type > 0)
396                     pr2serr("    reports Protection_type=%d, p_i_exp=%d\n",
397                             op->idip->prot_type, op->idip->p_i_exp);
398             }
399             if ((*in_num_blksp > 0) && (in_blk_sz != op->ibs)) {
400                 pr2serr(">> warning: %s block size confusion: ibs=%d, "
401                         "device claims=%d\n", ifn, op->ibs, in_blk_sz);
402                 if (0 == op->iflagp->force) {
403                     pr2serr(">> abort copy, use iflag=force to override\n");
404                     return -1;
405                 }
406             }
407         }
408 #ifndef SG_LIB_WIN32
409         if ((FT_BLOCK & in_type) && (0 == op->iflagp->force) &&
410             (0 == get_blkdev_capacity(op, DDPT_ARG_IN, &num_blks,
411                                       &blk_sz))) {
412             t = (*in_num_blksp) * in_blk_sz;
413             if (t != (num_blks * blk_sz)) {
414                 pr2serr(">> warning: Size of input block device is "
415                         "different from pt size.\n>> Pass-through on block "
416                         "partition can give unexpected offsets.\n");
417                 pr2serr(">> Abort copy, use iflag=force to override.\n");
418                 return -1;
419             }
420         }
421 #endif
422     } else if ((op->dd_count > 0) && (0 == op->oflagp->resume))
423         return 0;
424     else if (FT_BLOCK & in_type) {
425         if (0 != get_blkdev_capacity(op, DDPT_ARG_IN, in_num_blksp,
426                                      &in_blk_sz)) {
427             pr2serr("Unable to read block capacity on %s\n", ifn);
428             *in_num_blksp = -1;
429         }
430         if (op->verbose)
431             print_blk_sizes(ifn, "blk", *in_num_blksp, in_blk_sz, 1);
432         if ((*in_num_blksp > 0) && (op->ibs != in_blk_sz)) {
433             pr2serr(">> warning: %s block size confusion: bs=%d, "
434                     "device claims=%d\n", ifn, op->ibs, in_blk_sz);
435             *in_num_blksp = -1;
436         }
437     } else if (FT_REG & in_type) {
438         if (fstat(op->idip->fd, &st) < 0) {
439             perror("fstat(idip->fd) error");
440             *in_num_blksp = -1;
441         } else {
442             *in_num_blksp = st.st_size / op->ibs;
443             res = st.st_size % op->ibs;
444             if (op->verbose) {
445                 print_blk_sizes(ifn, "reg", *in_num_blksp, op->ibs, 1);
446                 if (res)
447                     pr2serr("    residual_bytes=%d\n", res);
448             }
449             if (res)
450                 ++*in_num_blksp;
451         }
452     }
453     return 0;
454 }
455 
456 /* Helper for calc_count(). Attempts to size OFILE. Returns 0 if no error
457  * detected. */
458 static int
calc_count_out(struct opts_t * op,int64_t * out_num_blksp)459 calc_count_out(struct opts_t * op, int64_t * out_num_blksp)
460 {
461     int res;
462     struct stat st;
463     int out_blk_sz, out_type;
464 #ifndef SG_LIB_WIN32
465     int64_t num_blks, t;
466     int blk_sz;
467 #endif
468     const char * ofn = op->odip->fn;
469 
470     *out_num_blksp = -1;
471     out_type = op->odip->d_type;
472     if (FT_PT & out_type) {
473         if (op->oflagp->norcap) {
474             if ((FT_BLOCK & out_type) && (0 == op->oflagp->force)) {
475                 pr2serr(">> warning: norcap on output block device "
476                         "accessed via pt is risky.\n");
477                 pr2serr(">> Abort copy, use oflag=force to override.\n");
478                 return -1;
479             }
480             return 0;
481         }
482         res = pt_read_capacity(op, DDPT_ARG_OUT, out_num_blksp, &out_blk_sz);
483         if (SG_LIB_CAT_UNIT_ATTENTION == res) {
484             pr2serr("Unit attention (readcap out), continuing\n");
485             res = pt_read_capacity(op, DDPT_ARG_OUT, out_num_blksp,
486                                    &out_blk_sz);
487         } else if (SG_LIB_CAT_ABORTED_COMMAND == res) {
488             pr2serr("Aborted command (readcap out), continuing\n");
489             res = pt_read_capacity(op, DDPT_ARG_OUT, out_num_blksp,
490                                    &out_blk_sz);
491         }
492         if (0 != res) {
493             if (res == SG_LIB_CAT_INVALID_OP)
494                 pr2serr("read capacity not supported on %s\n", ofn);
495             else
496                 pr2serr("Unable to read capacity on %s\n", ofn);
497             *out_num_blksp = -1;
498             return res;
499         } else {
500             if (op->verbose) {
501                 print_blk_sizes(ofn, "readcap", *out_num_blksp, out_blk_sz,
502                                 1);
503                 if (op->odip->prot_type > 0)
504                     pr2serr("    reports Protection_type=%d, p_i_exp=%d\n",
505                             op->odip->prot_type, op->odip->p_i_exp);
506             }
507             if ((*out_num_blksp > 0) && (op->obs != out_blk_sz)) {
508                 pr2serr(">> warning: %s block size confusion: "
509                         "obs=%d, device claims=%d\n", ofn, op->obs,
510                         out_blk_sz);
511                 if (0 == op->oflagp->force) {
512                     pr2serr(">> abort copy, use oflag=force to override\n");
513                     return -1;
514                 }
515             }
516         }
517 #ifndef SG_LIB_WIN32
518         if ((FT_BLOCK & out_type) && (0 == op->oflagp->force) &&
519              (0 == get_blkdev_capacity(op, DDPT_ARG_OUT, &num_blks,
520                                        &blk_sz))) {
521             t = (*out_num_blksp) * out_blk_sz;
522             if (t != (num_blks * blk_sz)) {
523                 pr2serr(">> warning: size of output block device is "
524                         "different from pt size.\n>> Pass-through on block "
525                         "partition can give unexpected results.\n");
526                 pr2serr(">> abort copy, use oflag=force to override\n");
527                 return -1;
528             }
529         }
530 #endif
531     } else if ((op->dd_count > 0) && (0 == op->oflagp->resume))
532         return 0;
533     if (FT_BLOCK & out_type) {
534         if (0 != get_blkdev_capacity(op, DDPT_ARG_OUT, out_num_blksp,
535                                      &out_blk_sz)) {
536             pr2serr("Unable to read block capacity on %s\n", ofn);
537             *out_num_blksp = -1;
538         } else {
539             if (op->verbose)
540                 print_blk_sizes(ofn, "blk", *out_num_blksp, out_blk_sz, 1);
541             if ((*out_num_blksp > 0) && (op->obs != out_blk_sz)) {
542                 pr2serr(">> warning: %s block size confusion: obs=%d, "
543                         "device claims=%d\n", ofn, op->obs, out_blk_sz);
544                 *out_num_blksp = -1;
545             }
546         }
547     } else if (FT_REG & out_type) {
548         if (fstat(op->odip->fd, &st) < 0) {
549             perror("fstat(odip->fd) error");
550             *out_num_blksp = -1;
551         } else {
552             *out_num_blksp = st.st_size / op->obs;
553             res = st.st_size % op->obs;
554             if (op->verbose) {
555                 print_blk_sizes(ofn, "reg", *out_num_blksp, op->obs, 1);
556                 if (res)
557                     pr2serr("    residual_bytes=%d\n", res);
558             }
559             if (res)
560                 ++*out_num_blksp;
561         }
562     }
563     return 0;
564 }
565 
566 
567 /* Calculates the number of blocks associated with the in and out files.
568  * May also yield the block size in bytes of devices. For regular files
569  * uses ibs or obs as the logical block size. Returns 0 for continue,
570  * otherwise bypass copy and exit. */
571 static int
calc_count(struct opts_t * op,int64_t * in_num_blksp,int64_t * out_num_blksp)572 calc_count(struct opts_t * op, int64_t * in_num_blksp,
573            int64_t * out_num_blksp)
574 {
575     int res;
576 
577     res = calc_count_in(op, in_num_blksp);
578     if (res) {
579         *out_num_blksp = -1;
580         return res;
581     }
582     return calc_count_out(op, out_num_blksp);
583 }
584 
585 #ifdef HAVE_POSIX_FADVISE
586 /* Used by iflag=nocache and oflag=nocache to suggest (via posix_fadvise()
587  * system call) that the OS doesn't cache data it has just read or written
588  * since it is unlikely to be used again in the short term. iflag=nocache
589  * additionally increases the read-ahead. Errors ignored. */
590 static void
do_fadvise(struct opts_t * op,int bytes_if,int bytes_of,int bytes_of2)591 do_fadvise(struct opts_t * op, int bytes_if, int bytes_of, int bytes_of2)
592 {
593     int rt, in_valid, out2_valid, out_valid, id_type, od_type, o2d_type;
594 
595     id_type = op->idip->d_type;
596     od_type = op->odip->d_type;
597     o2d_type = op->o2dip->d_type;
598     in_valid = ((FT_REG == id_type) || (FT_BLOCK == id_type));
599     out2_valid = ((FT_REG == o2d_type) || (FT_BLOCK == o2d_type));
600     out_valid = ((FT_REG == od_type) || (FT_BLOCK == od_type));
601     if (op->iflagp->nocache && (bytes_if > 0) && in_valid) {
602         if ((op->lowest_skip < 0) || (op->skip > op->lowest_skip))
603             op->lowest_skip = op->skip;
604         rt = posix_fadvise(op->idip->fd, (op->lowest_skip * op->ibs),
605                            ((op->skip - op->lowest_skip) * op->ibs) + bytes_if,
606                            POSIX_FADV_DONTNEED);
607         if (rt)         /* returns error as result */
608             pr2serr("posix_fadvise on read, skip=%" PRId64 " ,err=%d\n",
609                     op->skip, rt);
610     }
611     if ((op->oflagp->nocache & 2) && (bytes_of2 > 0) && out2_valid) {
612         rt = posix_fadvise(op->o2dip->fd, 0, 0, POSIX_FADV_DONTNEED);
613         if (rt)
614             pr2serr("posix_fadvise on of2, seek=%" PRId64 " ,err=%d\n",
615                     op->seek, rt);
616     }
617     if ((op->oflagp->nocache & 1) && (bytes_of > 0) && out_valid) {
618         if ((op->lowest_seek < 0) || (op->seek > op->lowest_seek))
619             op->lowest_seek = op->seek;
620         rt = posix_fadvise(op->odip->fd, (op->lowest_seek * op->obs),
621                    ((op->seek - op->lowest_seek) * op->obs) + bytes_of,
622                            POSIX_FADV_DONTNEED);
623         if (rt)
624             pr2serr("posix_fadvise on output, seek=%" PRId64 " , err=%d\n",
625                     op->seek, rt);
626     }
627 }
628 #endif
629 
630 /* Main copy loop's read (input) via pt. Returns 0 on success, else see
631  * pt_read()'s return values. */
632 static int
cp_read_pt(struct opts_t * op,struct cp_state_t * csp,unsigned char * bp)633 cp_read_pt(struct opts_t * op, struct cp_state_t * csp, unsigned char * bp)
634 {
635     int res;
636     int blks_read = 0;
637 
638     res = pt_read(op, 0, bp, csp->icbpt, &blks_read);
639     if (res) {
640         if (0 == blks_read) {
641             pr2serr("pt_read failed,%s at or after lba=%" PRId64 " "
642                     "[0x%" PRIx64 "]\n",
643                     ((-2 == res) ?  " try reducing bpt," : ""),
644                     op->skip, op->skip);
645             return res;
646         }
647         /* limp on if data, should stop after write; hold err number */
648         op->err_to_report = res;
649     }
650     if (blks_read < csp->icbpt) {
651         /* assume close to end, or some data prior to read error */
652         if (op->verbose > 1)
653             pr2serr("short read, requested %d blocks, got %d blocks\n",
654                     csp->icbpt, blks_read);
655         ++csp->leave_after_write;
656         /* csp->leave_reason = 0; assume at end rather than error */
657         csp->icbpt = blks_read;
658         /* round down since don't do partial writes from pt reads */
659         csp->ocbpt = (blks_read * op->ibs) / op->obs;
660     }
661     op->in_full += csp->icbpt;
662     return 0;
663 }
664 
665 /* Error occurred on block/regular read. coe active so assume all full
666  * blocks prior to error are good (if any) and start to read from the
667  * block containing the error, one block at a time, until ibpt. Supply
668  * zeros for unreadable blocks. Return 0 if successful, SG_LIB_CAT_OTHER
669  * if error other than EIO or EREMOTEIO, SG_LIB_FILE_ERROR if lseek fails,
670  * and SG_LIB_CAT_MEDIUM_HARD if the coe_limit is exceeded. */
671 static int
coe_cp_read_block_reg(struct opts_t * op,struct cp_state_t * csp,unsigned char * bp,int numread_errno)672 coe_cp_read_block_reg(struct opts_t * op, struct cp_state_t * csp,
673                       unsigned char * bp, int numread_errno)
674 {
675     int res, res2, k, total_read, num_read;
676     int ibs = op->ibs_pi;
677     int64_t offset, off_res, my_skip;
678 
679     if (0 == numread_errno) {
680         csp->icbpt = 0;
681         csp->ocbpt = 0;
682         ++csp->leave_after_write;
683         csp->leave_reason = 0;
684         return 0;       /* EOF */
685     } else if (numread_errno < 0) {
686         if ((-EIO == numread_errno) || (-EREMOTEIO == numread_errno)) {
687             num_read = 0;
688             if (1 == csp->icbpt) {
689                 // Don't read again, this must be bad block
690                 memset(bp, 0, ibs);
691                 if ((res2 = coe_process_eio(op, op->skip)))
692                     return res2;
693                 ++op->in_full;
694                 csp->bytes_read += ibs;
695                 return 0;
696             }
697         } else
698             return SG_LIB_CAT_OTHER;
699     } else
700         num_read = (numread_errno / ibs) * ibs;
701 
702     k = num_read / ibs;
703     if (k > 0) {
704         op->in_full += k;
705         zero_coe_limit_count(op);
706     }
707     csp->bytes_read = num_read;
708     my_skip = op->skip + k;
709     offset = my_skip * ibs;
710     bp += num_read;
711     for ( ; k < csp->icbpt; ++k, ++my_skip, bp += ibs, offset += ibs) {
712         if (offset != csp->if_filepos) {
713             if (op->verbose > 2)
714                 pr2serr("moving if filepos: new_pos=%" PRId64 "\n",
715                         (int64_t)offset);
716             off_res = lseek(op->idip->fd, offset, SEEK_SET);
717             if (off_res < 0) {
718                 pr2serr("failed moving if filepos: new_pos="
719                         "%" PRId64 "\nlseek on input: %s\n", (int64_t)offset,
720                         safe_strerror(errno));
721                 return SG_LIB_FILE_ERROR;
722             }
723             csp->if_filepos = offset;
724         }
725         memset(bp, 0, ibs);
726         while (((res = read(op->idip->fd, bp, ibs)) < 0) &&
727                (EINTR == errno))
728             ++op->interrupted_retries;
729         if (0 == res) {
730             csp->leave_reason = 0;
731             goto short_read;
732         } else if (res < 0) {
733             if ((EIO == errno) || (EREMOTEIO == errno)) {
734                 if ((res2 = coe_process_eio(op, my_skip)))
735                     return res2;
736             } else {
737                 pr2serr("reading 1 block, skip=%" PRId64 " : %s\n", my_skip,
738                         safe_strerror(errno));
739                 csp->leave_reason = SG_LIB_CAT_OTHER;
740                 goto short_read;
741             }
742         } else if (res < ibs) {
743             if (op->verbose)
744                 pr2serr("short read at skip=%" PRId64 " , wanted=%d, "
745                         "got=%d bytes\n", my_skip, ibs, res);
746             csp->leave_reason = 0;  /* assume EOF */
747             goto short_read;
748         } else { /* if (res == ibs) */
749             zero_coe_limit_count(op);
750             csp->if_filepos += ibs;
751             if (op->verbose > 2)
752                 pr2serr("reading 1 block, skip=%" PRId64 " : okay\n",
753                         my_skip);
754         }
755         ++op->in_full;
756         csp->bytes_read += ibs;
757     }
758     return 0;
759 
760 short_read:
761     total_read = (ibs * k) + ((res > 0) ? res : 0);
762     csp->icbpt = total_read / ibs;
763     if ((total_read % ibs) > 0) {
764         ++csp->icbpt;
765         ++op->in_partial;
766     }
767     csp->ocbpt = total_read / op->obs;
768     ++csp->leave_after_write;
769     if (0 == csp->leave_reason) {
770         csp->partial_write_bytes = total_read % op->obs;
771     } else {
772         /* if short read (not EOF) implies partial writes, bump obpt */
773         if ((total_read % op->obs) > 0)
774             ++csp->ocbpt;
775     }
776     return 0;
777 }
778 
779 /* Main copy loop's read (input) for block device or regular file.
780  * Returns 0 on success, else SG_LIB_FILE_ERROR, SG_LIB_CAT_MEDIUM_HARD,
781  * SG_LIB_CAT_OTHER or -1 . */
782 static int
cp_read_block_reg(struct opts_t * op,struct cp_state_t * csp,unsigned char * bp)783 cp_read_block_reg(struct opts_t * op, struct cp_state_t * csp,
784                   unsigned char * bp)
785 {
786     int res, res2, in_type;
787     int64_t offset = op->skip * op->ibs_pi;
788     int numbytes = csp->icbpt * op->ibs_pi;
789     int ibs = op->ibs_pi;
790 
791     if (op->verbose > 4)
792         pr2serr("%s: offset=0x%" PRIx64 ", numbytes=%d\n", __func__, offset,
793                 numbytes);
794     in_type = op->idip->d_type;
795 #ifdef SG_LIB_WIN32
796     if (FT_BLOCK & in_type) {
797         int ifull_extra;
798 
799         if ((res = win32_cp_read_block(op, csp, bp, &ifull_extra,
800                                        op->verbose)))
801             return res;
802         op->in_full += ifull_extra;
803         return 0;
804     }
805 #endif
806     if (offset != csp->if_filepos) {
807         int64_t off_res;
808 
809         if (op->verbose > 2)
810             pr2serr("moving if filepos: new_pos=%" PRId64 "\n",
811                     (int64_t)offset);
812         off_res = lseek(op->idip->fd, offset, SEEK_SET);
813         if (off_res < 0) {
814             pr2serr("failed moving if filepos: new_pos="
815                     "%" PRId64 "\nlseek on input: %s\n", (int64_t)offset,
816                     safe_strerror(errno));
817             return SG_LIB_FILE_ERROR;
818         }
819         csp->if_filepos = offset;
820     }
821     while (((res = read(op->idip->fd, bp, numbytes)) < 0) &&
822            (EINTR == errno))
823         ++op->interrupted_retries;
824 
825     if (op->verbose > 2)
826         pr2serr("read(unix): requested bytes=%d, res=%d\n", numbytes, res);
827     if ((op->iflagp->coe) && (res < numbytes)) {
828         res2 = (res >= 0) ? res : -errno;
829         if ((res < 0) && op->verbose) {
830             pr2serr("reading, skip=%" PRId64 " : %s, go to coe\n",
831                     op->skip, safe_strerror(errno));
832         } else if (op->verbose)
833             pr2serr("reading, skip=%" PRId64 " : short read, go to coe\n",
834                     op->skip);
835         if (res2 > 0)
836             csp->if_filepos += res2;
837         return coe_cp_read_block_reg(op, csp, bp, res2);
838     }
839     if (res < 0) {
840         pr2serr("reading, skip=%" PRId64 " : %s\n", op->skip,
841                 safe_strerror(errno));
842         if ((EIO == errno) || (EREMOTEIO == errno))
843             return SG_LIB_CAT_MEDIUM_HARD;
844         else
845             return SG_LIB_CAT_OTHER;
846     } else if (res < numbytes) {
847         csp->icbpt = res / ibs;
848         if ((res % ibs) > 0) {
849             ++csp->icbpt;
850             ++op->in_partial;
851             --op->in_full;
852         }
853         csp->ocbpt = res / op->obs;
854         ++csp->leave_after_write;
855         csp->leave_reason = 0;  /* fall through is assumed EOF */
856         if (op->verbose > 1) {
857             if (FT_BLOCK & in_type)
858                 pr2serr("short read at skip=%" PRId64 ", requested "
859                         "%d blocks, got %d blocks\n", op->skip,
860                         numbytes / ibs, csp->icbpt);
861             else
862                 pr2serr("short read, requested %d bytes, got %d bytes\n",
863                         numbytes, res);
864         }
865         res2 = 0;
866         if ((res >= ibs) && (res <= (numbytes - ibs))) {
867             /* Want to check for a EIO lurking */
868             while (((res2 = read(op->idip->fd, bp + res, ibs)) < 0) &&
869                    (EINTR == errno))
870                 ++op->interrupted_retries;
871             if (res2 < 0) {
872                 if ((EIO == errno) || (EREMOTEIO == errno)) {
873                     csp->leave_reason = SG_LIB_CAT_MEDIUM_HARD;
874                     ++op->unrecovered_errs;
875                 } else
876                     csp->leave_reason = SG_LIB_CAT_OTHER;
877                 if (op->verbose)
878                     pr2serr("after short read, read at skip=%" PRId64
879                             ": %s\n", op->skip + csp->icbpt,
880                             safe_strerror(errno));
881             } else {    /* actually expect 0==res2 indicating EOF */
882                 csp->if_filepos += res2;   /* could have moved filepos */
883                 if (op->verbose > 1)
884                     pr2serr("extra read after short read, res=%d\n", res2);
885             }
886         }
887         if (0 == csp->leave_reason)    /* if EOF, allow for partial write */
888             csp->partial_write_bytes = (res + res2) % op->obs;
889         else if ((res % op->obs) > 0) /* else if extra bytes bump obpt */
890             ++csp->ocbpt;
891     }
892     csp->if_filepos += res;
893     csp->bytes_read = res;
894     op->in_full += csp->icbpt;
895     return 0;
896 }
897 
898 #ifdef SG_LIB_LINUX
899 
900 /* Main copy loop's read (input) for tape device. Returns 0 on success,
901  * else SG_LIB_CAT_MEDIUM_HARD, SG_LIB_CAT_OTHER or -1 . */
902 static int
cp_read_tape(struct opts_t * op,struct cp_state_t * csp,unsigned char * bp)903 cp_read_tape(struct opts_t * op, struct cp_state_t * csp, unsigned char * bp)
904 {
905     int res, err, num;
906 
907     num = csp->icbpt * op->ibs;
908     op->read_tape_numbytes = num;
909     while (((res = read(op->idip->fd, bp, num)) < 0) && (EINTR == errno))
910         ++op->interrupted_retries;
911 
912     err = errno;
913 
914     /* Summarise previous consecutive same-length reads. */
915     print_tape_summary(op, res, "");
916 
917     if (op->verbose > 2)
918         pr2serr("read(tape%s): requested bytes=%d, res=%d\n",
919                 ((res >= num) || (res < 0)) ? "" : ", short", num, res);
920 
921     if (op->verbose > 3)
922         print_tape_pos("", "", op);
923 
924     if (res < 0) {
925         /* If a tape block larger than the requested read length is
926          * encountered, the Linux st driver returns ENOMEM. Handle that case
927          * otherwise we would print a confusing/incorrect message
928          * "Cannot allocate memory". */
929         pr2serr("reading, skip=%" PRId64 " : %s\n", op->skip,
930                 (ENOMEM == err) ? "Tape block larger than requested read"
931                 " length" : safe_strerror(err));
932 
933         /* So print_stats() doesn't print summary. */
934         op->last_tape_read_len = 0;
935 
936         if ((EIO == err) || (EREMOTEIO == err))
937             return SG_LIB_CAT_MEDIUM_HARD;
938         else
939             return SG_LIB_CAT_OTHER;
940     } else {
941         if (op->verbose > 1) {
942             if (res == op->last_tape_read_len)
943                 op->consec_same_len_reads++;
944             else {
945                 op->last_tape_read_len = res;
946                 op->consec_same_len_reads = 1;
947             }
948         }
949         if (res < num) {
950             csp->icbpt = res / op->ibs;
951             if ((res % op->ibs) > 0) {
952                 ++csp->icbpt;
953                 ++op->in_partial;
954                 --op->in_full;
955             }
956             csp->ocbpt = res / op->obs;
957             ++csp->leave_after_write;
958             csp->leave_reason = REASON_TAPE_SHORT_READ;
959             csp->partial_write_bytes = res % op->obs;
960             if ((op->verbose == 2) && (op->consec_same_len_reads == 1))
961                 pr2serr("short read: requested %d bytes, got %d\n",
962                         op->read_tape_numbytes, res);
963         }
964     }
965     csp->if_filepos += res;
966     csp->bytes_read = res;
967     op->in_full += csp->icbpt;
968     return 0;
969 }
970 
971 #endif /* SG_LIB_LINUX */
972 
973 /* Main copy loop's read (input) for a fifo. Returns 0 on success, else
974  * SG_LIB_CAT_OTHER or -1 . */
975 static int
cp_read_fifo(struct opts_t * op,struct cp_state_t * csp,unsigned char * bp)976 cp_read_fifo(struct opts_t * op, struct cp_state_t * csp, unsigned char * bp)
977 {
978     int res, k, err;
979     int64_t offset = op->skip * op->ibs;
980     int numbytes = csp->icbpt * op->ibs;
981 
982     if (offset != csp->if_filepos) {
983         if (op->verbose > 2)
984             pr2serr("%s: _not_ moving IFILE filepos to %" PRId64 "\n",
985                     __func__, (int64_t)offset);
986         csp->if_filepos = offset;
987     }
988 
989     for (k = 0; k < numbytes; k += res) {
990         while (((res = read(op->idip->fd, bp + k, numbytes - k)) < 0) &&
991                (EINTR == errno))
992             ++op->interrupted_retries;
993 
994         err = errno;
995         if (op->verbose > 2)
996             pr2serr("%s: requested bytes=%d, res=%d\n", __func__, numbytes,
997                     res);
998         if (res < 0) {
999             pr2serr("%s: skip=%" PRId64 " : %s\n", __func__, op->skip,
1000                     safe_strerror(err));
1001             return SG_LIB_CAT_OTHER;
1002         } else if (0 == res) {
1003             csp->icbpt = k / op->ibs;
1004             if ((k % op->ibs) > 0) {
1005                 ++csp->icbpt;
1006                 ++op->in_partial;
1007                 --op->in_full;
1008             }
1009             csp->ocbpt = k / op->obs;
1010             ++csp->leave_after_write;
1011             csp->leave_reason = 0;  /* EOF */
1012             csp->partial_write_bytes = k % op->obs;
1013             break;
1014         }
1015     }
1016     csp->if_filepos += k;
1017     csp->bytes_read = k;
1018     op->in_full += csp->icbpt;
1019     return 0;
1020 }
1021 
1022 /* Main copy loop's write (to of2) for regular file. Returns 0 if success,
1023  * else -1 on error. */
1024 static int
cp_write_of2(struct opts_t * op,struct cp_state_t * csp,const unsigned char * bp)1025 cp_write_of2(struct opts_t * op, struct cp_state_t * csp,
1026              const unsigned char * bp)
1027 {
1028     int res, off, part, err;
1029     int numbytes = (csp->ocbpt * op->obs) + csp->partial_write_bytes;
1030 
1031     // write to fifo (reg file ?) is non-atomic so loop if making progress
1032     off = 0;
1033     part = 0;
1034     do {
1035         while (((res = write(op->o2dip->fd, bp + off, numbytes - off)) < 0) &&
1036                (EINTR == errno))
1037             ++op->interrupted_retries;
1038         err = errno;
1039         if ((res > 0) && (res < (numbytes - off)))
1040             ++part;
1041     } while ((FT_FIFO & op->o2dip->d_type) && (res > 0) &&
1042              ((off += res) < numbytes));
1043     if (off >= numbytes) {
1044         res = numbytes;
1045         if (part && op->verbose)
1046             pr2serr("write to of2 splintered\n");
1047     } else if (off > 0)
1048         pr2serr("write to of2 fifo problem: count=%d, off=%d, res=%d\n",
1049                 numbytes, off, res);
1050     if ((op->verbose > 2) && (0 == off))
1051         pr2serr("write to of2: count=%d, res=%d\n", numbytes, res);
1052     if (res < 0) {
1053         pr2serr("writing to of2, seek=%" PRId64 " : %s\n", op->seek,
1054                 safe_strerror(err));
1055         return -1;
1056     }
1057     csp->bytes_of2 = res;
1058     return 0;
1059 }
1060 
1061 /* Main copy loop's read (output (of)) via pt. Returns 0 on success, else
1062  * see pt_read()'s return values. */
1063 static int
cp_read_of_pt(struct opts_t * op,struct cp_state_t * csp,unsigned char * bp)1064 cp_read_of_pt(struct opts_t * op, struct cp_state_t * csp, unsigned char * bp)
1065 {
1066     int res, blks_read;
1067 
1068     res = pt_read(op, 1, bp, csp->ocbpt, &blks_read);
1069     if (res) {
1070         pr2serr("pt_read(sparing) failed, at or after "
1071                 "lba=%" PRId64 " [0x%" PRIx64 "]\n", op->seek,
1072                 op->seek);
1073         return res;
1074     } else if (blks_read != csp->ocbpt)
1075         return 1;
1076     return 0;
1077 }
1078 
1079 /* Main copy loop's read (output (of)) for block device or regular file.
1080  * Returns 0 on success, else SG_LIB_FILE_ERROR, SG_LIB_CAT_MEDIUM_HARD
1081  * or -1 . */
1082 static int
cp_read_of_block_reg(struct opts_t * op,struct cp_state_t * csp,unsigned char * bp)1083 cp_read_of_block_reg(struct opts_t * op, struct cp_state_t * csp,
1084                      unsigned char * bp)
1085 {
1086     int res, err;
1087     int64_t offset = op->seek * op->obs;
1088     int numbytes = csp->ocbpt * op->obs;
1089 
1090 #ifdef SG_LIB_WIN32
1091     if (FT_BLOCK & op->odip->d_type) {
1092         if (offset != csp->of_filepos) {
1093             if (op->verbose > 2)
1094                 pr2serr("moving of filepos: new_pos=%" PRId64 "\n",
1095                         (int64_t)offset);
1096             if (win32_set_file_pos(op, DDPT_ARG_OUT, offset, op->verbose))
1097                 return SG_LIB_FILE_ERROR;
1098             csp->of_filepos = offset;
1099         }
1100         res = win32_block_read_from_of(op, bp, numbytes, op->verbose);
1101         if (op->verbose > 2)
1102             pr2serr("read(sparing): requested bytes=%d, res=%d\n", numbytes,
1103                     res);
1104         if (res < 0) {
1105             pr2serr("read(sparing), seek=%" PRId64 "\n", op->seek);
1106             return (-SG_LIB_CAT_MEDIUM_HARD == res) ? -res : -1;
1107         } else if (res == numbytes) {
1108             csp->of_filepos += numbytes;
1109             return 0;
1110         } else {
1111             if (op->verbose > 2)
1112                 pr2serr("short read\n");
1113             return -1;
1114         }
1115     } else
1116 #endif
1117     {
1118         if (offset != csp->of_filepos) {
1119             int64_t off_res;
1120 
1121             if (op->verbose > 2)
1122                 pr2serr("moving of filepos: new_pos=%" PRId64 "\n",
1123                         (int64_t)offset);
1124             off_res = lseek(op->odip->fd, offset, SEEK_SET);
1125             if (off_res < 0) {
1126                 pr2serr("failed moving of filepos: new_pos="
1127                         "%" PRId64 "\nlseek on output: %s\n", (int64_t)offset,
1128                         safe_strerror(errno));
1129                 return SG_LIB_FILE_ERROR;
1130             }
1131             csp->of_filepos = offset;
1132         }
1133         if (csp->partial_write_bytes > 0) {
1134             numbytes += csp->partial_write_bytes;
1135             if (op->verbose)
1136                 pr2serr("read(sparing): %d bytes extra to fetch "
1137                         "due to partial read\n", csp->partial_write_bytes);
1138         }
1139         while (((res = read(op->odip->fd, bp, numbytes)) < 0) &&
1140                (EINTR == errno))
1141             ++op->interrupted_retries;
1142 
1143         err = errno;
1144         if (op->verbose > 2)
1145             pr2serr("read(sparing): requested bytes=%d, res=%d\n", numbytes,
1146                     res);
1147         if (res < 0) {
1148             pr2serr("read(sparing), seek=%" PRId64 " : %s\n", op->seek,
1149                     safe_strerror(err));
1150             return -1;
1151         } else if (res == numbytes) {
1152             csp->of_filepos += numbytes;
1153             return 0;
1154         } else {
1155             if (op->verbose > 2)
1156                 pr2serr("short read\n");
1157             return 1;
1158         }
1159     }
1160 }
1161 
1162 
1163 /* Main copy loop's write (output (of)) via pt. Returns 0 on success, else
1164  * see pt_write()'s return values. */
1165 static int
cp_write_pt(struct opts_t * op,struct cp_state_t * csp,int seek_delta,int blks,const unsigned char * bp)1166 cp_write_pt(struct opts_t * op, struct cp_state_t * csp, int seek_delta,
1167             int blks, const unsigned char * bp)
1168 {
1169     int res;
1170     int numbytes;
1171     int64_t aseek = op->seek + seek_delta;
1172 
1173     if (op->oflagp->nowrite)
1174         return 0;
1175     if (csp->partial_write_bytes > 0) {
1176         if (op->oflagp->pad) {
1177             unsigned char * ncbp = (unsigned char *)bp;
1178 
1179             numbytes = blks * op->obs;
1180             numbytes += csp->partial_write_bytes;
1181             ++csp->ocbpt;
1182             ++blks;
1183             res = blks * op->obs;
1184             if (res > numbytes)
1185                 memset(ncbp + numbytes, 0, res - numbytes);
1186             if (op->verbose > 1)
1187                 pr2serr("%s: padding probable final write at seek=%" PRId64
1188                         "\n", __func__, aseek);
1189         } else
1190             pr2serr(">>> ignore partial write of %d bytes to pt "
1191                     "(unless oflag=pad given)\n", csp->partial_write_bytes);
1192     }
1193     res = pt_write(op, bp, blks, aseek);
1194     if (0 != res) {
1195         pr2serr("%s: failed,%s seek=%" PRId64 "\n", __func__,
1196                 ((-2 == res) ? " try reducing bpt," : ""), aseek);
1197         return res;
1198     } else
1199         op->out_full += blks;
1200     return 0;
1201 }
1202 
1203 #ifdef SG_LIB_LINUX
1204 
1205 /* Main copy loop's write (output (of)) for a tape device.
1206  * Returns 0 on success, else SG_LIB_CAT_OTHER, SG_LIB_CAT_MEDIUM_HARD
1207  * or -1 . */
1208 static int
cp_write_tape(struct opts_t * op,struct cp_state_t * csp,const unsigned char * bp,int could_be_last)1209 cp_write_tape(struct opts_t * op, struct cp_state_t * csp,
1210               const unsigned char * bp, int could_be_last)
1211 {
1212     int res, err;
1213     int numbytes;
1214     int partial = 0;
1215     int blks = csp->ocbpt;
1216     int64_t aseek = op->seek;
1217     int got_early_warning = 0;
1218 /* Only print early warning message once when verbose=2 */
1219     static int printed_ew_message = 0;
1220 
1221     numbytes = blks * op->obs;
1222     if (op->oflagp->nowrite)
1223         return 0;
1224     if (csp->partial_write_bytes > 0) {
1225         ++partial;
1226         numbytes += csp->partial_write_bytes;
1227         if (op->oflagp->nopad)
1228             ++op->out_partial;
1229         else {
1230             unsigned char * ncbp = (unsigned char *)bp;
1231 
1232             ++csp->ocbpt;
1233             ++blks;
1234             res = blks * op->obs;
1235             if (res > numbytes)
1236                 memset(ncbp + numbytes, 0, res - numbytes);
1237             numbytes = res;
1238         }
1239     }
1240 
1241 ew_retry:
1242     while (((res = write(op->odip->fd, bp, numbytes)) < 0) &&
1243            (EINTR == errno))
1244         ++op->interrupted_retries;
1245 
1246     err = errno;
1247     if ((op->verbose > 2) || ((op->verbose > 0) && could_be_last)) {
1248         const char * cp;
1249 
1250         cp = ((! op->oflagp->nopad) && partial) ? ", padded" : "";
1251         pr2serr("write(tape%s%s): requested bytes=%d, res=%d\n",
1252                 (partial ? ", partial" : ""), cp, numbytes, res);
1253     }
1254 
1255 /* Handle EOM early warning. */
1256 /* The Linux st driver returns -1 and ENOSPC to indicate the drive has reached
1257  * end of medium early warning. It is still possible to write a significant
1258  * amount of data before reaching end of tape (e.g. over 200MB for LTO 1). If
1259  * the user specified oflag=ignoreew (ignore early warning) retry the write.
1260  * The st driver should allow it; writes alternate until EOM, i.e. write okay,
1261  * ENOSPC, write okay, ENOSPC, etc. Exit if more than one ENOSPC in a row. */
1262     if ((op->oflagp->ignoreew) && (-1 == res) && (ENOSPC == err) &&
1263         (0 == got_early_warning)) {
1264         got_early_warning = 1;
1265         if (0 == printed_ew_message) {
1266             if (op->verbose > 1)
1267                 pr2serr("writing, seek=%" PRId64 " : EOM early "
1268                         "warning, continuing...\n", aseek);
1269              if (2 == op->verbose) {
1270                 pr2serr("(suppressing further early warning messages)\n");
1271                 printed_ew_message = 1;
1272             }
1273         }
1274         goto ew_retry;
1275     }
1276 
1277     if (op->verbose > 3)
1278         print_tape_pos("", "", op);
1279 
1280     if (res < 0) {
1281         pr2serr("writing, seek=%" PRId64 " : %s\n", aseek,
1282                 safe_strerror(err));
1283         if ((EIO == err) || (EREMOTEIO == err))
1284             return SG_LIB_CAT_MEDIUM_HARD;
1285         else
1286             return SG_LIB_CAT_OTHER;
1287     } else if (res < numbytes) {
1288         pr2serr("write(tape): wrote less than requested, exit\n");
1289         csp->of_filepos += res;
1290         csp->bytes_of = res;
1291         op->out_full += res / op->obs;
1292         /* can get a partial write due to a short write */
1293         if ((res % op->obs) > 0) {
1294             ++op->out_partial;
1295             ++op->out_full;
1296         }
1297         return -1;
1298     } else {    /* successful write */
1299         csp->of_filepos += numbytes;
1300         csp->bytes_of = numbytes;
1301         op->out_full += blks;
1302     }
1303     return 0;
1304 }
1305 
1306 #endif /* SG_LIB_LINUX */
1307 
1308 /* Main copy loop's write (output (of)) for block device fifo or regular
1309  * file. Returns 0 on success, else SG_LIB_FILE_ERROR,
1310  * SG_LIB_CAT_MEDIUM_HARD or -1 . */
1311 static int
cp_write_block_reg(struct opts_t * op,struct cp_state_t * csp,int seek_delta,int blks,const unsigned char * bp)1312 cp_write_block_reg(struct opts_t * op, struct cp_state_t * csp,
1313                    int seek_delta, int blks, const unsigned char * bp)
1314 {
1315     int64_t offset;
1316     int64_t aseek = op->seek + seek_delta;
1317     int res, off, part, out_type, err;
1318     int numbytes = blks * op->obs_pi;
1319     int obs = op->obs_pi;
1320 
1321     if (op->oflagp->nowrite)
1322         return 0;
1323     out_type = op->odip->d_type;
1324     offset = aseek * obs;
1325 #ifdef SG_LIB_WIN32
1326     if (FT_BLOCK & out_type) {
1327         if (csp->partial_write_bytes > 0) {
1328             if (op->oflagp->pad) {
1329                 numbytes += csp->partial_write_bytes;
1330                 ++csp->ocbpt;
1331                 ++blks;
1332                 res = blks * obs;
1333                 if (res > numbytes)
1334                     memset((unsigned char *)bp + numbytes, 0,
1335                            res - numbytes);
1336                 numbytes = res;
1337                 if (op->verbose > 1)
1338                     pr2serr("write(win32_block): padding probable "
1339                             "final write at seek=%" PRId64 "\n", aseek);
1340             } else
1341                 pr2serr(">>> ignore partial write of %d bytes to "
1342                         "block device\n", csp->partial_write_bytes);
1343         }
1344         if (offset != csp->of_filepos) {
1345             if (op->verbose > 2)
1346                 pr2serr("moving of filepos: new_pos=%" PRId64 "\n",
1347                         (int64_t)offset);
1348             if (win32_set_file_pos(op, DDPT_ARG_OUT, offset, op->verbose))
1349                 return SG_LIB_FILE_ERROR;
1350             csp->of_filepos = offset;
1351         }
1352         res = win32_block_write(op, bp, numbytes, op->verbose);
1353         if (res < 0) {
1354             pr2serr("write(win32_block), seek=%" PRId64 " ", aseek);
1355             return (-SG_LIB_CAT_MEDIUM_HARD == res) ? -res : -1;
1356         } else if (res < numbytes) {
1357             pr2serr("output file probably full, seek=%" PRId64 " ",
1358                     aseek);
1359             csp->of_filepos += res;
1360             csp->bytes_of = res;
1361             op->out_full += res / obs;
1362             /* can get a partial write due to a short write */
1363             if ((res % obs) > 0) {
1364                 ++op->out_partial;
1365                 ++op->out_full;
1366             }
1367             return -1;
1368         } else {
1369             csp->of_filepos += numbytes;
1370             csp->bytes_of = numbytes;
1371             op->out_full += blks;
1372         }
1373         return 0;
1374     } else
1375 #endif
1376     {
1377         if (csp->partial_write_bytes > 0) {
1378             if (op->oflagp->pad) {
1379                 unsigned char * ncbp = (unsigned char *)bp;
1380 
1381                 numbytes += csp->partial_write_bytes;
1382                 ++csp->ocbpt;
1383                 ++blks;
1384                 res = blks * obs;
1385                 if (res > numbytes)
1386                     memset(ncbp + numbytes, 0, res - numbytes);
1387                 numbytes = res;
1388                 if (op->verbose > 1)
1389                     pr2serr("write(unix): padding probable final "
1390                             "write at seek=%" PRId64 "\n", aseek);
1391             } else {
1392                 if (FT_BLOCK & out_type)
1393                     pr2serr(">>> ignore partial write of %d bytes to block "
1394                             "device\n", csp->partial_write_bytes);
1395                 else {
1396                     numbytes += csp->partial_write_bytes;
1397                     ++op->out_partial;
1398                 }
1399             }
1400         }
1401         if ((offset != csp->of_filepos) &&
1402             (! (REASON_TAPE_SHORT_READ == csp->leave_reason))) {
1403             int64_t off_res;
1404 
1405             if (op->verbose > 2)
1406                 pr2serr("moving of filepos: new_pos=%" PRId64 "\n",
1407                         (int64_t)offset);
1408             off_res = lseek(op->odip->fd, offset, SEEK_SET);
1409             if (off_res < 0) {
1410                 pr2serr("failed moving of filepos: new_pos="
1411                         "%" PRId64 "\nlseek on output: %s\n", (int64_t)offset,
1412                         safe_strerror(errno));
1413                 return SG_LIB_FILE_ERROR;
1414             }
1415             csp->of_filepos = offset;
1416         }
1417         // write to fifo (reg file ?) is non-atomic so loop if making progress
1418         off = 0;
1419         part = 0;
1420         do {
1421             while (((res = write(op->odip->fd, bp + off,
1422                                  numbytes - off)) < 0) && (EINTR == errno))
1423                 ++op->interrupted_retries;
1424             err = errno;
1425             if ((res > 0) && (res < (numbytes - off)))
1426                 ++part;
1427         } while ((FT_FIFO & out_type) && (res > 0) &&
1428                  ((off += res) < numbytes));
1429         if (off >= numbytes) {
1430             res = numbytes;
1431             if (part && op->verbose)
1432                 pr2serr("write to output file splintered\n");
1433         } else if (off > 0)
1434             pr2serr("write to of fifo problem: count=%d, off=%d, "
1435                     "res=%d\n", numbytes, off, res);
1436         if ((op->verbose > 2) && (0 == off))
1437             pr2serr("write(unix): requested bytes=%d, res=%d\n", numbytes,
1438                     res);
1439         if (res < 0) {
1440             pr2serr("writing, seek=%" PRId64 " : %s\n", aseek,
1441                     safe_strerror(err));
1442             if ((EIO == err) || (EREMOTEIO == err))
1443                 return SG_LIB_CAT_MEDIUM_HARD;
1444             else
1445                 return SG_LIB_CAT_OTHER;
1446         } else if (res < numbytes) {
1447             pr2serr("output file probably full, seek=%" PRId64 "\n", aseek);
1448             csp->of_filepos += res;
1449             csp->bytes_of = res;
1450             op->out_full += res / obs;
1451             /* can get a partial write due to a short write */
1452             if ((res % obs) > 0) {
1453                 ++op->out_partial;
1454                 ++op->out_full;
1455             }
1456             return -1;
1457         } else {    /* successful write */
1458             csp->of_filepos += numbytes;
1459             csp->bytes_of = numbytes;
1460             op->out_full += blks;
1461         }
1462         return 0;
1463     }
1464 }
1465 
1466 /* Only for regular OFILE. Check what to do if last blocks where
1467  * not written, may require OFILE length adjustment */
1468 static void
cp_sparse_cleanup(struct opts_t * op,struct cp_state_t * csp)1469 cp_sparse_cleanup(struct opts_t * op, struct cp_state_t * csp)
1470 {
1471     int64_t offset = (op->seek * op->obs) + csp->partial_write_bytes;
1472     struct stat a_st;
1473 
1474     if (offset > csp->of_filepos) {
1475         if ((0 == op->oflagp->strunc) && (op->oflagp->sparse > 1)) {
1476             if (op->verbose > 1)
1477                 pr2serr("asked to bypass writing sparse last block of "
1478                         "zeros\n");
1479             return;
1480         }
1481         if (fstat(op->odip->fd, &a_st) < 0) {
1482             pr2serr("%s: fstat: %s\n", __func__, safe_strerror(errno));
1483             return;
1484         }
1485         if (offset == a_st.st_size) {
1486             if (op->verbose > 1)
1487                 pr2serr("%s: OFILE already correct length\n", __func__);
1488             return;
1489         }
1490         if (offset < a_st.st_size) {
1491             if (op->verbose > 1)
1492                 pr2serr("%s: OFILE longer than required, do nothing\n",
1493                         __func__);
1494             return;
1495         }
1496         if (op->oflagp->strunc) {
1497             if (op->verbose > 1)
1498                 pr2serr("About to truncate %s to byte offset "
1499                         "%" PRId64 "\n", op->odip->fn, offset);
1500             if (ftruncate(op->odip->fd, offset) < 0) {
1501                 pr2serr("could not ftruncate after copy: %s\n",
1502                         safe_strerror(errno));
1503                 return;
1504             }
1505             /* N.B. file offset (pointer) not changed by ftruncate */
1506         } else if (1 == op->oflagp->sparse) {
1507             if (op->verbose > 1)
1508                 pr2serr("writing sparse last block of zeros\n");
1509             signals_process_delay(op, DELAY_WRITE);
1510             if (cp_write_block_reg(op, csp, -1, 1, op->zeros_buff) < 0)
1511                 pr2serr("writing sparse last block of zeros "
1512                         "error, seek=%" PRId64 "\n", op->seek - 1);
1513             else
1514                 --op->out_sparse;
1515         }
1516     } else if (op->verbose > 1)
1517         pr2serr("%s: bypass as output_offset <= output_filepos\n", __func__);
1518 }
1519 
1520 /* Main copy loop's finer grain comparison and possible write (to OFILE)
1521  * for all file types. Returns 0 on success. */
1522 static int
cp_finer_comp_wr(struct opts_t * op,struct cp_state_t * csp,const unsigned char * b1p,const unsigned char * b2p)1523 cp_finer_comp_wr(struct opts_t * op, struct cp_state_t * csp,
1524                  const unsigned char * b1p, const unsigned char * b2p)
1525 {
1526     int res, k, n, oblks, numbytes, chunk, need_wr, wr_len, wr_k, obs;
1527     int trim_check, need_tr, tr_len, tr_k, out_type;
1528     int done_sigs_delay = 0;
1529 
1530     oblks = csp->ocbpt;
1531     obs = op->obs;
1532     out_type = op->odip->d_type;
1533     if (op->obpch >= oblks) {
1534         if (FT_DEV_NULL & out_type)
1535             ;
1536         else if (FT_PT & out_type) {
1537             signals_process_delay(op, DELAY_WRITE);
1538             if ((res = cp_write_pt(op, csp, 0, oblks, b1p)))
1539                 return res;
1540         } else {
1541             signals_process_delay(op, DELAY_WRITE);
1542             if ((res = cp_write_block_reg(op, csp, 0, oblks, b1p)))
1543                 return res;
1544         }
1545         return 0;
1546     }
1547     numbytes = oblks * obs;
1548     if ((FT_REG & out_type) && (csp->partial_write_bytes > 0))
1549         numbytes += csp->partial_write_bytes;
1550     chunk = op->obpch * obs;
1551     trim_check = (op->oflagp->sparse && op->oflagp->wsame16 &&
1552                   (FT_PT & out_type));
1553     need_tr = 0;
1554     tr_len = 0;
1555     tr_k = 0;
1556     for (k = 0, need_wr = 0, wr_len = 0, wr_k = 0; k < numbytes; k += chunk) {
1557         n = ((k + chunk) < numbytes) ? chunk : (numbytes - k);
1558         if (0 == memcmp(b1p + k, b2p + k, n)) {
1559             if (need_wr) {
1560                 if (FT_DEV_NULL & out_type)
1561                     ;
1562                 else if (FT_PT & out_type) {
1563                     if (! done_sigs_delay) {
1564                         done_sigs_delay = 1;
1565                         signals_process_delay(op, DELAY_WRITE);
1566                     }
1567                     if ((res = cp_write_pt(op, csp, wr_k / obs,
1568                                            wr_len / obs, b1p + wr_k)))
1569                         return res;
1570                 } else {
1571                     if (! done_sigs_delay) {
1572                         done_sigs_delay = 1;
1573                         signals_process_delay(op, DELAY_WRITE);
1574                     }
1575                     if ((res = cp_write_block_reg(op, csp, wr_k / obs,
1576                                                   wr_len / obs, b1p + wr_k)))
1577                         return res;
1578                 }
1579                 need_wr = 0;
1580             }
1581             if (need_tr)
1582                 tr_len += n;
1583             else if (trim_check) {
1584                 need_tr = 1;
1585                 tr_len = n;
1586                 tr_k = k;
1587             }
1588             op->out_sparse += (n / obs);
1589         } else {   /* look for a sequence of unequals */
1590             if (need_wr)
1591                 wr_len += n;
1592             else {
1593                 need_wr = 1;
1594                 wr_len = n;
1595                 wr_k = k;
1596             }
1597             if (need_tr) {
1598                     if (! done_sigs_delay) {
1599                         done_sigs_delay = 1;
1600                         signals_process_delay(op, DELAY_WRITE);
1601                     }
1602                 res = pt_write_same16(op, b2p, obs, tr_len / obs,
1603                                       op->seek + (tr_k / obs));
1604                 if (res)
1605                     ++op->trim_errs;
1606                 /* continue past trim errors */
1607                 need_tr = 0;
1608             }
1609         }
1610     }
1611     if (need_wr) {
1612         if (FT_DEV_NULL & out_type)
1613             ;
1614         else if (FT_PT & out_type) {
1615             if (! done_sigs_delay) {
1616                 done_sigs_delay = 1;
1617                 signals_process_delay(op, DELAY_WRITE);
1618             }
1619             if ((res = cp_write_pt(op, csp, wr_k / obs, wr_len / obs,
1620                                    b1p + wr_k)))
1621                 return res;
1622         } else {
1623             if (! done_sigs_delay) {
1624                 done_sigs_delay = 1;
1625                 signals_process_delay(op, DELAY_WRITE);
1626             }
1627             if ((res = cp_write_block_reg(op, csp, wr_k / obs, wr_len / obs,
1628                                           b1p + wr_k)))
1629                 return res;
1630         }
1631     }
1632     if (need_tr) {
1633         if (! done_sigs_delay)
1634             signals_process_delay(op, DELAY_WRITE);
1635         res = pt_write_same16(op, b2p, obs, tr_len / obs,
1636                               op->seek + (tr_k / obs));
1637         if (res)
1638             ++op->trim_errs;
1639         /* continue past trim errors */
1640     }
1641     return 0;
1642 }
1643 
1644 static int
cp_construct_pt_zero_buff(struct opts_t * op,int obpt)1645 cp_construct_pt_zero_buff(struct opts_t * op, int obpt)
1646 {
1647     if ((FT_PT & op->idip->d_type) && (NULL == op->idip->ptvp)) {
1648         op->idip->ptvp = (struct sg_pt_base *)pt_construct_obj();
1649         if (NULL == op->idip->ptvp)
1650             return -1;
1651     }
1652     if ((FT_PT & op->odip->d_type) && (NULL == op->odip->ptvp)) {
1653         op->odip->ptvp = (struct sg_pt_base *)pt_construct_obj();
1654         if (NULL == op->odip->ptvp)
1655             return -1;
1656     }
1657     if ((op->oflagp->sparse) && (NULL == op->zeros_buff)) {
1658         op->zeros_buff = (unsigned char *)calloc(obpt * op->obs, 1);
1659         if (NULL == op->zeros_buff) {
1660             pr2serr("zeros_buff calloc failed\n");
1661             return -1;
1662         }
1663     }
1664     return 0;
1665 }
1666 
1667 /* Look at IFILE and OFILE lengths and blocks sizes. If dd_count
1668  * not given, try to deduce a value for it. If oflag=resume do skip,
1669  * seek, dd_count adjustments. Returns 0 to start copy, otherwise
1670  * bypass copy and exit */
1671 static int
count_calculate(struct opts_t * op)1672 count_calculate(struct opts_t * op)
1673 {
1674     int64_t in_num_blks = -1;
1675     int64_t out_num_blks = -1;
1676     int64_t ibytes, obytes, ibk;
1677     int valid_resume = 0;
1678     int res;
1679 
1680     if ((res = calc_count(op, &in_num_blks, &out_num_blks)))
1681         return res;
1682     if ((0 == op->oflagp->resume) && (op->dd_count > 0))
1683         return 0;
1684     if (op->verbose > 1)
1685         pr2serr("calc_count: in_num_blks=%" PRId64 ", out_num_blks"
1686                 "=%" PRId64 "\n", in_num_blks, out_num_blks);
1687     if (op->skip && (FT_REG == op->idip->d_type) &&
1688         (op->skip > in_num_blks)) {
1689         pr2serr("cannot skip to specified offset on %s\n", op->idip->fn);
1690         op->dd_count = 0;
1691         return -1;
1692     }
1693     if (op->oflagp->resume) {
1694         if (FT_REG == op->odip->d_type) {
1695             if (out_num_blks < 0)
1696                 pr2serr("resume cannot determine size of OFILE, ignore\n");
1697             else
1698                 valid_resume = 1;
1699         } else
1700             pr2serr("resume expects OFILE to be regular, ignore\n");
1701     }
1702     if ((op->dd_count < 0) && (! valid_resume)) {
1703         /* Scale back in_num_blks by value of skip */
1704         if (op->skip && (in_num_blks > op->skip))
1705             in_num_blks -= op->skip;
1706         /* Scale back out_num_blks by value of seek */
1707         if (op->seek && (out_num_blks > op->seek))
1708             out_num_blks -= op->seek;
1709 
1710         if ((out_num_blks < 0) && (in_num_blks > 0))
1711             op->dd_count = in_num_blks;
1712         else if ((op->reading_fifo) && (out_num_blks < 0))
1713             ;
1714         else if ((out_num_blks < 0) && (in_num_blks <= 0))
1715             ;
1716         else {
1717             ibytes = (in_num_blks > 0) ? (op->ibs * in_num_blks) : 0;
1718             obytes = op->obs * out_num_blks;
1719             if (0 == ibytes)
1720                 op->dd_count = obytes / op->ibs;
1721             else if ((ibytes > obytes) && (FT_REG != op->odip->d_type)) {
1722                 op->dd_count = obytes / op->ibs;
1723             } else
1724                 op->dd_count = in_num_blks;
1725         }
1726     }
1727     if (valid_resume) {
1728         if (op->dd_count < 0)
1729             op->dd_count = in_num_blks - op->skip;
1730         if (out_num_blks <= op->seek)
1731             pr2serr("resume finds no previous copy, restarting\n");
1732         else {
1733             obytes = op->obs * (out_num_blks - op->seek);
1734             ibk = obytes / op->ibs;
1735             if (ibk >= op->dd_count) {
1736                 pr2serr("resume finds copy complete, exiting\n");
1737                 op->dd_count = 0;
1738                 return -1;
1739             }
1740             /* align to bpt multiple */
1741             ibk = (ibk / op->bpt_i) * op->bpt_i;
1742             op->skip += ibk;
1743             op->seek += (ibk * op->ibs) / op->obs;
1744             op->dd_count -= ibk;
1745             pr2serr("resume adjusting skip=%" PRId64 ", seek=%"
1746                     PRId64 ", and count=%" PRId64 "\n", op->skip, op->seek,
1747                     op->dd_count);
1748         }
1749     }
1750     return 0;
1751 }
1752 
1753 /* This is the main copy loop (unless an offloaded copy is requested).
1754  * Attempts to copy 'dd_count' blocks (size given by bs or ibs) in chunks
1755  * of op->bpt_i blocks. Returns 0 if successful.  */
1756 static int
do_rw_copy(struct opts_t * op)1757 do_rw_copy(struct opts_t * op)
1758 {
1759     int ibpt, obpt, res, n, sparse_skip, sparing_skip, continual_read;
1760     int ret = 0;
1761     int first_time = 1;
1762     int first_time_ff = 1;
1763     int id_type = op->idip->d_type;
1764     int od_type = op->odip->d_type;
1765     struct cp_state_t cp_st;
1766     struct cp_state_t * csp;
1767     unsigned char * wPos = op->wrkPos;
1768 
1769     continual_read = op->reading_fifo && (op->dd_count < 0);
1770     if (op->verbose > 3) {
1771         if (continual_read)
1772             pr2serr("do_rw_copy: reading fifo continually\n");
1773         else
1774             pr2serr("do_rw_copy: dd_count=%" PRId64 "\n", op->dd_count);
1775     }
1776     if ((op->dd_count <= 0) && (! op->reading_fifo))
1777         return 0;
1778     csp = &cp_st;
1779     memset(csp, 0, sizeof(struct cp_state_t));
1780     ibpt = op->bpt_i;
1781     obpt = (op->ibs * op->bpt_i) / op->obs;
1782     if ((ret = cp_construct_pt_zero_buff(op, obpt)))
1783         goto copy_end;
1784     /* Both csp->if_filepos and csp->of_filepos are 0 */
1785 
1786     /* <<< main loop that does the copy >>> */
1787     while ((op->dd_count > 0) || continual_read) {
1788         if (first_time)
1789             first_time = 0;
1790         else
1791             signals_process_delay(op, DELAY_COPY_SEGMENT);
1792         csp->bytes_read = 0;
1793         csp->bytes_of = 0;
1794         csp->bytes_of2 = 0;
1795         sparing_skip = 0;
1796         sparse_skip = 0;
1797         if ((op->dd_count >= ibpt) || continual_read) {
1798             csp->icbpt = ibpt;
1799             csp->ocbpt = obpt;
1800         } else {
1801             csp->icbpt = op->dd_count;
1802             res = op->dd_count;
1803             n = res * op->ibs;
1804             csp->ocbpt = n / op->obs;
1805             if (n % op->obs) {
1806                 ++csp->ocbpt;
1807                 memset(wPos, 0, op->ibs * ibpt);
1808             }
1809         }
1810 
1811         /* Start of reading section */
1812         if (FT_PT & id_type) {
1813             if ((ret = cp_read_pt(op, csp, wPos)))
1814                 break;
1815         } else if (FT_FIFO & id_type) {
1816              if ((ret = cp_read_fifo(op, csp, wPos)))
1817                 break;
1818         } else if (FT_TAPE & id_type) {
1819 #ifdef SG_LIB_LINUX
1820              if ((ret = cp_read_tape(op, csp, wPos)))
1821                 break;
1822 #else
1823             pr2serr("reading from tape not supported in this OS\n");
1824             ret = SG_LIB_CAT_OTHER;
1825             break;
1826 #endif
1827         } else if (FT_ALL_FF & id_type) {
1828             if (first_time_ff) {
1829                 first_time_ff = 0;
1830                 memset(wPos, 0xff, op->ibs * ibpt);
1831             }
1832             op->in_full += csp->icbpt;
1833         } else {
1834              if ((ret = cp_read_block_reg(op, csp, wPos)))
1835                 break;
1836         }
1837         if (0 == csp->icbpt)
1838             break;      /* nothing read so leave loop */
1839 
1840         if ((op->o2dip->fd >= 0) &&
1841             ((ret = cp_write_of2(op, csp, wPos))))
1842             break;
1843 
1844         if (op->oflagp->sparse) {
1845             n = (csp->ocbpt * op->obs) + csp->partial_write_bytes;
1846             if (0 == memcmp(wPos, op->zeros_buff, n)) {
1847                 sparse_skip = 1;
1848                 if (op->oflagp->wsame16 && (FT_PT & od_type)) {
1849                     signals_process_delay(op, DELAY_WRITE);
1850                     res = pt_write_same16(op, op->zeros_buff, op->obs,
1851                                           csp->ocbpt, op->seek);
1852                     if (res)
1853                         ++op->trim_errs;
1854                 }
1855             } else if (op->obpch) {
1856                 ret = cp_finer_comp_wr(op, csp, wPos, op->zeros_buff);
1857                 if (ret)
1858                     break;
1859                 goto bypass_write;
1860             }
1861         }
1862         if (op->oflagp->sparing && (! sparse_skip)) {
1863             /* In write sparing, we read from the output */
1864             if (FT_PT & od_type)
1865                 res = cp_read_of_pt(op, csp, op->wrkPos2);
1866             else
1867                 res = cp_read_of_block_reg(op, csp, op->wrkPos2);
1868             if (0 == res) {
1869                 n = (csp->ocbpt * op->obs) + csp->partial_write_bytes;
1870                 if (0 == memcmp(wPos, op->wrkPos2, n))
1871                     sparing_skip = 1;
1872                 else if (op->obpch) {
1873                     ret = cp_finer_comp_wr(op, csp, wPos, op->wrkPos2);
1874                     if (ret)
1875                         break;
1876                     goto bypass_write;
1877                 }
1878             } else {
1879                 ret = res;
1880                 break;
1881             }
1882         }
1883 
1884         /* Start of writing section */
1885         if (sparing_skip || sparse_skip) {
1886             op->out_sparse += csp->ocbpt;
1887             if (csp->partial_write_bytes > 0)
1888                 ++op->out_sparse_partial;
1889         } else {
1890             if (FT_DEV_NULL & od_type)
1891                 ;  /* don't bump out_full (earlier revs did) */
1892             else {
1893                 signals_process_delay(op, DELAY_WRITE);
1894                 if (FT_PT & od_type) {
1895                     if ((ret = cp_write_pt(op, csp, 0, csp->ocbpt, wPos)))
1896                         break;
1897                 } else if (FT_TAPE & od_type) {
1898 #ifdef SG_LIB_LINUX
1899                     int could_be_last;
1900 
1901                     could_be_last = ((! continual_read) &&
1902                                      (csp->icbpt >= op->dd_count));
1903                     if ((ret = cp_write_tape(op, csp, wPos, could_be_last)))
1904                         break;
1905 #else
1906                     pr2serr("writing to tape not supported in this OS\n");
1907                     ret = SG_LIB_CAT_OTHER;
1908                     break;
1909 #endif
1910                 } else if ((ret = cp_write_block_reg(op, csp, 0, csp->ocbpt,
1911                                                      wPos))) /* plus fifo */
1912                     break;
1913             }
1914         }
1915 bypass_write:
1916 #ifdef HAVE_POSIX_FADVISE
1917         do_fadvise(op, csp->bytes_read, csp->bytes_of, csp->bytes_of2);
1918 #endif
1919         if (op->dd_count > 0)
1920             op->dd_count -= csp->icbpt;
1921         op->skip += csp->icbpt;
1922         op->seek += csp->ocbpt;
1923         if (csp->leave_after_write) {
1924             if (REASON_TAPE_SHORT_READ == csp->leave_reason) {
1925                 /* allow multiple partial writes for tape */
1926                 csp->partial_write_bytes = 0;
1927                 csp->leave_after_write = 0;
1928             } else {
1929                 /* other cases: stop copy after partial write */
1930                 ret = csp->leave_reason;
1931                 break;
1932             }
1933         }
1934     } /* end of main loop that does the copy ... */
1935 
1936     /* sparse: clean up ofile length when last block(s) were not written */
1937     if ((FT_REG & od_type) && (0 == op->oflagp->nowrite) &&
1938         op->oflagp->sparse)
1939         cp_sparse_cleanup(op, csp);
1940 
1941 #ifdef HAVE_FDATASYNC
1942     else if (op->oflagp->fdatasync) {
1943         if (fdatasync(op->odip->fd) < 0)
1944             perror("fdatasync() error");
1945         if (op->verbose)
1946             pr2serr("Called fdatasync() on %s successfully\n", op->odip->fn);
1947     }
1948 #endif
1949 #ifdef HAVE_FSYNC
1950     else if (op->oflagp->fsync) {
1951         if (fsync(op->odip->fd) < 0)
1952             perror("fsync() error");
1953         if (op->verbose)
1954             pr2serr("Called fsync() on %s successfully\n", op->odip->fn);
1955     }
1956 #endif
1957 
1958 copy_end:
1959     if (op->idip->ptvp) {
1960         pt_destruct_obj(op->idip->ptvp);
1961         op->idip->ptvp = NULL;
1962     }
1963     if (op->odip->ptvp) {
1964         pt_destruct_obj(op->odip->ptvp);
1965         op->odip->ptvp = NULL;
1966     }
1967     return ret;
1968 }
1969 
1970 static int
prepare_pi(struct opts_t * op)1971 prepare_pi(struct opts_t * op)
1972 {
1973 #define PI_WORK 1       /* Protection Information */
1974 #ifdef PI_WORK
1975     int res;
1976 
1977     op->ibs_pi = op->ibs;
1978     op->obs_pi = op->obs;
1979     if (op->rdprotect) {
1980         if ((0 == op->idip->prot_type) || (! (FT_PT & op->idip->d_type))) {
1981             pr2serr("IFILE is not a pt device or doesn't have "
1982                     "protection information\n");
1983             return SG_LIB_CAT_OTHER;
1984         }
1985         if (op->ibs != op->obs) {
1986             pr2serr("protect: don't support IFILE and OFILE "
1987                     "with different block sizes\n");
1988             return SG_LIB_CAT_OTHER;
1989         }
1990         if (op->wrprotect) {
1991             if (op->idip->p_i_exp != op->odip->p_i_exp) {
1992                 pr2serr("Don't support IFILE and OFILE with "
1993                         "different P_I_EXP fields\n");
1994                 return SG_LIB_CAT_OTHER;
1995             }
1996         }
1997         res = (op->idip->p_i_exp ? (1 << op->idip->p_i_exp) : 1) * 8;
1998         op->ibs_pi += res;
1999         op->obs_pi += res;
2000     }
2001     if (op->wrprotect) {
2002         if ((0 == op->odip->prot_type) || (! (FT_PT & op->odip->d_type))) {
2003             pr2serr("OFILE is not a pt device or doesn't have "
2004                     "protection information\n");
2005             return SG_LIB_CAT_OTHER;
2006         }
2007         if (op->ibs != op->obs) {
2008             pr2serr("protect: don't support IFILE and OFILE "
2009                     "with different block sizes\n");
2010             return SG_LIB_CAT_OTHER;
2011         }
2012         res = (op->odip->p_i_exp ? (1 << op->odip->p_i_exp) : 1) * 8;
2013         op->ibs_pi += res;
2014         op->obs_pi += res;
2015     }
2016 #else
2017     if (op) { ; }       /* suppress warning */
2018 #endif  /* PI_WORK */
2019     return 0;
2020 }
2021 
2022 static int
open_files_devices(struct opts_t * op)2023 open_files_devices(struct opts_t * op)
2024 {
2025     int fd, ret;
2026     struct dev_info_t * idip = op->idip;
2027     struct dev_info_t * odip = op->odip;
2028     struct dev_info_t * o2dip = op->o2dip;
2029 
2030 #ifdef SG_LIB_WIN32
2031     win32_adjust_fns_pt(op);
2032 #endif
2033     if (idip->fn[0]) {
2034         if (('-' == idip->fn[0]) && ('\0' == idip->fn[1])) {
2035             fd = STDIN_FILENO;
2036             idip->d_type = FT_FIFO;
2037             ++op->reading_fifo;
2038             if (op->verbose)
2039                 pr2serr(" >> Input file type: fifo [stdin, stdout, named "
2040                         "pipe]\n");
2041         } else {
2042             fd = open_if(op);
2043             if (fd < 0)
2044                 return -fd;
2045         }
2046         idip->fd = fd;
2047     } else if (op->iflagp->ff) {
2048         idip->d_type = FT_ALL_FF;
2049         idip->fd = 9999;        /* unlikely file descriptor */
2050     } else {
2051         pr2serr("'if=IFILE' option must be given. For stdin as input use "
2052                 "'if=-'\n");
2053         pr2serr("For more information use '--help'\n");
2054         return SG_LIB_SYNTAX_ERROR;
2055     }
2056 
2057     if ('\0' == odip->fn[0])
2058         strcpy(odip->fn, "."); /* treat no 'of=OFILE' option as /dev/null */
2059     if (('-' == odip->fn[0]) && ('\0' == odip->fn[1])) {
2060         fd = STDOUT_FILENO;
2061         odip->d_type = FT_FIFO;
2062         odip->d_type_hold = odip->d_type;
2063         if (op->verbose)
2064             pr2serr(" >> Output file type: fifo [stdin, stdout, named "
2065                     "pipe]\n");
2066     } else {
2067         fd = open_of(op);
2068         if (fd < -1)
2069             return -fd;
2070     }
2071     odip->fd = fd;
2072 
2073     if (o2dip->fn[0]) {
2074         if (('-' == o2dip->fn[0]) && ('\0' == o2dip->fn[1])) {
2075             fd = STDOUT_FILENO;
2076             o2dip->d_type = FT_FIFO;
2077             if (op->verbose)
2078                 pr2serr(" >> Output 2 file type: fifo  [stdin, stdout, "
2079                         "named pipe]\n");
2080         } else {
2081             o2dip->d_type = dd_filetype(o2dip->fn, op->verbose);
2082             if (FT_DEV_NULL & o2dip->d_type)
2083                 fd = -1;
2084             else if (! ((FT_REG | FT_FIFO) & o2dip->d_type)) {
2085                 pr2serr("Error: output 2 file type must be regular "
2086                         "file or fifo\n");
2087                 return SG_LIB_FILE_ERROR;
2088             } else {
2089                 if ((fd = open(o2dip->fn, O_WRONLY | O_CREAT, 0666)) < 0) {
2090                     ret = errno;
2091                     pr2serr("could not open %s for writing: %s\n", o2dip->fn,
2092                             safe_strerror(errno));
2093                     return ret;
2094                 }
2095                 if (sg_set_binary_mode(fd) < 0)
2096                     perror("sg_set_binary_mode");
2097                 if (op->verbose)
2098                     pr2serr(" >> Output 2 file type: regular\n");
2099             }
2100         }
2101     } else
2102         fd = -1;
2103     o2dip->fd = fd;
2104     return 0;
2105 }
2106 
2107 static void
block_size_bpt_check(struct opts_t * op)2108 block_size_bpt_check(struct opts_t * op)
2109 {
2110     if (0 == op->bpt_given) {
2111 /* If reading from or writing to tape, use default bpt 1 if user did not
2112  * specify. Avoids inadvertent/accidental use of wrong tape block size. */
2113         if ((FT_TAPE & op->idip->d_type) || (FT_TAPE & op->odip->d_type)) {
2114             op->bpt_i = 1;
2115         }
2116 #ifdef SG_LIB_FREEBSD
2117         else {
2118      /* FreeBSD (7+8 [DFLTPHYS]) doesn't like buffers larger than 64 KB being
2119      * sent to its pt interface (CAM), so take that into account when choosing
2120      * the default bpt value. There is overhead in the pt interface so reduce
2121      * default bpt value so bpt*ibs <= 32 KB .*/
2122         if (((FT_PT & op->idip->d_type) || (FT_PT & op->odip->d_type)) &&
2123             ((op->ibs <= 32768) && (op->bpt_i * op->ibs) > 32768))
2124             op->bpt_i = 32768 / op->ibs;
2125         }
2126 #endif
2127     }
2128 }
2129 
2130 static void
sparse_sparing_check(struct opts_t * op)2131 sparse_sparing_check(struct opts_t * op)
2132 {
2133     if (op->iflagp->sparse && (! op->oflagp->sparse)) {
2134         if (FT_DEV_NULL & op->odip->d_type) {
2135             pr2serr("sparse flag usually ignored on input; set it "
2136                     "on output in this case\n");
2137             ++op->oflagp->sparse;
2138         } else
2139             pr2serr("sparse flag ignored on input\n");
2140     }
2141     if (op->oflagp->sparse) {
2142         if ((FT_FIFO | FT_TAPE) & op->odip->d_type) {
2143             pr2serr("oflag=sparse needs seekable output file, ignore\n");
2144             op->oflagp->sparse = 0;
2145         } else {
2146             op->out_sparse_active = 1;
2147             if (op->oflagp->wsame16)
2148                 op->out_trim_active = 1;
2149         }
2150     }
2151     if (op->oflagp->sparing) {
2152         if ((FT_DEV_NULL | FT_FIFO | FT_TAPE) & op->odip->d_type) {
2153             pr2serr("oflag=sparing needs a readable and seekable "
2154                     "output file, ignore\n");
2155             op->oflagp->sparing = 0;
2156         } else
2157             op->out_sparing_active = 1;
2158     }
2159 }
2160 
2161 static void
cdb_size_prealloc(struct opts_t * op)2162 cdb_size_prealloc(struct opts_t * op)
2163 {
2164     if (op->oflagp->prealloc) {
2165         if ((FT_DEV_NULL | FT_FIFO | FT_TAPE | FT_PT) & op->odip->d_type) {
2166             pr2serr("oflag=pre-alloc needs a normal output file, ignore\n");
2167             op->oflagp->prealloc = 0;
2168         }
2169     }
2170     if (! op->cdbsz_given) {
2171         if ((FT_PT & op->idip->d_type) && (op->iflagp->cdbsz < 16) &&
2172             (((op->dd_count + op->skip) > UINT_MAX) ||
2173              (op->bpt_i > USHRT_MAX))) {
2174             if (op->verbose > 0)
2175                 pr2serr("SCSI command size increased from 10 to 16 "
2176                         "bytes on %s\n", op->idip->fn);
2177             op->iflagp->cdbsz = 16;
2178         }
2179         if ((FT_PT & op->odip->d_type) && (op->oflagp->cdbsz < 16) &&
2180             (((op->dd_count + op->seek) > UINT_MAX) ||
2181              (((op->ibs * op->bpt_i) / op->obs) > USHRT_MAX))) {
2182             if (op->verbose)
2183                 pr2serr("SCSI command size increased from 10 to 16 "
2184                         "bytes on %s\n", op->odip->fn);
2185             op->oflagp->cdbsz = 16;
2186         }
2187     }
2188 }
2189 
2190 #ifdef SG_LIB_LINUX
2191 
2192 static void
tape_cleanup_of(struct opts_t * op)2193 tape_cleanup_of(struct opts_t * op)
2194 {
2195     /* Before closing OFILE, if writing to tape handle suppressing the
2196      * writing of a filemark and/or flushing the drive buffer which the
2197      * Linux st driver normally does when tape file is closed after writing.
2198      * Possibilities depend on oflag arguments:
2199      * nofm:         MTWEOFI 0 if possible (kernel 2.6.37+), else MTBSR 0
2200      * nofm & fsync: MTWEOF 0
2201      * fsync:        Do nothing; st writes filemark & flushes buffer on close.
2202      * neither:      MTWEOFI 1 if possible (2.6.37+), else nothing (drive
2203      *               buffer will be flushed if MTWEOFI not possible). */
2204     struct mtop mt_cmd;
2205     int res;
2206 
2207     if (op->oflagp->nofm || !op->oflagp->fsync) {
2208         mt_cmd.mt_op = (op->oflagp->fsync) ? MTWEOF : MTWEOFI;
2209         mt_cmd.mt_count = (op->oflagp->nofm) ? 0 : 1;
2210         res = ioctl(op->odip->fd, MTIOCTOP, &mt_cmd);
2211         if (res != 0) {
2212             if (op->verbose > 0)
2213                 pr2serr("MTWEOF%s %d failed: %s\n",
2214                         (op->oflagp->fsync) ? "" : "I", mt_cmd.mt_count,
2215                         safe_strerror(errno));
2216             if (op->oflagp->nofm && !op->oflagp->fsync) {
2217                 if (op->verbose > 0)
2218                     pr2serr("Trying MTBSR 0 instead\n");
2219                 mt_cmd.mt_op = MTBSR; /* mt_cmd.mt_count = 0 from above */
2220                 res = ioctl(op->odip->fd, MTIOCTOP, &mt_cmd);
2221                 if (res != 0)
2222                     pr2serr("MTBSR 0 failed: %s\n(Filemark will be written "
2223                             "when tape file is closed)\n",
2224                             safe_strerror(errno));
2225             }
2226         }
2227     }
2228 }
2229 
2230 #endif  /* SG_LIB_LINUX */
2231 
2232 static int
do_falloc(struct opts_t * op)2233 do_falloc(struct opts_t * op)
2234 {
2235 #ifdef SG_LIB_LINUX
2236 #ifdef HAVE_FALLOCATE
2237     /* Try to pre-allocate space in the output file.
2238      *
2239      * If fallocate() does not succeed, exit with an error message. The user
2240      * can then either free up some disk space or invoke ddpt without
2241      * oflag=pre-alloc (at the risk of running out of disk space).
2242      *
2243      * TODO/DISCUSSION: Some filesystems (e.g. FAT32) don't support
2244      * fallocate(). In that case we should probably have a way to continue if
2245      * fallocate() fails, rather than exiting; useful for use in scripts
2246      * where the user would like to pre-allocate space when possible.
2247      *
2248      * On Linux, try fallocate() with the FALLOC_FL_KEEP_SIZE flag, which
2249      * allocates space but doesn't change the apparent file size (useful
2250      * since oflag=resume can be used).
2251      *
2252      * If fallocate() with FALLOC_FL_KEEP_SIZE returns ENOTTY, EINVAL or
2253      * EOPNOTSUPP, retry without that flag (since the flag is only supported
2254      * in recent Linux kernels). */
2255     int res;
2256 
2257 #ifdef PREALLOC_DEBUG
2258     pr2serr("About to call fallocate() with FALLOC_FL_KEEP_SIZE\n");
2259 #endif
2260     res = fallocate(op->odip->fd, FALLOC_FL_KEEP_SIZE, op->obs*op->seek,
2261                     op->obs*op->dd_count);
2262 #ifdef PREALLOC_DEBUG
2263     pr2serr("fallocate() returned %d\n", res);
2264 #endif
2265     /* fallocate() fails if the kernel does not support
2266      * FALLOC_FL_KEEP_SIZE, so retry without that flag. */
2267     if (-1 == res) {
2268         if ((ENOTTY == errno) || (EINVAL == errno)
2269              || (EOPNOTSUPP == errno)) {
2270             if (op->verbose)
2271                 pr2serr("Could not pre-allocate with "
2272                         "FALLOC_FL_KEEP_SIZE (%s), retrying without "
2273                         "...\n", safe_strerror(errno));
2274             res = fallocate(op->odip->fd, 0, op->obs*op->seek,
2275                             op->obs*op->dd_count);
2276 #ifdef PREALLOC_DEBUG
2277             pr2serr("fallocate() without FALLOC_FL_KEEP_SIZE "
2278                     " returned %d\n", res);
2279 #endif
2280         }
2281     } else {
2282         /* fallocate() with FALLOC_FL_KEEP_SIZE succeeded. Set
2283          * op->oflagp->prealloc to 0 so the possible message about using
2284          * oflag=resume is not suppressed later. */
2285         op->oflagp->prealloc = 0;
2286     }
2287     if (-1 == res) {
2288             pr2serr("Unable to pre-allocate space: %s\n",
2289                     safe_strerror(errno));
2290             return SG_LIB_CAT_OTHER;
2291     }
2292     if (op->verbose > 1)
2293         pr2serr("Pre-allocated %" PRId64 " bytes at offset %"
2294                 PRId64 "\n", op->obs*op->dd_count, op->obs*op->seek);
2295 
2296 #endif  /* HAVE_FALLOCATE */
2297 #else   /* other than SG_LIB_LINUX */
2298 #ifdef HAVE_POSIX_FALLOCATE
2299     int res;
2300 
2301     /* If not on Linux, use posix_fallocate(). (That sets the file size to its
2302      * full length, so re-invoking ddpt with oflag=resume will do nothing.) */
2303     res = posix_fallocate(op->odip->fd, op->obs*op->seek,
2304                           op->obs*op->dd_count);
2305     if (-1 == res) {
2306             pr2serr("Unable to pre-allocate space: %s\n",
2307                     safe_strerror(errno));
2308             return SG_LIB_CAT_OTHER;
2309     }
2310     if (op->verbose > 1)
2311         pr2serr("Pre-allocated %" PRId64 " bytes at offset %" PRId64 "\n",
2312                 op->obs*op->dd_count, op->obs*op->seek);
2313 #else   /* do not HAVE_POSIX_FALLOCATE */
2314     if (op) { ; }
2315 #endif  /* HAVE_POSIX_FALLOCATE else */
2316 #endif  /* SG_LIB_LINUX else */
2317     return 0;
2318 }
2319 
2320 static void
details_pre_copy_print(struct opts_t * op)2321 details_pre_copy_print(struct opts_t * op)
2322 {
2323     pr2serr("skip=%" PRId64 " (blocks on input), seek=%" PRId64
2324             " (blocks on output)\n", op->skip, op->seek);
2325     if (op->verbose > 1) {
2326         pr2serr("  ibs=%d bytes, obs=%d bytes, OBPC=%d\n",
2327                 op->ibs, op->obs, op->obpch);
2328         if (op->ibs != op->ibs_pi)
2329             pr2serr("  due to protect ibs_pi=%d bytes, "
2330                     "obs_pi=%d bytes\n", op->ibs_pi, op->obs_pi);
2331     }
2332     if (op->reading_fifo && (op->dd_count < 0))
2333         pr2serr("  reading fifo, blocks_per_transfer=%d\n", op->bpt_i);
2334     else
2335         pr2serr("  initial count=%" PRId64 " (blocks of input), "
2336                 "blocks_per_transfer=%d\n", op->dd_count, op->bpt_i);
2337     if ((op->delay > 0) || (op->wdelay > 0))
2338         pr2serr("  delay=%d ms, wdelay=%d ms\n", op->delay, op->wdelay);
2339 }
2340 
2341 static int
wrk_buffers_init(struct opts_t * op)2342 wrk_buffers_init(struct opts_t * op)
2343 {
2344     int len = op->ibs_pi * op->bpt_i;
2345 
2346     if (op->has_xcopy)
2347         return 0;
2348     if (op->iflagp->direct || op->oflagp->direct) {
2349         size_t psz;
2350 
2351 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
2352         psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */
2353 #elif defined(SG_LIB_WIN32)
2354         psz = win32_pagesize();
2355 #else
2356         psz = 4096;     /* give up, pick likely figure */
2357 #endif
2358 
2359 #ifdef HAVE_POSIX_MEMALIGN
2360         {
2361             int err;
2362             void * wp;
2363 
2364             wp = op->wrkBuff;
2365             err = posix_memalign(&wp, psz, len);
2366             if (err) {
2367                 pr2serr("posix_memalign: error [%d] out of memory?\n", err);
2368                 return SG_LIB_CAT_OTHER;
2369             }
2370             op->wrkBuff = (unsigned char *)wp;
2371             memset(op->wrkBuff, 0, len);
2372             op->wrkPos = op->wrkBuff;
2373             if (op->oflagp->sparing) {
2374                 wp = op->wrkBuff2;
2375                 err = posix_memalign(&wp, psz, len);
2376                 if (err) {
2377                     pr2serr("posix_memalign(2): error [%d] out of memory?\n",
2378                              err);
2379                     return SG_LIB_CAT_OTHER;
2380                 }
2381                 op->wrkBuff2 = (unsigned char *)wp;
2382                 memset(op->wrkBuff2, 0, len);
2383                 op->wrkPos2 = op->wrkBuff2;
2384             }
2385         }
2386 #else   /* do not HAVE_POSIX_MEMALIGN */
2387         op->wrkBuff = (unsigned char*)calloc(len + psz, 1);
2388         if (0 == op->wrkBuff) {
2389             pr2serr("Not enough user memory for aligned usage\n");
2390             return SG_LIB_CAT_OTHER;
2391         }
2392         op->wrkPos = (unsigned char *)(((uintptr_t)op->wrkBuff + psz - 1) &
2393                                        (~((uintptr_t)psz - 1)));
2394         if (op->oflagp->sparing) {
2395             op->wrkBuff2 = (unsigned char*)calloc(len + psz, 1);
2396             if (0 == op->wrkBuff2) {
2397                 pr2serr("Not enough user memory for aligned usage(2)\n");
2398                 return SG_LIB_CAT_OTHER;
2399             }
2400             op->wrkPos2 = (unsigned char *)
2401                            (((uintptr_t)op->wrkBuff2 + psz - 1) &
2402                             (~((uintptr_t)psz - 1)));
2403         }
2404 #endif  /* HAVE_POSIX_MEMALIGN */
2405     } else {
2406         op->wrkBuff = (unsigned char*)calloc(op->ibs_pi * op->bpt_i, 1);
2407         if (0 == op->wrkBuff) {
2408             pr2serr("Not enough user memory\n");
2409             return SG_LIB_CAT_OTHER;
2410         }
2411         op->wrkPos = op->wrkBuff;
2412         if (op->oflagp->sparing) {
2413             op->wrkBuff2 = (unsigned char*)calloc(op->ibs_pi * op->bpt_i, 1);
2414             if (0 == op->wrkBuff2) {
2415                 pr2serr("Not enough user memory(2)\n");
2416                 return SG_LIB_CAT_OTHER;
2417             }
2418             op->wrkPos2 = op->wrkBuff2;
2419         }
2420     }
2421     return 0;
2422 }
2423 
2424 static void
cleanup_resources(struct opts_t * op)2425 cleanup_resources(struct opts_t * op)
2426 {
2427 #ifdef SG_LIB_LINUX
2428     if ((FT_TAPE & op->idip->d_type) || (FT_TAPE & op->odip->d_type)) {
2429         /* For writing, the st driver writes a filemark on closing the file
2430          * (unless user specified oflag=nofm), so make clear that the
2431          * position shown is prior to closing. */
2432         print_tape_pos("Final ", " (before closing file)", op);
2433         if ((FT_TAPE & op->odip->d_type) && (op->verbose > 1) &&
2434             op->oflagp->nofm)
2435             pr2serr("(suppressing writing of filemark on close)\n");
2436     }
2437 #endif
2438 
2439     if (op->iflagp->errblk)
2440         errblk_close(op);
2441 
2442     if (op->wrkBuff)
2443         free(op->wrkBuff);
2444     if (op->wrkBuff2)
2445         free(op->wrkBuff2);
2446     if (op->zeros_buff)
2447         free(op->zeros_buff);
2448     if (FT_PT & op->idip->d_type)
2449         pt_close(op->idip->fd);
2450     else if ((op->idip->fd >= 0) && (STDIN_FILENO != op->idip->fd))
2451         close(op->idip->fd);
2452     if (FT_PT & op->odip->d_type)
2453         pt_close(op->odip->fd);
2454     if ((op->odip->fd >= 0) && (STDOUT_FILENO != op->odip->fd) &&
2455         !(FT_DEV_NULL & op->odip->d_type)) {
2456 #ifdef SG_LIB_LINUX
2457         if (FT_TAPE & op->odip->d_type)
2458             tape_cleanup_of(op);
2459 #endif
2460         close(op->odip->fd);
2461     }
2462     if ((op->o2dip->fd >= 0) && (STDOUT_FILENO != op->o2dip->fd))
2463         close(op->o2dip->fd);
2464 }
2465 
2466 static int
chk_sgl_for_non_offload(struct opts_t * op)2467 chk_sgl_for_non_offload(struct opts_t * op)
2468 {
2469     if (op->in_sgl) {
2470         if (op->in_sgl_elems > 1) {
2471             pr2serr("Only accept a multiple element skip= (gather) list for "
2472                     "%s with odx\n", op->idip->fn[0] ? op->idip->fn : "?");
2473             return SG_LIB_SYNTAX_ERROR;
2474         }
2475         if ((op->dd_count >= 0) && (op->dd_count != op->in_sgl[0].num)) {
2476             pr2serr("dd_count [%" PRIu64 "] and skip (sgl num) [%" PRIu32 "] "
2477                     "contradict\n", op->dd_count, op->in_sgl[0].num);
2478             return SG_LIB_SYNTAX_ERROR;
2479         }
2480         op->skip = op->in_sgl[0].lba;
2481         op->dd_count = op->in_sgl[0].num;
2482     }
2483     if (op->out_sgl) {
2484         if (op->out_sgl_elems > 1) {
2485             pr2serr("Only accept a multiple element seek= (scatter) list for "
2486                     "%s with odx\n", op->odip->fn[0] ? op->odip->fn : "?");
2487             return SG_LIB_SYNTAX_ERROR;
2488         }
2489         /* assuming ibs==obs, revisit xxxxxxx */
2490         if ((op->dd_count >= 0) && (op->dd_count != op->out_sgl[0].num)) {
2491             pr2serr("dd_count [%" PRIu64 "] and seek (sgl num) [%" PRIu32 "] "
2492                     "too confusing\n", op->dd_count, op->out_sgl[0].num);
2493             return SG_LIB_SYNTAX_ERROR;
2494         }
2495         op->seek = op->out_sgl[0].lba;
2496         op->dd_count = op->out_sgl[0].num;
2497     }
2498     return 0;
2499 }
2500 
2501 
2502 /* The main() function: much of the its complex logic is spawned off to
2503  * helper functions shown directly above. */
2504 int
main(int argc,char * argv[])2505 main(int argc, char * argv[])
2506 {
2507     int ret = 0;
2508     int started_copy = 0;
2509     int jf_depth = 0;
2510     struct opts_t ops;
2511     struct flags_t iflag, oflag;
2512     struct dev_info_t ids, ods, o2ds;
2513     struct opts_t * op;
2514 
2515     op = &ops;
2516     state_init(op, &iflag, &oflag, &ids, &ods, &o2ds);
2517     ret = cl_process(op, argc, argv, ddpt_version_str, jf_depth);
2518     if (op->do_help > 0) {
2519         ddpt_usage(op->do_help);
2520         return 0;
2521     } else if (ret)
2522         return (ret < 0) ? 0 : ret;
2523 
2524     if (op->quiet) {
2525         if (NULL == freopen("/dev/null", "w", stderr))
2526             pr2serr("freopen: failed to redirect stderr to /dev/null : %s\n",
2527                     safe_strerror(errno));
2528     }
2529 
2530 #ifdef SG_LIB_WIN32
2531     if (op->wscan)
2532         return sg_do_wscan('\0', op->wscan, op->verbose);
2533 #endif
2534 
2535     install_signal_handlers(op);
2536 
2537     if (op->has_odx) {
2538         started_copy = 1;
2539         ret = do_odx(op);
2540         goto cleanup;
2541     }
2542 
2543     /* may allow scatter gather lists for non-odx copies in future */
2544     ret = chk_sgl_for_non_offload(op);
2545     if (ret)
2546         return ret;
2547 
2548     if ((ret = open_files_devices(op)))
2549         return ret;
2550 
2551     block_size_bpt_check(op);
2552     sparse_sparing_check(op);
2553 
2554     if ((ret = count_calculate(op))) {
2555         if (op->verbose)
2556             pr2serr("count_calculate() returned %d, exit\n", ret);
2557         goto cleanup;
2558     }
2559 
2560     if ((ret = prepare_pi(op)))
2561         goto cleanup;
2562 
2563     if ((op->dd_count < 0) && (! op->reading_fifo)) {
2564         pr2serr("Couldn't calculate count, please give one\n");
2565         ret = SG_LIB_CAT_OTHER;
2566         goto cleanup;
2567     }
2568 
2569     cdb_size_prealloc(op);
2570 
2571     if ((ret = wrk_buffers_init(op)))
2572         goto cleanup;
2573 
2574     if (op->verbose)
2575         details_pre_copy_print(op);
2576 
2577     op->read1_or_transfer = !! (FT_DEV_NULL & op->odip->d_type);
2578     op->dd_count_start = op->dd_count;
2579     if (op->read1_or_transfer && (! op->outf_given) &&
2580         ((op->dd_count > 0) || op->reading_fifo))
2581         pr2serr("Output file not specified so no copy, just reading input\n");
2582 
2583     if (op->do_time)
2584         calc_duration_init(op);
2585 
2586     if (op->iflagp->errblk)
2587         errblk_open(op);
2588 
2589 #ifdef SG_LIB_LINUX
2590     if ((FT_TAPE & op->idip->d_type) || (FT_TAPE & op->odip->d_type))
2591         print_tape_pos("Initial ", "", op);
2592 #endif
2593 
2594     if (op->oflagp->prealloc) {
2595         if ((ret = do_falloc(op)))
2596             goto cleanup;
2597     }
2598 
2599     ++started_copy;
2600     if (op->has_xcopy)
2601         ret = do_xcopy_lid1(op);
2602     else
2603         ret = do_rw_copy(op);
2604 
2605     if (0 == op->status_none)
2606         print_stats("", op, 0);
2607 
2608     if ((op->oflagp->ssync) && (FT_PT & op->odip->d_type)) {
2609         if (0 == op->status_none)
2610             pr2serr(">> SCSI synchronizing cache on %s\n", op->odip->fn);
2611         pt_sync_cache(op->odip->fd);
2612     }
2613     if (op->do_time)
2614         calc_duration_throughput("", 0, op);
2615 
2616     if (op->sum_of_resids)
2617         pr2serr(">> Non-zero sum of residual counts=%d\n", op->sum_of_resids);
2618 
2619 cleanup:
2620     cleanup_resources(op);
2621     if ((0 == ret) && op->err_to_report)
2622         ret = op->err_to_report;
2623     if (started_copy && (0 != op->dd_count) && (! op->reading_fifo)) {
2624         if (0 == ret)
2625             pr2serr("Early termination, EOF on input?\n");
2626         else if (ret > 0)
2627             print_exit_status_msg("Early termination", ret, 1);
2628         else {
2629             if (op->verbose < 2)
2630                 pr2serr("Early termination: some error occurred; try again "
2631                         "with '-vv'\n");
2632             else
2633                 pr2serr("Early termination: some error occurred\n");
2634         }
2635     }
2636     return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
2637 }
2638