⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat.c

📁 This SPI-mode SD Card controller is a free SOPC Builder component that can be used in any SOPC Build
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 + -