diff --git a/cpp/scsidump/scsidump_core.cpp b/cpp/scsidump/scsidump_core.cpp index 92d2e1ce67..0d20757294 100644 --- a/cpp/scsidump/scsidump_core.cpp +++ b/cpp/scsidump/scsidump_core.cpp @@ -93,7 +93,7 @@ void ScsiDump::ParseArguments(span args) int buffer_size = DEFAULT_BUFFER_SIZE; opterr = 0; - while ((opt = getopt(static_cast(args.size()), args.data(), "i:f:s:t:rvpIS")) != -1) { + while ((opt = getopt(static_cast(args.size()), args.data(), "i:f:o:s:t:rvpIS")) != -1) { switch (opt) { case 'i': if (!GetAsUnsignedInt(optarg, initiator_id) || initiator_id > 7) { @@ -116,6 +116,10 @@ void ScsiDump::ParseArguments(span args) break; + case 'o': + start_sector = static_cast(strtoull(optarg, NULL, 0)); + break; + case 'S': scan_bus = true; break; @@ -549,8 +553,18 @@ int ScsiDump::DumpRestore() return EXIT_FAILURE; } + // Dump by buffer size + auto dsiz = static_cast(buffer.size()); + const int duni = dsiz / inq_info.sector_size; + auto dnum = static_cast((inq_info.capacity * inq_info.sector_size) / dsiz); + + // Verify start sector. + if (start_sector % duni != 0) { + throw parser_exception("Start sector must be a multiple of " + to_string(duni) + " (= bufsize / sectsize)"); + } + fstream fs; - fs.open(filename, (restore ? ios::in : ios::out) | ios::binary); + fs.open(filename, (restore ? ios::in : ios::out) | ios::binary | ios::app); if (fs.fail()) { throw parser_exception("Can't open image file '" + filename + "'"); @@ -573,19 +587,16 @@ int ScsiDump::DumpRestore() } else if (size < (off_t)(inq_info.sector_size * inq_info.capacity)) { throw parser_exception("File size is smaller than disk size"); } + fs.seekg(start_sector * inq_info.sector_size); } else { + fs.seekp(start_sector * inq_info.sector_size); cout << "Starting dump\n" << flush; } - // Dump by buffer size - auto dsiz = static_cast(buffer.size()); - const int duni = dsiz / inq_info.sector_size; - auto dnum = static_cast((inq_info.capacity * inq_info.sector_size) / dsiz); - const auto start_time = chrono::high_resolution_clock::now(); int i; - for (i = 0; i < dnum; i++) { + for (i = start_sector / duni; i < dnum; i++) { if (restore) { fs.read((char*)buffer.data(), dsiz); Write10(i * duni, duni, dsiz); diff --git a/cpp/scsidump/scsidump_core.h b/cpp/scsidump/scsidump_core.h index 58feb41915..8bf07449a6 100644 --- a/cpp/scsidump/scsidump_core.h +++ b/cpp/scsidump/scsidump_core.h @@ -87,6 +87,8 @@ class ScsiDump string filename; + uint64_t start_sector = 0; + bool inquiry = false; bool scan_bus = false; diff --git a/doc/scsidump.1 b/doc/scsidump.1 index 7fb7f3fc22..0cf806795e 100644 --- a/doc/scsidump.1 +++ b/doc/scsidump.1 @@ -33,6 +33,8 @@ If the generated drive image is intended to be used with PiSCSI, the drive image Display INQUIRY data of ID[:LUN]. .It Fl i Ar BID SCSI ID of the PiSCSI device. If not specified, the PiSCSI device will use ID 7. The PiSCSI host will be functioning as the "Initiator" device. +.It Fl o Ar offs +Use `offs` as the sector offset to start dumping. It must be aligned to the buffer size. Can be used to resume an aborted transfer from/to a somewhat broken device by specifying the last shown sector number. .It Fl f Ar FILE Path to the dump file. .It Fl p @@ -52,12 +54,12 @@ Enable verbose logging. Dump Mode: [SCSI Drive] ---> [PiSCSI host] .Pp Launch scsidump to dump an all data from SCSI ID 3 with block size 64 KiB, store it to the local filesystem as a drive image named outimage.hda, and generate the outimage.hda.properties file with the drive's INQUIRY information: -.Dl Nm scsidump Fl t 3 Fl f ./outimage.hda Fl s 65536 Fl p +.Dl Nm scsidump -t 3 -f ./outimage.hda -s 65536 -p .Pp Restore Mode: [PiSCSI host] ---> [SCSI Drive] .Pp Launch scsidump to restore/upload a drive image from the local file system to SCSI ID 0 with block size 1MiB: -.Dl Nm scsidump Fl r Fl t 0 Fl f ./outimage.hda Fl s 1048576 +.Dl Nm scsidump -r -t 0 -f ./outimage.hda -s 1048576 .Sh SEE ALSO .Xr scsictl 1 , .Xr piscsi 1 ,