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