embox

Форк
0
/
fat_common.c 
2114 строк · 55.0 Кб
1
/**
2
 * @file
3
 * @brief  VFS-independent part of FAT driver
4
 * @date   9 Apr 2015
5
 * @author Denis Deryugin
6
 */
7
#include <util/log.h>
8

9
#include <assert.h>
10
#include <errno.h>
11
#include <fcntl.h>
12
#include <limits.h>
13
#include <stdbool.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <ctype.h>
18

19
#include <drivers/block_dev.h>
20
#include <fs/dir_context.h>
21
#include <fs/inode.h>
22
#include <fs/inode_operation.h>
23
#include <fs/mount.h>
24
#include <fs/super_block.h>
25

26
#include <fs/mbr.h>
27

28
#include "fat.h"
29

30
#include <util/log.h>
31
#include <util/math.h>
32

33
#include <framework/mod/options.h>
34

35
#define FAT_USE_LONG_NAMES OPTION_GET(BOOLEAN, fat_max_sector_size)
36

37
#if OPTION_GET(STRING, log_level) >= 4
38
void fat_volinfo_print(struct volinfo *volinfo) {
39
	log_debug("volinfo->label(%s)", volinfo->label);
40
	log_debug("volinfo->unit(%x)", volinfo->unit);
41
	log_debug("volinfo->filesystem(%x)", volinfo->filesystem);
42
	log_debug("volinfo->startsector(%d)", volinfo->startsector);
43
	log_debug("volinfo->bytepersec(%d)", volinfo->bytepersec);
44
	log_debug("volinfo->secperclus(%d)", volinfo->secperclus);
45
	log_debug("volinfo->reservedsecs(%d)", volinfo->reservedsecs);
46
	log_debug("volinfo->numsecs(%d)", volinfo->numsecs);
47
	log_debug("volinfo->secperfat(%d)", volinfo->secperfat);
48
	log_debug("volinfo->rootentries(%d)", volinfo->rootentries);
49
	log_debug("volinfo->numclusters(%d)", volinfo->numclusters);
50
	log_debug("volinfo->fat1(%d)", volinfo->fat1);
51
	log_debug("volinfo->rootdir(%d)", volinfo->rootdir);
52
	log_debug("volinfo->dataarea(%d)", volinfo->dataarea);
53
}
54
#else
55
#define fat_volinfo_print(volinfo)
56
#endif
57

58
#define LABEL    "EMBOX_DISK " /* Whitespace-padded 11-char string */
59
#define SYSTEM12 "FAT12   "
60
#define SYSTEM16 "FAT16   "
61
#define SYSTEM32 "FAT32   "
62

63
uint8_t fat_sector_buff[FAT_MAX_SECTOR_SIZE] __attribute__((aligned(16)));
64

65
static const char bootcode[130] =
66
	{ 0x0e, 0x1f, 0xbe, 0x5b, 0x7c, 0xac, 0x22, 0xc0, 0x74, 0x0b,
67
	  0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10, 0x5e, 0xeb,
68
	  0xf0, 0x32, 0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x54,
69
	  0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74,
70
	  0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
71
	  0x65, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x2e, 0x20, 0x20, 0x50,
72
	  0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x65,
73
	  0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61,
74
	  0x62, 0x6c, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79,
75
	  0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72, 0x65, 0x73,
76
	  0x73, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20,
77
	  0x74, 0x6f, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61,
78
	  0x69, 0x6e, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00 };
79

80
static uint32_t fat_dir_rewind(struct dirinfo *di, int n);
81
static uint32_t fat_write_de(struct dirinfo *di, struct fat_dirent *de);
82
static uint32_t fat_get_free_entries(struct dirinfo *dir, int n);
83
static uint32_t fat_dir_extend(struct dirinfo *di);
84
int fat_read_sector(struct fat_fs_info *fsi, uint8_t *buffer, uint32_t sector) {
85
	size_t ret;
86
	int blk;
87
	int blkpersec = fsi->vi.bytepersec / fsi->bdev->block_size;
88

89
	log_debug("sector(%d), fsi: bytepersec(%d), bdev->block_size(%d)",
90
			sector, fsi->vi.bytepersec, fsi->bdev->block_size);
91
	blk = sector * blkpersec;
92

93
	ret = block_dev_read(fsi->bdev, (char*) buffer, fsi->vi.bytepersec, blk);
94
	if (ret != fsi->vi.bytepersec)
95
		return DFS_ERRMISC;
96
	else
97
		return DFS_OK;
98
}
99

100
int fat_write_sector(struct fat_fs_info *fsi, uint8_t *buffer, uint32_t sector) {
101
	size_t ret;
102
	int blk;
103
	int blkpersec = fsi->vi.bytepersec / fsi->bdev->block_size;
104

105
	log_debug("sector(%d), fsi: bytepersec(%d), bdev->block_size(%d)",
106
			sector, fsi->vi.bytepersec, fsi->bdev->block_size);
107

108
	blk = sector * blkpersec;
109
	ret = block_dev_write(fsi->bdev, (char*) buffer, fsi->vi.bytepersec, blk);
110
	if (ret != fsi->vi.bytepersec)
111
		return DFS_ERRMISC;
112
	else
113
		return DFS_OK;
114
}
115

116
uint32_t fat_current_dirsector(struct dirinfo *di) {
117
	struct fat_fs_info *fsi = di->fi.fsi;
118
	struct volinfo *vi = &fsi->vi;
119

120
	if (di->fi.dirsector == 0 &&
121
			(vi->filesystem == FAT12 || vi->filesystem == FAT16)) {
122
		return fsi->vi.secperclus * di->currentcluster + di->currentsector;
123
	} else {
124
		return fat_sec_by_clus(fsi, di->currentcluster) + di->currentsector;
125
	}
126
}
127
/**
128
* @brief Read related dir entries into dir buffer
129
*
130
* @param fsi Used to determine bdev and fat type (12/16/32)
131
* @param di  Pointer to dirinfo structure
132
*
133
* @return Negative error number
134
* @retval 0 Success
135
*/
136
int read_dir_buf(struct dirinfo *di) {
137
	struct fat_fs_info *fsi = di->fi.fsi;
138
	int sector;
139

140
	sector = fat_current_dirsector(di);
141

142
	return fat_read_sector(fsi, di->p_scratch, sector);
143
}
144

145
uint32_t fat_direntry_get_clus(struct fat_dirent *de) {
146
	return (uint32_t) de->startclus_l_l |
147
	  ((uint32_t) de->startclus_l_h) << 8 |
148
	  ((uint32_t) de->startclus_h_l) << 16 |
149
	  ((uint32_t) de->startclus_h_h) << 24;
150
}
151

152
void fat_direntry_set_clus(struct fat_dirent *de, uint32_t clus) {
153
	de->startclus_l_l = clus & 0xff;
154
	de->startclus_l_h = (clus & 0xff00) >> 8;
155
	de->startclus_h_l = (clus & 0xff0000) >> 16;
156
	de->startclus_h_h = (clus & 0xff000000) >> 24;
157
}
158

159
uint32_t fat_direntry_get_size(struct fat_dirent *de) {
160
	return  (uint32_t) de->filesize_0 |
161
		((uint32_t) de->filesize_1) << 8 |
162
		((uint32_t) de->filesize_2) << 16 |
163
		((uint32_t) de->filesize_3) << 24;
164
}
165

166
void fat_direntry_set_size(struct fat_dirent *de, uint32_t size) {
167
	de->filesize_0 = size & 0xff;
168
	de->filesize_1 = (size & 0xff00) >> 8;
169
	de->filesize_2 = (size & 0xff0000) >> 16;
170
	de->filesize_3 = (size & 0xff000000) >> 24;
171
}
172
/**
173
 * @brief Format given block device
174
 *
175
 * @param dev Block device to be formatted
176
 * @param fat_n should be 12/16/32 or 0
177
 *
178
 * @return Negative error code or 0 if succeed
179
 */
