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