xref: /aosp_15_r20/external/mtools/msdos.h (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
1*d5c9a868SElliott Hughes #ifndef MTOOLS_MSDOS_H
2*d5c9a868SElliott Hughes #define MTOOLS_MSDOS_H
3*d5c9a868SElliott Hughes 
4*d5c9a868SElliott Hughes /*  Copyright 1986-1992 Emmet P. Gray.
5*d5c9a868SElliott Hughes  *  Copyright 1996-1998,2000-2003,2006,2007,2009 Alain Knaff.
6*d5c9a868SElliott Hughes  *  This file is part of mtools.
7*d5c9a868SElliott Hughes  *
8*d5c9a868SElliott Hughes  *  Mtools is free software: you can redistribute it and/or modify
9*d5c9a868SElliott Hughes  *  it under the terms of the GNU General Public License as published by
10*d5c9a868SElliott Hughes  *  the Free Software Foundation, either version 3 of the License, or
11*d5c9a868SElliott Hughes  *  (at your option) any later version.
12*d5c9a868SElliott Hughes  *
13*d5c9a868SElliott Hughes  *  Mtools is distributed in the hope that it will be useful,
14*d5c9a868SElliott Hughes  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15*d5c9a868SElliott Hughes  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*d5c9a868SElliott Hughes  *  GNU General Public License for more details.
17*d5c9a868SElliott Hughes  *
18*d5c9a868SElliott Hughes  *  You should have received a copy of the GNU General Public License
19*d5c9a868SElliott Hughes  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
20*d5c9a868SElliott Hughes  *
21*d5c9a868SElliott Hughes  * msdos common header file
22*d5c9a868SElliott Hughes  */
23*d5c9a868SElliott Hughes 
24*d5c9a868SElliott Hughes #define MAX_SECTOR	8192   		/* largest sector size */
25*d5c9a868SElliott Hughes #define MDIR_SIZE	32		/* MSDOS directory entry size in bytes*/
26*d5c9a868SElliott Hughes #define MAX_CLUSTER	8192		/* largest cluster size */
27*d5c9a868SElliott Hughes #ifndef MAX_PATH
28*d5c9a868SElliott Hughes #define MAX_PATH	128		/* largest MSDOS path length */
29*d5c9a868SElliott Hughes #endif
30*d5c9a868SElliott Hughes #define MAX_DIR_SECS	64		/* largest directory (in sectors) */
31*d5c9a868SElliott Hughes #define MSECTOR_SIZE    msector_size
32*d5c9a868SElliott Hughes 
33*d5c9a868SElliott Hughes #define NEW		1
34*d5c9a868SElliott Hughes #define OLD		0
35*d5c9a868SElliott Hughes 
36*d5c9a868SElliott Hughes #define _WORD(x) ((uint16_t)((unsigned char)(x)[0] + (((unsigned char)(x)[1]) << 8)))
37*d5c9a868SElliott Hughes #define _DWORD(x) ((uint32_t)(_WORD(x) + (_WORD((x)+2) << 16)))
38*d5c9a868SElliott Hughes 
39*d5c9a868SElliott Hughes #define DELMARK ((char) 0xe5)
40*d5c9a868SElliott Hughes #define ENDMARK ((char) 0x00)
41*d5c9a868SElliott Hughes 
42*d5c9a868SElliott Hughes struct directory {
43*d5c9a868SElliott Hughes 	char name[8];			/*  0 file name */
44*d5c9a868SElliott Hughes 	char ext[3];			/*  8 file extension */
45*d5c9a868SElliott Hughes 	unsigned char attr;		/* 11 attribute byte */
46*d5c9a868SElliott Hughes 	unsigned char Case;		/* 12 case of short filename */
47*d5c9a868SElliott Hughes 	unsigned char ctime_ms;		/* 13 creation time, milliseconds (?) */
48*d5c9a868SElliott Hughes 	unsigned char ctime[2];		/* 14 creation time */
49*d5c9a868SElliott Hughes 	unsigned char cdate[2];		/* 16 creation date */
50*d5c9a868SElliott Hughes 	unsigned char adate[2];		/* 18 last access date */
51*d5c9a868SElliott Hughes 	unsigned char startHi[2];	/* 20 start cluster, Hi */
52*d5c9a868SElliott Hughes 	unsigned char time[2];		/* 22 time stamp */
53*d5c9a868SElliott Hughes 	unsigned char date[2];		/* 24 date stamp */
54*d5c9a868SElliott Hughes 	unsigned char start[2];		/* 26 starting cluster number */
55*d5c9a868SElliott Hughes 	unsigned char size[4];		/* 28 size of the file */
56*d5c9a868SElliott Hughes };
57*d5c9a868SElliott Hughes 
58*d5c9a868SElliott Hughes #define EXTCASE 0x10
59*d5c9a868SElliott Hughes #define BASECASE 0x8
60*d5c9a868SElliott Hughes 
61*d5c9a868SElliott Hughes #define MAX16 0xffff
62*d5c9a868SElliott Hughes #define MAX32 0xffffffff
63*d5c9a868SElliott Hughes #define MAX_SIZE 0x7fffffff
64*d5c9a868SElliott Hughes 
65*d5c9a868SElliott Hughes #define FILE_SIZE(dir)  (_DWORD((dir)->size))
66*d5c9a868SElliott Hughes #define START(dir) (_WORD((dir)->start))
67*d5c9a868SElliott Hughes #define STARTHI(dir) (_WORD((dir)->startHi))
68*d5c9a868SElliott Hughes 
69*d5c9a868SElliott Hughes /* ASSUMPTION: long is at least 32 bits */
UNUSED(static __inline__ void set_dword (unsigned char * data,uint32_t value))70*d5c9a868SElliott Hughes UNUSED(static __inline__ void set_dword(unsigned char *data, uint32_t value))
71*d5c9a868SElliott Hughes {
72*d5c9a868SElliott Hughes 	data[3] = (value >> 24) & 0xff;
73*d5c9a868SElliott Hughes 	data[2] = (value >> 16) & 0xff;
74*d5c9a868SElliott Hughes 	data[1] = (value >>  8) & 0xff;
75*d5c9a868SElliott Hughes 	data[0] = (value >>  0) & 0xff;
76*d5c9a868SElliott Hughes }
77*d5c9a868SElliott Hughes 
78*d5c9a868SElliott Hughes 
79*d5c9a868SElliott Hughes /* ASSUMPTION: short is at least 16 bits */
UNUSED(static __inline__ void set_word (unsigned char * data,unsigned short value))80*d5c9a868SElliott Hughes UNUSED(static __inline__ void set_word(unsigned char *data, unsigned short value))
81*d5c9a868SElliott Hughes {
82*d5c9a868SElliott Hughes 	data[1] = (value >>  8) & 0xff;
83*d5c9a868SElliott Hughes 	data[0] = (value >>  0) & 0xff;
84*d5c9a868SElliott Hughes }
85*d5c9a868SElliott Hughes 
86*d5c9a868SElliott Hughes 
87*d5c9a868SElliott Hughes /*
88*d5c9a868SElliott Hughes  *	    hi byte     |    low byte
89*d5c9a868SElliott Hughes  *	|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
90*d5c9a868SElliott Hughes  *  | | | | | | | | | | | | | | | | |
91*d5c9a868SElliott Hughes  *  \   7 bits    /\4 bits/\ 5 bits /
92*d5c9a868SElliott Hughes  *     year +80     month     day
93*d5c9a868SElliott Hughes  */
94*d5c9a868SElliott Hughes #define	DOS_YEAR(dir) (((dir)->date[1] >> 1) + 1980)
95*d5c9a868SElliott Hughes #define	DOS_MONTH(dir) (((((dir)->date[1]&0x1) << 3) + ((dir)->date[0] >> 5)))
96*d5c9a868SElliott Hughes #define	DOS_DAY(dir) ((dir)->date[0] & 0x1f)
97*d5c9a868SElliott Hughes 
98*d5c9a868SElliott Hughes /*
99*d5c9a868SElliott Hughes  *	    hi byte     |    low byte
100*d5c9a868SElliott Hughes  *	|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
101*d5c9a868SElliott Hughes  *      | | | | | | | | | | | | | | | | |
102*d5c9a868SElliott Hughes  *      \  5 bits /\  6 bits  /\ 5 bits /
103*d5c9a868SElliott Hughes  *         hour      minutes     sec*2
104*d5c9a868SElliott Hughes  */
105*d5c9a868SElliott Hughes #define	DOS_HOUR(dir) ((dir)->time[1] >> 3)
106*d5c9a868SElliott Hughes #define	DOS_MINUTE(dir) (((((dir)->time[1]&0x7) << 3) + ((dir)->time[0] >> 5)))
107*d5c9a868SElliott Hughes #define	DOS_SEC(dir) (((dir)->time[0] & 0x1f) * 2)
108*d5c9a868SElliott Hughes 
109*d5c9a868SElliott Hughes 
110*d5c9a868SElliott Hughes typedef struct InfoSector_t {
111*d5c9a868SElliott Hughes 	unsigned char signature1[4];
112*d5c9a868SElliott Hughes 	unsigned char filler1[0x1e0];
113*d5c9a868SElliott Hughes 	unsigned char signature2[4];
114*d5c9a868SElliott Hughes 	unsigned char count[4];
115*d5c9a868SElliott Hughes 	unsigned char pos[4];
116*d5c9a868SElliott Hughes 	unsigned char filler2[14];
117*d5c9a868SElliott Hughes 	unsigned char signature3[2];
118*d5c9a868SElliott Hughes } InfoSector_t;
119*d5c9a868SElliott Hughes 
120*d5c9a868SElliott Hughes #define INFOSECT_SIGNATURE1 0x41615252
121*d5c9a868SElliott Hughes #define INFOSECT_SIGNATURE2 0x61417272
122*d5c9a868SElliott Hughes 
123*d5c9a868SElliott Hughes 
124*d5c9a868SElliott Hughes typedef struct label_blk_t {
125*d5c9a868SElliott Hughes 	unsigned char physdrive;	/* 36 physical drive ? */
126*d5c9a868SElliott Hughes 	unsigned char reserved;		/* 37 reserved */
127*d5c9a868SElliott Hughes 	unsigned char dos4;		/* 38 dos > 4.0 diskette */
128*d5c9a868SElliott Hughes 	unsigned char serial[4];       	/* 39 serial number */
129*d5c9a868SElliott Hughes 	char label[11];			/* 43 disk label */
130*d5c9a868SElliott Hughes 	char fat_type[8];		/* 54 FAT type */
131*d5c9a868SElliott Hughes } label_blk_t;
132*d5c9a868SElliott Hughes 
133*d5c9a868SElliott Hughes #define has_BPB4 (labelBlock->dos4 == 0x28 || labelBlock->dos4 == 0x29)
134*d5c9a868SElliott Hughes 
135*d5c9a868SElliott Hughes /* FAT32 specific info in the bootsector */
136*d5c9a868SElliott Hughes struct fat32_t {
137*d5c9a868SElliott Hughes 	unsigned char bigFat[4];	/* 36 nb of sectors per FAT */
138*d5c9a868SElliott Hughes 	unsigned char extFlags[2];     	/* 40 extension flags */
139*d5c9a868SElliott Hughes 	unsigned char fsVersion[2];	/* 42 ? */
140*d5c9a868SElliott Hughes 	unsigned char rootCluster[4];	/* 44 start cluster of root dir */
141*d5c9a868SElliott Hughes 	unsigned char infoSector[2];	/* 48 changeable global info */
142*d5c9a868SElliott Hughes 	unsigned char backupBoot[2];	/* 50 back up boot sector */
143*d5c9a868SElliott Hughes 	unsigned char reserved[6];	/* 52 ? */
144*d5c9a868SElliott Hughes 	unsigned char reserved2[6];	/* 58 ? */
145*d5c9a868SElliott Hughes 	struct label_blk_t labelBlock;
146*d5c9a868SElliott Hughes }; /* ends at 58 */
147*d5c9a868SElliott Hughes 
148*d5c9a868SElliott Hughes typedef struct oldboot_t {
149*d5c9a868SElliott Hughes 	struct label_blk_t labelBlock;
150*d5c9a868SElliott Hughes 	unsigned char res_2m;		/* 62 reserved by 2M */
151*d5c9a868SElliott Hughes 	unsigned char CheckSum;		/* 63 2M checksum (not used) */
152*d5c9a868SElliott Hughes 	unsigned char fmt_2mf;		/* 64 2MF format version */
153*d5c9a868SElliott Hughes 	unsigned char wt;		/* 65 1 if write track after format */
154*d5c9a868SElliott Hughes 	unsigned char rate_0;		/* 66 data transfer rate on track 0 */
155*d5c9a868SElliott Hughes 	unsigned char rate_any;		/* 67 data transfer rate on track<>0 */
156*d5c9a868SElliott Hughes 	unsigned char BootP[2];		/* 68 offset to boot program */
157*d5c9a868SElliott Hughes 	unsigned char Infp0[2];		/* 70 T1: information for track 0 */
158*d5c9a868SElliott Hughes 	unsigned char InfpX[2];		/* 72 T2: information for track<>0 */
159*d5c9a868SElliott Hughes 	unsigned char InfTm[2];		/* 74 T3: track sectors size table */
160*d5c9a868SElliott Hughes 	unsigned char DateF[2];		/* 76 Format date */
161*d5c9a868SElliott Hughes 	unsigned char TimeF[2];		/* 78 Format time */
162*d5c9a868SElliott Hughes 	unsigned char junk[1024 - 80];	/* 80 remaining data */
163*d5c9a868SElliott Hughes } oldboot_t;
164*d5c9a868SElliott Hughes 
165*d5c9a868SElliott Hughes struct bootsector_s {
166*d5c9a868SElliott Hughes 	unsigned char jump[3];		/* 0  Jump to boot code */
167*d5c9a868SElliott Hughes 	char banner[8] NONULLTERM; 	/* 3  OEM name & version */
168*d5c9a868SElliott Hughes 	unsigned char secsiz[2];	/* 11 Bytes per sector hopefully 512 */
169*d5c9a868SElliott Hughes 	unsigned char clsiz;    	/* 13 Cluster size in sectors */
170*d5c9a868SElliott Hughes 	unsigned char nrsvsect[2];	/* 14 Number of reserved (boot) sectors */
171*d5c9a868SElliott Hughes 	unsigned char nfat;		/* 16 Number of FAT tables hopefully 2 */
172*d5c9a868SElliott Hughes 	unsigned char dirents[2];	/* 17 Number of directory slots */
173*d5c9a868SElliott Hughes 	unsigned char psect[2]; 	/* 19 Total sectors on disk */
174*d5c9a868SElliott Hughes 	unsigned char descr;		/* 21 Media descriptor=first byte of FAT */
175*d5c9a868SElliott Hughes 	unsigned char fatlen[2];	/* 22 Sectors in FAT */
176*d5c9a868SElliott Hughes 	unsigned char nsect[2];		/* 24 Sectors/track */
177*d5c9a868SElliott Hughes 	unsigned char nheads[2];	/* 26 Heads */
178*d5c9a868SElliott Hughes 	unsigned char nhs[4];		/* 28 number of hidden sectors */
179*d5c9a868SElliott Hughes 	unsigned char bigsect[4];	/* 32 big total sectors */
180*d5c9a868SElliott Hughes 
181*d5c9a868SElliott Hughes 	union {
182*d5c9a868SElliott Hughes 		struct fat32_t fat32;
183*d5c9a868SElliott Hughes 		struct oldboot_t old;
184*d5c9a868SElliott Hughes 	} ext;
185*d5c9a868SElliott Hughes };
186*d5c9a868SElliott Hughes 
187*d5c9a868SElliott Hughes #define MAX_BOOT 4096
188*d5c9a868SElliott Hughes 
189*d5c9a868SElliott Hughes union bootsector {
190*d5c9a868SElliott Hughes 	unsigned char bytes[MAX_BOOT];
191*d5c9a868SElliott Hughes 	char characters[MAX_BOOT];
192*d5c9a868SElliott Hughes 	struct bootsector_s boot;
193*d5c9a868SElliott Hughes };
194*d5c9a868SElliott Hughes 
195*d5c9a868SElliott Hughes #define CHAR(x) (boot->x[0])
196*d5c9a868SElliott Hughes #define WORD(x) (_WORD(boot->boot.x))
197*d5c9a868SElliott Hughes #define DWORD(x) (_DWORD(boot->boot.x))
198*d5c9a868SElliott Hughes 
199*d5c9a868SElliott Hughes #define WORD_S(x) (_WORD(boot.boot.x))
200*d5c9a868SElliott Hughes #define DWORD_S(x) (_DWORD(boot.boot.x))
201*d5c9a868SElliott Hughes 
202*d5c9a868SElliott Hughes #define OFFSET(x) (((char *) (boot->x)) - ((char *)(boot->jump)))
203*d5c9a868SElliott Hughes 
204*d5c9a868SElliott Hughes /* max FAT12/FAT16 sizes, according to
205*d5c9a868SElliott Hughes 
206*d5c9a868SElliott Hughes  https://staff.washington.edu/dittrich/misc/fatgen103.pdf
207*d5c9a868SElliott Hughes  https://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc
208*d5c9a868SElliott Hughes 
209*d5c9a868SElliott Hughes  interestingly enough, another Microsoft document
210*d5c9a868SElliott Hughes  [http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b67321]
211*d5c9a868SElliott Hughes  gives different values, but the first seems to be more sure about
212*d5c9a868SElliott Hughes  itself, so we believe that one ;-)
213*d5c9a868SElliott Hughes */
214*d5c9a868SElliott Hughes #define FAT12 0x0ff5 /* max. number + 1 of clusters described by a 12 bit FAT */
215*d5c9a868SElliott Hughes #define FAT16 0xfff5 /* max number + 1 of clusters for a 16 bit FAT */
216*d5c9a868SElliott Hughes #define FAT32 0xffffff5 /* max number + 1 of clusters for a 32 bit FAT */
217*d5c9a868SElliott Hughes 
218*d5c9a868SElliott Hughes #define ATTR_ARCHIVE 0x20
219*d5c9a868SElliott Hughes #define ATTR_DIR 0x10
220*d5c9a868SElliott Hughes #define ATTR_LABEL 0x8
221*d5c9a868SElliott Hughes #define ATTR_SYSTEM 0x4
222*d5c9a868SElliott Hughes #define ATTR_HIDDEN 0x2
223*d5c9a868SElliott Hughes #define ATTR_READONLY 0x1
224*d5c9a868SElliott Hughes 
225*d5c9a868SElliott Hughes #define HAS_BIT(entry,x) ((entry)->dir.attr & (x))
226*d5c9a868SElliott Hughes 
227*d5c9a868SElliott Hughes #define IS_ARCHIVE(entry) (HAS_BIT((entry),ATTR_ARCHIVE))
228*d5c9a868SElliott Hughes #define IS_DIR(entry) (HAS_BIT((entry),ATTR_DIR))
229*d5c9a868SElliott Hughes #define IS_LABEL(entry) (HAS_BIT((entry),ATTR_LABEL))
230*d5c9a868SElliott Hughes #define IS_SYSTEM(entry) (HAS_BIT((entry),ATTR_SYSTEM))
231*d5c9a868SElliott Hughes #define IS_HIDDEN(entry) (HAS_BIT((entry),ATTR_HIDDEN))
232*d5c9a868SElliott Hughes #define IS_READONLY(entry) (HAS_BIT((entry),ATTR_READONLY))
233*d5c9a868SElliott Hughes 
234*d5c9a868SElliott Hughes 
235*d5c9a868SElliott Hughes #define MAX_BYTES_PER_CLUSTER (32*1024)
236*d5c9a868SElliott Hughes /* Experimentally, it turns out that DOS only accepts cluster sizes
237*d5c9a868SElliott Hughes  * which are powers of two, and less than 128 sectors (else it gets a
238*d5c9a868SElliott Hughes  * divide overflow) */
239*d5c9a868SElliott Hughes 
240*d5c9a868SElliott Hughes 
241*d5c9a868SElliott Hughes #define FAT_SIZE(bits, sec_siz, clusters) \
242*d5c9a868SElliott Hughes 	((((clusters)+2) * ((bits)/4) - 1) / 2 / (sec_siz) + 1)
243*d5c9a868SElliott Hughes 
244*d5c9a868SElliott Hughes #define NEEDED_FAT_SIZE(x) FAT_SIZE((x)->fat_bits, (x)->sector_size, \
245*d5c9a868SElliott Hughes 				    (x)->num_clus)
246*d5c9a868SElliott Hughes 
247*d5c9a868SElliott Hughes /* disk size taken by FAT and clusters */
248*d5c9a868SElliott Hughes #define DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) \
249*d5c9a868SElliott Hughes 	((n) * FAT_SIZE(bits, sec_siz, clusters) + \
250*d5c9a868SElliott Hughes 	 (clusters) * (cluster_size))
251*d5c9a868SElliott Hughes 
252*d5c9a868SElliott Hughes /* approx. total disk size: assume 1 boot sector and one directory sector */
253*d5c9a868SElliott Hughes 
254*d5c9a868SElliott Hughes extern const char *mversion;
255*d5c9a868SElliott Hughes extern const char *mdate;
256*d5c9a868SElliott Hughes extern const char *mformat_banner;
257*d5c9a868SElliott Hughes 
258*d5c9a868SElliott Hughes extern char *Version;
259*d5c9a868SElliott Hughes extern char *Date;
260*d5c9a868SElliott Hughes 
261*d5c9a868SElliott Hughes 
262*d5c9a868SElliott Hughes int init(char drive, int mode);
263*d5c9a868SElliott Hughes 
264*d5c9a868SElliott Hughes #define MT_READ 1
265*d5c9a868SElliott Hughes #define MT_WRITE 2
266*d5c9a868SElliott Hughes 
267*d5c9a868SElliott Hughes #endif
268*d5c9a868SElliott Hughes 
269