180
int fat_create_partition(void *dev, int fat_n) {
181
	struct block_dev *bdev = dev;
182
	uint16_t bytepersec = bdev->block_size;
183
	size_t num_sect = block_dev(bdev)->size / bytepersec;
184
	assert(bdev->block_size <= FAT_MAX_SECTOR_SIZE);
185
	uint32_t secperfat = 1;
186
	uint16_t rootentries = 0x0200;             /* 512 for FAT16 */
187
	int reserved;
188
	int err;
189
	int i;
190
	int fat_size;
191
	int blkpersec;
192

193
	struct lbr lbr = (struct lbr) {
194
		.jump = {0xeb, 0x3c, 0x90},        /* JMP 0x3c; NOP; */
195
		.oemid = {0x45, 0x45, 0x45, 0x45,
196
		          0x45, 0x45, 0x45, 0x45}, /* ASCII "EEEEEEEE" */
197
		.bpb = {
198
			.bytepersec_l  = (uint8_t)(bytepersec & 0xFF),
199
			.bytepersec_h  = (uint8_t)((bytepersec & 0xFF00) >> 8),
200
			.secperclus    = 0x04,
201
			.reserved_l    = 0x01,     /* reserved sectors */
202
			.reserved_h    = 0x00,
203
			.numfats       = 0x02,     /* 2 FAT copy */
204
			.rootentries_l = (uint8_t)(0x00FF & rootentries ),
205
			.rootentries_h = (uint8_t)(0x00FF & (rootentries >> 8)),
206
			.mediatype     = 0xF8,     /* Fixed disk */
207
			.secpertrk_l   = 0x3F,     /* TODO use actual value? */
208
			.heads_l       = 0xFF,     /* TODO use actual value? */
209
			/* TODO handle hidden sectors? */
210
		},
211
		.sig_55 = 0x55,
212
		.sig_aa = 0xAA,
213
	};
214

215

216
	if (0xFFFF > num_sect)	{
217
		lbr.bpb.sectors_s_l = (uint8_t)(0x00000FF & num_sect);
218
		lbr.bpb.sectors_s_h = (uint8_t)(0x00000FF & (num_sect >> 8));
219
	} else {
220
		lbr.bpb.sectors_l_0 = (uint8_t)(0x00000FF & num_sect );
221
		lbr.bpb.sectors_l_1 = (uint8_t)(0x00000FF & (num_sect >> 8));
222
		lbr.bpb.sectors_l_2 = (uint8_t)(0x00000FF & (num_sect >> 16));
223
		lbr.bpb.sectors_l_3 = (uint8_t)(0x00000FF & (num_sect >> 24));
224
	}
225

226
	switch (fat_n) {
227
	case 12:
228
	case 16:
229
		lbr.bpb.secperfat_l   = (uint8_t)(0x00FF & secperfat),
230
		lbr.bpb.secperfat_h   = (uint8_t)(0x00FF & (secperfat >> 8)),
231
		lbr.ebpb.ebpb = (struct ebpb) {
232
			.unit      = 0x80, /* Hard disk */
233
			.signature = 0x29,
234
			.serial_0  = 0x81, /* We can actually ignore .serial_N */
235
			.serial_1  = 0xDB,
236
			.serial_2  = 0xF7,
237
			.serial_3  = 0xBB,
238
		};
239

240
		memcpy(lbr.ebpb.ebpb.label, LABEL, sizeof(lbr.ebpb.ebpb.label));
241
		memcpy(lbr.ebpb.ebpb.system,
242
		       fat_n == 12 ? SYSTEM12:SYSTEM16,
243
		       sizeof(lbr.ebpb.ebpb.system));
244

245
		memcpy(lbr.ebpb.ebpb.code, bootcode, sizeof(bootcode));
246
		break;
247
	case 32:
248
		lbr.ebpb.ebpb32 = (struct ebpb32) {
249
			.fatsize_0 = (uint8_t) (0xFF & secperfat),
250
			.fatsize_1 = (uint8_t) (0xFF & (secperfat >> 8)),
251
			.fatsize_2 = (uint8_t) (0xFF & (secperfat >> 16)),
252
			.fatsize_3 = (uint8_t) (0xFF & (secperfat >> 24)),
253
			/* TODO fill flags? */
254
			.fsver_l = 0x1, /* TODO fill actual fat version */
255
			.fsver_h = 0x1,
256
			.root_0  = 0x2, /* Root directory is in the second cluster */
257
			/* TODO fill fsinfo */
258
			.unit      = 0x80, /* Hard disk */
259
			.signature = 0x29,
260
			.serial_0  = 0x81, /* We can actually ignore .serial_N */
261
			.serial_1  = 0xDB,
262
			.serial_2  = 0xF7,
263
			.serial_3  = 0xBB,
264
			.label     = LABEL,
265
			.system    = SYSTEM32,
266
		};
267
		memcpy(lbr.ebpb.ebpb32.label, LABEL, sizeof(lbr.ebpb.ebpb32.label));
268
		memcpy(lbr.ebpb.ebpb32.system, SYSTEM32, sizeof(lbr.ebpb.ebpb32.system));
269
		memcpy(lbr.ebpb.ebpb32.code, bootcode, sizeof(bootcode));
270
		break;
271
	default:
272
		return -1;
273
	}
274

275
	if (0 > (err = block_dev_write(bdev, (void *) &lbr, sizeof(lbr), 0)))
276
		return err;
277

278
	/* Clear FAT from garbage */
279
	memset(fat_sector_buff, 0, sizeof(fat_sector_buff));
280
	reserved = (uint16_t) lbr.bpb.reserved_l |
281
		(((uint16_t) lbr.bpb.reserved_h) << 8);
282
	fat_size = lbr.bpb.numfats * secperfat;
283
	blkpersec = bytepersec / bdev->block_size;
284

285
	for (i = reserved; i < reserved + fat_size; i++)
286
		if (0 > (err = block_dev_write(bdev, (void*) fat_sector_buff, sizeof(fat_sector_buff), i * blkpersec)))
287
			return err;
288

289
	return 0;
290
}
291

292
/**
293
 *	Get starting sector# of specified partition on drive #unit
294
 *	NOTE: This code ASSUMES an MBR on the disk.
295
 *	p_scratchsector should point to a SECTOR_SIZE scratch area
296
 *	Returns 0xffffffff for any error.
297
 *	If pactive is non-NULL, this function also returns partition active flag.
298
 *	If pptype is non-NULL, this function also returns the partition type.
299
 *	If psize is non-NULL, this function also returns the partition size.
300
 */
301
uint32_t fat_get_ptn_start(void *bdev, uint8_t pnum, uint8_t *pactive,
302
		uint8_t *pptype, uint32_t *psize) {
303
	uint32_t result;
304
	struct mbr *mbr = (struct mbr*) fat_sector_buff;
305

306
	/* DOS ptable supports maximum 4 partitions */
307
	if (pnum > 3) {
308
		return DFS_ERRMISC;
309
	}
310

311
	if (0 > block_dev_read(bdev, (char *) fat_sector_buff, sizeof(struct mbr), 0)) {
312
		return DFS_ERRMISC;
313
	}
314
	/* check if that a lbr */
315
	if ((mbr->bootcode[0] == 0xeb) &&
316
		(mbr->bootcode[1] == 0x3c) &&
317
		(mbr->bootcode[2] == 0x90)) {
318
		return 0;
319
	}
320

321
	result = (uint32_t) mbr->ptable[pnum].start_0 |
322
		(((uint32_t) mbr->ptable[pnum].start_1) << 8) |
323
		(((uint32_t) mbr->ptable[pnum].start_2) << 16) |
324
		(((uint32_t) mbr->ptable[pnum].start_3) << 24);
325

326
	if (pactive) {
327
		*pactive = mbr->ptable[pnum].active;
328
	}
329

330
	if (pptype) {
331
		*pptype = mbr->ptable[pnum].type;
332
	}
333

334
	if (psize) {
335
		*psize = (uint32_t) mbr->ptable[pnum].size_0 |
336
			(((uint32_t) mbr->ptable[pnum].size_1) << 8) |
337
			(((uint32_t) mbr->ptable[pnum].size_2) << 16) |
338
			(((uint32_t) mbr->ptable[pnum].size_3) << 24);
339
	}
340

341
	return result;
342
}
343

344
/**
345
 * Retrieve volume info from BPB and store it in a volinfo_t structure
346
 * You must provide the unit and starting sector of the filesystem, and
347
 * a pointer to a sector buffer for scratch
348
 * Attempts to read BPB and glean information about the FS from that.
349
 * Returns 0 OK, nonzero for any error.
350
 */
351
uint32_t fat_get_volinfo(void *bdev, struct volinfo * volinfo, uint32_t startsector) {
352
	struct lbr *lbr = (struct lbr *) fat_sector_buff;
353

354
	log_debug("startsector %d", startsector);
355

356
	if (0 > block_dev_read(bdev,
357
				(char *) fat_sector_buff,
358
				sizeof(struct lbr),
359
				0)) { /* TODO start sector */
360
		return DFS_ERRMISC;
361
	}
362

363
	volinfo->bytepersec = lbr->bpb.bytepersec_l + (lbr->bpb.bytepersec_h << 8);
364
	volinfo->startsector = startsector;
365
	volinfo->secperclus = lbr->bpb.secperclus;
366
	volinfo->reservedsecs = (uint16_t) lbr->bpb.reserved_l |
367
		  (((uint16_t) lbr->bpb.reserved_h) << 8);
368

369
	volinfo->numsecs =  (uint16_t) lbr->bpb.sectors_s_l |
370
		  (((uint16_t) lbr->bpb.sectors_s_h) << 8);
371

372
	if (!volinfo->numsecs)
373
		volinfo->numsecs = (uint32_t) lbr->bpb.sectors_l_0 |
374
		  (((uint32_t) lbr->bpb.sectors_l_1) << 8) |
375
		  (((uint32_t) lbr->bpb.sectors_l_2) << 16) |
376
		  (((uint32_t) lbr->bpb.sectors_l_3) << 24);
377

378
	/**
379
	 * If secperfat is 0, we must be in a FAT32 volume
380
	 */
381
	volinfo->secperfat =  (uint16_t) lbr->bpb.secperfat_l |
382
		  (((uint16_t) lbr->bpb.secperfat_h) << 8);
383

384
	if (!volinfo->secperfat) {
385
		volinfo->secperfat = (uint32_t) lbr->ebpb.ebpb32.fatsize_0 |
386
		  (((uint32_t) lbr->ebpb.ebpb32.fatsize_1) << 8) |
387
		  (((uint32_t) lbr->ebpb.ebpb32.fatsize_2) << 16) |
388
		  (((uint32_t) lbr->ebpb.ebpb32.fatsize_3) << 24);
389

390
		memcpy(volinfo->label, lbr->ebpb.ebpb32.label, MSDOS_NAME);
391
		volinfo->label[11] = 0;
392
	} else {
393
		memcpy(volinfo->label, lbr->ebpb.ebpb.label, MSDOS_NAME);
394
		volinfo->label[11] = 0;
395
	}
396

397
	/* note: if rootentries is 0, we must be in a FAT32 volume. */
398
	volinfo->rootentries =  (uint16_t) lbr->bpb.rootentries_l |
399
		  (((uint16_t) lbr->bpb.rootentries_h) << 8);
400

401
	volinfo->fat1 = startsector + volinfo->reservedsecs;
402

403
	/**
404
	 * The calculation below is designed to round up the root directory size
405
	 * for FAT12/16 and to simply ignore the root directory for FAT32, since
406
	 * it's a normal, expandable file in that situation.
407
	 */
408

409
	if (volinfo->rootentries) {
410
		volinfo->rootdir = volinfo->fat1 + (volinfo->secperfat * 2);
411
		volinfo->dataarea = volinfo->rootdir
412
			+ (((volinfo->rootentries * 32) + (volinfo->bytepersec - 1))
413
			/ volinfo->bytepersec);
414
	} else {
415
		volinfo->dataarea = volinfo->fat1 + (volinfo->secperfat * 2);
416
		volinfo->rootdir = (uint32_t) lbr->ebpb.ebpb32.root_0 |
417
		  (((uint32_t) lbr->ebpb.ebpb32.root_1) << 8) |
418
		  (((uint32_t) lbr->ebpb.ebpb32.root_2) << 16) |
419
		  (((uint32_t) lbr->ebpb.ebpb32.root_3) << 24);
420
	}
421

422
	if (0 == volinfo->secperclus) {
423
		volinfo->numclusters = 0;
424
		fat_volinfo_print(volinfo);
425
		return DFS_ERRMISC;
426
	} else {
427
		volinfo->numclusters = (volinfo->numsecs - volinfo->dataarea) /
428
			volinfo->secperclus;
429
	}
430

431
	if (volinfo->numclusters < 4085) {
432
		volinfo->filesystem = FAT12;
433
	} else if (volinfo->numclusters < 65525) {
434
		volinfo->filesystem = FAT16;
435
	} else {
436
		volinfo->filesystem = FAT32;
437
	}
438

439
	fat_volinfo_print(volinfo);
440

441
	return DFS_OK;
442
}
443

