void com_err (const char *whoami, errcode_t code, const char *fmt, ...) { if(whoami) ext2_log_trace("%s: ", whoami); ext2_log_trace("error code: %i ", (int) code); if(fmt) ext2_log_trace(fmt); ext2_log_trace("\n"); }
int ext2_fsync_r (struct _reent *r, int fd) { ext2_log_trace("fd %p\n", (void *) fd); ext2_file_state* file = STATE(fd); int ret = 0; // Sanity check if (!file || !file->fd) { r->_errno = EINVAL; return -1; } // Lock ext2Lock(file->vd); // Sync the file (and its attributes) to disc ret = ext2fs_file_flush(file->fd); if (ret) r->_errno = ret; // Unlock ext2Unlock(file->vd); return ret; }
int ext2_close_r (struct _reent *r, int fd) { ext2_log_trace("fd %p\n", (void *) fd); ext2_file_state* file = STATE(fd); // Sanity check if (!file || !file->vd) { r->_errno = EBADF; return -1; } // Lock ext2Lock(file->vd); // Close the file ext2CloseFile(file); // Remove the file from the double-linked FILO list of open files file->vd->openFileCount--; if (file->nextOpenFile) file->nextOpenFile->prevOpenFile = file->prevOpenFile; if (file->prevOpenFile) file->prevOpenFile->nextOpenFile = file->nextOpenFile; else file->vd->firstOpenFile = file->nextOpenFile; // Unlock ext2Unlock(file->vd); return 0; }
int ext2_dirreset_r (struct _reent *r, DIR_ITER *dirState) { ext2_log_trace("dirState %p\n", dirState); if(!dirState) { r->_errno = EINVAL; return -1; } ext2_dir_state* dir = STATE(dirState); // Sanity check if (!dir || !dir->vd || !dir->ni) { r->_errno = EBADF; return -1; } // Lock ext2Lock(dir->vd); // Move to the first entry in the directory dir->current = dir->first; // Update directory times ext2UpdateTimes(dir->vd, dir->ni, EXT2_UPDATE_ATIME); // Unlock ext2Unlock(dir->vd); return 0; }
int ext2_link_r (struct _reent *r, const char *existing, const char *newLink) { ext2_log_trace("existing %s, newLink %s\n", existing, newLink); ext2_vd *vd = NULL; ext2_inode_t *ni = NULL; // Get the volume descriptor for this path vd = ext2GetVolume(existing); if (!vd) { r->_errno = ENODEV; return -1; } // Lock ext2Lock(vd); // Create a symbolic link between the two paths ni = ext2Create(vd, existing, S_IFLNK, newLink); if (!ni) { ext2Unlock(vd); r->_errno = errno; return -1; } // Close the symbolic link ext2CloseEntry(vd, ni); // Unlock ext2Unlock(vd); return 0; }
int ext2_mkdir_r (struct _reent *r, const char *path, int mode) { ext2_log_trace("path %s, mode %i\n", path, mode); ext2_vd *vd = NULL; ext2_inode_t *ni = NULL; // Get the volume descriptor for this path vd = ext2GetVolume(path); if (!vd) { r->_errno = ENODEV; return -1; } // Lock ext2Lock(vd); // Create the directory ni = ext2Create(vd, path, S_IFDIR, NULL); if (!ni) { ext2Unlock(vd); r->_errno = errno; return -1; } // Close the directory ext2CloseEntry(vd, ni); // Unlock ext2Unlock(vd); return 0; }
int ext2_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat) { ext2_log_trace("dirState %p, filename %p, filestat %p\n", dirState, filename, filestat); if(!dirState) { r->_errno = EINVAL; return -1; } ext2_dir_state* dir = STATE(dirState); ext2_inode_t *ni = NULL; // Sanity check if (!dir || !dir->vd || !dir->ni) { r->_errno = EBADF; return -1; } // Lock ext2Lock(dir->vd); // Check that there is a entry waiting to be fetched if (!dir->current) { ext2Unlock(dir->vd); r->_errno = ENOENT; return -1; } // Fetch the current entry strcpy(filename, dir->current->name); if(filestat != NULL) { if(strcmp(dir->current->name, ".") == 0 || strcmp(dir->current->name, "..") == 0) { memset(filestat, 0, sizeof(struct stat)); filestat->st_mode = S_IFDIR; } else { ni = ext2OpenEntry(dir->vd, dir->current->name); if (ni) { ext2Stat(dir->vd, ni, filestat); ext2CloseEntry(dir->vd, ni); } } } // Move to the next entry in the directory dir->current = dir->current->next; // Update directory times ext2UpdateTimes(dir->vd, dir->ni, EXT2_UPDATE_ATIME); // Unlock ext2Unlock(dir->vd); return 0; }
int ext2_rename_r (struct _reent *r, const char *oldName, const char *newName) { ext2_log_trace("oldName %s, newName %s\n", oldName, newName); ext2_vd *vd = NULL; ext2_inode_t *ni = NULL; // Get the volume descriptor for this path vd = ext2GetVolume(oldName); if (!vd) { r->_errno = ENODEV; return -1; } // Lock ext2Lock(vd); // You cannot rename between devices if(vd != ext2GetVolume(newName)) { ext2Unlock(vd); r->_errno = EXDEV; return -1; } // Check that there is no existing entry with the new name ni = ext2OpenEntry(vd, newName); if (ni) { ext2CloseEntry(vd, ni); ext2Unlock(vd); r->_errno = EEXIST; return -1; } // Link the old entry with the new one if (ext2Link(vd, oldName, newName)) { ext2Unlock(vd); return -1; } // Unlink the old entry if (ext2Unlink(vd, oldName)) { if (ext2Unlink(vd, newName)) { ext2Unlock(vd); return -1; } ext2Unlock(vd); return -1; } // Unlock ext2Unlock(vd); return 0; }
int ext2_stat_r (struct _reent *r, const char *path, struct stat *st) { // Short circuit cases were we don't actually have to do anything if (!st || !path) return 0; ext2_log_trace("path %s, st %p\n", path, st); ext2_vd *vd = NULL; ext2_inode_t *ni = NULL; // Get the volume descriptor for this path vd = ext2GetVolume(path); if (!vd) { r->_errno = ENODEV; return -1; } if(strcmp(path, ".") == 0 || strcmp(path, "..") == 0) { memset(st, 0, sizeof(struct stat)); st->st_mode = S_IFDIR; return 0; } // Lock ext2Lock(vd); // Find the entry ni = ext2OpenEntry(vd, path); if (!ni) { r->_errno = errno; ext2Unlock(vd); return -1; } // Get the entry stats int ret = ext2Stat(vd, ni, st); if (ret) r->_errno = errno; // Close the entry ext2CloseEntry(vd, ni); ext2Unlock(vd); return 0; }
int ext2_chdir_r (struct _reent *r, const char *name) { ext2_log_trace("name %s\n", name); ext2_vd *vd = NULL; ext2_inode_t *ni = NULL; // Get the volume descriptor for this path vd = ext2GetVolume(name); if (!vd) { r->_errno = ENODEV; return -1; } // Lock ext2Lock(vd); // Find the directory ni = ext2OpenEntry(vd, name); if (!ni) { ext2Unlock(vd); r->_errno = ENOENT; return -1; } // Ensure that this directory is indeed a directory if (!LINUX_S_ISDIR(ni->ni.i_mode)) { ext2CloseEntry(vd, ni); ext2Unlock(vd); r->_errno = ENOTDIR; return -1; } // Close the old current directory (if any) if (vd->cwd_ni) ext2CloseEntry(vd, vd->cwd_ni); // Set the new current directory vd->cwd_ni = ni; // Unlock ext2Unlock(vd); return 0; }
s64 ext2_seek64_r (struct _reent *r, int fd, s64 pos, int dir) { ext2_log_trace("fd %p, pos %lli, dir %i\n", (void *) fd, pos, dir); ext2_file_state* file = STATE(fd); // Sanity check if (!file || !file->fd) { r->_errno = EINVAL; return -1; } __u64 pos_loaded = 0; ext2fs_file_llseek(file->fd, pos, dir, &pos_loaded); return (s64) pos_loaded; }
ssize_t ext2_read_r (struct _reent *r, int fd, char *ptr, size_t len) { ext2_log_trace("fd %p, ptr %p, len %i\n", (void *) fd, ptr, len); ext2_file_state* file = STATE(fd); // Sanity check if (!file || !file->vd || !file->fd) { r->_errno = EINVAL; return -1; } // Short circuit cases where we don't actually have to do anything if (!ptr || len <= 0) { return 0; } // Lock ext2Lock(file->vd); // Check that we are allowed to read from this file if (!file->read) { ext2Unlock(file->vd); r->_errno = EACCES; return -1; } u32 read = 0; errcode_t err = 0; // Read from the files data attribute err = ext2fs_file_read(file->fd, ptr, len, &read); if (err || read <= 0 || read > len) { ext2Unlock(file->vd); r->_errno = errno; return err ? err : -1; } // Unlock ext2Unlock(file->vd); return (read == 0) ? -1 : read; }
static errcode_t device_gekko_io_sync(io_channel dev) { gekko_fd *fd = DEV_FD(dev); ext2_log_trace("dev %p\n", dev); // Check that the device can be written to if(!(dev->flags & EXT2_FLAG_RW)) return -1; // Flush any sectors in the disc cache (if required) if (fd->cache) { if (!_EXT2_cache_flush(fd->cache)) { errno = EIO; return EXT2_ET_BLOCK_BITMAP_WRITE; } } return EXT2_ET_OK; }
int ext2_unlink_r (struct _reent *r, const char *name) { ext2_log_trace("name %s\n", name); ext2_vd *vd = NULL; // Get the volume descriptor for this path vd = ext2GetVolume(name); if (!vd) { r->_errno = ENODEV; return -1; } // Unlink the entry int ret = ext2Unlink(vd, name); if (ret) r->_errno = errno; return ret; }
ssize_t ext2_write_r (struct _reent *r, int fd, const char *ptr, size_t len) { ext2_log_trace("fd %p, ptr %p, len %i\n", (void *) fd, ptr, len); ext2_file_state* file = STATE(fd); // Sanity check if (!file || !file->vd || !file->fd) { r->_errno = EINVAL; return -1; } // Short circuit cases where we don't actually have to do anything if (!ptr || len <= 0) { return 0; } // Check that we are allowed to write to this file if (!file->write) { r->_errno = EACCES; return -1; } // Lock ext2Lock(file->vd); u32 writen = 0; // Write to the files data atrribute errcode_t err = ext2fs_file_write(file->fd, ptr, len, &writen); if (writen <= 0 || err) { ext2Unlock(file->vd); r->_errno = errno; return (err ? err : -1); } // Unlock ext2Unlock(file->vd); return (writen == 0 ? -1 : writen); }
int ext2_dirclose_r (struct _reent *r, DIR_ITER *dirState) { ext2_log_trace("dirState %p\n", dirState); if(!dirState) { r->_errno = EINVAL; return -1; } ext2_dir_state* dir = STATE(dirState); // Sanity check if (!dir || !dir->vd) { r->_errno = EBADF; return -1; } // Lock ext2Lock(dir->vd); // Close the directory ext2CloseDir(dir); // Remove the directory from the double-linked FILO list of open directories dir->vd->openDirCount--; if (dir->nextOpenDir) dir->nextOpenDir->prevOpenDir = dir->prevOpenDir; if (dir->prevOpenDir) dir->prevOpenDir->nextOpenDir = dir->nextOpenDir; else dir->vd->firstOpenDir = dir->nextOpenDir; // Unlock ext2Unlock(dir->vd); return 0; }
int ext2_ftruncate_r (struct _reent *r, int fd, off_t len) { ext2_log_trace("fd %p, len %Li\n", (void *) fd, len); ext2_file_state* file = STATE(fd); errcode_t err = 0; // Sanity check if (!file || !file->vd || !file->ni || !file->fd) { r->_errno = EINVAL; return -1; } // Lock ext2Lock(file->vd); // Check that we are allowed to write to this file if (!file->write) { ext2Unlock(file->vd); r->_errno = EACCES; return -1; } err = ext2fs_file_set_size2(file->fd, len); // Sync the file (and its attributes) to disc if(!err) ext2Sync(file->vd, file->ni); // update times ext2UpdateTimes(file->vd, file->ni, EXT2_UPDATE_AMTIME); // Unlock ext2Unlock(file->vd); return err; }
int ext2_fstat_r (struct _reent *r, int fd, struct stat *st) { ext2_log_trace("fd %p\n", (void *) fd); ext2_file_state* file = STATE(fd); int ret = 0; // Sanity check if (!file || !file->vd || !file->ni || !file->fd) { r->_errno = EINVAL; return -1; } // Short circuit cases were we don't actually have to do anything if (!st) return 0; // Get the file stats ret = ext2Stat(file->vd, file->ni, st); if (ret) r->_errno = errno; return ret; }
static s64 device_gekko_io_readbytes(io_channel dev, s64 offset, s64 count, void *buf) { ext2_log_trace("dev %p, offset %lli, count %lli\n", dev, offset, count); // Get the device driver descriptor gekko_fd *fd = DEV_FD(dev); if (!fd) { errno = EBADF; return -1; } // Get the device interface const DISC_INTERFACE* interface = fd->interface; if (!interface) { errno = ENODEV; return -1; } if(offset < 0) { errno = EROFS; return -1; } if(!count) return 0; sec_t sec_start = (sec_t) fd->startSector; sec_t sec_count = 1; u32 buffer_offset = (u32) (offset % fd->sectorSize); u8 *buffer = NULL; // Determine the range of sectors required for this read if (offset > 0) { sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize); } if (buffer_offset+count > fd->sectorSize) { sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) fd->sectorSize); } // Don't read over the partitions limit if(sec_start+sec_count > fd->startSector+fd->sectorCount) { ext2_log_trace("Error: read requested up to sector %lli while partition goes up to %lli\n", (s64) (sec_start+sec_count), (s64) (fd->startSector+fd->sectorCount)); errno = EROFS; return -1; } // If this read happens to be on the sector boundaries then do the read straight into the destination buffer if((buffer_offset == 0) && (count % fd->sectorSize == 0)) { // Read from the device ext2_log_trace("direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count); if (!device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) { ext2_log_trace("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count); errno = EIO; return -1; } // Else read into a buffer and copy over only what was requested } else { // Allocate a buffer to hold the read data buffer = (u8*)mem_alloc(sec_count * fd->sectorSize); if (!buffer) { errno = ENOMEM; return -1; } // Read from the device ext2_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count); ext2_log_trace("count: %d sec_count:%d fd->sectorSize: %d )\n", (u32)count, (u32)sec_count,(u32)fd->sectorSize); if (!device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) { ext2_log_trace("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count); mem_free(buffer); errno = EIO; return -1; } // Copy what was requested to the destination buffer memcpy(buf, buffer + buffer_offset, count); mem_free(buffer); } return count; }
static s64 device_gekko_io_writebytes(io_channel dev, s64 offset, s64 count, const void *buf) { ext2_log_trace("dev %p, offset %lli, count %lli\n", dev, offset, count); // Get the device driver descriptor gekko_fd *fd = DEV_FD(dev); if (!fd) { errno = EBADF; return -1; } if(!(dev->flags & EXT2_FLAG_RW)) return -1; // Get the device interface const DISC_INTERFACE* interface = fd->interface; if (!interface) { errno = ENODEV; return -1; } if(count < 0 || offset < 0) { errno = EROFS; return -1; } if(count == 0) return 0; sec_t sec_start = (sec_t) fd->startSector; sec_t sec_count = 1; u32 buffer_offset = (u32) (offset % fd->sectorSize); u8 *buffer = NULL; // Determine the range of sectors required for this write if (offset > 0) { sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize); } if ((buffer_offset+count) > fd->sectorSize) { sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) fd->sectorSize); } // Don't write over the partitions limit if(sec_start+sec_count > fd->startSector+fd->sectorCount) { ext2_log_trace("Error: write requested up to sector %lli while partition goes up to %lli\n", (s64) (sec_start+sec_count), (s64) (fd->startSector+fd->sectorCount)); errno = EROFS; return -1; } // If this write happens to be on the sector boundaries then do the write straight to disc if((buffer_offset == 0) && (count % fd->sectorSize == 0)) { // Write to the device ext2_log_trace("direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count); if (!device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) { ext2_log_trace("direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count); errno = EIO; return -1; } // Else write from a buffer aligned to the sector boundaries } else { // Allocate a buffer to hold the write data buffer = (u8 *) mem_alloc(sec_count * fd->sectorSize); if (!buffer) { errno = ENOMEM; return -1; } // Read the first and last sectors of the buffer from disc (if required) // NOTE: This is done because the data does not line up with the sector boundaries, // we just read in the buffer edges where the data overlaps with the rest of the disc if(buffer_offset != 0) { if (!device_gekko_io_readsectors(dev, sec_start, 1, buffer)) { ext2_log_trace("read failure @ sector %d\n", sec_start); mem_free(buffer); errno = EIO; return -1; } } if((buffer_offset+count) % fd->sectorSize != 0) { if (!device_gekko_io_readsectors(dev, sec_start + sec_count - 1, 1, buffer + ((sec_count-1) * fd->sectorSize))) { ext2_log_trace("read failure @ sector %d\n", sec_start + sec_count - 1); mem_free(buffer); errno = EIO; return -1; } } // Copy the data into the write buffer memcpy(buffer + buffer_offset, buf, count); // Write to the device ext2_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count); if (!device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) { ext2_log_trace("buffered write failure @ sector %d\n", sec_start); mem_free(buffer); errno = EIO; return -1; } // Free the buffer mem_free(buffer); } return count; }
DIR_ITER *ext2_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path) { ext2_log_trace("dirState %p, path %s\n", dirState, path); if(!dirState) { r->_errno = EINVAL; return NULL; } ext2_dir_state* dir = STATE(dirState); if(!dir) { r->_errno = EINVAL; return NULL; } // Get the volume descriptor for this path dir->vd = ext2GetVolume(path); if (!dir->vd) { r->_errno = ENODEV; return NULL; } // Lock ext2Lock(dir->vd); // Find the directory dir->ni = ext2OpenEntry(dir->vd, path); if (!dir->ni) { ext2Unlock(dir->vd); r->_errno = ENOENT; return NULL; } // Ensure that this directory is indeed a directory if (!LINUX_S_ISDIR(dir->ni->ni.i_mode)) { ext2CloseEntry(dir->vd, dir->ni); ext2Unlock(dir->vd); r->_errno = ENOTDIR; return NULL; } // Read the directory dir->first = dir->current = NULL; if (ext2fs_dir_iterate(dir->vd->fs, dir->ni->ino, 0, 0, DirIterateCallback, dirState) != EXT2_ET_OK) { ext2CloseDir(dir); ext2Unlock(dir->vd); r->_errno = errno; return NULL; } // Move to the first entry in the directory dir->current = dir->first; // Update directory times ext2UpdateTimes(dir->vd, dir->ni, EXT2_UPDATE_ATIME); // Insert the directory into the double-linked FILO list of open directories if (dir->vd->firstOpenDir) { dir->nextOpenDir = dir->vd->firstOpenDir; dir->vd->firstOpenDir->prevOpenDir = dir; } else { dir->nextOpenDir = NULL; } dir->prevOpenDir = NULL; dir->vd->cwd_ni = dir->ni; dir->vd->firstOpenDir = dir; dir->vd->openDirCount++; // Unlock ext2Unlock(dir->vd); return dirState; }
static errcode_t device_gekko_io_open(const char *name, int flags, io_channel *dev) { // Get the device driver descriptor gekko_fd *fd = DEV_FD((*dev)); if (!fd) { errno = EBADF; return -1; } // Get the device interface const DISC_INTERFACE* interface = fd->interface; if (!interface) { errno = ENODEV; return -1; } // Start the device interface and ensure that it is inserted if (!interface->startup()) { ext2_log_trace("device failed to start\n"); errno = EIO; return -1; } if (!interface->isInserted()) { ext2_log_trace("device media is not inserted\n"); errno = EIO; return -1; } // Allocate 4 x max sector size in case of 4096 sector size u8 *buffer = (u8 *) mem_alloc(4 * MAX_SECTOR_SIZE); if(!buffer) { ext2_log_trace("no memory for superblock"); errno = ENOMEM; return -1; } // Check that there is a valid EXT boot sector at the start of the device if (!interface->readSectors(fd->startSector, 4, buffer)) { ext2_log_trace("read failure @ sector %d\n", fd->startSector); errno = EROFS; mem_free(buffer); return -1; } struct ext2_super_block * super = (struct ext2_super_block *) (buffer + SUPERBLOCK_OFFSET); if(ext2fs_le16_to_cpu(super->s_magic) != EXT2_SUPER_MAGIC) { ext2_log_trace("super mismatch: read %04X - expected %04X\n", ext2fs_le16_to_cpu(super->s_magic), EXT2_SUPER_MAGIC); mem_free(buffer); errno = EROFS; return -1; } switch(ext2fs_le32_to_cpu(super->s_log_block_size)) { case 1: (*dev)->block_size = 2048; break; case 2: (*dev)->block_size = 4096; break; case 3: (*dev)->block_size = 8192; break; default: case 0: (*dev)->block_size = 1024; break; } // Parse the boot sector fd->sectorSize = readSectorSize(interface); fd->offset = 0; fd->sectorCount = 0; fd->sectorCount = (sec_t) ((u64) ext2fs_le32_to_cpu(super->s_blocks_count) * (u64) ((*dev)->block_size) / (u64) fd->sectorSize); mem_free(buffer); // Create the cache fd->cache = cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector, fd->startSector + fd->sectorCount, fd->sectorSize); return 0; }
static errcode_t device_gekko_io_open(const char *name, int flags, io_channel *dev) { // Get the device driver descriptor gekko_fd *fd = DEV_FD((*dev)); if (!fd) { errno = EBADF; return -1; } // Get the device interface const DISC_INTERFACE* interface = fd->interface; if (!interface) { errno = ENODEV; return -1; } // Start the device interface and ensure that it is inserted if (!interface->startup()) { ext2_log_trace("device failed to start\n"); errno = EIO; return -1; } if (!interface->isInserted()) { ext2_log_trace("device media is not inserted\n"); errno = EIO; return -1; } struct ext2_super_block * super = (struct ext2_super_block *) mem_alloc(SUPERBLOCK_SIZE); //1024 bytes if(!super) { ext2_log_trace("no memory for superblock"); errno = ENOMEM; return -1; } // Check that there is a valid EXT boot sector at the start of the device if (!interface->readSectors(fd->startSector+SUPERBLOCK_OFFSET/BYTES_PER_SECTOR, SUPERBLOCK_SIZE/BYTES_PER_SECTOR, super)) { ext2_log_trace("read failure @ sector %d\n", fd->startSector); errno = EROFS; mem_free(super); return -1; } if(ext2fs_le16_to_cpu(super->s_magic) != EXT2_SUPER_MAGIC) { mem_free(super); errno = EROFS; return -1; } // Parse the boot sector fd->sectorSize = BYTES_PER_SECTOR; fd->offset = 0; fd->sectorCount = 0; switch(ext2fs_le32_to_cpu(super->s_log_block_size)) { case 1: fd->sectorCount = (sec_t) ((u64) ext2fs_le32_to_cpu(super->s_blocks_count) * (u64) 2048 / (u64) BYTES_PER_SECTOR); break; case 2: fd->sectorCount = (sec_t) ((u64) ext2fs_le32_to_cpu(super->s_blocks_count) * (u64) 4096 / (u64) BYTES_PER_SECTOR); break; case 3: fd->sectorCount = (sec_t) ((u64) ext2fs_le32_to_cpu(super->s_blocks_count) * (u64) 8192 / (u64) BYTES_PER_SECTOR); break; default: case 0: fd->sectorCount = (sec_t) ((u64) ext2fs_le32_to_cpu(super->s_blocks_count) * (u64) 1024 / (u64) BYTES_PER_SECTOR); break; } mem_free(super); // Create the cache fd->cache = _EXT2_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount, fd->sectorSize); return 0; }
int ext2_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) { ext2_log_trace("path %s, buf %p\n", path, buf); ext2_vd *vd = NULL; // Get the volume descriptor for this path vd = ext2GetVolume(path); if (!vd) { r->_errno = ENODEV; return -1; } // Short circuit cases were we don't actually have to do anything if (!buf) return 0; // Lock ext2Lock(vd); // Zero out the stat buffer memset(buf, 0, sizeof(struct statvfs)); // File system block size switch(vd->fs->super->s_log_block_size) { case 1: buf->f_bsize = 2048; break; case 2: buf->f_bsize = 4096; break; case 3: buf->f_bsize = 8192; break; default: case 0: buf->f_bsize = 1024; break; } // Fundamental file system block size buf->f_frsize = buf->f_bsize; // Total number of blocks on file system in units of f_frsize buf->f_blocks = vd->fs->super->s_blocks_count | (((u64) vd->fs->super->s_blocks_count_hi) << 32); // Free blocks available for all and for non-privileged processes buf->f_bfree = vd->fs->super->s_free_blocks_count | (((u64) vd->fs->super->s_free_blocks_hi) << 32); // Number of inodes at this point in time buf->f_files = vd->fs->super->s_inodes_count; // Free inodes available for all and for non-privileged processes buf->f_ffree = vd->fs->super->s_free_inodes_count; // File system id buf->f_fsid = vd->fs->super->s_magic; // Bit mask of f_flag values. buf->f_flag = vd->fs->super->s_flags; // Maximum length of filenames buf->f_namemax = EXT2_NAME_LEN; // Unlock ext2Unlock(vd); return 0; }
int ext2_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { ext2_log_trace("fileStruct %p, path %s, flags %i, mode %i\n", fileStruct, path, flags, mode); ext2_file_state* file = STATE(fileStruct); // Get the volume descriptor for this path file->vd = ext2GetVolume(path); if (!file->vd) { r->_errno = ENODEV; return -1; } // Lock ext2Lock(file->vd); // Determine which mode the file is opened for file->flags = flags; if ((flags & 0x03) == O_RDONLY) { file->read = true; file->write = false; file->append = false; } else if ((flags & 0x03) == O_WRONLY) { file->read = false; file->write = true; file->append = (flags & O_APPEND); } else if ((flags & 0x03) == O_RDWR) { file->read = true; file->write = true; file->append = (flags & O_APPEND); } else { r->_errno = EACCES; ext2Unlock(file->vd); return -1; } // Try and find the file and (if found) ensure that it is not a directory file->ni = ext2OpenEntry(file->vd, path); if (file->ni && LINUX_S_ISDIR(file->ni->ni.i_mode)) { ext2CloseEntry(file->vd, file->ni); ext2Unlock(file->vd); r->_errno = EISDIR; return -1; } // Are we creating this file? if ((flags & O_CREAT) && !file->ni) // Create the file file->ni = ext2Create(file->vd, path, S_IFREG, NULL); // Sanity check, the file should be open by now if (!file->ni) { ext2Unlock(file->vd); r->_errno = ENOENT; return -1; } // Make sure we aren't trying to write to a read-only file if (!(file->vd->fs->flags & EXT2_FLAG_RW) && file->write) { ext2CloseEntry(file->vd, file->ni); ext2Unlock(file->vd); r->_errno = EROFS; return -1; } errcode_t err = ext2fs_file_open2(file->vd->fs, file->ni->ino, &file->ni->ni, file->write ? EXT2_FLAG_RW : 0, &file->fd); if(err != 0) { ext2CloseEntry(file->vd, file->ni); ext2Unlock(file->vd); r->_errno = ENOENT; return -1; } // Truncate the file if requested if ((flags & O_TRUNC) && file->write) { if (ext2fs_file_set_size2(file->fd, 0) != 0) { ext2CloseEntry(file->vd, file->ni); ext2Unlock(file->vd); r->_errno = errno; return -1; } file->ni->ni.i_size = file->ni->ni.i_size_high = 0; } // Set the files current position ext2fs_file_llseek(file->fd, file->append ? EXT2_I_SIZE(&file->ni->ni) : 0, SEEK_SET, 0); ext2_log_trace("file->len %lld\n", EXT2_I_SIZE(&file->ni->ni)); // Update file times ext2UpdateTimes(file->vd, file->ni, EXT2_UPDATE_ATIME); // Insert the file into the double-linked FILO list of open files if (file->vd->firstOpenFile) { file->nextOpenFile = file->vd->firstOpenFile; file->vd->firstOpenFile->prevOpenFile = file; } else { file->nextOpenFile = NULL; } file->prevOpenFile = NULL; file->vd->firstOpenFile = file; file->vd->openFileCount++; // Sync access time ext2Sync(file->vd, file->ni); // Unlock ext2Unlock(file->vd); return (int)fileStruct; }