Files
herolib/lib/vfs/vfs_local/vfs_implementation.v
2025-02-27 11:42:46 +03:00

279 lines
7.7 KiB
V

module vfs_local
import os
import freeflowuniverse.herolib.vfs
// Basic operations
pub fn (myvfs LocalVFS) root_get() !vfs.FSEntry {
if !os.exists(myvfs.root_path) {
return error('Root path does not exist: ${myvfs.root_path}')
}
metadata := myvfs.os_attr_to_metadata(myvfs.root_path) or {
return error('Failed to get root metadata: ${err}')
}
return LocalFSEntry{
path: ''
metadata: metadata
}
}
// File operations with improved error handling and TOCTOU protection
pub fn (myvfs LocalVFS) file_create(path string) !vfs.FSEntry {
abs_path := myvfs.abs_path(path)
if os.exists(abs_path) {
return error('File already exists: ${path}')
}
os.write_file(abs_path, '') or { return error('Failed to create file ${path}: ${err}') }
metadata := myvfs.os_attr_to_metadata(abs_path) or {
return error('Failed to get metadata: ${err}')
}
return LocalFSEntry{
path: path
metadata: metadata
}
}
pub fn (myvfs LocalVFS) file_read(path string) ![]u8 {
abs_path := myvfs.abs_path(path)
if !os.exists(abs_path) {
return error('File does not exist: ${path}')
}
if os.is_dir(abs_path) {
return error('Path is a directory: ${path}')
}
return os.read_bytes(abs_path) or { return error('Failed to read file ${path}: ${err}') }
}
pub fn (myvfs LocalVFS) file_write(path string, data []u8) ! {
abs_path := myvfs.abs_path(path)
if os.is_dir(abs_path) {
return error('Cannot write to directory: ${path}')
}
os.write_file(abs_path, data.bytestr()) or {
return error('Failed to write file ${path}: ${err}')
}
}
pub fn (myvfs LocalVFS) file_delete(path string) ! {
abs_path := myvfs.abs_path(path)
if !os.exists(abs_path) {
return error('File does not exist: ${path}')
}
if os.is_dir(abs_path) {
return error('Cannot delete directory using file_delete: ${path}')
}
os.rm(abs_path) or { return error('Failed to delete file ${path}: ${err}') }
}
// Directory operations with improved error handling
pub fn (myvfs LocalVFS) dir_create(path string) !vfs.FSEntry {
abs_path := myvfs.abs_path(path)
if os.exists(abs_path) {
return error('Path already exists: ${path}')
}
os.mkdir_all(abs_path) or { return error('Failed to create directory ${path}: ${err}') }
metadata := myvfs.os_attr_to_metadata(abs_path) or {
return error('Failed to get metadata: ${err}')
}
return LocalFSEntry{
path: path
metadata: metadata
}
}
pub fn (myvfs LocalVFS) dir_list(path string) ![]vfs.FSEntry {
abs_path := myvfs.abs_path(path)
if !os.exists(abs_path) {
return error('Directory does not exist: ${path}')
}
if !os.is_dir(abs_path) {
return error('Path is not a directory: ${path}')
}
entries := os.ls(abs_path) or { return error('Failed to list directory ${path}: ${err}') }
mut result := []vfs.FSEntry{cap: entries.len}
for entry in entries {
rel_path := os.join_path(path, entry)
abs_entry_path := os.join_path(abs_path, entry)
metadata := myvfs.os_attr_to_metadata(abs_entry_path) or { continue } // Skip entries we can't stat
result << LocalFSEntry{
path: rel_path
metadata: metadata
}
}
return result
}
pub fn (myvfs LocalVFS) dir_delete(path string) ! {
abs_path := myvfs.abs_path(path)
if !os.exists(abs_path) {
return error('Directory does not exist: ${path}')
}
if !os.is_dir(abs_path) {
return error('Path is not a directory: ${path}')
}
os.rmdir_all(abs_path) or { return error('Failed to delete directory ${path}: ${err}') }
}
// Symlink operations with improved handling
pub fn (myvfs LocalVFS) link_create(target_path string, link_path string) !vfs.FSEntry {
abs_target := myvfs.abs_path(target_path)
abs_link := myvfs.abs_path(link_path)
if !os.exists(abs_target) {
return error('Target path does not exist: ${target_path}')
}
if os.exists(abs_link) {
return error('Link path already exists: ${link_path}')
}
os.symlink(target_path, abs_link) or {
return error('Failed to create symlink from ${target_path} to ${link_path}: ${err}')
}
metadata := myvfs.os_attr_to_metadata(abs_link) or {
return error('Failed to get metadata: ${err}')
}
return LocalFSEntry{
path: link_path
metadata: metadata
}
}
pub fn (myvfs LocalVFS) link_read(path string) !string {
abs_path := myvfs.abs_path(path)
if !os.exists(abs_path) {
return error('Symlink does not exist: ${path}')
}
if !os.is_link(abs_path) {
return error('Path is not a symlink: ${path}')
}
real_path := os.real_path(abs_path)
return os.base(real_path)
}
pub fn (myvfs LocalVFS) link_delete(path string) ! {
abs_path := myvfs.abs_path(path)
if !os.exists(abs_path) {
return error('Symlink does not exist: ${path}')
}
if !os.is_link(abs_path) {
return error('Path is not a symlink: ${path}')
}
os.rm(abs_path) or { return error('Failed to delete symlink ${path}: ${err}') }
}
// Common operations with improved error handling
pub fn (myvfs LocalVFS) exists(path string) bool {
// TODO: check is link if link the link can be broken but it stil exists
return os.exists(myvfs.abs_path(path))
}
pub fn (myvfs LocalVFS) get(path string) !vfs.FSEntry {
abs_path := myvfs.abs_path(path)
if !os.exists(abs_path) {
return error('Entry does not exist: ${path}')
}
metadata := myvfs.os_attr_to_metadata(abs_path) or {
return error('Failed to get metadata: ${err}')
}
return LocalFSEntry{
path: path
metadata: metadata
}
}
pub fn (myvfs LocalVFS) rename(old_path string, new_path string) !vfs.FSEntry {
abs_old := myvfs.abs_path(old_path)
abs_new := myvfs.abs_path(new_path)
if !os.exists(abs_old) {
return error('Source path does not exist: ${old_path}')
}
if os.exists(abs_new) {
return error('Destination path already exists: ${new_path}')
}
os.mv(abs_old, abs_new) or {
return error('Failed to rename ${old_path} to ${new_path}: ${err}')
}
metadata := myvfs.os_attr_to_metadata(abs_new) or {
return error('Failed to get metadata: ${err}')
}
return LocalFSEntry{
path: abs_new
metadata: metadata
}
}
pub fn (myvfs LocalVFS) copy(src_path string, dst_path string) !vfs.FSEntry {
abs_src := myvfs.abs_path(src_path)
abs_dst := myvfs.abs_path(dst_path)
if !os.exists(abs_src) {
return error('Source path does not exist: ${src_path}')
}
if os.exists(abs_dst) {
return error('Destination path already exists: ${dst_path}')
}
os.cp(abs_src, abs_dst) or { return error('Failed to copy ${src_path} to ${dst_path}: ${err}') }
metadata := myvfs.os_attr_to_metadata(abs_dst) or {
return error('Failed to get metadata: ${err}')
}
return LocalFSEntry{
path: dst_path
metadata: metadata
}
}
pub fn (myvfs LocalVFS) move(src_path string, dst_path string) !vfs.FSEntry {
abs_src := myvfs.abs_path(src_path)
abs_dst := myvfs.abs_path(dst_path)
if !os.exists(abs_src) {
return error('Source path does not exist: ${src_path}')
}
if os.exists(abs_dst) {
return error('Destination path already exists: ${dst_path}')
}
os.mv(abs_src, abs_dst) or { return error('Failed to move ${src_path} to ${dst_path}: ${err}') }
metadata := myvfs.os_attr_to_metadata(abs_dst) or {
return error('Failed to get metadata: ${err}')
}
return LocalFSEntry{
path: dst_path
metadata: metadata
}
}
// Generic delete operation that handles all types
pub fn (myvfs LocalVFS) delete(path string) ! {
abs_path := myvfs.abs_path(path)
if !os.exists(abs_path) {
return error('Path does not exist: ${path}')
}
if os.is_link(abs_path) {
myvfs.link_delete(path)!
} else if os.is_dir(abs_path) {
myvfs.dir_delete(path)!
} else {
myvfs.file_delete(path)!
}
}
// Destroy the vfscore by removing all its contents
pub fn (mut myvfs LocalVFS) destroy() ! {
if !os.exists(myvfs.root_path) {
return error('vfscore root path does not exist: ${myvfs.root_path}')
}
os.rmdir_all(myvfs.root_path) or {
return error('Failed to destroy vfscore at ${myvfs.root_path}: ${err}')
}
myvfs.init()!
}