444
/*
445
 *	Fetch FAT entry for specified cluster number You must provide a scratch
446
 *	buffer for one sector (SECTOR_SIZE) and a populated struct volinfo
447
 *	Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents
448
 *	of the desired FAT entry.
449
 */
450
uint32_t fat_get_fat(struct fat_fs_info *fsi,
451
		uint8_t *p_scratch, uint32_t cluster) {
452
	uint32_t offset, sector, result;
453
	struct volinfo *volinfo = &fsi->vi;
454

455
	switch (volinfo->filesystem) {
456
	case FAT12:
457
		offset = cluster + (cluster / 2);
458
		break;
459
	case FAT16:
460
		offset = cluster * 2;
461
		break;
462
	case FAT32:
463
		offset = cluster * 4;
464
		break;
465
	default:
466
		return DFS_BAD_CLUS;
467
	}
468

469
	sector = offset / volinfo->bytepersec + volinfo->fat1;
470

471
	if (fat_read_sector(fsi, p_scratch, sector)) {
472
		return DFS_BAD_CLUS;
473
	}
474

475
	/*
476
	 * At this point, we "merely" need to extract the relevant entry.
477
	 * This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as
478
	 * a single entry may span a sector boundary. The normal way around this is
479
	 * always to read two FAT sectors, but that luxury is (by design intent)
480
	 * unavailable to DOSFS.
481
	 */
482
	offset %= volinfo->bytepersec;
483
	if (volinfo->filesystem == FAT12) {
484
		/* Special case for sector boundary - Store last byte of current sector
485
		 * Then read in the next sector and put the first byte of that sector
486
		 * into the high byte of result.
487
		 */
488
		if (offset == volinfo->bytepersec - 1) {
489
			result = (uint32_t) p_scratch[offset];
490
			sector++;
491
			if (fat_read_sector(fsi, p_scratch, sector)) {
492
				return DFS_BAD_CLUS;
493
			}
494
			result |= ((uint32_t) p_scratch[0]) << 8;
495
		} else {
496
			result = (uint32_t) p_scratch[offset] |
497
			  ((uint32_t) p_scratch[offset+1]) << 8;
498
		}
499
		if (cluster & 1)
500
			result = result >> 4;
501
		else
502
			result = result & 0xfff;
503
	} else if (volinfo->filesystem == FAT16) {
504
		result = (uint32_t) p_scratch[offset] |
505
		  ((uint32_t) p_scratch[offset+1]) << 8;
506
	} else if (volinfo->filesystem == FAT32) {
507
		result = ((uint32_t) p_scratch[offset] |
508
		  ((uint32_t) p_scratch[offset+1]) << 8 |
509
		  ((uint32_t) p_scratch[offset+2]) << 16 |
510
		  ((uint32_t) p_scratch[offset+3]) << 24) & 0x0fffffff;
511
	} else
512
		result = DFS_BAD_CLUS;
513

514
	return result;
515
}
516

517
static uint32_t fat_end_of_chain(struct fat_fs_info *fsi) {
518
	switch(fsi->vi.filesystem) {
519
	case FAT12:
520
		return 0xfff;
521
	case FAT16:
522
		return 0xffff;
523
	case FAT32:
524
		return 0x0fffffff; /* FAT32 is really "FAT28" */
525
	default:
526
		return 0;
527
	}
528
}
529

530
static uint32_t fat_is_end_of_chain(struct fat_fs_info *fsi, uint32_t clus) {
531
	switch (fsi->vi.filesystem) {
532
	case FAT12:
533
		return clus >= 0xff7;
534
	case FAT16:
535
		return clus >= 0xfff7;
536
	case FAT32:
537
		return clus >= 0xffffff7;
538
	}
539

540
	return 1;
541
}
542

543
/*
544
 * Set FAT entry for specified cluster number
545
 * You must provide a scratch buffer for one sector (SECTOR_SIZE)
546
 * and a populated volinfo_t Returns DFS_ERRMISC for any error, otherwise
547
 * DFS_OK p_scratchcache should point to a UINT32.
548
 * */
549
static uint32_t fat_set_fat(struct fat_fs_info *fsi, uint8_t *p_scratch,
550
		uint32_t cluster, uint32_t new_contents) {
551
	uint32_t offset, sector, result;
552
	struct volinfo *volinfo = &fsi->vi;
553

554
	switch (volinfo->filesystem) {
555
	case FAT12:
556
		offset = cluster + (cluster / 2);
557
		break;
558
	case FAT16:
559
		offset = cluster * 2;
560
		break;
561
	case FAT32:
562
		offset = cluster * 4;
563
		break;
564
	default:
565
		return DFS_ERRMISC;
566
	}
567

568
	new_contents &= fat_end_of_chain(fsi);
569
	/*
570
	 * at this point, offset is the BYTE offset of the desired sector from
571
	 * the start of the FAT.
572
	 * Calculate the physical sector containing this FAT entry.
573
	 */
574
	sector = offset / volinfo->bytepersec + volinfo->fat1;
575

576
	if (fat_read_sector(fsi, p_scratch, sector)) {
577
		return DFS_ERRMISC;
578
	}
579

580
	/*
581
	 * At this point, we "merely" need to extract the relevant entry.
582
	 * This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a
583
	 * single entry may span a sector boundary. The normal way around this
584
	 * is always to read two FAT sectors, but that luxury is (by design intent)
585
	 * unavailable to DOSFS.
586
	 */
587
	offset %= volinfo->bytepersec;
588

589
	switch (volinfo->filesystem) {
590
	case FAT12:
591
		if (cluster & 1)
592
			new_contents = new_contents << 4;
593

594
		if (offset == volinfo->bytepersec - 1) {
595
			/* Odd cluster: High 12 bits being set */
596
			if (cluster & 1) {
597
				p_scratch[offset] = (p_scratch[offset] & 0x0f) |
598
						(new_contents & 0xf0);
599
			}
600
			/* Even cluster: Low 12 bits being set */
601
			else {
602
				p_scratch[offset] = new_contents & 0xff;
603
			}
604
			result = fat_write_sector(fsi, p_scratch, sector);
605
			/* mirror the FAT into copy 2 */
606
			if (DFS_OK == result) {
607
				result = fat_write_sector(fsi, p_scratch,
608
						sector + volinfo->secperfat);
609
			}
610

611
			/*
612
			 * If we wrote that sector OK, then read in the subsequent sector
613
			 * and poke the first byte with the remainder of this FAT entry.
614
			 */
615
			if (DFS_OK == result) {
616
				result = fat_read_sector(fsi, p_scratch, ++sector);
617
				if (DFS_OK == result) {
618
					/* Odd cluster: High 12 bits being set*/
619
					if (cluster & 1) {
620
						p_scratch[0] = new_contents & 0xff00;
621
					}
622
					/* Even cluster: Low 12 bits being set */
623
					else {
624
						p_scratch[0] = (p_scratch[0] & 0xf0) |
625
								(new_contents & 0x0f);
626
					}
627
					result = fat_write_sector(fsi, p_scratch, sector);
628
					/* mirror the FAT into copy 2 */
629
					if (DFS_OK == result) {
630
						result = fat_write_sector(fsi, p_scratch,
631
								sector+volinfo->secperfat);
632
					}
633
				}
634
			}
635
		}
636

637
		/*
638
		 * Not a sector boundary. But we still have to worry about if it's an
639
		 * odd or even cluster number.
640
		 */
641
		else {
642
			/* Odd cluster: High 12 bits being set */
643
			if (cluster & 1) {
644
				p_scratch[offset] = (p_scratch[offset] & 0x0f) |
645
						(new_contents & 0xf0);
646
				p_scratch[offset + 1] = (new_contents & 0xff00) >> 8;
647
			}
648
			/* Even cluster: Low 12 bits being set */
649
			else {
650
				p_scratch[offset] = new_contents & 0xff;
651
				p_scratch[offset+1] = (p_scratch[offset+1] & 0xf0) |
652
						((new_contents & 0x0f00) >> 8);
653
			}
654
			result = fat_write_sector(fsi, p_scratch, sector);
655
			/* mirror the FAT into copy 2 */
656
			if (DFS_OK == result) {
657
				result = fat_write_sector(fsi, p_scratch,
658
						sector + volinfo->secperfat);
659
			}
660
		}
661
		break;
662
	case FAT32:
663
		p_scratch[offset + 3] = (p_scratch[offset  + 3] & 0xf0) |
664
				((new_contents & 0x0f000000) >> 24);
665
		p_scratch[offset + 2] = (new_contents & 0xff0000) >> 16;
666
		/* Fall through */
667
	case FAT16:
668
		p_scratch[offset + 1] = (new_contents & 0xff00) >> 8;
669
		p_scratch[offset] = (new_contents & 0xff);
670
		result = fat_write_sector(fsi, p_scratch, sector);
671
		/* mirror the FAT into copy 2 */
672
		if (DFS_OK == result)
673
			result = fat_write_sector(
674
					fsi,
675
					p_scratch,
676
					sector + volinfo->secperfat
677
				);
678
		break;
679
	default:
680
		result = DFS_ERRMISC;
681
	}
682
	return result;
683
}
684

685
/* For long names string is divided in a pretty ugly way so old drivers
686
 * will be able to read directory content, so we need some ugly code to
687
 * figure it out. NOTE: we support only ASCII-charaters filenames */
688
static void fat_append_longname(char *name, struct fat_dirent *di) {
689
	struct fat_long_dirent *ld;
690
	const int chars_per_long_entry = 13;
691
	int l;
692

693
	assert(name);
694
	assert(di);
695

696
	ld = (void *) di;
697

698
	l = chars_per_long_entry * ((di->name[0] & FAT_LONG_ORDER_NUM_MASK) - 1);
699

700
	name[l++] = (char) ld->name1[0];
701
	name[l++] = (char) ld->name1[2];
702
	name[l++] = (char) ld->name1[4];
703
	name[l++] = (char) ld->name1[6];
704
	name[l++] = (char) ld->name1[8];
705

706
	name[l++] = (char) ld->name2[0];
707
	name[l++] = (char) ld->name2[2];
708
	name[l++] = (char) ld->name2[4];
709
	name[l++] = (char) ld->name2[6];
710
	name[l++] = (char) ld->name2[8];
711
	name[l++] = (char) ld->name2[10];
712

713
	name[l++] = (char) ld->name3[0];
714
	name[l++] = (char) ld->name3[2];
715

716
	if (di->name[0] & FAT_LONG_ORDER_LAST) {
717
		name[l] = '\0';
718
	}
719
}
720

