📄 file.c
字号:
/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: file.c,v 1.53 2004/03/10 19:47:59 linusnielsen Exp $ * * Copyright (C) 2002 by Bj鰎n Stenberg * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/#include <string.h>#include <errno.h>#include <stdbool.h>#include "file.h"#include "fat.h"#include "dir.h"#include "debug.h"/* These functions provide a roughly POSIX-compatible file IO API. Since the fat32 driver only manages sectors, we maintain a one-sector cache for each open file. This way we can provide byte access without having to re-read the sector each time. The penalty is the RAM used for the cache and slightly more complex code.*/#define MAX_OPEN_FILES 8struct filedesc { unsigned char cache[SECTOR_SIZE]; int cacheoffset; int fileoffset; int size; int attr; struct fat_file fatfile; bool busy; bool write; bool dirty; bool trunc;};static struct filedesc openfiles[MAX_OPEN_FILES];static int flush_cache(int fd);int creat(const char *pathname, mode_t mode){ (void)mode; return open(pathname, O_WRONLY|O_CREAT|O_TRUNC);}int open(const char* pathname, int flags){ DIR* dir; struct dirent* entry; int fd; char* name; struct filedesc* file = NULL; int rc; LDEBUGF("open(\"%s\",%d)\n",pathname,flags); if ( pathname[0] != '/' ) { DEBUGF("'%s' is not an absolute path.\n",pathname); DEBUGF("Only absolute pathnames supported at the moment\n"); errno = EINVAL; return -1; } /* find a free file descriptor */ for ( fd=0; fd<MAX_OPEN_FILES; fd++ ) if ( !openfiles[fd].busy ) break; if ( fd == MAX_OPEN_FILES ) { DEBUGF("Too many files open\n"); errno = EMFILE; return -2; } file = &openfiles[fd]; memset(file, 0, sizeof(struct filedesc)); if (flags & (O_RDWR | O_WRONLY)) { file->write = true; if (flags & O_TRUNC) file->trunc = true; } file->busy = true; /* locate filename */ name=strrchr(pathname+1,'/'); if ( name ) { *name = 0; dir = opendir((char*)pathname); *name = '/'; name++; } else { dir = opendir("/"); name = (char*)pathname+1; } if (!dir) { DEBUGF("Failed opening dir\n"); errno = EIO; file->busy = false; return -4; } if(name[0] == 0) { DEBUGF("Empty file name\n"); errno = EINVAL; file->busy = false; closedir(dir); return -5; } /* scan dir for name */ while ((entry = readdir(dir))) { if ( !strcasecmp(name, entry->d_name) ) { fat_open(entry->startcluster, &(file->fatfile), &(dir->fatdir)); file->size = entry->size; file->attr = entry->attribute; break; } } if ( !entry ) { LDEBUGF("Didn't find file %s\n",name); if ( file->write && (flags & O_CREAT) ) { rc = fat_create_file(name, &(file->fatfile), &(dir->fatdir)); if (rc < 0) { DEBUGF("Couldn't create %s in %s\n",name,pathname); errno = EIO; file->busy = false; closedir(dir); return rc * 10 - 6; } file->size = 0; file->attr = 0; } else { DEBUGF("Couldn't find %s in %s\n",name,pathname); errno = ENOENT; file->busy = false; closedir(dir); return -7; } } else { if(file->write && (file->attr & FAT_ATTR_DIRECTORY)) { errno = EISDIR; file->busy = false; closedir(dir); return -8; } } closedir(dir); file->cacheoffset = -1; file->fileoffset = 0; if (file->write && (flags & O_APPEND)) { rc = lseek(fd,0,SEEK_END); if (rc < 0 ) return rc * 10 - 9; } return fd;}int close(int fd){ struct filedesc* file = &openfiles[fd]; int rc = 0; LDEBUGF("close(%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) { rc = fsync(fd); if (rc < 0) return rc * 10 - 3; } file->busy = false; return 0;}int 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 = ftruncate(fd, file->fileoffset); 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 remove(const char* name){ int rc; struct filedesc* file; int fd = open(name, O_WRONLY); if ( fd < 0 ) return fd * 10 - 1; file = &openfiles[fd]; rc = fat_truncate(&(file->fatfile)); if ( rc < 0 ) { DEBUGF("Failed truncating file: %d\n", rc); errno = EIO; return rc * 10 - 2; } rc = fat_remove(&(file->fatfile)); if ( rc < 0 ) { DEBUGF("Failed removing file: %d\n", rc); errno = EIO; return rc * 10 - 3; } file->size = 0; rc = close(fd); if (rc<0) return rc * 10 - 4; return 0;}int rename(const char* path, const char* newpath){ int rc, fd; char* nameptr; struct filedesc* file; /* verify new path does not already exist */ fd = open(newpath, O_RDONLY); if ( fd >= 0 ) { close(fd); errno = EBUSY; return -1; } close(fd); fd = open(path, O_RDONLY); if ( fd < 0 ) { errno = EIO; return fd * 10 - 2; } /* strip path */ nameptr = strrchr(newpath,'/'); if (nameptr) nameptr++; else nameptr = (char*)newpath; file = &openfiles[fd]; rc = fat_rename(&file->fatfile, nameptr, file->size, file->attr); if ( rc < 0 ) { DEBUGF("Failed renaming file: %d\n", rc); errno = EIO; return rc * 10 - 3; } rc = close(fd); if (rc<0) { errno = EIO; return rc * 10 - 4;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -