xref: /aosp_15_r20/external/mtools/mcat.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
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