xref: /minix3/minix/commands/dosread/dosread.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* dos{dir|read|write} - {list|read|write} MS-DOS disks	 Author: M. Huisjes */
2*433d6423SLionel Sambuc 
3*433d6423SLionel Sambuc /* Dosdir - list MS-DOS directories. doswrite - write stdin to DOS-file
4*433d6423SLionel Sambuc  * dosread - read DOS-file to stdout
5*433d6423SLionel Sambuc  *
6*433d6423SLionel Sambuc  * Author: Michiel Huisjes.
7*433d6423SLionel Sambuc  *
8*433d6423SLionel Sambuc  * Usage: dos... [-lra] drive [file/dir]
9*433d6423SLionel Sambuc  *	  l: Give long listing.
10*433d6423SLionel Sambuc  *	  r: List recursively.
11*433d6423SLionel Sambuc  *	  a: Set ASCII bit.
12*433d6423SLionel Sambuc  */
13*433d6423SLionel Sambuc 
14*433d6423SLionel Sambuc #include <assert.h>
15*433d6423SLionel Sambuc #include <ctype.h>
16*433d6423SLionel Sambuc #include <errno.h>
17*433d6423SLionel Sambuc #include <limits.h>
18*433d6423SLionel Sambuc #include <sys/types.h>
19*433d6423SLionel Sambuc #include <sys/stat.h>
20*433d6423SLionel Sambuc #include <fcntl.h>
21*433d6423SLionel Sambuc #include <stdlib.h>
22*433d6423SLionel Sambuc #include <stdio.h>
23*433d6423SLionel Sambuc #include <string.h>
24*433d6423SLionel Sambuc #include <time.h>
25*433d6423SLionel Sambuc #include <sys/times.h>
26*433d6423SLionel Sambuc #include <unistd.h>
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc 
29*433d6423SLionel Sambuc #define MAX_CLUSTER_SIZE	4096
30*433d6423SLionel Sambuc #define MAX_ROOT_ENTRIES	512
31*433d6423SLionel Sambuc #define FAT_START		512L	/* After bootsector */
32*433d6423SLionel Sambuc #define ROOTADDR		(FAT_START + 2L * fat_size)
33*433d6423SLionel Sambuc #define clus_add(cl_no)		((long) (((long) cl_no - 2L) \
34*433d6423SLionel Sambuc 				 * (long) cluster_size \
35*433d6423SLionel Sambuc 				 + data_start \
36*433d6423SLionel Sambuc 			        ))
37*433d6423SLionel Sambuc struct dir_entry {
38*433d6423SLionel Sambuc   unsigned char d_name[8];
39*433d6423SLionel Sambuc   unsigned char d_ext[3];
40*433d6423SLionel Sambuc   unsigned char d_attribute;
41*433d6423SLionel Sambuc   unsigned char d_reserved[10];
42*433d6423SLionel Sambuc   unsigned short d_time;
43*433d6423SLionel Sambuc   unsigned short d_date;
44*433d6423SLionel Sambuc   unsigned short d_cluster;
45*433d6423SLionel Sambuc   unsigned long d_size;
46*433d6423SLionel Sambuc };
47*433d6423SLionel Sambuc 
48*433d6423SLionel Sambuc typedef struct dir_entry DIRECTORY;
49*433d6423SLionel Sambuc 
50*433d6423SLionel Sambuc #define NOT_USED	0x00
51*433d6423SLionel Sambuc #define ERASED		0xE5
52*433d6423SLionel Sambuc #define DIR		0x2E
53*433d6423SLionel Sambuc #define DIR_SIZE	(sizeof (struct dir_entry))
54*433d6423SLionel Sambuc #define SUB_DIR		0x10
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc #define LAST_CLUSTER12	0xFFF
57*433d6423SLionel Sambuc #define LAST_CLUSTER	0xFFFF
58*433d6423SLionel Sambuc #define FREE		0x000
59*433d6423SLionel Sambuc #define BAD		0xFF0
60*433d6423SLionel Sambuc #define BAD16		0xFFF0
61*433d6423SLionel Sambuc 
62*433d6423SLionel Sambuc typedef int BOOL;
63*433d6423SLionel Sambuc 
64*433d6423SLionel Sambuc #define TRUE	1
65*433d6423SLionel Sambuc #define FALSE	0
66*433d6423SLionel Sambuc 
67*433d6423SLionel Sambuc #define DOS_TIME	315532800L	/* 1970 - 1980 */
68*433d6423SLionel Sambuc 
69*433d6423SLionel Sambuc #define READ			0
70*433d6423SLionel Sambuc #define WRITE			1
71*433d6423SLionel Sambuc 
72*433d6423SLionel Sambuc #define FIND	3
73*433d6423SLionel Sambuc #define LABEL	4
74*433d6423SLionel Sambuc #define ENTRY	5
75*433d6423SLionel Sambuc #define find_entry(d, e, p)	directory(d, e, FIND, p)
76*433d6423SLionel Sambuc #define list_dir(d, e, f)	(void) directory(d, e, f, NULL)
77*433d6423SLionel Sambuc #define label()			directory(root, root_entries, LABEL, NULL)
78*433d6423SLionel Sambuc #define new_entry(d, e)		directory(d, e, ENTRY, NULL)
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc #define is_dir(d)		((d)->d_attribute & SUB_DIR)
81*433d6423SLionel Sambuc 
82*433d6423SLionel Sambuc #define STD_OUT			1
83*433d6423SLionel Sambuc 
84*433d6423SLionel Sambuc char	*cmnd;
85*433d6423SLionel Sambuc 
86*433d6423SLionel Sambuc static int disk;	/* File descriptor for disk I/O */
87*433d6423SLionel Sambuc 
88*433d6423SLionel Sambuc static DIRECTORY root[MAX_ROOT_ENTRIES];
89*433d6423SLionel Sambuc static DIRECTORY save_entry;
90*433d6423SLionel Sambuc static char drive[] = "/dev/dosX";
91*433d6423SLionel Sambuc #define DRIVE_NR	(sizeof (drive) - 2)
92*433d6423SLionel Sambuc static char null[MAX_CLUSTER_SIZE], *device = drive, path[128];
93*433d6423SLionel Sambuc static long data_start;
94*433d6423SLionel Sambuc static long mark;	/* offset of directory entry to be written */
95*433d6423SLionel Sambuc static unsigned short total_clusters, cluster_size, root_entries, sub_entries;
96*433d6423SLionel Sambuc static unsigned long fat_size;
97*433d6423SLionel Sambuc 
98*433d6423SLionel Sambuc static BOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir, fat_16 = 0;
99*433d6423SLionel Sambuc static BOOL big_endian;
100*433d6423SLionel Sambuc 
101*433d6423SLionel Sambuc /* maximum size of a cooked 12bit FAT. Also Size of 16bit FAT cache
102*433d6423SLionel Sambuc  * if not enough memory for whole FAT
103*433d6423SLionel Sambuc  */
104*433d6423SLionel Sambuc #define COOKED_SIZE		8192
105*433d6423SLionel Sambuc /* raw FAT. Only used for 12bit FAT to make conversion easier
106*433d6423SLionel Sambuc  */
107*433d6423SLionel Sambuc static unsigned char	*raw_fat;
108*433d6423SLionel Sambuc /* Cooked FAT. May be only part of the FAT for 16 bit FATs
109*433d6423SLionel Sambuc  */
110*433d6423SLionel Sambuc static unsigned short	*cooked_fat;
111*433d6423SLionel Sambuc /* lowest and highest entry in fat cache
112*433d6423SLionel Sambuc  */
113*433d6423SLionel Sambuc static unsigned short	fat_low = USHRT_MAX,
114*433d6423SLionel Sambuc 			fat_high = 0;
115*433d6423SLionel Sambuc static BOOL		fat_dirty = FALSE;
116*433d6423SLionel Sambuc static unsigned int	cache_size;
117*433d6423SLionel Sambuc 
118*433d6423SLionel Sambuc 
119*433d6423SLionel Sambuc /* Prototypes. */
120*433d6423SLionel Sambuc void usage(char *prog_name);
121*433d6423SLionel Sambuc unsigned c2u2(unsigned char *ucarray);
122*433d6423SLionel Sambuc unsigned long c4u4(unsigned char *ucarray);
123*433d6423SLionel Sambuc void determine(void);
124*433d6423SLionel Sambuc int main(int argc, char *argv []);
125*433d6423SLionel Sambuc DIRECTORY *directory(DIRECTORY *dir, int entries, BOOL function, char
126*433d6423SLionel Sambuc 	*pathname);
127*433d6423SLionel Sambuc void extract(DIRECTORY *entry);
128*433d6423SLionel Sambuc void make_file(DIRECTORY *dir_ptr, int entries, char *name);
129*433d6423SLionel Sambuc void fill_date(DIRECTORY *entry);
130*433d6423SLionel Sambuc char *make_name(DIRECTORY *dir_ptr, int dir_fl);
131*433d6423SLionel Sambuc int fill(char *buffer, size_t size);
132*433d6423SLionel Sambuc void xmodes(int mode);
133*433d6423SLionel Sambuc void show(DIRECTORY *dir_ptr, char *name);
134*433d6423SLionel Sambuc void free_blocks(void);
135*433d6423SLionel Sambuc DIRECTORY *read_cluster(unsigned int cluster);
136*433d6423SLionel Sambuc unsigned short free_cluster(BOOL leave_fl);
137*433d6423SLionel Sambuc void link_fat(unsigned int cl_1, unsigned int cl_2);
138*433d6423SLionel Sambuc unsigned short next_cluster(unsigned int cl_no);
139*433d6423SLionel Sambuc char *slash(char *str);
140*433d6423SLionel Sambuc void add_path(char *file, BOOL slash_fl);
141*433d6423SLionel Sambuc void disk_io(BOOL op, unsigned long seek, void *address, unsigned
142*433d6423SLionel Sambuc 	bytes);
143*433d6423SLionel Sambuc void flush_fat(void);
144*433d6423SLionel Sambuc void read_fat(unsigned int cl_no);
145*433d6423SLionel Sambuc BOOL free_range(unsigned short *first, unsigned short *last);
146*433d6423SLionel Sambuc long lmin(long a, long b);
147*433d6423SLionel Sambuc 
148*433d6423SLionel Sambuc 
usage(prog_name)149*433d6423SLionel Sambuc void usage(prog_name)
150*433d6423SLionel Sambuc register char *prog_name;
151*433d6423SLionel Sambuc {
152*433d6423SLionel Sambuc   fprintf (stderr, "Usage: %s [%s\n", prog_name,
153*433d6423SLionel Sambuc 	     (dos_dir ? "-lr] drive [dir]" : "-a] drive file"));
154*433d6423SLionel Sambuc   exit(1);
155*433d6423SLionel Sambuc }
156*433d6423SLionel Sambuc 
c2u2(ucarray)157*433d6423SLionel Sambuc unsigned c2u2(ucarray)
158*433d6423SLionel Sambuc unsigned char *ucarray;
159*433d6423SLionel Sambuc {
160*433d6423SLionel Sambuc   return ucarray[0] + (ucarray[1] << 8);	/* parens vital */
161*433d6423SLionel Sambuc }
162*433d6423SLionel Sambuc 
c4u4(ucarray)163*433d6423SLionel Sambuc unsigned long c4u4(ucarray)
164*433d6423SLionel Sambuc unsigned char *ucarray;
165*433d6423SLionel Sambuc {
166*433d6423SLionel Sambuc   return ucarray[0] + ((unsigned long) ucarray[1] << 8) +
167*433d6423SLionel Sambuc 		      ((unsigned long) ucarray[2] << 16) +
168*433d6423SLionel Sambuc 		      ((unsigned long) ucarray[3] << 24);
169*433d6423SLionel Sambuc }
170*433d6423SLionel Sambuc 
determine()171*433d6423SLionel Sambuc void determine()
172*433d6423SLionel Sambuc {
173*433d6423SLionel Sambuc   struct dosboot {
174*433d6423SLionel Sambuc 	unsigned char cjump[2];	/* unsigneds avoid bugs */
175*433d6423SLionel Sambuc 	unsigned char nop;
176*433d6423SLionel Sambuc 	unsigned char name[8];
177*433d6423SLionel Sambuc 	unsigned char cbytepers[2];	/* don't use shorts, etc */
178*433d6423SLionel Sambuc 	unsigned char secpclus;		/* to avoid struct member */
179*433d6423SLionel Sambuc 	unsigned char creservsec[2];	/* alignment and byte */
180*433d6423SLionel Sambuc 	unsigned char fats;		/* order bugs */
181*433d6423SLionel Sambuc 	unsigned char cdirents[2];
182*433d6423SLionel Sambuc 	unsigned char ctotsec[2];
183*433d6423SLionel Sambuc 	unsigned char media;
184*433d6423SLionel Sambuc 	unsigned char csecpfat[2];
185*433d6423SLionel Sambuc 	unsigned char csecptrack[2];
186*433d6423SLionel Sambuc 	unsigned char cheads[2];
187*433d6423SLionel Sambuc 	unsigned char chiddensec[2];
188*433d6423SLionel Sambuc 	unsigned char dos4hidd2[2];
189*433d6423SLionel Sambuc 	unsigned char dos4totsec[4];
190*433d6423SLionel Sambuc 	/* Char    fill[476]; */
191*433d6423SLionel Sambuc   } boot;
192*433d6423SLionel Sambuc   unsigned short boot_magic;	/* last of boot block */
193*433d6423SLionel Sambuc   unsigned bytepers, reservsec, dirents;
194*433d6423SLionel Sambuc   unsigned secpfat, secptrack, heads, hiddensec;
195*433d6423SLionel Sambuc   unsigned long totsec;
196*433d6423SLionel Sambuc   unsigned char fat_info, fat_check;
197*433d6423SLionel Sambuc   unsigned short endiantest = 1;
198*433d6423SLionel Sambuc   int errcount = 0;
199*433d6423SLionel Sambuc 
200*433d6423SLionel Sambuc   big_endian = !(*(unsigned char *)&endiantest);
201*433d6423SLionel Sambuc 
202*433d6423SLionel Sambuc   /* Read Bios-Parameterblock */
203*433d6423SLionel Sambuc   disk_io(READ, 0L, &boot, sizeof boot);
204*433d6423SLionel Sambuc   disk_io(READ, 0x1FEL, &boot_magic, sizeof boot_magic);
205*433d6423SLionel Sambuc 
206*433d6423SLionel Sambuc   /* Convert some arrays */
207*433d6423SLionel Sambuc   bytepers = c2u2(boot.cbytepers);
208*433d6423SLionel Sambuc   reservsec = c2u2(boot.creservsec);
209*433d6423SLionel Sambuc   dirents = c2u2(boot.cdirents);
210*433d6423SLionel Sambuc   totsec = c2u2(boot.ctotsec);
211*433d6423SLionel Sambuc   if (totsec == 0) totsec = c4u4(boot.dos4totsec);
212*433d6423SLionel Sambuc   secpfat = c2u2(boot.csecpfat);
213*433d6423SLionel Sambuc   secptrack = c2u2(boot.csecptrack);
214*433d6423SLionel Sambuc   heads = c2u2(boot.cheads);
215*433d6423SLionel Sambuc 
216*433d6423SLionel Sambuc   /* The `hidden sectors' are the sectors before the partition.
217*433d6423SLionel Sambuc    * The calculation here is probably wrong (I think the dos4hidd2
218*433d6423SLionel Sambuc    * bytes are the msbs), but that doesn't matter, since the
219*433d6423SLionel Sambuc    * value isn't used anyway
220*433d6423SLionel Sambuc    */
221*433d6423SLionel Sambuc   hiddensec = c2u2(boot.chiddensec);
222*433d6423SLionel Sambuc   if (hiddensec == 0) hiddensec = c2u2 (boot.dos4hidd2);
223*433d6423SLionel Sambuc 
224*433d6423SLionel Sambuc   /* Safety checking */
225*433d6423SLionel Sambuc   if (boot_magic != 0xAA55) {
226*433d6423SLionel Sambuc 	fprintf (stderr, "%s: magic != 0xAA55\n", cmnd);
227*433d6423SLionel Sambuc 	++errcount;
228*433d6423SLionel Sambuc   }
229*433d6423SLionel Sambuc 
230*433d6423SLionel Sambuc   /* Check sectors per track instead of inadequate media byte */
231*433d6423SLionel Sambuc   if (secptrack < 15 &&		/* assume > 15 hard disk & wini OK */
232*433d6423SLionel Sambuc #ifdef SECT10			/* BIOS modified for 10 sec/track */
233*433d6423SLionel Sambuc       secptrack != 10 &&
234*433d6423SLionel Sambuc #endif
235*433d6423SLionel Sambuc #ifdef SECT8			/* BIOS modified for 8 sec/track */
236*433d6423SLionel Sambuc       secptrack != 8 &&
237*433d6423SLionel Sambuc #endif
238*433d6423SLionel Sambuc       secptrack != 9) {
239*433d6423SLionel Sambuc 	fprintf (stderr, "%s: %d sectors per track not supported\n", cmnd, secptrack);
240*433d6423SLionel Sambuc 	++errcount;
241*433d6423SLionel Sambuc   }
242*433d6423SLionel Sambuc   if (bytepers == 0) {
243*433d6423SLionel Sambuc 	fprintf (stderr, "%s: bytes per sector == 0\n", cmnd);
244*433d6423SLionel Sambuc 	++errcount;
245*433d6423SLionel Sambuc   }
246*433d6423SLionel Sambuc   if (boot.secpclus == 0) {
247*433d6423SLionel Sambuc 	fprintf (stderr, "%s: sectors per cluster == 0\n", cmnd);
248*433d6423SLionel Sambuc 	++errcount;
249*433d6423SLionel Sambuc   }
250*433d6423SLionel Sambuc   if (boot.fats != 2 && dos_write) {
251*433d6423SLionel Sambuc 	fprintf (stderr, "%s: fats != 2\n", cmnd);
252*433d6423SLionel Sambuc 	++errcount;
253*433d6423SLionel Sambuc   }
254*433d6423SLionel Sambuc   if (reservsec != 1) {
255*433d6423SLionel Sambuc 	fprintf (stderr, "%s: reserved != 1\n", cmnd);
256*433d6423SLionel Sambuc 	++errcount;
257*433d6423SLionel Sambuc   }
258*433d6423SLionel Sambuc   if (errcount != 0) {
259*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Can't handle disk\n", cmnd);
260*433d6423SLionel Sambuc 	exit(2);
261*433d6423SLionel Sambuc   }
262*433d6423SLionel Sambuc 
263*433d6423SLionel Sambuc   /* Calculate everything. */
264*433d6423SLionel Sambuc   if (boot.secpclus == 0) boot.secpclus = 1;
265*433d6423SLionel Sambuc   total_clusters =
266*433d6423SLionel Sambuc 	(totsec - boot.fats * secpfat - reservsec -
267*433d6423SLionel Sambuc 	 dirents * 32L / bytepers		    ) / boot.secpclus + 2;
268*433d6423SLionel Sambuc   	/* first 2 entries in FAT aren't used */
269*433d6423SLionel Sambuc   cluster_size = bytepers * boot.secpclus;
270*433d6423SLionel Sambuc   fat_size = (unsigned long) secpfat * (unsigned long) bytepers;
271*433d6423SLionel Sambuc   data_start = (long) bytepers + (long) boot.fats * fat_size
272*433d6423SLionel Sambuc 	+ (long) dirents *32L;
273*433d6423SLionel Sambuc   root_entries = dirents;
274*433d6423SLionel Sambuc   sub_entries = boot.secpclus * bytepers / 32;
275*433d6423SLionel Sambuc   if (total_clusters > 4096) fat_16 = 1;
276*433d6423SLionel Sambuc 
277*433d6423SLionel Sambuc   /* Further safety checking */
278*433d6423SLionel Sambuc   if (cluster_size > MAX_CLUSTER_SIZE) {
279*433d6423SLionel Sambuc 	fprintf (stderr, "%s: cluster size too big\n", cmnd);
280*433d6423SLionel Sambuc 	++errcount;
281*433d6423SLionel Sambuc   }
282*433d6423SLionel Sambuc 
283*433d6423SLionel Sambuc   disk_io(READ, FAT_START, &fat_info, 1);
284*433d6423SLionel Sambuc   disk_io(READ, FAT_START + fat_size, &fat_check, 1);
285*433d6423SLionel Sambuc   if (fat_check != fat_info) {
286*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Disk type in FAT copy differs from disk type in FAT original.\n", cmnd);
287*433d6423SLionel Sambuc 	++errcount;
288*433d6423SLionel Sambuc   }
289*433d6423SLionel Sambuc   if (errcount != 0) {
290*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Can't handle disk\n", cmnd);
291*433d6423SLionel Sambuc 	exit(2);
292*433d6423SLionel Sambuc   }
293*433d6423SLionel Sambuc }
294*433d6423SLionel Sambuc 
main(argc,argv)295*433d6423SLionel Sambuc int main(argc, argv)
296*433d6423SLionel Sambuc int argc;
297*433d6423SLionel Sambuc register char *argv[];
298*433d6423SLionel Sambuc {
299*433d6423SLionel Sambuc   register char *arg_ptr = slash(argv[0]);
300*433d6423SLionel Sambuc   DIRECTORY *entry;
301*433d6423SLionel Sambuc   short idx = 1;
302*433d6423SLionel Sambuc   char dev_nr = '0';
303*433d6423SLionel Sambuc 
304*433d6423SLionel Sambuc   cmnd = arg_ptr;	/* needed for error messages */
305*433d6423SLionel Sambuc   if (!strcmp(arg_ptr, "dosdir"))
306*433d6423SLionel Sambuc 	dos_dir = TRUE;
307*433d6423SLionel Sambuc   else if (!strcmp(arg_ptr, "dosread"))
308*433d6423SLionel Sambuc 	dos_read = TRUE;
309*433d6423SLionel Sambuc   else if (!strcmp(arg_ptr, "doswrite"))
310*433d6423SLionel Sambuc 	dos_write = TRUE;
311*433d6423SLionel Sambuc   else {
312*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Program should be named dosread, doswrite or dosdir.\n", cmnd);
313*433d6423SLionel Sambuc 	exit(1);
314*433d6423SLionel Sambuc   }
315*433d6423SLionel Sambuc 
316*433d6423SLionel Sambuc   if (argc == 1) usage(argv[0]);
317*433d6423SLionel Sambuc 
318*433d6423SLionel Sambuc   if (argv[1][0] == '-') {
319*433d6423SLionel Sambuc 	for (arg_ptr = &argv[1][1]; *arg_ptr; arg_ptr++) {
320*433d6423SLionel Sambuc 		if (*arg_ptr == 'l' && dos_dir) {
321*433d6423SLionel Sambuc 			Lflag = TRUE;
322*433d6423SLionel Sambuc 		} else if (*arg_ptr == 'r' && dos_dir) {
323*433d6423SLionel Sambuc 			Rflag = TRUE;
324*433d6423SLionel Sambuc 		} else if (*arg_ptr == 'a' && !dos_dir) {
325*433d6423SLionel Sambuc 			assert ('\n' == 10);
326*433d6423SLionel Sambuc 			assert ('\r' == 13);
327*433d6423SLionel Sambuc 			Aflag = TRUE;
328*433d6423SLionel Sambuc 		} else {
329*433d6423SLionel Sambuc 			usage(argv[0]);
330*433d6423SLionel Sambuc 		}
331*433d6423SLionel Sambuc 	}
332*433d6423SLionel Sambuc 	idx++;
333*433d6423SLionel Sambuc   }
334*433d6423SLionel Sambuc   if (idx == argc) usage(argv[0]);
335*433d6423SLionel Sambuc 
336*433d6423SLionel Sambuc   if (strlen(argv[idx]) > 1) {
337*433d6423SLionel Sambuc 	device = argv[idx++];
338*433d6423SLionel Sambuc 
339*433d6423SLionel Sambuc 	/* If the device does not contain a / we assume that it
340*433d6423SLionel Sambuc 	 * is the name of a device in /dev. Instead of prepending
341*433d6423SLionel Sambuc 	 * /dev/ we try to chdir there.
342*433d6423SLionel Sambuc 	 */
343*433d6423SLionel Sambuc 	if (strchr(device, '/') == NULL && chdir("/dev") < 0) {
344*433d6423SLionel Sambuc 		perror("/dev");
345*433d6423SLionel Sambuc 		exit(1);
346*433d6423SLionel Sambuc 	}
347*433d6423SLionel Sambuc   } else {
348*433d6423SLionel Sambuc 	if ((dev_nr = toupper (*argv[idx++])) < 'A' || dev_nr > 'Z')
349*433d6423SLionel Sambuc 		usage(argv[0]);
350*433d6423SLionel Sambuc 
351*433d6423SLionel Sambuc 	device[DRIVE_NR] = dev_nr;
352*433d6423SLionel Sambuc   }
353*433d6423SLionel Sambuc 
354*433d6423SLionel Sambuc   if ((disk = open(device, dos_write ? O_RDWR : O_RDONLY)) < 0) {
355*433d6423SLionel Sambuc 	fprintf (stderr, "%s: cannot open %s: %s\n",
356*433d6423SLionel Sambuc 		 cmnd, device, strerror (errno));
357*433d6423SLionel Sambuc 	exit(1);
358*433d6423SLionel Sambuc   }
359*433d6423SLionel Sambuc   determine();
360*433d6423SLionel Sambuc   disk_io(READ, ROOTADDR, root, DIR_SIZE * root_entries);
361*433d6423SLionel Sambuc 
362*433d6423SLionel Sambuc   if (dos_dir && Lflag) {
363*433d6423SLionel Sambuc 	entry = label();
364*433d6423SLionel Sambuc 	printf ("Volume in drive %c ", dev_nr);
365*433d6423SLionel Sambuc 	if (entry == NULL)
366*433d6423SLionel Sambuc 		printf("has no label.\n\n");
367*433d6423SLionel Sambuc 	else
368*433d6423SLionel Sambuc 		printf ("is %.11s\n\n", entry->d_name);
369*433d6423SLionel Sambuc   }
370*433d6423SLionel Sambuc   if (argv[idx] == NULL) {
371*433d6423SLionel Sambuc 	if (!dos_dir) usage(argv[0]);
372*433d6423SLionel Sambuc 	if (Lflag) printf ("Root directory:\n");
373*433d6423SLionel Sambuc 	list_dir(root, root_entries, FALSE);
374*433d6423SLionel Sambuc 	if (Lflag) free_blocks();
375*433d6423SLionel Sambuc 	fflush (stdout);
376*433d6423SLionel Sambuc 	exit(0);
377*433d6423SLionel Sambuc   }
378*433d6423SLionel Sambuc   for (arg_ptr = argv[idx]; *arg_ptr; arg_ptr++)
379*433d6423SLionel Sambuc 	if (*arg_ptr == '\\')	*arg_ptr = '/';
380*433d6423SLionel Sambuc 	else		     	*arg_ptr = toupper (*arg_ptr);
381*433d6423SLionel Sambuc   if (*--arg_ptr == '/') *arg_ptr = '\0';	/* skip trailing '/' */
382*433d6423SLionel Sambuc 
383*433d6423SLionel Sambuc   add_path(argv[idx], FALSE);
384*433d6423SLionel Sambuc   add_path("/", FALSE);
385*433d6423SLionel Sambuc 
386*433d6423SLionel Sambuc   if (dos_dir && Lflag) printf ( "Directory %s:\n", path);
387*433d6423SLionel Sambuc 
388*433d6423SLionel Sambuc   entry = find_entry(root, root_entries, argv[idx]);
389*433d6423SLionel Sambuc 
390*433d6423SLionel Sambuc   if (dos_dir) {
391*433d6423SLionel Sambuc 	list_dir(entry, sub_entries, FALSE);
392*433d6423SLionel Sambuc 	if (Lflag) free_blocks();
393*433d6423SLionel Sambuc   } else if (dos_read)
394*433d6423SLionel Sambuc 	extract(entry);
395*433d6423SLionel Sambuc   else {
396*433d6423SLionel Sambuc 	if (entry != NULL) {
397*433d6423SLionel Sambuc 		fflush (stdout);
398*433d6423SLionel Sambuc 		if (is_dir(entry))
399*433d6423SLionel Sambuc 			fprintf (stderr, "%s: %s is a directory.\n", cmnd, path);
400*433d6423SLionel Sambuc 		else
401*433d6423SLionel Sambuc 			fprintf (stderr, "%s: %s already exists.\n", cmnd, argv[idx]);
402*433d6423SLionel Sambuc 		exit(1);
403*433d6423SLionel Sambuc 	}
404*433d6423SLionel Sambuc 	add_path(NULL, TRUE);
405*433d6423SLionel Sambuc 
406*433d6423SLionel Sambuc 	if (*path) make_file(find_entry(root, root_entries, path),
407*433d6423SLionel Sambuc 			  sub_entries, slash(argv[idx]));
408*433d6423SLionel Sambuc 	else
409*433d6423SLionel Sambuc 		make_file(root, root_entries, argv[idx]);
410*433d6423SLionel Sambuc   }
411*433d6423SLionel Sambuc 
412*433d6423SLionel Sambuc   (void) close(disk);
413*433d6423SLionel Sambuc   fflush (stdout);
414*433d6423SLionel Sambuc   exit(0);
415*433d6423SLionel Sambuc   return(0);
416*433d6423SLionel Sambuc }
417*433d6423SLionel Sambuc 
418*433d6423SLionel Sambuc 
419*433d6423SLionel Sambuc /* General directory search routine.
420*433d6423SLionel Sambuc  *
421*433d6423SLionel Sambuc  * dir:
422*433d6423SLionel Sambuc  *	Points to one or more directory entries
423*433d6423SLionel Sambuc  * entries:
424*433d6423SLionel Sambuc  *	number of entries
425*433d6423SLionel Sambuc  *	if entries == root_entries, dir points to the entire
426*433d6423SLionel Sambuc  *	root directory. Otherwise it points to a single directory
427*433d6423SLionel Sambuc  *	entry describing the directory to be searched.
428*433d6423SLionel Sambuc  *
429*433d6423SLionel Sambuc  * function:
430*433d6423SLionel Sambuc  *	FIND ... find pathname relative to directory dir.
431*433d6423SLionel Sambuc  *	LABEL ... find first label entry in dir.
432*433d6423SLionel Sambuc  *	ENTRY ... create a new empty entry.
433*433d6423SLionel Sambuc  *	FALSE ... list directory
434*433d6423SLionel Sambuc  *
435*433d6423SLionel Sambuc  * pathname:
436*433d6423SLionel Sambuc  *	name of the file to be found or directory to be listed.
437*433d6423SLionel Sambuc  *	must be in upper case, pathname components must be
438*433d6423SLionel Sambuc  *	separated by slashes, but can be longer than than
439*433d6423SLionel Sambuc  *	8+3 characters (The rest is ignored).
440*433d6423SLionel Sambuc  */
directory(dir,entries,function,pathname)441*433d6423SLionel Sambuc DIRECTORY *directory(dir, entries, function, pathname)
442*433d6423SLionel Sambuc DIRECTORY *dir;
443*433d6423SLionel Sambuc int entries;
444*433d6423SLionel Sambuc int function;
445*433d6423SLionel Sambuc register char *pathname;
446*433d6423SLionel Sambuc {
447*433d6423SLionel Sambuc   register DIRECTORY *dir_ptr = dir;
448*433d6423SLionel Sambuc   DIRECTORY *mem = NULL;
449*433d6423SLionel Sambuc   unsigned short cl_no = dir->d_cluster;
450*433d6423SLionel Sambuc   unsigned short type, last = 0;
451*433d6423SLionel Sambuc   char file_name[14];
452*433d6423SLionel Sambuc   char *name;
453*433d6423SLionel Sambuc   int i = 0;
454*433d6423SLionel Sambuc 
455*433d6423SLionel Sambuc   if (function == FIND) {
456*433d6423SLionel Sambuc 	while (*pathname != '/' && *pathname != '.' && *pathname &&
457*433d6423SLionel Sambuc 	       i < 8) {
458*433d6423SLionel Sambuc 		file_name[i++] = *pathname++;
459*433d6423SLionel Sambuc 	}
460*433d6423SLionel Sambuc 	if (*pathname == '.') {
461*433d6423SLionel Sambuc 		int j = 0;
462*433d6423SLionel Sambuc 		file_name[i++] = *pathname++;
463*433d6423SLionel Sambuc 		while (*pathname != '/' && *pathname != '.' && *pathname &&
464*433d6423SLionel Sambuc 		       j++ < 3) {
465*433d6423SLionel Sambuc 			file_name[i++] = *pathname++;
466*433d6423SLionel Sambuc 		}
467*433d6423SLionel Sambuc 	}
468*433d6423SLionel Sambuc 	while (*pathname != '/' && *pathname) pathname++;
469*433d6423SLionel Sambuc 	file_name[i] = '\0';
470*433d6423SLionel Sambuc   }
471*433d6423SLionel Sambuc   do {
472*433d6423SLionel Sambuc 	if (entries != root_entries) {
473*433d6423SLionel Sambuc 		mem = dir_ptr = read_cluster(cl_no);
474*433d6423SLionel Sambuc 		last = cl_no;
475*433d6423SLionel Sambuc 		cl_no = next_cluster(cl_no);
476*433d6423SLionel Sambuc 	}
477*433d6423SLionel Sambuc 	for (i = 0; i < entries; i++, dir_ptr++) {
478*433d6423SLionel Sambuc 		type = dir_ptr->d_name[0] & 0x0FF;
479*433d6423SLionel Sambuc 		if (function == ENTRY) {
480*433d6423SLionel Sambuc 			if (type == NOT_USED || type == ERASED) {
481*433d6423SLionel Sambuc 				if (!mem)
482*433d6423SLionel Sambuc 					mark = ROOTADDR + (long) i *(long) DIR_SIZE;
483*433d6423SLionel Sambuc 				else
484*433d6423SLionel Sambuc 					mark = clus_add(last) + (long) i *(long) DIR_SIZE;
485*433d6423SLionel Sambuc 				return dir_ptr;
486*433d6423SLionel Sambuc 			}
487*433d6423SLionel Sambuc 			continue;
488*433d6423SLionel Sambuc 		}
489*433d6423SLionel Sambuc 		if (type == NOT_USED) break;
490*433d6423SLionel Sambuc 		if (dir_ptr->d_attribute & 0x08) {
491*433d6423SLionel Sambuc 			if (function == LABEL) return dir_ptr;
492*433d6423SLionel Sambuc 			continue;
493*433d6423SLionel Sambuc 		}
494*433d6423SLionel Sambuc 		if (type == DIR || type == ERASED || function == LABEL)
495*433d6423SLionel Sambuc 			continue;
496*433d6423SLionel Sambuc 		type = is_dir(dir_ptr);
497*433d6423SLionel Sambuc 		name = make_name(dir_ptr,
498*433d6423SLionel Sambuc 				 (function == FIND) ?  FALSE : type);
499*433d6423SLionel Sambuc 		if (function == FIND) {
500*433d6423SLionel Sambuc 			if (strcmp(file_name, name) != 0) continue;
501*433d6423SLionel Sambuc 			if (!type) {
502*433d6423SLionel Sambuc 				if (dos_dir || *pathname) {
503*433d6423SLionel Sambuc 					fflush (stdout);
504*433d6423SLionel Sambuc 					fprintf (stderr, "%s: Not a directory: %s\n", cmnd, file_name);
505*433d6423SLionel Sambuc 					exit(1);
506*433d6423SLionel Sambuc 				}
507*433d6423SLionel Sambuc 			} else if (*pathname == '\0' && dos_read) {
508*433d6423SLionel Sambuc 				fflush (stdout);
509*433d6423SLionel Sambuc 				fprintf (stderr, "%s: %s is a directory.\n", cmnd, path);
510*433d6423SLionel Sambuc 				exit(1);
511*433d6423SLionel Sambuc 			}
512*433d6423SLionel Sambuc 			if (*pathname) {
513*433d6423SLionel Sambuc 				dir_ptr = find_entry(dir_ptr,
514*433d6423SLionel Sambuc 					 sub_entries, pathname + 1);
515*433d6423SLionel Sambuc 			}
516*433d6423SLionel Sambuc 			if (mem) {
517*433d6423SLionel Sambuc 				if (dir_ptr) {
518*433d6423SLionel Sambuc 					memcpy((char *)&save_entry, (char *)dir_ptr, DIR_SIZE);
519*433d6423SLionel Sambuc 					dir_ptr = &save_entry;
520*433d6423SLionel Sambuc 				}
521*433d6423SLionel Sambuc 				free( (void *) mem);
522*433d6423SLionel Sambuc 			}
523*433d6423SLionel Sambuc 			return dir_ptr;
524*433d6423SLionel Sambuc 		} else {
525*433d6423SLionel Sambuc 			if (function == FALSE) {
526*433d6423SLionel Sambuc 				show(dir_ptr, name);
527*433d6423SLionel Sambuc 			} else if (type) {	/* Recursive */
528*433d6423SLionel Sambuc 				printf ( "Directory %s%s:\n", path, name);
529*433d6423SLionel Sambuc 				add_path(name, FALSE);
530*433d6423SLionel Sambuc 				list_dir(dir_ptr, sub_entries, FALSE);
531*433d6423SLionel Sambuc 				add_path(NULL, FALSE);
532*433d6423SLionel Sambuc 			}
533*433d6423SLionel Sambuc 		}
534*433d6423SLionel Sambuc 	}
535*433d6423SLionel Sambuc 	if (mem) free( (void *) mem);
536*433d6423SLionel Sambuc   } while (cl_no != LAST_CLUSTER && mem);
537*433d6423SLionel Sambuc 
538*433d6423SLionel Sambuc   switch (function) {
539*433d6423SLionel Sambuc       case FIND:
540*433d6423SLionel Sambuc 	if (dos_write && *pathname == '\0') return NULL;
541*433d6423SLionel Sambuc 	fflush (stdout);
542*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Cannot find `%s'.\n", cmnd, file_name);
543*433d6423SLionel Sambuc 	exit(1);
544*433d6423SLionel Sambuc       case LABEL:
545*433d6423SLionel Sambuc 	return NULL;
546*433d6423SLionel Sambuc       case ENTRY:
547*433d6423SLionel Sambuc 	if (!mem) {
548*433d6423SLionel Sambuc 		fflush (stdout);
549*433d6423SLionel Sambuc 		fprintf (stderr, "%s: No entries left in root directory.\n", cmnd);
550*433d6423SLionel Sambuc 		exit(1);
551*433d6423SLionel Sambuc 	}
552*433d6423SLionel Sambuc 	cl_no = free_cluster(TRUE);
553*433d6423SLionel Sambuc 	link_fat(last, cl_no);
554*433d6423SLionel Sambuc 	link_fat(cl_no, LAST_CLUSTER);
555*433d6423SLionel Sambuc 	disk_io(WRITE, clus_add(cl_no), null, cluster_size);
556*433d6423SLionel Sambuc 
557*433d6423SLionel Sambuc 	return new_entry(dir, entries);
558*433d6423SLionel Sambuc       case FALSE:
559*433d6423SLionel Sambuc 	if (Rflag) {
560*433d6423SLionel Sambuc 		printf ("\n");
561*433d6423SLionel Sambuc 		list_dir(dir, entries, TRUE);
562*433d6423SLionel Sambuc 	}
563*433d6423SLionel Sambuc   }
564*433d6423SLionel Sambuc   return NULL;
565*433d6423SLionel Sambuc }
566*433d6423SLionel Sambuc 
extract(entry)567*433d6423SLionel Sambuc void extract(entry)
568*433d6423SLionel Sambuc register DIRECTORY *entry;
569*433d6423SLionel Sambuc {
570*433d6423SLionel Sambuc   register unsigned short cl_no = entry->d_cluster;
571*433d6423SLionel Sambuc   char buffer[MAX_CLUSTER_SIZE];
572*433d6423SLionel Sambuc   int rest, i;
573*433d6423SLionel Sambuc 
574*433d6423SLionel Sambuc   if (entry->d_size == 0)	/* Empty file */
575*433d6423SLionel Sambuc 	return;
576*433d6423SLionel Sambuc 
577*433d6423SLionel Sambuc   do {
578*433d6423SLionel Sambuc 	disk_io(READ, clus_add(cl_no), buffer, cluster_size);
579*433d6423SLionel Sambuc 	rest = (entry->d_size > (long) cluster_size) ? cluster_size : (short) entry->d_size;
580*433d6423SLionel Sambuc 
581*433d6423SLionel Sambuc 	if (Aflag) {
582*433d6423SLionel Sambuc 		for (i = 0; i < rest; i ++) {
583*433d6423SLionel Sambuc 			if (buffer [i] != '\r') putchar (buffer [i]);
584*433d6423SLionel Sambuc 		}
585*433d6423SLionel Sambuc 		if (ferror (stdout)) {
586*433d6423SLionel Sambuc 			fprintf (stderr, "%s: cannot write to stdout: %s\n",
587*433d6423SLionel Sambuc 				 cmnd, strerror (errno));
588*433d6423SLionel Sambuc 			exit (1);
589*433d6423SLionel Sambuc 		}
590*433d6423SLionel Sambuc 	} else {
591*433d6423SLionel Sambuc 		if (fwrite (buffer, 1, rest, stdout) != rest) {
592*433d6423SLionel Sambuc 			fprintf (stderr, "%s: cannot write to stdout: %s\n",
593*433d6423SLionel Sambuc 				 cmnd, strerror (errno));
594*433d6423SLionel Sambuc 			exit (1);
595*433d6423SLionel Sambuc 		}
596*433d6423SLionel Sambuc 	}
597*433d6423SLionel Sambuc 	entry->d_size -= (long) rest;
598*433d6423SLionel Sambuc 	cl_no = next_cluster(cl_no);
599*433d6423SLionel Sambuc 	if (cl_no == BAD16) {
600*433d6423SLionel Sambuc 		fflush (stdout);
601*433d6423SLionel Sambuc 		fprintf (stderr, "%s: reserved cluster value %x encountered.\n",
602*433d6423SLionel Sambuc 			 cmnd, cl_no);
603*433d6423SLionel Sambuc 		exit (1);
604*433d6423SLionel Sambuc 	}
605*433d6423SLionel Sambuc   } while (entry->d_size && cl_no != LAST_CLUSTER);
606*433d6423SLionel Sambuc 
607*433d6423SLionel Sambuc   if (cl_no != LAST_CLUSTER)
608*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Too many clusters allocated for file.\n", cmnd);
609*433d6423SLionel Sambuc   else if (entry->d_size != 0)
610*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Premature EOF: %ld bytes left.\n", cmnd,
611*433d6423SLionel Sambuc 		     entry->d_size);
612*433d6423SLionel Sambuc }
613*433d6423SLionel Sambuc 
614*433d6423SLionel Sambuc 
615*433d6423SLionel Sambuc /* Minimum of two long values
616*433d6423SLionel Sambuc  */
lmin(a,b)617*433d6423SLionel Sambuc long lmin (a, b)
618*433d6423SLionel Sambuc long a, b;
619*433d6423SLionel Sambuc {
620*433d6423SLionel Sambuc 	if (a < b) return a;
621*433d6423SLionel Sambuc 	else return b;
622*433d6423SLionel Sambuc }
623*433d6423SLionel Sambuc 
624*433d6423SLionel Sambuc 
make_file(dir_ptr,entries,name)625*433d6423SLionel Sambuc void make_file(dir_ptr, entries, name)
626*433d6423SLionel Sambuc DIRECTORY *dir_ptr;
627*433d6423SLionel Sambuc int entries;
628*433d6423SLionel Sambuc char *name;
629*433d6423SLionel Sambuc {
630*433d6423SLionel Sambuc   register DIRECTORY *entry = new_entry(dir_ptr, entries);
631*433d6423SLionel Sambuc   register char *ptr;
632*433d6423SLionel Sambuc   char buffer[MAX_CLUSTER_SIZE];
633*433d6423SLionel Sambuc   unsigned short cl_no = 0;
634*433d6423SLionel Sambuc   int i, r;
635*433d6423SLionel Sambuc   long size = 0L;
636*433d6423SLionel Sambuc   unsigned short first_cluster, last_cluster;
637*433d6423SLionel Sambuc   long chunk;
638*433d6423SLionel Sambuc 
639*433d6423SLionel Sambuc   memset (&entry->d_name[0], ' ', 11);    /* clear entry */
640*433d6423SLionel Sambuc   for (i = 0, ptr = name; i < 8 && *ptr != '.' && *ptr; i++)
641*433d6423SLionel Sambuc 	entry->d_name[i] = *ptr++;
642*433d6423SLionel Sambuc   while (*ptr != '.' && *ptr) ptr++;
643*433d6423SLionel Sambuc   if (*ptr == '.') ptr++;
644*433d6423SLionel Sambuc   for (i = 0; i < 3 && *ptr != '.' && *ptr; i++) entry->d_ext[i] = *ptr++;
645*433d6423SLionel Sambuc 
646*433d6423SLionel Sambuc   for (i = 0; i < 10; i++) entry->d_reserved[i] = '\0';
647*433d6423SLionel Sambuc   entry->d_attribute = '\0';
648*433d6423SLionel Sambuc 
649*433d6423SLionel Sambuc   entry->d_cluster = 0;
650*433d6423SLionel Sambuc 
651*433d6423SLionel Sambuc   while (free_range (&first_cluster, &last_cluster)) {
652*433d6423SLionel Sambuc 	do {
653*433d6423SLionel Sambuc 		unsigned short	nr_clus;
654*433d6423SLionel Sambuc 
655*433d6423SLionel Sambuc 		chunk = lmin ((long) (last_cluster - first_cluster + 1) *
656*433d6423SLionel Sambuc 			     		  cluster_size,
657*433d6423SLionel Sambuc 			      (long) MAX_CLUSTER_SIZE);
658*433d6423SLionel Sambuc 		r = fill(buffer, chunk);
659*433d6423SLionel Sambuc 		if (r == 0) goto done;
660*433d6423SLionel Sambuc 		nr_clus = (r + cluster_size - 1) / cluster_size;
661*433d6423SLionel Sambuc 		disk_io(WRITE, clus_add(first_cluster), buffer, r);
662*433d6423SLionel Sambuc 
663*433d6423SLionel Sambuc 		for (i = 0; i < nr_clus; i ++) {
664*433d6423SLionel Sambuc 			if (entry->d_cluster == 0)
665*433d6423SLionel Sambuc 				cl_no = entry->d_cluster = first_cluster;
666*433d6423SLionel Sambuc 			else {
667*433d6423SLionel Sambuc 				link_fat(cl_no, first_cluster);
668*433d6423SLionel Sambuc 				cl_no = first_cluster;
669*433d6423SLionel Sambuc 			}
670*433d6423SLionel Sambuc 			first_cluster ++;
671*433d6423SLionel Sambuc 		}
672*433d6423SLionel Sambuc 
673*433d6423SLionel Sambuc 		size += r;
674*433d6423SLionel Sambuc 	} while (first_cluster <= last_cluster);
675*433d6423SLionel Sambuc   }
676*433d6423SLionel Sambuc   fprintf (stderr, "%s: disk full. File truncated\n", cmnd);
677*433d6423SLionel Sambuc done:
678*433d6423SLionel Sambuc   if (entry->d_cluster != 0) link_fat(cl_no, LAST_CLUSTER);
679*433d6423SLionel Sambuc   entry->d_size = size;
680*433d6423SLionel Sambuc   fill_date(entry);
681*433d6423SLionel Sambuc   disk_io(WRITE, mark, entry, DIR_SIZE);
682*433d6423SLionel Sambuc 
683*433d6423SLionel Sambuc   if (fat_dirty) flush_fat ();
684*433d6423SLionel Sambuc 
685*433d6423SLionel Sambuc }
686*433d6423SLionel Sambuc 
687*433d6423SLionel Sambuc 
688*433d6423SLionel Sambuc #define SEC_MIN	60L
689*433d6423SLionel Sambuc #define SEC_HOUR	(60L * SEC_MIN)
690*433d6423SLionel Sambuc #define SEC_DAY	(24L * SEC_HOUR)
691*433d6423SLionel Sambuc #define SEC_YEAR	(365L * SEC_DAY)
692*433d6423SLionel Sambuc #define SEC_LYEAR	(366L * SEC_DAY)
693*433d6423SLionel Sambuc 
694*433d6423SLionel Sambuc unsigned short mon_len[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
695*433d6423SLionel Sambuc 
fill_date(entry)696*433d6423SLionel Sambuc void fill_date(entry)
697*433d6423SLionel Sambuc DIRECTORY *entry;
698*433d6423SLionel Sambuc {
699*433d6423SLionel Sambuc   register long cur_time = time(NULL) - DOS_TIME;
700*433d6423SLionel Sambuc   unsigned short year = 0, month = 1, day, hour, minutes, seconds;
701*433d6423SLionel Sambuc   int i;
702*433d6423SLionel Sambuc   long tmp;
703*433d6423SLionel Sambuc 
704*433d6423SLionel Sambuc   if (cur_time < 0)		/* Date not set on booting ... */
705*433d6423SLionel Sambuc 	cur_time = 0;
706*433d6423SLionel Sambuc   for (;;) {
707*433d6423SLionel Sambuc 	tmp = (year % 4 == 0) ? SEC_LYEAR : SEC_YEAR;
708*433d6423SLionel Sambuc 	if (cur_time < tmp) break;
709*433d6423SLionel Sambuc 	cur_time -= tmp;
710*433d6423SLionel Sambuc 	year++;
711*433d6423SLionel Sambuc   }
712*433d6423SLionel Sambuc 
713*433d6423SLionel Sambuc   day = (unsigned short) (cur_time / SEC_DAY);
714*433d6423SLionel Sambuc   cur_time -= (long) day *SEC_DAY;
715*433d6423SLionel Sambuc 
716*433d6423SLionel Sambuc   hour = (unsigned short) (cur_time / SEC_HOUR);
717*433d6423SLionel Sambuc   cur_time -= (long) hour *SEC_HOUR;
718*433d6423SLionel Sambuc 
719*433d6423SLionel Sambuc   minutes = (unsigned short) (cur_time / SEC_MIN);
720*433d6423SLionel Sambuc   cur_time -= (long) minutes *SEC_MIN;
721*433d6423SLionel Sambuc 
722*433d6423SLionel Sambuc   seconds = (unsigned short) cur_time;
723*433d6423SLionel Sambuc 
724*433d6423SLionel Sambuc   mon_len[1] = (year % 4 == 0) ? 29 : 28;
725*433d6423SLionel Sambuc   i = 0;
726*433d6423SLionel Sambuc   while (day >= mon_len[i]) {
727*433d6423SLionel Sambuc 	month++;
728*433d6423SLionel Sambuc 	day -= mon_len[i++];
729*433d6423SLionel Sambuc   }
730*433d6423SLionel Sambuc   day++;
731*433d6423SLionel Sambuc 
732*433d6423SLionel Sambuc   entry->d_date = (year << 9) | (month << 5) | day;
733*433d6423SLionel Sambuc   entry->d_time = (hour << 11) | (minutes << 5) | seconds;
734*433d6423SLionel Sambuc }
735*433d6423SLionel Sambuc 
make_name(dir_ptr,dir_fl)736*433d6423SLionel Sambuc char *make_name(dir_ptr, dir_fl)
737*433d6423SLionel Sambuc register DIRECTORY *dir_ptr;
738*433d6423SLionel Sambuc short dir_fl;
739*433d6423SLionel Sambuc {
740*433d6423SLionel Sambuc   static char name_buf[14];
741*433d6423SLionel Sambuc   register char *ptr = name_buf;
742*433d6423SLionel Sambuc   short i;
743*433d6423SLionel Sambuc 
744*433d6423SLionel Sambuc   for (i = 0; i < 8; i++) *ptr++ = dir_ptr->d_name[i];
745*433d6423SLionel Sambuc 
746*433d6423SLionel Sambuc   while (*--ptr == ' ');
747*433d6423SLionel Sambuc   assert (ptr >= name_buf);
748*433d6423SLionel Sambuc 
749*433d6423SLionel Sambuc   ptr++;
750*433d6423SLionel Sambuc   if (dir_ptr->d_ext[0] != ' ') {
751*433d6423SLionel Sambuc 	*ptr++ = '.';
752*433d6423SLionel Sambuc 	for (i = 0; i < 3; i++) *ptr++ = dir_ptr->d_ext[i];
753*433d6423SLionel Sambuc 	while (*--ptr == ' ');
754*433d6423SLionel Sambuc 	ptr++;
755*433d6423SLionel Sambuc   }
756*433d6423SLionel Sambuc   if (dir_fl) *ptr++ = '/';
757*433d6423SLionel Sambuc   *ptr = '\0';
758*433d6423SLionel Sambuc 
759*433d6423SLionel Sambuc   return name_buf;
760*433d6423SLionel Sambuc }
761*433d6423SLionel Sambuc 
762*433d6423SLionel Sambuc 
fill(buffer,size)763*433d6423SLionel Sambuc int fill(buffer, size)
764*433d6423SLionel Sambuc register char *buffer;
765*433d6423SLionel Sambuc size_t	size;
766*433d6423SLionel Sambuc {
767*433d6423SLionel Sambuc   static BOOL nl_mark = FALSE;
768*433d6423SLionel Sambuc   char *last = &buffer[size];
769*433d6423SLionel Sambuc   char *begin = buffer;
770*433d6423SLionel Sambuc   register int c;
771*433d6423SLionel Sambuc 
772*433d6423SLionel Sambuc   while (buffer < last) {
773*433d6423SLionel Sambuc   	if (nl_mark) {
774*433d6423SLionel Sambuc   		*buffer ++ = '\n';
775*433d6423SLionel Sambuc   		nl_mark = FALSE;
776*433d6423SLionel Sambuc   	} else {
777*433d6423SLionel Sambuc 		c = getchar();
778*433d6423SLionel Sambuc 		if (c == EOF) break;
779*433d6423SLionel Sambuc 		if (Aflag && c == '\n') {
780*433d6423SLionel Sambuc 			*buffer ++ = '\r';
781*433d6423SLionel Sambuc 			nl_mark = TRUE;
782*433d6423SLionel Sambuc 		} else {
783*433d6423SLionel Sambuc 			*buffer++ = c;
784*433d6423SLionel Sambuc 		}
785*433d6423SLionel Sambuc 	}
786*433d6423SLionel Sambuc   }
787*433d6423SLionel Sambuc 
788*433d6423SLionel Sambuc   return (buffer - begin);
789*433d6423SLionel Sambuc }
790*433d6423SLionel Sambuc 
791*433d6423SLionel Sambuc #define HOUR	0xF800		/* Upper 5 bits */
792*433d6423SLionel Sambuc #define MIN	0x07E0		/* Middle 6 bits */
793*433d6423SLionel Sambuc #define YEAR	0xFE00		/* Upper 7 bits */
794*433d6423SLionel Sambuc #define MONTH	0x01E0		/* Mid 4 bits */
795*433d6423SLionel Sambuc #define DAY	0x01F		/* Lowest 5 bits */
796*433d6423SLionel Sambuc 
797*433d6423SLionel Sambuc char *month[] = {
798*433d6423SLionel Sambuc 	 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
799*433d6423SLionel Sambuc 	 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
800*433d6423SLionel Sambuc };
801*433d6423SLionel Sambuc 
xmodes(mode)802*433d6423SLionel Sambuc void xmodes(mode)
803*433d6423SLionel Sambuc int mode;
804*433d6423SLionel Sambuc {
805*433d6423SLionel Sambuc   printf ( "\t%c%c%c%c%c", (mode & SUB_DIR) ? 'd' : '-',
806*433d6423SLionel Sambuc 	     (mode & 02) ? 'h' : '-', (mode & 04) ? 's' : '-',
807*433d6423SLionel Sambuc 	     (mode & 01) ? '-' : 'w', (mode & 0x20) ? 'a' : '-');
808*433d6423SLionel Sambuc }
809*433d6423SLionel Sambuc 
show(dir_ptr,name)810*433d6423SLionel Sambuc void show(dir_ptr, name)
811*433d6423SLionel Sambuc DIRECTORY *dir_ptr;
812*433d6423SLionel Sambuc char *name;
813*433d6423SLionel Sambuc {
814*433d6423SLionel Sambuc   register unsigned short e_date = dir_ptr->d_date;
815*433d6423SLionel Sambuc   register unsigned short e_time = dir_ptr->d_time;
816*433d6423SLionel Sambuc   unsigned short next;
817*433d6423SLionel Sambuc   char bname[20];
818*433d6423SLionel Sambuc   short i = 0;
819*433d6423SLionel Sambuc 
820*433d6423SLionel Sambuc   while (*name && *name != '/') bname[i++] = *name++;
821*433d6423SLionel Sambuc   bname[i] = '\0';
822*433d6423SLionel Sambuc   if (!Lflag) {
823*433d6423SLionel Sambuc 	printf ( "%s\n", bname);
824*433d6423SLionel Sambuc 	return;
825*433d6423SLionel Sambuc   }
826*433d6423SLionel Sambuc   xmodes( (int) dir_ptr->d_attribute);
827*433d6423SLionel Sambuc   printf ( "\t%s%s", bname, strlen(bname) < 8 ? "\t\t" : "\t");
828*433d6423SLionel Sambuc   i = 1;
829*433d6423SLionel Sambuc   if (is_dir(dir_ptr)) {
830*433d6423SLionel Sambuc 	next = dir_ptr->d_cluster;
831*433d6423SLionel Sambuc 	while ((next = next_cluster(next)) != LAST_CLUSTER) i++;
832*433d6423SLionel Sambuc 	printf ("%8ld", (long) i * (long) cluster_size);
833*433d6423SLionel Sambuc   } else
834*433d6423SLionel Sambuc 	printf ("%8ld", dir_ptr->d_size);
835*433d6423SLionel Sambuc   printf (" %02d:%02d %2d %s %d\n", ((e_time & HOUR) >> 11),
836*433d6423SLionel Sambuc 	     ((e_time & MIN) >> 5), (e_date & DAY),
837*433d6423SLionel Sambuc    month[((e_date & MONTH) >> 5) - 1], ((e_date & YEAR) >> 9) + 1980);
838*433d6423SLionel Sambuc }
839*433d6423SLionel Sambuc 
free_blocks()840*433d6423SLionel Sambuc void free_blocks()
841*433d6423SLionel Sambuc {
842*433d6423SLionel Sambuc   register unsigned short cl_no;
843*433d6423SLionel Sambuc   long nr_free = 0;
844*433d6423SLionel Sambuc   long nr_bad = 0;
845*433d6423SLionel Sambuc 
846*433d6423SLionel Sambuc   for (cl_no = 2; cl_no < total_clusters; cl_no++) {
847*433d6423SLionel Sambuc 	switch (next_cluster(cl_no)) {
848*433d6423SLionel Sambuc 	    case FREE:	nr_free++;	break;
849*433d6423SLionel Sambuc 	    case BAD16:	nr_bad++;	break;
850*433d6423SLionel Sambuc 	}
851*433d6423SLionel Sambuc   }
852*433d6423SLionel Sambuc 
853*433d6423SLionel Sambuc   printf ("Free space: %ld bytes.\n", nr_free * (long) cluster_size);
854*433d6423SLionel Sambuc   if (nr_bad != 0)
855*433d6423SLionel Sambuc 	printf ("Bad sectors: %ld bytes.\n", nr_bad * (long) cluster_size);
856*433d6423SLionel Sambuc }
857*433d6423SLionel Sambuc 
858*433d6423SLionel Sambuc 
read_cluster(cluster)859*433d6423SLionel Sambuc DIRECTORY *read_cluster(cluster)
860*433d6423SLionel Sambuc register unsigned int cluster;
861*433d6423SLionel Sambuc {
862*433d6423SLionel Sambuc   register DIRECTORY *sub_dir;
863*433d6423SLionel Sambuc 
864*433d6423SLionel Sambuc   if ((sub_dir = malloc(cluster_size)) == NULL) {
865*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Cannot set break!\n", cmnd);
866*433d6423SLionel Sambuc 	exit(1);
867*433d6423SLionel Sambuc   }
868*433d6423SLionel Sambuc   disk_io(READ, clus_add(cluster), sub_dir, cluster_size);
869*433d6423SLionel Sambuc 
870*433d6423SLionel Sambuc   return sub_dir;
871*433d6423SLionel Sambuc }
872*433d6423SLionel Sambuc 
873*433d6423SLionel Sambuc static unsigned short cl_index = 2;
874*433d6423SLionel Sambuc 
875*433d6423SLionel Sambuc /* find a range of consecutive free clusters. Return TRUE if found
876*433d6423SLionel Sambuc  * and return the first and last cluster in the |*first| and |*last|.
877*433d6423SLionel Sambuc  * If no free clusters are left, return FALSE.
878*433d6423SLionel Sambuc  *
879*433d6423SLionel Sambuc  * Warning: Assumes that all of the range is used before the next call
880*433d6423SLionel Sambuc  *	to free_range or free_cluster.
881*433d6423SLionel Sambuc  */
free_range(first,last)882*433d6423SLionel Sambuc BOOL free_range (first, last)
883*433d6423SLionel Sambuc unsigned short *first, *last;
884*433d6423SLionel Sambuc {
885*433d6423SLionel Sambuc   while (cl_index < total_clusters && next_cluster(cl_index) != FREE)
886*433d6423SLionel Sambuc 	cl_index++;
887*433d6423SLionel Sambuc   if (cl_index >= total_clusters) return FALSE;
888*433d6423SLionel Sambuc   *first = cl_index;
889*433d6423SLionel Sambuc   while (cl_index < total_clusters && next_cluster(cl_index) == FREE)
890*433d6423SLionel Sambuc 	cl_index++;
891*433d6423SLionel Sambuc   *last = cl_index - 1;
892*433d6423SLionel Sambuc   return TRUE;
893*433d6423SLionel Sambuc }
894*433d6423SLionel Sambuc 
895*433d6423SLionel Sambuc 
896*433d6423SLionel Sambuc /* find a free cluster.
897*433d6423SLionel Sambuc  * Return the number of the free cluster or a number > |total_clusters|
898*433d6423SLionel Sambuc  * if none is found.
899*433d6423SLionel Sambuc  * If |leave_fl| is TRUE, the the program will be terminated if
900*433d6423SLionel Sambuc  * no free cluster can be found
901*433d6423SLionel Sambuc  *
902*433d6423SLionel Sambuc  * Warning: Assumes that the cluster is used before the next call
903*433d6423SLionel Sambuc  *	to free_range or free_cluster.
904*433d6423SLionel Sambuc  */
free_cluster(leave_fl)905*433d6423SLionel Sambuc unsigned short free_cluster(leave_fl)
906*433d6423SLionel Sambuc BOOL leave_fl;
907*433d6423SLionel Sambuc {
908*433d6423SLionel Sambuc   while (cl_index < total_clusters && next_cluster(cl_index) != FREE)
909*433d6423SLionel Sambuc 	cl_index++;
910*433d6423SLionel Sambuc 
911*433d6423SLionel Sambuc   if (leave_fl && cl_index >= total_clusters) {
912*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Diskette full. File not added.\n", cmnd);
913*433d6423SLionel Sambuc 	exit(1);
914*433d6423SLionel Sambuc   }
915*433d6423SLionel Sambuc   return cl_index++;
916*433d6423SLionel Sambuc }
917*433d6423SLionel Sambuc 
918*433d6423SLionel Sambuc 
919*433d6423SLionel Sambuc /* read a portion of the fat containing |cl_no| into the cache
920*433d6423SLionel Sambuc  */
read_fat(cl_no)921*433d6423SLionel Sambuc void read_fat (cl_no)
922*433d6423SLionel Sambuc   unsigned int cl_no;
923*433d6423SLionel Sambuc {
924*433d6423SLionel Sambuc 
925*433d6423SLionel Sambuc   if (!cooked_fat) {
926*433d6423SLionel Sambuc   	/* Read the fat for the first time. We have to allocate all the
927*433d6423SLionel Sambuc   	 * buffers
928*433d6423SLionel Sambuc   	 */
929*433d6423SLionel Sambuc   	if (fat_16) {
930*433d6423SLionel Sambuc 		/* FAT consists of little endian shorts. Easy to convert
931*433d6423SLionel Sambuc 		 */
932*433d6423SLionel Sambuc 		if ((cooked_fat = malloc (fat_size)) == NULL) {
933*433d6423SLionel Sambuc 			/* Oops, FAT doesn't fit into memory, just read
934*433d6423SLionel Sambuc 			 * a chunk
935*433d6423SLionel Sambuc 			 */
936*433d6423SLionel Sambuc 			if ((cooked_fat = malloc (COOKED_SIZE)) == NULL) {
937*433d6423SLionel Sambuc 				fprintf (stderr, "%s: not enough memory for FAT cache. Use chmem\n",
938*433d6423SLionel Sambuc 					 cmnd);
939*433d6423SLionel Sambuc 				exit (1);
940*433d6423SLionel Sambuc 			}
941*433d6423SLionel Sambuc 			cache_size = COOKED_SIZE / 2;
942*433d6423SLionel Sambuc 		} else {
943*433d6423SLionel Sambuc 			cache_size = fat_size / 2;
944*433d6423SLionel Sambuc 		}
945*433d6423SLionel Sambuc 	} else {
946*433d6423SLionel Sambuc 		/* 12 bit FAT. Difficult encoding, but small. Keep
947*433d6423SLionel Sambuc 		 * both raw FAT and cooked version in memory.
948*433d6423SLionel Sambuc 		 */
949*433d6423SLionel Sambuc 		if ((cooked_fat = malloc (total_clusters * sizeof (short))) == NULL ||
950*433d6423SLionel Sambuc 		    (raw_fat = malloc (fat_size)) == NULL) {
951*433d6423SLionel Sambuc 			fprintf (stderr, "%s: not enough memory for FAT cache. Use chmem\n",
952*433d6423SLionel Sambuc 				 cmnd);
953*433d6423SLionel Sambuc 			exit (1);
954*433d6423SLionel Sambuc 		}
955*433d6423SLionel Sambuc 		cache_size = total_clusters;
956*433d6423SLionel Sambuc 	}
957*433d6423SLionel Sambuc   }
958*433d6423SLionel Sambuc   fat_low = cl_no / cache_size * cache_size;
959*433d6423SLionel Sambuc   fat_high = fat_low + cache_size - 1;
960*433d6423SLionel Sambuc 
961*433d6423SLionel Sambuc   if (!fat_16) {
962*433d6423SLionel Sambuc   	unsigned short	*cp;
963*433d6423SLionel Sambuc   	unsigned char	*rp;
964*433d6423SLionel Sambuc   	unsigned short	i;
965*433d6423SLionel Sambuc 
966*433d6423SLionel Sambuc 	disk_io (READ, FAT_START, raw_fat, fat_size);
967*433d6423SLionel Sambuc 	for (rp = raw_fat, cp = cooked_fat, i = 0;
968*433d6423SLionel Sambuc 	     i < cache_size;
969*433d6423SLionel Sambuc 	     rp += 3, i += 2) {
970*433d6423SLionel Sambuc 	     	*cp = *rp + ((*(rp + 1) & 0x0f) << 8);
971*433d6423SLionel Sambuc 	     	if (*cp == BAD) *cp = BAD16;
972*433d6423SLionel Sambuc 	     	else if (*cp == LAST_CLUSTER12) *cp = LAST_CLUSTER;
973*433d6423SLionel Sambuc 	     	cp ++;
974*433d6423SLionel Sambuc 	     	*cp = ((*(rp + 1) & 0xf0) >> 4) + (*(rp + 2) << 4);
975*433d6423SLionel Sambuc 	     	if (*cp == BAD) *cp = BAD16;
976*433d6423SLionel Sambuc 	     	else if (*cp == LAST_CLUSTER12) *cp = LAST_CLUSTER;
977*433d6423SLionel Sambuc 	     	cp ++;
978*433d6423SLionel Sambuc 	}
979*433d6423SLionel Sambuc   } else {
980*433d6423SLionel Sambuc 
981*433d6423SLionel Sambuc 	assert (sizeof (short) == 2);
982*433d6423SLionel Sambuc 	assert (CHAR_BIT == 8);		/* just in case */
983*433d6423SLionel Sambuc 
984*433d6423SLionel Sambuc 	disk_io (READ, FAT_START + fat_low * 2, (void *)cooked_fat, cache_size * 2);
985*433d6423SLionel Sambuc 	if (big_endian) {
986*433d6423SLionel Sambuc 		unsigned short	*cp;
987*433d6423SLionel Sambuc 		unsigned char	*rp;
988*433d6423SLionel Sambuc 		unsigned short	i;
989*433d6423SLionel Sambuc 
990*433d6423SLionel Sambuc 		for (i = 0, rp = (unsigned char *)cooked_fat /* sic */, cp = cooked_fat;
991*433d6423SLionel Sambuc 		     i < cache_size;
992*433d6423SLionel Sambuc 		     rp += 2, cp ++, i ++) {
993*433d6423SLionel Sambuc 		     	*cp = c2u2 (rp);
994*433d6423SLionel Sambuc 		}
995*433d6423SLionel Sambuc 	}
996*433d6423SLionel Sambuc   }
997*433d6423SLionel Sambuc }
998*433d6423SLionel Sambuc 
999*433d6423SLionel Sambuc 
1000*433d6423SLionel Sambuc /* flush the fat cache out to disk
1001*433d6423SLionel Sambuc  */
flush_fat()1002*433d6423SLionel Sambuc void flush_fat ()
1003*433d6423SLionel Sambuc {
1004*433d6423SLionel Sambuc   if (fat_16) {
1005*433d6423SLionel Sambuc 	if (big_endian) {
1006*433d6423SLionel Sambuc 		unsigned short	*cp;
1007*433d6423SLionel Sambuc 		unsigned char	*rp;
1008*433d6423SLionel Sambuc 		unsigned short	i;
1009*433d6423SLionel Sambuc 
1010*433d6423SLionel Sambuc 		for (i = 0, rp = (unsigned char *)cooked_fat /* sic */, cp = cooked_fat;
1011*433d6423SLionel Sambuc 		     i < cache_size;
1012*433d6423SLionel Sambuc 		     rp += 2, cp ++, i ++) {
1013*433d6423SLionel Sambuc 		     	*rp = *cp;
1014*433d6423SLionel Sambuc 		     	*(rp + 1) = *cp >> 8;
1015*433d6423SLionel Sambuc 		}
1016*433d6423SLionel Sambuc 	}
1017*433d6423SLionel Sambuc 	disk_io (WRITE, FAT_START + fat_low * 2, (void *)cooked_fat, cache_size * 2);
1018*433d6423SLionel Sambuc 	disk_io (WRITE, FAT_START + fat_size + fat_low * 2, (void *)cooked_fat, cache_size * 2);
1019*433d6423SLionel Sambuc   } else {
1020*433d6423SLionel Sambuc   	unsigned short	*cp;
1021*433d6423SLionel Sambuc   	unsigned char	*rp;
1022*433d6423SLionel Sambuc   	unsigned short	i;
1023*433d6423SLionel Sambuc 
1024*433d6423SLionel Sambuc 	for (rp = raw_fat, cp = cooked_fat, i = 0;
1025*433d6423SLionel Sambuc 	     i < cache_size;
1026*433d6423SLionel Sambuc 	     rp += 3, cp += 2, i += 2) {
1027*433d6423SLionel Sambuc 	     	*rp = *cp;
1028*433d6423SLionel Sambuc 	     	*(rp + 1) = ((*cp & 0xf00) >> 8) |
1029*433d6423SLionel Sambuc 	     		    ((*(cp + 1) & 0x00f) << 4);
1030*433d6423SLionel Sambuc 	     	*(rp + 2) = ((*(cp + 1) & 0xff0) >> 4);
1031*433d6423SLionel Sambuc 	}
1032*433d6423SLionel Sambuc 	disk_io (WRITE, FAT_START, raw_fat, fat_size);
1033*433d6423SLionel Sambuc 	disk_io (WRITE, FAT_START + fat_size, raw_fat, fat_size);
1034*433d6423SLionel Sambuc   }
1035*433d6423SLionel Sambuc }
1036*433d6423SLionel Sambuc 
1037*433d6423SLionel Sambuc 
1038*433d6423SLionel Sambuc /* make cl_2 the successor of cl_1
1039*433d6423SLionel Sambuc  */
link_fat(cl_1,cl_2)1040*433d6423SLionel Sambuc void link_fat(cl_1, cl_2)
1041*433d6423SLionel Sambuc unsigned int cl_1;
1042*433d6423SLionel Sambuc unsigned int cl_2;
1043*433d6423SLionel Sambuc {
1044*433d6423SLionel Sambuc   if (cl_1 < fat_low || cl_1 > fat_high) {
1045*433d6423SLionel Sambuc   	if (fat_dirty) flush_fat ();
1046*433d6423SLionel Sambuc   	read_fat (cl_1);
1047*433d6423SLionel Sambuc   }
1048*433d6423SLionel Sambuc   cooked_fat [cl_1 - fat_low] = cl_2;
1049*433d6423SLionel Sambuc   fat_dirty = TRUE;
1050*433d6423SLionel Sambuc }
1051*433d6423SLionel Sambuc 
1052*433d6423SLionel Sambuc 
next_cluster(cl_no)1053*433d6423SLionel Sambuc unsigned short next_cluster(cl_no)
1054*433d6423SLionel Sambuc register unsigned int cl_no;
1055*433d6423SLionel Sambuc {
1056*433d6423SLionel Sambuc   if (cl_no < fat_low || cl_no > fat_high) {
1057*433d6423SLionel Sambuc   	if (fat_dirty) flush_fat ();
1058*433d6423SLionel Sambuc   	read_fat (cl_no);
1059*433d6423SLionel Sambuc   }
1060*433d6423SLionel Sambuc   return cooked_fat [cl_no - fat_low];
1061*433d6423SLionel Sambuc }
1062*433d6423SLionel Sambuc 
slash(str)1063*433d6423SLionel Sambuc char *slash(str)
1064*433d6423SLionel Sambuc register char *str;
1065*433d6423SLionel Sambuc {
1066*433d6423SLionel Sambuc   register char *result = str;
1067*433d6423SLionel Sambuc 
1068*433d6423SLionel Sambuc   while (*str)
1069*433d6423SLionel Sambuc 	if (*str++ == '/') result = str;
1070*433d6423SLionel Sambuc 
1071*433d6423SLionel Sambuc   return result;
1072*433d6423SLionel Sambuc }
1073*433d6423SLionel Sambuc 
add_path(file,slash_fl)1074*433d6423SLionel Sambuc void add_path(file, slash_fl)
1075*433d6423SLionel Sambuc char *file;
1076*433d6423SLionel Sambuc BOOL slash_fl;
1077*433d6423SLionel Sambuc {
1078*433d6423SLionel Sambuc   register char *ptr = path;
1079*433d6423SLionel Sambuc 
1080*433d6423SLionel Sambuc   while (*ptr) ptr++;
1081*433d6423SLionel Sambuc 
1082*433d6423SLionel Sambuc   if (file == NULL) {
1083*433d6423SLionel Sambuc 	if (ptr != path) ptr--;
1084*433d6423SLionel Sambuc 	if (ptr != path) do {
1085*433d6423SLionel Sambuc 			ptr--;
1086*433d6423SLionel Sambuc 		} while (*ptr != '/' && ptr != path);
1087*433d6423SLionel Sambuc 	if (ptr != path && !slash_fl) *ptr++ = '/';
1088*433d6423SLionel Sambuc 	*ptr = '\0';
1089*433d6423SLionel Sambuc   } else
1090*433d6423SLionel Sambuc 	strcpy (ptr, file);
1091*433d6423SLionel Sambuc }
1092*433d6423SLionel Sambuc 
1093*433d6423SLionel Sambuc 
disk_io(op,seek,address,bytes)1094*433d6423SLionel Sambuc void disk_io(op, seek, address, bytes)
1095*433d6423SLionel Sambuc register BOOL op;
1096*433d6423SLionel Sambuc unsigned long seek;
1097*433d6423SLionel Sambuc void *address;
1098*433d6423SLionel Sambuc register unsigned bytes;
1099*433d6423SLionel Sambuc {
1100*433d6423SLionel Sambuc   unsigned int r;
1101*433d6423SLionel Sambuc 
1102*433d6423SLionel Sambuc   if (lseek(disk, seek, SEEK_SET) < 0L) {
1103*433d6423SLionel Sambuc 	fflush (stdout);
1104*433d6423SLionel Sambuc 	fprintf (stderr, "%s: Bad lseek: %s\n", cmnd, strerror (errno));
1105*433d6423SLionel Sambuc 	exit(1);
1106*433d6423SLionel Sambuc   }
1107*433d6423SLionel Sambuc   if (op == READ)
1108*433d6423SLionel Sambuc 	r = read(disk, (char *) address, bytes);
1109*433d6423SLionel Sambuc   else {
1110*433d6423SLionel Sambuc 	r = write(disk, (char *) address, bytes);
1111*433d6423SLionel Sambuc   }
1112*433d6423SLionel Sambuc 
1113*433d6423SLionel Sambuc   if (r != bytes) {
1114*433d6423SLionel Sambuc   	fprintf (stderr, "%s: read error: %s\n", cmnd, strerror (errno));
1115*433d6423SLionel Sambuc   	exit (1);
1116*433d6423SLionel Sambuc   }
1117*433d6423SLionel Sambuc }
1118