//--------------------------------------------------------------------------- int fs_ioctl(iop_file_t *fd, u32 request, void *data) { fat_driver* fatd; struct fs_dirent* dirent = (struct fs_dirent *) fd->privdata; //Remember to re-cast this to the right structure (either fs_rec or fs_dir)! int ret; if (dirent == NULL) return -EBADF; _fs_lock(); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } switch (request) { case USBMASS_IOCTL_RENAME: ret = fat_renameFile(fatd, &dirent->fatdir, data); //No need to re-cast since this inner structure is a common one. FLUSH_SECTORS(fatd); break; default: ret = fs_dummy(); } _fs_unlock(); return ret; }
//--------------------------------------------------------------------------- static int fs_close(iop_file_t* fd) { fat_driver* fatd; fs_rec* rec = (fs_rec*)fd->privdata; if (rec == NULL) return -EBADF; _fs_lock(); if (rec->dirent.file_flag != FS_FILE_FLAG_FILE) { _fs_unlock(); return -EISDIR; } rec->dirent.file_flag = -1; fd->privdata = NULL; fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } if ((rec->mode & O_WRONLY)) { //update direntry size and time if (rec->sizeChange) { fat_updateSfn(fatd, rec->dirent.fatdir.size, rec->sfnSector, rec->sfnOffset); } FLUSH_SECTORS(fatd); } _fs_unlock(); return 0; }
//--------------------------------------------------------------------------- static int fs_getstat(iop_file_t *fd, const char *name, fio_stat_t *stat) { fat_driver* fatd; int ret; unsigned int cluster = 0; fat_dir fatdir; _fs_lock(); XPRINTF("USBHDFSD: fs_getstat called: unit %d name %s\n", fd->unit, name); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } XPRINTF("USBHDFSD: Calling fat_getFileStartCluster from fs_getstat\n"); ret = fat_getFileStartCluster(fatd, name, &cluster, &fatdir); if (ret < 0) { _fs_unlock(); return ret; } memset(stat, 0, sizeof(fio_stat_t)); fillStat(stat, &fatdir); _fs_unlock(); return 0; }
//--------------------------------------------------------------------------- int fs_ioctl(iop_file_t *fd, int cmd, void *data) { fat_driver* fatd; struct fs_dirent* dirent = (struct fs_dirent *) fd->privdata; //Remember to re-cast this to the right structure (either fs_rec or fs_dir)! int ret; if (dirent == NULL) return -EBADF; _fs_lock(); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } switch (cmd) { case USBMASS_IOCTL_RENAME: ret = fat_renameFile(fatd, &dirent->fatdir, data); //No need to re-cast since this inner structure is a common one. FLUSH_SECTORS(fatd); break; case USBMASS_IOCTL_GET_CLUSTER: ret = ((fs_rec *)fd->privdata)->dirent.fatdir.startCluster; break; case USBMASS_IOCTL_GET_LBA: ret = fat_cluster2sector(&fatd->partBpb, ((fs_rec *)fd->privdata)->dirent.fatdir.startCluster); break; default: ret = fs_dummy(); } _fs_unlock(); return ret; }
//--------------------------------------------------------------------------- static int fs_rmdir(iop_file_t *fd, const char *name) { fat_driver* fatd; int ret; _fs_lock(); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } ret = fat_deleteFile(fatd, name, 1); FLUSH_SECTORS(fatd); _fs_unlock(); return ret; }
//--------------------------------------------------------------------------- static int fs_dclose(iop_file_t *fd) { fs_dir *rec = (fs_dir*)fd->privdata; if (fd->privdata == NULL) return -EBADF; _fs_lock(); XPRINTF("USBHDFSD: fs_dclose called: unit %d\n", fd->unit); if (rec->dirent.file_flag != FS_FILE_FLAG_FOLDER) { _fs_unlock(); return -ENOTDIR; } free(fd->privdata); fd->privdata = NULL; _fs_unlock(); return 0; }
//--------------------------------------------------------------------------- static int fs_write(iop_file_t* fd, void * buffer, int size ) { fat_driver* fatd; fs_rec* rec = (fs_rec*)fd->privdata; int result; int updateClusterIndices = 0; if (rec == NULL) return -EBADF; _fs_lock(); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } if (rec->dirent.file_flag != FS_FILE_FLAG_FILE) { _fs_unlock(); return -EISDIR; } if (!(rec->mode & O_WRONLY)) { _fs_unlock(); return -EACCES; } if (size <= 0) { _fs_unlock(); return 0; } result = fat_writeFile(fatd, &rec->dirent.fatdir, &updateClusterIndices, rec->filePos, (unsigned char*) buffer, size); if (result > 0) { //write succesful rec->filePos += result; if (rec->filePos > rec->dirent.fatdir.size) { rec->dirent.fatdir.size = rec->filePos; rec->sizeChange = 1; //if new clusters allocated - then update file cluster indices if (updateClusterIndices) { fat_setFatDirChain(fatd, &rec->dirent.fatdir); } } } _fs_unlock(); return result; }
//--------------------------------------------------------------------------- static int fs_lseek(iop_file_t* fd, int offset, int whence) { fat_driver* fatd; fs_rec* rec = (fs_rec*)fd->privdata; if (rec == NULL) return -EBADF; _fs_lock(); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } if (rec->dirent.file_flag != FS_FILE_FLAG_FILE) { _fs_unlock(); return -EISDIR; } switch(whence) { case SEEK_SET: rec->filePos = offset; break; case SEEK_CUR: rec->filePos += offset; break; case SEEK_END: rec->filePos = rec->dirent.fatdir.size + offset; break; default: _fs_unlock(); return -1; } if (rec->filePos < 0) { rec->filePos = 0; } if (rec->filePos > rec->dirent.fatdir.size) { rec->filePos = rec->dirent.fatdir.size; } _fs_unlock(); return rec->filePos; }
//--------------------------------------------------------------------------- static int fs_dread(iop_file_t *fd, fio_dirent_t *buffer) { fat_driver* fatd; int ret; fs_dir* rec = (fs_dir *) fd->privdata; if (rec == NULL) return -EBADF; _fs_lock(); XPRINTF("USBHDFSD: fs_dread called: unit %d\n", fd->unit); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } if (rec->dirent.file_flag != FS_FILE_FLAG_FOLDER) { _fs_unlock(); return -ENOTDIR; } while (rec->status > 0 && (rec->current_fatdir.attr & FAT_ATTR_VOLUME_LABEL || ((rec->current_fatdir.attr & (FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM)) == (FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM)))) rec->status = fat_getNextDirentry(fatd, &rec->fatdlist, &rec->current_fatdir); ret = rec->status; if (rec->status >= 0) { memset(buffer, 0, sizeof(fio_dirent_t)); fillStat(&buffer->stat, &rec->current_fatdir); strcpy(buffer->name, rec->current_fatdir.name); } if (rec->status > 0) rec->status = fat_getNextDirentry(fatd, &rec->fatdlist, &rec->current_fatdir); _fs_unlock(); return ret; }
//--------------------------------------------------------------------------- static int fs_remove(iop_file_t *fd, const char *name) { fat_driver* fatd; fs_rec* rec; int result; unsigned int cluster; fat_dir fatdir; _fs_lock(); fatd = fat_getData(fd->unit); if (fatd == NULL) { result = -ENODEV; _fs_unlock(); return result; } cluster = 0; //allways start from root XPRINTF("USBHDFSD: Calling fat_getFileStartCluster from fs_remove\n"); result = fat_getFileStartCluster(fatd, name, &cluster, &fatdir); if (result < 0) { _fs_unlock(); return result; } rec = fs_findFileSlotByCluster(fatdir.startCluster); //file is opened - can't delete the file if (rec != NULL) { result = -EINVAL; _fs_unlock(); return result; } result = fat_deleteFile(fatd, name, 0); FLUSH_SECTORS(fatd); _fs_unlock(); return result; }
//--------------------------------------------------------------------------- static int fs_read(iop_file_t* fd, void * buffer, int size ) { fat_driver* fatd; fs_rec* rec = (fs_rec*)fd->privdata; int result; if (rec == NULL) return -EBADF; _fs_lock(); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } if (rec->dirent.file_flag != FS_FILE_FLAG_FILE) { _fs_unlock(); return -EISDIR; } if (!(rec->mode & O_RDONLY)) { _fs_unlock(); return -EACCES; } if (size<=0) { _fs_unlock(); return 0; } if ((rec->filePos+size) > rec->dirent.fatdir.size) { size = rec->dirent.fatdir.size - rec->filePos; } result = fat_readFile(fatd, &rec->dirent.fatdir, rec->filePos, (unsigned char*) buffer, size); if (result > 0) { //read succesful rec->filePos += result; } _fs_unlock(); return result; }
//--------------------------------------------------------------------------- static int fs_dopen(iop_file_t *fd, const char *name) { fat_driver* fatd; int is_root = 0; fs_dir* rec; _fs_lock(); XPRINTF("USBHDFSD: fs_dopen called: unit %d name %s\n", fd->unit, name); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } if( ((name[0] == '/') && (name[1] == '\0')) ||((name[0] == '/') && (name[1] == '.') && (name[2] == '\0'))) { name = "/"; is_root = 1; } fd->privdata = malloc(sizeof(fs_dir)); memset(fd->privdata, 0, sizeof(fs_dir)); //NB: also implies "file_flag = FS_FILE_FLAG_FOLDER;" rec = (fs_dir *) fd->privdata; rec->status = fat_getFirstDirentry(fatd, (char*)name, &rec->fatdlist, &rec->dirent.fatdir, &rec->current_fatdir); // root directory may have no entries, nothing else may. if(rec->status == 0 && !is_root) rec->status = -EFAULT; if (rec->status < 0) free(fd->privdata); _fs_unlock(); return rec->status; }
//--------------------------------------------------------------------------- static int fs_mkdir(iop_file_t *fd, const char *name) { fat_driver* fatd; int ret; int sfnOffset; unsigned int sfnSector; unsigned int cluster; _fs_lock(); fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } XPRINTF("USBHDFSD: fs_mkdir: name=%s \n",name); ret = fat_createFile(fatd, name, 1, 0, &cluster, &sfnSector, &sfnOffset); //directory of the same name already exist if (ret == 2) { ret = -EEXIST; } FLUSH_SECTORS(fatd); _fs_unlock(); return ret; }
//--------------------------------------------------------------------------- static int fs_open(iop_file_t* fd, const char *name, int mode) { fat_driver* fatd; fs_rec* rec, *rec2; int ret; unsigned int cluster; char escapeNotExist; _fs_lock(); XPRINTF("USBHDFSD: fs_open called: %s mode=%X \n", name, mode) ; fatd = fat_getData(fd->unit); if (fatd == NULL) { _fs_unlock(); return -ENODEV; } //check if the slot is free rec = fs_findFreeFileSlot(); if (rec == NULL) { _fs_unlock(); return -EMFILE; } //find the file cluster = 0; //allways start from root XPRINTF("USBHDFSD: Calling fat_getFileStartCluster from fs_open\n"); ret = fat_getFileStartCluster(fatd, name, &cluster, &rec->dirent.fatdir); if (ret < 0 && ret != -ENOENT) { _fs_unlock(); return ret; }else{ //File exists. Check if the file is already open rec2 = fs_findFileSlotByCluster(rec->dirent.fatdir.startCluster); if (rec2 != NULL) { if ((mode & O_WRONLY) || //current file is opened for write (rec2->mode & O_WRONLY) ) {//other file is opened for write _fs_unlock(); return -EACCES; } } } if(mode & O_WRONLY) { //dlanor: corrected bad test condition cluster = 0; //start from root escapeNotExist = 1; if (mode & O_CREAT) { XPRINTF("USBHDFSD: FAT I: O_CREAT detected!\n"); escapeNotExist = 0; } rec->sfnSector = 0; rec->sfnOffset = 0; ret = fat_createFile(fatd, name, 0, escapeNotExist, &cluster, &rec->sfnSector, &rec->sfnOffset); if (ret < 0) { _fs_unlock(); return ret; } //the file already exist but mode is set to truncate if (ret == 2 && (mode & O_TRUNC)) { XPRINTF("USBHDFSD: FAT I: O_TRUNC detected!\n"); fat_truncateFile(fatd, cluster, rec->sfnSector, rec->sfnOffset); } //find the file cluster = 0; //allways start from root XPRINTF("USBHDFSD: Calling fat_getFileStartCluster from fs_open after file creation\n"); ret = fat_getFileStartCluster(fatd, name, &cluster, &rec->dirent.fatdir); } if (ret < 0) { //At this point, the file should be locatable without any errors. _fs_unlock(); return ret; } if ((rec->dirent.fatdir.attr & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) { // Can't open a directory with fioOpen _fs_unlock(); return -EISDIR; } rec->dirent.file_flag = FS_FILE_FLAG_FILE; rec->mode = mode; rec->filePos = 0; rec->sizeChange = 0; if ((mode & O_APPEND) && (mode & O_WRONLY)) { XPRINTF("USBHDFSD: FAT I: O_APPEND detected!\n"); rec->filePos = rec->dirent.fatdir.size; } //store the slot to user parameters fd->privdata = rec; _fs_unlock(); return 1; }