diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c869ebc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: [ master, main, develop ] + pull_request: + branches: [ master, main, develop, feature/**, copilot/** ] + +jobs: + build: + name: Build + runs-on: ubuntu-latest + permissions: + contents: read + container: + image: chocotechnologies/dmod:1.0.4 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Build dmdfs project + run: | + mkdir -p build + cd build + cmake .. -DDMOD_MODE=DMOD_MODULE + cmake --build . + + - name: Verify build artifacts + run: | + echo "Build completed successfully" + ls -lh build/dmf/ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..447993a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,272 @@ +name: Release + +on: + release: + types: [created] + +jobs: + discover-architectures: + name: Discover Architectures + runs-on: ubuntu-latest + permissions: + contents: read + container: + image: chocotechnologies/dmod:1.0.4 + outputs: + architectures: ${{ steps.list-archs.outputs.architectures }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Fetch dmod to discover architectures + run: | + mkdir -p build_discovery + cd build_discovery + cmake .. -DDMOD_MODE=DMOD_MODULE + + - name: List available architectures + id: list-archs + run: | + DMOD_SRC_DIR=$(find build_discovery -path "*/_deps/dmod-src" -type d | head -1) + + # create JSON array + ARCHS=$(find ${DMOD_SRC_DIR}/configs/arch -name "tools-cfg.cmake" | \ + sed "s|${DMOD_SRC_DIR}/configs/arch/||g" | \ + sed 's|/tools-cfg.cmake||g' | \ + jq -R -s -c 'split("\n") | map(select(length > 0))') + + echo "Found architectures: $ARCHS" + echo "architectures=$ARCHS" >> $GITHUB_OUTPUT + + build-release: + name: Build Release for ${{ matrix.arch_name }} + needs: discover-architectures + runs-on: ubuntu-latest + permissions: + contents: write + strategy: + matrix: + arch_name: ${{ fromJson(needs.discover-architectures.outputs.architectures) }} + + container: + image: chocotechnologies/dmod:1.0.4 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Extract version from tag + id: get_version + run: | + # Extract version from tag (e.g., v1.2 -> 1.2) + VERSION="${{ github.event.release.tag_name }}" + VERSION="${VERSION#v}" # Remove 'v' prefix if present + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Extracted version: $VERSION" + + - name: Build dmdfs for ${{ matrix.arch_name }} + run: | + set -e + ARCH_DIR_NAME=$(echo "${{ matrix.arch_name }}" | sed 's|/|-|') + echo "ARCH_DIR_NAME=$ARCH_DIR_NAME" >> $GITHUB_ENV + echo "ARTIFACT_NAME=release-$ARCH_DIR_NAME" >> $GITHUB_ENV + mkdir -p build_$ARCH_DIR_NAME + cd build_$ARCH_DIR_NAME + + # First run cmake to fetch dependencies with version from tag + cmake .. -DDMOD_TOOLS_NAME=arch/${{ matrix.arch_name }} -DDMOD_MODULE_VERSION="${{ steps.get_version.outputs.version }}" + + # Build the modules + cmake --build . + + echo "Build completed for ${{ matrix.arch_name }}" + ls -la dmf/ + ls -la dmfc/ + + - name: Prepare release package + run: | + set -e + mkdir -p release_package + BUILD_DIR=build_$ARCH_DIR_NAME + DMF_DIR="$BUILD_DIR/dmf" + DMFC_DIR="$BUILD_DIR/dmfc" + + cp $DMF_DIR/dmdfs.dmf release_package/ + cp $DMF_DIR/dmdfs_version.txt release_package/ + cp $DMFC_DIR/dmdfs.dmfc release_package/ + # Copy .dmd file if it exists + if [ -f $DMF_DIR/dmdfs.dmd ]; then + cp $DMF_DIR/dmdfs.dmd release_package/ + fi + + # Copy documentation and license + cp README.md release_package/ + cp LICENSE release_package/ + + # Create release notes file from GitHub release + echo "${{ github.event.release.body }}" > release_package/RELEASE_NOTES.txt + + echo "Package contents:" + ls -la release_package/ + + - name: Create release archive + run: | + cd release_package + zip -r ../dmdfs-${{ github.event.release.tag_name }}-$ARCH_DIR_NAME.zip . + cd .. + echo "Created archive:" + ls -lh dmdfs-*.zip + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME }} + path: dmdfs-${{ github.event.release.tag_name }}-*.zip + retention-days: 1 + + generate-versions-manifest: + name: Generate versions.dmm + needs: discover-architectures + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history to get all tags + + - name: Generate versions.dmm + run: | + set -e + echo "# List of available versions for dmdfs modules" > versions.dmm + echo "# Generated automatically by CI" >> versions.dmm + echo "" >> versions.dmm + + # Get all version tags (starting with 'v') and extract version numbers + VERSIONS=$(git tag -l 'v*' | sed 's/^v//' | sort -V | tr '\n' ' ' | sed 's/ $//') + + # Remove vlatest from the list if present + VERSIONS=$(echo $VERSIONS | sed 's/\blatest\b//g' | xargs) + + if [ -z "$VERSIONS" ]; then + echo "Warning: No version tags found" + VERSIONS="${{ github.event.release.tag_name }}" + VERSIONS="${VERSIONS#v}" + fi + + echo "Found versions: $VERSIONS" + + # Add $version-available directive for dmdfs module + echo "\$version-available dmdfs $VERSIONS" >> versions.dmm + + echo "Generated versions.dmm:" + cat versions.dmm + + - name: Upload versions.dmm as artifact + uses: actions/upload-artifact@v4 + with: + name: versions-manifest + path: versions.dmm + retention-days: 1 + + upload-release-assets: + name: Upload Release Assets + needs: [build-release, generate-versions-manifest] + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Display artifact structure + run: | + echo "Downloaded artifacts:" + ls -lR artifacts/ + + - name: Upload release assets to versioned tag + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + set -e + # Upload all release archives to the GitHub release + shopt -s nullglob + zip_files=(artifacts/release-*/*.zip) + + if [ ${#zip_files[@]} -eq 0 ]; then + echo "Error: No artifacts found to upload" + exit 1 + fi + + for zip_file in "${zip_files[@]}"; do + echo "Uploading $zip_file to ${{ github.event.release.tag_name }}..." + gh release upload ${{ github.event.release.tag_name }} \ + "$zip_file" \ + --repo ${{ github.repository }} \ + --clobber + done + + # Upload versions.dmm to the versioned release + if [ -f artifacts/versions-manifest/versions.dmm ]; then + echo "Uploading versions.dmm to ${{ github.event.release.tag_name }}..." + gh release upload ${{ github.event.release.tag_name }} \ + artifacts/versions-manifest/versions.dmm \ + --repo ${{ github.repository }} \ + --clobber + fi + + echo "Successfully uploaded ${#zip_files[@]} artifact(s) to ${{ github.event.release.tag_name }}" + + - name: Create or update latest release + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + set -e + + # Check if vlatest release exists + if gh release view vlatest --repo ${{ github.repository }} >/dev/null 2>&1; then + echo "Release vlatest exists, deleting it..." + gh release delete vlatest --repo ${{ github.repository }} --yes + fi + + # Create new vlatest release + echo "Creating vlatest release..." + gh release create vlatest \ + --repo ${{ github.repository }} \ + --title "Latest Release (based on ${{ github.event.release.tag_name }})" \ + --notes "This release always points to the latest stable version. Currently based on ${{ github.event.release.tag_name }}." + + - name: Upload release assets to latest tag + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + set -e + shopt -s nullglob + zip_files=(artifacts/release-*/*.zip) + + for zip_file in "${zip_files[@]}"; do + echo "Uploading $zip_file to vlatest..." + gh release upload vlatest \ + "$zip_file" \ + --repo ${{ github.repository }} \ + --clobber + done + + # Upload versions.dmm to the latest release + if [ -f artifacts/versions-manifest/versions.dmm ]; then + echo "Uploading versions.dmm to vlatest..." + gh release upload vlatest \ + artifacts/versions-manifest/versions.dmm \ + --repo ${{ github.repository }} \ + --clobber + fi + + echo "Successfully uploaded ${#zip_files[@]} artifact(s) to vlatest" diff --git a/.gitignore b/.gitignore index 1f99f9d..788d9b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,16 @@ -CMakeLists.txt.user -CMakeCache.txt -CMakeFiles -CMakeScripts -Testing -Makefile -cmake_install.cmake -install_manifest.txt -compile_commands.json -CTestTestfile.cmake -_deps -CMakeUserPresets.json +# Build directories +build/ +build_*/ +_codeql_build_dir/ +_codeql_detected_source_root +*.dmf +*.dmfc -# CLion -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#cmake-build-* +# IDE +.vscode/ +.idea/ + +# Temporary files +*.tmp +*.swp +*~ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b4606aa --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,90 @@ +# ===================================================================== +# DMOD Driver File System Module +# ===================================================================== +cmake_minimum_required(VERSION 3.18) + + +# ====================================================================== +# DMOD DFS +# ====================================================================== +# Allow version to be passed as a parameter, default to 0.1 +if(NOT DEFINED DMOD_MODULE_VERSION) + set(DMOD_MODULE_VERSION "0.1" CACHE STRING "DMOD module version") +endif() + +# ====================================================================== +# Fetch DMOD repository +# ====================================================================== +include(FetchContent) +FetchContent_Declare( + dmod + GIT_REPOSITORY https://github.com/choco-technologies/dmod.git + GIT_TAG develop +) + +# ====================================================================== +# DMOD Configuration +# ====================================================================== +set(DMOD_MODE "DMOD_MODULE" CACHE STRING "DMOD build mode") +set(DMOD_BUILD_TESTS OFF CACHE BOOL "Build tests") +set(DMOD_BUILD_EXAMPLES OFF CACHE BOOL "Build examples") +set(DMOD_BUILD_TOOLS OFF CACHE BOOL "Build tools") +set(DMOD_BUILD_TEMPLATES OFF CACHE BOOL "Build templates") + +FetchContent_MakeAvailable(dmod) + +project(dmdfs + VERSION ${DMOD_MODULE_VERSION} + DESCRIPTION "DMOD Driver File System" + LANGUAGES C CXX) + +# ====================================================================== +# Import dmod functions and macros +# ====================================================================== +set(DMOD_DIR ${dmod_SOURCE_DIR} CACHE PATH "DMOD source directory") +include(${DMOD_DIR}/paths.cmake) +dmod_setup_external_module() + +# ====================================================================== +# Fetch DMOD File System Interface +# ====================================================================== +FetchContent_Declare( + dmfsi + GIT_REPOSITORY + https://github.com/choco-technologies/dmfsi.git + GIT_TAG master +) +FetchContent_MakeAvailable(dmfsi) + +# ====================================================================== +# DMDFS Module Configuration +# ====================================================================== +# Name of the module +set(DMOD_MODULE_NAME dmdfs) + +# Version is already set above and used in project() +# No need to set it again here + +# Author (should be string) +set(DMOD_AUTHOR_NAME Patryk Kubiak) + +# Stack size for the module (should be integer) +set(DMOD_STACK_SIZE 1024) + +# +# dmod_add_library - create a library module +# it has the same signature as add_library +# and can be used in the same way after the creation +# (for example, to link libraries) +# +dmod_add_library(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION} + # List of source files - can include C and C++ files + src/dmdfs.c +) + +target_include_directories(${DMOD_MODULE_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include +) + +# Link to DMFSI interface +target_link_libraries(${DMOD_MODULE_NAME} dmfsi_if) diff --git a/README.md b/README.md index 8114776..f224991 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,201 @@ # dmdfs -DMOD Driver File System + +DMOD Driver File System - A driver-based file system module for embedded systems. + +## Overview + +`dmdfs` (DMOD Driver File System) is a file system implementation that provides an interface to access files through hardware drivers or external storage. It is built on the **DMOD (Dynamic Modules)** framework and implements the **DMFSI (DMOD File System Interface)**, making it compatible with **DMVFS (DMOD Virtual File System)** and other DMOD-based applications. + +### Key Features + +- **Driver-Based**: Interfaces with hardware drivers for storage access +- **DMFSI Compatible**: Implements the standard DMOD file system interface +- **DMVFS Integration**: Can be mounted as a file system in DMVFS +- **Modular Design**: Built on DMOD framework for easy integration + +## Architecture + +DMDFS is part of a modular embedded file system architecture built on DMOD: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Application Layer │ +│ (Your embedded application code) │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ DMVFS (Virtual File System) │ +│ • Unified file system interface │ +│ • Multiple mount points │ +│ • Path resolution │ +│ https://github.com/choco-technologies/dmvfs │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ DMFSI (DMOD File System Interface) │ +│ • Standardized POSIX-like API │ +│ • Common interface for all file systems │ +│ https://github.com/choco-technologies/dmfsi │ +└─────────────────────────────────────────────────────────────┘ + │ + ┌─────────────────┼─────────────────┐ + ▼ ▼ ▼ +┌────────────────┐ ┌─────────────┐ ┌─────────────┐ +│ DMDFS (Driver) │ │ DMFFS (Flash│ │ DMRAMFS (RAM│ +│ Driver-based │ │ Read-only │ │ Temporary │ +│ (This Project) │ │ │ │ │ +└────────────────┘ └─────────────┘ └─────────────┘ + │ │ │ + ▼ ▼ ▼ +┌────────────────┐ ┌─────────────┐ ┌─────────────┐ +│ Hardware Driver│ │ Flash Memory│ │ RAM │ +└────────────────┘ └─────────────┘ └─────────────┘ +``` + +### Component Relationships + +- **[DMOD](https://github.com/choco-technologies/dmod)**: The foundation providing dynamic module loading, inter-module communication, and resource management +- **[DMFSI](https://github.com/choco-technologies/dmfsi)**: Defines the standard file system interface that DMDFS implements +- **[DMVFS](https://github.com/choco-technologies/dmvfs)**: Virtual file system layer that can mount DMDFS at any path in a unified directory tree +- **DMDFS**: This project - implements DMFSI to provide access to driver-based storage + +## Building + +```bash +mkdir build +cd build +cmake .. -DDMOD_MODE=DMOD_MODULE +cmake --build . +``` + +## Usage + +The module can be loaded and mounted using DMVFS: + +```c +#include "dmvfs.h" + +// Initialize DMVFS +dmvfs_init(16, 32); + +// Mount the driver filesystem at /mnt +dmvfs_mount_fs("dmdfs", "/mnt", NULL); + +// Use standard file operations +void* fp; +dmvfs_fopen(&fp, "/mnt/file.txt", DMFSI_O_RDONLY, 0, 0); +// ... use file ... +dmvfs_fclose(fp); + +// Unmount when done +dmvfs_unmount_fs("/mnt"); +dmvfs_deinit(); +``` + +## API + +The module implements the full DMFSI interface: + +### File Operations +- `_fopen` - Open a file +- `_fclose` - Close a file +- `_fread` - Read from a file +- `_fwrite` - Write to a file +- `_lseek` - Seek to a position +- `_tell` - Get current position +- `_eof` - Check for end of file +- `_size` - Get file size +- `_getc` - Read a single character +- `_putc` - Write a single character +- `_sync` - Sync file +- `_fflush` - Flush buffers + +### Directory Operations +- `_mkdir` - Create a directory +- `_opendir` - Open a directory for reading +- `_readdir` - Read directory entries +- `_closedir` - Close a directory +- `_direxists` - Check if directory exists + +### File Management +- `_stat` - Get file/directory statistics +- `_unlink` - Delete a file +- `_rename` - Rename a file + +## Project Structure + +``` +dmdfs/ +├── include/ +│ └── dmdfs.h # Public header +├── src/ +│ └── dmdfs.c # Main DMDFS implementation +├── CMakeLists.txt # CMake build configuration +├── manifest.dmm # DMOD manifest file +├── README.md # This file +└── LICENSE # License file +``` + +## Development Status + +**Note**: This is an initial implementation with the basic structure in place. The actual driver integration and file operations are marked with TODO comments and need to be implemented based on specific hardware driver requirements. + +## Integration into Your Project + +### Using CMake FetchContent + +```cmake +include(FetchContent) + +# Fetch DMDFS +FetchContent_Declare( + dmdfs + GIT_REPOSITORY https://github.com/choco-technologies/dmdfs.git + GIT_TAG main +) + +# Set DMOD mode +set(DMOD_MODE "DMOD_MODULE" CACHE STRING "DMOD build mode") + +FetchContent_MakeAvailable(dmdfs) + +# Link to your target +target_link_libraries(your_target PRIVATE dmdfs) +``` + +### Manual Integration + +1. Clone the repository: `git clone https://github.com/choco-technologies/dmdfs.git` +2. Add as subdirectory: `add_subdirectory(dmdfs)` +3. Link library: `target_link_libraries(your_target dmdfs)` + +## Contributing + +Contributions are welcome! Please: +1. Fork the repository +2. Create a feature branch +3. Make your changes with tests +4. Submit a pull request + +## Related Projects + +- **[DMOD](https://github.com/choco-technologies/dmod)** - Dynamic module system +- **[DMFSI](https://github.com/choco-technologies/dmfsi)** - File system interface specification +- **[DMVFS](https://github.com/choco-technologies/dmvfs)** - Virtual file system implementation +- **[DMFFS](https://github.com/choco-technologies/dmffs)** - Flash file system implementation +- **[DMRAMFS](https://github.com/choco-technologies/dmramfs)** - RAM file system implementation + +## License + +See [LICENSE](LICENSE) file for details. + +## Author + +Patryk Kubiak + +## Support + +For questions, issues, or feature requests, please open an issue on GitHub: +https://github.com/choco-technologies/dmdfs/issues diff --git a/include/dmdfs.h b/include/dmdfs.h new file mode 100644 index 0000000..f4d2d69 --- /dev/null +++ b/include/dmdfs.h @@ -0,0 +1,22 @@ +/** + * @file dmdfs.h + * @brief DMOD Driver File System - Public header + * @author Patryk Kubiak + */ + +#ifndef DMDFS_H +#define DMDFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Module version +#define DMDFS_VERSION_MAJOR 0 +#define DMDFS_VERSION_MINOR 1 + +#ifdef __cplusplus +} +#endif + +#endif // DMDFS_H diff --git a/manifest.dmm b/manifest.dmm new file mode 100644 index 0000000..6485918 --- /dev/null +++ b/manifest.dmm @@ -0,0 +1,5 @@ +# Include dynamically generated versions list from latest release +$include https://github.com/choco-technologies/dmdfs/releases/download/vlatest/versions.dmm + +# Module entries with version placeholder - will be expanded by $version-available +dmdfs https://github.com/choco-technologies/dmdfs/releases/download/v/dmdfs-v-.zip diff --git a/src/dmdfs.c b/src/dmdfs.c new file mode 100644 index 0000000..66332e2 --- /dev/null +++ b/src/dmdfs.c @@ -0,0 +1,408 @@ +/** + * @file dmdfs.c + * @brief DMOD Driver File System - Implementation + * @author Patryk Kubiak + * + * This is a driver-based file system that provides an interface to access + * files through hardware drivers or external storage. + */ + +#define DMOD_ENABLE_REGISTRATION ON +#define ENABLE_DIF_REGISTRATIONS ON +#include "dmod.h" +#include "dmdfs.h" +#include "dmfsi.h" +#include + +/** + * @brief Magic number for DMDFS context validation + */ +#define DMDFS_CONTEXT_MAGIC 0x444D4446 // 'DMDF' + +/** + * @brief File system context structure + */ +struct dmfsi_context +{ + uint32_t magic; + void* driver_context; // Driver-specific context +}; + +// ============================================================================ +// Module Interface Implementation +// ============================================================================ + +/** + * @brief Module pre-initialization (optional) + */ +void dmod_preinit(void) +{ + // Nothing to do +} + +/** + * @brief Module initialization + */ +int dmod_init(const Dmod_Config_t *Config) +{ + // Nothing to do + return 0; +} + +/** + * @brief Module deinitialization + */ +int dmod_deinit(void) +{ + // Nothing to do + return 0; +} + +// ============================================================================ +// DMFSI Interface Implementation +// ============================================================================ + +/** + * @brief Initialize the file system + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, dmfsi_context_t, _init, (const char* config) ) +{ + dmfsi_context_t ctx = Dmod_Malloc(sizeof(struct dmfsi_context)); + if (ctx == NULL) + { + DMOD_LOG_ERROR("dmdfs: Failed to allocate memory for context\n"); + return NULL; + } + + ctx->magic = DMDFS_CONTEXT_MAGIC; + ctx->driver_context = NULL; + + // TODO: Initialize driver context based on config + + return ctx; +} + +/** + * @brief Deinitialize the file system + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _deinit, (dmfsi_context_t ctx) ) +{ + if (ctx) + { + // TODO: Cleanup driver context + Dmod_Free(ctx); + } + return DMFSI_OK; +} + +/** + * @brief Validate the file system context + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _context_is_valid, (dmfsi_context_t ctx) ) +{ + return (ctx && ctx->magic == DMDFS_CONTEXT_MAGIC) ? 1 : 0; +} + +/** + * @brief Open a file + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _fopen, (dmfsi_context_t ctx, void** fp, const char* path, int mode, int attr) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in fopen\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement file opening through driver + DMOD_LOG_ERROR("dmdfs: fopen not yet implemented\n"); + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Close a file + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _fclose, (dmfsi_context_t ctx, void* fp) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in fclose\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement file closing + DMOD_LOG_ERROR("dmdfs: fclose not yet implemented\n"); + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Read from a file + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _fread, (dmfsi_context_t ctx, void* fp, void* buffer, size_t size, size_t* read) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in fread\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement file reading + if (read) *read = 0; + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Write to a file + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _fwrite, (dmfsi_context_t ctx, void* fp, const void* buffer, size_t size, size_t* written) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in fwrite\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement file writing + if (written) *written = 0; + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Seek to a position in a file + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _lseek, (dmfsi_context_t ctx, void* fp, long offset, int whence) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in lseek\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement file seeking + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Get current position in a file + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, long, _tell, (dmfsi_context_t ctx, void* fp) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in tell\n"); + return -1; + } + + // TODO: Implement position retrieval + return -1; +} + +/** + * @brief Check if at end of file + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _eof, (dmfsi_context_t ctx, void* fp) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in eof\n"); + return 1; + } + + // TODO: Implement EOF checking + return 1; +} + +/** + * @brief Get file size + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, long, _size, (dmfsi_context_t ctx, void* fp) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in size\n"); + return -1; + } + + // TODO: Implement size retrieval + return -1; +} + +/** + * @brief Read a single character + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _getc, (dmfsi_context_t ctx, void* fp) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in getc\n"); + return -1; + } + + // TODO: Implement character reading + return -1; +} + +/** + * @brief Write a single character + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _putc, (dmfsi_context_t ctx, void* fp, char c) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in putc\n"); + return -1; + } + + // TODO: Implement character writing + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Flush file buffers + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _fflush, (dmfsi_context_t ctx, void* fp) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in fflush\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement buffer flushing + return DMFSI_OK; +} + +/** + * @brief Sync file to storage + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _sync, (dmfsi_context_t ctx, void* fp) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in sync\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement sync + return DMFSI_OK; +} + +/** + * @brief Open a directory + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _opendir, (dmfsi_context_t ctx, void** dp, const char* path) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in opendir\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement directory opening + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Read directory entry + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _readdir, (dmfsi_context_t ctx, void* dp, dmfsi_dir_entry_t* entry) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in readdir\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement directory reading + return DMFSI_ERR_NOT_FOUND; +} + +/** + * @brief Close a directory + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _closedir, (dmfsi_context_t ctx, void* dp) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in closedir\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement directory closing + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Create a directory + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _mkdir, (dmfsi_context_t ctx, const char* path) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in mkdir\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement directory creation + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Check if directory exists + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _direxists, (dmfsi_context_t ctx, const char* path) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in direxists\n"); + return 0; + } + + // TODO: Implement directory existence check + return 0; +} + +/** + * @brief Get file/directory statistics + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _stat, (dmfsi_context_t ctx, const char* path, dmfsi_stat_t* stat) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in stat\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement stat + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Delete a file + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _unlink, (dmfsi_context_t ctx, const char* path) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in unlink\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement file deletion + return DMFSI_ERR_GENERAL; +} + +/** + * @brief Rename a file + */ +dmod_dmfsi_dif_api_declaration( 1.0, dmdfs, int, _rename, (dmfsi_context_t ctx, const char* oldpath, const char* newpath) ) +{ + if(dmfsi_dmdfs_context_is_valid(ctx) == 0) + { + DMOD_LOG_ERROR("dmdfs: Invalid context in rename\n"); + return DMFSI_ERR_INVALID; + } + + // TODO: Implement file renaming + return DMFSI_ERR_GENERAL; +}