• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <common.h>
9 #include <command.h>
10 #include <config.h>
11 #include <fat.h>
12 #include <asm/byteorder.h>
13 #include <part.h>
14 #include <linux/ctype.h>
15 #include <div64.h>
16 #include <linux/math64.h>
17 #include "fat.c"
18 
uppercase(char * str,int len)19 static void uppercase(char *str, int len)
20 {
21 	int i;
22 
23 	for (i = 0; i < len; i++) {
24 		*str = toupper(*str);
25 		str++;
26 	}
27 }
28 
29 static int total_sector;
disk_write(__u32 block,__u32 nr_blocks,void * buf)30 static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
31 {
32 	ulong ret;
33 
34 	if (!cur_dev)
35 		return -1;
36 
37 	if (cur_part_info.start + block + nr_blocks >
38 		cur_part_info.start + total_sector) {
39 		printf("error: overflow occurs\n");
40 		return -1;
41 	}
42 
43 	ret = blk_dwrite(cur_dev, cur_part_info.start + block, nr_blocks, buf);
44 	if (nr_blocks && ret == 0)
45 		return -1;
46 
47 	return ret;
48 }
49 
50 /*
51  * Set short name in directory entry
52  */
set_name(dir_entry * dirent,const char * filename)53 static void set_name(dir_entry *dirent, const char *filename)
54 {
55 	char s_name[VFAT_MAXLEN_BYTES];
56 	char *period;
57 	int period_location, len, i, ext_num;
58 
59 	if (filename == NULL)
60 		return;
61 
62 	len = strlen(filename);
63 	if (len == 0)
64 		return;
65 
66 	strcpy(s_name, filename);
67 	uppercase(s_name, len);
68 
69 	period = strchr(s_name, '.');
70 	if (period == NULL) {
71 		period_location = len;
72 		ext_num = 0;
73 	} else {
74 		period_location = period - s_name;
75 		ext_num = len - period_location - 1;
76 	}
77 
78 	/* Pad spaces when the length of file name is shorter than eight */
79 	if (period_location < 8) {
80 		memcpy(dirent->name, s_name, period_location);
81 		for (i = period_location; i < 8; i++)
82 			dirent->name[i] = ' ';
83 	} else if (period_location == 8) {
84 		memcpy(dirent->name, s_name, period_location);
85 	} else {
86 		memcpy(dirent->name, s_name, 6);
87 		dirent->name[6] = '~';
88 		dirent->name[7] = '1';
89 	}
90 
91 	if (ext_num < 3) {
92 		memcpy(dirent->ext, s_name + period_location + 1, ext_num);
93 		for (i = ext_num; i < 3; i++)
94 			dirent->ext[i] = ' ';
95 	} else
96 		memcpy(dirent->ext, s_name + period_location + 1, 3);
97 
98 	debug("name : %s\n", dirent->name);
99 	debug("ext : %s\n", dirent->ext);
100 }
101 
102 /*
103  * Write fat buffer into block device
104  */
flush_dirty_fat_buffer(fsdata * mydata)105 static int flush_dirty_fat_buffer(fsdata *mydata)
106 {
107 	int getsize = FATBUFBLOCKS;
108 	__u32 fatlength = mydata->fatlength;
109 	__u8 *bufptr = mydata->fatbuf;
110 	__u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
111 
112 	debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum,
113 	      (int)mydata->fat_dirty);
114 
115 	if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1))
116 		return 0;
117 
118 	/* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
119 	if (startblock + getsize > fatlength)
120 		getsize = fatlength - startblock;
121 
122 	startblock += mydata->fat_sect;
123 
124 	/* Write FAT buf */
125 	if (disk_write(startblock, getsize, bufptr) < 0) {
126 		debug("error: writing FAT blocks\n");
127 		return -1;
128 	}
129 
130 	if (mydata->fats == 2) {
131 		/* Update corresponding second FAT blocks */
132 		startblock += mydata->fatlength;
133 		if (disk_write(startblock, getsize, bufptr) < 0) {
134 			debug("error: writing second FAT blocks\n");
135 			return -1;
136 		}
137 	}
138 	mydata->fat_dirty = 0;
139 
140 	return 0;
141 }
142 
143 /*
144  * Set the file name information from 'name' into 'slotptr',
145  */
str2slot(dir_slot * slotptr,const char * name,int * idx)146 static int str2slot(dir_slot *slotptr, const char *name, int *idx)
147 {
148 	int j, end_idx = 0;
149 
150 	for (j = 0; j <= 8; j += 2) {
151 		if (name[*idx] == 0x00) {
152 			slotptr->name0_4[j] = 0;
153 			slotptr->name0_4[j + 1] = 0;
154 			end_idx++;
155 			goto name0_4;
156 		}
157 		slotptr->name0_4[j] = name[*idx];
158 		(*idx)++;
159 		end_idx++;
160 	}
161 	for (j = 0; j <= 10; j += 2) {
162 		if (name[*idx] == 0x00) {
163 			slotptr->name5_10[j] = 0;
164 			slotptr->name5_10[j + 1] = 0;
165 			end_idx++;
166 			goto name5_10;
167 		}
168 		slotptr->name5_10[j] = name[*idx];
169 		(*idx)++;
170 		end_idx++;
171 	}
172 	for (j = 0; j <= 2; j += 2) {
173 		if (name[*idx] == 0x00) {
174 			slotptr->name11_12[j] = 0;
175 			slotptr->name11_12[j + 1] = 0;
176 			end_idx++;
177 			goto name11_12;
178 		}
179 		slotptr->name11_12[j] = name[*idx];
180 		(*idx)++;
181 		end_idx++;
182 	}
183 
184 	if (name[*idx] == 0x00)
185 		return 1;
186 
187 	return 0;
188 /* Not used characters are filled with 0xff 0xff */
189 name0_4:
190 	for (; end_idx < 5; end_idx++) {
191 		slotptr->name0_4[end_idx * 2] = 0xff;
192 		slotptr->name0_4[end_idx * 2 + 1] = 0xff;
193 	}
194 	end_idx = 5;
195 name5_10:
196 	end_idx -= 5;
197 	for (; end_idx < 6; end_idx++) {
198 		slotptr->name5_10[end_idx * 2] = 0xff;
199 		slotptr->name5_10[end_idx * 2 + 1] = 0xff;
200 	}
201 	end_idx = 11;
202 name11_12:
203 	end_idx -= 11;
204 	for (; end_idx < 2; end_idx++) {
205 		slotptr->name11_12[end_idx * 2] = 0xff;
206 		slotptr->name11_12[end_idx * 2 + 1] = 0xff;
207 	}
208 
209 	return 1;
210 }
211 
212 static int new_dir_table(fat_itr *itr);
213 static int flush_dir(fat_itr *itr);
214 
215 /*
216  * Fill dir_slot entries with appropriate name, id, and attr
217  * 'itr' will point to a next entry
218  */
219 static int
fill_dir_slot(fat_itr * itr,const char * l_name)220 fill_dir_slot(fat_itr *itr, const char *l_name)
221 {
222 	__u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)];
223 	dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer;
224 	__u8 counter = 0, checksum;
225 	int idx = 0, ret;
226 
227 	/* Get short file name checksum value */
228 	checksum = mkcksum(itr->dent->name, itr->dent->ext);
229 
230 	do {
231 		memset(slotptr, 0x00, sizeof(dir_slot));
232 		ret = str2slot(slotptr, l_name, &idx);
233 		slotptr->id = ++counter;
234 		slotptr->attr = ATTR_VFAT;
235 		slotptr->alias_checksum = checksum;
236 		slotptr++;
237 	} while (ret == 0);
238 
239 	slotptr--;
240 	slotptr->id |= LAST_LONG_ENTRY_MASK;
241 
242 	while (counter >= 1) {
243 		memcpy(itr->dent, slotptr, sizeof(dir_slot));
244 		slotptr--;
245 		counter--;
246 
247 		if (itr->remaining == 0)
248 			flush_dir(itr);
249 
250 		/* allocate a cluster for more entries */
251 		if (!fat_itr_next(itr))
252 			if (!itr->dent &&
253 			    (!itr->is_root || itr->fsdata->fatsize == 32) &&
254 			    new_dir_table(itr))
255 				return -1;
256 	}
257 
258 	return 0;
259 }
260 
261 /*
262  * Set the entry at index 'entry' in a FAT (12/16/32) table.
263  */
set_fatent_value(fsdata * mydata,__u32 entry,__u32 entry_value)264 static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
265 {
266 	__u32 bufnum, offset, off16;
267 	__u16 val1, val2;
268 
269 	switch (mydata->fatsize) {
270 	case 32:
271 		bufnum = entry / FAT32BUFSIZE;
272 		offset = entry - bufnum * FAT32BUFSIZE;
273 		break;
274 	case 16:
275 		bufnum = entry / FAT16BUFSIZE;
276 		offset = entry - bufnum * FAT16BUFSIZE;
277 		break;
278 	case 12:
279 		bufnum = entry / FAT12BUFSIZE;
280 		offset = entry - bufnum * FAT12BUFSIZE;
281 		break;
282 	default:
283 		/* Unsupported FAT size */
284 		return -1;
285 	}
286 
287 	/* Read a new block of FAT entries into the cache. */
288 	if (bufnum != mydata->fatbufnum) {
289 		int getsize = FATBUFBLOCKS;
290 		__u8 *bufptr = mydata->fatbuf;
291 		__u32 fatlength = mydata->fatlength;
292 		__u32 startblock = bufnum * FATBUFBLOCKS;
293 
294 		/* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
295 		if (startblock + getsize > fatlength)
296 			getsize = fatlength - startblock;
297 
298 		if (flush_dirty_fat_buffer(mydata) < 0)
299 			return -1;
300 
301 		startblock += mydata->fat_sect;
302 
303 		if (disk_read(startblock, getsize, bufptr) < 0) {
304 			debug("Error reading FAT blocks\n");
305 			return -1;
306 		}
307 		mydata->fatbufnum = bufnum;
308 	}
309 
310 	/* Mark as dirty */
311 	mydata->fat_dirty = 1;
312 
313 	/* Set the actual entry */
314 	switch (mydata->fatsize) {
315 	case 32:
316 		((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
317 		break;
318 	case 16:
319 		((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
320 		break;
321 	case 12:
322 		off16 = (offset * 3) / 4;
323 
324 		switch (offset & 0x3) {
325 		case 0:
326 			val1 = cpu_to_le16(entry_value) & 0xfff;
327 			((__u16 *)mydata->fatbuf)[off16] &= ~0xfff;
328 			((__u16 *)mydata->fatbuf)[off16] |= val1;
329 			break;
330 		case 1:
331 			val1 = cpu_to_le16(entry_value) & 0xf;
332 			val2 = (cpu_to_le16(entry_value) >> 4) & 0xff;
333 
334 			((__u16 *)mydata->fatbuf)[off16] &= ~0xf000;
335 			((__u16 *)mydata->fatbuf)[off16] |= (val1 << 12);
336 
337 			((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xff;
338 			((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
339 			break;
340 		case 2:
341 			val1 = cpu_to_le16(entry_value) & 0xff;
342 			val2 = (cpu_to_le16(entry_value) >> 8) & 0xf;
343 
344 			((__u16 *)mydata->fatbuf)[off16] &= ~0xff00;
345 			((__u16 *)mydata->fatbuf)[off16] |= (val1 << 8);
346 
347 			((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xf;
348 			((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
349 			break;
350 		case 3:
351 			val1 = cpu_to_le16(entry_value) & 0xfff;
352 			((__u16 *)mydata->fatbuf)[off16] &= ~0xfff0;
353 			((__u16 *)mydata->fatbuf)[off16] |= (val1 << 4);
354 			break;
355 		default:
356 			break;
357 		}
358 
359 		break;
360 	default:
361 		return -1;
362 	}
363 
364 	return 0;
365 }
366 
367 /*
368  * Determine the next free cluster after 'entry' in a FAT (12/16/32) table
369  * and link it to 'entry'. EOC marker is not set on returned entry.
370  */
determine_fatent(fsdata * mydata,__u32 entry)371 static __u32 determine_fatent(fsdata *mydata, __u32 entry)
372 {
373 	__u32 next_fat, next_entry = entry + 1;
374 
375 	while (1) {
376 		next_fat = get_fatent(mydata, next_entry);
377 		if (next_fat == 0) {
378 			/* found free entry, link to entry */
379 			set_fatent_value(mydata, entry, next_entry);
380 			break;
381 		}
382 		next_entry++;
383 	}
384 	debug("FAT%d: entry: %08x, entry_value: %04x\n",
385 	       mydata->fatsize, entry, next_entry);
386 
387 	return next_entry;
388 }
389 
390 /**
391  * set_sectors() - write data to sectors
392  *
393  * Write 'size' bytes from 'buffer' into the specified sector.
394  *
395  * @mydata:	data to be written
396  * @startsect:	sector to be written to
397  * @buffer:	data to be written
398  * @size:	bytes to be written (but not more than the size of a cluster)
399  * Return:	0 on success, -1 otherwise
400  */
401 static int
set_sectors(fsdata * mydata,u32 startsect,u8 * buffer,u32 size)402 set_sectors(fsdata *mydata, u32 startsect, u8 *buffer, u32 size)
403 {
404 	u32 nsects = 0;
405 	int ret;
406 
407 	debug("startsect: %d\n", startsect);
408 
409 	if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
410 		ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
411 
412 		debug("FAT: Misaligned buffer address (%p)\n", buffer);
413 
414 		while (size >= mydata->sect_size) {
415 			memcpy(tmpbuf, buffer, mydata->sect_size);
416 			ret = disk_write(startsect++, 1, tmpbuf);
417 			if (ret != 1) {
418 				debug("Error writing data (got %d)\n", ret);
419 				return -1;
420 			}
421 
422 			buffer += mydata->sect_size;
423 			size -= mydata->sect_size;
424 		}
425 	} else if (size >= mydata->sect_size) {
426 		nsects = size / mydata->sect_size;
427 		ret = disk_write(startsect, nsects, buffer);
428 		if (ret != nsects) {
429 			debug("Error writing data (got %d)\n", ret);
430 			return -1;
431 		}
432 
433 		startsect += nsects;
434 		buffer += nsects * mydata->sect_size;
435 		size -= nsects * mydata->sect_size;
436 	}
437 
438 	if (size) {
439 		ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
440 		/* Do not leak content of stack */
441 		memset(tmpbuf, 0, mydata->sect_size);
442 		memcpy(tmpbuf, buffer, size);
443 		ret = disk_write(startsect, 1, tmpbuf);
444 		if (ret != 1) {
445 			debug("Error writing data (got %d)\n", ret);
446 			return -1;
447 		}
448 	}
449 
450 	return 0;
451 }
452 
453 /**
454  * set_cluster() - write data to cluster
455  *
456  * Write 'size' bytes from 'buffer' into the specified cluster.
457  *
458  * @mydata:	data to be written
459  * @clustnum:	cluster to be written to
460  * @buffer:	data to be written
461  * @size:	bytes to be written (but not more than the size of a cluster)
462  * Return:	0 on success, -1 otherwise
463  */
464 static int
set_cluster(fsdata * mydata,u32 clustnum,u8 * buffer,u32 size)465 set_cluster(fsdata *mydata, u32 clustnum, u8 *buffer, u32 size)
466 {
467 	return set_sectors(mydata, clust_to_sect(mydata, clustnum),
468 			   buffer, size);
469 }
470 
471 static int
flush_dir(fat_itr * itr)472 flush_dir(fat_itr *itr)
473 {
474 	fsdata *mydata = itr->fsdata;
475 	u32 startsect, sect_offset, nsects;
476 
477 	if (!itr->is_root || mydata->fatsize == 32)
478 		return set_cluster(mydata, itr->clust, itr->block,
479 				   mydata->clust_size * mydata->sect_size);
480 
481 	sect_offset = itr->clust * mydata->clust_size;
482 	startsect = mydata->rootdir_sect + sect_offset;
483 	/* do not write past the end of rootdir */
484 	nsects = min_t(u32, mydata->clust_size,
485 		       mydata->rootdir_size - sect_offset);
486 
487 	return set_sectors(mydata, startsect, itr->block,
488 			   nsects * mydata->sect_size);
489 }
490 
491 static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
492 
493 /*
494  * Read and modify data on existing and consecutive cluster blocks
495  */
496 static int
get_set_cluster(fsdata * mydata,__u32 clustnum,loff_t pos,__u8 * buffer,loff_t size,loff_t * gotsize)497 get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
498 		loff_t size, loff_t *gotsize)
499 {
500 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
501 	__u32 startsect;
502 	loff_t wsize;
503 	int clustcount, i, ret;
504 
505 	*gotsize = 0;
506 	if (!size)
507 		return 0;
508 
509 	assert(pos < bytesperclust);
510 	startsect = clust_to_sect(mydata, clustnum);
511 
512 	debug("clustnum: %d, startsect: %d, pos: %lld\n",
513 	      clustnum, startsect, pos);
514 
515 	/* partial write at beginning */
516 	if (pos) {
517 		wsize = min(bytesperclust - pos, size);
518 		ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
519 		if (ret != mydata->clust_size) {
520 			debug("Error reading data (got %d)\n", ret);
521 			return -1;
522 		}
523 
524 		memcpy(tmpbuf_cluster + pos, buffer, wsize);
525 		ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
526 		if (ret != mydata->clust_size) {
527 			debug("Error writing data (got %d)\n", ret);
528 			return -1;
529 		}
530 
531 		size -= wsize;
532 		buffer += wsize;
533 		*gotsize += wsize;
534 
535 		startsect += mydata->clust_size;
536 
537 		if (!size)
538 			return 0;
539 	}
540 
541 	/* full-cluster write */
542 	if (size >= bytesperclust) {
543 		clustcount = lldiv(size, bytesperclust);
544 
545 		if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
546 			wsize = clustcount * bytesperclust;
547 			ret = disk_write(startsect,
548 					 clustcount * mydata->clust_size,
549 					 buffer);
550 			if (ret != clustcount * mydata->clust_size) {
551 				debug("Error writing data (got %d)\n", ret);
552 				return -1;
553 			}
554 
555 			size -= wsize;
556 			buffer += wsize;
557 			*gotsize += wsize;
558 
559 			startsect += clustcount * mydata->clust_size;
560 		} else {
561 			for (i = 0; i < clustcount; i++) {
562 				memcpy(tmpbuf_cluster, buffer, bytesperclust);
563 				ret = disk_write(startsect,
564 						 mydata->clust_size,
565 						 tmpbuf_cluster);
566 				if (ret != mydata->clust_size) {
567 					debug("Error writing data (got %d)\n",
568 					      ret);
569 					return -1;
570 				}
571 
572 				size -= bytesperclust;
573 				buffer += bytesperclust;
574 				*gotsize += bytesperclust;
575 
576 				startsect += mydata->clust_size;
577 			}
578 		}
579 	}
580 
581 	/* partial write at end */
582 	if (size) {
583 		wsize = size;
584 		ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
585 		if (ret != mydata->clust_size) {
586 			debug("Error reading data (got %d)\n", ret);
587 			return -1;
588 		}
589 		memcpy(tmpbuf_cluster, buffer, wsize);
590 		ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
591 		if (ret != mydata->clust_size) {
592 			debug("Error writing data (got %d)\n", ret);
593 			return -1;
594 		}
595 
596 		size -= wsize;
597 		buffer += wsize;
598 		*gotsize += wsize;
599 	}
600 
601 	assert(!size);
602 
603 	return 0;
604 }
605 
606 /*
607  * Find the first empty cluster
608  */
find_empty_cluster(fsdata * mydata)609 static int find_empty_cluster(fsdata *mydata)
610 {
611 	__u32 fat_val, entry = 3;
612 
613 	while (1) {
614 		fat_val = get_fatent(mydata, entry);
615 		if (fat_val == 0)
616 			break;
617 		entry++;
618 	}
619 
620 	return entry;
621 }
622 
623 /*
624  * Allocate a cluster for additional directory entries
625  */
new_dir_table(fat_itr * itr)626 static int new_dir_table(fat_itr *itr)
627 {
628 	fsdata *mydata = itr->fsdata;
629 	int dir_newclust = 0;
630 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
631 
632 	dir_newclust = find_empty_cluster(mydata);
633 	set_fatent_value(mydata, itr->clust, dir_newclust);
634 	if (mydata->fatsize == 32)
635 		set_fatent_value(mydata, dir_newclust, 0xffffff8);
636 	else if (mydata->fatsize == 16)
637 		set_fatent_value(mydata, dir_newclust, 0xfff8);
638 	else if (mydata->fatsize == 12)
639 		set_fatent_value(mydata, dir_newclust, 0xff8);
640 
641 	itr->clust = dir_newclust;
642 	itr->next_clust = dir_newclust;
643 
644 	if (flush_dirty_fat_buffer(mydata) < 0)
645 		return -1;
646 
647 	memset(itr->block, 0x00, bytesperclust);
648 
649 	itr->dent = (dir_entry *)itr->block;
650 	itr->last_cluster = 1;
651 	itr->remaining = bytesperclust / sizeof(dir_entry) - 1;
652 
653 	return 0;
654 }
655 
656 /*
657  * Set empty cluster from 'entry' to the end of a file
658  */
clear_fatent(fsdata * mydata,__u32 entry)659 static int clear_fatent(fsdata *mydata, __u32 entry)
660 {
661 	__u32 fat_val;
662 
663 	while (!CHECK_CLUST(entry, mydata->fatsize)) {
664 		fat_val = get_fatent(mydata, entry);
665 		if (fat_val != 0)
666 			set_fatent_value(mydata, entry, 0);
667 		else
668 			break;
669 
670 		entry = fat_val;
671 	}
672 
673 	/* Flush fat buffer */
674 	if (flush_dirty_fat_buffer(mydata) < 0)
675 		return -1;
676 
677 	return 0;
678 }
679 
680 /*
681  * Set start cluster in directory entry
682  */
set_start_cluster(const fsdata * mydata,dir_entry * dentptr,__u32 start_cluster)683 static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
684 			      __u32 start_cluster)
685 {
686 	if (mydata->fatsize == 32)
687 		dentptr->starthi =
688 			cpu_to_le16((start_cluster & 0xffff0000) >> 16);
689 	dentptr->start = cpu_to_le16(start_cluster & 0xffff);
690 }
691 
692 /*
693  * Check whether adding a file makes the file system to
694  * exceed the size of the block device
695  * Return -1 when overflow occurs, otherwise return 0
696  */
check_overflow(fsdata * mydata,__u32 clustnum,loff_t size)697 static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
698 {
699 	__u32 startsect, sect_num, offset;
700 
701 	if (clustnum > 0)
702 		startsect = clust_to_sect(mydata, clustnum);
703 	else
704 		startsect = mydata->rootdir_sect;
705 
706 	sect_num = div_u64_rem(size, mydata->sect_size, &offset);
707 
708 	if (offset != 0)
709 		sect_num++;
710 
711 	if (startsect + sect_num > total_sector)
712 		return -1;
713 	return 0;
714 }
715 
716 /*
717  * Write at most 'maxsize' bytes from 'buffer' into
718  * the file associated with 'dentptr'
719  * Update the number of bytes written in *gotsize and return 0
720  * or return -1 on fatal errors.
721  */
722 static int
set_contents(fsdata * mydata,dir_entry * dentptr,loff_t pos,__u8 * buffer,loff_t maxsize,loff_t * gotsize)723 set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
724 	     loff_t maxsize, loff_t *gotsize)
725 {
726 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
727 	__u32 curclust = START(dentptr);
728 	__u32 endclust = 0, newclust = 0;
729 	u64 cur_pos, filesize;
730 	loff_t offset, actsize, wsize;
731 
732 	*gotsize = 0;
733 	filesize = pos + maxsize;
734 
735 	debug("%llu bytes\n", filesize);
736 
737 	if (!filesize) {
738 		if (!curclust)
739 			return 0;
740 		if (!CHECK_CLUST(curclust, mydata->fatsize) ||
741 		    IS_LAST_CLUST(curclust, mydata->fatsize)) {
742 			clear_fatent(mydata, curclust);
743 			set_start_cluster(mydata, dentptr, 0);
744 			return 0;
745 		}
746 		debug("curclust: 0x%x\n", curclust);
747 		debug("Invalid FAT entry\n");
748 		return -1;
749 	}
750 
751 	if (!curclust) {
752 		assert(pos == 0);
753 		goto set_clusters;
754 	}
755 
756 	/* go to cluster at pos */
757 	cur_pos = bytesperclust;
758 	while (1) {
759 		if (pos <= cur_pos)
760 			break;
761 		if (IS_LAST_CLUST(curclust, mydata->fatsize))
762 			break;
763 
764 		newclust = get_fatent(mydata, curclust);
765 		if (!IS_LAST_CLUST(newclust, mydata->fatsize) &&
766 		    CHECK_CLUST(newclust, mydata->fatsize)) {
767 			debug("curclust: 0x%x\n", curclust);
768 			debug("Invalid FAT entry\n");
769 			return -1;
770 		}
771 
772 		cur_pos += bytesperclust;
773 		curclust = newclust;
774 	}
775 	if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
776 		assert(pos == cur_pos);
777 		goto set_clusters;
778 	}
779 
780 	assert(pos < cur_pos);
781 	cur_pos -= bytesperclust;
782 
783 	/* overwrite */
784 	assert(IS_LAST_CLUST(curclust, mydata->fatsize) ||
785 	       !CHECK_CLUST(curclust, mydata->fatsize));
786 
787 	while (1) {
788 		/* search for allocated consecutive clusters */
789 		actsize = bytesperclust;
790 		endclust = curclust;
791 		while (1) {
792 			if (filesize <= (cur_pos + actsize))
793 				break;
794 
795 			newclust = get_fatent(mydata, endclust);
796 
797 			if (IS_LAST_CLUST(newclust, mydata->fatsize))
798 				break;
799 			if (CHECK_CLUST(newclust, mydata->fatsize)) {
800 				debug("curclust: 0x%x\n", curclust);
801 				debug("Invalid FAT entry\n");
802 				return -1;
803 			}
804 
805 			actsize += bytesperclust;
806 			endclust = newclust;
807 		}
808 
809 		/* overwrite to <curclust..endclust> */
810 		if (pos < cur_pos)
811 			offset = 0;
812 		else
813 			offset = pos - cur_pos;
814 		wsize = min(cur_pos + actsize, filesize) - pos;
815 		if (get_set_cluster(mydata, curclust, offset,
816 				    buffer, wsize, &actsize)) {
817 			printf("Error get-and-setting cluster\n");
818 			return -1;
819 		}
820 		buffer += wsize;
821 		*gotsize += wsize;
822 		cur_pos += offset + wsize;
823 
824 		if (filesize <= cur_pos)
825 			break;
826 
827 		/* CHECK: newclust = get_fatent(mydata, endclust); */
828 
829 		if (IS_LAST_CLUST(newclust, mydata->fatsize))
830 			/* no more clusters */
831 			break;
832 
833 		curclust = newclust;
834 	}
835 
836 	if (filesize <= cur_pos) {
837 		/* no more write */
838 		newclust = get_fatent(mydata, endclust);
839 		if (!IS_LAST_CLUST(newclust, mydata->fatsize)) {
840 			/* truncate the rest */
841 			clear_fatent(mydata, newclust);
842 
843 			/* Mark end of file in FAT */
844 			if (mydata->fatsize == 12)
845 				newclust = 0xfff;
846 			else if (mydata->fatsize == 16)
847 				newclust = 0xffff;
848 			else if (mydata->fatsize == 32)
849 				newclust = 0xfffffff;
850 			set_fatent_value(mydata, endclust, newclust);
851 		}
852 
853 		return 0;
854 	}
855 
856 	curclust = endclust;
857 	filesize -= cur_pos;
858 	assert(!do_div(cur_pos, bytesperclust));
859 
860 set_clusters:
861 	/* allocate and write */
862 	assert(!pos);
863 
864 	/* Assure that curclust is valid */
865 	if (!curclust) {
866 		curclust = find_empty_cluster(mydata);
867 		set_start_cluster(mydata, dentptr, curclust);
868 	} else {
869 		newclust = get_fatent(mydata, curclust);
870 
871 		if (IS_LAST_CLUST(newclust, mydata->fatsize)) {
872 			newclust = determine_fatent(mydata, curclust);
873 			set_fatent_value(mydata, curclust, newclust);
874 			curclust = newclust;
875 		} else {
876 			debug("error: something wrong\n");
877 			return -1;
878 		}
879 	}
880 
881 	/* TODO: already partially written */
882 	if (check_overflow(mydata, curclust, filesize)) {
883 		printf("Error: no space left: %llu\n", filesize);
884 		return -1;
885 	}
886 
887 	actsize = bytesperclust;
888 	endclust = curclust;
889 	do {
890 		/* search for consecutive clusters */
891 		while (actsize < filesize) {
892 			newclust = determine_fatent(mydata, endclust);
893 
894 			if ((newclust - 1) != endclust)
895 				/* write to <curclust..endclust> */
896 				goto getit;
897 
898 			if (CHECK_CLUST(newclust, mydata->fatsize)) {
899 				debug("newclust: 0x%x\n", newclust);
900 				debug("Invalid FAT entry\n");
901 				return 0;
902 			}
903 			endclust = newclust;
904 			actsize += bytesperclust;
905 		}
906 
907 		/* set remaining bytes */
908 		actsize = filesize;
909 		if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
910 			debug("error: writing cluster\n");
911 			return -1;
912 		}
913 		*gotsize += actsize;
914 
915 		/* Mark end of file in FAT */
916 		if (mydata->fatsize == 12)
917 			newclust = 0xfff;
918 		else if (mydata->fatsize == 16)
919 			newclust = 0xffff;
920 		else if (mydata->fatsize == 32)
921 			newclust = 0xfffffff;
922 		set_fatent_value(mydata, endclust, newclust);
923 
924 		return 0;
925 getit:
926 		if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
927 			debug("error: writing cluster\n");
928 			return -1;
929 		}
930 		*gotsize += actsize;
931 		filesize -= actsize;
932 		buffer += actsize;
933 
934 		if (CHECK_CLUST(newclust, mydata->fatsize)) {
935 			debug("newclust: 0x%x\n", newclust);
936 			debug("Invalid FAT entry\n");
937 			return 0;
938 		}
939 		actsize = bytesperclust;
940 		curclust = endclust = newclust;
941 	} while (1);
942 
943 	return 0;
944 }
945 
946 /*
947  * Fill dir_entry
948  */
fill_dentry(fsdata * mydata,dir_entry * dentptr,const char * filename,__u32 start_cluster,__u32 size,__u8 attr)949 static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
950 	const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
951 {
952 	set_start_cluster(mydata, dentptr, start_cluster);
953 	dentptr->size = cpu_to_le32(size);
954 
955 	dentptr->attr = attr;
956 
957 	set_name(dentptr, filename);
958 }
959 
960 /*
961  * Find a directory entry based on filename or start cluster number
962  * If the directory entry is not found,
963  * the new position for writing a directory entry will be returned
964  */
find_directory_entry(fat_itr * itr,char * filename)965 static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
966 {
967 	int match = 0;
968 
969 	while (fat_itr_next(itr)) {
970 		/* check both long and short name: */
971 		if (!strcasecmp(filename, itr->name))
972 			match = 1;
973 		else if (itr->name != itr->s_name &&
974 			 !strcasecmp(filename, itr->s_name))
975 			match = 1;
976 
977 		if (!match)
978 			continue;
979 
980 		if (itr->dent->name[0] == '\0')
981 			return NULL;
982 		else
983 			return itr->dent;
984 	}
985 
986 	/* allocate a cluster for more entries */
987 	if (!itr->dent &&
988 	    (!itr->is_root || itr->fsdata->fatsize == 32) &&
989 	    new_dir_table(itr))
990 		/* indicate that allocating dent failed */
991 		itr->dent = NULL;
992 
993 	return NULL;
994 }
995 
split_filename(char * filename,char ** dirname,char ** basename)996 static int split_filename(char *filename, char **dirname, char **basename)
997 {
998 	char *p, *last_slash, *last_slash_cont;
999 
1000 again:
1001 	p = filename;
1002 	last_slash = NULL;
1003 	last_slash_cont = NULL;
1004 	while (*p) {
1005 		if (ISDIRDELIM(*p)) {
1006 			last_slash = p;
1007 			last_slash_cont = p;
1008 			/* continuous slashes */
1009 			while (ISDIRDELIM(*p))
1010 				last_slash_cont = p++;
1011 			if (!*p)
1012 				break;
1013 		}
1014 		p++;
1015 	}
1016 
1017 	if (last_slash) {
1018 		if (last_slash_cont == (filename + strlen(filename) - 1)) {
1019 			/* remove trailing slashes */
1020 			*last_slash = '\0';
1021 			goto again;
1022 		}
1023 
1024 		if (last_slash == filename) {
1025 			/* avoid ""(null) directory */
1026 			*dirname = "/";
1027 		} else {
1028 			*last_slash = '\0';
1029 			*dirname = filename;
1030 		}
1031 
1032 		*last_slash_cont = '\0';
1033 		*basename = last_slash_cont + 1;
1034 	} else {
1035 		*dirname = "/"; /* root by default */
1036 		*basename = filename;
1037 	}
1038 
1039 	return 0;
1040 }
1041 
1042 /**
1043  * normalize_longname() - check long file name and convert to lower case
1044  *
1045  * We assume here that the FAT file system is using an 8bit code page.
1046  * Linux typically uses CP437, EDK2 assumes CP1250.
1047  *
1048  * @l_filename:	preallocated buffer receiving the normalized name
1049  * @filename:	filename to normalize
1050  * Return:	0 on success, -1 on failure
1051  */
normalize_longname(char * l_filename,const char * filename)1052 static int normalize_longname(char *l_filename, const char *filename)
1053 {
1054 	const char *p, illegal[] = "<>:\"/\\|?*";
1055 
1056 	if (strlen(filename) >= VFAT_MAXLEN_BYTES)
1057 		return -1;
1058 
1059 	for (p = filename; *p; ++p) {
1060 		if ((unsigned char)*p < 0x20)
1061 			return -1;
1062 		if (strchr(illegal, *p))
1063 			return -1;
1064 	}
1065 
1066 	strcpy(l_filename, filename);
1067 	downcase(l_filename, VFAT_MAXLEN_BYTES);
1068 
1069 	return 0;
1070 }
1071 
file_fat_write_at(const char * filename,loff_t pos,void * buffer,loff_t size,loff_t * actwrite)1072 int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
1073 		      loff_t size, loff_t *actwrite)
1074 {
1075 	dir_entry *retdent;
1076 	fsdata datablock = { .fatbuf = NULL, };
1077 	fsdata *mydata = &datablock;
1078 	fat_itr *itr = NULL;
1079 	int ret = -1;
1080 	char *filename_copy, *parent, *basename;
1081 	char l_filename[VFAT_MAXLEN_BYTES];
1082 
1083 	debug("writing %s\n", filename);
1084 
1085 	filename_copy = strdup(filename);
1086 	if (!filename_copy)
1087 		return -ENOMEM;
1088 
1089 	split_filename(filename_copy, &parent, &basename);
1090 	if (!strlen(basename)) {
1091 		ret = -EINVAL;
1092 		goto exit;
1093 	}
1094 
1095 	filename = basename;
1096 	if (normalize_longname(l_filename, filename)) {
1097 		printf("FAT: illegal filename (%s)\n", filename);
1098 		ret = -EINVAL;
1099 		goto exit;
1100 	}
1101 
1102 	itr = malloc_cache_aligned(sizeof(fat_itr));
1103 	if (!itr) {
1104 		ret = -ENOMEM;
1105 		goto exit;
1106 	}
1107 
1108 	ret = fat_itr_root(itr, &datablock);
1109 	if (ret)
1110 		goto exit;
1111 
1112 	total_sector = datablock.total_sect;
1113 
1114 	ret = fat_itr_resolve(itr, parent, TYPE_DIR);
1115 	if (ret) {
1116 		printf("%s: doesn't exist (%d)\n", parent, ret);
1117 		goto exit;
1118 	}
1119 
1120 	retdent = find_directory_entry(itr, l_filename);
1121 
1122 	if (retdent) {
1123 		if (fat_itr_isdir(itr)) {
1124 			ret = -EISDIR;
1125 			goto exit;
1126 		}
1127 
1128 		/* A file exists */
1129 		if (pos == -1)
1130 			/* Append to the end */
1131 			pos = FAT2CPU32(retdent->size);
1132 		if (pos > retdent->size) {
1133 			/* No hole allowed */
1134 			ret = -EINVAL;
1135 			goto exit;
1136 		}
1137 
1138 		/* Update file size in a directory entry */
1139 		retdent->size = cpu_to_le32(pos + size);
1140 	} else {
1141 		/* Create a new file */
1142 
1143 		if (itr->is_root) {
1144 			/* root dir cannot have "." or ".." */
1145 			if (!strcmp(l_filename, ".") ||
1146 			    !strcmp(l_filename, "..")) {
1147 				ret = -EINVAL;
1148 				goto exit;
1149 			}
1150 		}
1151 
1152 		if (!itr->dent) {
1153 			printf("Error: allocating new dir entry\n");
1154 			ret = -EIO;
1155 			goto exit;
1156 		}
1157 
1158 		if (pos) {
1159 			/* No hole allowed */
1160 			ret = -EINVAL;
1161 			goto exit;
1162 		}
1163 
1164 		memset(itr->dent, 0, sizeof(*itr->dent));
1165 
1166 		/* Calculate checksum for short name */
1167 		set_name(itr->dent, filename);
1168 
1169 		/* Set long name entries */
1170 		if (fill_dir_slot(itr, filename)) {
1171 			ret = -EIO;
1172 			goto exit;
1173 		}
1174 
1175 		/* Set short name entry */
1176 		fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20);
1177 
1178 		retdent = itr->dent;
1179 	}
1180 
1181 	ret = set_contents(mydata, retdent, pos, buffer, size, actwrite);
1182 	if (ret < 0) {
1183 		printf("Error: writing contents\n");
1184 		ret = -EIO;
1185 		goto exit;
1186 	}
1187 	debug("attempt to write 0x%llx bytes\n", *actwrite);
1188 
1189 	/* Flush fat buffer */
1190 	ret = flush_dirty_fat_buffer(mydata);
1191 	if (ret) {
1192 		printf("Error: flush fat buffer\n");
1193 		ret = -EIO;
1194 		goto exit;
1195 	}
1196 
1197 	/* Write directory table to device */
1198 	ret = flush_dir(itr);
1199 	if (ret) {
1200 		printf("Error: writing directory entry\n");
1201 		ret = -EIO;
1202 	}
1203 
1204 exit:
1205 	free(filename_copy);
1206 	free(mydata->fatbuf);
1207 	free(itr);
1208 	return ret;
1209 }
1210 
file_fat_write(const char * filename,void * buffer,loff_t offset,loff_t maxsize,loff_t * actwrite)1211 int file_fat_write(const char *filename, void *buffer, loff_t offset,
1212 		   loff_t maxsize, loff_t *actwrite)
1213 {
1214 	return file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
1215 }
1216 
fat_dir_entries(fat_itr * itr)1217 static int fat_dir_entries(fat_itr *itr)
1218 {
1219 	fat_itr *dirs;
1220 	fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
1221 						/* for FATBUFSIZE */
1222 	int count;
1223 
1224 	dirs = malloc_cache_aligned(sizeof(fat_itr));
1225 	if (!dirs) {
1226 		debug("Error: allocating memory\n");
1227 		count = -ENOMEM;
1228 		goto exit;
1229 	}
1230 
1231 	/* duplicate fsdata */
1232 	fat_itr_child(dirs, itr);
1233 	fsdata = *dirs->fsdata;
1234 
1235 	/* allocate local fat buffer */
1236 	fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
1237 	if (!fsdata.fatbuf) {
1238 		debug("Error: allocating memory\n");
1239 		count = -ENOMEM;
1240 		goto exit;
1241 	}
1242 	fsdata.fatbufnum = -1;
1243 	dirs->fsdata = &fsdata;
1244 
1245 	for (count = 0; fat_itr_next(dirs); count++)
1246 		;
1247 
1248 exit:
1249 	free(fsdata.fatbuf);
1250 	free(dirs);
1251 	return count;
1252 }
1253 
delete_dentry(fat_itr * itr)1254 static int delete_dentry(fat_itr *itr)
1255 {
1256 	fsdata *mydata = itr->fsdata;
1257 	dir_entry *dentptr = itr->dent;
1258 
1259 	/* free cluster blocks */
1260 	clear_fatent(mydata, START(dentptr));
1261 	if (flush_dirty_fat_buffer(mydata) < 0) {
1262 		printf("Error: flush fat buffer\n");
1263 		return -EIO;
1264 	}
1265 
1266 	/*
1267 	 * update a directory entry
1268 	 * TODO:
1269 	 *  - long file name support
1270 	 *  - find and mark the "new" first invalid entry as name[0]=0x00
1271 	 */
1272 	memset(dentptr, 0, sizeof(*dentptr));
1273 	dentptr->name[0] = 0xe5;
1274 
1275 	if (flush_dir(itr)) {
1276 		printf("error: writing directory entry\n");
1277 		return -EIO;
1278 	}
1279 
1280 	return 0;
1281 }
1282 
fat_unlink(const char * filename)1283 int fat_unlink(const char *filename)
1284 {
1285 	fsdata fsdata = { .fatbuf = NULL, };
1286 	fat_itr *itr = NULL;
1287 	int n_entries, ret;
1288 	char *filename_copy, *dirname, *basename;
1289 
1290 	filename_copy = strdup(filename);
1291 	if (!filename_copy) {
1292 		printf("Error: allocating memory\n");
1293 		ret = -ENOMEM;
1294 		goto exit;
1295 	}
1296 	split_filename(filename_copy, &dirname, &basename);
1297 
1298 	if (!strcmp(dirname, "/") && !strcmp(basename, "")) {
1299 		printf("Error: cannot remove root\n");
1300 		ret = -EINVAL;
1301 		goto exit;
1302 	}
1303 
1304 	itr = malloc_cache_aligned(sizeof(fat_itr));
1305 	if (!itr) {
1306 		printf("Error: allocating memory\n");
1307 		ret = -ENOMEM;
1308 		goto exit;
1309 	}
1310 
1311 	ret = fat_itr_root(itr, &fsdata);
1312 	if (ret)
1313 		goto exit;
1314 
1315 	total_sector = fsdata.total_sect;
1316 
1317 	ret = fat_itr_resolve(itr, dirname, TYPE_DIR);
1318 	if (ret) {
1319 		printf("%s: doesn't exist (%d)\n", dirname, ret);
1320 		ret = -ENOENT;
1321 		goto exit;
1322 	}
1323 
1324 	if (!find_directory_entry(itr, basename)) {
1325 		printf("%s: doesn't exist\n", basename);
1326 		ret = -ENOENT;
1327 		goto exit;
1328 	}
1329 
1330 	if (fat_itr_isdir(itr)) {
1331 		n_entries = fat_dir_entries(itr);
1332 		if (n_entries < 0) {
1333 			ret = n_entries;
1334 			goto exit;
1335 		}
1336 		if (n_entries > 2) {
1337 			printf("Error: directory is not empty: %d\n",
1338 			       n_entries);
1339 			ret = -EINVAL;
1340 			goto exit;
1341 		}
1342 	}
1343 
1344 	ret = delete_dentry(itr);
1345 
1346 exit:
1347 	free(fsdata.fatbuf);
1348 	free(itr);
1349 	free(filename_copy);
1350 
1351 	return ret;
1352 }
1353 
fat_mkdir(const char * new_dirname)1354 int fat_mkdir(const char *new_dirname)
1355 {
1356 	dir_entry *retdent;
1357 	fsdata datablock = { .fatbuf = NULL, };
1358 	fsdata *mydata = &datablock;
1359 	fat_itr *itr = NULL;
1360 	char *dirname_copy, *parent, *dirname;
1361 	char l_dirname[VFAT_MAXLEN_BYTES];
1362 	int ret = -1;
1363 	loff_t actwrite;
1364 	unsigned int bytesperclust;
1365 	dir_entry *dotdent = NULL;
1366 
1367 	dirname_copy = strdup(new_dirname);
1368 	if (!dirname_copy)
1369 		goto exit;
1370 
1371 	split_filename(dirname_copy, &parent, &dirname);
1372 	if (!strlen(dirname)) {
1373 		ret = -EINVAL;
1374 		goto exit;
1375 	}
1376 
1377 	if (normalize_longname(l_dirname, dirname)) {
1378 		printf("FAT: illegal filename (%s)\n", dirname);
1379 		ret = -EINVAL;
1380 		goto exit;
1381 	}
1382 
1383 	itr = malloc_cache_aligned(sizeof(fat_itr));
1384 	if (!itr) {
1385 		ret = -ENOMEM;
1386 		goto exit;
1387 	}
1388 
1389 	ret = fat_itr_root(itr, &datablock);
1390 	if (ret)
1391 		goto exit;
1392 
1393 	total_sector = datablock.total_sect;
1394 
1395 	ret = fat_itr_resolve(itr, parent, TYPE_DIR);
1396 	if (ret) {
1397 		printf("%s: doesn't exist (%d)\n", parent, ret);
1398 		goto exit;
1399 	}
1400 
1401 	retdent = find_directory_entry(itr, l_dirname);
1402 
1403 	if (retdent) {
1404 		printf("%s: already exists\n", l_dirname);
1405 		ret = -EEXIST;
1406 		goto exit;
1407 	} else {
1408 		if (itr->is_root) {
1409 			/* root dir cannot have "." or ".." */
1410 			if (!strcmp(l_dirname, ".") ||
1411 			    !strcmp(l_dirname, "..")) {
1412 				ret = -EINVAL;
1413 				goto exit;
1414 			}
1415 		}
1416 
1417 		if (!itr->dent) {
1418 			printf("Error: allocating new dir entry\n");
1419 			ret = -EIO;
1420 			goto exit;
1421 		}
1422 
1423 		memset(itr->dent, 0, sizeof(*itr->dent));
1424 
1425 		/* Set short name to set alias checksum field in dir_slot */
1426 		set_name(itr->dent, dirname);
1427 		fill_dir_slot(itr, dirname);
1428 
1429 		/* Set attribute as archive for regular file */
1430 		fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0,
1431 			    ATTR_DIR | ATTR_ARCH);
1432 
1433 		retdent = itr->dent;
1434 	}
1435 
1436 	/* Default entries */
1437 	bytesperclust = mydata->clust_size * mydata->sect_size;
1438 	dotdent = malloc_cache_aligned(bytesperclust);
1439 	if (!dotdent) {
1440 		ret = -ENOMEM;
1441 		goto exit;
1442 	}
1443 	memset(dotdent, 0, bytesperclust);
1444 
1445 	memcpy(dotdent[0].name, ".       ", 8);
1446 	memcpy(dotdent[0].ext, "   ", 3);
1447 	dotdent[0].attr = ATTR_DIR | ATTR_ARCH;
1448 
1449 	memcpy(dotdent[1].name, "..      ", 8);
1450 	memcpy(dotdent[1].ext, "   ", 3);
1451 	dotdent[1].attr = ATTR_DIR | ATTR_ARCH;
1452 	set_start_cluster(mydata, &dotdent[1], itr->start_clust);
1453 
1454 	ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
1455 			   bytesperclust, &actwrite);
1456 	if (ret < 0) {
1457 		printf("Error: writing contents\n");
1458 		goto exit;
1459 	}
1460 	/* Write twice for "." */
1461 	set_start_cluster(mydata, &dotdent[0], START(retdent));
1462 	ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
1463 			   bytesperclust, &actwrite);
1464 	if (ret < 0) {
1465 		printf("Error: writing contents\n");
1466 		goto exit;
1467 	}
1468 
1469 	/* Flush fat buffer */
1470 	ret = flush_dirty_fat_buffer(mydata);
1471 	if (ret) {
1472 		printf("Error: flush fat buffer\n");
1473 		goto exit;
1474 	}
1475 
1476 	/* Write directory table to device */
1477 	ret = flush_dir(itr);
1478 	if (ret)
1479 		printf("Error: writing directory entry\n");
1480 
1481 exit:
1482 	free(dirname_copy);
1483 	free(mydata->fatbuf);
1484 	free(itr);
1485 	free(dotdent);
1486 	return ret;
1487 }
1488