📄 fat.c
字号:
if ((i == sectorcount-1) && /* last sector requested */
(!eof))
{
long count = sector - first + 1;
rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
if (rc < 0)
return rc * 10 - 2;
}
last = sector;
}
file->lastcluster = cluster;
file->lastsector = sector;
file->clusternum = clusternum;
file->sectornum = numsec;
file->eof = eof;
/* if eof, don't report last block as read/written */
if (eof)
i--;
DEBUGF("Sectors written: %ld\n", i);
return i;
}
int fat_open(IF_MV2(int volume,)
long startcluster,
struct fat_file *file,
const struct fat_dir* dir)
{
file->firstcluster = startcluster;
file->lastcluster = startcluster;
file->lastsector = 0;
file->clusternum = 0;
file->sectornum = 0;
file->eof = false;
#ifdef HAVE_MULTIVOLUME
file->volume = volume;
/* fixme: remove error check when done */
if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
{
LDEBUGF("fat_open() illegal volume %d\n", volume);
return -1;
}
#endif
/* remember where the file's dir entry is located */
if ( dir ) {
file->direntry = dir->entry - 1;
file->direntries = dir->entrycount;
file->dircluster = dir->file.firstcluster;
}
LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry);
return 0;
}
/* Recode a UTF-16 string with little-endian byte ordering to UTF-8 */
unsigned char* utf16LEdecode(const unsigned char *utf16, unsigned char *utf8,
unsigned int count)
{
unsigned long ucs;
while (count != 0) {
/* Check for a surrogate pair */
if (utf16[1] >= 0xD8 && utf16[1] < 0xE0) {
ucs = 0x10000 + ((utf16[0] << 10) | ((utf16[1] - 0xD8) << 18)
| utf16[2] | ((utf16[3] - 0xDC) << 8));
utf16 += 4;
count -= 2;
} else {
ucs = (utf16[0] | (utf16[1] << 8));
utf16 += 2;
count -= 1;
}
utf8 = utf8encode(ucs, utf8);
}
return utf8;
}
unsigned long utf8length(const unsigned char *utf8)
{
unsigned long l = 0;
while (*utf8 != 0)
if ((*utf8++ & MASK) != COMP)
l++;
return l;
}
/* Encode a UCS value as UTF-8 and return a pointer after this UTF-8 char. */
unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8)
{
int tail = 0;
if (ucs > 0x7F)
while (ucs >> (5*tail + 6))
tail++;
*utf8++ = (ucs >> (6*tail)) | utf8comp[tail];
while (tail--)
*utf8++ = ((ucs >> (6*tail)) & (MASK ^ 0xFF)) | COMP;
return utf8;
}
static void randomize_dos_name(unsigned char *name)
{
int i;
unsigned char buf[5];
snprintf(buf, sizeof buf, "%04X", (unsigned)rand() & 0xffff);
for (i = 0; (i < 4) && (name[i] != ' '); i++);
/* account for possible shortname length < 4 */
memcpy(&name[i], buf, 4);
}
static void fat_time(unsigned short* date,
unsigned short* time,
unsigned short* tenth )
{
#ifdef CONFIG_RTC
struct tm* tm = get_time();
if (date)
*date = ((tm->tm_year - 80) << 9) |
((tm->tm_mon + 1) << 5) |
tm->tm_mday;
if (time)
*time = (tm->tm_hour << 11) |
(tm->tm_min << 5) |
(tm->tm_sec >> 1);
if (tenth)
*tenth = (tm->tm_sec & 1) * 100;
#else
/* non-RTC version returns an increment from the supplied time, or a
* fixed standard time/date if no time given as input */
bool next_day = false;
if (time)
{
if (0 == *time)
{
/* set to 00:15:00 */
*time = (15 << 5);
}
else
{
unsigned short mins = (*time >> 5) & 0x003F;
unsigned short hours = (*time >> 11) & 0x001F;
if ((mins += 10) >= 60)
{
mins = 0;
hours++;
}
if ((++hours) >= 24)
{
hours = hours - 24;
next_day = true;
}
*time = (hours << 11) | (mins << 5);
}
}
if (date)
{
if (0 == *date)
{
/* Macros to convert a 2-digit string to a decimal constant.
(YEAR), MONTH and DAY are set by the date command, which outputs
DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
misinterpretation as an octal constant. */
#define S100(x) 1 ## x
#define C2DIG2DEC(x) (S100(x)-100)
/* set to build date */
*date = ((YEAR - 1980) << 9) | (C2DIG2DEC(MONTH) << 5)
| C2DIG2DEC(DAY);
}
else
{
unsigned short day = *date & 0x001F;
unsigned short month = (*date >> 5) & 0x000F;
unsigned short year = (*date >> 9) & 0x007F;
if (next_day)
{
/* do a very simple day increment - never go above 28 days */
if (++day > 28)
{
day = 1;
if (++month > 12)
{
month = 1;
year++;
}
}
*date = (year << 9) | (month << 5) | day;
}
}
}
if (tenth)
*tenth = 0;
#endif /* CONFIG_RTC */
}
static int write_long_name(struct fat_file* file,
unsigned int firstentry,
unsigned int numentries,
const unsigned char* name,
const unsigned char* shortname,
bool is_directory)
{
unsigned char buf[SECTOR_SIZE];
unsigned char* entry;
unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
unsigned char chksum = 0;
unsigned int i, j=0;
unsigned int nameidx=0, namelen = utf8length(name);
int rc;
unsigned short name_utf16[namelen + 1];
LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
file->firstcluster, firstentry, numentries, name);
rc = fat_seek(file, sector);
if (rc<0)
return rc * 10 - 1;
rc = fat_readwrite(file, 1, buf, false);
if (rc<1)
return rc * 10 - 2;
/* calculate shortname checksum */
for (i=11; i>0; i--)
chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
/* calc position of last name segment */
if ( namelen > NAME_BYTES_PER_ENTRY )
for (nameidx=0;
nameidx < (namelen - NAME_BYTES_PER_ENTRY);
nameidx += NAME_BYTES_PER_ENTRY);
/* we need to convert the name first */
/* since it is written in reverse order */
for (i = 0; i <= namelen; i++)
name = utf8decode(name, &name_utf16[i]);
for (i=0; i < numentries; i++) {
/* new sector? */
if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
/* update current sector */
rc = fat_seek(file, sector);
if (rc<0)
return rc * 10 - 3;
rc = fat_readwrite(file, 1, buf, true);
if (rc<1)
return rc * 10 - 4;
/* read next sector */
rc = fat_readwrite(file, 1, buf, false);
if (rc<0) {
LDEBUGF("Failed writing new sector: %d\n",rc);
return rc * 10 - 5;
}
if (rc==0)
/* end of dir */
memset(buf, 0, sizeof buf);
sector++;
idx = 0;
}
entry = buf + idx * DIR_ENTRY_SIZE;
/* verify this entry is free */
if (entry[0] && entry[0] != 0xe5 )
panicf("Dir entry %d in sector %x is not free! "
"%02x %02x %02x %02x",
idx, sector,
entry[0], entry[1], entry[2], entry[3]);
memset(entry, 0, DIR_ENTRY_SIZE);
if ( i+1 < numentries ) {
/* longname entry */
unsigned int k, l = nameidx;
entry[FATLONG_ORDER] = numentries-i-1;
if (i==0) {
/* mark this as last long entry */
entry[FATLONG_ORDER] |= 0x40;
/* pad name with 0xffff */
for (k=1; k<11; k++) entry[k] = 0xff;
for (k=14; k<26; k++) entry[k] = 0xff;
for (k=28; k<32; k++) entry[k] = 0xff;
};
/* set name */
for (k=0; k<5 && l <= namelen; k++) {
entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
}
for (k=0; k<6 && l <= namelen; k++) {
entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
}
for (k=0; k<2 && l <= namelen; k++) {
entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
}
entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
entry[FATDIR_FSTCLUSLO] = 0;
entry[FATLONG_TYPE] = 0;
entry[FATLONG_CHKSUM] = chksum;
LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx);
}
else {
/* shortname entry */
unsigned short date=0, time=0, tenth=0;
LDEBUGF("Shortname entry: %s\n", shortname);
strncpy(entry + FATDIR_NAME, shortname, 11);
entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0;
entry[FATDIR_NTRES] = 0;
fat_time(&date, &time, &tenth);
entry[FATDIR_CRTTIMETENTH] = tenth;
*(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
*(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
*(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
*(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
*(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
}
idx++;
nameidx -= NAME_BYTES_PER_ENTRY;
}
/* update last sector */
rc = fat_seek(file, sector);
if (rc<0)
return rc * 10 - 6;
rc = fat_readwrite(file, 1, buf, true);
if (rc<1)
return rc * 10 - 7;
return 0;
}
static void create_dos_name(const unsigned char *name, unsigned char *newname)
{
int i;
unsigned char *ext;
/* Find extension part */
ext = strrchr(name, '.');
if (ext == name) /* handle .dotnames */
ext = NULL;
/* Name part */
for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
{
unsigned char c = char2dos(*name);
if (c)
newname[i++] = c;
}
/* Pad both name and extension */
while (i < 11)
newname[i++] = ' ';
if (newname[0] == 0xe5) /* Special kanji character */
newname[0] = 0x05;
if (ext)
{ /* Extension part */
ext++;
for (i = 8; *ext && (i < 11); ext++)
{
unsigned char c = char2dos(*ext);
if (c)
newname[i++] = c;
}
}
}
static int fat_checkname(const unsigned char* newname)
{
/* More sanity checks are probably needed */
if ( newname[strlen(newname) - 1] == '.' ) {
return -1;
}
return 0;
}
static int add_dir_entry(struct fat_dir* dir,
struct fat_file* file,
const char* name,
bool is_directory,
bool dotdir)
{
#ifdef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
#else
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
unsigned char buf[SECTOR_SIZE];
unsigned char shortname[12];
int rc;
unsigned int sector;
bool done = false;
int entries_needed, entries_found = 0;
int firstentry;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -