📄 fat.c
字号:
LDEBUGF( "add_dir_entry(%s,%lx)\n",
name, file->firstcluster);
/* Don't check dotdirs name for validity */
if (dotdir == false) {
rc = fat_checkname(name);
if (rc < 0) {
/* filename is invalid */
return rc * 10 - 1;
}
}
#ifdef HAVE_MULTIVOLUME
file->volume = dir->file.volume; /* inherit the volume, to make sure */
#endif
/* The "." and ".." directory entries must not be long names */
if(dotdir) {
int i;
strncpy(shortname, name, 12);
for(i = strlen(shortname); i < 12; i++)
shortname[i] = ' ';
entries_needed = 1;
} else {
create_dos_name(name, shortname);
/* one dir entry needed for every 13 bytes of filename,
plus one entry for the short name */
entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
/ NAME_BYTES_PER_ENTRY + 1;
}
restart:
firstentry = -1;
rc = fat_seek(&dir->file, 0);
if (rc < 0)
return rc * 10 - 2;
/* step 1: search for free entries and check for duplicate shortname */
for (sector = 0; !done; sector++)
{
unsigned int i;
rc = fat_readwrite(&dir->file, 1, buf, false);
if (rc < 0) {
DEBUGF( "add_dir_entry() - Couldn't read dir"
" (error code %d)\n", rc);
return rc * 10 - 3;
}
if (rc == 0) { /* current end of dir reached */
LDEBUGF("End of dir on cluster boundary\n");
break;
}
/* look for free slots */
for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
{
switch (buf[i * DIR_ENTRY_SIZE]) {
case 0:
entries_found += DIR_ENTRIES_PER_SECTOR - i;
LDEBUGF("Found end of dir %d\n",
sector * DIR_ENTRIES_PER_SECTOR + i);
i = DIR_ENTRIES_PER_SECTOR - 1;
done = true;
break;
case 0xe5:
entries_found++;
LDEBUGF("Found free entry %d (%d/%d)\n",
sector * DIR_ENTRIES_PER_SECTOR + i,
entries_found, entries_needed);
break;
default:
entries_found = 0;
/* check that our intended shortname doesn't already exist */
if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 12)) {
/* shortname exists already, make a new one */
randomize_dos_name(shortname);
LDEBUGF("Duplicate shortname, changing to %s\n",
shortname);
/* name has changed, we need to restart search */
goto restart;
}
break;
}
if (firstentry < 0 && (entries_found >= entries_needed))
firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1
- entries_found;
}
}
/* step 2: extend the dir if necessary */
if (firstentry < 0)
{
LDEBUGF("Adding new sector(s) to dir\n");
rc = fat_seek(&dir->file, sector);
if (rc < 0)
return rc * 10 - 4;
memset(buf, 0, sizeof buf);
/* we must clear whole clusters */
for (; (entries_found < entries_needed) ||
(dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
{
if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
return -5; /* dir too large -- FAT specification */
rc = fat_readwrite(&dir->file, 1, buf, true);
if (rc < 1) /* No more room or something went wrong */
return rc * 10 - 6;
entries_found += DIR_ENTRIES_PER_SECTOR;
}
firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
}
/* step 3: add entry */
sector = firstentry / DIR_ENTRIES_PER_SECTOR;
LDEBUGF("Adding longname to entry %d in sector %d\n",
firstentry, sector);
rc = write_long_name(&dir->file, firstentry,
entries_needed, name, shortname, is_directory);
if (rc < 0)
return rc * 10 - 7;
/* remember where the shortname dir entry is located */
file->direntry = firstentry + entries_needed - 1;
file->direntries = entries_needed;
file->dircluster = dir->file.firstcluster;
LDEBUGF("Added new dir entry %d, using %d slots.\n",
file->direntry, file->direntries);
return 0;
}
int fat_create_file(const char* name,
struct fat_file* file,
struct fat_dir* dir)
{
int rc;
LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir);
rc = add_dir_entry(dir, file, name, false, false);
if (!rc) {
file->firstcluster = 0;
file->lastcluster = 0;
file->lastsector = 0;
file->clusternum = 0;
file->sectornum = 0;
file->eof = false;
}
return rc;
}
static int update_short_entry( struct fat_file* file, long size, int attr )
{
unsigned char buf[SECTOR_SIZE];
int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
unsigned char* entry =
buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
unsigned long* sizeptr;
unsigned short* clusptr;
struct fat_file dir;
int rc;
LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n",
file->firstcluster, file->direntry, size);
/* create a temporary file handle for the dir holding this file */
rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
if (rc < 0)
return rc * 10 - 1;
rc = fat_seek( &dir, sector );
if (rc<0)
return rc * 10 - 2;
rc = fat_readwrite(&dir, 1, buf, false);
if (rc < 1)
return rc * 10 - 3;
if (!entry[0] || entry[0] == 0xe5)
panicf("Updating size on empty dir entry %d\n", file->direntry);
entry[FATDIR_ATTR] = attr & 0xFF;
clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
*clusptr = htole16(file->firstcluster >> 16);
clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
*clusptr = htole16(file->firstcluster & 0xffff);
sizeptr = (long*)(entry + FATDIR_FILESIZE);
*sizeptr = htole32(size);
{
#ifdef CONFIG_RTC
unsigned short time = 0;
unsigned short date = 0;
#else
/* get old time to increment from */
unsigned short time = htole16(*(unsigned short*)(entry + FATDIR_WRTTIME));
unsigned short date = htole16(*(unsigned short*)(entry + FATDIR_WRTDATE));
#endif
fat_time(&date, &time, NULL);
*(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
*(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
*(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
}
rc = fat_seek( &dir, sector );
if (rc < 0)
return rc * 10 - 4;
rc = fat_readwrite(&dir, 1, buf, true);
if (rc < 1)
return rc * 10 - 5;
return 0;
}
int fat_create_dir(const char* name,
struct fat_dir* newdir,
struct fat_dir* dir)
{
#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];
int i;
long sector;
int rc;
struct fat_file dummyfile;
LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir);
memset(newdir, 0, sizeof(struct fat_dir));
memset(&dummyfile, 0, sizeof(struct fat_file));
/* First, add the entry in the parent directory */
rc = add_dir_entry(dir, &newdir->file, name, true, false);
if (rc < 0)
return rc * 10 - 1;
/* Allocate a new cluster for the directory */
newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
if(newdir->file.firstcluster == 0)
return -1;
update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
/* Clear the entire cluster */
memset(buf, 0, sizeof buf);
sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
if (rc < 0)
return rc * 10 - 2;
}
/* Then add the "." entry */
rc = add_dir_entry(newdir, &dummyfile, ".", true, true);
if (rc < 0)
return rc * 10 - 3;
dummyfile.firstcluster = newdir->file.firstcluster;
update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
/* and the ".." entry */
rc = add_dir_entry(newdir, &dummyfile, "..", true, true);
if (rc < 0)
return rc * 10 - 4;
/* The root cluster is cluster 0 in the ".." entry */
if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
dummyfile.firstcluster = 0;
else
dummyfile.firstcluster = dir->file.firstcluster;
update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
/* Set the firstcluster field in the direntry */
update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
rc = flush_fat(IF_MV(fat_bpb));
if (rc < 0)
return rc * 10 - 5;
return rc;
}
int fat_opendir(IF_MV2(int volume,)
struct fat_dir *dir, unsigned long startcluster,
const struct fat_dir *parent_dir)
{
#ifdef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[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;
}
#else
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
int rc;
dir->entry = 0;
dir->sector = 0;
if (startcluster == 0)
startcluster = fat_bpb->bpb_rootclus;
rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
if(rc)
{
DEBUGF( "fat_opendir() - Couldn't open dir"
" (error code %d)\n", rc);
return rc * 10 - 1;
}
return 0;
}
int fat_seek(struct fat_file *file, unsigned long seeksector )
{
#ifdef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[file->volume];
#else
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
long clusternum=0, numclusters=0, sectornum=0, sector=0;
long cluster = file->firstcluster;
long i;
#ifdef HAVE_FAT16SUPPORT
if (cluster < 0) /* FAT16 root dir */
seeksector += fat_bpb->rootdiroffset;
#endif
file->eof = false;
if (seeksector) {
/* we need to find the sector BEFORE the requested, since
the file struct stores the last accessed sector */
seeksector--;
numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
sectornum = seeksector % fat_bpb->bpb_secperclus;
if (file->clusternum && clusternum >= file->clusternum)
{
cluster = file->lastcluster;
numclusters -= file->clusternum;
}
for (i=0; i<numclusters; i++) {
cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
if (!cluster) {
DEBUGF("Seeking beyond the end of the file! "
"(sector %ld, cluster %ld)\n", seeksector, i);
return -1;
}
}
sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
}
else {
sectornum = -1;
}
LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n",
file->firstcluster, seeksector, cluster, sector, sectornum);
file->lastcluster = cluster;
file->lastsector = sector;
file->clusternum = clusternum;
file->sectornum = sectornum + 1;
return 0;
}
unsigned char char2dos(unsigned char c)
{
switch(c)
{
case 0x22:
case 0x2a:
case 0x2b:
case 0x2c:
case 0x2e:
case 0x3a:
case 0x3b:
case 0x3c:
case 0x3d:
case 0x3e:
case 0x3f:
case 0x5b:
case 0x5c:
case 0x5d:
case 0x7c:
/* Illegal char, replace */
c = '_';
break;
default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -