119ea8026Sopenharmony_ci/* 219ea8026Sopenharmony_ci * Block device emulated in a file 319ea8026Sopenharmony_ci * 419ea8026Sopenharmony_ci * Copyright (c) 2022, The littlefs authors. 519ea8026Sopenharmony_ci * Copyright (c) 2017, Arm Limited. All rights reserved. 619ea8026Sopenharmony_ci * SPDX-License-Identifier: BSD-3-Clause 719ea8026Sopenharmony_ci */ 819ea8026Sopenharmony_ci#include "bd/lfs_filebd.h" 919ea8026Sopenharmony_ci 1019ea8026Sopenharmony_ci#include <fcntl.h> 1119ea8026Sopenharmony_ci#include <unistd.h> 1219ea8026Sopenharmony_ci#include <errno.h> 1319ea8026Sopenharmony_ci 1419ea8026Sopenharmony_ci#ifdef _WIN32 1519ea8026Sopenharmony_ci#include <windows.h> 1619ea8026Sopenharmony_ci#endif 1719ea8026Sopenharmony_ci 1819ea8026Sopenharmony_ciint lfs_filebd_create(const struct lfs_config *cfg, const char *path, 1919ea8026Sopenharmony_ci const struct lfs_filebd_config *bdcfg) { 2019ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, " 2119ea8026Sopenharmony_ci ".read=%p, .prog=%p, .erase=%p, .sync=%p}, " 2219ea8026Sopenharmony_ci "\"%s\", " 2319ea8026Sopenharmony_ci "%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", " 2419ea8026Sopenharmony_ci ".erase_size=%"PRIu32", .erase_count=%"PRIu32"})", 2519ea8026Sopenharmony_ci (void*)cfg, cfg->context, 2619ea8026Sopenharmony_ci (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, 2719ea8026Sopenharmony_ci (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, 2819ea8026Sopenharmony_ci path, 2919ea8026Sopenharmony_ci (void*)bdcfg, 3019ea8026Sopenharmony_ci bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size, 3119ea8026Sopenharmony_ci bdcfg->erase_count); 3219ea8026Sopenharmony_ci lfs_filebd_t *bd = cfg->context; 3319ea8026Sopenharmony_ci bd->cfg = bdcfg; 3419ea8026Sopenharmony_ci 3519ea8026Sopenharmony_ci // open file 3619ea8026Sopenharmony_ci #ifdef _WIN32 3719ea8026Sopenharmony_ci bd->fd = open(path, O_RDWR | O_CREAT | O_BINARY, 0666); 3819ea8026Sopenharmony_ci #else 3919ea8026Sopenharmony_ci bd->fd = open(path, O_RDWR | O_CREAT, 0666); 4019ea8026Sopenharmony_ci #endif 4119ea8026Sopenharmony_ci 4219ea8026Sopenharmony_ci if (bd->fd < 0) { 4319ea8026Sopenharmony_ci int err = -errno; 4419ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err); 4519ea8026Sopenharmony_ci return err; 4619ea8026Sopenharmony_ci } 4719ea8026Sopenharmony_ci 4819ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_create -> %d", 0); 4919ea8026Sopenharmony_ci return 0; 5019ea8026Sopenharmony_ci} 5119ea8026Sopenharmony_ci 5219ea8026Sopenharmony_ciint lfs_filebd_destroy(const struct lfs_config *cfg) { 5319ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)cfg); 5419ea8026Sopenharmony_ci lfs_filebd_t *bd = cfg->context; 5519ea8026Sopenharmony_ci int err = close(bd->fd); 5619ea8026Sopenharmony_ci if (err < 0) { 5719ea8026Sopenharmony_ci err = -errno; 5819ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", err); 5919ea8026Sopenharmony_ci return err; 6019ea8026Sopenharmony_ci } 6119ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", 0); 6219ea8026Sopenharmony_ci return 0; 6319ea8026Sopenharmony_ci} 6419ea8026Sopenharmony_ci 6519ea8026Sopenharmony_ciint lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, 6619ea8026Sopenharmony_ci lfs_off_t off, void *buffer, lfs_size_t size) { 6719ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_read(%p, " 6819ea8026Sopenharmony_ci "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", 6919ea8026Sopenharmony_ci (void*)cfg, block, off, buffer, size); 7019ea8026Sopenharmony_ci lfs_filebd_t *bd = cfg->context; 7119ea8026Sopenharmony_ci 7219ea8026Sopenharmony_ci // check if read is valid 7319ea8026Sopenharmony_ci LFS_ASSERT(block < bd->cfg->erase_count); 7419ea8026Sopenharmony_ci LFS_ASSERT(off % bd->cfg->read_size == 0); 7519ea8026Sopenharmony_ci LFS_ASSERT(size % bd->cfg->read_size == 0); 7619ea8026Sopenharmony_ci LFS_ASSERT(off+size <= bd->cfg->erase_size); 7719ea8026Sopenharmony_ci 7819ea8026Sopenharmony_ci // zero for reproducibility (in case file is truncated) 7919ea8026Sopenharmony_ci memset(buffer, 0, size); 8019ea8026Sopenharmony_ci 8119ea8026Sopenharmony_ci // read 8219ea8026Sopenharmony_ci off_t res1 = lseek(bd->fd, 8319ea8026Sopenharmony_ci (off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET); 8419ea8026Sopenharmony_ci if (res1 < 0) { 8519ea8026Sopenharmony_ci int err = -errno; 8619ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err); 8719ea8026Sopenharmony_ci return err; 8819ea8026Sopenharmony_ci } 8919ea8026Sopenharmony_ci 9019ea8026Sopenharmony_ci ssize_t res2 = read(bd->fd, buffer, size); 9119ea8026Sopenharmony_ci if (res2 < 0) { 9219ea8026Sopenharmony_ci int err = -errno; 9319ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err); 9419ea8026Sopenharmony_ci return err; 9519ea8026Sopenharmony_ci } 9619ea8026Sopenharmony_ci 9719ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_read -> %d", 0); 9819ea8026Sopenharmony_ci return 0; 9919ea8026Sopenharmony_ci} 10019ea8026Sopenharmony_ci 10119ea8026Sopenharmony_ciint lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, 10219ea8026Sopenharmony_ci lfs_off_t off, const void *buffer, lfs_size_t size) { 10319ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_prog(%p, " 10419ea8026Sopenharmony_ci "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", 10519ea8026Sopenharmony_ci (void*)cfg, block, off, buffer, size); 10619ea8026Sopenharmony_ci lfs_filebd_t *bd = cfg->context; 10719ea8026Sopenharmony_ci 10819ea8026Sopenharmony_ci // check if write is valid 10919ea8026Sopenharmony_ci LFS_ASSERT(block < bd->cfg->erase_count); 11019ea8026Sopenharmony_ci LFS_ASSERT(off % bd->cfg->prog_size == 0); 11119ea8026Sopenharmony_ci LFS_ASSERT(size % bd->cfg->prog_size == 0); 11219ea8026Sopenharmony_ci LFS_ASSERT(off+size <= bd->cfg->erase_size); 11319ea8026Sopenharmony_ci 11419ea8026Sopenharmony_ci // program data 11519ea8026Sopenharmony_ci off_t res1 = lseek(bd->fd, 11619ea8026Sopenharmony_ci (off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET); 11719ea8026Sopenharmony_ci if (res1 < 0) { 11819ea8026Sopenharmony_ci int err = -errno; 11919ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); 12019ea8026Sopenharmony_ci return err; 12119ea8026Sopenharmony_ci } 12219ea8026Sopenharmony_ci 12319ea8026Sopenharmony_ci ssize_t res2 = write(bd->fd, buffer, size); 12419ea8026Sopenharmony_ci if (res2 < 0) { 12519ea8026Sopenharmony_ci int err = -errno; 12619ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); 12719ea8026Sopenharmony_ci return err; 12819ea8026Sopenharmony_ci } 12919ea8026Sopenharmony_ci 13019ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", 0); 13119ea8026Sopenharmony_ci return 0; 13219ea8026Sopenharmony_ci} 13319ea8026Sopenharmony_ci 13419ea8026Sopenharmony_ciint lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { 13519ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32" (%"PRIu32"))", 13619ea8026Sopenharmony_ci (void*)cfg, block, ((lfs_file_t*)cfg->context)->cfg->erase_size); 13719ea8026Sopenharmony_ci lfs_filebd_t *bd = cfg->context; 13819ea8026Sopenharmony_ci 13919ea8026Sopenharmony_ci // check if erase is valid 14019ea8026Sopenharmony_ci LFS_ASSERT(block < bd->cfg->erase_count); 14119ea8026Sopenharmony_ci 14219ea8026Sopenharmony_ci // erase is a noop 14319ea8026Sopenharmony_ci (void)block; 14419ea8026Sopenharmony_ci 14519ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", 0); 14619ea8026Sopenharmony_ci return 0; 14719ea8026Sopenharmony_ci} 14819ea8026Sopenharmony_ci 14919ea8026Sopenharmony_ciint lfs_filebd_sync(const struct lfs_config *cfg) { 15019ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg); 15119ea8026Sopenharmony_ci 15219ea8026Sopenharmony_ci // file sync 15319ea8026Sopenharmony_ci lfs_filebd_t *bd = cfg->context; 15419ea8026Sopenharmony_ci #ifdef _WIN32 15519ea8026Sopenharmony_ci int err = FlushFileBuffers((HANDLE) _get_osfhandle(bd->fd)) ? 0 : -1; 15619ea8026Sopenharmony_ci #else 15719ea8026Sopenharmony_ci int err = fsync(bd->fd); 15819ea8026Sopenharmony_ci #endif 15919ea8026Sopenharmony_ci if (err) { 16019ea8026Sopenharmony_ci err = -errno; 16119ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0); 16219ea8026Sopenharmony_ci return err; 16319ea8026Sopenharmony_ci } 16419ea8026Sopenharmony_ci 16519ea8026Sopenharmony_ci LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0); 16619ea8026Sopenharmony_ci return 0; 16719ea8026Sopenharmony_ci} 168