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