diff options
author | Björn Stenberg <bjorn@haxx.se> | 2002-11-15 16:41:02 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2002-11-15 16:41:02 +0000 |
commit | 7aabb1ab66b3126b987200528b62f4a3fb98d205 (patch) | |
tree | cdba27a268be90d14e06ba25d9607c1485e10d81 /firmware/drivers | |
parent | c442a683220493c6f2e961067f16caf60c6d6a21 (diff) | |
download | rockbox-7aabb1ab66b3126b987200528b62f4a3fb98d205.tar.gz rockbox-7aabb1ab66b3126b987200528b62f4a3fb98d205.zip |
Long filename support added. (fat_remove() not updated yet.)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@2852 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/fat.c | 285 |
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; | |||
162 | static int first_sector_of_cluster(int cluster); | 168 | static int first_sector_of_cluster(int cluster); |
163 | static int bpb_is_sane(void); | 169 | static int bpb_is_sane(void); |
164 | static void *cache_fat_sector(int secnum); | 170 | static void *cache_fat_sector(int secnum); |
165 | #ifdef DISK_WRITE | ||
166 | static unsigned int getcurrdostime(unsigned short *dosdate, | ||
167 | unsigned short *dostime, | ||
168 | unsigned char *dostenth); | ||
169 | static int create_dos_name(unsigned char *name, unsigned char *newname); | 171 | static int create_dos_name(unsigned char *name, unsigned char *newname); |
170 | static unsigned int find_free_cluster(unsigned int start); | 172 | static 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 | ||
640 | static unsigned int getcurrdostime(unsigned short *dosdate, | 641 | static 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 | ||
666 | static int add_dir_entry(struct fat_dir* dir, | 744 | static 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 | ||