summaryrefslogtreecommitdiff
path: root/firmware/drivers/fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/fat.c')
-rw-r--r--firmware/drivers/fat.c285
1 files changed, 188 insertions, 97 deletions
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index 5ca422063b..534d48bf76 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -99,9 +99,15 @@
99#define FATDIR_FSTCLUSLO 26 99#define FATDIR_FSTCLUSLO 26
100#define FATDIR_FILESIZE 28 100#define FATDIR_FILESIZE 28
101 101
102#define FATLONG_ORDER 0
103#define FATLONG_ATTR 11
104#define FATLONG_TYPE 12
105#define FATLONG_CHKSUM 13
106
102#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4) 107#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
103#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE) 108#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
104#define DIR_ENTRY_SIZE 32 109#define DIR_ENTRY_SIZE 32
110#define NAME_BYTES_PER_ENTRY 13
105#define FAT_BAD_MARK 0x0ffffff7 111#define FAT_BAD_MARK 0x0ffffff7
106#define FAT_EOF_MARK 0x0ffffff8 112#define FAT_EOF_MARK 0x0ffffff8
107 113
@@ -162,13 +168,8 @@ static struct bpb fat_bpb;
162static int first_sector_of_cluster(int cluster); 168static int first_sector_of_cluster(int cluster);
163static int bpb_is_sane(void); 169static int bpb_is_sane(void);
164static void *cache_fat_sector(int secnum); 170static void *cache_fat_sector(int secnum);
165#ifdef DISK_WRITE
166static unsigned int getcurrdostime(unsigned short *dosdate,
167 unsigned short *dostime,
168 unsigned char *dostenth);
169static int create_dos_name(unsigned char *name, unsigned char *newname); 171static int create_dos_name(unsigned char *name, unsigned char *newname);
170static unsigned int find_free_cluster(unsigned int start); 172static unsigned int find_free_cluster(unsigned int start);
171#endif
172 173
173#define FAT_CACHE_SIZE 0x20 174#define FAT_CACHE_SIZE 0x20
174#define FAT_CACHE_MASK (FAT_CACHE_SIZE-1) 175#define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
@@ -637,45 +638,134 @@ static int flush_fat(void)
637 return 0; 638 return 0;
638} 639}
639 640
640static unsigned int getcurrdostime(unsigned short *dosdate, 641static int write_long_name(struct fat_file* file,
641 unsigned short *dostime, 642 unsigned int firstentry,
642 unsigned char *dostenth) 643 unsigned int numentries,
644 unsigned char* name,
645 unsigned char* shortname)
643{ 646{
644#if 0 647 unsigned char buf[SECTOR_SIZE];
645 struct tm *tm; 648 unsigned char* entry;
646 unsigned long now = time(); 649 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
647 tm = localtime(&tb.time); 650 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
651 unsigned int i, j=0, nameidx;
652 unsigned char chksum = 0;
653 unsigned int namelen = strlen(name);
654 int rc;
655
656 LDEBUGF("write_long_name(file:%x, first:%d, num:%d, name:%s)\n",
657 file->firstcluster, firstentry, numentries, name);
658
659 rc = fat_seek(file, sector);
660 if (rc<0)
661 return -1;
648 662
649 *dosdate = ((tm->tm_year - 80) << 9) | 663 rc = fat_readwrite(file, 1, buf, false);
650 ((tm->tm_mon + 1) << 5) | 664 if (rc<1)
651 (tm->tm_mday); 665 return -2;
652 666
653 *dostime = (tm->tm_hour << 11) | 667 /* calculate shortname checksum */
654 (tm->tm_min << 5) | 668 for (i=11; i>0; i--)
655 (tm->tm_sec >> 1); 669 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
670
671 /* calc position of last name segment */
672 for (nameidx=0;
673 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
674 nameidx += NAME_BYTES_PER_ENTRY);
675
676 for (i=0; i < numentries; i++) {
677 /* new sector? */
678 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
679 /* update current sector */
680 rc = fat_seek(file, sector);
681 if (rc<0)
682 return -3;
683
684 rc = fat_readwrite(file, 1, buf, true);
685 if (rc<1)
686 return -4;
687
688 /* grab next sector */
689 rc = fat_readwrite(file, 1, buf, false);
690 if (rc<1)
691 return -5;
656 692
657 *dostenth = (tm->tm_sec & 1) * 100 + tb.millitm / 10; 693 sector++;
658#else 694 idx = 0;
659 *dosdate = 0; 695 }
660 *dostime = 0; 696
661 *dostenth = 0; 697 entry = buf + idx * DIR_ENTRY_SIZE;
662#endif 698
699 /* verify this entry is free */
700 if (entry[0] && entry[0] != 0xe5 )
701 panicf("Dir entry %d in sector %x is not free! "
702 "%02x %02x %02x %02x",
703 idx, sector,
704 entry[0], entry[1], entry[2], entry[3]);
705
706 memset(entry, 0, DIR_ENTRY_SIZE);
707 if ( i+1 < numentries ) {
708 /* longname entry */
709 int k, l = nameidx;
710 entry[FATLONG_ORDER] = numentries-i-1;
711 if (i==0)
712 entry[FATLONG_ORDER] |= 0x40;
713 for (k=0; k<5 && name[l]; k++) entry[k*2 + 1] = name[l++];
714 for (k=0; k<6 && name[l]; k++) entry[k*2 + 14] = name[l++];
715 for (k=0; k<2 && name[l]; k++) entry[k*2 + 28] = name[l++];
716 entry[FATLONG_ATTR] = FAT_ATTR_LONG_NAME;
717 entry[FATLONG_CHKSUM] = chksum;
718 LDEBUGF("Longname entry %d: %.13s\n", idx, name+nameidx);
719 }
720 else {
721 /* shortname entry */
722 LDEBUGF("Shortname entry: %.13s\n", shortname);
723 strncpy(entry + FATDIR_NAME, shortname, 11);
724 entry[FATDIR_ATTR] = 0;
725 entry[FATDIR_NTRES] = 0;
726 }
727 idx++;
728 nameidx -= NAME_BYTES_PER_ENTRY;
729 //dbg_dump_buffer(buf, SECTOR_SIZE, 0);
730 }
731
732 /* update last sector */
733 rc = fat_seek(file, sector);
734 if (rc<0)
735 return -5;
736
737 rc = fat_readwrite(file, 1, buf, true);
738 if (rc<1)
739 return -6;
740
663 return 0; 741 return 0;
664} 742}
665 743
666static int add_dir_entry(struct fat_dir* dir, 744static int add_dir_entry(struct fat_dir* dir,
667 struct fat_direntry* de, 745 struct fat_file* file,
668 struct fat_file* file) 746 char* name)
669{ 747{
670 unsigned char buf[SECTOR_SIZE]; 748 unsigned char buf[SECTOR_SIZE];
749 unsigned char shortname[16];
671 int err; 750 int err;
672 unsigned int sector; 751 unsigned int sector;
673 bool update_last = false;
674 bool done = false; 752 bool done = false;
675 bool eof = false; 753 bool eof = false;
754 int entries_needed, entries_found = 0;
755 int namelen = strlen(name);
676 756
677 LDEBUGF( "add_dir_entry(%s,%x)\n", 757 LDEBUGF( "add_dir_entry(%s,%x)\n",
678 de->name, file->firstcluster); 758 name, file->firstcluster);
759
760 /* create dos name */
761 if (create_dos_name(name, shortname) < 0)
762 return -1;
763
764 /* one dir entry needed for every 13 bytes of filename,
765 plus one entry for the short name */
766 entries_needed = namelen / NAME_BYTES_PER_ENTRY + 1;
767 if (namelen % NAME_BYTES_PER_ENTRY)
768 entries_needed++;
679 769
680 err=fat_seek(&dir->file, 0); 770 err=fat_seek(&dir->file, 0);
681 if (err<0) 771 if (err<0)
@@ -683,6 +773,8 @@ static int add_dir_entry(struct fat_dir* dir,
683 773
684 for (sector=0; !done; sector++) 774 for (sector=0; !done; sector++)
685 { 775 {
776 unsigned int i;
777
686 err = 0; 778 err = 0;
687 if (!eof) { 779 if (!eof) {
688 err = fat_readwrite(&dir->file, 1, buf, false); 780 err = fat_readwrite(&dir->file, 1, buf, false);
@@ -695,7 +787,7 @@ static int add_dir_entry(struct fat_dir* dir,
695 LDEBUGF("Adding new sector to dir\n"); 787 LDEBUGF("Adding new sector to dir\n");
696 err=fat_seek(&dir->file, sector); 788 err=fat_seek(&dir->file, sector);
697 if (err<0) 789 if (err<0)
698 return -5; 790 return -2;
699 791
700 /* add sectors (we must clear the whole cluster) */ 792 /* add sectors (we must clear the whole cluster) */
701 do { 793 do {
@@ -703,74 +795,83 @@ static int add_dir_entry(struct fat_dir* dir,
703 if (err<1) 795 if (err<1)
704 return -3; 796 return -3;
705 } while (dir->file.sectornum < (int)fat_bpb.bpb_secperclus); 797 } while (dir->file.sectornum < (int)fat_bpb.bpb_secperclus);
706 } 798 }
707 if (err<0) { 799 if (err<0) {
708 DEBUGF( "add_dir_entry() - Couldn't read dir" 800 DEBUGF( "add_dir_entry() - Couldn't read dir"
709 " (error code %d)\n", err); 801 " (error code %d)\n", err);
710 return -4; 802 return -4;
711 } 803 }
712 804
713 if (update_last) 805 /* look for free slots */
806 for (i=0; i < DIR_ENTRIES_PER_SECTOR; i++)
714 { 807 {
715 /* buffer is already cleared, 808 unsigned char firstbyte = buf[i * DIR_ENTRY_SIZE];
716 we just need to flag for sector update */ 809 switch (firstbyte) {
717 done = true; 810 case 0: /* end of dir */
718 } 811 entries_found = entries_needed;
719 else 812 LDEBUGF("Found last entry %d\n",
720 { 813 sector * DIR_ENTRIES_PER_SECTOR + i);
721 unsigned int i; 814 break;
722 /* Look for a free slot */ 815
723 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++) 816 case 0xe5: /* free entry */
817 entries_found++;
818 LDEBUGF("Found free entry %d (%d/%d)\n",
819 sector * DIR_ENTRIES_PER_SECTOR + i,
820 entries_found, entries_needed);
821 break;
822
823 default:
824 entries_found = 0;
825 break;
826 }
827
828 if (entries_found == entries_needed)
724 { 829 {
725 unsigned char firstbyte = buf[i*DIR_ENTRY_SIZE]; 830 int firstentry = sector * DIR_ENTRIES_PER_SECTOR + i;
726 if (firstbyte == 0xe5 || firstbyte == 0) 831
832 /* if we're not extending the dir, we must go back to first
833 free entry */
834 if (firstbyte)
835 firstentry -= (entries_needed - 1);
836
837 LDEBUGF("Adding longname to entry %d in sector %d\n",
838 i, sector);
839
840 err = write_long_name(&dir->file, firstentry,
841 entries_needed, name, shortname);
842 if (err < 0)
843 return -5;
844
845 /* remember where the shortname dir entry is located */
846 file->dirsector = dir->file.lastsector;
847 file->direntry =
848 (i + entries_needed - 1) % DIR_ENTRIES_PER_SECTOR;
849
850 /* advance the last_empty_entry marker? */
851 if (firstbyte == 0)
727 { 852 {
728 unsigned char* eptr; 853 i++;
729 LDEBUGF("Found free entry %d in sector %d (%x)\n", 854 if (i < DIR_ENTRIES_PER_SECTOR)
730 i, sector, dir->file.lastsector);
731 eptr = &buf[i*DIR_ENTRY_SIZE];
732 memset(eptr, 0, DIR_ENTRY_SIZE);
733 strncpy(&eptr[FATDIR_NAME], de->name, 11);
734 eptr[FATDIR_ATTR] = de->attr;
735 eptr[FATDIR_NTRES] = 0;
736
737 /* remember where the dir entry is located */
738 file->dirsector = dir->file.lastsector;
739 file->direntry = i;
740
741 /* advance the last_empty_entry marker? */
742 if (firstbyte == 0)
743 { 855 {
744 i++; 856 /* next entry is now last */
745 if (i < DIR_ENTRIES_PER_SECTOR) 857 buf[i*DIR_ENTRY_SIZE] = 0;
746 {
747 /* next entry is now last */
748 buf[i*DIR_ENTRY_SIZE] = 0;
749 done = true;
750 }
751 else
752 {
753 /* We must fill in the first entry
754 in the next sector */
755 update_last = true;
756 LDEBUGF("update_last = true\n");
757 }
758 } 858 }
759 else 859 else
760 done = true; 860 {
761 break; 861 /* add a new sector/cluster for last entry */
862 memset(buf, 0, sizeof buf);
863 do {
864 err = fat_readwrite(&dir->file, 1, buf, true);
865 if (err<1)
866 return -6;
867 } while (dir->file.sectornum <
868 (int)fat_bpb.bpb_secperclus);
869 }
762 } 870 }
871 done = true;
872 break;
763 } 873 }
764 } 874 }
765 if (done || update_last) {
766 /* update sector */
767 err=fat_seek(&dir->file, sector);
768 if (err<0)
769 return -5;
770 err = fat_readwrite(&dir->file, 1, buf, true);
771 if (err<1)
772 return -6;
773 }
774 } 875 }
775 876
776 return 0; 877 return 0;
@@ -820,7 +921,7 @@ static int create_dos_name(unsigned char *name, unsigned char *newname)
820 int i; 921 int i;
821 char *ext; 922 char *ext;
822 923
823 strcpy(n, name); 924 strncpy(n, name, sizeof n);
824 925
825 ext = strchr(n, '.'); 926 ext = strchr(n, '.');
826 if(ext) 927 if(ext)
@@ -862,6 +963,8 @@ static int create_dos_name(unsigned char *name, unsigned char *newname)
862 { 963 {
863 newname[8+i++] = ' '; 964 newname[8+i++] = ' ';
864 } 965 }
966
967 newname[11] = 0;
865 return 0; 968 return 0;
866} 969}
867 970
@@ -965,22 +1068,10 @@ int fat_create_file(char* name,
965 struct fat_file* file, 1068 struct fat_file* file,
966 struct fat_dir* dir) 1069 struct fat_dir* dir)
967{ 1070{
968 struct fat_direntry de;
969 int err; 1071 int err;
970 1072
971 LDEBUGF("fat_create_file(\"%s\",%x,%x)\n",name,file,dir); 1073 LDEBUGF("fat_create_file(\"%s\",%x,%x)\n",name,file,dir);
972 memset(&de, 0, sizeof(struct fat_direntry)); 1074 err = add_dir_entry(dir, file, name);
973 if (create_dos_name(name, de.name) < 0)
974 {
975 DEBUGF( "fat_create_file() - Illegal file name (%s)\n", name);
976 return -1;
977 }
978 getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth);
979 de.wrtdate = de.crtdate;
980 de.wrttime = de.crttime;
981 de.filesize = 0;
982
983 err = add_dir_entry(dir, &de, file);
984 if (!err) { 1075 if (!err) {
985 file->firstcluster = 0; 1076 file->firstcluster = 0;
986 file->lastcluster = 0; 1077 file->lastcluster = 0;
@@ -1145,7 +1236,7 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
1145 int i; 1236 int i;
1146 1237
1147 LDEBUGF( "fat_readwrite(file:%x,count:0x%x,buf:%x,%s)\n", 1238 LDEBUGF( "fat_readwrite(file:%x,count:0x%x,buf:%x,%s)\n",
1148 cluster,sectorcount,buf,write?"write":"read"); 1239 file->firstcluster,sectorcount,buf,write?"write":"read");
1149 LDEBUGF( "fat_readwrite: sec=%x numsec=%d eof=%d\n", 1240 LDEBUGF( "fat_readwrite: sec=%x numsec=%d eof=%d\n",
1150 sector,numsec, eof?1:0); 1241 sector,numsec, eof?1:0);
1151 1242