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

📄 fat_file.c

📁 This SPI-mode SD Card controller is a free SOPC Builder component that can be used in any SOPC Build
💻 C
📖 第 1 页 / 共 2 页
字号:
        }

        if (offs + headbytes == SECTOR_SIZE) {
            if (file->dirty) {
                int rc = flush_cache(fd);
                if ( rc < 0 ) {
                    errno = EIO;
                    return rc * 10 - 2;
                }
            }
            file->cacheoffset = -1;
        }
        else {
            file->cacheoffset += headbytes;
        }

        nread = headbytes;
        count -= headbytes;
    }
    
    /* If the buffer has been modified, either it has been flushed already
     * (if (offs+headbytes == SECTOR_SIZE)...) or does not need to be (no
     * more data to follow in this call). Do NOT flush here. */

    /* read/write whole sectors right into/from the supplied buffer */
    sectors = count / SECTOR_SIZE;
    if ( sectors ) {
        int rc = fat_readwrite(&(file->fatfile), sectors,
            (unsigned char*)buf+nread, write );
        if ( rc < 0 ) {
            DEBUGF("Failed read/writing %ld sectors\n",sectors);
            errno = EIO;
            if(write && file->fatfile.eof) {
                DEBUGF("No space left on device\n");
                errno = ENOSPC;
            } else {
                file->fileoffset += nread;
            }
            file->cacheoffset = -1;
            return nread ? nread : rc * 10 - 4;
        }
        else {
            if ( rc > 0 ) {
                nread += rc * SECTOR_SIZE;
                count -= sectors * SECTOR_SIZE;

                /* if eof, skip tail bytes */
                if ( rc < sectors )
                    count = 0;
            }
            else {
                /* eof */
                count=0;
            }

            file->cacheoffset = -1;
        }
    }

    /* any tail bytes? */
    if ( count ) {
        if (write) {
            if ( file->fileoffset + nread < file->size ) {
                /* sector is only partially filled. copy-back from disk */
                int rc;
                LDEBUGF("Copy-back tail cache\n");
                rc = fat_readwrite(&(file->fatfile), 1, file->cache, false );
                if ( rc < 0 ) {
                    DEBUGF("Failed writing\n");
                    errno = EIO;
                    file->fileoffset += nread;
                    file->cacheoffset = -1;
                    return nread ? nread : rc * 10 - 5;
                }
                /* seek back one sector to put file position right */
                rc = fat_seek(&(file->fatfile), 
                              (file->fileoffset + nread) / 
                              SECTOR_SIZE);
                if ( rc < 0 ) {
                    DEBUGF("fat_seek() failed\n");
                    errno = EIO;
                    file->fileoffset += nread;
                    file->cacheoffset = -1;
                    return nread ? nread : rc * 10 - 6;
                }
            }
            memcpy( file->cache, (unsigned char*)buf + nread, count );
            file->dirty = true;
        }
        else {
            rc = fat_readwrite(&(file->fatfile), 1, &(file->cache),false);
            if (rc < 1 ) {
                DEBUGF("Failed caching sector\n");
                errno = EIO;
                file->fileoffset += nread;
                file->cacheoffset = -1;
                return nread ? nread : rc * 10 - 7;
            }
            memcpy( (unsigned char*)buf + nread, file->cache, count );
        }
            
        nread += count;
        file->cacheoffset = count;
    }

    file->fileoffset += nread;
    LDEBUGF("fileoffset: %ld\n", file->fileoffset);

    /* adjust file size to length written */
    if ( write && file->fileoffset > file->size )
    {
        file->size = file->fileoffset;
#ifdef HAVE_DIRCACHE
        dircache_update_filesize(fd, file->size);
#endif
    }

    return nread;
}


ssize_t rb_fat_write(int fd, const void* buf, size_t count)
{
    if (!openfiles[fd].write) {
        errno = EACCES;
        return -1;
    }
    return rb_fat_readwrite(fd, (void *)buf, count, true);
}


ssize_t rb_fat_read(int fd, void* buf, size_t count)
{
    return rb_fat_readwrite(fd, buf, count, false);
}


int rb_fat_list( char* pathname, char* buf )
{
    DIR* dir;
    struct dirent* entry;
    int files = 0;
    char* buf_wr_ptr = buf;
    char temp_pathname[512];

    LDEBUGF("ls(\"%s\")\n",pathname);

    strcpy( temp_pathname, pathname );
    
    // Check that path starts with a /
    if ( temp_pathname[0] != '/' ) {
        DEBUGF("'%s' is not an absolute path.\n",pathname);
        DEBUGF("Only absolute paths supported at the moment\n");
        errno = EINVAL;
        return -1;
    }
    
    // Ensure that path ends with a /
    int pathlen = strlen(temp_pathname);
    if( temp_pathname[pathlen -1] != '/' )
    {
      temp_pathname[pathlen] = '/';
      temp_pathname[pathlen+1] = 0x0;
    }
      
    dir = rb_fat_opendir(temp_pathname);
    if (!dir) {
        DEBUGF("Failed opening dir\n");
        errno = EIO;
        return -4;
    }
    /* scan dir for name */
    while ((entry = readdir(dir))) {
      files++;
      strcpy( buf_wr_ptr , entry->d_name );
      buf_wr_ptr += strlen( entry->d_name ) + 1;
    }
    
    rb_fat_closedir(dir);

    return files;
}


