home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AMIGA PD 1
/
AMIGA-PD-1.iso
/
NetBSD
/
Tools
/
dcp1.1.lha
/
dcp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-14
|
15KB
|
555 lines
/*
* File/Device copier by Chris Hooper (cdh@mtu.edu) on 5-Jul-93 v1.0
* 14-Oct-93 v1.1
*
* This program can copy files to devices and devices to files, etc.
*
* Usage:
* dcp {source} {dest} [-m number of blocks] [-b buffer size] [-v verbose]
* [-ss source start block] [-ds dest start block]
* [-d dryrun] [-h help]
*
* This product is distributed as freeware with no warrantees expressed or
* implied. There are no restrictions on distribution or application of
* this program other than it may not be used in contribution with or
* converted to an application under the terms of the GNU Public License
* nor sold for profit greater than the cost of distribution. Also, this
* notice must accompany all redistributions and/or modifications of this
* program. Remember: If you expect bugs, you should not be disappointed.
*
*/
#include <stdio.h>
#include <exec/types.h>
#include <devices/trackdisk.h>
#include <libraries/dos.h>
#include <dos/dosextens.h>
#include <dos/filehandler.h>
#include <exec/io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <exec/memory.h>
/* #define DEBUG(x) fprintf(stderr, x) */
/* Possible file types
* tNONE 0 = Could not be opened
* tDEVICE 1 = Block device opened
* tFILE 2 = Regular AmigaDOS file opened
* tSTDIO 3 = STDIO channel specified
*/
#define tNONE 0
#define tDEVICE 1
#define tFILE 2
#define tSTDIO 3
#define dREAD 0
#define dWRITE 1
/* BCPL conversion functions */
#define BTOC(x) ((x)<<2)
#define CTOB(x) ((x)>>2)
/* quick parameter parser */
#define ACCEPT(x,y) \
if (!strcmp(argv[index], y)) { \
index++; \
if (index < argc) { \
x = atoi(argv[index]); \
if (x < 1) { \
fprintf(stderr, "number required for %s parameter\n", y); \
exit(1); \
} \
} else { \
fprintf(stderr, "number required for %s parameter\n", y); \
exit(1); \
} \
}
char *strchr();
struct FileSysStartupMsg *find_startup();
struct file_info {
char *name; /* filename as specified on cmdline */
int dtype; /* NONE, DEVICE, FILE, or STDIO */
FILE *strIO; /* stream file pointer */
struct IOExtTD *trackIO; /* device packet pointer */
ULONG currentblk; /* current read/write block in device/file */
ULONG maxblk; /* maximum allowed read/write blk in dev/file */
};
struct file_info in; /* internal input file descriptor */
struct file_info out; /* internal output file descriptor */
char *progname; /* name of this program running */
char iobuf[128]; /* buffer for line-oriented I/O */
char *version = "1.1"; /* program revision */
char *revdate = "14-Oct-93"; /* program revision date */
int last_read_blocks; /* number of blocks last read */
char *buffer = NULL; /* buffer area for copy operations */
int buffer_blocks = 2000; /* size of buffer area */
int verbose = 0; /* verbose mode - default = off */
int dryrun = 0; /* dryrun mode - default = off */
ULONG maxblk = 0; /* maximum block - default = none */
ULONG source_start = 0; /* src start blk - default = zero */
ULONG dest_start = 0; /* dst start blk - default = zero */
main(argc, argv)
int argc;
char *argv[];
{
int names = 0;
int index;
progname = argv[0];
setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf));
if (argc == 1)
print_usage();
for (index = 1; index < argc; index++) {
ACCEPT(maxblk, "-m")
else ACCEPT(buffer_blocks, "-b")
else ACCEPT(source_start, "-ss")
else ACCEPT(dest_start, "-sd")
else ACCEPT(dest_start, "-ds")
else if (!strcmp(argv[index], "-v"))
verbose++;
else if (!strcmp(argv[index], "-h"))
print_help();
else if (!strcmp(argv[index], "-d"))
dryrun++;
else {
names++;
if (names == 1)
in.name = argv[index];
else if (names == 2)
out.name = argv[index];
else {
fprintf(stderr, "unknown parameter %s\n", argv[index]);
exit(1);
}
}
}
if (names != 2) {
printf("Source and destination are required for %s\n", progname);
exit(1);
}
if (maxblk && (buffer_blocks > maxblk))
buffer_blocks = maxblk;
while ((buffer == NULL) && (buffer_blocks)) {
buffer = (char *) AllocMem(buffer_blocks *
TD_SECTOR, MEMF_PUBLIC);
if (buffer == NULL)
buffer_blocks >>= 1;
}
if (buffer == NULL) {
fprintf(stderr, "Unable to allocate even 1 block for copy buffer!\n");
exit(1);
}
do_open(&in, dREAD);
do_open(&out, dWRITE);
set_limits(&in, &out);
if ((in.dtype != tNONE) && (out.dtype != tNONE))
while (do_io(&in, dREAD))
if (do_io(&out, dWRITE) == 0)
break;
if (verbose)
fprintf(stderr, "\n");
do_close(&in);
do_close(&out);
FreeMem(buffer, buffer_blocks * TD_SECTOR);
exit(0);
}
do_open(fdes, dtype)
struct file_info *fdes;
int dtype;
{
int len;
char *pos;
fdes->currentblk = 0; /* start at beginning */
fdes->maxblk = 0; /* no maximum block */
if (verbose)
if (dtype == dREAD)
fprintf(stderr, "R ");
else
fprintf(stderr, "W ");
if (!strcmp(fdes->name, "-")) { /* stdio */
fdes->dtype = tSTDIO;
if (dtype == dREAD)
fdes->strIO = stdin;
else
fdes->strIO = stdout;
if (verbose)
fprintf(stderr, "STDIO %s\n", fdes->name);
return;
}
len = strlen(fdes->name);
if (len == 0) {
fprintf(stderr, "Error opening file for %s.\n",
(dtype == dREAD) ? "read" : "write");
return;
}
pos = strchr(fdes->name, ',');
if (!pos && (fdes->name[len - 1] != ':')) { /* must be a file */
if (dtype == dREAD) {
struct stat stat_buf;
if (!stat(fdes->name, &stat_buf))
fdes->maxblk = (stat_buf.st_size + TD_SECTOR - 1) / TD_SECTOR;
}
if (!dryrun)
fdes->strIO = fopen(fdes->name, (dtype == dREAD) ? "r" : "w");
if ((fdes->strIO == NULL) && !dryrun) {
fprintf(stderr, "Error opening file %s for %s.\n",
fdes->name, (dtype == dREAD) ? "read" : "write");
fdes->dtype = tNONE;
} else {
fdes->dtype = tFILE;
if (verbose) {
fprintf(stderr, "file %-40s", fdes->name);
fprintf(stderr, "start=%-7d ", fdes->currentblk);
fprintf(stderr, "end=%-7d\n", fdes->maxblk);
}
}
} else { /* must be a device */
struct FileSysStartupMsg *startup;
struct DosEnvec *envec;
char *disk_device;
int disk_unit, disk_flags;
if (!(fdes->trackIO = (struct IOExtTD *)
CreateExtIO(CreatePort(0, 0), sizeof(struct IOExtTD)) )) {
fprintf(stderr, "Failed to create trackIO structure for %s.\n", fdes->name);
return;
}
if (pos) {
char *pos2;
disk_device = fdes->name;
disk_flags = 0;
*pos = '\0';
if (isdigit(pos + 1)) {
disk_unit = atoi(pos + 1);
pos2 = strchr(pos + 1, ",");
if (pos2)
disk_flags = atoi(pos2 + 1);
} else {
fprintf(stderr, "Error opening device %s for %s; you must specify a unit number!\n",
fdes->name, (dtype == dREAD) ? "read" : "write");
fdes->dtype = tNONE;
return;
}
fdes->currentblk = 0;
fdes->maxblk = 0;
} else {
startup = find_startup(fdes->name);
if (startup == NULL) {
fprintf(stderr, "Error opening device %s for %s; does not exist\n",
fdes->name, (dtype == dREAD) ? "read" : "write");
fdes->dtype = tNONE;
return;
}
disk_device = ((char *) BTOC(startup->fssm_Device)) + 1;
disk_unit = startup->fssm_Unit;
disk_flags = startup->fssm_Flags;
envec = (struct DosEnvec *) BTOC(startup->fssm_Environ);
fdes->currentblk = envec->de_LowCyl * envec->de_Surfaces *
envec->de_BlocksPerTrack;
fdes->maxblk = envec->de_HighCyl * envec->de_Surfaces *
envec->de_BlocksPerTrack;
}
if (verbose) {
char buf[40];
sprintf(buf, "%s=%s", fdes->name, disk_device);
fprintf(stderr, "dev %-21s ", buf);
fprintf(stderr, "unit=%-2d ", disk_unit);
fprintf(stderr, "flag=%-2d ", disk_flags);
fprintf(stderr, "start=%-7d ", fdes->currentblk);
fprintf(stderr, "end=%-7d\n", fdes->maxblk);
}
if (OpenDevice(disk_device, disk_unit, fdes->trackIO, disk_flags)) {
fprintf(stderr, "fatal: Unable to open %s unit %d for %s.\n",
disk_device, disk_unit, fdes->name);
DeletePort(fdes->trackIO->iotd_Req.io_Message.mn_ReplyPort);
DeleteExtIO(fdes->trackIO);
return;
}
fdes->trackIO->iotd_Req.io_Command = (dtype == dREAD) ?
CMD_READ : CMD_WRITE;
fdes->trackIO->iotd_Req.io_Data = buffer;
fdes->dtype = tDEVICE;
if (pos)
*pos = ',';
}
}
set_limits(in, out)
struct file_info *in;
struct file_info *out;
{
if (maxblk) {
if (in->maxblk > maxblk)
in->maxblk = maxblk;
if (out->maxblk > maxblk)
out->maxblk = maxblk;
}
if (source_start)
in->currentblk += source_start;
if (dest_start)
out->currentblk += dest_start;
if (in->maxblk && (in->currentblk > in->maxblk))
in->dtype = tNONE;
if (out->maxblk && (out->currentblk > out->maxblk))
out->dtype = tNONE;
if (!dryrun && (in->dtype == tFILE) && (in->dtype != tNONE))
fseek(in->strIO, in->currentblk * TD_SECTOR, SEEK_SET);
if (!dryrun && (out->dtype == tFILE) && (out->dtype != tNONE))
fseek(out->strIO, out->currentblk * TD_SECTOR, SEEK_SET);
}
struct FileSysStartupMsg *find_startup(name)
char *name;
{
struct DosLibrary *DosBase;
struct RootNode *rootnode;
struct DosInfo *dosinfo;
struct DevInfo *devinfo;
struct DosEnvec *envec;
static struct FileSysStartupMsg *startup;
char *devname;
char *pos;
int notfound = 1;
if ((pos = strchr(name, ':')) != NULL)
*pos = '\0';
DosBase = (struct DosLibrary *) OpenLibrary("dos.library", 0L);
rootnode= DosBase->dl_Root;
dosinfo = (struct DosInfo *) BTOC(rootnode->rn_Info);
devinfo = (struct DevInfo *) BTOC(dosinfo->di_DevInfo);
while (devinfo != NULL) {
devname = (char *) BTOC(devinfo->dvi_Name);
if (unstrcmp(devname + 1, name)) {
notfound = 0;
break;
}
devinfo = (struct DevInfo *) BTOC(devinfo->dvi_Next);
}
if (notfound) {
fprintf(stderr, "%s: is not mounted.\n", name);
exit(1);
}
startup = (struct FileSysStartupMsg *) BTOC(devinfo->dvi_Startup);
CloseLibrary(DosBase);
return(startup);
}
/* unsigned string compare */
int unstrcmp(str1, str2)
char *str1;
char *str2;
{
while (*str1 != '\0') {
if (*str2 == '\0')
break;
else if (*str1 != *str2)
if ((*str1 >= 'A') && (*str1 <= 'Z')) {
if ((*str2 >= 'A') && (*str2 <= 'Z'))
break;
else if (*str1 != *str2 + 'A' - 'a')
break;
} else {
if ((*str2 >= 'a') && (*str2 <= 'a'))
break;
else if (*str1 != *str2 - 'A' + 'a')
break;
}
str1++;
str2++;
}
if (*str1 == *str2)
return(1);
else
return(0);
}
do_close(fdes)
struct file_info *fdes;
{
if (fdes->dtype == tSTDIO)
return;
else if (fdes->dtype == tFILE) {
if (!dryrun)
fclose(fdes->strIO);
} else if (fdes->dtype == tDEVICE)
if (fdes->trackIO != NULL) {
CloseDevice(fdes->trackIO);
DeletePort(fdes->trackIO->iotd_Req.io_Message.mn_ReplyPort);
DeleteExtIO(fdes->trackIO);
}
}
do_io(fdes, dtype)
struct file_info *fdes;
int dtype;
{
int io_left = 0;
int last_write_blks;
if (dtype == dREAD) {
io_left = buffer_blocks;
if (fdes->maxblk)
if ((fdes->maxblk - fdes->currentblk) < io_left)
io_left = fdes->maxblk - fdes->currentblk;
#ifdef DEBUG
fprintf(stderr, "tran=R blocks=%d cur=%d max=%d left=%d\n",
buffer_blocks, fdes->currentblk, fdes->maxblk, io_left);
#endif
if (io_left < 1)
return(0);
} else {
io_left = last_read_blocks;
if (fdes->maxblk)
if ((fdes->maxblk - fdes->currentblk) < io_left)
io_left = fdes->maxblk - fdes->currentblk;
#ifdef DEBUG
fprintf(stderr, "tran=W blocks=%d cur=%d max=%d left=%d\n",
buffer_blocks, fdes->currentblk, fdes->maxblk, io_left);
#endif
if (io_left < 1)
return(0);
}
if (verbose) {
setvbuf(stderr, NULL, _IONBF, 0);
fprintf(stderr, "%s at %-7d count=%d%5s\r",
(dtype == dREAD) ? "Read " : "Write",
fdes->currentblk, io_left, "");
#ifdef DEBUG
fprintf(stderr, "\n");
#endif
setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf));
}
if ((fdes->dtype == tDEVICE) && !dryrun) {
fdes->trackIO->iotd_Req.io_Length = io_left * TD_SECTOR;
fdes->trackIO->iotd_Req.io_Offset = fdes->currentblk * TD_SECTOR;
DoIO(fdes->trackIO);
if (dtype == dREAD)
last_read_blocks = io_left;
} else if (!dryrun) { /* Must be either file or stdio */
if (dtype == dREAD)
last_read_blocks = fread(buffer, TD_SECTOR, io_left, fdes->strIO);
else if ((last_write_blks = fwrite(buffer, TD_SECTOR, io_left,
fdes->strIO)) != io_left) {
if (last_write_blks >= 0)
fprintf(stderr, "destination full before source exhausted.\n");
else
fprintf(stderr, "failure: write did not finish normally\n");
return(0);
}
} else if (dtype == dREAD)
last_read_blocks = io_left;
fdes->currentblk += io_left;
return(1);
}
print_usage()
{
int len;
setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf));
len = strlen(progname) + 9;
fprintf(stderr, "%s %s by Chris Hooper on %s\n",
progname, version, revdate);
fprintf(stderr, "Usage: %s [options] {source} {dest}\n", progname);
fprintf(stderr, "%*s -b = specify buffer size\n", len, "");
fprintf(stderr, "%*s -m = specify maximum blocks to transfer\n", len, "");
fprintf(stderr, "%*s-ss = specify source block number at which to start\n", len, "");
fprintf(stderr, "%*s-ds = specify destination block number at which to start\n", len, "");
fprintf(stderr, "%*s -v = turn on verbose mode\n", len, "");
fprintf(stderr, "%*s -h = give more help\n", len, "");
exit(1);
}
print_help()
{
setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf));
fprintf(stderr, "%s is a program which will does block copies from the specified source\n", progname);
fprintf(stderr, "to the specified destination. The source and destination may each\n");
fprintf(stderr, "independently be either a file or a block device.\n");
fprintf(stderr, "\n");
fprintf(stderr, "The source and destination are specified as filenames. A device is\n");
fprintf(stderr, "differentiated from a file as having a colon (:) as the last character\n");
fprintf(stderr, "of the filename. A device may also be specified by giving the Amiga\n");
fprintf(stderr, "device information, separated by commas (,). The source is always\n");
fprintf(stderr, "specified first. WARNING: A comma makes it a device!");
fprintf(stderr, "\n");
fprintf(stderr, "Examples of usage:\n");
fprintf(stderr, "\n");
fprintf(stderr, "Copy file \"unix_fs\" from dh0: and overwrite df0: with that file\n");
fprintf(stderr, "\t%s dh0:unix_fs df0:\n", progname);
fprintf(stderr, "\n");
fprintf(stderr, "Copy 8192 blocks from raw SCSI disk, unit 6 starting at block 16384\n");
fprintf(stderr, "and write that to file \"junk\" in current directory\n");
fprintf(stderr, "\t%s -ss 16384 -m 8192 scsi.device,6 junk\n", progname);
fprintf(stderr, "\n");
fprintf(stderr, "Copy partition BSDR: to a file \"BSD_root\"\n");
fprintf(stderr, "\t%s bsdr: BSD_root\n", progname);
fprintf(stderr, "\n");
fprintf(stderr, "Copy first five blocks from partition BAK: to block 1532 in partition TEST:\n");
fprintf(stderr, "\t%s -m 5 -ds 1532 BAK: Test:\n", progname);
exit(1);
}