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 "open_image.h"
27
28 static void usage(void) NORETURN;
usage(void)29 static void usage(void)
30 {
31 fprintf(stderr, "Mtools version %s, dated %s\n",
32 mversion, mdate);
33 fprintf(stderr, "Usage: mcat [-V] [-w] device\n");
34 fprintf(stderr, " -w write on device else read\n");
35 exit(1);
36 }
37
38 #ifdef __CYGWIN__
39 #define BUF_SIZE 512u
40 #else
41 #define BUF_SIZE 16000u
42 #endif
43
bufLen(size_t blocksize,mt_off_t totalSize,mt_off_t address)44 static size_t bufLen(size_t blocksize, mt_off_t totalSize, mt_off_t address)
45 {
46 if(totalSize == 0)
47 return blocksize;
48 if((mt_off_t) blocksize > totalSize - address)
49 return (size_t) (totalSize - address);
50 return blocksize;
51 }
52
53 void mcat(int argc, char **argv, int type UNUSEDP) NORETURN;
mcat(int argc,char ** argv,int type UNUSEDP)54 void mcat(int argc, char **argv, int type UNUSEDP)
55 {
56 struct device *dev;
57 struct device out_dev;
58 char drive, name[EXPAND_BUF];
59 char errmsg[200];
60 Stream_t *Stream;
61 char buf[BUF_SIZE];
62
63 mt_off_t address = 0;
64 mt_off_t maxSize = 0;
65
66 char mode = O_RDONLY;
67 int c;
68
69 noPrivileges = 1;
70
71 if (argc < 2) {
72 usage();
73 }
74
75 while ((c = getopt(argc,argv, "wi:"))!= EOF) {
76 switch (c) {
77 case 'w':
78 mode = O_WRONLY;
79 break;
80 case 'i':
81 set_cmd_line_image(optarg);
82 break;
83 default:
84 usage();
85 }
86 }
87
88 if (argc - optind > 1)
89 usage();
90 if(argc - optind == 1) {
91 if(!argv[optind][0] || argv[optind][1] != ':')
92 usage();
93 drive = ch_toupper(argv[argc -1][0]);
94 } else {
95 drive = get_default_drive();
96 }
97
98 /* check out a drive whose letter and parameters match */
99 sprintf(errmsg, "Drive '%c:' not supported", drive);
100 Stream = NULL;
101 for (dev=devices; dev->name; dev++) {
102 FREE(&Stream);
103 if (dev->drive != drive)
104 continue;
105 out_dev = *dev;
106 expand(dev->name,name);
107 #ifdef USING_NEW_VOLD
108 strcpy(name, getVoldName(dev, name));
109 #endif
110
111 Stream = OpenImage(&out_dev, dev, name, mode,
112 errmsg, ALWAYS_GET_GEOMETRY, mode, &maxSize,
113 NULL, NULL);
114 if( !Stream)
115 continue;
116 break;
117 }
118
119 /* print error msg if needed */
120 if ( dev->drive == 0 )
121 goto exit_1;
122
123 if (mode == O_WRONLY) {
124 size_t len;
125 mt_off_t size=0;
126 if(chs_to_totsectors(&out_dev, errmsg) < 0 ||
127 check_if_sectors_fit(out_dev.tot_sectors,
128 maxSize, 512, errmsg))
129 goto exit_1;
130 size = 512 * (mt_off_t) out_dev.tot_sectors;
131 while ((len = fread(buf, 1,
132 bufLen(BUF_SIZE, size, address),
133 stdin)) > 0) {
134 ssize_t r = PWRITES(Stream, buf, address, len);
135 fprintf(stderr, "Wrote to %d\n", (int) address);
136 if(r < 0)
137 break;
138 address += len;
139 }
140 } else {
141 ssize_t len;
142 while ((len = PREADS(Stream, buf, address, BUF_SIZE)) > 0) {
143 fwrite(buf, 1, (size_t) len, stdout);
144 address += (size_t) len;
145 }
146 }
147
148 FREE(&Stream);
149 exit(0);
150 exit_1:
151 FREE(&Stream);
152 fprintf(stderr,"%s\n",errmsg);
153 exit(1);
154 }
155