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_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_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_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; }
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; }
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); // exit(0); // 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); file->is_ntfs = 0; // Unlock ext2Unlock(file->vd); return (int)(s64)fileStruct; }
int ext2_file_to_sectors (struct _reent *r,const char *path,uint32_t *sec_out,uint32_t *size_out,int max,int phys) { ntfs_file_state fileStruct; 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); file->flags = 0; file->read = true; file->write = false; file->append = false; // 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; } // Sanity check, the file should be open by now if (!file->ni) { ext2Unlock(file->vd); r->_errno = ENOENT; return -1; } errcode_t err = ext2fs_file_open2(file->vd->fs, file->ni->ino, &file->ni->ni, 0, &file->fd); if(err != 0) { ext2CloseEntry(file->vd, file->ni); ext2Unlock(file->vd); r->_errno = ENOENT; return -1; } //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); file->is_ntfs = 0; u64 read = 0; err = 0; // Read from the files data attribute //err = ext2fs_file_read(file->fd, ptr, len, &read); u64 len = 0; ext2fs_file_llseek(file->fd, 0, SEEK_END, (__u64 *) &len); // Set the files current position ext2fs_file_llseek(file->fd, 0, SEEK_SET, 0); u32 current_block = 0; err = ext2fs_file_read_sectors(file->fd, len, &read, sec_out, size_out, ¤t_block, max); if (err || read <= 0 || read > len) { ext2Unlock(file->vd); r->_errno = errno; current_block = err ? err : -1; goto end; } end: // 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; ext2Unlock(file->vd); return current_block; }
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; }
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 ext2Link(ext2_vd *vd, const char *old_path, const char *new_path) { ext2_inode_t *dir_ni = NULL, *ni = NULL; char *dir = NULL; char *name = NULL; errcode_t err = 0; // Sanity check if (!vd || !vd->fs) { errno = ENODEV; return -1; } if(!(vd->fs->flags & EXT2_FLAG_RW)) { errno = EACCES; return -1; } // You cannot link between devices if(vd != ext2GetVolume(new_path)) { errno = EXDEV; return -1; } // Get the actual paths of the entry old_path = ext2RealPath(old_path); new_path = ext2RealPath(new_path); if (!old_path || !new_path) return -1; // Lock ext2Lock(vd); //check for existing in new path ni = ext2OpenEntry(vd, new_path); if (ni) { errno = EEXIST; goto cleanup; } dir = strdup(new_path); if (!dir) { errno = ENOMEM; err = -1; goto cleanup; } char * ptr = strrchr(dir, '/'); if (ptr) { name = strdup(ptr+1); *ptr = 0; } else name = strdup(dir); // Find the entry ni = ext2OpenEntry(vd, old_path); if (!ni) { err = -1; goto cleanup; } // Open the entries new parent directory dir_ni = ext2OpenEntry(vd, dir); if (!dir_ni) { err = -1; goto cleanup; } do { // Link the entry to its new parent err = ext2fs_link(vd->fs, dir_ni->ino, name, ni->ino, ext2_file_type(ni->ni.i_mode)); if (err == EXT2_ET_DIR_NO_SPACE) { if (ext2fs_expand_dir(vd->fs, dir_ni->ino) != 0) goto cleanup; } else if(err != EXT2_ET_OK) { errno = EMLINK; goto cleanup; } } while(err == EXT2_ET_DIR_NO_SPACE); ni->ni.i_links_count++; // Update entry times ext2UpdateTimes(vd, ni, EXT2_UPDATE_MCTIME); // Sync the entry to disc ext2Sync(vd, ni); cleanup: if(dir_ni) ext2CloseEntry(vd, dir_ni); if(ni) ext2CloseEntry(vd, ni); if(dir) mem_free(dir); if(name) mem_free(name); // Unlock ext2Unlock(vd); return err; }
ext2_inode_t *ext2Create(ext2_vd *vd, const char *path, mode_t type, const char *target) { ext2_inode_t *dir_ni = NULL, *ni = NULL; char *dir = NULL; char *targetdir = NULL; char *name = NULL; ext2_ino_t newentry = 0; // Sanity check if (!vd || !vd->fs) { errno = ENODEV; return NULL; } if(!(vd->fs->flags & EXT2_FLAG_RW)) { errno = EACCES; return NULL; } // You cannot link between devices if(target) { if(vd != ext2GetVolume(target)) { errno = EXDEV; return NULL; } // Check if existing dir_ni = ext2OpenEntry(vd, target); if (dir_ni) { errno = EEXIST; goto cleanup; } targetdir = strdup(target); if (!targetdir) { errno = ENOMEM; goto cleanup; } target = ext2RealPath(target); } // Get the actual paths of the entry path = ext2RealPath(path); if (!path) goto cleanup; // Lock ext2Lock(vd); // Clean me // NOTE: this looks horrible right now and need a cleanup dir = strdup(path); if (!dir) { errno = ENOMEM; goto cleanup; } char * tmp_path = (targetdir && (type == S_IFLNK)) ? targetdir : dir; if (strrchr(tmp_path, '/') != NULL) { char * ptr = strrchr(tmp_path, '/'); name = strdup(ptr+1); *ptr = '\0'; } else name = strdup(tmp_path); // Open the entries parent directory dir_ni = ext2OpenEntry(vd, dir); if (!dir_ni) goto cleanup; // If not yet read, read the inode and block bitmap if((!vd->fs->inode_map || !vd->fs->block_map)) ext2fs_read_bitmaps(vd->fs); // Symbolic link if(type == S_IFLNK) { if (!target) { errno = EINVAL; goto cleanup; } newentry = ext2CreateSymlink(vd, path, targetdir, name, type); } // Directory else if(type == S_IFDIR) { newentry = ext2CreateMkDir(vd, dir_ni, LINUX_S_IFDIR | (0755 & ~vd->fs->umask), name); } // File else if(type == S_IFREG) { newentry = ext2CreateFile(vd, dir_ni, LINUX_S_IFREG | (0755 & ~vd->fs->umask), name); } // If the entry was created if (newentry != 0) { // Sync the entry to disc ext2Sync(vd, NULL); ni = ext2OpenEntry(vd, target ? target : path); } cleanup: if(dir_ni) ext2CloseEntry(vd, dir_ni); if(name) mem_free(name); if(dir) mem_free(dir); if(targetdir) mem_free(targetdir); // Unlock ext2Unlock(vd); return ni; }