721
/*
722
 * 	Find the first unused FAT entry
723
 * 	You must provide a scratch buffer for one sector (SECTOR_SIZE) and a
724
 * 	populated volinfo_t Returns a FAT32 BAD_CLUSTER value for any error,
725
 * 	otherwise the contents of the desired FAT entry.
726
 * 	Returns FAT32 bad_sector (0x0ffffff7) if there is no free cluster available
727
 */
728
static uint32_t fat_get_free_fat(struct fat_fs_info *fsi, uint8_t *p_scratch) {
729
	uint32_t i;
730
	/*
731
	 * Search starts at cluster 2, which is the first usable cluster
732
	 * NOTE: This search can't terminate at a bad cluster, because there might
733
	 * legitimately be bad clusters on the disk.
734
	 */
735
	for (i = 2; i < fsi->vi.numclusters; i++) {
736
		if (!fat_get_fat(fsi, p_scratch, i)) {
737
			return i;
738
		}
739
	}
740
	return DFS_BAD_CLUS;
741
}
742

743
uint32_t fat_open_rootdir(struct fat_fs_info *fsi, struct dirinfo *dirinfo) {
744
	struct volinfo *volinfo;
745
	uint32_t ret;
746

747
	assert(fsi);
748

749
	volinfo = &fsi->vi;
750

751
	dirinfo->flags = 0;
752
	dirinfo->fi.mode = S_IFDIR;
753
	dirinfo->currentsector = volinfo->rootdir % volinfo->secperclus;
754
	dirinfo->currentcluster = volinfo->rootdir / volinfo->secperclus;
755

756
	log_debug("dirinfo: p_scratch(%p), currentsector(%d), currentcluster(%d)",
757
			dirinfo->p_scratch, dirinfo->currentsector, dirinfo->currentcluster);
758
	log_debug("volinfo: secperclus %d rootdir %d", volinfo->secperclus, volinfo->rootdir);
759

760
	ret = fat_read_sector(fsi, dirinfo->p_scratch, volinfo->rootdir);
761

762
	return ret;
763
}
764

765
static uint32_t fat_fetch_dir(struct dirinfo *dir) {
766
	struct fat_fs_info *fsi = dir->fi.fsi;
767
	struct volinfo *volinfo = &fsi->vi;
768
	int ent_per_sec = volinfo->bytepersec / sizeof(struct fat_dirent);
769
	int read_sector;
770

771
	if (dir->currententry >= ent_per_sec) {
772
		int next_ent;
773
		dir->currententry = 0;
774
		dir->currentsector++;
775

776
		/* Root directory; special case handling
777
		 * Note that currentcluster will only ever be zero if both:
778
		 * (a) this is the root directory, and
779
		 * (b) we are on a FAT12/16 volume, where the root dir can't be
780
		 * expanded
781
		 */
782
		if (dir->currentcluster == 0) {
783
			/* Trying to read past end of root directory? */
784
			next_ent  = dir->currentsector * volinfo->bytepersec;
785
			next_ent /= sizeof(struct fat_dirent);
786
			if (next_ent >= volinfo->rootentries)
787
				return DFS_EOF;
788

789
			/* Otherwise try to read the next sector */
790
			if (fat_read_sector(fsi, dir->p_scratch, dir->currentsector))
791
				return DFS_ERRMISC;
792
		} else {
793
			if (dir->currentsector >= volinfo->secperclus) {
794
				int tempclus;
795

796
				dir->currentsector = 0;
797

798
				tempclus = fat_get_fat(fsi,
799
						dir->p_scratch,
800
						dir->currentcluster);
801

802
				if (fat_is_end_of_chain(fsi, tempclus)) {
803
					return DFS_ALLOCNEW;
804
				} else {
805
					dir->currentcluster = tempclus;
806
				}
807
			}
808

809
			read_sector = fat_current_dirsector(dir);
810

811
			if (fat_read_sector(fsi, dir->p_scratch, read_sector))
812
				return DFS_ERRMISC;
813
		}
814
	}
815

816
	return DFS_OK;
817
}
818

819
static uint32_t fat_get_current(struct dirinfo *dir, struct fat_dirent *dirent) {
820
	struct fat_dirent *dirent_src;
821
	uint32_t tmp;
822

823
	/* Do we need to read the next sector of the directory? */
824
	if (DFS_OK != (tmp = fat_fetch_dir(dir))) {
825
		return tmp;
826
	}
827

828
	dirent_src = &((struct fat_dirent *) dir->p_scratch)[dir->currententry];
829
	memcpy(dirent, dirent_src, sizeof(struct fat_dirent));
830

831
	if (dirent->name[0] == '\0') {
832
		return DFS_EOF;
833
	}
834

835
	if (dirent->name[0] == 0xe5) {
836
		dirent->name[0] = '\0';
837
	}
838

839
	return DFS_OK;
840
}
841

842

843
/*
844
 * Get next entry in opened directory structure.
845
 * Copies fields into the dirent structure, updates dirinfo. Note that it is
846
 * the _caller's_ responsibility to	handle the '.' and '..' entries.
847
 * A deleted file will be returned as a NULL entry (first char of filename=0)
848
 * by this code. Filenames beginning with 0x05 will be translated to 0xE5
849
 * automatically. Long file name entries will be returned as NULL.
850
 * returns DFS_EOF if there are no more entries, DFS_OK if this entry is valid,
851
 * or DFS_ERRMISC for a media error
852
 */
853
uint32_t fat_get_next(struct dirinfo *dir, struct fat_dirent *dirent) {
854
	struct fat_dirent *dirent_src;
855
	uint32_t tmp;
856

857
	dirent->name[0] = '\0';
858

859
	log_debug("dir->currententry %d", dir->currententry);
860
	/* Do we need to read the next sector of the directory? */
861
	if (DFS_OK != (tmp = fat_fetch_dir(dir))) {
862
		if (tmp == DFS_ALLOCNEW) {
863
			if (DFS_OK != (tmp = fat_dir_extend(dir))) {
864
				return tmp;
865
			}
866
		} else {
867
			return tmp;
868
		}
869
	}
870

871
	dirent_src = &((struct fat_dirent *) dir->p_scratch)[dir->currententry];
872
	memcpy(dirent, dirent_src, sizeof(struct fat_dirent));
873
	log_debug("dir: p_scratch = %p, currententry = %d",dir->p_scratch, dir->currententry);
874
	log_debug("dirent->name (%s), dirent->name[0]=0x%x", dirent->name, dirent->name[0]);
875

876
	if (dirent->name[0] == '\0') {
877
		if (dir->flags & DFS_DI_BLANKENT) {
878
			dir->currententry++; // DOSFS 1.03 BUG, currententry was not incremented in this case
879
			return DFS_OK;
880
		} else {
881
			return DFS_EOF;
882
		}
883
	}
884

885
	if (dirent->name[0] == 0xe5) {
886
		memset(dirent, 0, sizeof(*dirent));
887
	} else if (dirent->name[0] == 0x05)
888
		/* handle kanji filenames beginning with 0xE5 */
889
		dirent->name[0] = 0xe5;
890

891
	dir->currententry++;
892

893
	return DFS_OK;
894
}
895

896
/* Same as fat_get_next(), but skip long-name entries with following 8.3-entries */
897
uint32_t fat_get_next_long(struct dirinfo *dir, struct fat_dirent *dirent, char *name_buf) {
898
	uint32_t ret;
899
	char c;
900
	int i;
901

902
	assert(dir);
903
	assert(dir->p_scratch);
904
	assert(dirent);
905
	assert(dir->fi.fsi);
906

907
	do {
908
		ret = fat_get_next(dir, dirent);
909
		if (ret == DFS_EOF) {
910
			return ret;
911
		}
912
	} while (dirent->name[0] == '\0');
913

914
	if (dirent->attr != ATTR_LONG_NAME) {
915
		if (name_buf != NULL) {
916
			/* Copy name body */
917
			for (i = 0; i < 8; i++) {
918
				c = dirent->name[i];
919
				if (c == ' ') {
920
					break;
921
				}
922

923
				if (isupper(c)) {
924
					c += 0x20;
925
				}
926

927
				*name_buf++ = c;
928
			}
929

930
			/* Copy name extension */
931
			if (dirent->name[8] != ' ') {
932
				*name_buf++ = '.';
933
				for (i = 8; i < 11; i++) {
934
					c = dirent->name[i];
935
					if (c == ' ')
936
						break;
937

938
					if (isupper(c)) {
939
						c += 0x20;
940
					}
941

942
					*name_buf++ = c;
943
				}
944
			}
945

946
			/* Terminate SFN str by a \0 */
947
			*name_buf = 0;
948
		}
949
	} else {
950
		while (dirent->attr == ATTR_LONG_NAME) {
951
			if (name_buf != NULL) {
952
				fat_append_longname(name_buf, dirent);
953
			}
954
			ret = fat_get_next(dir, dirent);
955
		}
956
		/* Now cur_di points to 8.3 entry which corresponds to current
957
		 * file, so we need to get next entry for a next file */
958
	}
959

960
	return ret;
961
}
962

963
/* Fill given cluster number with zeroes */
964
static uint32_t fat_clear_clus(struct fat_fs_info *fsi,
965
		uint32_t clus, uint8_t *p_scratch) {
966
	uint32_t sec;
967

968
	assert(fsi);
969
	assert(p_scratch);
970

971
	sec = fat_sec_by_clus(fsi, clus);
972

973
	memset(p_scratch, 0, fsi->vi.bytepersec);
974
	for (int i = 0; i < fsi->vi.secperclus; i++) {
975
		if (fat_write_sector(fsi, p_scratch, sec + i)) {
976
			return DFS_ERRMISC;
977
		}
978
	}
979

980
	return 0;
981
}
982

