1 /*  Copyright 1999-2003,2007,2009 Alain Knaff.
2  *  This file is part of mtools.
3  *
4  *  Mtools is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Mtools is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * mcat.c
18  * Same thing as cat /dev/fd0 or cat file >/dev/fd0
19  * Something, that isn't possible with floppyd anymore.
20  */
21 
22 #include "sysincludes.h"
23 #include "msdos.h"
24 #include "mtools.h"
25 #include "mainloop.h"
26 #include "fsP.h"
27 #include "xdf_io.h"
28 #include "floppyd_io.h"
29 #include "plain_io.h"
30 
31 static void usage(void) NORETURN;
usage(void)32 static void usage(void)
33 {
34 	fprintf(stderr, "Mtools version %s, dated %s\n",
35 		mversion, mdate);
36 	fprintf(stderr, "Usage: mcat [-V] [-w] device\n");
37 	fprintf(stderr, "       -w write on device else read\n");
38 	exit(1);
39 }
40 
41 #ifdef __CYGWIN__
42 #define BUF_SIZE 512u
43 #else
44 #define BUF_SIZE 16000u
45 #endif
46 
bufLen(size_t blocksize,mt_size_t totalSize,mt_off_t address)47 static size_t bufLen(size_t blocksize, mt_size_t totalSize, mt_off_t address)
48 {
49 	if(totalSize == 0)
50 		return blocksize;
51 	if(address + blocksize > totalSize)
52 		return totalSize - address;
53 	return blocksize;
54 }
55 
56 void mcat(int argc, char **argv, int type UNUSEDP) NORETURN;
mcat(int argc,char ** argv,int type UNUSEDP)57 void mcat(int argc, char **argv, int type UNUSEDP)
58 {
59 	struct device *dev;
60 	struct device out_dev;
61 	char drive, name[EXPAND_BUF];
62         char errmsg[200];
63         Stream_t *Stream;
64 	char buf[BUF_SIZE];
65 
66 	mt_off_t address = 0;
67 
68 	char mode = O_RDONLY;
69 	int optindex = 1;
70 	size_t len;
71 
72 	noPrivileges = 1;
73 
74 	if (argc < 2) {
75 		usage();
76 	}
77 
78 	if (argv[1][0] == '-') {
79 		if (argv[1][1] != 'w') {
80 			usage();
81 		}
82 		mode = O_WRONLY;
83 		optindex++;
84 	}
85 
86 	if (argc - optindex < 1)
87 		usage();
88 
89 
90 	if (!argv[optindex][0] || argv[optindex][1] != ':'
91 	    || argv[optindex][2]) {
92 		usage();
93 	}
94 
95         drive = ch_toupper(argv[optindex][0]);
96 
97         /* check out a drive whose letter and parameters match */
98         sprintf(errmsg, "Drive '%c:' not supported", drive);
99         Stream = NULL;
100         for (dev=devices; dev->name; dev++) {
101                 FREE(&Stream);
102                 if (dev->drive != drive)
103                         continue;
104                 out_dev = *dev;
105                 expand(dev->name,name);
106 #ifdef USING_NEW_VOLD
107                 strcpy(name, getVoldName(dev, name));
108 #endif
109 
110                 Stream = 0;
111 #ifdef USE_XDF
112                 Stream = XdfOpen(&out_dev, name, mode, errmsg, 0);
113 				if(Stream)
114                         out_dev.use_2m = 0x7f;
115 
116 #endif
117 
118 #ifdef USE_FLOPPYD
119                 if(!Stream)
120                         Stream = FloppydOpen(&out_dev, name,
121 					     mode, errmsg, NULL);
122 #endif
123 
124 
125                 if (!Stream)
126                         Stream = SimpleFileOpen(&out_dev, dev, name, mode,
127 						errmsg, 0, 1, 0);
128 
129                 if( !Stream)
130                         continue;
131                 break;
132         }
133 
134         /* print error msg if needed */
135         if ( dev->drive == 0 ){
136                 FREE(&Stream);
137                 fprintf(stderr,"%s\n",errmsg);
138                 exit(1);
139         }
140 
141 
142 	if (mode == O_WRONLY) {
143 		mt_size_t size=0;
144 		size = out_dev.sectors * out_dev.heads * out_dev.tracks;
145 		size *= 512;
146 		while ((len = fread(buf, 1,
147 				    bufLen(BUF_SIZE, size, address),
148 				    stdin)) > 0) {
149 			int r = WRITES(Stream, buf, address, len);
150 			fprintf(stderr, "Wrote to %d\n", (int) address);
151 			if(r < 0)
152 				break;
153 			address += len;
154 		}
155 	} else {
156 		while ((len = READS(Stream, buf, address, BUF_SIZE)) > 0) {
157 			fwrite(buf, 1, len, stdout);
158 			address += len;
159 		}
160 	}
161 
162 	FREE(&Stream);
163 	exit(0);
164 }
165