xref: /rk3399_rockchip-uboot/fs/fat/fat_write.c (revision fb7e16cc1c1f5d5bb212118b89218b2e706226b2)
1 /*
2  * fat_write.c
3  *
4  * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24 
25 #include <common.h>
26 #include <command.h>
27 #include <config.h>
28 #include <fat.h>
29 #include <asm/byteorder.h>
30 #include <part.h>
31 #include <linux/ctype.h>
32 #include "fat.c"
33 
34 static void uppercase(char *str, int len)
35 {
36 	int i;
37 
38 	for (i = 0; i < len; i++) {
39 		*str = toupper(*str);
40 		str++;
41 	}
42 }
43 
44 static int total_sector;
45 static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
46 {
47 	if (!cur_dev || !cur_dev->block_write)
48 		return -1;
49 
50 	if (cur_part_info.start + block + nr_blocks >
51 		cur_part_info.start + total_sector) {
52 		printf("error: overflow occurs\n");
53 		return -1;
54 	}
55 
56 	return cur_dev->block_write(cur_dev->dev,
57 			cur_part_info.start + block, nr_blocks,	buf);
58 }
59 
60 /*
61  * Set short name in directory entry
62  */
63 static void set_name(dir_entry *dirent, const char *filename)
64 {
65 	char s_name[VFAT_MAXLEN_BYTES];
66 	char *period;
67 	int period_location, len, i, ext_num;
68 
69 	if (filename == NULL)
70 		return;
71 
72 	len = strlen(filename);
73 	if (len == 0)
74 		return;
75 
76 	memcpy(s_name, filename, len);
77 	uppercase(s_name, len);
78 
79 	period = strchr(s_name, '.');
80 	if (period == NULL) {
81 		period_location = len;
82 		ext_num = 0;
83 	} else {
84 		period_location = period - s_name;
85 		ext_num = len - period_location - 1;
86 	}
87 
88 	/* Pad spaces when the length of file name is shorter than eight */
89 	if (period_location < 8) {
90 		memcpy(dirent->name, s_name, period_location);
91 		for (i = period_location; i < 8; i++)
92 			dirent->name[i] = ' ';
93 	} else if (period_location == 8) {
94 		memcpy(dirent->name, s_name, period_location);
95 	} else {
96 		memcpy(dirent->name, s_name, 6);
97 		dirent->name[6] = '~';
98 		dirent->name[7] = '1';
99 	}
100 
101 	if (ext_num < 3) {
102 		memcpy(dirent->ext, s_name + period_location + 1, ext_num);
103 		for (i = ext_num; i < 3; i++)
104 			dirent->ext[i] = ' ';
105 	} else
106 		memcpy(dirent->ext, s_name + period_location + 1, 3);
107 
108 	debug("name : %s\n", dirent->name);
109 	debug("ext : %s\n", dirent->ext);
110 }
111 
112 static __u8 num_of_fats;
113 /*
114  * Write fat buffer into block device
115  */
116 static int flush_fat_buffer(fsdata *mydata)
117 {
118 	int getsize = FATBUFBLOCKS;
119 	__u32 fatlength = mydata->fatlength;
120 	__u8 *bufptr = mydata->fatbuf;
121 	__u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
122 
123 	fatlength *= mydata->sect_size;
124 	startblock += mydata->fat_sect;
125 
126 	if (getsize > fatlength)
127 		getsize = fatlength;
128 
129 	/* Write FAT buf */
130 	if (disk_write(startblock, getsize, bufptr) < 0) {
131 		debug("error: writing FAT blocks\n");
132 		return -1;
133 	}
134 
135 	if (num_of_fats == 2) {
136 		/* Update corresponding second FAT blocks */
137 		startblock += mydata->fatlength;
138 		if (disk_write(startblock, getsize, bufptr) < 0) {
139 			debug("error: writing second FAT blocks\n");
140 			return -1;
141 		}
142 	}
143 
144 	return 0;
145 }
146 
147 /*
148  * Get the entry at index 'entry' in a FAT (12/16/32) table.
149  * On failure 0x00 is returned.
150  * When bufnum is changed, write back the previous fatbuf to the disk.
151  */
152 static __u32 get_fatent_value(fsdata *mydata, __u32 entry)
153 {
154 	__u32 bufnum;
155 	__u32 off16, offset;
156 	__u32 ret = 0x00;
157 	__u16 val1, val2;
158 
159 	switch (mydata->fatsize) {
160 	case 32:
161 		bufnum = entry / FAT32BUFSIZE;
162 		offset = entry - bufnum * FAT32BUFSIZE;
163 		break;
164 	case 16:
165 		bufnum = entry / FAT16BUFSIZE;
166 		offset = entry - bufnum * FAT16BUFSIZE;
167 		break;
168 	case 12:
169 		bufnum = entry / FAT12BUFSIZE;
170 		offset = entry - bufnum * FAT12BUFSIZE;
171 		break;
172 
173 	default:
174 		/* Unsupported FAT size */
175 		return ret;
176 	}
177 
178 	debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n",
179 	       mydata->fatsize, entry, entry, offset, offset);
180 
181 	/* Read a new block of FAT entries into the cache. */
182 	if (bufnum != mydata->fatbufnum) {
183 		int getsize = FATBUFBLOCKS;
184 		__u8 *bufptr = mydata->fatbuf;
185 		__u32 fatlength = mydata->fatlength;
186 		__u32 startblock = bufnum * FATBUFBLOCKS;
187 
188 		if (getsize > fatlength)
189 			getsize = fatlength;
190 
191 		fatlength *= mydata->sect_size;	/* We want it in bytes now */
192 		startblock += mydata->fat_sect;	/* Offset from start of disk */
193 
194 		/* Write back the fatbuf to the disk */
195 		if (mydata->fatbufnum != -1) {
196 			if (flush_fat_buffer(mydata) < 0)
197 				return -1;
198 		}
199 
200 		if (disk_read(startblock, getsize, bufptr) < 0) {
201 			debug("Error reading FAT blocks\n");
202 			return ret;
203 		}
204 		mydata->fatbufnum = bufnum;
205 	}
206 
207 	/* Get the actual entry from the table */
208 	switch (mydata->fatsize) {
209 	case 32:
210 		ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]);
211 		break;
212 	case 16:
213 		ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]);
214 		break;
215 	case 12:
216 		off16 = (offset * 3) / 4;
217 
218 		switch (offset & 0x3) {
219 		case 0:
220 			ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]);
221 			ret &= 0xfff;
222 			break;
223 		case 1:
224 			val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
225 			val1 &= 0xf000;
226 			val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
227 			val2 &= 0x00ff;
228 			ret = (val2 << 4) | (val1 >> 12);
229 			break;
230 		case 2:
231 			val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
232 			val1 &= 0xff00;
233 			val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
234 			val2 &= 0x000f;
235 			ret = (val2 << 8) | (val1 >> 8);
236 			break;
237 		case 3:
238 			ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
239 			ret = (ret & 0xfff0) >> 4;
240 			break;
241 		default:
242 			break;
243 		}
244 		break;
245 	}
246 	debug("FAT%d: ret: %08x, entry: %08x, offset: %04x\n",
247 	       mydata->fatsize, ret, entry, offset);
248 
249 	return ret;
250 }
251 
252 #ifdef CONFIG_SUPPORT_VFAT
253 /*
254  * Set the file name information from 'name' into 'slotptr',
255  */
256 static int str2slot(dir_slot *slotptr, const char *name, int *idx)
257 {
258 	int j, end_idx = 0;
259 
260 	for (j = 0; j <= 8; j += 2) {
261 		if (name[*idx] == 0x00) {
262 			slotptr->name0_4[j] = 0;
263 			slotptr->name0_4[j + 1] = 0;
264 			end_idx++;
265 			goto name0_4;
266 		}
267 		slotptr->name0_4[j] = name[*idx];
268 		(*idx)++;
269 		end_idx++;
270 	}
271 	for (j = 0; j <= 10; j += 2) {
272 		if (name[*idx] == 0x00) {
273 			slotptr->name5_10[j] = 0;
274 			slotptr->name5_10[j + 1] = 0;
275 			end_idx++;
276 			goto name5_10;
277 		}
278 		slotptr->name5_10[j] = name[*idx];
279 		(*idx)++;
280 		end_idx++;
281 	}
282 	for (j = 0; j <= 2; j += 2) {
283 		if (name[*idx] == 0x00) {
284 			slotptr->name11_12[j] = 0;
285 			slotptr->name11_12[j + 1] = 0;
286 			end_idx++;
287 			goto name11_12;
288 		}
289 		slotptr->name11_12[j] = name[*idx];
290 		(*idx)++;
291 		end_idx++;
292 	}
293 
294 	if (name[*idx] == 0x00)
295 		return 1;
296 
297 	return 0;
298 /* Not used characters are filled with 0xff 0xff */
299 name0_4:
300 	for (; end_idx < 5; end_idx++) {
301 		slotptr->name0_4[end_idx * 2] = 0xff;
302 		slotptr->name0_4[end_idx * 2 + 1] = 0xff;
303 	}
304 	end_idx = 5;
305 name5_10:
306 	end_idx -= 5;
307 	for (; end_idx < 6; end_idx++) {
308 		slotptr->name5_10[end_idx * 2] = 0xff;
309 		slotptr->name5_10[end_idx * 2 + 1] = 0xff;
310 	}
311 	end_idx = 11;
312 name11_12:
313 	end_idx -= 11;
314 	for (; end_idx < 2; end_idx++) {
315 		slotptr->name11_12[end_idx * 2] = 0xff;
316 		slotptr->name11_12[end_idx * 2 + 1] = 0xff;
317 	}
318 
319 	return 1;
320 }
321 
322 static int is_next_clust(fsdata *mydata, dir_entry *dentptr);
323 static void flush_dir_table(fsdata *mydata, dir_entry **dentptr);
324 
325 /*
326  * Fill dir_slot entries with appropriate name, id, and attr
327  * The real directory entry is returned by 'dentptr'
328  */
329 static void
330 fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name)
331 {
332 	dir_slot *slotptr = (dir_slot *)get_contents_vfatname_block;
333 	__u8 counter = 0, checksum;
334 	int idx = 0, ret;
335 	char s_name[16];
336 
337 	/* Get short file name and checksum value */
338 	strncpy(s_name, (*dentptr)->name, 16);
339 	checksum = mkcksum((*dentptr)->name, (*dentptr)->ext);
340 
341 	do {
342 		memset(slotptr, 0x00, sizeof(dir_slot));
343 		ret = str2slot(slotptr, l_name, &idx);
344 		slotptr->id = ++counter;
345 		slotptr->attr = ATTR_VFAT;
346 		slotptr->alias_checksum = checksum;
347 		slotptr++;
348 	} while (ret == 0);
349 
350 	slotptr--;
351 	slotptr->id |= LAST_LONG_ENTRY_MASK;
352 
353 	while (counter >= 1) {
354 		if (is_next_clust(mydata, *dentptr)) {
355 			/* A new cluster is allocated for directory table */
356 			flush_dir_table(mydata, dentptr);
357 		}
358 		memcpy(*dentptr, slotptr, sizeof(dir_slot));
359 		(*dentptr)++;
360 		slotptr--;
361 		counter--;
362 	}
363 
364 	if (is_next_clust(mydata, *dentptr)) {
365 		/* A new cluster is allocated for directory table */
366 		flush_dir_table(mydata, dentptr);
367 	}
368 }
369 
370 static __u32 dir_curclust;
371 
372 /*
373  * Extract the full long filename starting at 'retdent' (which is really
374  * a slot) into 'l_name'. If successful also copy the real directory entry
375  * into 'retdent'
376  * If additional adjacent cluster for directory entries is read into memory,
377  * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' and
378  * the location of the real directory entry is returned by 'retdent'
379  * Return 0 on success, -1 otherwise.
380  */
381 static int
382 get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster,
383 	      dir_entry **retdent, char *l_name)
384 {
385 	dir_entry *realdent;
386 	dir_slot *slotptr = (dir_slot *)(*retdent);
387 	dir_slot *slotptr2 = NULL;
388 	__u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
389 							PREFETCH_BLOCKS :
390 							mydata->clust_size);
391 	__u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
392 	int idx = 0, cur_position = 0;
393 
394 	if (counter > VFAT_MAXSEQ) {
395 		debug("Error: VFAT name is too long\n");
396 		return -1;
397 	}
398 
399 	while ((__u8 *)slotptr < buflimit) {
400 		if (counter == 0)
401 			break;
402 		if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter)
403 			return -1;
404 		slotptr++;
405 		counter--;
406 	}
407 
408 	if ((__u8 *)slotptr >= buflimit) {
409 		if (curclust == 0)
410 			return -1;
411 		curclust = get_fatent_value(mydata, dir_curclust);
412 		if (CHECK_CLUST(curclust, mydata->fatsize)) {
413 			debug("curclust: 0x%x\n", curclust);
414 			printf("Invalid FAT entry\n");
415 			return -1;
416 		}
417 
418 		dir_curclust = curclust;
419 
420 		if (get_cluster(mydata, curclust, get_contents_vfatname_block,
421 				mydata->clust_size * mydata->sect_size) != 0) {
422 			debug("Error: reading directory block\n");
423 			return -1;
424 		}
425 
426 		slotptr2 = (dir_slot *)get_contents_vfatname_block;
427 		while (counter > 0) {
428 			if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
429 			    & 0xff) != counter)
430 				return -1;
431 			slotptr2++;
432 			counter--;
433 		}
434 
435 		/* Save the real directory entry */
436 		realdent = (dir_entry *)slotptr2;
437 		while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
438 			slotptr2--;
439 			slot2str(slotptr2, l_name, &idx);
440 		}
441 	} else {
442 		/* Save the real directory entry */
443 		realdent = (dir_entry *)slotptr;
444 	}
445 
446 	do {
447 		slotptr--;
448 		if (slot2str(slotptr, l_name, &idx))
449 			break;
450 	} while (!(slotptr->id & LAST_LONG_ENTRY_MASK));
451 
452 	l_name[idx] = '\0';
453 	if (*l_name == DELETED_FLAG)
454 		*l_name = '\0';
455 	else if (*l_name == aRING)
456 		*l_name = DELETED_FLAG;
457 	downcase(l_name);
458 
459 	/* Return the real directory entry */
460 	*retdent = realdent;
461 
462 	if (slotptr2) {
463 		memcpy(get_dentfromdir_block, get_contents_vfatname_block,
464 			mydata->clust_size * mydata->sect_size);
465 		cur_position = (__u8 *)realdent - get_contents_vfatname_block;
466 		*retdent = (dir_entry *) &get_dentfromdir_block[cur_position];
467 	}
468 
469 	return 0;
470 }
471 
472 #endif
473 
474 /*
475  * Set the entry at index 'entry' in a FAT (16/32) table.
476  */
477 static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
478 {
479 	__u32 bufnum, offset;
480 
481 	switch (mydata->fatsize) {
482 	case 32:
483 		bufnum = entry / FAT32BUFSIZE;
484 		offset = entry - bufnum * FAT32BUFSIZE;
485 		break;
486 	case 16:
487 		bufnum = entry / FAT16BUFSIZE;
488 		offset = entry - bufnum * FAT16BUFSIZE;
489 		break;
490 	default:
491 		/* Unsupported FAT size */
492 		return -1;
493 	}
494 
495 	/* Read a new block of FAT entries into the cache. */
496 	if (bufnum != mydata->fatbufnum) {
497 		int getsize = FATBUFBLOCKS;
498 		__u8 *bufptr = mydata->fatbuf;
499 		__u32 fatlength = mydata->fatlength;
500 		__u32 startblock = bufnum * FATBUFBLOCKS;
501 
502 		fatlength *= mydata->sect_size;
503 		startblock += mydata->fat_sect;
504 
505 		if (getsize > fatlength)
506 			getsize = fatlength;
507 
508 		if (mydata->fatbufnum != -1) {
509 			if (flush_fat_buffer(mydata) < 0)
510 				return -1;
511 		}
512 
513 		if (disk_read(startblock, getsize, bufptr) < 0) {
514 			debug("Error reading FAT blocks\n");
515 			return -1;
516 		}
517 		mydata->fatbufnum = bufnum;
518 	}
519 
520 	/* Set the actual entry */
521 	switch (mydata->fatsize) {
522 	case 32:
523 		((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
524 		break;
525 	case 16:
526 		((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
527 		break;
528 	default:
529 		return -1;
530 	}
531 
532 	return 0;
533 }
534 
535 /*
536  * Determine the entry value at index 'entry' in a FAT (16/32) table
537  */
538 static __u32 determine_fatent(fsdata *mydata, __u32 entry)
539 {
540 	__u32 next_fat, next_entry = entry + 1;
541 
542 	while (1) {
543 		next_fat = get_fatent_value(mydata, next_entry);
544 		if (next_fat == 0) {
545 			set_fatent_value(mydata, entry, next_entry);
546 			break;
547 		}
548 		next_entry++;
549 	}
550 	debug("FAT%d: entry: %08x, entry_value: %04x\n",
551 	       mydata->fatsize, entry, next_entry);
552 
553 	return next_entry;
554 }
555 
556 /*
557  * Write at most 'size' bytes from 'buffer' into the specified cluster.
558  * Return 0 on success, -1 otherwise.
559  */
560 static int
561 set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
562 	     unsigned long size)
563 {
564 	int idx = 0;
565 	__u32 startsect;
566 
567 	if (clustnum > 0)
568 		startsect = mydata->data_begin +
569 				clustnum * mydata->clust_size;
570 	else
571 		startsect = mydata->rootdir_sect;
572 
573 	debug("clustnum: %d, startsect: %d\n", clustnum, startsect);
574 
575 	if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) {
576 		debug("Error writing data\n");
577 		return -1;
578 	}
579 
580 	if (size % mydata->sect_size) {
581 		__u8 tmpbuf[mydata->sect_size];
582 
583 		idx = size / mydata->sect_size;
584 		buffer += idx * mydata->sect_size;
585 		memcpy(tmpbuf, buffer, size % mydata->sect_size);
586 
587 		if (disk_write(startsect + idx, 1, tmpbuf) < 0) {
588 			debug("Error writing data\n");
589 			return -1;
590 		}
591 
592 		return 0;
593 	}
594 
595 	return 0;
596 }
597 
598 /*
599  * Find the first empty cluster
600  */
601 static int find_empty_cluster(fsdata *mydata)
602 {
603 	__u32 fat_val, entry = 3;
604 
605 	while (1) {
606 		fat_val = get_fatent_value(mydata, entry);
607 		if (fat_val == 0)
608 			break;
609 		entry++;
610 	}
611 
612 	return entry;
613 }
614 
615 /*
616  * Write directory entries in 'get_dentfromdir_block' to block device
617  */
618 static void flush_dir_table(fsdata *mydata, dir_entry **dentptr)
619 {
620 	int dir_newclust = 0;
621 
622 	if (set_cluster(mydata, dir_curclust,
623 		    get_dentfromdir_block,
624 		    mydata->clust_size * mydata->sect_size) != 0) {
625 		printf("error: wrinting directory entry\n");
626 		return;
627 	}
628 	dir_newclust = find_empty_cluster(mydata);
629 	set_fatent_value(mydata, dir_curclust, dir_newclust);
630 	if (mydata->fatsize == 32)
631 		set_fatent_value(mydata, dir_newclust, 0xffffff8);
632 	else if (mydata->fatsize == 16)
633 		set_fatent_value(mydata, dir_newclust, 0xfff8);
634 
635 	dir_curclust = dir_newclust;
636 
637 	if (flush_fat_buffer(mydata) < 0)
638 		return;
639 
640 	memset(get_dentfromdir_block, 0x00,
641 		mydata->clust_size * mydata->sect_size);
642 
643 	*dentptr = (dir_entry *) get_dentfromdir_block;
644 }
645 
646 /*
647  * Set empty cluster from 'entry' to the end of a file
648  */
649 static int clear_fatent(fsdata *mydata, __u32 entry)
650 {
651 	__u32 fat_val;
652 
653 	while (1) {
654 		fat_val = get_fatent_value(mydata, entry);
655 		if (fat_val != 0)
656 			set_fatent_value(mydata, entry, 0);
657 		else
658 			break;
659 
660 		if (fat_val == 0xfffffff || fat_val == 0xffff)
661 			break;
662 
663 		entry = fat_val;
664 	}
665 
666 	/* Flush fat buffer */
667 	if (flush_fat_buffer(mydata) < 0)
668 		return -1;
669 
670 	return 0;
671 }
672 
673 /*
674  * Write at most 'maxsize' bytes from 'buffer' into
675  * the file associated with 'dentptr'
676  * Return the number of bytes read or -1 on fatal errors.
677  */
678 static int
679 set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
680 	      unsigned long maxsize)
681 {
682 	unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
683 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
684 	__u32 curclust = START(dentptr);
685 	__u32 endclust = 0, newclust = 0;
686 	unsigned long actsize;
687 
688 	debug("Filesize: %ld bytes\n", filesize);
689 
690 	if (maxsize > 0 && filesize > maxsize)
691 		filesize = maxsize;
692 
693 	debug("%ld bytes\n", filesize);
694 
695 	actsize = bytesperclust;
696 	endclust = curclust;
697 	do {
698 		/* search for consecutive clusters */
699 		while (actsize < filesize) {
700 			newclust = determine_fatent(mydata, endclust);
701 
702 			if ((newclust - 1) != endclust)
703 				goto getit;
704 
705 			if (CHECK_CLUST(newclust, mydata->fatsize)) {
706 				debug("curclust: 0x%x\n", newclust);
707 				debug("Invalid FAT entry\n");
708 				return gotsize;
709 			}
710 			endclust = newclust;
711 			actsize += bytesperclust;
712 		}
713 		/* actsize >= file size */
714 		actsize -= bytesperclust;
715 		/* set remaining clusters */
716 		if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
717 			debug("error: writing cluster\n");
718 			return -1;
719 		}
720 
721 		/* set remaining bytes */
722 		gotsize += (int)actsize;
723 		filesize -= actsize;
724 		buffer += actsize;
725 		actsize = filesize;
726 
727 		if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) {
728 			debug("error: writing cluster\n");
729 			return -1;
730 		}
731 		gotsize += actsize;
732 
733 		/* Mark end of file in FAT */
734 		if (mydata->fatsize == 16)
735 			newclust = 0xffff;
736 		else if (mydata->fatsize == 32)
737 			newclust = 0xfffffff;
738 		set_fatent_value(mydata, endclust, newclust);
739 
740 		return gotsize;
741 getit:
742 		if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
743 			debug("error: writing cluster\n");
744 			return -1;
745 		}
746 		gotsize += (int)actsize;
747 		filesize -= actsize;
748 		buffer += actsize;
749 
750 		if (CHECK_CLUST(curclust, mydata->fatsize)) {
751 			debug("curclust: 0x%x\n", curclust);
752 			debug("Invalid FAT entry\n");
753 			return gotsize;
754 		}
755 		actsize = bytesperclust;
756 		curclust = endclust = newclust;
757 	} while (1);
758 }
759 
760 /*
761  * Fill dir_entry
762  */
763 static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
764 	const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
765 {
766 	if (mydata->fatsize == 32)
767 		dentptr->starthi =
768 			cpu_to_le16((start_cluster & 0xffff0000) >> 16);
769 	dentptr->start = cpu_to_le16(start_cluster & 0xffff);
770 	dentptr->size = cpu_to_le32(size);
771 
772 	dentptr->attr = attr;
773 
774 	set_name(dentptr, filename);
775 }
776 
777 /*
778  * Check whether adding a file makes the file system to
779  * exceed the size of the block device
780  * Return -1 when overflow occurs, otherwise return 0
781  */
782 static int check_overflow(fsdata *mydata, __u32 clustnum, unsigned long size)
783 {
784 	__u32 startsect, sect_num;
785 
786 	if (clustnum > 0) {
787 		startsect = mydata->data_begin +
788 				clustnum * mydata->clust_size;
789 	} else {
790 		startsect = mydata->rootdir_sect;
791 	}
792 
793 	sect_num = size / mydata->sect_size;
794 	if (size % mydata->sect_size)
795 		sect_num++;
796 
797 	if (startsect + sect_num > cur_part_info.start + total_sector)
798 		return -1;
799 
800 	return 0;
801 }
802 
803 /*
804  * Check if adding several entries exceed one cluster boundary
805  */
806 static int is_next_clust(fsdata *mydata, dir_entry *dentptr)
807 {
808 	int cur_position;
809 
810 	cur_position = (__u8 *)dentptr - get_dentfromdir_block;
811 
812 	if (cur_position >= mydata->clust_size * mydata->sect_size)
813 		return 1;
814 	else
815 		return 0;
816 }
817 
818 static dir_entry *empty_dentptr;
819 /*
820  * Find a directory entry based on filename or start cluster number
821  * If the directory entry is not found,
822  * the new position for writing a directory entry will be returned
823  */
824 static dir_entry *find_directory_entry(fsdata *mydata, int startsect,
825 	char *filename, dir_entry *retdent, __u32 start)
826 {
827 	__u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size;
828 
829 	debug("get_dentfromdir: %s\n", filename);
830 
831 	while (1) {
832 		dir_entry *dentptr;
833 
834 		int i;
835 
836 		if (get_cluster(mydata, curclust, get_dentfromdir_block,
837 			    mydata->clust_size * mydata->sect_size) != 0) {
838 			printf("Error: reading directory block\n");
839 			return NULL;
840 		}
841 
842 		dentptr = (dir_entry *)get_dentfromdir_block;
843 
844 		dir_curclust = curclust;
845 
846 		for (i = 0; i < DIRENTSPERCLUST; i++) {
847 			char s_name[14], l_name[VFAT_MAXLEN_BYTES];
848 
849 			l_name[0] = '\0';
850 			if (dentptr->name[0] == DELETED_FLAG) {
851 				dentptr++;
852 				if (is_next_clust(mydata, dentptr))
853 					break;
854 				continue;
855 			}
856 			if ((dentptr->attr & ATTR_VOLUME)) {
857 #ifdef CONFIG_SUPPORT_VFAT
858 				if ((dentptr->attr & ATTR_VFAT) &&
859 				    (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
860 					get_long_file_name(mydata, curclust,
861 						     get_dentfromdir_block,
862 						     &dentptr, l_name);
863 					debug("vfatname: |%s|\n", l_name);
864 				} else
865 #endif
866 				{
867 					/* Volume label or VFAT entry */
868 					dentptr++;
869 					if (is_next_clust(mydata, dentptr))
870 						break;
871 					continue;
872 				}
873 			}
874 			if (dentptr->name[0] == 0) {
875 				debug("Dentname == NULL - %d\n", i);
876 				empty_dentptr = dentptr;
877 				return NULL;
878 			}
879 
880 			get_name(dentptr, s_name);
881 
882 			if (strcmp(filename, s_name)
883 			    && strcmp(filename, l_name)) {
884 				debug("Mismatch: |%s|%s|\n",
885 					s_name, l_name);
886 				dentptr++;
887 				if (is_next_clust(mydata, dentptr))
888 					break;
889 				continue;
890 			}
891 
892 			memcpy(retdent, dentptr, sizeof(dir_entry));
893 
894 			debug("DentName: %s", s_name);
895 			debug(", start: 0x%x", START(dentptr));
896 			debug(", size:  0x%x %s\n",
897 			      FAT2CPU32(dentptr->size),
898 			      (dentptr->attr & ATTR_DIR) ?
899 			      "(DIR)" : "");
900 
901 			return dentptr;
902 		}
903 
904 		curclust = get_fatent_value(mydata, dir_curclust);
905 		if ((curclust >= 0xffffff8) || (curclust >= 0xfff8)) {
906 			empty_dentptr = dentptr;
907 			return NULL;
908 		}
909 		if (CHECK_CLUST(curclust, mydata->fatsize)) {
910 			debug("curclust: 0x%x\n", curclust);
911 			debug("Invalid FAT entry\n");
912 			return NULL;
913 		}
914 	}
915 
916 	return NULL;
917 }
918 
919 static int do_fat_write(const char *filename, void *buffer,
920 	unsigned long size)
921 {
922 	dir_entry *dentptr, *retdent;
923 	__u32 startsect;
924 	__u32 start_cluster;
925 	boot_sector bs;
926 	volume_info volinfo;
927 	fsdata datablock;
928 	fsdata *mydata = &datablock;
929 	int cursect;
930 	int ret = -1, name_len;
931 	char l_filename[VFAT_MAXLEN_BYTES];
932 	int write_size = size;
933 
934 	dir_curclust = 0;
935 
936 	if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
937 		debug("error: reading boot sector\n");
938 		return -1;
939 	}
940 
941 	total_sector = bs.total_sect;
942 	if (total_sector == 0)
943 		total_sector = cur_part_info.size;
944 
945 	if (mydata->fatsize == 32)
946 		mydata->fatlength = bs.fat32_length;
947 	else
948 		mydata->fatlength = bs.fat_length;
949 
950 	mydata->fat_sect = bs.reserved;
951 
952 	cursect = mydata->rootdir_sect
953 		= mydata->fat_sect + mydata->fatlength * bs.fats;
954 	num_of_fats = bs.fats;
955 
956 	mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
957 	mydata->clust_size = bs.cluster_size;
958 
959 	if (mydata->fatsize == 32) {
960 		mydata->data_begin = mydata->rootdir_sect -
961 					(mydata->clust_size * 2);
962 	} else {
963 		int rootdir_size;
964 
965 		rootdir_size = ((bs.dir_entries[1]  * (int)256 +
966 				 bs.dir_entries[0]) *
967 				 sizeof(dir_entry)) /
968 				 mydata->sect_size;
969 		mydata->data_begin = mydata->rootdir_sect +
970 					rootdir_size -
971 					(mydata->clust_size * 2);
972 	}
973 
974 	mydata->fatbufnum = -1;
975 	mydata->fatbuf = malloc(FATBUFSIZE);
976 	if (mydata->fatbuf == NULL) {
977 		debug("Error: allocating memory\n");
978 		return -1;
979 	}
980 
981 	if (disk_read(cursect,
982 		(mydata->fatsize == 32) ?
983 		(mydata->clust_size) :
984 		PREFETCH_BLOCKS, do_fat_read_at_block) < 0) {
985 		debug("Error: reading rootdir block\n");
986 		goto exit;
987 	}
988 	dentptr = (dir_entry *) do_fat_read_at_block;
989 
990 	name_len = strlen(filename);
991 	if (name_len >= VFAT_MAXLEN_BYTES)
992 		name_len = VFAT_MAXLEN_BYTES - 1;
993 
994 	memcpy(l_filename, filename, name_len);
995 	l_filename[name_len] = 0; /* terminate the string */
996 	downcase(l_filename);
997 
998 	startsect = mydata->rootdir_sect;
999 	retdent = find_directory_entry(mydata, startsect,
1000 				l_filename, dentptr, 0);
1001 	if (retdent) {
1002 		/* Update file size and start_cluster in a directory entry */
1003 		retdent->size = cpu_to_le32(size);
1004 		start_cluster = FAT2CPU16(retdent->start);
1005 		if (mydata->fatsize == 32)
1006 			start_cluster |=
1007 				(FAT2CPU16(retdent->starthi) << 16);
1008 
1009 		ret = check_overflow(mydata, start_cluster, size);
1010 		if (ret) {
1011 			printf("Error: %ld overflow\n", size);
1012 			goto exit;
1013 		}
1014 
1015 		ret = clear_fatent(mydata, start_cluster);
1016 		if (ret) {
1017 			printf("Error: clearing FAT entries\n");
1018 			goto exit;
1019 		}
1020 
1021 		ret = set_contents(mydata, retdent, buffer, size);
1022 		if (ret < 0) {
1023 			printf("Error: writing contents\n");
1024 			goto exit;
1025 		}
1026 		write_size = ret;
1027 		debug("attempt to write 0x%x bytes\n", write_size);
1028 
1029 		/* Flush fat buffer */
1030 		ret = flush_fat_buffer(mydata);
1031 		if (ret) {
1032 			printf("Error: flush fat buffer\n");
1033 			goto exit;
1034 		}
1035 
1036 		/* Write directory table to device */
1037 		ret = set_cluster(mydata, dir_curclust,
1038 			    get_dentfromdir_block,
1039 			    mydata->clust_size * mydata->sect_size);
1040 		if (ret) {
1041 			printf("Error: writing directory entry\n");
1042 			goto exit;
1043 		}
1044 	} else {
1045 		/* Set short name to set alias checksum field in dir_slot */
1046 		set_name(empty_dentptr, filename);
1047 		fill_dir_slot(mydata, &empty_dentptr, filename);
1048 
1049 		ret = start_cluster = find_empty_cluster(mydata);
1050 		if (ret < 0) {
1051 			printf("Error: finding empty cluster\n");
1052 			goto exit;
1053 		}
1054 
1055 		ret = check_overflow(mydata, start_cluster, size);
1056 		if (ret) {
1057 			printf("Error: %ld overflow\n", size);
1058 			goto exit;
1059 		}
1060 
1061 		/* Set attribute as archieve for regular file */
1062 		fill_dentry(mydata, empty_dentptr, filename,
1063 			start_cluster, size, 0x20);
1064 
1065 		ret = set_contents(mydata, empty_dentptr, buffer, size);
1066 		if (ret < 0) {
1067 			printf("Error: writing contents\n");
1068 			goto exit;
1069 		}
1070 		write_size = ret;
1071 		debug("attempt to write 0x%x bytes\n", write_size);
1072 
1073 		/* Flush fat buffer */
1074 		ret = flush_fat_buffer(mydata);
1075 		if (ret) {
1076 			printf("Error: flush fat buffer\n");
1077 			goto exit;
1078 		}
1079 
1080 		/* Write directory table to device */
1081 		ret = set_cluster(mydata, dir_curclust,
1082 			    get_dentfromdir_block,
1083 			    mydata->clust_size * mydata->sect_size);
1084 		if (ret) {
1085 			printf("Error: writing directory entry\n");
1086 			goto exit;
1087 		}
1088 	}
1089 
1090 exit:
1091 	free(mydata->fatbuf);
1092 	return ret < 0 ? ret : write_size;
1093 }
1094 
1095 int file_fat_write(const char *filename, void *buffer, unsigned long maxsize)
1096 {
1097 	printf("writing %s\n", filename);
1098 	return do_fat_write(filename, buffer, maxsize);
1099 }
1100