1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * fat_write.c
4  *
5  * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim
6  */
7 
8 #define LOG_CATEGORY LOGC_FS
9 
10 #include <command.h>
11 #include <config.h>
12 #include <div64.h>
13 #include <fat.h>
14 #include <log.h>
15 #include <malloc.h>
16 #include <part.h>
17 #include <rand.h>
18 #include <asm/byteorder.h>
19 #include <asm/cache.h>
20 #include <dm/uclass.h>
21 #include <linux/ctype.h>
22 #include <linux/math64.h>
23 #include "fat.c"
24 
25 static dir_entry *find_directory_entry(fat_itr *itr, char *filename);
26 static int new_dir_table(fat_itr *itr);
27 
28 /* Characters that may only be used in long file names */
29 static const char LONG_ONLY_CHARS[] = "+,;=[]";
30 
31 /* Combined size of the name and ext fields in the directory entry */
32 #define SHORT_NAME_SIZE 11
33 
34 /**
35  * str2fat() - convert string to valid FAT name characters
36  *
37  * Stop when reaching end of @src or a period.
38  * Ignore spaces.
39  * Replace characters that may only be used in long names by underscores.
40  * Convert lower case characters to upper case.
41  *
42  * To avoid assumptions about the code page we do not use characters
43  * above 0x7f for the short name.
44  *
45  * @dest:	destination buffer
46  * @src:	source buffer
47  * @length:	size of destination buffer
48  * Return:	number of bytes in destination buffer
49  */
str2fat(char * dest,char * src,int length)50 static int str2fat(char *dest, char *src, int length)
51 {
52 	int i;
53 
54 	for (i = 0; i < length; ++src) {
55 		char c = *src;
56 
57 		if (!c || c == '.')
58 			break;
59 		if (c == ' ')
60 			continue;
61 		if (strchr(LONG_ONLY_CHARS, c) || c > 0x7f)
62 			c = '_';
63 		else if (c >= 'a' && c <= 'z')
64 			c &= 0xdf;
65 		dest[i] = c;
66 		++i;
67 	}
68 	return i;
69 }
70 
71 /**
72  * fat_move_to_cluster() - position to first directory entry in cluster
73  *
74  * @itr:	directory iterator
75  * @cluster	cluster
76  * Return:	0 for success, -EIO on error
77  */
fat_move_to_cluster(fat_itr * itr,unsigned int cluster)78 static int fat_move_to_cluster(fat_itr *itr, unsigned int cluster)
79 {
80 	unsigned int nbytes;
81 
82 	/* position to the start of the directory */
83 	itr->next_clust = cluster;
84 	itr->last_cluster = 0;
85 	if (!fat_next_cluster(itr, &nbytes))
86 		return -EIO;
87 	itr->dent = (dir_entry *)itr->block;
88 	itr->remaining = nbytes / sizeof(dir_entry) - 1;
89 	return 0;
90 }
91 
92 /**
93  * set_name() - set short name in directory entry
94  *
95  * The function determines if the @filename is a valid short name.
96  * In this case no long name is needed.
97  *
98  * If a long name is needed, a short name is constructed.
99  *
100  * @itr:	directory iterator
101  * @filename:	long file name
102  * @shortname:	buffer of 11 bytes to receive chosen short name and extension
103  * Return:	number of directory entries needed, negative on error
104  */
set_name(fat_itr * itr,const char * filename,char * shortname)105 static int set_name(fat_itr *itr, const char *filename, char *shortname)
106 {
107 	char *period;
108 	char *pos;
109 	int period_location;
110 	char buf[13];
111 	int i;
112 	int ret;
113 	struct nameext dirent;
114 
115 	if (!filename)
116 		return -EIO;
117 
118 	/* Initialize buffer */
119 	memset(&dirent, ' ', sizeof(dirent));
120 
121 	/* Convert filename to upper case short name */
122 	period = strrchr(filename, '.');
123 	pos = (char *)filename;
124 	if (*pos == '.') {
125 		pos = period + 1;
126 		period = 0;
127 	}
128 	if (period)
129 		str2fat(dirent.ext, period + 1, sizeof(dirent.ext));
130 	period_location = str2fat(dirent.name, pos, sizeof(dirent.name));
131 	if (period_location < 0)
132 		return period_location;
133 	if (*dirent.name == ' ')
134 		*dirent.name = '_';
135 	/* Substitute character 0xe5 signaling deletetion by character 0x05 */
136 	if (*dirent.name == DELETED_FLAG)
137 		*dirent.name = aRING;
138 
139 	/* If filename and short name are the same, quit. */
140 	sprintf(buf, "%.*s.%.3s", period_location, dirent.name, dirent.ext);
141 	if (!strcmp(buf, filename)) {
142 		ret = 1;
143 		goto out;
144 	} else if (!strcasecmp(buf, filename)) {
145 		goto out_ret;
146 	}
147 
148 	/* Construct an indexed short name */
149 	for (i = 1; i < 0x200000; ++i) {
150 		int suffix_len;
151 		int suffix_start;
152 		int j;
153 
154 		/* To speed up the search use random numbers */
155 		if (i < 10) {
156 			j = i;
157 		} else {
158 			j = 30 - fls(i);
159 			j = 10 + (rand() >> j);
160 		}
161 		sprintf(buf, "~%d", j);
162 		suffix_len = strlen(buf);
163 		suffix_start = 8 - suffix_len;
164 		if (suffix_start > period_location)
165 			suffix_start = period_location;
166 		memcpy(dirent.name + suffix_start, buf, suffix_len);
167 		if (*dirent.ext != ' ')
168 			sprintf(buf, "%.*s.%.3s", suffix_start + suffix_len,
169 				dirent.name, dirent.ext);
170 		else
171 			sprintf(buf, "%.*s", suffix_start + suffix_len,
172 				dirent.name);
173 		debug("generated short name: %s\n", buf);
174 
175 		/* Check that the short name does not exist yet. */
176 		ret = fat_move_to_cluster(itr, itr->start_clust);
177 		if (ret)
178 			return ret;
179 		if (find_directory_entry(itr, buf))
180 			continue;
181 
182 		goto out_ret;
183 	}
184 	return -EIO;
185 out_ret:
186 	debug("chosen short name: %s\n", buf);
187 	/* Each long name directory entry takes 13 characters. */
188 	ret = (strlen(filename) + 25) / 13;
189 out:
190 	memcpy(shortname, &dirent, SHORT_NAME_SIZE);
191 	return ret;
192 }
193 
194 static int total_sector;
disk_write(__u32 block,__u32 nr_blocks,void * buf)195 static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
196 {
197 	ulong ret;
198 
199 	if (!cur_dev)
200 		return -1;
201 
202 	if (cur_part_info.start + block + nr_blocks >
203 		cur_part_info.start + total_sector) {
204 		printf("error: overflow occurs\n");
205 		return -1;
206 	}
207 
208 	ret = blk_dwrite(cur_dev, cur_part_info.start + block, nr_blocks, buf);
209 	if (nr_blocks && ret == 0)
210 		return -1;
211 
212 	return ret;
213 }
214 
215 /*
216  * Write fat buffer into block device
217  */
flush_dirty_fat_buffer(fsdata * mydata)218 static int flush_dirty_fat_buffer(fsdata *mydata)
219 {
220 	int getsize = FATBUFBLOCKS;
221 	__u32 fatlength = mydata->fatlength;
222 	__u8 *bufptr = mydata->fatbuf;
223 	__u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
224 
225 	debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum,
226 	      (int)mydata->fat_dirty);
227 
228 	if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1))
229 		return 0;
230 
231 	/* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
232 	if (startblock + getsize > fatlength)
233 		getsize = fatlength - startblock;
234 
235 	startblock += mydata->fat_sect;
236 
237 	/* Write FAT buf */
238 	if (disk_write(startblock, getsize, bufptr) < 0) {
239 		debug("error: writing FAT blocks\n");
240 		return -1;
241 	}
242 
243 	if (mydata->fats == 2) {
244 		/* Update corresponding second FAT blocks */
245 		startblock += mydata->fatlength;
246 		if (disk_write(startblock, getsize, bufptr) < 0) {
247 			debug("error: writing second FAT blocks\n");
248 			return -1;
249 		}
250 	}
251 	mydata->fat_dirty = 0;
252 
253 	return 0;
254 }
255 
256 /**
257  * fat_find_empty_dentries() - find a sequence of available directory entries
258  *
259  * @itr:	directory iterator
260  * @count:	number of directory entries to find
261  * Return:	0 on success or negative error number
262  */
fat_find_empty_dentries(fat_itr * itr,int count)263 static int fat_find_empty_dentries(fat_itr *itr, int count)
264 {
265 	unsigned int cluster;
266 	dir_entry *dent;
267 	int remaining;
268 	unsigned int n = 0;
269 	int ret;
270 
271 	ret = fat_move_to_cluster(itr, itr->start_clust);
272 	if (ret)
273 		return ret;
274 
275 	for (;;) {
276 		if (!itr->dent) {
277 			log_debug("Not enough directory entries available\n");
278 			return -ENOSPC;
279 		}
280 		switch (itr->dent->nameext.name[0]) {
281 		case 0x00:
282 		case DELETED_FLAG:
283 			if (!n) {
284 				/* Remember first deleted directory entry */
285 				cluster = itr->clust;
286 				dent = itr->dent;
287 				remaining = itr->remaining;
288 			}
289 			++n;
290 			if (n == count)
291 				goto out;
292 			break;
293 		default:
294 			n = 0;
295 			break;
296 		}
297 
298 		next_dent(itr);
299 		if (!itr->dent &&
300 		    (!itr->is_root || itr->fsdata->fatsize == 32) &&
301 		    new_dir_table(itr))
302 			return -ENOSPC;
303 	}
304 out:
305 	/* Position back to first directory entry */
306 	if (itr->clust != cluster) {
307 		ret = fat_move_to_cluster(itr, cluster);
308 		if (ret)
309 			return ret;
310 	}
311 	itr->dent = dent;
312 	itr->remaining = remaining;
313 	return 0;
314 }
315 
316 /*
317  * Set the file name information from 'name' into 'slotptr',
318  */
str2slot(dir_slot * slotptr,const char * name,int * idx)319 static int str2slot(dir_slot *slotptr, const char *name, int *idx)
320 {
321 	int j, end_idx = 0;
322 
323 	for (j = 0; j <= 8; j += 2) {
324 		if (name[*idx] == 0x00) {
325 			slotptr->name0_4[j] = 0;
326 			slotptr->name0_4[j + 1] = 0;
327 			end_idx++;
328 			goto name0_4;
329 		}
330 		slotptr->name0_4[j] = name[*idx];
331 		(*idx)++;
332 		end_idx++;
333 	}
334 	for (j = 0; j <= 10; j += 2) {
335 		if (name[*idx] == 0x00) {
336 			slotptr->name5_10[j] = 0;
337 			slotptr->name5_10[j + 1] = 0;
338 			end_idx++;
339 			goto name5_10;
340 		}
341 		slotptr->name5_10[j] = name[*idx];
342 		(*idx)++;
343 		end_idx++;
344 	}
345 	for (j = 0; j <= 2; j += 2) {
346 		if (name[*idx] == 0x00) {
347 			slotptr->name11_12[j] = 0;
348 			slotptr->name11_12[j + 1] = 0;
349 			end_idx++;
350 			goto name11_12;
351 		}
352 		slotptr->name11_12[j] = name[*idx];
353 		(*idx)++;
354 		end_idx++;
355 	}
356 
357 	if (name[*idx] == 0x00)
358 		return 1;
359 
360 	return 0;
361 /* Not used characters are filled with 0xff 0xff */
362 name0_4:
363 	for (; end_idx < 5; end_idx++) {
364 		slotptr->name0_4[end_idx * 2] = 0xff;
365 		slotptr->name0_4[end_idx * 2 + 1] = 0xff;
366 	}
367 	end_idx = 5;
368 name5_10:
369 	end_idx -= 5;
370 	for (; end_idx < 6; end_idx++) {
371 		slotptr->name5_10[end_idx * 2] = 0xff;
372 		slotptr->name5_10[end_idx * 2 + 1] = 0xff;
373 	}
374 	end_idx = 11;
375 name11_12:
376 	end_idx -= 11;
377 	for (; end_idx < 2; end_idx++) {
378 		slotptr->name11_12[end_idx * 2] = 0xff;
379 		slotptr->name11_12[end_idx * 2 + 1] = 0xff;
380 	}
381 
382 	return 1;
383 }
384 
385 static int flush_dir(fat_itr *itr);
386 
387 /**
388  * fill_dir_slot() - fill directory entries for long name
389  *
390  * @itr:	directory iterator
391  * @l_name:	long name
392  * @shortname:	short name
393  * Return:	0 for success, -errno otherwise
394  */
395 static int
fill_dir_slot(fat_itr * itr,const char * l_name,const char * shortname)396 fill_dir_slot(fat_itr *itr, const char *l_name, const char *shortname)
397 {
398 	__u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)];
399 	dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer;
400 	__u8 counter = 0, checksum;
401 	int idx = 0, ret;
402 
403 	/* Get short file name checksum value */
404 	checksum = mkcksum((void *)shortname);
405 
406 	do {
407 		memset(slotptr, 0x00, sizeof(dir_slot));
408 		ret = str2slot(slotptr, l_name, &idx);
409 		slotptr->id = ++counter;
410 		slotptr->attr = ATTR_VFAT;
411 		slotptr->alias_checksum = checksum;
412 		slotptr++;
413 	} while (ret == 0);
414 
415 	slotptr--;
416 	slotptr->id |= LAST_LONG_ENTRY_MASK;
417 
418 	while (counter >= 1) {
419 		memcpy(itr->dent, slotptr, sizeof(dir_slot));
420 		slotptr--;
421 		counter--;
422 
423 		if (!itr->remaining) {
424 			/* Write directory table to device */
425 			ret = flush_dir(itr);
426 			if (ret)
427 				return ret;
428 		}
429 
430 		next_dent(itr);
431 		if (!itr->dent)
432 			return -EIO;
433 	}
434 
435 	return 0;
436 }
437 
438 /*
439  * Set the entry at index 'entry' in a FAT (12/16/32) table.
440  */
set_fatent_value(fsdata * mydata,__u32 entry,__u32 entry_value)441 static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
442 {
443 	__u32 bufnum, offset, off16;
444 	__u16 val1, val2;
445 
446 	switch (mydata->fatsize) {
447 	case 32:
448 		bufnum = entry / FAT32BUFSIZE;
449 		offset = entry - bufnum * FAT32BUFSIZE;
450 		break;
451 	case 16:
452 		bufnum = entry / FAT16BUFSIZE;
453 		offset = entry - bufnum * FAT16BUFSIZE;
454 		break;
455 	case 12:
456 		bufnum = entry / FAT12BUFSIZE;
457 		offset = entry - bufnum * FAT12BUFSIZE;
458 		break;
459 	default:
460 		/* Unsupported FAT size */
461 		return -1;
462 	}
463 
464 	/* Read a new block of FAT entries into the cache. */
465 	if (bufnum != mydata->fatbufnum) {
466 		int getsize = FATBUFBLOCKS;
467 		__u8 *bufptr = mydata->fatbuf;
468 		__u32 fatlength = mydata->fatlength;
469 		__u32 startblock = bufnum * FATBUFBLOCKS;
470 
471 		/* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
472 		if (startblock + getsize > fatlength)
473 			getsize = fatlength - startblock;
474 
475 		if (flush_dirty_fat_buffer(mydata) < 0)
476 			return -1;
477 
478 		startblock += mydata->fat_sect;
479 
480 		if (disk_read(startblock, getsize, bufptr) < 0) {
481 			debug("Error reading FAT blocks\n");
482 			return -1;
483 		}
484 		mydata->fatbufnum = bufnum;
485 	}
486 
487 	/* Mark as dirty */
488 	mydata->fat_dirty = 1;
489 
490 	/* Set the actual entry */
491 	switch (mydata->fatsize) {
492 	case 32:
493 		((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
494 		break;
495 	case 16:
496 		((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
497 		break;
498 	case 12:
499 		off16 = (offset * 3) / 4;
500 
501 		switch (offset & 0x3) {
502 		case 0:
503 			val1 = cpu_to_le16(entry_value) & 0xfff;
504 			((__u16 *)mydata->fatbuf)[off16] &= ~0xfff;
505 			((__u16 *)mydata->fatbuf)[off16] |= val1;
506 			break;
507 		case 1:
508 			val1 = cpu_to_le16(entry_value) & 0xf;
509 			val2 = (cpu_to_le16(entry_value) >> 4) & 0xff;
510 
511 			((__u16 *)mydata->fatbuf)[off16] &= ~0xf000;
512 			((__u16 *)mydata->fatbuf)[off16] |= (val1 << 12);
513 
514 			((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xff;
515 			((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
516 			break;
517 		case 2:
518 			val1 = cpu_to_le16(entry_value) & 0xff;
519 			val2 = (cpu_to_le16(entry_value) >> 8) & 0xf;
520 
521 			((__u16 *)mydata->fatbuf)[off16] &= ~0xff00;
522 			((__u16 *)mydata->fatbuf)[off16] |= (val1 << 8);
523 
524 			((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xf;
525 			((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
526 			break;
527 		case 3:
528 			val1 = cpu_to_le16(entry_value) & 0xfff;
529 			((__u16 *)mydata->fatbuf)[off16] &= ~0xfff0;
530 			((__u16 *)mydata->fatbuf)[off16] |= (val1 << 4);
531 			break;
532 		default:
533 			break;
534 		}
535 
536 		break;
537 	default:
538 		return -1;
539 	}
540 
541 	return 0;
542 }
543 
544 /*
545  * Determine the next free cluster after 'entry' in a FAT (12/16/32) table
546  * and link it to 'entry'. EOC marker is not set on returned entry.
547  */
determine_fatent(fsdata * mydata,__u32 entry)548 static __u32 determine_fatent(fsdata *mydata, __u32 entry)
549 {
550 	__u32 next_fat, next_entry = entry + 1;
551 
552 	while (1) {
553 		next_fat = get_fatent(mydata, next_entry);
554 		if (next_fat == 0) {
555 			/* found free entry, link to entry */
556 			set_fatent_value(mydata, entry, next_entry);
557 			break;
558 		}
559 		next_entry++;
560 	}
561 	debug("FAT%d: entry: %08x, entry_value: %04x\n",
562 	       mydata->fatsize, entry, next_entry);
563 
564 	return next_entry;
565 }
566 
567 /**
568  * set_sectors() - write data to sectors
569  *
570  * Write 'size' bytes from 'buffer' into the specified sector.
571  *
572  * @mydata:	data to be written
573  * @startsect:	sector to be written to
574  * @buffer:	data to be written
575  * @size:	bytes to be written (but not more than the size of a cluster)
576  * Return:	0 on success, -1 otherwise
577  */
578 static int
set_sectors(fsdata * mydata,u32 startsect,u8 * buffer,u32 size)579 set_sectors(fsdata *mydata, u32 startsect, u8 *buffer, u32 size)
580 {
581 	int ret;
582 
583 	debug("startsect: %d\n", startsect);
584 
585 	if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
586 		ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
587 
588 		debug("FAT: Misaligned buffer address (%p)\n", buffer);
589 
590 		while (size >= mydata->sect_size) {
591 			memcpy(tmpbuf, buffer, mydata->sect_size);
592 			ret = disk_write(startsect++, 1, tmpbuf);
593 			if (ret != 1) {
594 				debug("Error writing data (got %d)\n", ret);
595 				return -1;
596 			}
597 
598 			buffer += mydata->sect_size;
599 			size -= mydata->sect_size;
600 		}
601 	} else if (size >= mydata->sect_size) {
602 		u32 nsects;
603 
604 		nsects = size / mydata->sect_size;
605 		ret = disk_write(startsect, nsects, buffer);
606 		if (ret != nsects) {
607 			debug("Error writing data (got %d)\n", ret);
608 			return -1;
609 		}
610 
611 		startsect += nsects;
612 		buffer += nsects * mydata->sect_size;
613 		size -= nsects * mydata->sect_size;
614 	}
615 
616 	if (size) {
617 		ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
618 		/* Do not leak content of stack */
619 		memset(tmpbuf, 0, mydata->sect_size);
620 		memcpy(tmpbuf, buffer, size);
621 		ret = disk_write(startsect, 1, tmpbuf);
622 		if (ret != 1) {
623 			debug("Error writing data (got %d)\n", ret);
624 			return -1;
625 		}
626 	}
627 
628 	return 0;
629 }
630 
631 /**
632  * set_cluster() - write data to cluster
633  *
634  * Write 'size' bytes from 'buffer' into the specified cluster.
635  *
636  * @mydata:	data to be written
637  * @clustnum:	cluster to be written to
638  * @buffer:	data to be written
639  * @size:	bytes to be written (but not more than the size of a cluster)
640  * Return:	0 on success, -1 otherwise
641  */
642 static int
set_cluster(fsdata * mydata,u32 clustnum,u8 * buffer,u32 size)643 set_cluster(fsdata *mydata, u32 clustnum, u8 *buffer, u32 size)
644 {
645 	return set_sectors(mydata, clust_to_sect(mydata, clustnum),
646 			   buffer, size);
647 }
648 
649 /**
650  * flush_dir() - flush directory
651  *
652  * @itr:	directory iterator
653  * Return:	0 for success, -EIO on error
654  */
flush_dir(fat_itr * itr)655 static int flush_dir(fat_itr *itr)
656 {
657 	fsdata *mydata = itr->fsdata;
658 	u32 startsect, sect_offset, nsects;
659 	int ret;
660 
661 	if (!itr->is_root || mydata->fatsize == 32) {
662 		ret = set_cluster(mydata, itr->clust, itr->block,
663 				  mydata->clust_size * mydata->sect_size);
664 		goto out;
665 	}
666 
667 	sect_offset = itr->clust * mydata->clust_size;
668 	startsect = mydata->rootdir_sect + sect_offset;
669 	/* do not write past the end of rootdir */
670 	nsects = min_t(u32, mydata->clust_size,
671 		       mydata->rootdir_size - sect_offset);
672 
673 	ret = set_sectors(mydata, startsect, itr->block,
674 			  nsects * mydata->sect_size);
675 out:
676 	if (ret) {
677 		log_err("Error: writing directory entry\n");
678 		return -EIO;
679 	}
680 	return 0;
681 }
682 
683 /*
684  * Read and modify data on existing and consecutive cluster blocks
685  */
686 static int
get_set_cluster(fsdata * mydata,__u32 clustnum,loff_t pos,__u8 * buffer,loff_t size,loff_t * gotsize)687 get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
688 		loff_t size, loff_t *gotsize)
689 {
690 	static u8 *tmpbuf_cluster;
691 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
692 	__u32 startsect;
693 	loff_t clustcount, wsize;
694 	int i, ret;
695 
696 	*gotsize = 0;
697 	if (!size)
698 		return 0;
699 
700 	if (!tmpbuf_cluster) {
701 		tmpbuf_cluster = memalign(ARCH_DMA_MINALIGN, MAX_CLUSTSIZE);
702 		if (!tmpbuf_cluster)
703 			return -1;
704 	}
705 
706 	assert(pos < bytesperclust);
707 	startsect = clust_to_sect(mydata, clustnum);
708 
709 	debug("clustnum: %d, startsect: %d, pos: %lld\n",
710 	      clustnum, startsect, pos);
711 
712 	/* partial write at beginning */
713 	if (pos) {
714 		wsize = min(bytesperclust - pos, size);
715 		ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
716 		if (ret != mydata->clust_size) {
717 			debug("Error reading data (got %d)\n", ret);
718 			return -1;
719 		}
720 
721 		memcpy(tmpbuf_cluster + pos, buffer, wsize);
722 		ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
723 		if (ret != mydata->clust_size) {
724 			debug("Error writing data (got %d)\n", ret);
725 			return -1;
726 		}
727 
728 		size -= wsize;
729 		buffer += wsize;
730 		*gotsize += wsize;
731 
732 		startsect += mydata->clust_size;
733 
734 		if (!size)
735 			return 0;
736 	}
737 
738 	/* full-cluster write */
739 	if (size >= bytesperclust) {
740 		clustcount = lldiv(size, bytesperclust);
741 
742 		if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
743 			wsize = clustcount * bytesperclust;
744 			ret = disk_write(startsect,
745 					 clustcount * mydata->clust_size,
746 					 buffer);
747 			if (ret != clustcount * mydata->clust_size) {
748 				debug("Error writing data (got %d)\n", ret);
749 				return -1;
750 			}
751 
752 			size -= wsize;
753 			buffer += wsize;
754 			*gotsize += wsize;
755 
756 			startsect += clustcount * mydata->clust_size;
757 		} else {
758 			for (i = 0; i < clustcount; i++) {
759 				memcpy(tmpbuf_cluster, buffer, bytesperclust);
760 				ret = disk_write(startsect,
761 						 mydata->clust_size,
762 						 tmpbuf_cluster);
763 				if (ret != mydata->clust_size) {
764 					debug("Error writing data (got %d)\n",
765 					      ret);
766 					return -1;
767 				}
768 
769 				size -= bytesperclust;
770 				buffer += bytesperclust;
771 				*gotsize += bytesperclust;
772 
773 				startsect += mydata->clust_size;
774 			}
775 		}
776 	}
777 
778 	/* partial write at end */
779 	if (size) {
780 		wsize = size;
781 		ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
782 		if (ret != mydata->clust_size) {
783 			debug("Error reading data (got %d)\n", ret);
784 			return -1;
785 		}
786 		memcpy(tmpbuf_cluster, buffer, wsize);
787 		ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
788 		if (ret != mydata->clust_size) {
789 			debug("Error writing data (got %d)\n", ret);
790 			return -1;
791 		}
792 
793 		size -= wsize;
794 		*gotsize += wsize;
795 	}
796 
797 	assert(!size);
798 
799 	return 0;
800 }
801 
802 /*
803  * Find the first empty cluster
804  */
find_empty_cluster(fsdata * mydata)805 static int find_empty_cluster(fsdata *mydata)
806 {
807 	__u32 fat_val, entry = 3;
808 
809 	while (1) {
810 		fat_val = get_fatent(mydata, entry);
811 		if (fat_val == 0)
812 			break;
813 		entry++;
814 	}
815 
816 	return entry;
817 }
818 
819 /**
820  * new_dir_table() - allocate a cluster for additional directory entries
821  *
822  * @itr:	directory iterator
823  * Return:	0 on success, -EIO otherwise
824  */
new_dir_table(fat_itr * itr)825 static int new_dir_table(fat_itr *itr)
826 {
827 	fsdata *mydata = itr->fsdata;
828 	int dir_newclust = 0;
829 	int dir_oldclust = itr->clust;
830 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
831 
832 	dir_newclust = find_empty_cluster(mydata);
833 
834 	/*
835 	 * Flush before updating FAT to ensure valid directory structure
836 	 * in case of failure.
837 	 */
838 	itr->clust = dir_newclust;
839 	itr->next_clust = dir_newclust;
840 	memset(itr->block, 0x00, bytesperclust);
841 	if (flush_dir(itr))
842 		return -EIO;
843 
844 	set_fatent_value(mydata, dir_oldclust, dir_newclust);
845 	if (mydata->fatsize == 32)
846 		set_fatent_value(mydata, dir_newclust, 0xffffff8);
847 	else if (mydata->fatsize == 16)
848 		set_fatent_value(mydata, dir_newclust, 0xfff8);
849 	else if (mydata->fatsize == 12)
850 		set_fatent_value(mydata, dir_newclust, 0xff8);
851 
852 	if (flush_dirty_fat_buffer(mydata) < 0)
853 		return -EIO;
854 
855 	itr->dent = (dir_entry *)itr->block;
856 	itr->last_cluster = 1;
857 	itr->remaining = bytesperclust / sizeof(dir_entry) - 1;
858 
859 	return 0;
860 }
861 
862 /*
863  * Set empty cluster from 'entry' to the end of a file
864  */
clear_fatent(fsdata * mydata,__u32 entry)865 static int clear_fatent(fsdata *mydata, __u32 entry)
866 {
867 	__u32 fat_val;
868 
869 	while (!CHECK_CLUST(entry, mydata->fatsize)) {
870 		fat_val = get_fatent(mydata, entry);
871 		if (fat_val != 0)
872 			set_fatent_value(mydata, entry, 0);
873 		else
874 			break;
875 
876 		entry = fat_val;
877 	}
878 
879 	/* Flush fat buffer */
880 	if (flush_dirty_fat_buffer(mydata) < 0)
881 		return -1;
882 
883 	return 0;
884 }
885 
886 /*
887  * Set start cluster in directory entry
888  */
set_start_cluster(const fsdata * mydata,dir_entry * dentptr,__u32 start_cluster)889 static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
890 			      __u32 start_cluster)
891 {
892 	if (mydata->fatsize == 32)
893 		dentptr->starthi =
894 			cpu_to_le16((start_cluster & 0xffff0000) >> 16);
895 	dentptr->start = cpu_to_le16(start_cluster & 0xffff);
896 }
897 
898 /*
899  * Check whether adding a file makes the file system to
900  * exceed the size of the block device
901  * Return -1 when overflow occurs, otherwise return 0
902  */
check_overflow(fsdata * mydata,__u32 clustnum,loff_t size)903 static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
904 {
905 	__u32 startsect, sect_num, offset;
906 
907 	if (clustnum > 0)
908 		startsect = clust_to_sect(mydata, clustnum);
909 	else
910 		startsect = mydata->rootdir_sect;
911 
912 	sect_num = div_u64_rem(size, mydata->sect_size, &offset);
913 
914 	if (offset != 0)
915 		sect_num++;
916 
917 	if (startsect + sect_num > total_sector)
918 		return -1;
919 	return 0;
920 }
921 
922 /*
923  * Write at most 'maxsize' bytes from 'buffer' into
924  * the file associated with 'dentptr'
925  * Update the number of bytes written in *gotsize and return 0
926  * or return -1 on fatal errors.
927  */
928 static int
set_contents(fsdata * mydata,dir_entry * dentptr,loff_t pos,__u8 * buffer,loff_t maxsize,loff_t * gotsize)929 set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
930 	     loff_t maxsize, loff_t *gotsize)
931 {
932 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
933 	__u32 curclust = START(dentptr);
934 	__u32 endclust = 0, newclust = 0;
935 	u64 cur_pos, filesize;
936 	loff_t offset, actsize, wsize;
937 
938 	*gotsize = 0;
939 	filesize = pos + maxsize;
940 
941 	debug("%llu bytes\n", filesize);
942 
943 	if (!filesize) {
944 		if (!curclust)
945 			return 0;
946 		if (!CHECK_CLUST(curclust, mydata->fatsize) ||
947 		    IS_LAST_CLUST(curclust, mydata->fatsize)) {
948 			clear_fatent(mydata, curclust);
949 			set_start_cluster(mydata, dentptr, 0);
950 			return 0;
951 		}
952 		debug("curclust: 0x%x\n", curclust);
953 		debug("Invalid FAT entry\n");
954 		return -1;
955 	}
956 
957 	if (!curclust) {
958 		assert(pos == 0);
959 		goto set_clusters;
960 	}
961 
962 	/* go to cluster at pos */
963 	cur_pos = bytesperclust;
964 	while (1) {
965 		if (pos <= cur_pos)
966 			break;
967 		if (IS_LAST_CLUST(curclust, mydata->fatsize))
968 			break;
969 
970 		newclust = get_fatent(mydata, curclust);
971 		if (!IS_LAST_CLUST(newclust, mydata->fatsize) &&
972 		    CHECK_CLUST(newclust, mydata->fatsize)) {
973 			debug("curclust: 0x%x\n", curclust);
974 			debug("Invalid FAT entry\n");
975 			return -1;
976 		}
977 
978 		cur_pos += bytesperclust;
979 		curclust = newclust;
980 	}
981 	if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
982 		assert(pos == cur_pos);
983 		goto set_clusters;
984 	}
985 
986 	assert(pos < cur_pos);
987 	cur_pos -= bytesperclust;
988 
989 	/* overwrite */
990 	assert(IS_LAST_CLUST(curclust, mydata->fatsize) ||
991 	       !CHECK_CLUST(curclust, mydata->fatsize));
992 
993 	while (1) {
994 		/* search for allocated consecutive clusters */
995 		actsize = bytesperclust;
996 		endclust = curclust;
997 		while (1) {
998 			if (filesize <= (cur_pos + actsize))
999 				break;
1000 
1001 			newclust = get_fatent(mydata, endclust);
1002 
1003 			if (newclust != endclust + 1)
1004 				break;
1005 			if (IS_LAST_CLUST(newclust, mydata->fatsize))
1006 				break;
1007 			if (CHECK_CLUST(newclust, mydata->fatsize)) {
1008 				debug("curclust: 0x%x\n", curclust);
1009 				debug("Invalid FAT entry\n");
1010 				return -1;
1011 			}
1012 
1013 			actsize += bytesperclust;
1014 			endclust = newclust;
1015 		}
1016 
1017 		/* overwrite to <curclust..endclust> */
1018 		if (pos < cur_pos)
1019 			offset = 0;
1020 		else
1021 			offset = pos - cur_pos;
1022 		wsize = min_t(unsigned long long, actsize, filesize - cur_pos);
1023 		wsize -= offset;
1024 
1025 		if (get_set_cluster(mydata, curclust, offset,
1026 				    buffer, wsize, &actsize)) {
1027 			printf("Error get-and-setting cluster\n");
1028 			return -1;
1029 		}
1030 		buffer += wsize;
1031 		*gotsize += wsize;
1032 		cur_pos += offset + wsize;
1033 
1034 		if (filesize <= cur_pos)
1035 			break;
1036 
1037 		if (IS_LAST_CLUST(newclust, mydata->fatsize))
1038 			/* no more clusters */
1039 			break;
1040 
1041 		curclust = newclust;
1042 	}
1043 
1044 	if (filesize <= cur_pos) {
1045 		/* no more write */
1046 		newclust = get_fatent(mydata, endclust);
1047 		if (!IS_LAST_CLUST(newclust, mydata->fatsize)) {
1048 			/* truncate the rest */
1049 			clear_fatent(mydata, newclust);
1050 
1051 			/* Mark end of file in FAT */
1052 			if (mydata->fatsize == 12)
1053 				newclust = 0xfff;
1054 			else if (mydata->fatsize == 16)
1055 				newclust = 0xffff;
1056 			else if (mydata->fatsize == 32)
1057 				newclust = 0xfffffff;
1058 			set_fatent_value(mydata, endclust, newclust);
1059 		}
1060 
1061 		return 0;
1062 	}
1063 
1064 	curclust = endclust;
1065 	filesize -= cur_pos;
1066 	assert(!do_div(cur_pos, bytesperclust));
1067 
1068 set_clusters:
1069 	/* allocate and write */
1070 	assert(!pos);
1071 
1072 	/* Assure that curclust is valid */
1073 	if (!curclust) {
1074 		curclust = find_empty_cluster(mydata);
1075 		set_start_cluster(mydata, dentptr, curclust);
1076 	} else {
1077 		newclust = get_fatent(mydata, curclust);
1078 
1079 		if (IS_LAST_CLUST(newclust, mydata->fatsize)) {
1080 			newclust = determine_fatent(mydata, curclust);
1081 			set_fatent_value(mydata, curclust, newclust);
1082 			curclust = newclust;
1083 		} else {
1084 			debug("error: something wrong\n");
1085 			return -1;
1086 		}
1087 	}
1088 
1089 	/* TODO: already partially written */
1090 	if (check_overflow(mydata, curclust, filesize)) {
1091 		printf("Error: no space left: %llu\n", filesize);
1092 		return -1;
1093 	}
1094 
1095 	actsize = bytesperclust;
1096 	endclust = curclust;
1097 	do {
1098 		/* search for consecutive clusters */
1099 		while (actsize < filesize) {
1100 			newclust = determine_fatent(mydata, endclust);
1101 
1102 			if ((newclust - 1) != endclust)
1103 				/* write to <curclust..endclust> */
1104 				goto getit;
1105 
1106 			if (CHECK_CLUST(newclust, mydata->fatsize)) {
1107 				debug("newclust: 0x%x\n", newclust);
1108 				debug("Invalid FAT entry\n");
1109 				return 0;
1110 			}
1111 			endclust = newclust;
1112 			actsize += bytesperclust;
1113 		}
1114 
1115 		/* set remaining bytes */
1116 		actsize = filesize;
1117 		if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
1118 			debug("error: writing cluster\n");
1119 			return -1;
1120 		}
1121 		*gotsize += actsize;
1122 
1123 		/* Mark end of file in FAT */
1124 		if (mydata->fatsize == 12)
1125 			newclust = 0xfff;
1126 		else if (mydata->fatsize == 16)
1127 			newclust = 0xffff;
1128 		else if (mydata->fatsize == 32)
1129 			newclust = 0xfffffff;
1130 		set_fatent_value(mydata, endclust, newclust);
1131 
1132 		return 0;
1133 getit:
1134 		if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
1135 			debug("error: writing cluster\n");
1136 			return -1;
1137 		}
1138 		*gotsize += actsize;
1139 		filesize -= actsize;
1140 		buffer += actsize;
1141 
1142 		if (CHECK_CLUST(newclust, mydata->fatsize)) {
1143 			debug("newclust: 0x%x\n", newclust);
1144 			debug("Invalid FAT entry\n");
1145 			return 0;
1146 		}
1147 		actsize = bytesperclust;
1148 		curclust = endclust = newclust;
1149 	} while (1);
1150 
1151 	return 0;
1152 }
1153 
1154 /**
1155  * dentry_set_time() - set change time
1156  *
1157  * @dentptr:	directory entry
1158  */
dentry_set_time(dir_entry * dentptr)1159 static void dentry_set_time(dir_entry *dentptr)
1160 {
1161 	if (CONFIG_IS_ENABLED(DM_RTC)) {
1162 		struct udevice *dev;
1163 		struct rtc_time tm;
1164 		u16 date;
1165 		u16 time;
1166 
1167 		uclass_first_device(UCLASS_RTC, &dev);
1168 		if (!dev)
1169 			goto err;
1170 		if (dm_rtc_get(dev, &tm))
1171 			goto err;
1172 		if (tm.tm_year < 1980 || tm.tm_year > 2107)
1173 			goto err;
1174 		date = (tm.tm_mday & 0x1f) |
1175 		       ((tm.tm_mon & 0xf) << 5) |
1176 		       ((tm.tm_year - 1980) << 9);
1177 		time = (tm.tm_sec > 1) |
1178 		       ((tm.tm_min & 0x3f) << 5) |
1179 		(tm.tm_hour << 11);
1180 		dentptr->date = date;
1181 		dentptr->time = time;
1182 		return;
1183 	}
1184 err:
1185 	dentptr->date = 0x2821; /* 2000-01-01 */
1186 	dentptr->time = 0;
1187 }
1188 
1189 /**
1190  * fill_dentry() - fill directory entry with shortname
1191  *
1192  * @mydata:		private filesystem parameters
1193  * @dentptr:		directory entry
1194  * @shortname:		chosen short name
1195  * @start_cluster:	first cluster of file
1196  * @size:		file size
1197  * @attr:		file attributes
1198  */
fill_dentry(fsdata * mydata,dir_entry * dentptr,const char * shortname,__u32 start_cluster,__u32 size,__u8 attr)1199 static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
1200 	const char *shortname, __u32 start_cluster, __u32 size, __u8 attr)
1201 {
1202 	memset(dentptr, 0, sizeof(*dentptr));
1203 
1204 	set_start_cluster(mydata, dentptr, start_cluster);
1205 	dentptr->size = cpu_to_le32(size);
1206 
1207 	dentptr->attr = attr;
1208 
1209 	/* Set change date */
1210 	dentry_set_time(dentptr);
1211 	/* Set creation date */
1212 	dentptr->cdate = dentptr->date;
1213 	dentptr->ctime = dentptr->time;
1214 
1215 	memcpy(&dentptr->nameext, shortname, SHORT_NAME_SIZE);
1216 }
1217 
1218 /**
1219  * fat_itr_parent() - modifies the iterator to the parent directory of the
1220  * current iterator.
1221  *
1222  * @itr:	iterator positioned anywhere in a directory
1223  * @Return:	0 if the iterator is in the parent directory, -errno otherwise
1224  */
fat_itr_parent(fat_itr * itr)1225 static int fat_itr_parent(fat_itr *itr)
1226 {
1227 	int ret;
1228 
1229 	if (itr->is_root)
1230 		return -EIO;
1231 
1232 	/* ensure iterator is at the first directory entry */
1233 	ret = fat_move_to_cluster(itr, itr->start_clust);
1234 	if (ret)
1235 		return ret;
1236 
1237 	return fat_itr_resolve(itr, "..", TYPE_DIR);
1238 }
1239 
1240 /**
1241  * update_parent_dir_props - updates the modified time for the parent directory
1242  *
1243  * @dir_itr:	iterator positioned anywhere in a directory whose parent
1244  * should be updated
1245  * @Return:	0 for success, -errno otherwise
1246  */
update_parent_dir_props(fat_itr * dir_itr)1247 static int update_parent_dir_props(fat_itr *dir_itr)
1248 {
1249 	int ret = 0;
1250 
1251 	fat_itr itr;
1252 	fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
1253 	__u32 target_clust = dir_itr->start_clust;
1254 
1255 	/* Short circuit if no RTC because it only updates timestamps */
1256 	if (!CONFIG_IS_ENABLED(DM_RTC))
1257 		return ret;
1258 
1259 	/* duplicate fsdata */
1260 	itr = *dir_itr;
1261 	fsdata = *itr.fsdata;
1262 
1263 	/* allocate local fat buffer */
1264 	fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
1265 	if (!fsdata.fatbuf) {
1266 		log_debug("Error: allocating memory\n");
1267 		ret = -ENOMEM;
1268 		return ret;
1269 	}
1270 
1271 	fsdata.fatbufnum = -1;
1272 	itr.fsdata = &fsdata;
1273 
1274 	if (!itr.is_root) {
1275 		ret = fat_itr_parent(&itr);
1276 		if (ret)
1277 			goto exit;
1278 
1279 		while (fat_itr_next(&itr)) {
1280 			if (START(itr.dent) == target_clust)
1281 				goto update;
1282 		}
1283 
1284 		/* dent not found */
1285 		ret = -EIO;
1286 		goto exit;
1287 update:
1288 		dentry_set_time(itr.dent);
1289 		ret = flush_dir(&itr);
1290 	}
1291 
1292 exit:
1293 	free(fsdata.fatbuf);
1294 
1295 	return ret;
1296 }
1297 
1298 /**
1299  * create_link() - inserts a directory entry for a file or directory
1300  *
1301  * @itr:	directory iterator
1302  * @basename:	file name
1303  * @clust:	cluster number the new directory entry should point to. Use 0
1304  * if no cluster is assigned yet
1305  * @size:	file size
1306  * @attr:	file attributes
1307  * Return:	0 for success
1308  */
create_link(fat_itr * itr,char * basename,__u32 clust,__u32 size,__u8 attr)1309 static int create_link(fat_itr *itr, char *basename, __u32 clust, __u32 size,
1310 		       __u8 attr)
1311 {
1312 	char shortname[SHORT_NAME_SIZE];
1313 	int ndent;
1314 	int ret;
1315 
1316 	/* Check if long name is needed */
1317 	ndent = set_name(itr, basename, shortname);
1318 	if (ndent < 0)
1319 		return ndent;
1320 	ret = fat_find_empty_dentries(itr, ndent);
1321 	if (ret)
1322 		return ret;
1323 	if (ndent > 1) {
1324 		/* Set long name entries */
1325 		ret = fill_dir_slot(itr, basename, shortname);
1326 		if (ret)
1327 			return ret;
1328 	}
1329 
1330 	fill_dentry(itr->fsdata, itr->dent, shortname, clust, size, attr);
1331 	ret = update_parent_dir_props(itr);
1332 
1333 	return ret;
1334 }
1335 
1336 /**
1337  * find_directory_entry() - find a directory entry by filename
1338  *
1339  * @itr:	directory iterator
1340  * @filename:	name of file to find
1341  * Return:	directory entry or NULL
1342  */
find_directory_entry(fat_itr * itr,char * filename)1343 static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
1344 {
1345 	int match = 0;
1346 
1347 	while (fat_itr_next(itr)) {
1348 		/* check both long and short name: */
1349 		if (!strcasecmp(filename, itr->name))
1350 			match = 1;
1351 		else if (itr->name != itr->s_name &&
1352 			 !strcasecmp(filename, itr->s_name))
1353 			match = 1;
1354 
1355 		if (!match)
1356 			continue;
1357 
1358 		if (itr->dent->nameext.name[0] == '\0')
1359 			return NULL;
1360 		else
1361 			return itr->dent;
1362 	}
1363 
1364 	return NULL;
1365 }
1366 
split_filename(char * filename,char ** dirname,char ** basename)1367 static int split_filename(char *filename, char **dirname, char **basename)
1368 {
1369 	char *p, *last_slash, *last_slash_cont;
1370 
1371 again:
1372 	p = filename;
1373 	last_slash = NULL;
1374 	last_slash_cont = NULL;
1375 	while (*p) {
1376 		if (ISDIRDELIM(*p)) {
1377 			last_slash = p;
1378 			last_slash_cont = p;
1379 			/* continuous slashes */
1380 			while (ISDIRDELIM(*p))
1381 				last_slash_cont = p++;
1382 			if (!*p)
1383 				break;
1384 		}
1385 		p++;
1386 	}
1387 
1388 	if (last_slash) {
1389 		if (last_slash_cont == (filename + strlen(filename) - 1)) {
1390 			/* remove trailing slashes */
1391 			*last_slash = '\0';
1392 			goto again;
1393 		}
1394 
1395 		if (last_slash == filename) {
1396 			/* avoid ""(null) directory */
1397 			*dirname = "/";
1398 		} else {
1399 			*last_slash = '\0';
1400 			*dirname = filename;
1401 		}
1402 
1403 		*last_slash_cont = '\0';
1404 		filename = last_slash_cont + 1;
1405 	} else {
1406 		*dirname = "/"; /* root by default */
1407 	}
1408 
1409 	/*
1410 	 * The FAT32 File System Specification v1.03 requires leading and
1411 	 * trailing spaces as well as trailing periods to be ignored.
1412 	 */
1413 	for (; *filename == ' '; ++filename)
1414 		;
1415 
1416 	/* Keep special entries '.' and '..' */
1417 	if (filename[0] == '.' &&
1418 	    (!filename[1] || (filename[1] == '.' && !filename[2])))
1419 		goto done;
1420 
1421 	/* Remove trailing periods and spaces */
1422 	for (p = filename + strlen(filename) - 1; p >= filename; --p) {
1423 		switch (*p) {
1424 		case ' ':
1425 		case '.':
1426 			*p = 0;
1427 			break;
1428 		default:
1429 			goto done;
1430 		}
1431 	}
1432 
1433 done:
1434 	*basename = filename;
1435 
1436 	return 0;
1437 }
1438 
1439 /**
1440  * normalize_longname() - check long file name and convert to lower case
1441  *
1442  * We assume here that the FAT file system is using an 8bit code page.
1443  * Linux typically uses CP437, EDK2 assumes CP1250.
1444  *
1445  * @l_filename:	preallocated buffer receiving the normalized name
1446  * @filename:	filename to normalize
1447  * Return:	0 on success, -1 on failure
1448  */
normalize_longname(char * l_filename,const char * filename)1449 static int normalize_longname(char *l_filename, const char *filename)
1450 {
1451 	const char *p, illegal[] = "<>:\"/\\|?*";
1452 	size_t len;
1453 
1454 	len = strlen(filename);
1455 	if (!len || len >= VFAT_MAXLEN_BYTES || filename[len - 1] == '.')
1456 		return -1;
1457 
1458 	for (p = filename; *p; ++p) {
1459 		if ((unsigned char)*p < 0x20)
1460 			return -1;
1461 		if (strchr(illegal, *p))
1462 			return -1;
1463 	}
1464 
1465 	strcpy(l_filename, filename);
1466 	downcase(l_filename, VFAT_MAXLEN_BYTES);
1467 
1468 	return 0;
1469 }
1470 
file_fat_write_at(const char * filename,loff_t pos,void * buffer,loff_t size,loff_t * actwrite)1471 int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
1472 		      loff_t size, loff_t *actwrite)
1473 {
1474 	dir_entry *retdent;
1475 	fsdata datablock = { .fatbuf = NULL, };
1476 	fsdata *mydata = &datablock;
1477 	fat_itr *itr = NULL;
1478 	int ret = -1;
1479 	char *filename_copy, *parent, *basename;
1480 	char l_filename[VFAT_MAXLEN_BYTES];
1481 
1482 	debug("writing %s\n", filename);
1483 
1484 	filename_copy = strdup(filename);
1485 	if (!filename_copy)
1486 		return -ENOMEM;
1487 
1488 	split_filename(filename_copy, &parent, &basename);
1489 	if (!strlen(basename)) {
1490 		ret = -EINVAL;
1491 		goto exit;
1492 	}
1493 
1494 	if (normalize_longname(l_filename, basename)) {
1495 		printf("FAT: illegal filename (%s)\n", basename);
1496 		ret = -EINVAL;
1497 		goto exit;
1498 	}
1499 
1500 	itr = malloc_cache_aligned(sizeof(fat_itr));
1501 	if (!itr) {
1502 		ret = -ENOMEM;
1503 		goto exit;
1504 	}
1505 
1506 	ret = fat_itr_root(itr, &datablock);
1507 	if (ret)
1508 		goto exit;
1509 
1510 	total_sector = datablock.total_sect;
1511 
1512 	ret = fat_itr_resolve(itr, parent, TYPE_DIR);
1513 	if (ret) {
1514 		printf("%s: doesn't exist (%d)\n", parent, ret);
1515 		goto exit;
1516 	}
1517 
1518 	retdent = find_directory_entry(itr, l_filename);
1519 
1520 	if (retdent) {
1521 		if (fat_itr_isdir(itr)) {
1522 			ret = -EISDIR;
1523 			goto exit;
1524 		}
1525 
1526 		/* A file exists */
1527 		if (pos == -1)
1528 			/* Append to the end */
1529 			pos = FAT2CPU32(retdent->size);
1530 		if (pos > retdent->size) {
1531 			/* No hole allowed */
1532 			ret = -EINVAL;
1533 			goto exit;
1534 		}
1535 
1536 		/* Update file size in a directory entry */
1537 		retdent->size = cpu_to_le32(pos + size);
1538 		/* Update change date */
1539 		dentry_set_time(retdent);
1540 	} else {
1541 		if (pos) {
1542 			/* No hole allowed */
1543 			ret = -EINVAL;
1544 			goto exit;
1545 		}
1546 
1547 		ret = create_link(itr, basename, 0, size, ATTR_ARCH);
1548 		if (ret)
1549 			goto exit;
1550 
1551 		retdent = itr->dent;
1552 	}
1553 
1554 	ret = set_contents(mydata, retdent, pos, buffer, size, actwrite);
1555 	if (ret < 0) {
1556 		printf("Error: writing contents\n");
1557 		ret = -EIO;
1558 		goto exit;
1559 	}
1560 	debug("attempt to write 0x%llx bytes\n", *actwrite);
1561 
1562 	/* Flush fat buffer */
1563 	ret = flush_dirty_fat_buffer(mydata);
1564 	if (ret) {
1565 		printf("Error: flush fat buffer\n");
1566 		ret = -EIO;
1567 		goto exit;
1568 	}
1569 
1570 	/* Write directory table to device */
1571 	ret = flush_dir(itr);
1572 
1573 exit:
1574 	free(filename_copy);
1575 	free(mydata->fatbuf);
1576 	free(itr);
1577 	return ret;
1578 }
1579 
file_fat_write(const char * filename,void * buffer,loff_t offset,loff_t maxsize,loff_t * actwrite)1580 int file_fat_write(const char *filename, void *buffer, loff_t offset,
1581 		   loff_t maxsize, loff_t *actwrite)
1582 {
1583 	return file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
1584 }
1585 
fat_dir_entries(fat_itr * itr)1586 static int fat_dir_entries(fat_itr *itr)
1587 {
1588 	fat_itr *dirs;
1589 	fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
1590 						/* for FATBUFSIZE */
1591 	int count;
1592 
1593 	dirs = malloc_cache_aligned(sizeof(fat_itr));
1594 	if (!dirs) {
1595 		debug("Error: allocating memory\n");
1596 		count = -ENOMEM;
1597 		goto exit;
1598 	}
1599 
1600 	/* duplicate fsdata */
1601 	fat_itr_child(dirs, itr);
1602 	fsdata = *dirs->fsdata;
1603 
1604 	/* allocate local fat buffer */
1605 	fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
1606 	if (!fsdata.fatbuf) {
1607 		debug("Error: allocating memory\n");
1608 		count = -ENOMEM;
1609 		goto exit;
1610 	}
1611 	fsdata.fatbufnum = -1;
1612 	dirs->fsdata = &fsdata;
1613 
1614 	for (count = 0; fat_itr_next(dirs); count++)
1615 		;
1616 
1617 exit:
1618 	free(fsdata.fatbuf);
1619 	free(dirs);
1620 	return count;
1621 }
1622 
1623 /**
1624  * delete_single_dentry() - delete a single directory entry
1625  *
1626  * @itr:	directory iterator
1627  * Return:	0 for success
1628  */
delete_single_dentry(fat_itr * itr)1629 static int delete_single_dentry(fat_itr *itr)
1630 {
1631 	struct dir_entry *dent = itr->dent;
1632 
1633 	memset(dent, 0, sizeof(*dent));
1634 	dent->nameext.name[0] = DELETED_FLAG;
1635 
1636 	if (!itr->remaining)
1637 		return flush_dir(itr);
1638 	return 0;
1639 }
1640 
1641 /**
1642  * delete_long_name() - delete long name directory entries
1643  *
1644  * @itr:	directory iterator
1645  * Return:	0 for success
1646  */
delete_long_name(fat_itr * itr)1647 static int delete_long_name(fat_itr *itr)
1648 {
1649 	int seqn = itr->dent->nameext.name[0] & ~LAST_LONG_ENTRY_MASK;
1650 
1651 	while (seqn--) {
1652 		struct dir_entry *dent;
1653 		int ret;
1654 
1655 		ret = delete_single_dentry(itr);
1656 		if (ret)
1657 			return ret;
1658 		dent = next_dent(itr);
1659 		if (!dent)
1660 			return -EIO;
1661 	}
1662 	return 0;
1663 }
1664 
1665 /**
1666  * delete_dentry_link() - deletes a directory entry, but not the cluster chain
1667  * it points to
1668  *
1669  * @itr:	the first directory entry (if a longname) to remove
1670  * Return:	0 for success
1671  */
delete_dentry_link(fat_itr * itr)1672 static int delete_dentry_link(fat_itr *itr)
1673 {
1674 	int ret;
1675 
1676 	itr->dent = itr->dent_start;
1677 	itr->remaining = itr->dent_rem;
1678 	/* Delete long name */
1679 	if ((itr->dent->attr & ATTR_VFAT) == ATTR_VFAT &&
1680 	    (itr->dent->nameext.name[0] & LAST_LONG_ENTRY_MASK)) {
1681 		ret = delete_long_name(itr);
1682 		if (ret)
1683 			return ret;
1684 	}
1685 	/* Delete short name */
1686 	delete_single_dentry(itr);
1687 
1688 	ret = flush_dir(itr);
1689 	if (ret)
1690 		return ret;
1691 
1692 	return update_parent_dir_props(itr);
1693 }
1694 
1695 /**
1696  * delete_dentry_long() - remove directory entry
1697  *
1698  * @itr:	directory iterator
1699  * Return:	0 for success
1700  */
delete_dentry_long(fat_itr * itr)1701 static int delete_dentry_long(fat_itr *itr)
1702 {
1703 	fsdata *mydata = itr->fsdata;
1704 	dir_entry *dent = itr->dent;
1705 
1706 	/* free cluster blocks */
1707 	clear_fatent(mydata, START(dent));
1708 	if (flush_dirty_fat_buffer(mydata) < 0) {
1709 		printf("Error: flush fat buffer\n");
1710 		return -EIO;
1711 	}
1712 	/* Position to first directory entry for long name */
1713 	if (itr->clust != itr->dent_clust) {
1714 		int ret;
1715 
1716 		ret = fat_move_to_cluster(itr, itr->dent_clust);
1717 		if (ret)
1718 			return ret;
1719 	}
1720 	return delete_dentry_link(itr);
1721 }
1722 
fat_unlink(const char * filename)1723 int fat_unlink(const char *filename)
1724 {
1725 	fsdata fsdata = { .fatbuf = NULL, };
1726 	fat_itr *itr = NULL;
1727 	int n_entries, ret;
1728 	char *filename_copy, *dirname, *basename;
1729 
1730 	filename_copy = strdup(filename);
1731 	itr = malloc_cache_aligned(sizeof(fat_itr));
1732 	if (!itr || !filename_copy) {
1733 		printf("Error: out of memory\n");
1734 		ret = -ENOMEM;
1735 		goto exit;
1736 	}
1737 	split_filename(filename_copy, &dirname, &basename);
1738 
1739 	if (!strcmp(dirname, "/") && !strcmp(basename, "")) {
1740 		printf("Error: cannot remove root\n");
1741 		ret = -EINVAL;
1742 		goto exit;
1743 	}
1744 
1745 	ret = fat_itr_root(itr, &fsdata);
1746 	if (ret)
1747 		goto exit;
1748 
1749 	total_sector = fsdata.total_sect;
1750 
1751 	ret = fat_itr_resolve(itr, dirname, TYPE_DIR);
1752 	if (ret) {
1753 		printf("%s: doesn't exist (%d)\n", dirname, ret);
1754 		ret = -ENOENT;
1755 		goto exit;
1756 	}
1757 
1758 	if (!find_directory_entry(itr, basename)) {
1759 		log_err("%s: doesn't exist (%d)\n", basename, -ENOENT);
1760 		ret = -ENOENT;
1761 		goto exit;
1762 	}
1763 
1764 	if (fat_itr_isdir(itr)) {
1765 		n_entries = fat_dir_entries(itr);
1766 		if (n_entries < 0) {
1767 			ret = n_entries;
1768 			goto exit;
1769 		}
1770 		if (n_entries > 2) {
1771 			printf("Error: directory is not empty: %d\n",
1772 			       n_entries);
1773 			ret = -EINVAL;
1774 			goto exit;
1775 		}
1776 	}
1777 
1778 	ret = delete_dentry_long(itr);
1779 
1780 exit:
1781 	free(fsdata.fatbuf);
1782 	free(itr);
1783 	free(filename_copy);
1784 
1785 	return ret;
1786 }
1787 
fat_mkdir(const char * dirname)1788 int fat_mkdir(const char *dirname)
1789 {
1790 	dir_entry *retdent;
1791 	fsdata datablock = { .fatbuf = NULL, };
1792 	fsdata *mydata = &datablock;
1793 	fat_itr *itr = NULL;
1794 	char *dirname_copy, *parent, *basename;
1795 	char l_dirname[VFAT_MAXLEN_BYTES];
1796 	int ret = -1;
1797 	loff_t actwrite;
1798 	unsigned int bytesperclust;
1799 	dir_entry *dotdent = NULL;
1800 
1801 	dirname_copy = strdup(dirname);
1802 	if (!dirname_copy)
1803 		goto exit;
1804 
1805 	split_filename(dirname_copy, &parent, &basename);
1806 	if (!strlen(basename)) {
1807 		ret = -EINVAL;
1808 		goto exit;
1809 	}
1810 
1811 	if (normalize_longname(l_dirname, basename)) {
1812 		printf("FAT: illegal filename (%s)\n", basename);
1813 		ret = -EINVAL;
1814 		goto exit;
1815 	}
1816 
1817 	itr = malloc_cache_aligned(sizeof(fat_itr));
1818 	if (!itr) {
1819 		ret = -ENOMEM;
1820 		goto exit;
1821 	}
1822 
1823 	ret = fat_itr_root(itr, &datablock);
1824 	if (ret)
1825 		goto exit;
1826 
1827 	total_sector = datablock.total_sect;
1828 
1829 	ret = fat_itr_resolve(itr, parent, TYPE_DIR);
1830 	if (ret) {
1831 		printf("%s: doesn't exist (%d)\n", parent, ret);
1832 		goto exit;
1833 	}
1834 
1835 	retdent = find_directory_entry(itr, l_dirname);
1836 
1837 	if (retdent) {
1838 		printf("%s: already exists\n", l_dirname);
1839 		ret = -EEXIST;
1840 		goto exit;
1841 	} else {
1842 		if (itr->is_root) {
1843 			/* root dir cannot have "." or ".." */
1844 			if (!strcmp(l_dirname, ".") ||
1845 			    !strcmp(l_dirname, "..")) {
1846 				ret = -EINVAL;
1847 				goto exit;
1848 			}
1849 		}
1850 
1851 		ret = create_link(itr, basename, 0, 0, ATTR_DIR | ATTR_ARCH);
1852 		if (ret)
1853 			goto exit;
1854 
1855 		retdent = itr->dent;
1856 	}
1857 
1858 	/* Default entries */
1859 	bytesperclust = mydata->clust_size * mydata->sect_size;
1860 	dotdent = malloc_cache_aligned(bytesperclust);
1861 	if (!dotdent) {
1862 		ret = -ENOMEM;
1863 		goto exit;
1864 	}
1865 	memset(dotdent, 0, bytesperclust);
1866 
1867 	memcpy(&dotdent[0].nameext, ".          ", 11);
1868 	dotdent[0].attr = ATTR_DIR | ATTR_ARCH;
1869 
1870 	memcpy(&dotdent[1].nameext, "..         ", 11);
1871 	dotdent[1].attr = ATTR_DIR | ATTR_ARCH;
1872 
1873 	if (itr->is_root)
1874 		set_start_cluster(mydata, &dotdent[1], 0);
1875 	else
1876 		set_start_cluster(mydata, &dotdent[1], itr->start_clust);
1877 
1878 	ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
1879 			   bytesperclust, &actwrite);
1880 	if (ret < 0) {
1881 		printf("Error: writing contents\n");
1882 		goto exit;
1883 	}
1884 	/* Write twice for "." */
1885 	set_start_cluster(mydata, &dotdent[0], START(retdent));
1886 	ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
1887 			   bytesperclust, &actwrite);
1888 	if (ret < 0) {
1889 		printf("Error: writing contents\n");
1890 		goto exit;
1891 	}
1892 
1893 	/* Flush fat buffer */
1894 	ret = flush_dirty_fat_buffer(mydata);
1895 	if (ret) {
1896 		printf("Error: flush fat buffer\n");
1897 		ret = -EIO;
1898 		goto exit;
1899 	}
1900 
1901 	/* Write directory table to device */
1902 	ret = flush_dir(itr);
1903 
1904 exit:
1905 	free(dirname_copy);
1906 	free(mydata->fatbuf);
1907 	free(itr);
1908 	free(dotdent);
1909 	return ret;
1910 }
1911 
1912 /**
1913  * check_path_prefix() - ensures one path does not contains another path as a
1914  * prefix.
1915  *
1916  * for example: path foo/bar/baz/qux contains the path prefix foo/bar/baz
1917  *
1918  * note: the iterator may be pointing to any directory entry in the directory
1919  *
1920  * @prefix_clust:	start cluster of the final directory in the prefix path
1921  * (the start cluster of 'baz' in the above example)
1922  * @path_itr:	iterator of the path to check (an iterator pointing to any
1923  * direntry in 'qux' in the above example)
1924  * Return:	-errno on error, 0 if path_itr does not have the directory
1925  * at prefix_clust as an ancestor.
1926  */
check_path_prefix(loff_t prefix_clust,fat_itr * path_itr)1927 static int check_path_prefix(loff_t prefix_clust, fat_itr *path_itr)
1928 {
1929 	fat_itr itr;
1930 	fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
1931 	int ret;
1932 
1933 	/* duplicate fsdata */
1934 	itr = *path_itr;
1935 	fsdata = *itr.fsdata;
1936 
1937 	/* allocate local fat buffer */
1938 	fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
1939 	if (!fsdata.fatbuf) {
1940 		log_debug("Error: allocating memory\n");
1941 		ret = -ENOMEM;
1942 		goto exit;
1943 	}
1944 
1945 	fsdata.fatbufnum = -1;
1946 	itr.fsdata = &fsdata;
1947 
1948 	/* ensure iterator is at the first directory entry */
1949 	ret = fat_move_to_cluster(&itr, itr.start_clust);
1950 	if (ret)
1951 		goto exit;
1952 
1953 	while (1) {
1954 		if (prefix_clust == itr.start_clust) {
1955 			ret = -EINVAL;
1956 			goto exit;
1957 		}
1958 
1959 		if (itr.is_root) {
1960 			ret = 0;
1961 			goto exit;
1962 		}
1963 
1964 		/* Should not occur in a well-formed FAT filesystem besides the root */
1965 		if (fat_itr_parent(&itr)) {
1966 			log_debug("FAT filesystem corrupt!\n");
1967 			log_debug("dir @ clust %u has no parent direntry\n",
1968 				  itr.start_clust);
1969 			ret = -EIO;
1970 			goto exit;
1971 		}
1972 	}
1973 
1974 exit:
1975 	free(fsdata.fatbuf);
1976 	return ret;
1977 }
1978 
1979 /**
1980  * fat_rename - rename/move a file or directory
1981  *
1982  * @old_path:	path to the existing file/directory
1983  * @new_path:	new path/name for the rename/move
1984  * Return:	0 on success, -errno otherwise
1985  */
fat_rename(const char * old_path,const char * new_path)1986 int fat_rename(const char *old_path, const char *new_path)
1987 {
1988 	fat_itr *old_itr = NULL, *new_itr = NULL;
1989 	fsdata old_datablock = { .fatbuf = NULL, };
1990 	fsdata new_datablock = { .fatbuf = NULL, };
1991 	/* used for START macro */
1992 	fsdata *mydata = &old_datablock;
1993 	int ret = -EIO, is_old_dir;
1994 	char *old_path_copy, *old_dirname, *old_basename;
1995 	char *new_path_copy, *new_dirname, *new_basename;
1996 	char l_new_basename[VFAT_MAXLEN_BYTES];
1997 	__u32 old_clust;
1998 	dir_entry *found_existing;
1999 	/* only set if found_existing != NULL */
2000 	__u32 new_clust;
2001 
2002 	old_path_copy = strdup(old_path);
2003 	new_path_copy = strdup(new_path);
2004 	old_itr = malloc_cache_aligned(sizeof(fat_itr));
2005 	new_itr = malloc_cache_aligned(sizeof(fat_itr));
2006 	if (!old_path_copy || !new_path_copy || !old_itr || !new_itr) {
2007 		log_debug("Error: out of memory\n");
2008 		ret = -ENOMEM;
2009 		goto exit;
2010 	}
2011 	split_filename(old_path_copy, &old_dirname, &old_basename);
2012 	split_filename(new_path_copy, &new_dirname, &new_basename);
2013 
2014 	if (normalize_longname(l_new_basename, new_basename)) {
2015 		log_debug("FAT: illegal filename (%s)\n", new_basename);
2016 		ret = -EINVAL;
2017 		goto exit;
2018 	}
2019 
2020 	if (!strcmp(old_basename, ".") || !strcmp(old_basename, "..") ||
2021 	    !strcmp(old_basename, "") || !strcmp(l_new_basename, ".") ||
2022 	    !strcmp(l_new_basename, "..") || !strcmp(l_new_basename, "")) {
2023 		ret = -EINVAL;
2024 		goto exit;
2025 	}
2026 
2027 	/* checking for old_path == new_path is deferred until they're resolved */
2028 
2029 	/* resolve old_path */
2030 	ret = fat_itr_root(old_itr, &old_datablock);
2031 	if (ret)
2032 		goto exit;
2033 
2034 	ret = fat_itr_resolve(old_itr, old_dirname, TYPE_DIR);
2035 	if (ret) {
2036 		log_debug("%s doesn't exist (%d)\n", old_dirname, ret);
2037 		ret = -ENOENT;
2038 		goto exit;
2039 	}
2040 
2041 	if (!find_directory_entry(old_itr, old_basename)) {
2042 		log_debug("%s doesn't exist (%d)\n", old_basename, -ENOENT);
2043 		ret = -ENOENT;
2044 		goto exit;
2045 	}
2046 
2047 	/* store clust old_path points to, to relink later */
2048 	total_sector = old_datablock.total_sect;
2049 	old_clust = START(old_itr->dent);
2050 	is_old_dir = fat_itr_isdir(old_itr);
2051 
2052 	/* resolve new_path*/
2053 	ret = fat_itr_root(new_itr, &new_datablock);
2054 	if (ret)
2055 		goto exit;
2056 
2057 	ret = fat_itr_resolve(new_itr, new_dirname, TYPE_DIR);
2058 	if (ret) {
2059 		log_debug("%s doesn't exist (%d)\n", new_dirname, ret);
2060 		ret = -ENOENT;
2061 		goto exit;
2062 	}
2063 
2064 	found_existing = find_directory_entry(new_itr, l_new_basename);
2065 
2066 	if (found_existing) {
2067 		/* store cluster of new_path since it may need to be deleted */
2068 		new_clust = START(new_itr->dent);
2069 
2070 		/* old_path is new_path, noop */
2071 		if (old_clust == new_clust) {
2072 			ret = 0;
2073 			goto exit;
2074 		}
2075 
2076 		if (fat_itr_isdir(new_itr) != is_old_dir) {
2077 			if (is_old_dir)
2078 				ret = -ENOTDIR;
2079 			else
2080 				ret = -EISDIR;
2081 			goto exit;
2082 		}
2083 	}
2084 
2085 	if (is_old_dir) {
2086 		ret = check_path_prefix(old_clust, new_itr);
2087 		if (ret)
2088 			goto exit;
2089 	}
2090 
2091 	/* create/update dentry to point to old_path's data cluster */
2092 	if (found_existing) {
2093 		struct nameext new_name = new_itr->dent->nameext;
2094 		__u8 lcase = new_itr->dent->lcase;
2095 
2096 		if (is_old_dir) {
2097 			int n_entries = fat_dir_entries(new_itr);
2098 
2099 			if (n_entries < 0) {
2100 				ret = n_entries;
2101 				goto exit;
2102 			}
2103 			if (n_entries > 2) {
2104 				log_debug("Error: directory is not empty: %d\n",
2105 					  n_entries);
2106 				ret = -ENOTEMPTY;
2107 				goto exit;
2108 			}
2109 		}
2110 
2111 		*new_itr->dent = *old_itr->dent;
2112 		new_itr->dent->nameext = new_name;
2113 		new_itr->dent->lcase = lcase;
2114 
2115 		ret = update_parent_dir_props(new_itr);
2116 		if (ret)
2117 			goto exit;
2118 	} else {
2119 		/* reset iterator to the start of the directory */
2120 		ret = fat_move_to_cluster(new_itr, new_itr->start_clust);
2121 		if (ret)
2122 			goto exit;
2123 
2124 		ret = create_link(new_itr, l_new_basename, old_clust,
2125 				  old_itr->dent->size,
2126 				  old_itr->dent->attr | ATTR_ARCH);
2127 		if (ret)
2128 			goto exit;
2129 	}
2130 
2131 	ret = flush_dir(new_itr);
2132 	if (ret)
2133 		goto exit;
2134 
2135 	/* with new_path data cluster unreferenced, clear it */
2136 	if (found_existing) {
2137 		ret = clear_fatent(&new_datablock, new_clust);
2138 		if (ret)
2139 			goto exit;
2140 	}
2141 
2142 	/* update moved directory so the parent is new_path */
2143 	if (is_old_dir) {
2144 		__u32 clust = new_itr->start_clust;
2145 		dir_entry *dent;
2146 
2147 		fat_itr_child(new_itr, new_itr);
2148 		dent = find_directory_entry(new_itr, "..");
2149 		if (!dent) {
2150 			log_debug("FAT filesystem corrupt!\n");
2151 			log_debug("dir %s has no parent direntry\n",
2152 				  l_new_basename);
2153 			ret = -EIO;
2154 			goto exit;
2155 		}
2156 		set_start_cluster(&new_datablock, dent, clust);
2157 		ret = flush_dir(new_itr);
2158 		if (ret)
2159 			goto exit;
2160 		/* restore directory location to update parent props below */
2161 		fat_itr_child(new_itr, new_itr);
2162 	}
2163 
2164 	/* refresh old in case write happened to the same block. */
2165 	ret = fat_move_to_cluster(old_itr, old_itr->dent_clust);
2166 	if (ret)
2167 		goto exit;
2168 
2169 	ret = delete_dentry_link(old_itr);
2170 exit:
2171 	free(new_datablock.fatbuf);
2172 	free(old_datablock.fatbuf);
2173 	free(new_itr);
2174 	free(old_itr);
2175 	free(new_path_copy);
2176 	free(old_path_copy);
2177 
2178 	return ret;
2179 }
2180