off_t rb_fat_lseek(int fd, off_t offset, int whence)
{
    off_t pos;
    long newsector;
    long oldsector;
    int sectoroffset;
    int rc;
    struct filedesc* file = &openfiles[fd];

    LDEBUGF("lseek(%d,%ld,%d)\n",fd,offset,whence);

    if ( !file->busy ) {
        errno = EBADF;
        return -1;
    }

    switch ( whence ) {
        case SEEK_SET:
            pos = offset;
            break;

        case SEEK_CUR:
            pos = file->fileoffset + offset;
            break;

        case SEEK_END:
            pos = file->size + offset;
            break;

        default:
            errno = EINVAL;
            return -2;
    }
    if ((pos < 0) || (pos > file->size)) {
        errno = EINVAL;
        return -3;
    }

    /* new sector? */
    newsector = pos / SECTOR_SIZE;
    oldsector = file->fileoffset / SECTOR_SIZE;
    sectoroffset = pos % SECTOR_SIZE;

    if ( (newsector != oldsector) ||
         ((file->cacheoffset==-1) && sectoroffset) ) {

        if ( newsector != oldsector ) {
            if (file->dirty) {
                rc = flush_cache(fd);
                if (rc < 0)
                    return rc * 10 - 5;
            }
            
            rc = fat_seek(&(file->fatfile), newsector);
            if ( rc < 0 ) {
                errno = EIO;
                return rc * 10 - 4;
            }
        }
        if ( sectoroffset ) {
            rc = fat_readwrite(&(file->fatfile), 1,
                               &(file->cache),false);
            if ( rc < 0 ) {
                errno = EIO;
                return rc * 10 - 6;
            }
            file->cacheoffset = sectoroffset;
        }
        else
            file->cacheoffset = -1;
    }
    else
        if ( file->cacheoffset != -1 )
            file->cacheoffset = sectoroffset;

    file->fileoffset = pos;

    return pos;
}

off_t rb_fat_filesize(int fd)
{
    struct filedesc* file = &openfiles[fd];

    if ( !file->busy ) {
        errno = EBADF;
        return -1;
    }
    
    return file->size;
}

int rb_fat_creat(const char *pathname, mode_t mode)
{
    (void)mode;
    return rb_fat_open(pathname, O_WRONLY|O_CREAT|O_TRUNC);
}

int rb_fat_fsync(int fd)
{
    struct filedesc* file = &openfiles[fd];
    int rc = 0;

    LDEBUGF("fsync(%d)\n", fd);

    if (fd < 0 || fd > MAX_OPEN_FILES-1) {
        errno = EINVAL;
        return -1;
    }
    if (!file->busy) {
        errno = EBADF;
        return -2;
    }
    if (file->write) {
        /* flush sector cache */
        if ( file->dirty ) {
            rc = flush_cache(fd);
            if (rc < 0)
                return rc * 10 - 3;
        }

        /* truncate? */
        if (file->trunc) {
            rc = rb_fat_ftruncate(fd, file->size);
            if (rc < 0)
                return rc * 10 - 4;
        }

        /* tie up all loose ends */
        rc = fat_closewrite(&(file->fatfile), file->size, file->attr);
        if (rc < 0)
            return rc * 10 - 5;
    }
    return 0;
}

int rb_fat_remove(const char* name)
{
    int rc;
    struct filedesc* file;
    int fd = rb_fat_open(name, O_WRONLY);
    if ( fd < 0 )
        return fd * 10 - 1;

    file = &openfiles[fd];
    rc = fat_remove(&(file->fatfile));
    if ( rc < 0 ) {
        DEBUGF("Failed removing file: %d\n", rc);
        errno = EIO;
        return rc * 10 - 3;
    }

    file->size = 0;
#ifdef HAVE_DIRCACHE
    dircache_remove(name);
#endif

    rc = rb_fat_close(fd);
    if (rc<0)
        return rc * 10 - 4;

    return 0;
}