983
static uint32_t fat_dir_extend(struct dirinfo *di) {
984
	struct fat_fs_info *fsi = di->fi.fsi;
985
	uint32_t clus;
986
	clus = fat_get_free_fat(fsi, di->p_scratch);
987
	if (clus == DFS_BAD_CLUS) {
988
		return DFS_ERRMISC;
989
	}
990

991
	if (0 != fat_clear_clus(fsi, clus, di->p_scratch)) {
992
		return DFS_ERRMISC;
993
	}
994

995
	fat_set_fat(fsi, di->p_scratch, di->currentcluster, clus);
996

997
	di->currentcluster = clus;
998
	di->currentsector = 0;
999
	di->currententry = 0; /* clus is not zero but contains fat entry,
1000
				 so next loop will call */
1001
	clus = fat_end_of_chain(fsi);
1002

1003
	fat_set_fat(fsi, di->p_scratch, di->currentcluster, clus);
1004

1005
	read_dir_buf(di);
1006

1007
	return DFS_OK;
1008
}
1009
/*
1010
 * INTERNAL
1011
 * Find a free directory entry in the directory specified by path
1012
 * This function MAY cause a disk write if it is necessary to extend the
1013
 * directory size.
1014
 * Note - di.p_scratch must be preinitialized to point to a sector scratch buffer
1015
 * de is a scratch structure
1016
 * Returns DFS_ERRMISC if a new entry could not be located or created
1017
 * de is updated with the same return information you would expect
1018
 * from fat_get_next
1019
 */
1020
static uint32_t fat_get_free_dir_ent(struct dirinfo *di, struct fat_dirent *de) {
1021
	uint32_t ret;
1022
	int offset = 0;
1023

1024
	do {
1025
		ret = fat_get_current(di, de);
1026

1027
		if (ret == DFS_EOF) {
1028
			return offset;
1029
		}
1030

1031
		if (ret == DFS_OK) {
1032
			if (de->name[0] == '\0') {
1033
				return offset;
1034
			}
1035
		}
1036

1037
		offset++;
1038
		di->currententry++;
1039

1040
		ret = fat_fetch_dir(di);
1041
		if (ret == DFS_ALLOCNEW) {
1042
			/* Need to allocate new cluster */
1043
			if (DFS_OK != (ret = fat_dir_extend(di))) {
1044
				return -1;
1045
			}
1046

1047
			return offset;
1048
		}
1049
	} while (1);
1050

1051
	/* We shouldn't get here */
1052
	return DFS_ERRMISC;
1053
}
1054

1055
static void fat_set_direntry(uint32_t dir_cluster, uint32_t cluster) {
1056
	struct fat_dirent *de = (struct fat_dirent *) fat_sector_buff;
1057

1058
	de[0] = (struct fat_dirent) {
1059
		.name = MSDOS_DOT,
1060
		.attr = ATTR_DIRECTORY,
1061
	};
1062
	fat_direntry_set_clus(&de[0], cluster);
1063

1064
	de[1] = (struct fat_dirent) {
1065
		.name = MSDOS_DOTDOT,
1066
		.attr = ATTR_DIRECTORY,
1067
	};
1068
	fat_direntry_set_clus(&de[1], dir_cluster);
1069

1070
	fat_set_filetime(&de[0]);
1071
	fat_set_filetime(&de[1]);
1072
}
1073

1074
int fat_root_dir_record(void *bdev) {
1075
	uint32_t cluster;
1076
	struct fat_fs_info fsi;
1077
	uint32_t pstart, psize;
1078
	uint8_t pactive, ptype;
1079
	struct fat_dirent de;
1080
	int dev_blk_size = block_dev(bdev)->block_size;
1081
	int root_dir_sz;
1082

1083
	assert(dev_blk_size > 0);
1084

1085
	fsi.bdev = bdev;
1086

1087
	/* Obtain pointer to first partition on first (only) unit */
1088
	pstart = fat_get_ptn_start(bdev, 0, &pactive, &ptype, &psize);
1089
	if (pstart == 0xffffffff) {
1090
		return -1;
1091
	}
1092

1093
	if (fat_get_volinfo(bdev, &fsi.vi, pstart)) {
1094
		return -1;
1095
	}
1096

1097
	cluster = fsi.vi.rootdir / fsi.vi.secperclus;
1098

1099
	de = (struct fat_dirent) {
1100
		.name = "ROOT DIR   ",
1101
		.attr = ATTR_DIRECTORY,
1102
	};
1103
	fat_direntry_set_clus(&de, cluster);
1104

1105
	fat_set_filetime(&de);
1106

1107
	/*
1108
	 * write the directory entry
1109
	 * note that we no longer have the sector containing the directory
1110
	 * entry, tragically, so we have to re-read it
1111
	 */
1112

1113
	/* we clear other FAT TABLE */
1114
	memset(fat_sector_buff, 0, sizeof(fat_sector_buff));
1115
	memcpy(&(((struct fat_dirent*) fat_sector_buff)[0]), &de, sizeof(struct fat_dirent));
1116

1117
	if (0 > block_dev_write(	bdev,
1118
					(char *) fat_sector_buff,
1119
					fsi.vi.bytepersec,
1120
					fsi.vi.rootdir * fsi.vi.bytepersec / dev_blk_size)) {
1121
		return DFS_ERRMISC;
1122
	}
1123

1124
	root_dir_sz = (fsi.vi.rootentries * sizeof(struct fat_dirent) +
1125
	               fsi.vi.bytepersec - 1) / fsi.vi.bytepersec - 1;
1126

1127
	if (root_dir_sz)
1128
		memset(fat_sector_buff, 0, sizeof(struct fat_dirent)); /* The rest is zeroes already */
1129
	/* Clear the rest of root directory */
1130
	while (root_dir_sz) {
1131
		block_dev_write(bdev,
1132
				(char *) fat_sector_buff,
1133
				fsi.vi.bytepersec,
1134
				(root_dir_sz + fsi.vi.rootdir) * fsi.vi.bytepersec / dev_blk_size);
1135
		root_dir_sz--;
1136
	}
1137

1138
	cluster = fat_end_of_chain(&fsi);
1139
	fat_set_fat(&fsi, fat_sector_buff, cluster, cluster);
1140

1141
	return DFS_OK;
1142
}
1143

1144
/*
1145
 * Read an open file
1146
 * You must supply a prepopulated file_info_t as provided by fat_open_file,
1147
 * and a pointer to a volinfo->bytepersec scratch buffer.
1148
 * 	Note that returning DFS_EOF is not an error condition. This function
1149
 * 	updates the	successcount field with the number of bytes actually read.
1150
 */
1151
uint32_t fat_read_file(struct fat_file_info *fi, uint8_t *p_scratch,
1152
		uint8_t *buffer, uint32_t *successcount, uint32_t len) {
1153
	uint32_t remain;
1154
	uint32_t result;
1155
	uint32_t sector;
1156
	uint32_t bytesread;
1157
	uint32_t clastersize;
1158
	struct fat_fs_info *fsi;
1159
	fsi = fi->fsi;
1160

1161
	log_debug("len(%d) volinfo: secperclus(%d), bytepersec(%d)",
1162
			len, fi->volinfo->secperclus, fi->volinfo->bytepersec );
1163

1164
	result = DFS_OK;
1165
	remain = len;
1166
	*successcount = 0;
1167
	clastersize = fi->volinfo->secperclus * fi->volinfo->bytepersec;
1168

1169
	while (remain && result == DFS_OK) {
1170
		/* This is a bit complicated. The sector we want to read is addressed
1171
		 * at a cluster granularity by the fi->cluster member. The file
1172
		 * pointer tells us how many extra sectors to add to that number.
1173
		 */
1174
		sector = fi->volinfo->dataarea +
1175
		  ((fi->cluster - 2) * fi->volinfo->secperclus) +
1176
		  div(div(fi->pointer, clastersize).rem, fi->volinfo->bytepersec).quot;
1177

1178
		/* Case 1 - File pointer is not on a sector boundary */
1179
		if (div(fi->pointer, fi->volinfo->bytepersec).rem) {
1180
			uint16_t tempreadsize;
1181

1182
			/* We always have to go through scratch in this case */
1183
			result = fat_read_sector(fsi, p_scratch, sector);
1184

1185
			/*
1186
			 * This is the number of bytes that we actually care about in the
1187
			 * sector just read.
1188
			 */
1189
			tempreadsize = fi->volinfo->bytepersec -
1190
					(div(fi->pointer, fi->volinfo->bytepersec).rem);
1191

1192
			/* Case 1A - We want the entire remainder of the sector. After this
1193
			 * point, all passes through the read loop will be aligned on a
1194
			 * sector boundary, which allows us to go through the optimal path
1195
			 *  2A below.
1196
			 */
1197
		   	if (remain >= tempreadsize) {
1198
				memcpy(buffer, p_scratch + (fi->volinfo->bytepersec - tempreadsize),
1199
						tempreadsize);
1200
				bytesread = tempreadsize;
1201
				buffer += tempreadsize;
1202
				fi->pointer += tempreadsize;
1203
				remain -= tempreadsize;
1204
			}
1205
			/* Case 1B - This read concludes the file read operation */
1206
			else {
1207
				memcpy(buffer, p_scratch +
1208
						(fi->volinfo->bytepersec - tempreadsize), remain);
1209

1210
				buffer += remain;
1211
				fi->pointer += remain;
1212
				bytesread = remain;
1213
				remain = 0;
1214
			}
1215
		}
1216
		/* Case 2 - File pointer is on sector boundary */
1217
		else {
1218
			/*
1219
			 * Case 2A - We have at least one more full sector to read and
1220
			 * don't have to go through the scratch buffer. You could insert
1221
			 * optimizations here to read multiple sectors at a time, if you
1222
			 * were thus inclined (note that the maximum multi-read you could
1223
			 * perform is a single cluster, so it would be advantageous to have
1224
			 * code similar to case 1A above that would round the pointer to a
1225
			 * cluster boundary the first pass through, so all subsequent
1226
			 * [large] read requests would be able to go a cluster at a time).
1227
			 */
1228
			 if (remain >= fi->volinfo->bytepersec) {
1229
				result = fat_read_sector(fsi, buffer, sector);
1230
				remain -= fi->volinfo->bytepersec;
1231
				buffer += fi->volinfo->bytepersec;
1232
				fi->pointer += fi->volinfo->bytepersec;
1233
				bytesread = fi->volinfo->bytepersec;
1234
			}
1235
			/* Case 2B - We are only reading a partial sector */
1236
			else {
1237
				result = fat_read_sector(fsi, p_scratch, sector);
1238
				memcpy(buffer, p_scratch, remain);
1239
				buffer += remain;
1240
				fi->pointer += remain;
1241
				bytesread = remain;
1242
				remain = 0;
1243
			}
1244
		}
1245

1246
		*successcount += bytesread;
1247
		/* check to see if we stepped over a cluster boundary */
1248
		if (div(fi->pointer - bytesread, clastersize).quot !=
1249
			div(fi->pointer, clastersize).quot) {
1250
			if (fat_is_end_of_chain(fsi, fi->cluster)) {
1251
				result = DFS_EOF;
1252
			} else {
1253
				fi->cluster = fat_get_fat(fsi, p_scratch, fi->cluster);
1254
			}
1255
		}
1256
	}
1257

1258
	return result;
1259
}
1260

