1 // SPDX-License-Identifier: GPL-2.0+
5 * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim
17 #include <asm/byteorder.h>
18 #include <asm/cache.h>
19 #include <linux/ctype.h>
20 #include <linux/math64.h>
23 static dir_entry *find_directory_entry(fat_itr *itr, char *filename);
24 static int new_dir_table(fat_itr *itr);
26 /* Characters that may only be used in long file names */
27 static const char LONG_ONLY_CHARS[] = "+,;=[]";
29 /* Combined size of the name and ext fields in the directory entry */
30 #define SHORT_NAME_SIZE 11
33 * str2fat() - convert string to valid FAT name characters
35 * Stop when reaching end of @src or a period.
37 * Replace characters that may only be used in long names by underscores.
38 * Convert lower case characters to upper case.
40 * To avoid assumptions about the code page we do not use characters
41 * above 0x7f for the short name.
43 * @dest: destination buffer
45 * @length: size of destination buffer
46 * Return: number of bytes in destination buffer
48 static int str2fat(char *dest, char *src, int length)
52 for (i = 0; i < length; ++src) {
59 if (strchr(LONG_ONLY_CHARS, c) || c > 0x7f)
61 else if (c >= 'a' && c <= 'z')
70 * fat_move_to_cluster() - position to first directory entry in cluster
72 * @itr: directory iterator
74 * Return: 0 for success, -EIO on error
76 static int fat_move_to_cluster(fat_itr *itr, unsigned int cluster)
80 /* position to the start of the directory */
81 itr->next_clust = cluster;
82 itr->last_cluster = 0;
83 if (!fat_next_cluster(itr, &nbytes))
85 itr->dent = (dir_entry *)itr->block;
86 itr->remaining = nbytes / sizeof(dir_entry) - 1;
91 * set_name() - set short name in directory entry
93 * The function determines if the @filename is a valid short name.
94 * In this case no long name is needed.
96 * If a long name is needed, a short name is constructed.
98 * @itr: directory iterator
99 * @filename: long file name
100 * @shortname: buffer of 11 bytes to receive chosen short name and extension
101 * Return: number of directory entries needed, negative on error
103 static int set_name(fat_itr *itr, const char *filename, char *shortname)
119 /* Initialize buffer */
120 memset(&dirent, ' ', sizeof(dirent));
122 /* Convert filename to upper case short name */
123 period = strrchr(filename, '.');
124 pos = (char *)filename;
130 str2fat(dirent.ext, period + 1, sizeof(dirent.ext));
131 period_location = str2fat(dirent.name, pos, sizeof(dirent.name));
132 if (period_location < 0)
133 return period_location;
134 if (*dirent.name == ' ')
136 /* 0xe5 signals a deleted directory entry. Replace it by 0x05. */
137 if (*dirent.name == 0xe5)
140 /* If filename and short name are the same, quit. */
141 sprintf(buf, "%.*s.%.3s", period_location, dirent.name, dirent.ext);
142 if (!strcmp(buf, filename)) {
147 /* Construct an indexed short name */
148 for (i = 1; i < 0x200000; ++i) {
153 /* To speed up the search use random numbers */
158 j = 10 + (rand() >> j);
160 sprintf(buf, "~%d", j);
161 suffix_len = strlen(buf);
162 suffix_start = 8 - suffix_len;
163 if (suffix_start > period_location)
164 suffix_start = period_location;
165 memcpy(dirent.name + suffix_start, buf, suffix_len);
166 if (*dirent.ext != ' ')
167 sprintf(buf, "%.*s.%.3s", suffix_start + suffix_len,
168 dirent.name, dirent.ext);
170 sprintf(buf, "%.*s", suffix_start + suffix_len,
172 debug("generated short name: %s\n", buf);
174 /* Check that the short name does not exist yet. */
175 ret = fat_move_to_cluster(itr, itr->start_clust);
178 if (find_directory_entry(itr, buf))
181 debug("chosen short name: %s\n", buf);
182 /* Each long name directory entry takes 13 characters. */
183 ret = (strlen(filename) + 25) / 13;
188 memcpy(shortname, dirent.name, SHORT_NAME_SIZE);
192 static int total_sector;
193 static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
200 if (cur_part_info.start + block + nr_blocks >
201 cur_part_info.start + total_sector) {
202 printf("error: overflow occurs\n");
206 ret = blk_dwrite(cur_dev, cur_part_info.start + block, nr_blocks, buf);
207 if (nr_blocks && ret == 0)
214 * Write fat buffer into block device
216 static int flush_dirty_fat_buffer(fsdata *mydata)
218 int getsize = FATBUFBLOCKS;
219 __u32 fatlength = mydata->fatlength;
220 __u8 *bufptr = mydata->fatbuf;
221 __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
223 debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum,
224 (int)mydata->fat_dirty);
226 if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1))
229 /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
230 if (startblock + getsize > fatlength)
231 getsize = fatlength - startblock;
233 startblock += mydata->fat_sect;
236 if (disk_write(startblock, getsize, bufptr) < 0) {
237 debug("error: writing FAT blocks\n");
241 if (mydata->fats == 2) {
242 /* Update corresponding second FAT blocks */
243 startblock += mydata->fatlength;
244 if (disk_write(startblock, getsize, bufptr) < 0) {
245 debug("error: writing second FAT blocks\n");
249 mydata->fat_dirty = 0;
255 * fat_find_empty_dentries() - find a sequence of available directory entries
257 * @itr: directory iterator
258 * @count: number of directory entries to find
259 * Return: 0 on success or negative error number
261 static int fat_find_empty_dentries(fat_itr *itr, int count)
263 unsigned int cluster;
269 ret = fat_move_to_cluster(itr, itr->start_clust);
275 log_debug("Not enough directory entries available\n");
278 switch (itr->dent->name[0]) {
282 /* Remember first deleted directory entry */
283 cluster = itr->clust;
285 remaining = itr->remaining;
298 (!itr->is_root || itr->fsdata->fatsize == 32) &&
303 /* Position back to first directory entry */
304 if (itr->clust != cluster) {
305 ret = fat_move_to_cluster(itr, cluster);
310 itr->remaining = remaining;
315 * Set the file name information from 'name' into 'slotptr',
317 static int str2slot(dir_slot *slotptr, const char *name, int *idx)
321 for (j = 0; j <= 8; j += 2) {
322 if (name[*idx] == 0x00) {
323 slotptr->name0_4[j] = 0;
324 slotptr->name0_4[j + 1] = 0;
328 slotptr->name0_4[j] = name[*idx];
332 for (j = 0; j <= 10; j += 2) {
333 if (name[*idx] == 0x00) {
334 slotptr->name5_10[j] = 0;
335 slotptr->name5_10[j + 1] = 0;
339 slotptr->name5_10[j] = name[*idx];
343 for (j = 0; j <= 2; j += 2) {
344 if (name[*idx] == 0x00) {
345 slotptr->name11_12[j] = 0;
346 slotptr->name11_12[j + 1] = 0;
350 slotptr->name11_12[j] = name[*idx];
355 if (name[*idx] == 0x00)
359 /* Not used characters are filled with 0xff 0xff */
361 for (; end_idx < 5; end_idx++) {
362 slotptr->name0_4[end_idx * 2] = 0xff;
363 slotptr->name0_4[end_idx * 2 + 1] = 0xff;
368 for (; end_idx < 6; end_idx++) {
369 slotptr->name5_10[end_idx * 2] = 0xff;
370 slotptr->name5_10[end_idx * 2 + 1] = 0xff;
375 for (; end_idx < 2; end_idx++) {
376 slotptr->name11_12[end_idx * 2] = 0xff;
377 slotptr->name11_12[end_idx * 2 + 1] = 0xff;
383 static int flush_dir(fat_itr *itr);
386 * fill_dir_slot() - fill directory entries for long name
388 * @itr: directory iterator
390 * @shortname: short name
391 * Return: 0 for success, -errno otherwise
394 fill_dir_slot(fat_itr *itr, const char *l_name, const char *shortname)
396 __u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)];
397 dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer;
398 __u8 counter = 0, checksum;
401 /* Get short file name checksum value */
402 checksum = mkcksum(shortname, shortname + 8);
405 memset(slotptr, 0x00, sizeof(dir_slot));
406 ret = str2slot(slotptr, l_name, &idx);
407 slotptr->id = ++counter;
408 slotptr->attr = ATTR_VFAT;
409 slotptr->alias_checksum = checksum;
414 slotptr->id |= LAST_LONG_ENTRY_MASK;
416 while (counter >= 1) {
417 memcpy(itr->dent, slotptr, sizeof(dir_slot));
421 if (itr->remaining == 0)
433 * Set the entry at index 'entry' in a FAT (12/16/32) table.
435 static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
437 __u32 bufnum, offset, off16;
440 switch (mydata->fatsize) {
442 bufnum = entry / FAT32BUFSIZE;
443 offset = entry - bufnum * FAT32BUFSIZE;
446 bufnum = entry / FAT16BUFSIZE;
447 offset = entry - bufnum * FAT16BUFSIZE;
450 bufnum = entry / FAT12BUFSIZE;
451 offset = entry - bufnum * FAT12BUFSIZE;
454 /* Unsupported FAT size */
458 /* Read a new block of FAT entries into the cache. */
459 if (bufnum != mydata->fatbufnum) {
460 int getsize = FATBUFBLOCKS;
461 __u8 *bufptr = mydata->fatbuf;
462 __u32 fatlength = mydata->fatlength;
463 __u32 startblock = bufnum * FATBUFBLOCKS;
465 /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
466 if (startblock + getsize > fatlength)
467 getsize = fatlength - startblock;
469 if (flush_dirty_fat_buffer(mydata) < 0)
472 startblock += mydata->fat_sect;
474 if (disk_read(startblock, getsize, bufptr) < 0) {
475 debug("Error reading FAT blocks\n");
478 mydata->fatbufnum = bufnum;
482 mydata->fat_dirty = 1;
484 /* Set the actual entry */
485 switch (mydata->fatsize) {
487 ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
490 ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
493 off16 = (offset * 3) / 4;
495 switch (offset & 0x3) {
497 val1 = cpu_to_le16(entry_value) & 0xfff;
498 ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff;
499 ((__u16 *)mydata->fatbuf)[off16] |= val1;
502 val1 = cpu_to_le16(entry_value) & 0xf;
503 val2 = (cpu_to_le16(entry_value) >> 4) & 0xff;
505 ((__u16 *)mydata->fatbuf)[off16] &= ~0xf000;
506 ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 12);
508 ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xff;
509 ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
512 val1 = cpu_to_le16(entry_value) & 0xff;
513 val2 = (cpu_to_le16(entry_value) >> 8) & 0xf;
515 ((__u16 *)mydata->fatbuf)[off16] &= ~0xff00;
516 ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 8);
518 ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xf;
519 ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
522 val1 = cpu_to_le16(entry_value) & 0xfff;
523 ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff0;
524 ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 4);
539 * Determine the next free cluster after 'entry' in a FAT (12/16/32) table
540 * and link it to 'entry'. EOC marker is not set on returned entry.
542 static __u32 determine_fatent(fsdata *mydata, __u32 entry)
544 __u32 next_fat, next_entry = entry + 1;
547 next_fat = get_fatent(mydata, next_entry);
549 /* found free entry, link to entry */
550 set_fatent_value(mydata, entry, next_entry);
555 debug("FAT%d: entry: %08x, entry_value: %04x\n",
556 mydata->fatsize, entry, next_entry);
562 * set_sectors() - write data to sectors
564 * Write 'size' bytes from 'buffer' into the specified sector.
566 * @mydata: data to be written
567 * @startsect: sector to be written to
568 * @buffer: data to be written
569 * @size: bytes to be written (but not more than the size of a cluster)
570 * Return: 0 on success, -1 otherwise
573 set_sectors(fsdata *mydata, u32 startsect, u8 *buffer, u32 size)
578 debug("startsect: %d\n", startsect);
580 if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
581 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
583 debug("FAT: Misaligned buffer address (%p)\n", buffer);
585 while (size >= mydata->sect_size) {
586 memcpy(tmpbuf, buffer, mydata->sect_size);
587 ret = disk_write(startsect++, 1, tmpbuf);
589 debug("Error writing data (got %d)\n", ret);
593 buffer += mydata->sect_size;
594 size -= mydata->sect_size;
596 } else if (size >= mydata->sect_size) {
597 nsects = size / mydata->sect_size;
598 ret = disk_write(startsect, nsects, buffer);
600 debug("Error writing data (got %d)\n", ret);
605 buffer += nsects * mydata->sect_size;
606 size -= nsects * mydata->sect_size;
610 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
611 /* Do not leak content of stack */
612 memset(tmpbuf, 0, mydata->sect_size);
613 memcpy(tmpbuf, buffer, size);
614 ret = disk_write(startsect, 1, tmpbuf);
616 debug("Error writing data (got %d)\n", ret);
625 * set_cluster() - write data to cluster
627 * Write 'size' bytes from 'buffer' into the specified cluster.
629 * @mydata: data to be written
630 * @clustnum: cluster to be written to
631 * @buffer: data to be written
632 * @size: bytes to be written (but not more than the size of a cluster)
633 * Return: 0 on success, -1 otherwise
636 set_cluster(fsdata *mydata, u32 clustnum, u8 *buffer, u32 size)
638 return set_sectors(mydata, clust_to_sect(mydata, clustnum),
643 flush_dir(fat_itr *itr)
645 fsdata *mydata = itr->fsdata;
646 u32 startsect, sect_offset, nsects;
648 if (!itr->is_root || mydata->fatsize == 32)
649 return set_cluster(mydata, itr->clust, itr->block,
650 mydata->clust_size * mydata->sect_size);
652 sect_offset = itr->clust * mydata->clust_size;
653 startsect = mydata->rootdir_sect + sect_offset;
654 /* do not write past the end of rootdir */
655 nsects = min_t(u32, mydata->clust_size,
656 mydata->rootdir_size - sect_offset);
658 return set_sectors(mydata, startsect, itr->block,
659 nsects * mydata->sect_size);
663 * Read and modify data on existing and consecutive cluster blocks
666 get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
667 loff_t size, loff_t *gotsize)
669 static u8 *tmpbuf_cluster;
670 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
673 int clustcount, i, ret;
679 if (!tmpbuf_cluster) {
680 tmpbuf_cluster = memalign(ARCH_DMA_MINALIGN, MAX_CLUSTSIZE);
685 assert(pos < bytesperclust);
686 startsect = clust_to_sect(mydata, clustnum);
688 debug("clustnum: %d, startsect: %d, pos: %lld\n",
689 clustnum, startsect, pos);
691 /* partial write at beginning */
693 wsize = min(bytesperclust - pos, size);
694 ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
695 if (ret != mydata->clust_size) {
696 debug("Error reading data (got %d)\n", ret);
700 memcpy(tmpbuf_cluster + pos, buffer, wsize);
701 ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
702 if (ret != mydata->clust_size) {
703 debug("Error writing data (got %d)\n", ret);
711 startsect += mydata->clust_size;
717 /* full-cluster write */
718 if (size >= bytesperclust) {
719 clustcount = lldiv(size, bytesperclust);
721 if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
722 wsize = clustcount * bytesperclust;
723 ret = disk_write(startsect,
724 clustcount * mydata->clust_size,
726 if (ret != clustcount * mydata->clust_size) {
727 debug("Error writing data (got %d)\n", ret);
735 startsect += clustcount * mydata->clust_size;
737 for (i = 0; i < clustcount; i++) {
738 memcpy(tmpbuf_cluster, buffer, bytesperclust);
739 ret = disk_write(startsect,
742 if (ret != mydata->clust_size) {
743 debug("Error writing data (got %d)\n",
748 size -= bytesperclust;
749 buffer += bytesperclust;
750 *gotsize += bytesperclust;
752 startsect += mydata->clust_size;
757 /* partial write at end */
760 ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
761 if (ret != mydata->clust_size) {
762 debug("Error reading data (got %d)\n", ret);
765 memcpy(tmpbuf_cluster, buffer, wsize);
766 ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
767 if (ret != mydata->clust_size) {
768 debug("Error writing data (got %d)\n", ret);
783 * Find the first empty cluster
785 static int find_empty_cluster(fsdata *mydata)
787 __u32 fat_val, entry = 3;
790 fat_val = get_fatent(mydata, entry);
800 * new_dir_table() - allocate a cluster for additional directory entries
802 * @itr: directory iterator
803 * Return: 0 on success, -EIO otherwise
805 static int new_dir_table(fat_itr *itr)
807 fsdata *mydata = itr->fsdata;
808 int dir_newclust = 0;
809 int dir_oldclust = itr->clust;
810 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
812 dir_newclust = find_empty_cluster(mydata);
815 * Flush before updating FAT to ensure valid directory structure
816 * in case of failure.
818 itr->clust = dir_newclust;
819 itr->next_clust = dir_newclust;
820 memset(itr->block, 0x00, bytesperclust);
824 set_fatent_value(mydata, dir_oldclust, dir_newclust);
825 if (mydata->fatsize == 32)
826 set_fatent_value(mydata, dir_newclust, 0xffffff8);
827 else if (mydata->fatsize == 16)
828 set_fatent_value(mydata, dir_newclust, 0xfff8);
829 else if (mydata->fatsize == 12)
830 set_fatent_value(mydata, dir_newclust, 0xff8);
832 if (flush_dirty_fat_buffer(mydata) < 0)
835 itr->dent = (dir_entry *)itr->block;
836 itr->last_cluster = 1;
837 itr->remaining = bytesperclust / sizeof(dir_entry) - 1;
843 * Set empty cluster from 'entry' to the end of a file
845 static int clear_fatent(fsdata *mydata, __u32 entry)
849 while (!CHECK_CLUST(entry, mydata->fatsize)) {
850 fat_val = get_fatent(mydata, entry);
852 set_fatent_value(mydata, entry, 0);
859 /* Flush fat buffer */
860 if (flush_dirty_fat_buffer(mydata) < 0)
867 * Set start cluster in directory entry
869 static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
872 if (mydata->fatsize == 32)
874 cpu_to_le16((start_cluster & 0xffff0000) >> 16);
875 dentptr->start = cpu_to_le16(start_cluster & 0xffff);
879 * Check whether adding a file makes the file system to
880 * exceed the size of the block device
881 * Return -1 when overflow occurs, otherwise return 0
883 static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
885 __u32 startsect, sect_num, offset;
888 startsect = clust_to_sect(mydata, clustnum);
890 startsect = mydata->rootdir_sect;
892 sect_num = div_u64_rem(size, mydata->sect_size, &offset);
897 if (startsect + sect_num > total_sector)
903 * Write at most 'maxsize' bytes from 'buffer' into
904 * the file associated with 'dentptr'
905 * Update the number of bytes written in *gotsize and return 0
906 * or return -1 on fatal errors.
909 set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
910 loff_t maxsize, loff_t *gotsize)
912 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
913 __u32 curclust = START(dentptr);
914 __u32 endclust = 0, newclust = 0;
915 u64 cur_pos, filesize;
916 loff_t offset, actsize, wsize;
919 filesize = pos + maxsize;
921 debug("%llu bytes\n", filesize);
926 if (!CHECK_CLUST(curclust, mydata->fatsize) ||
927 IS_LAST_CLUST(curclust, mydata->fatsize)) {
928 clear_fatent(mydata, curclust);
929 set_start_cluster(mydata, dentptr, 0);
932 debug("curclust: 0x%x\n", curclust);
933 debug("Invalid FAT entry\n");
942 /* go to cluster at pos */
943 cur_pos = bytesperclust;
947 if (IS_LAST_CLUST(curclust, mydata->fatsize))
950 newclust = get_fatent(mydata, curclust);
951 if (!IS_LAST_CLUST(newclust, mydata->fatsize) &&
952 CHECK_CLUST(newclust, mydata->fatsize)) {
953 debug("curclust: 0x%x\n", curclust);
954 debug("Invalid FAT entry\n");
958 cur_pos += bytesperclust;
961 if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
962 assert(pos == cur_pos);
966 assert(pos < cur_pos);
967 cur_pos -= bytesperclust;
970 assert(IS_LAST_CLUST(curclust, mydata->fatsize) ||
971 !CHECK_CLUST(curclust, mydata->fatsize));
974 /* search for allocated consecutive clusters */
975 actsize = bytesperclust;
978 if (filesize <= (cur_pos + actsize))
981 newclust = get_fatent(mydata, endclust);
983 if (newclust != endclust + 1)
985 if (IS_LAST_CLUST(newclust, mydata->fatsize))
987 if (CHECK_CLUST(newclust, mydata->fatsize)) {
988 debug("curclust: 0x%x\n", curclust);
989 debug("Invalid FAT entry\n");
993 actsize += bytesperclust;
997 /* overwrite to <curclust..endclust> */
1001 offset = pos - cur_pos;
1002 wsize = min_t(unsigned long long, actsize, filesize - cur_pos);
1005 if (get_set_cluster(mydata, curclust, offset,
1006 buffer, wsize, &actsize)) {
1007 printf("Error get-and-setting cluster\n");
1012 cur_pos += offset + wsize;
1014 if (filesize <= cur_pos)
1017 if (IS_LAST_CLUST(newclust, mydata->fatsize))
1018 /* no more clusters */
1021 curclust = newclust;
1024 if (filesize <= cur_pos) {
1026 newclust = get_fatent(mydata, endclust);
1027 if (!IS_LAST_CLUST(newclust, mydata->fatsize)) {
1028 /* truncate the rest */
1029 clear_fatent(mydata, newclust);
1031 /* Mark end of file in FAT */
1032 if (mydata->fatsize == 12)
1034 else if (mydata->fatsize == 16)
1036 else if (mydata->fatsize == 32)
1037 newclust = 0xfffffff;
1038 set_fatent_value(mydata, endclust, newclust);
1044 curclust = endclust;
1045 filesize -= cur_pos;
1046 assert(!do_div(cur_pos, bytesperclust));
1049 /* allocate and write */
1052 /* Assure that curclust is valid */
1054 curclust = find_empty_cluster(mydata);
1055 set_start_cluster(mydata, dentptr, curclust);
1057 newclust = get_fatent(mydata, curclust);
1059 if (IS_LAST_CLUST(newclust, mydata->fatsize)) {
1060 newclust = determine_fatent(mydata, curclust);
1061 set_fatent_value(mydata, curclust, newclust);
1062 curclust = newclust;
1064 debug("error: something wrong\n");
1069 /* TODO: already partially written */
1070 if (check_overflow(mydata, curclust, filesize)) {
1071 printf("Error: no space left: %llu\n", filesize);
1075 actsize = bytesperclust;
1076 endclust = curclust;
1078 /* search for consecutive clusters */
1079 while (actsize < filesize) {
1080 newclust = determine_fatent(mydata, endclust);
1082 if ((newclust - 1) != endclust)
1083 /* write to <curclust..endclust> */
1086 if (CHECK_CLUST(newclust, mydata->fatsize)) {
1087 debug("newclust: 0x%x\n", newclust);
1088 debug("Invalid FAT entry\n");
1091 endclust = newclust;
1092 actsize += bytesperclust;
1095 /* set remaining bytes */
1097 if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
1098 debug("error: writing cluster\n");
1101 *gotsize += actsize;
1103 /* Mark end of file in FAT */
1104 if (mydata->fatsize == 12)
1106 else if (mydata->fatsize == 16)
1108 else if (mydata->fatsize == 32)
1109 newclust = 0xfffffff;
1110 set_fatent_value(mydata, endclust, newclust);
1114 if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
1115 debug("error: writing cluster\n");
1118 *gotsize += actsize;
1119 filesize -= actsize;
1122 if (CHECK_CLUST(newclust, mydata->fatsize)) {
1123 debug("newclust: 0x%x\n", newclust);
1124 debug("Invalid FAT entry\n");
1127 actsize = bytesperclust;
1128 curclust = endclust = newclust;
1135 * fill_dentry() - fill directory entry with shortname
1137 * @mydata: private filesystem parameters
1138 * @dentptr: directory entry
1139 * @shortname: chosen short name
1140 * @start_cluster: first cluster of file
1142 * @attr: file attributes
1144 static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
1145 const char *shortname, __u32 start_cluster, __u32 size, __u8 attr)
1147 memset(dentptr, 0, sizeof(*dentptr));
1149 set_start_cluster(mydata, dentptr, start_cluster);
1150 dentptr->size = cpu_to_le32(size);
1152 dentptr->attr = attr;
1154 memcpy(dentptr->name, shortname, SHORT_NAME_SIZE);
1158 * Find a directory entry based on filename or start cluster number
1159 * If the directory entry is not found,
1160 * the new position for writing a directory entry will be returned
1162 static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
1166 while (fat_itr_next(itr)) {
1167 /* check both long and short name: */
1168 if (!strcasecmp(filename, itr->name))
1170 else if (itr->name != itr->s_name &&
1171 !strcasecmp(filename, itr->s_name))
1177 if (itr->dent->name[0] == '\0')
1183 /* allocate a cluster for more entries */
1185 (!itr->is_root || itr->fsdata->fatsize == 32) &&
1187 /* indicate that allocating dent failed */
1193 static int split_filename(char *filename, char **dirname, char **basename)
1195 char *p, *last_slash, *last_slash_cont;
1200 last_slash_cont = NULL;
1202 if (ISDIRDELIM(*p)) {
1204 last_slash_cont = p;
1205 /* continuous slashes */
1206 while (ISDIRDELIM(*p))
1207 last_slash_cont = p++;
1215 if (last_slash_cont == (filename + strlen(filename) - 1)) {
1216 /* remove trailing slashes */
1221 if (last_slash == filename) {
1222 /* avoid ""(null) directory */
1226 *dirname = filename;
1229 *last_slash_cont = '\0';
1230 *basename = last_slash_cont + 1;
1232 *dirname = "/"; /* root by default */
1233 *basename = filename;
1240 * normalize_longname() - check long file name and convert to lower case
1242 * We assume here that the FAT file system is using an 8bit code page.
1243 * Linux typically uses CP437, EDK2 assumes CP1250.
1245 * @l_filename: preallocated buffer receiving the normalized name
1246 * @filename: filename to normalize
1247 * Return: 0 on success, -1 on failure
1249 static int normalize_longname(char *l_filename, const char *filename)
1251 const char *p, illegal[] = "<>:\"/\\|?*";
1253 if (strlen(filename) >= VFAT_MAXLEN_BYTES)
1256 for (p = filename; *p; ++p) {
1257 if ((unsigned char)*p < 0x20)
1259 if (strchr(illegal, *p))
1263 strcpy(l_filename, filename);
1264 downcase(l_filename, VFAT_MAXLEN_BYTES);
1269 int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
1270 loff_t size, loff_t *actwrite)
1273 fsdata datablock = { .fatbuf = NULL, };
1274 fsdata *mydata = &datablock;
1275 fat_itr *itr = NULL;
1277 char *filename_copy, *parent, *basename;
1278 char l_filename[VFAT_MAXLEN_BYTES];
1280 debug("writing %s\n", filename);
1282 filename_copy = strdup(filename);
1286 split_filename(filename_copy, &parent, &basename);
1287 if (!strlen(basename)) {
1292 filename = basename;
1293 if (normalize_longname(l_filename, filename)) {
1294 printf("FAT: illegal filename (%s)\n", filename);
1299 itr = malloc_cache_aligned(sizeof(fat_itr));
1305 ret = fat_itr_root(itr, &datablock);
1309 total_sector = datablock.total_sect;
1311 ret = fat_itr_resolve(itr, parent, TYPE_DIR);
1313 printf("%s: doesn't exist (%d)\n", parent, ret);
1317 retdent = find_directory_entry(itr, l_filename);
1320 if (fat_itr_isdir(itr)) {
1327 /* Append to the end */
1328 pos = FAT2CPU32(retdent->size);
1329 if (pos > retdent->size) {
1330 /* No hole allowed */
1335 /* Update file size in a directory entry */
1336 retdent->size = cpu_to_le32(pos + size);
1338 /* Create a new file */
1339 char shortname[SHORT_NAME_SIZE];
1343 /* root dir cannot have "." or ".." */
1344 if (!strcmp(l_filename, ".") ||
1345 !strcmp(l_filename, "..")) {
1352 printf("Error: allocating new dir entry\n");
1358 /* No hole allowed */
1363 /* Check if long name is needed */
1364 ndent = set_name(itr, filename, shortname);
1369 ret = fat_find_empty_dentries(itr, ndent);
1373 /* Set long name entries */
1374 ret = fill_dir_slot(itr, filename, shortname);
1379 /* Set short name entry */
1380 fill_dentry(itr->fsdata, itr->dent, shortname, 0, size,
1383 retdent = itr->dent;
1386 ret = set_contents(mydata, retdent, pos, buffer, size, actwrite);
1388 printf("Error: writing contents\n");
1392 debug("attempt to write 0x%llx bytes\n", *actwrite);
1394 /* Flush fat buffer */
1395 ret = flush_dirty_fat_buffer(mydata);
1397 printf("Error: flush fat buffer\n");
1402 /* Write directory table to device */
1403 ret = flush_dir(itr);
1405 printf("Error: writing directory entry\n");
1410 free(filename_copy);
1411 free(mydata->fatbuf);
1416 int file_fat_write(const char *filename, void *buffer, loff_t offset,
1417 loff_t maxsize, loff_t *actwrite)
1419 return file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
1422 static int fat_dir_entries(fat_itr *itr)
1425 fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
1426 /* for FATBUFSIZE */
1429 dirs = malloc_cache_aligned(sizeof(fat_itr));
1431 debug("Error: allocating memory\n");
1436 /* duplicate fsdata */
1437 fat_itr_child(dirs, itr);
1438 fsdata = *dirs->fsdata;
1440 /* allocate local fat buffer */
1441 fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
1442 if (!fsdata.fatbuf) {
1443 debug("Error: allocating memory\n");
1447 fsdata.fatbufnum = -1;
1448 dirs->fsdata = &fsdata;
1450 for (count = 0; fat_itr_next(dirs); count++)
1454 free(fsdata.fatbuf);
1459 static int delete_dentry(fat_itr *itr)
1461 fsdata *mydata = itr->fsdata;
1462 dir_entry *dentptr = itr->dent;
1464 /* free cluster blocks */
1465 clear_fatent(mydata, START(dentptr));
1466 if (flush_dirty_fat_buffer(mydata) < 0) {
1467 printf("Error: flush fat buffer\n");
1472 * update a directory entry
1474 * - long file name support
1475 * - find and mark the "new" first invalid entry as name[0]=0x00
1477 memset(dentptr, 0, sizeof(*dentptr));
1478 dentptr->name[0] = 0xe5;
1480 if (flush_dir(itr)) {
1481 printf("error: writing directory entry\n");
1488 int fat_unlink(const char *filename)
1490 fsdata fsdata = { .fatbuf = NULL, };
1491 fat_itr *itr = NULL;
1493 char *filename_copy, *dirname, *basename;
1495 filename_copy = strdup(filename);
1496 if (!filename_copy) {
1497 printf("Error: allocating memory\n");
1501 split_filename(filename_copy, &dirname, &basename);
1503 if (!strcmp(dirname, "/") && !strcmp(basename, "")) {
1504 printf("Error: cannot remove root\n");
1509 itr = malloc_cache_aligned(sizeof(fat_itr));
1511 printf("Error: allocating memory\n");
1516 ret = fat_itr_root(itr, &fsdata);
1520 total_sector = fsdata.total_sect;
1522 ret = fat_itr_resolve(itr, dirname, TYPE_DIR);
1524 printf("%s: doesn't exist (%d)\n", dirname, ret);
1529 if (!find_directory_entry(itr, basename)) {
1530 printf("%s: doesn't exist\n", basename);
1535 if (fat_itr_isdir(itr)) {
1536 n_entries = fat_dir_entries(itr);
1537 if (n_entries < 0) {
1541 if (n_entries > 2) {
1542 printf("Error: directory is not empty: %d\n",
1549 ret = delete_dentry(itr);
1552 free(fsdata.fatbuf);
1554 free(filename_copy);
1559 int fat_mkdir(const char *new_dirname)
1562 fsdata datablock = { .fatbuf = NULL, };
1563 fsdata *mydata = &datablock;
1564 fat_itr *itr = NULL;
1565 char *dirname_copy, *parent, *dirname;
1566 char l_dirname[VFAT_MAXLEN_BYTES];
1569 unsigned int bytesperclust;
1570 dir_entry *dotdent = NULL;
1572 dirname_copy = strdup(new_dirname);
1576 split_filename(dirname_copy, &parent, &dirname);
1577 if (!strlen(dirname)) {
1582 if (normalize_longname(l_dirname, dirname)) {
1583 printf("FAT: illegal filename (%s)\n", dirname);
1588 itr = malloc_cache_aligned(sizeof(fat_itr));
1594 ret = fat_itr_root(itr, &datablock);
1598 total_sector = datablock.total_sect;
1600 ret = fat_itr_resolve(itr, parent, TYPE_DIR);
1602 printf("%s: doesn't exist (%d)\n", parent, ret);
1606 retdent = find_directory_entry(itr, l_dirname);
1609 printf("%s: already exists\n", l_dirname);
1613 char shortname[SHORT_NAME_SIZE];
1617 /* root dir cannot have "." or ".." */
1618 if (!strcmp(l_dirname, ".") ||
1619 !strcmp(l_dirname, "..")) {
1626 printf("Error: allocating new dir entry\n");
1631 /* Check if long name is needed */
1632 ndent = set_name(itr, dirname, shortname);
1637 ret = fat_find_empty_dentries(itr, ndent);
1641 /* Set long name entries */
1642 ret = fill_dir_slot(itr, dirname, shortname);
1647 /* Set attribute as archive for regular file */
1648 fill_dentry(itr->fsdata, itr->dent, shortname, 0, 0,
1649 ATTR_DIR | ATTR_ARCH);
1651 retdent = itr->dent;
1654 /* Default entries */
1655 bytesperclust = mydata->clust_size * mydata->sect_size;
1656 dotdent = malloc_cache_aligned(bytesperclust);
1661 memset(dotdent, 0, bytesperclust);
1663 memcpy(dotdent[0].name, ". ", 8);
1664 memcpy(dotdent[0].ext, " ", 3);
1665 dotdent[0].attr = ATTR_DIR | ATTR_ARCH;
1667 memcpy(dotdent[1].name, ".. ", 8);
1668 memcpy(dotdent[1].ext, " ", 3);
1669 dotdent[1].attr = ATTR_DIR | ATTR_ARCH;
1672 set_start_cluster(mydata, &dotdent[1], 0);
1674 set_start_cluster(mydata, &dotdent[1], itr->start_clust);
1676 ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
1677 bytesperclust, &actwrite);
1679 printf("Error: writing contents\n");
1682 /* Write twice for "." */
1683 set_start_cluster(mydata, &dotdent[0], START(retdent));
1684 ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
1685 bytesperclust, &actwrite);
1687 printf("Error: writing contents\n");
1691 /* Flush fat buffer */
1692 ret = flush_dirty_fat_buffer(mydata);
1694 printf("Error: flush fat buffer\n");
1698 /* Write directory table to device */
1699 ret = flush_dir(itr);
1701 printf("Error: writing directory entry\n");
1705 free(mydata->fatbuf);