int rb_fat_rename(const char* path, const char* newpath)
{
    int rc, fd;
    DIR* dir;
    char* nameptr;
    char* dirptr;
    struct filedesc* file;
    char newpath2[MAX_PATH];

    /* verify new path does not already exist */
    /* If it is a directory, errno == EISDIR if the name exists */
    fd = rb_fat_open(newpath, O_RDONLY);
    if ( fd >= 0 || errno == EISDIR) {
        rb_fat_close(fd);
        errno = EBUSY;
        return -1;
    }
    rb_fat_close(fd);

    fd = rb_fat_open(path, O_RDONLY);
    if ( fd < 0 ) {
        errno = EIO;
        return fd * 10 - 2;
    }

    /* extract new file name */
    nameptr = strrchr(newpath,'/');
    if (nameptr)
        nameptr++;
    else
        return - 3;

    /* Extract new path */
    strcpy(newpath2, newpath);
    
    dirptr = strrchr(newpath2,'/');
    if(dirptr)
        *dirptr = 0;
    else
        return - 4;

    dirptr = newpath2;
    
    if(strlen(dirptr) == 0) {
        dirptr = "/";
    }
    
    dir = rb_fat_opendir(dirptr);
    if(!dir)
        return - 5;
    
    file = &openfiles[fd];
    rc = fat_rename(&file->fatfile, &dir->fatdir, nameptr,
                    file->size, file->attr);
    if ( rc < 0 ) {
        DEBUGF("Failed renaming file: %d\n", rc);
        errno = EIO;
        return rc * 10 - 6;
    }

#ifdef HAVE_DIRCACHE
    dircache_rename(path, newpath);
#endif
    
    rc = rb_fat_close(fd);
    if (rc<0) {
        errno = EIO;
        return rc * 10 - 7;
    }

    rc = rb_fat_closedir(dir);
    if (rc<0) {
        errno = EIO;
        return rc * 10 - 8;
    }

    return 0;
}

int rb_fat_ftruncate(int fd, off_t size)
{
    int rc, sector;
    struct filedesc* file = &openfiles[fd];

    sector = size / SECTOR_SIZE;
    if (size % SECTOR_SIZE)
        sector++;

    rc = fat_seek(&(file->fatfile), sector);
    if (rc < 0) {
        errno = EIO;
        return rc * 10 - 1;
    }

    rc = fat_truncate(&(file->fatfile));
    if (rc < 0) {
        errno = EIO;
        return rc * 10 - 2;
    }

    file->size = size;

    return 0;
}

int rb_fat_mkdir(const char *name, int mode)
{
    DIR *dir;
    char namecopy[MAX_PATH];
    char* end;
    char *basename;
    char *parent;
    struct dirent *entry;
    struct fat_dir newdir;
    int rc;

    (void)mode;

    if ( name[0] != '/' ) {
        DEBUGF("mkdir: Only absolute paths supported right now\n");
        return -1;
    }

    strncpy(namecopy,name,sizeof(namecopy));
    namecopy[sizeof(namecopy)-1] = 0;

    /* Split the base name and the path */
    end = strrchr(namecopy, '/');
    *end = 0;
    basename = end+1;

    if(namecopy == end) /* Root dir? */
        parent = "/";
    else
        parent = namecopy;
        
    DEBUGF("mkdir: parent: %s, name: %s\n", parent, basename);

    dir = rb_fat_opendir(parent);
    
    if(!dir) {
        DEBUGF("mkdir: can't open parent dir\n");
        return -2;
    }    

    if(basename[0] == 0) {
        DEBUGF("mkdir: Empty dir name\n");
        errno = EINVAL;
        return -3;
    }
    
    /* Now check if the name already exists */
    while ((entry = readdir(dir))) {
        if ( !strcasecmp(basename, entry->d_name) ) {
            DEBUGF("mkdir error: file exists\n");
            errno = EEXIST;
            rb_fat_closedir(dir);
            return - 4;
        }
    }

    memset(&newdir, sizeof(struct fat_dir), 0);
    
    rc = fat_create_dir(basename, &newdir, &(dir->fatdir));
#ifdef HAVE_DIRCACHE
    if (rc >= 0)
        dircache_mkdir(name);
#endif

    rb_fat_closedir(dir);
    
    return rc;
}

int rb_fat_rmdir(const char* name)
{
    int rc;
    DIR* dir;
    struct dirent* entry;
    
    dir = rb_fat_opendir(name);
    if (!dir)
    {
        errno = ENOENT; /* open error */
        return -1;
    }

    /* check if the directory is empty */
    while ((entry = readdir(dir)))
    {
        if (strcmp(entry->d_name, ".") &&
            strcmp(entry->d_name, ".."))
        {
            DEBUGF("rmdir error: not empty\n");
            errno = ENOTEMPTY;
            rb_fat_closedir(dir);
            return -2;
        }
    }

    rc = fat_remove(&(dir->fatdir.file));
    if ( rc < 0 ) {
        DEBUGF("Failed removing dir: %d\n", rc);
        errno = EIO;
        rc = rc * 10 - 3;
    }
#ifdef HAVE_DIRCACHE
    else
    {
        dircache_rmdir(name);
    }
#endif

    rb_fat_closedir(dir);
    
    return rc;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -