ARM: dts: at91: sama5d2_icp: fix i2c eeprom compatible
[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 /*
504  * Read and modify data on existing and consecutive cluster blocks
505  */
506 static int
507 get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
508                 loff_t size, loff_t *gotsize)
509 {
510         static u8 *tmpbuf_cluster;
511         unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
512         __u32 startsect;
513         loff_t wsize;
514         int clustcount, i, ret;
515
516         *gotsize = 0;
517         if (!size)
518                 return 0;
519
520         if (!tmpbuf_cluster) {
521                 tmpbuf_cluster = memalign(ARCH_DMA_MINALIGN, MAX_CLUSTSIZE);
522                 if (!tmpbuf_cluster)
523                         return -1;
524         }
525
526         assert(pos < bytesperclust);
527         startsect = clust_to_sect(mydata, clustnum);
528
529         debug("clustnum: %d, startsect: %d, pos: %lld\n",
530               clustnum, startsect, pos);
531
532         /* partial write at beginning */
533         if (pos) {
534                 wsize = min(bytesperclust - pos, size);
535                 ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
536                 if (ret != mydata->clust_size) {
537                         debug("Error reading data (got %d)\n", ret);
538                         return -1;
539                 }
540
541                 memcpy(tmpbuf_cluster + pos, buffer, wsize);
542                 ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
543                 if (ret != mydata->clust_size) {
544                         debug("Error writing data (got %d)\n", ret);
545                         return -1;
546                 }
547
548                 size -= wsize;
549                 buffer += wsize;
550                 *gotsize += wsize;
551
552                 startsect += mydata->clust_size;
553
554                 if (!size)
555                         return 0;
556         }
557
558         /* full-cluster write */
559         if (size >= bytesperclust) {
560                 clustcount = lldiv(size, bytesperclust);
561
562                 if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
563                         wsize = clustcount * bytesperclust;
564                         ret = disk_write(startsect,
565                                          clustcount * mydata->clust_size,
566                                          buffer);
567                         if (ret != clustcount * mydata->clust_size) {
568                                 debug("Error writing data (got %d)\n", ret);
569                                 return -1;
570                         }
571
572                         size -= wsize;
573                         buffer += wsize;
574                         *gotsize += wsize;
575
576                         startsect += clustcount * mydata->clust_size;
577                 } else {
578                         for (i = 0; i < clustcount; i++) {
579                                 memcpy(tmpbuf_cluster, buffer, bytesperclust);
580                                 ret = disk_write(startsect,
581                                                  mydata->clust_size,
582                                                  tmpbuf_cluster);
583                                 if (ret != mydata->clust_size) {
584                                         debug("Error writing data (got %d)\n",
585                                               ret);
586                                         return -1;
587                                 }
588
589                                 size -= bytesperclust;
590                                 buffer += bytesperclust;
591                                 *gotsize += bytesperclust;
592
593                                 startsect += mydata->clust_size;
594                         }
595                 }
596         }
597
598         /* partial write at end */
599         if (size) {
600                 wsize = size;
601                 ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
602                 if (ret != mydata->clust_size) {
603                         debug("Error reading data (got %d)\n", ret);
604                         return -1;
605                 }
606                 memcpy(tmpbuf_cluster, buffer, wsize);
607                 ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
608                 if (ret != mydata->clust_size) {
609                         debug("Error writing data (got %d)\n", ret);
610                         return -1;
611                 }
612
613                 size -= wsize;
614                 buffer += wsize;
615                 *gotsize += wsize;
616         }
617
618         assert(!size);
619
620         return 0;
621 }
622
623 /*
624  * Find the first empty cluster
625  */
626 static int find_empty_cluster(fsdata *mydata)
627 {
628         __u32 fat_val, entry = 3;
629
630         while (1) {
631                 fat_val = get_fatent(mydata, entry);
632                 if (fat_val == 0)
633                         break;
634                 entry++;
635         }
636
637         return entry;
638 }
639
640 /*
641  * Allocate a cluster for additional directory entries
642  */
643 static int new_dir_table(fat_itr *itr)
644 {
645         fsdata *mydata = itr->fsdata;
646         int dir_newclust = 0;
647         unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
648
649         dir_newclust = find_empty_cluster(mydata);
650         set_fatent_value(mydata, itr->clust, dir_newclust);
651         if (mydata->fatsize == 32)
652                 set_fatent_value(mydata, dir_newclust, 0xffffff8);
653         else if (mydata->fatsize == 16)
654                 set_fatent_value(mydata, dir_newclust, 0xfff8);
655         else if (mydata->fatsize == 12)
656                 set_fatent_value(mydata, dir_newclust, 0xff8);
657
658         itr->clust = dir_newclust;
659         itr->next_clust = dir_newclust;
660
661         if (flush_dirty_fat_buffer(mydata) < 0)
662                 return -1;
663
664         memset(itr->block, 0x00, bytesperclust);
665
666         itr->dent = (dir_entry *)itr->block;
667         itr->last_cluster = 1;
668         itr->remaining = bytesperclust / sizeof(dir_entry) - 1;
669
670         return 0;
671 }
672
673 /*
674  * Set empty cluster from 'entry' to the end of a file
675  */
676 static int clear_fatent(fsdata *mydata, __u32 entry)
677 {
678         __u32 fat_val;
679
680         while (!CHECK_CLUST(entry, mydata->fatsize)) {
681                 fat_val = get_fatent(mydata, entry);
682                 if (fat_val != 0)
683                         set_fatent_value(mydata, entry, 0);
684                 else
685                         break;
686
687                 entry = fat_val;
688         }
689
690         /* Flush fat buffer */
691         if (flush_dirty_fat_buffer(mydata) < 0)
692                 return -1;
693
694         return 0;
695 }
696
697 /*
698  * Set start cluster in directory entry
699  */
700 static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
701                               __u32 start_cluster)
702 {
703         if (mydata->fatsize == 32)
704                 dentptr->starthi =
705                         cpu_to_le16((start_cluster & 0xffff0000) >> 16);
706         dentptr->start = cpu_to_le16(start_cluster & 0xffff);
707 }
708
709 /*
710  * Check whether adding a file makes the file system to
711  * exceed the size of the block device
712  * Return -1 when overflow occurs, otherwise return 0
713  */
714 static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
715 {
716         __u32 startsect, sect_num, offset;
717
718         if (clustnum > 0)
719                 startsect = clust_to_sect(mydata, clustnum);
720         else
721                 startsect = mydata->rootdir_sect;
722
723         sect_num = div_u64_rem(size, mydata->sect_size, &offset);
724
725         if (offset != 0)
726                 sect_num++;
727
728         if (startsect + sect_num > total_sector)
729                 return -1;
730         return 0;
731 }
732
733 /*
734  * Write at most 'maxsize' bytes from 'buffer' into
735  * the file associated with 'dentptr'
736  * Update the number of bytes written in *gotsize and return 0
737  * or return -1 on fatal errors.
738  */
739 static int
740 set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
741              loff_t maxsize, loff_t *gotsize)
742 {
743         unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
744         __u32 curclust = START(dentptr);
745         __u32 endclust = 0, newclust = 0;
746         u64 cur_pos, filesize;
747         loff_t offset, actsize, wsize;
748
749         *gotsize = 0;
750         filesize = pos + maxsize;
751
752         debug("%llu bytes\n", filesize);
753
754         if (!filesize) {
755                 if (!curclust)
756                         return 0;
757                 if (!CHECK_CLUST(curclust, mydata->fatsize) ||
758                     IS_LAST_CLUST(curclust, mydata->fatsize)) {
759                         clear_fatent(mydata, curclust);
760                         set_start_cluster(mydata, dentptr, 0);
761                         return 0;
762                 }
763                 debug("curclust: 0x%x\n", curclust);
764                 debug("Invalid FAT entry\n");
765                 return -1;
766         }
767
768         if (!curclust) {
769                 assert(pos == 0);
770                 goto set_clusters;
771         }
772
773         /* go to cluster at pos */
774         cur_pos = bytesperclust;
775         while (1) {
776                 if (pos <= cur_pos)
777                         break;
778                 if (IS_LAST_CLUST(curclust, mydata->fatsize))
779                         break;
780
781                 newclust = get_fatent(mydata, curclust);
782                 if (!IS_LAST_CLUST(newclust, mydata->fatsize) &&
783                     CHECK_CLUST(newclust, mydata->fatsize)) {
784                         debug("curclust: 0x%x\n", curclust);
785                         debug("Invalid FAT entry\n");
786                         return -1;
787                 }
788
789                 cur_pos += bytesperclust;
790                 curclust = newclust;
791         }
792         if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
793                 assert(pos == cur_pos);
794                 goto set_clusters;
795         }
796
797         assert(pos < cur_pos);
798         cur_pos -= bytesperclust;
799
800         /* overwrite */
801         assert(IS_LAST_CLUST(curclust, mydata->fatsize) ||
802                !CHECK_CLUST(curclust, mydata->fatsize));
803
804         while (1) {
805                 /* search for allocated consecutive clusters */
806                 actsize = bytesperclust;
807                 endclust = curclust;
808                 while (1) {
809                         if (filesize <= (cur_pos + actsize))
810                                 break;
811
812                         newclust = get_fatent(mydata, endclust);
813
814                         if (newclust != endclust + 1)
815                                 break;
816                         if (IS_LAST_CLUST(newclust, mydata->fatsize))
817                                 break;
818                         if (CHECK_CLUST(newclust, mydata->fatsize)) {
819                                 debug("curclust: 0x%x\n", curclust);
820                                 debug("Invalid FAT entry\n");
821                                 return -1;
822                         }
823
824                         actsize += bytesperclust;
825                         endclust = newclust;
826                 }
827
828                 /* overwrite to <curclust..endclust> */
829                 if (pos < cur_pos)
830                         offset = 0;
831                 else
832                         offset = pos - cur_pos;
833                 wsize = min_t(unsigned long long, actsize, filesize - cur_pos);
834                 wsize -= offset;
835
836                 if (get_set_cluster(mydata, curclust, offset,
837                                     buffer, wsize, &actsize)) {
838                         printf("Error get-and-setting cluster\n");
839                         return -1;
840                 }
841                 buffer += wsize;
842                 *gotsize += wsize;
843                 cur_pos += offset + wsize;
844
845                 if (filesize <= cur_pos)
846                         break;
847
848                 if (IS_LAST_CLUST(newclust, mydata->fatsize))
849                         /* no more clusters */
850                         break;
851
852                 curclust = newclust;
853         }
854
855         if (filesize <= cur_pos) {
856                 /* no more write */
857                 newclust = get_fatent(mydata, endclust);
858                 if (!IS_LAST_CLUST(newclust, mydata->fatsize)) {
859                         /* truncate the rest */
860                         clear_fatent(mydata, newclust);
861
862                         /* Mark end of file in FAT */
863                         if (mydata->fatsize == 12)
864                                 newclust = 0xfff;
865                         else if (mydata->fatsize == 16)
866                                 newclust = 0xffff;
867                         else if (mydata->fatsize == 32)
868                                 newclust = 0xfffffff;
869                         set_fatent_value(mydata, endclust, newclust);
870                 }
871
872                 return 0;
873         }
874
875         curclust = endclust;
876         filesize -= cur_pos;
877         assert(!do_div(cur_pos, bytesperclust));
878
879 set_clusters:
880         /* allocate and write */
881         assert(!pos);
882
883         /* Assure that curclust is valid */
884         if (!curclust) {
885                 curclust = find_empty_cluster(mydata);
886                 set_start_cluster(mydata, dentptr, curclust);
887         } else {
888                 newclust = get_fatent(mydata, curclust);
889
890                 if (IS_LAST_CLUST(newclust, mydata->fatsize)) {
891                         newclust = determine_fatent(mydata, curclust);
892                         set_fatent_value(mydata, curclust, newclust);
893                         curclust = newclust;
894                 } else {
895                         debug("error: something wrong\n");
896                         return -1;
897                 }
898         }
899
900         /* TODO: already partially written */
901         if (check_overflow(mydata, curclust, filesize)) {
902                 printf("Error: no space left: %llu\n", filesize);
903                 return -1;
904         }
905
906         actsize = bytesperclust;
907         endclust = curclust;
908         do {
909                 /* search for consecutive clusters */
910                 while (actsize < filesize) {
911                         newclust = determine_fatent(mydata, endclust);
912
913                         if ((newclust - 1) != endclust)
914                                 /* write to <curclust..endclust> */
915                                 goto getit;
916
917                         if (CHECK_CLUST(newclust, mydata->fatsize)) {
918                                 debug("newclust: 0x%x\n", newclust);
919                                 debug("Invalid FAT entry\n");
920                                 return 0;
921                         }
922                         endclust = newclust;
923                         actsize += bytesperclust;
924                 }
925
926                 /* set remaining bytes */
927                 actsize = filesize;
928                 if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
929                         debug("error: writing cluster\n");
930                         return -1;
931                 }
932                 *gotsize += actsize;
933
934                 /* Mark end of file in FAT */
935                 if (mydata->fatsize == 12)
936                         newclust = 0xfff;
937                 else if (mydata->fatsize == 16)
938                         newclust = 0xffff;
939                 else if (mydata->fatsize == 32)
940                         newclust = 0xfffffff;
941                 set_fatent_value(mydata, endclust, newclust);
942
943                 return 0;
944 getit:
945                 if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
946                         debug("error: writing cluster\n");
947                         return -1;
948                 }
949                 *gotsize += actsize;
950                 filesize -= actsize;
951                 buffer += actsize;
952
953                 if (CHECK_CLUST(newclust, mydata->fatsize)) {
954                         debug("newclust: 0x%x\n", newclust);
955                         debug("Invalid FAT entry\n");
956                         return 0;
957                 }
958                 actsize = bytesperclust;
959                 curclust = endclust = newclust;
960         } while (1);
961
962         return 0;
963 }
964
965 /*
966  * Fill dir_entry
967  */
968 static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
969         const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
970 {
971         set_start_cluster(mydata, dentptr, start_cluster);
972         dentptr->size = cpu_to_le32(size);
973
974         dentptr->attr = attr;
975
976         set_name(dentptr, filename);
977 }
978
979 /*
980  * Find a directory entry based on filename or start cluster number
981  * If the directory entry is not found,
982  * the new position for writing a directory entry will be returned
983  */
984 static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
985 {
986         int match = 0;
987
988         while (fat_itr_next(itr)) {
989                 /* check both long and short name: */
990                 if (!strcasecmp(filename, itr->name))
991                         match = 1;
992                 else if (itr->name != itr->s_name &&
993                          !strcasecmp(filename, itr->s_name))
994                         match = 1;
995
996                 if (!match)
997                         continue;
998
999                 if (itr->dent->name[0] == '\0')
1000                         return NULL;
1001                 else
1002                         return itr->dent;
1003         }
1004
1005         /* allocate a cluster for more entries */
1006         if (!itr->dent &&
1007             (!itr->is_root || itr->fsdata->fatsize == 32) &&
1008             new_dir_table(itr))
1009                 /* indicate that allocating dent failed */
1010                 itr->dent = NULL;
1011
1012         return NULL;
1013 }
1014
1015 static int split_filename(char *filename, char **dirname, char **basename)
1016 {
1017         char *p, *last_slash, *last_slash_cont;
1018
1019 again:
1020         p = filename;
1021         last_slash = NULL;
1022         last_slash_cont = NULL;
1023         while (*p) {
1024                 if (ISDIRDELIM(*p)) {
1025                         last_slash = p;
1026                         last_slash_cont = p;
1027                         /* continuous slashes */
1028                         while (ISDIRDELIM(*p))
1029                                 last_slash_cont = p++;
1030                         if (!*p)
1031                                 break;
1032                 }
1033                 p++;
1034         }
1035
1036         if (last_slash) {
1037                 if (last_slash_cont == (filename + strlen(filename) - 1)) {
1038                         /* remove trailing slashes */
1039                         *last_slash = '\0';
1040                         goto again;
1041                 }
1042
1043                 if (last_slash == filename) {
1044                         /* avoid ""(null) directory */
1045                         *dirname = "/";
1046                 } else {
1047                         *last_slash = '\0';
1048                         *dirname = filename;
1049                 }
1050
1051                 *last_slash_cont = '\0';
1052                 *basename = last_slash_cont + 1;
1053         } else {
1054                 *dirname = "/"; /* root by default */
1055                 *basename = filename;
1056         }
1057
1058         return 0;
1059 }
1060
1061 /**
1062  * normalize_longname() - check long file name and convert to lower case
1063  *
1064  * We assume here that the FAT file system is using an 8bit code page.
1065  * Linux typically uses CP437, EDK2 assumes CP1250.
1066  *
1067  * @l_filename: preallocated buffer receiving the normalized name
1068  * @filename:   filename to normalize
1069  * Return:      0 on success, -1 on failure
1070  */
1071 static int normalize_longname(char *l_filename, const char *filename)
1072 {
1073         const char *p, illegal[] = "<>:\"/\\|?*";
1074
1075         if (strlen(filename) >= VFAT_MAXLEN_BYTES)
1076                 return -1;
1077
1078         for (p = filename; *p; ++p) {
1079                 if ((unsigned char)*p < 0x20)
1080                         return -1;
1081                 if (strchr(illegal, *p))
1082                         return -1;
1083         }
1084
1085         strcpy(l_filename, filename);
1086         downcase(l_filename, VFAT_MAXLEN_BYTES);
1087
1088         return 0;
1089 }
1090
1091 int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
1092                       loff_t size, loff_t *actwrite)
1093 {
1094         dir_entry *retdent;
1095         fsdata datablock = { .fatbuf = NULL, };
1096         fsdata *mydata = &datablock;
1097         fat_itr *itr = NULL;
1098         int ret = -1;
1099         char *filename_copy, *parent, *basename;
1100         char l_filename[VFAT_MAXLEN_BYTES];
1101
1102         debug("writing %s\n", filename);
1103
1104         filename_copy = strdup(filename);
1105         if (!filename_copy)
1106                 return -ENOMEM;
1107
1108         split_filename(filename_copy, &parent, &basename);
1109         if (!strlen(basename)) {
1110                 ret = -EINVAL;
1111                 goto exit;
1112         }
1113
1114         filename = basename;
1115         if (normalize_longname(l_filename, filename)) {
1116                 printf("FAT: illegal filename (%s)\n", filename);
1117                 ret = -EINVAL;
1118                 goto exit;
1119         }
1120
1121         itr = malloc_cache_aligned(sizeof(fat_itr));
1122         if (!itr) {
1123                 ret = -ENOMEM;
1124                 goto exit;
1125         }
1126
1127         ret = fat_itr_root(itr, &datablock);
1128         if (ret)
1129                 goto exit;
1130
1131         total_sector = datablock.total_sect;
1132
1133         ret = fat_itr_resolve(itr, parent, TYPE_DIR);
1134         if (ret) {
1135                 printf("%s: doesn't exist (%d)\n", parent, ret);
1136                 goto exit;
1137         }
1138
1139         retdent = find_directory_entry(itr, l_filename);
1140
1141         if (retdent) {
1142                 if (fat_itr_isdir(itr)) {
1143                         ret = -EISDIR;
1144                         goto exit;
1145                 }
1146
1147                 /* A file exists */
1148                 if (pos == -1)
1149                         /* Append to the end */
1150                         pos = FAT2CPU32(retdent->size);
1151                 if (pos > retdent->size) {
1152                         /* No hole allowed */
1153                         ret = -EINVAL;
1154                         goto exit;
1155                 }
1156
1157                 /* Update file size in a directory entry */
1158                 retdent->size = cpu_to_le32(pos + size);
1159         } else {
1160                 /* Create a new file */
1161
1162                 if (itr->is_root) {
1163                         /* root dir cannot have "." or ".." */
1164                         if (!strcmp(l_filename, ".") ||
1165                             !strcmp(l_filename, "..")) {
1166                                 ret = -EINVAL;
1167                                 goto exit;
1168                         }
1169                 }
1170
1171                 if (!itr->dent) {
1172                         printf("Error: allocating new dir entry\n");
1173                         ret = -EIO;
1174                         goto exit;
1175                 }
1176
1177                 if (pos) {
1178                         /* No hole allowed */
1179                         ret = -EINVAL;
1180                         goto exit;
1181                 }
1182
1183                 memset(itr->dent, 0, sizeof(*itr->dent));
1184
1185                 /* Calculate checksum for short name */
1186                 set_name(itr->dent, filename);
1187
1188                 /* Set long name entries */
1189                 if (fill_dir_slot(itr, filename)) {
1190                         ret = -EIO;
1191                         goto exit;
1192                 }
1193
1194                 /* Set short name entry */
1195                 fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20);
1196
1197                 retdent = itr->dent;
1198         }
1199
1200         ret = set_contents(mydata, retdent, pos, buffer, size, actwrite);
1201         if (ret < 0) {
1202                 printf("Error: writing contents\n");
1203                 ret = -EIO;
1204                 goto exit;
1205         }
1206         debug("attempt to write 0x%llx bytes\n", *actwrite);
1207
1208         /* Flush fat buffer */
1209         ret = flush_dirty_fat_buffer(mydata);
1210         if (ret) {
1211                 printf("Error: flush fat buffer\n");
1212                 ret = -EIO;
1213                 goto exit;
1214         }
1215
1216         /* Write directory table to device */
1217         ret = flush_dir(itr);
1218         if (ret) {
1219                 printf("Error: writing directory entry\n");
1220                 ret = -EIO;
1221         }
1222
1223 exit:
1224         free(filename_copy);
1225         free(mydata->fatbuf);
1226         free(itr);
1227         return ret;
1228 }
1229
1230 int file_fat_write(const char *filename, void *buffer, loff_t offset,
1231                    loff_t maxsize, loff_t *actwrite)
1232 {
1233         return file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
1234 }
1235
1236 static int fat_dir_entries(fat_itr *itr)
1237 {
1238         fat_itr *dirs;
1239         fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
1240                                                 /* for FATBUFSIZE */
1241         int count;
1242
1243         dirs = malloc_cache_aligned(sizeof(fat_itr));
1244         if (!dirs) {
1245                 debug("Error: allocating memory\n");
1246                 count = -ENOMEM;
1247                 goto exit;
1248         }
1249
1250         /* duplicate fsdata */
1251         fat_itr_child(dirs, itr);
1252         fsdata = *dirs->fsdata;
1253
1254         /* allocate local fat buffer */
1255         fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
1256         if (!fsdata.fatbuf) {
1257                 debug("Error: allocating memory\n");
1258                 count = -ENOMEM;
1259                 goto exit;
1260         }
1261         fsdata.fatbufnum = -1;
1262         dirs->fsdata = &fsdata;
1263
1264         for (count = 0; fat_itr_next(dirs); count++)
1265                 ;
1266
1267 exit:
1268         free(fsdata.fatbuf);
1269         free(dirs);
1270         return count;
1271 }
1272
1273 static int delete_dentry(fat_itr *itr)
1274 {
1275         fsdata *mydata = itr->fsdata;
1276         dir_entry *dentptr = itr->dent;
1277
1278         /* free cluster blocks */
1279         clear_fatent(mydata, START(dentptr));
1280         if (flush_dirty_fat_buffer(mydata) < 0) {
1281                 printf("Error: flush fat buffer\n");
1282                 return -EIO;
1283         }
1284
1285         /*
1286          * update a directory entry
1287          * TODO:
1288          *  - long file name support
1289          *  - find and mark the "new" first invalid entry as name[0]=0x00
1290          */
1291         memset(dentptr, 0, sizeof(*dentptr));
1292         dentptr->name[0] = 0xe5;
1293
1294         if (flush_dir(itr)) {
1295                 printf("error: writing directory entry\n");
1296                 return -EIO;
1297         }
1298
1299         return 0;
1300 }
1301
1302 int fat_unlink(const char *filename)
1303 {
1304         fsdata fsdata = { .fatbuf = NULL, };
1305         fat_itr *itr = NULL;
1306         int n_entries, ret;
1307         char *filename_copy, *dirname, *basename;
1308
1309         filename_copy = strdup(filename);
1310         if (!filename_copy) {
1311                 printf("Error: allocating memory\n");
1312                 ret = -ENOMEM;
1313                 goto exit;
1314         }
1315         split_filename(filename_copy, &dirname, &basename);
1316
1317         if (!strcmp(dirname, "/") && !strcmp(basename, "")) {
1318                 printf("Error: cannot remove root\n");
1319                 ret = -EINVAL;
1320                 goto exit;
1321         }
1322
1323         itr = malloc_cache_aligned(sizeof(fat_itr));
1324         if (!itr) {
1325                 printf("Error: allocating memory\n");
1326                 ret = -ENOMEM;
1327                 goto exit;
1328         }
1329
1330         ret = fat_itr_root(itr, &fsdata);
1331         if (ret)
1332                 goto exit;
1333
1334         total_sector = fsdata.total_sect;
1335
1336         ret = fat_itr_resolve(itr, dirname, TYPE_DIR);
1337         if (ret) {
1338                 printf("%s: doesn't exist (%d)\n", dirname, ret);
1339                 ret = -ENOENT;
1340                 goto exit;
1341         }
1342
1343         if (!find_directory_entry(itr, basename)) {
1344                 printf("%s: doesn't exist\n", basename);
1345                 ret = -ENOENT;
1346                 goto exit;
1347         }
1348
1349         if (fat_itr_isdir(itr)) {
1350                 n_entries = fat_dir_entries(itr);
1351                 if (n_entries < 0) {
1352                         ret = n_entries;
1353                         goto exit;
1354                 }
1355                 if (n_entries > 2) {
1356                         printf("Error: directory is not empty: %d\n",
1357                                n_entries);
1358                         ret = -EINVAL;
1359                         goto exit;
1360                 }
1361         }
1362
1363         ret = delete_dentry(itr);
1364
1365 exit:
1366         free(fsdata.fatbuf);
1367         free(itr);
1368         free(filename_copy);
1369
1370         return ret;
1371 }
1372
1373 int fat_mkdir(const char *new_dirname)
1374 {
1375         dir_entry *retdent;
1376         fsdata datablock = { .fatbuf = NULL, };
1377         fsdata *mydata = &datablock;
1378         fat_itr *itr = NULL;
1379         char *dirname_copy, *parent, *dirname;
1380         char l_dirname[VFAT_MAXLEN_BYTES];
1381         int ret = -1;
1382         loff_t actwrite;
1383         unsigned int bytesperclust;
1384         dir_entry *dotdent = NULL;
1385
1386         dirname_copy = strdup(new_dirname);
1387         if (!dirname_copy)
1388                 goto exit;
1389
1390         split_filename(dirname_copy, &parent, &dirname);
1391         if (!strlen(dirname)) {
1392                 ret = -EINVAL;
1393                 goto exit;
1394         }
1395
1396         if (normalize_longname(l_dirname, dirname)) {
1397                 printf("FAT: illegal filename (%s)\n", dirname);
1398                 ret = -EINVAL;
1399                 goto exit;
1400         }
1401
1402         itr = malloc_cache_aligned(sizeof(fat_itr));
1403         if (!itr) {
1404                 ret = -ENOMEM;
1405                 goto exit;
1406         }
1407
1408         ret = fat_itr_root(itr, &datablock);
1409         if (ret)
1410                 goto exit;
1411
1412         total_sector = datablock.total_sect;
1413
1414         ret = fat_itr_resolve(itr, parent, TYPE_DIR);
1415         if (ret) {
1416                 printf("%s: doesn't exist (%d)\n", parent, ret);
1417                 goto exit;
1418         }
1419
1420         retdent = find_directory_entry(itr, l_dirname);
1421
1422         if (retdent) {
1423                 printf("%s: already exists\n", l_dirname);
1424                 ret = -EEXIST;
1425                 goto exit;
1426         } else {
1427                 if (itr->is_root) {
1428                         /* root dir cannot have "." or ".." */
1429                         if (!strcmp(l_dirname, ".") ||
1430                             !strcmp(l_dirname, "..")) {
1431                                 ret = -EINVAL;
1432                                 goto exit;
1433                         }
1434                 }
1435
1436                 if (!itr->dent) {
1437                         printf("Error: allocating new dir entry\n");
1438                         ret = -EIO;
1439                         goto exit;
1440                 }
1441
1442                 memset(itr->dent, 0, sizeof(*itr->dent));
1443
1444                 /* Set short name to set alias checksum field in dir_slot */
1445                 set_name(itr->dent, dirname);
1446                 fill_dir_slot(itr, dirname);
1447
1448                 /* Set attribute as archive for regular file */
1449                 fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0,
1450                             ATTR_DIR | ATTR_ARCH);
1451
1452                 retdent = itr->dent;
1453         }
1454
1455         /* Default entries */
1456         bytesperclust = mydata->clust_size * mydata->sect_size;
1457         dotdent = malloc_cache_aligned(bytesperclust);
1458         if (!dotdent) {
1459                 ret = -ENOMEM;
1460                 goto exit;
1461         }
1462         memset(dotdent, 0, bytesperclust);
1463
1464         memcpy(dotdent[0].name, ".       ", 8);
1465         memcpy(dotdent[0].ext, "   ", 3);
1466         dotdent[0].attr = ATTR_DIR | ATTR_ARCH;
1467
1468         memcpy(dotdent[1].name, "..      ", 8);
1469         memcpy(dotdent[1].ext, "   ", 3);
1470         dotdent[1].attr = ATTR_DIR | ATTR_ARCH;
1471         set_start_cluster(mydata, &dotdent[1], itr->start_clust);
1472
1473         ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
1474                            bytesperclust, &actwrite);
1475         if (ret < 0) {
1476                 printf("Error: writing contents\n");
1477                 goto exit;
1478         }
1479         /* Write twice for "." */
1480         set_start_cluster(mydata, &dotdent[0], START(retdent));
1481         ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
1482                            bytesperclust, &actwrite);
1483         if (ret < 0) {
1484                 printf("Error: writing contents\n");
1485                 goto exit;
1486         }
1487
1488         /* Flush fat buffer */
1489         ret = flush_dirty_fat_buffer(mydata);
1490         if (ret) {
1491                 printf("Error: flush fat buffer\n");
1492                 goto exit;
1493         }
1494
1495         /* Write directory table to device */
1496         ret = flush_dir(itr);
1497         if (ret)
1498                 printf("Error: writing directory entry\n");
1499
1500 exit:
1501         free(dirname_copy);
1502         free(mydata->fatbuf);
1503         free(itr);
1504         free(dotdent);
1505         return ret;
1506 }