1261

1262
/*
1263
 * Write an open file
1264
 * You must supply a prepopulated file_info_t as provided by
1265
 * fat_open_file, and a pointer to a SECTOR_SIZE scratch buffer.
1266
 * This function updates the successcount field with the number
1267
 * of bytes actually written.
1268
 */
1269
uint32_t fat_write_file(struct fat_file_info *fi, uint8_t *p_scratch,
1270
		uint8_t *buffer, uint32_t *successcount, uint32_t len, size_t *size) {
1271
	uint32_t remain;
1272
	uint32_t result = DFS_OK;
1273
	uint32_t sector;
1274
	uint32_t byteswritten;
1275
	uint32_t lastcluster, nextcluster;
1276
	uint32_t clastersize;
1277
	uint32_t new_clus = 0;
1278
	struct fat_fs_info *fsi;
1279
	fsi = fi->fsi;
1280

1281
	if (!(fi->mode & O_WRONLY) && !(fi->mode & O_APPEND) && !(fi->mode & O_RDWR)) {
1282
		return DFS_ERRMISC;
1283
	}
1284

1285
	log_debug("len(%d) volinfo: secperclus(%d), bytepersec(%d)",
1286
			len, fi->volinfo->secperclus, fi->volinfo->bytepersec );
1287

1288
	if (fi->firstcluster == 0) {
1289
		new_clus = fat_get_free_fat(fsi, fat_sector_buff);
1290
		fat_set_fat(fsi, fat_sector_buff, new_clus, fat_end_of_chain(fsi));
1291
		fi->firstcluster = fi->cluster = new_clus;
1292
	}
1293

1294
	remain = len;
1295
	*successcount = 0;
1296
	clastersize = fi->volinfo->secperclus * fi->volinfo->bytepersec;
1297

1298
	while (remain && result == DFS_OK) {
1299
		/*
1300
		 * This is a bit complicated. The sector we want to read is addressed
1301
		 * at a cluster granularity by  the fi->cluster member.
1302
		 * The file pointer tells us how many extra sectors to add to that
1303
		 * number.
1304
		 */
1305
		sector = fi->volinfo->dataarea +
1306
		  ((fi->cluster - 2) * fi->volinfo->secperclus) +
1307
		  div(div(fi->pointer, clastersize).rem, fi->volinfo->bytepersec).quot;
1308

1309
		/* Case 1 - File pointer is not on a sector boundary */
1310
		if (div(fi->pointer, fi->volinfo->bytepersec).rem) {
1311
			uint16_t tempsize;
1312

1313
			/* We always have to go through scratch in this case */
1314
			result = fat_read_sector(fsi, p_scratch, sector);
1315

1316
			/*
1317
			 * This is the number of bytes that we don't want to molest in the
1318
			 * scratch sector just read.
1319
			 */
1320
			tempsize = div(fi->pointer, fi->volinfo->bytepersec).rem;
1321

1322
			/*
1323
			 * Case 1A - We are writing the entire remainder of the sector.
1324
			 * After this point, all passes through the read loop will be
1325
			 * aligned on a sector boundary, which allows us to go through the
1326
			 * optimal path
1327
			 * 2A below.
1328
			 */
1329
		   	if (remain >= fi->volinfo->bytepersec - tempsize) {
1330
				memcpy(p_scratch + tempsize, buffer, fi->volinfo->bytepersec - tempsize);
1331
				if (!result) {
1332
					result = fat_write_sector(fsi, p_scratch, sector);
1333
				}
1334

1335
				byteswritten = fi->volinfo->bytepersec - tempsize;
1336
				buffer += fi->volinfo->bytepersec - tempsize;
1337
				fi->pointer += fi->volinfo->bytepersec - tempsize;
1338
				if (*size < fi->pointer) {
1339
					*size = fi->pointer;
1340
				}
1341
				remain -= fi->volinfo->bytepersec - tempsize;
1342
			}
1343
			/* Case 1B - This concludes the file write operation */
1344
			else {
1345
				memcpy(p_scratch + tempsize, buffer, remain);
1346
				if (!result) {
1347
					result = fat_write_sector(fsi, p_scratch, sector);
1348
				}
1349

1350
				buffer += remain;
1351
				fi->pointer += remain;
1352
				if (*size < fi->pointer) {
1353
					*size = fi->pointer;
1354
				}
1355
				byteswritten = remain;
1356
				remain = 0;
1357
			}
1358
		} /* case 1 */
1359
		/* Case 2 - File pointer is on sector boundary */
1360
		else {
1361
			/* Case 2A - We have at least one more full sector to write and
1362
			 * don't have to go through the scratch buffer. You could insert
1363
			 * optimizations here to write multiple sectors at a time, if you
1364
			 * were thus inclined. Refer to similar notes in fat_read_file.
1365
			 */
1366
			if (remain >= fi->volinfo->bytepersec) {
1367
				result = fat_write_sector(fsi, buffer, sector);
1368
				remain -= fi->volinfo->bytepersec;
1369
				buffer += fi->volinfo->bytepersec;
1370
				fi->pointer += fi->volinfo->bytepersec;
1371
				if (*size < fi->pointer) {
1372
					*size = fi->pointer;
1373
				}
1374
				byteswritten = fi->volinfo->bytepersec;
1375
			}
1376
			/*
1377
			 * Case 2B - We are only writing a partial sector and potentially
1378
			 * need to go through the scratch buffer.
1379
			 */
1380
			else {
1381
				/* If the current file pointer is not yet at or beyond the file
1382
				 * length, we are writing somewhere in the middle of the file
1383
				 * and need to load the original sector to do
1384
				 * a read-modify-write.
1385
				 */
1386
				if (fi->pointer < *size) {
1387
					result = fat_read_sector(fsi, p_scratch, sector);
1388
					if (!result) {
1389
						memcpy(p_scratch, buffer, remain);
1390
						result = fat_write_sector(fsi, p_scratch, sector);
1391
					}
1392
				}
1393
				else {
1394
					memset(p_scratch, 0, fi->volinfo->bytepersec);
1395
					memcpy(p_scratch, buffer, remain);
1396
					result = fat_write_sector(fsi, p_scratch, sector);
1397
				}
1398

1399
				buffer += remain;
1400
				fi->pointer += remain;
1401
				if (*size < fi->pointer) {
1402
					*size = fi->pointer;
1403
				}
1404
				byteswritten = remain;
1405
				remain = 0;
1406
			}
1407
		}
1408

1409
		*successcount += byteswritten;
1410

1411
		/* check to see if we stepped over a cluster boundary */
1412
		if (div(fi->pointer - byteswritten, clastersize).quot !=
1413
				div(fi->pointer, clastersize).quot) {
1414

1415
		  	/* We've transgressed into another cluster. If we were already
1416
		  	 * at EOF, we need to allocate a new cluster.
1417
		  	 * An act of minor evil - we use byteswritten as a scratch integer,
1418
		  	 * knowing that its value is not used after updating *successcount
1419
		  	 * above
1420
		  	 */
1421
		  	byteswritten = 0;
1422

1423
			lastcluster = fi->cluster;
1424
			fi->cluster = fat_get_fat(fsi, p_scratch, fi->cluster);
1425

1426
			/* Allocate a new cluster? */
1427
			if (fat_is_end_of_chain(fsi, fi->cluster)) {
1428
			  	uint32_t tempclus;
1429
				tempclus = fat_get_free_fat(fsi, p_scratch);
1430
				if (tempclus == DFS_BAD_CLUS)
1431
					return DFS_ERRMISC;
1432
				/* Link new cluster onto file */
1433
				fat_set_fat(fsi, p_scratch, lastcluster, tempclus);
1434
				fi->cluster = tempclus;
1435
				tempclus = fat_end_of_chain(fsi);
1436
				fat_set_fat(fsi, p_scratch, fi->cluster, tempclus);
1437

1438
				result = DFS_OK;
1439
			}
1440
		}
1441
	}
1442
	/* If cleared, then mark free clusters*/
1443
	// TODO implement fat truncate
1444
	if (0 && *size > fi->pointer) {
1445
		if (div(*size, clastersize).quot !=
1446
			div(fi->pointer, clastersize).quot) {
1447

1448
			nextcluster = fat_get_fat(fsi, p_scratch, fi->cluster);
1449

1450
			lastcluster = fat_end_of_chain(fsi);
1451
			fat_set_fat(fsi, p_scratch, fi->cluster, lastcluster);
1452

1453
			/* Now follow the cluster chain to free the file space */
1454
			while (!fat_is_end_of_chain(fsi, nextcluster)) {
1455
				lastcluster = nextcluster;
1456
				nextcluster = fat_get_fat(fsi, p_scratch, nextcluster);
1457

1458
				fat_set_fat(fsi, p_scratch, lastcluster, 0);
1459
			}
1460

1461
		}
1462
	}
1463

1464
	/* Update directory entry */
1465
	if (fat_read_sector(fsi, p_scratch, fi->dirsector)) {
1466
		return DFS_ERRMISC;
1467
	}
1468

1469
	if (new_clus != 0) {
1470
		fat_direntry_set_clus(&((struct fat_dirent*) p_scratch)[fi->diroffset], new_clus);
1471
	}
1472

1473
	fat_direntry_set_size(&((struct fat_dirent*) p_scratch)[fi->diroffset], *size);
1474

1475
	if (fat_write_sector(fsi, p_scratch, fi->dirsector)) {
1476
		return DFS_ERRMISC;
1477
	}
1478

1479
	return result;
1480
}
1481

1482
static void fat_dir_clean_long(struct dirinfo *di, struct fat_file_info *fi) {
1483
	struct fat_dirent de = { };
1484
	struct dirinfo saved_di = { };
1485
	struct dirinfo last_di = { };
1486
	void *p_scratch = di->p_scratch;
1487
	struct fat_fs_info *fsi = fi->fsi;
1488

1489
	fat_reset_dir(di);
1490

1491
	if (read_dir_buf(di)) {
1492
		return;
1493
	}
1494

1495
	while (true) {
1496
		memcpy(&last_di, di, sizeof(last_di));
1497

1498
		fat_get_next(di, &de);
1499

1500
		if (fi->cluster == fat_direntry_get_clus(&de)) {
1501
			if (saved_di.p_scratch == NULL) {
1502
				/* Not a long entry */
1503
				return;
1504
			}
1505

1506
			read_dir_buf(&saved_di);
1507

1508
			while (saved_di.currententry != di->currententry ||
1509
					saved_di.currentcluster != di->currentcluster ||
1510
					saved_di.currentsector != di->currentsector) {
1511
				((struct fat_dirent*) p_scratch)[saved_di.currententry].name[0] = 0xe5;
1512

1513
				if (fat_write_sector(fsi, p_scratch, fat_current_dirsector(&saved_di))) {
1514
					return;
1515
				}
1516

1517
				fat_get_next(&saved_di, &de);
1518
			}
1519

1520
			return;
1521
		}
1522

1523
		if (de.attr != ATTR_LONG_NAME) {
1524
			memset(&saved_di, 0, sizeof(saved_di));
1525
		} else if ((de.name[0] & FAT_LONG_ORDER_NUM_MASK) &&
1526
				saved_di.p_scratch == NULL) {
1527
			/* Save directory state only if it was not saved
1528
			 * for previous entry */
1529
			memcpy(&saved_di, &last_di, sizeof(saved_di));
1530
		}
1531
	}
1532
}
1533

1534
int fat_dir_empty(struct fat_file_info *fi) {
1535
	struct dirinfo *di = (void *) fi;
1536
	struct fat_dirent de = { };
1537
	int res = 0;
1538

1539
	fat_reset_dir(di);
1540

1541
	if (read_dir_buf(di)) {
1542
		return 0;
1543
	}
1544

1545
	while (de.name[0] == '\0' && res != DFS_EOF) {
1546
		res = fat_get_next(di, &de);
1547
		if (!strncmp((void *) de.name, ".  ", 3) ||
1548
			!strncmp((void *) de.name, ".. ", 3) ||
1549
			de.name[0] == 0xe5 ||
1550
			ATTR_LONG_NAME == (de.attr & ATTR_LONG_NAME)) {
1551
			de.name[0] = '\0';
1552
		}
1553
	}
1554

1555
	return DFS_EOF == res;
1556
}
1557

1558
/*
1559
 * Delete a file
1560
 * p_scratch must point to a sector-sized buffer
1561
 */
1562
int fat_unlike_file(struct fat_file_info *fi, uint8_t *p_scratch) {
1563
	uint32_t tempclus;
1564
	struct fat_fs_info *fsi;
1565
	struct dirinfo *di = fi->fdi;
1566

1567
	fsi = fi->fsi;
1568

1569

1570
	fat_dir_clean_long(di, fi);
1571

1572
	if (fat_read_sector(fsi, p_scratch, fi->dirsector)) {
1573
		return DFS_ERRMISC;
1574
	}
1575
	((struct fat_dirent*) p_scratch)[fi->diroffset].name[0] = 0xe5;
1576
	if (fat_write_sector(fsi, p_scratch, fi->dirsector)) {
1577
		return DFS_ERRMISC;
1578
	}
1579

1580
	/* Now follow the cluster chain to free the file space */
1581
	while (!fat_is_end_of_chain(fsi, fi->firstcluster)) {
1582
		tempclus = fi->firstcluster;
1583
		fi->firstcluster = fat_get_fat(fsi, p_scratch, fi->firstcluster);
1584
		fat_set_fat(fsi, p_scratch, tempclus, 0);
1585
	}
1586
	return DFS_OK;
1587
}
1588

1589
/**
1590
 * @brief Fill dirent with dirinfo data
1591
 *
1592
 * @param di Directory
1593
 * @param de Dirent to be filled
1594
 *
1595
 * @return Negative error code or zero if succeed
1596
 */
1597
static int fat_dirent_by_file(struct fat_file_info *fi, struct fat_dirent *de) {
1598
	struct fat_fs_info *fsi = fi->fsi;
1599
	void *de_src;
1600

1601
	if (fat_read_sector(fsi, fat_sector_buff, fi->dirsector))
1602
		return -1;
1603

1604
	de_src = &(((struct fat_dirent *)fat_sector_buff)[fi->diroffset]);
1605
	memcpy(de, de_src, sizeof(struct fat_dirent));
1606

1607
	return 0;
1608
}
1609

1610
/**
1611
 * @brief Read directory info from drive and set currentcluster,
1612
 * current sector
1613
 *
1614
 * @param di Directory to be updated. Di->fi.fsi should be set properly.
1615
 *
1616
 * @return Negative error code or zero if succeed
1617
 */
1618
int fat_reset_dir(struct dirinfo *di) {
1619
	struct fat_dirent de = { }; /* Initialize with zeroes to fit -O2 */
1620
	struct volinfo *vi;
1621

1622
	vi = &di->fi.fsi->vi;
1623

1624
	if (di->fi.dirsector == 0) {
1625
		/* This is root dir */
1626
		di->currentcluster = vi->rootdir / vi->secperclus;
1627
		if (vi->filesystem == FAT32) {
1628
			di->currentsector = 0;
1629
			di->currentcluster = 2;
1630
		} else {
1631
			di->currentsector = (vi->rootdir % vi->secperclus);
1632
			di->currentcluster = vi->rootdir / vi->secperclus;
1633
		}
1634

1635
		di->currententry = 0;
1636
	} else {
1637
		fat_dirent_by_file(&di->fi, &de);
1638

1639
		di->currentcluster = fat_direntry_get_clus(&de);
1640
		di->currentsector = 0;
1641
		di->currententry = 0;
1642
	}
1643

1644
	return 0;
1645
}
1646

1647
/*
1648
 * Create a file or directory. You supply a file_create_param_t
1649
 * structure.
1650
 * Returns various DFS_* error states. If the result is DFS_OK, file
1651
 * was created and can be used.
1652
 */
1653
int fat_create_file(struct fat_file_info *fi, struct dirinfo *di, char *name, int mode) {
1654
	uint8_t filename[12];
1655
	struct fat_dirent de;
1656
	struct volinfo *volinfo;
1657
	uint32_t cluster;
1658
	struct fat_fs_info *fsi;
1659
	int entries;
1660
	uint32_t res;
1661

1662
	assert(fi);
1663
	assert(di);
1664
	assert(name);
1665

1666
	fsi = fi->fsi;
1667
	assert(fsi);
1668

1669
	volinfo = &fsi->vi;
1670
	fi->volinfo = volinfo;
1671

1672
	while (*name == '/') {
1673
		name++;
1674
	}
1675
	log_debug("fsi: bytepersec(%d), bdev->block_size(%d)",
1676
			fsi->vi.bytepersec, fsi->bdev->block_size);
1677
	log_debug("name(%s), mode(%x)", name, mode);
1678

1679
	entries = fat_entries_per_name(name);
1680

1681
	di->fi.fsi = fsi;
1682

1683
	res = fat_get_free_entries(di, entries);
1684
	if (res < 0) {
1685
		return -1;
1686
	}
1687

1688
	fat_dir_rewind(di, res);
1689

1690
	if (entries > 1) {
1691
		path_canonical_to_dir((char *) filename, name);
1692
		/* Write long-name descriptors */
1693
		for (int i = entries - 1; i >= 1; i--) {
1694
			memset(&de, 0, sizeof(de));
1695
			fat_write_longname(name + 13 * (i - 1), &de);
1696
			de.attr = ATTR_LONG_NAME;
1697
			de.crttimetenth = fat_canonical_name_checksum((char *) filename);
1698
			de.name[0] = FAT_LONG_ORDER_NUM_MASK & i;
1699
			if (i == entries - 1) {
1700
				de.name[0] |= FAT_LONG_ORDER_LAST;
1701
			}
1702

1703
			fat_write_de(di, &de);
1704
			di->currententry++;
1705
			if (DFS_EOF == fat_fetch_dir(di)) {
1706
				fat_dir_extend(di);
1707
			}
1708
		}
1709
	} else {
1710
		memcpy(filename, name, sizeof(filename));
1711
	}
1712

1713
	cluster = fat_get_free_fat(fsi, fat_sector_buff);
1714
	de = (struct fat_dirent) {
1715
		.attr = S_ISDIR(mode) ? ATTR_DIRECTORY : 0,
1716
	};
1717
	fat_direntry_set_clus(&de, cluster);
1718
	memcpy(de.name, filename, MSDOS_NAME);
1719
	fat_set_filetime(&de);
1720

1721
	fi->volinfo = volinfo;
1722
	fi->pointer = 0;
1723
	fi->dirsector = fat_current_dirsector(di);
1724
	fi->diroffset = di->currententry;
1725
	fi->cluster = cluster;
1726
	fi->firstcluster = cluster;
1727

1728
	fat_write_de(di, &de);
1729

1730
	cluster = fat_end_of_chain(fsi);
1731
	fat_set_fat(fsi, fat_sector_buff, fi->cluster, cluster);
1732

1733
	if (S_ISDIR(mode)) {
1734
		/* create . and ..  files of this catalog */
1735
		fat_set_direntry(di->currentcluster, fi->cluster);
1736
		cluster = fi->volinfo->dataarea +
1737
				  ((fi->cluster - 2) * fi->volinfo->secperclus);
1738
		if (fat_write_sector(fsi, fat_sector_buff, cluster)) {
1739
			return DFS_ERRMISC;
1740
		}
1741
	}
1742

1743
	return DFS_OK;
1744
}
1745

1746
void fat_write_longname(char *name, struct fat_dirent *di) {
1747
	struct fat_long_dirent *ld;
1748
	int l;
1749

1750
	assert(name);
1751
	assert(di);
1752

1753
	ld = (void *) di;
1754
	memset(ld->name1, 0xff, sizeof(ld->name1));
1755
	memset(ld->name2, 0xff, sizeof(ld->name2));
1756
	memset(ld->name3, 0xff, sizeof(ld->name3));
1757

1758
	l = strlen(name) + 1;
1759

1760
	for (int i = 0; i < sizeof(ld->name1) / 2; i++) {
1761
		if (i >= l) {
1762
			return;
1763
		}
1764

1765
		ld->name1[i * 2] = name[i];
1766
		ld->name1[i * 2 + 1] = '\0';
1767
	}
1768

1769
	name += sizeof(ld->name1) / 2;
1770
	l -= sizeof(ld->name1) / 2;
1771

1772
	for (int i = 0; i < sizeof(ld->name2) / 2; i++) {
1773
		if (i >= l) {
1774
			return;
1775
		}
1776

1777
		ld->name2[i * 2] = name[i];
1778
		ld->name2[i * 2 + 1] = '\0';
1779
	}
1780

1781
	name += sizeof(ld->name2) / 2;
1782
	l -= sizeof(ld->name2) / 2;
1783

1784
	for (int i = 0; i < sizeof(ld->name3) / 2; i++) {
1785
		if (i >= l) {
1786
			return;
1787
		}
1788

1789
		ld->name3[i * 2] = name[i];
1790
		ld->name3[i * 2 + 1] = '\0';
1791
	}
1792
}
1793

1794
int fat_read_filename(struct fat_file_info *fi, void *p_scratch, char *name) {
1795
	struct fat_dirent de;
1796
	struct dirinfo *dir;
1797
	int offt = 1;
1798

1799
	assert(name);
1800
	assert(fi);
1801

1802
	log_debug("fi->dirsector (%d)", fi->dirsector);
1803

1804
	name[0] = '\0';
1805

1806
	dir = fi->fdi;
1807
	fat_reset_dir(dir);
1808
	read_dir_buf(dir);
1809

1810
	while (1) {
1811
		int dirsect =fat_current_dirsector(dir);
1812

1813
		if (dirsect == fi->dirsector && dir->currententry == fi->diroffset + 1) {
1814
			break;
1815
		}
1816

1817
		fat_get_next_long(dir, &de, name);
1818
	}
1819

1820
	if (name[0] == '\0') {
1821
		/* Entry is the first in the directory */
1822
		fat_get_next_long(dir, &de, name);
1823
	}
1824

1825
	/* In FAT names by default are padded with zeroes,
1826
	 * we don't want that in VFS tree */
1827
	offt = strlen(name);
1828
	while (name[offt - 1] == ' ' && offt > 0) {
1829
		name[--offt] = '\0';
1830
	}
1831
	log_debug("name(%s)", name);
1832

1833
	return DFS_OK;
1834
}
1835

1836
static bool fat_old_dirent_symbol(char c) {
1837
	if (c == ' ') {
1838
		return true;
1839
	}
1840

1841
	if (c >= 'A' && c <= 'Z') {
1842
		return true;
1843
	}
1844

1845
	if (c >= '0' && c <= '9') {
1846
		return true;
1847
	}
1848

1849
	return false;
1850
}
1851

1852
/* Count how much long name entries will it take */
1853
int fat_entries_per_name(const char *name) {
1854
	ssize_t l;
1855
	bool old_compat = true;
1856

1857
	assert(name);
1858

1859
	l = strlen(name);
1860

1861
	if (l > MSDOS_NAME) {
1862
		old_compat = false;
1863
	} else {
1864
		for (int i = 0; i < l; i++) {
1865
			if (!fat_old_dirent_symbol(name[i])) {
1866
				old_compat = false;
1867
			}
1868
		}
1869
	}
1870

1871
	if (old_compat) {
1872
		return 1;
1873
	} else {
1874
		int ret = 1; /* We need at least one 8.3 entry */
1875
		while (l > 0) {
1876
			ret++;
1877
			l -= 13;
1878
		}
1879

1880
		return ret;
1881
	}
1882
}
1883

1884
static uint32_t fat_dir_rewind(struct dirinfo *di, int n) {
1885
	fat_reset_dir(di);
1886
	read_dir_buf(di);
1887

1888
	for (int i = 0; i < n; i++) {
1889
		di->currententry++;
1890
		fat_fetch_dir(di);
1891
	}
1892

1893
	return 0;
1894
}
1895

1896
static uint32_t fat_get_free_entries(struct dirinfo *dir, int n) {
1897
	struct fat_dirent de;
1898
	uint32_t res;
1899
	int offt = 0;
1900
	bool failed;
1901

1902
	assert(dir);
1903

1904
	fat_reset_dir(dir);
1905
	read_dir_buf(dir);
1906

1907
	while (true) {
1908
		failed = false;
1909

1910
		/* Find some free entry */
1911
		res = fat_get_free_dir_ent(dir, &de);
1912
		if (res >= 0) {
1913
			offt += res;
1914
		} else {
1915
			while (1);
1916
		}
1917

1918
		if (res == DFS_EOF) {
1919
			break;
1920
		}
1921

1922
		/* Check if following N - 1 entries are free as well */
1923
		for (int i = 0; i < n - 1; i++) {
1924
			dir->currententry++;
1925
			res = fat_fetch_dir(dir);
1926
			if (res == DFS_ALLOCNEW) {
1927
				/* Need to allocate new cluster */
1928
				if (DFS_OK != (res = fat_dir_extend(dir))) {
1929
					return -1;
1930
				}
1931
			}
1932
			res = fat_get_current(dir, &de);
1933
			if (res == DFS_OK && de.name[0] != '\0') {
1934
				failed = true;
1935
				offt += i + 1;
1936
				break;
1937
			}
1938

1939
			if (res == DFS_EOF) {
1940
				break;
1941
			}
1942
		}
1943

1944
		if (failed) {
1945
			continue;
1946
		}
1947

1948
		break;
1949
	}
1950

1951
	return offt;
1952
}
1953

1954
static uint32_t fat_write_de(struct dirinfo *di, struct fat_dirent *de) {
1955
	uint32_t sector;
1956
	struct fat_fs_info *fsi = di->fi.fsi;
1957

1958
	assert(di);
1959
	assert(de);
1960

1961
	sector = fat_current_dirsector(di);
1962

1963
	if (fat_read_sector(fsi, di->p_scratch, sector))
1964
		return -1;
1965

1966
	memcpy(&(((struct fat_dirent *) di->p_scratch)[di->currententry]),
1967
			de, sizeof(struct fat_dirent));
1968
	if (fat_write_sector(fsi, di->p_scratch, sector))
1969
		return -1;
1970

1971
	return 0;
1972
}
1973

1974
uint8_t fat_canonical_name_checksum(const char *name) {
1975
	uint8_t res = 0x00;
1976

1977
	assert(name);
1978

1979
	for (int i = 0; i < MSDOS_NAME; i++) {
1980
		res = (res / 2) + (res % 2) * 0x80;
1981
		res += name[i];
1982
	}
1983

1984
	return res;
1985
}
1986

1987
int fat_alloc_inode_priv(struct inode *inode, struct fat_dirent *de) {
1988
	struct fat_file_info *fi;
1989
	
1990
	fi = inode_priv(inode);
1991
	if (fi) {
1992
		/*we already allocated file info for this inode */
1993
		return 0;
1994
	}
1995
	
1996
	if (de->attr & ATTR_DIRECTORY){
1997
		struct dirinfo *new_di;
1998

1999
		new_di = fat_dirinfo_alloc();
2000
		if (NULL == new_di) {
2001
			return -ENOMEM;
2002
		}
2003

2004
		memset(new_di, 0, sizeof(struct dirinfo));
2005
		new_di->p_scratch = fat_sector_buff;
2006
		new_di->currentcluster = fat_direntry_get_clus(de);
2007

2008
		fi = &new_di->fi;
2009

2010
		inode->i_mode |= S_IFDIR;
2011
	} else {
2012
		fi = fat_file_alloc();
2013
		if (NULL == fi) {
2014
			return -ENOMEM;
2015
		}
2016
		memset(fi, 0, sizeof(struct fat_file_info));
2017

2018
		inode->i_mode |= S_IFREG;
2019
	}
2020

2021
	inode_priv_set(inode, fi);
2022

2023
	return 0;
2024
}
2025

2026
/**
2027
 * @brief Set appropriate flags and i_data for given inode
2028
 *
2029
 * @param inode Inode to be filled
2030
 * @param di FAT directory entry related to file
2031
 *
2032
 * @return Negative error code or zero if succeed
2033
 */
2034
int fat_fill_inode(struct inode *inode, struct fat_dirent *de, struct dirinfo *di) {
2035
	struct fat_file_info *fi;
2036
	struct fat_fs_info *fsi;
2037
	struct volinfo *vi;
2038
	struct super_block *sb;
2039
	int res, tmp_sector, tmp_entry, tmp_cluster;
2040

2041
	assert(de);
2042
	assert(inode);
2043
	assert(di);
2044

2045
	sb = inode->i_sb;
2046
	assert(sb);
2047

2048
	fsi = sb->sb_data;
2049
	assert(fsi);
2050

2051
	vi = &fsi->vi;
2052
	assert(vi);
2053

2054
	fi = inode_priv(inode);
2055
	assert(fi);
2056

2057
	/* Need to save some dirinfo data because this
2058
	 * stuff may change while we traverse to the end
2059
	 * of long name entry */
2060
	tmp_sector = di->currentsector;
2061
	tmp_entry = di->currententry;
2062
	tmp_cluster = di->currentcluster;
2063

2064
	while (de->attr == ATTR_LONG_NAME) {
2065
		res = fat_get_next(di, de);
2066

2067
		if (res != DFS_OK && res != DFS_ALLOCNEW) {
2068
			return -EINVAL;
2069
		}
2070
	}
2071

2072
	if (di->fi.dirsector == 0 && (vi->filesystem == FAT12 || vi->filesystem == FAT16)) {
2073
		fi->dirsector = tmp_sector + tmp_cluster * vi->secperclus;
2074
	} else {
2075
		fi->dirsector = tmp_sector + fat_sec_by_clus(fsi, tmp_cluster);
2076
	}
2077
	fi->fsi = fsi;
2078
	fi->volinfo = vi;
2079
	fi->diroffset    = tmp_entry - 1;
2080
	fi->cluster      = fat_direntry_get_clus(de);
2081
	fi->firstcluster = fi->cluster;
2082
	fi->filelen      = fat_direntry_get_size(de);
2083
	fi->fdi          = di;
2084

2085
	inode_size_set(inode, fi->filelen);
2086
	if (de->attr & ATTR_READ_ONLY) {
2087
		inode->i_mode |= S_IRALL;
2088
	} else {
2089
		inode->i_mode |= S_IRWXA;
2090
	}
2091

2092
	return 0;
2093
}
2094

2095
int fat_destroy_inode(struct inode *inode) {
2096
	struct fat_file_info *fi;
2097
	struct dirinfo *di;
2098

2099
	if (!inode_priv(inode)) {
2100
		return 0;
2101
	}
2102

2103
	if (S_ISDIR(inode->i_mode)) {
2104
		di = inode_priv(inode);
2105
		fat_dirinfo_free(di);
2106
	} else {
2107
		fi = inode_priv(inode);
2108
		fat_file_free(fi);
2109
	}
2110

2111
	inode_priv_set(inode, NULL);
2112

2113
	return 0;
2114
}
2115

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.