From eca83c4a73b2bbddc2cf1daa7f36b27aab8eb14f Mon Sep 17 00:00:00 2001 From: buxiasen Date: Fri, 8 Nov 2024 20:59:08 +0800 Subject: [PATCH] blk/mtdoutstream: use lib_sostream_s to support seek Signed-off-by: buxiasen --- include/nuttx/streams.h | 4 +- libs/libc/stream/lib_blkoutstream.c | 77 ++++++++++++++++++- libs/libc/stream/lib_mtdoutstream.c | 112 ++++++++++++++++++++++++---- 3 files changed, 172 insertions(+), 21 deletions(-) diff --git a/include/nuttx/streams.h b/include/nuttx/streams.h index 5f39fab655..dedf16a5f6 100644 --- a/include/nuttx/streams.h +++ b/include/nuttx/streams.h @@ -293,7 +293,7 @@ struct lib_lzfoutstream_s #ifndef CONFIG_DISABLE_MOUNTPOINT struct lib_blkoutstream_s { - struct lib_outstream_s common; + struct lib_sostream_s common; FAR struct inode *inode; struct geometry geo; FAR unsigned char *cache; @@ -303,7 +303,7 @@ struct lib_blkoutstream_s #if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD) struct lib_mtdoutstream_s { - struct lib_outstream_s common; + struct lib_sostream_s common; FAR struct inode *inode; struct mtd_geometry_s geo; FAR unsigned char *cache; diff --git a/libs/libc/stream/lib_blkoutstream.c b/libs/libc/stream/lib_blkoutstream.c index c9132b445d..7ee0e793f1 100644 --- a/libs/libc/stream/lib_blkoutstream.c +++ b/libs/libc/stream/lib_blkoutstream.c @@ -45,7 +45,7 @@ * Name: blkoutstream_flush ****************************************************************************/ -static int blkoutstream_flush(FAR struct lib_outstream_s *self) +static int blkoutstream_flush(FAR struct lib_sostream_s *self) { FAR struct lib_blkoutstream_s *stream = (FAR struct lib_blkoutstream_s *)self; @@ -61,11 +61,81 @@ static int blkoutstream_flush(FAR struct lib_outstream_s *self) return ret; } +/**************************************************************************** + * Name: blkoutstream_seek + ****************************************************************************/ + +static off_t blkoutstream_seek(FAR struct lib_sostream_s *self, + off_t offset, int whence) +{ + FAR struct lib_blkoutstream_s *stream = + (FAR struct lib_blkoutstream_s *)self; + size_t sectorsize = stream->geo.geo_sectorsize; + off_t streamsize = sectorsize * stream->geo.geo_nsectors; + FAR struct inode *inode = stream->inode; + off_t sector; + off_t ret; + + switch (whence) + { + case SEEK_SET: + break; + case SEEK_END: + offset += streamsize; + break; + case SEEK_CUR: + offset += self->nput; + break; + default: + return -ENOTSUP; + } + + /* Seek to negative value or value larger than maximum size shall fail. */ + + if (offset < 0 || offset > streamsize) + { + return -EINVAL; + } + + if (self->nput % sectorsize) + { + sector = self->nput / sectorsize; + if (offset >= sector * sectorsize && + offset < (sector + 1) * sectorsize) + { + /* Inside same sector */ + + goto out; + } + + ret = inode->u.i_bops->write(stream->inode, stream->cache, + sector, 1); + if (ret < 0) + { + return ret; + } + } + + if (offset % sectorsize) + { + ret = inode->u.i_bops->read(inode, stream->cache, + offset / sectorsize, 1); + if (ret < 0) + { + return ret; + } + } + +out: + self->nput = offset; + return offset; +} + /**************************************************************************** * Name: blkoutstream_puts ****************************************************************************/ -static ssize_t blkoutstream_puts(FAR struct lib_outstream_s *self, +static ssize_t blkoutstream_puts(FAR struct lib_sostream_s *self, FAR const void *buf, size_t len) { FAR struct lib_blkoutstream_s *stream = @@ -140,7 +210,7 @@ static ssize_t blkoutstream_puts(FAR struct lib_outstream_s *self, * Name: blkoutstream_putc ****************************************************************************/ -static void blkoutstream_putc(FAR struct lib_outstream_s *self, int ch) +static void blkoutstream_putc(FAR struct lib_sostream_s *self, int ch) { char tmp = ch; blkoutstream_puts(self, &tmp, 1); @@ -240,6 +310,7 @@ int lib_blkoutstream_open(FAR struct lib_blkoutstream_s *stream, stream->common.putc = blkoutstream_putc; stream->common.puts = blkoutstream_puts; stream->common.flush = blkoutstream_flush; + stream->common.seek = blkoutstream_seek; return OK; } diff --git a/libs/libc/stream/lib_mtdoutstream.c b/libs/libc/stream/lib_mtdoutstream.c index 8ea4da95c8..eebd15f3c5 100644 --- a/libs/libc/stream/lib_mtdoutstream.c +++ b/libs/libc/stream/lib_mtdoutstream.c @@ -47,11 +47,11 @@ * Name: mtdoutstream_flush ****************************************************************************/ -static int mtdoutstream_flush(FAR struct lib_outstream_s *self) +static int mtdoutstream_flush(FAR struct lib_sostream_s *self) { FAR struct lib_mtdoutstream_s *stream = (FAR struct lib_mtdoutstream_s *)self; - FAR struct inode *inode = stream->inode; + FAR struct mtd_dev_s *i_mtd = stream->inode->u.i_mtd; size_t erasesize = stream->geo.erasesize; size_t nblkpererase = erasesize / stream->geo.blocksize; int ret = OK; @@ -60,13 +60,13 @@ static int mtdoutstream_flush(FAR struct lib_outstream_s *self) { size_t sblock = self->nput / erasesize; - ret = MTD_ERASE(inode->u.i_mtd, sblock, 1); + ret = MTD_ERASE(i_mtd, sblock, 1); if (ret < 0) { return ret; } - ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblkpererase, + ret = MTD_BWRITE(i_mtd, sblock * nblkpererase, nblkpererase, stream->cache); } @@ -77,15 +77,15 @@ static int mtdoutstream_flush(FAR struct lib_outstream_s *self) * Name: mtdoutstream_puts ****************************************************************************/ -static ssize_t mtdoutstream_puts(FAR struct lib_outstream_s *self, +static ssize_t mtdoutstream_puts(FAR struct lib_sostream_s *self, FAR const void *buf, size_t len) { FAR struct lib_mtdoutstream_s *stream = (FAR struct lib_mtdoutstream_s *)self; - FAR struct inode *inode = stream->inode; - FAR const unsigned char *ptr = buf; + FAR struct mtd_dev_s *i_mtd = stream->inode->u.i_mtd; size_t erasesize = stream->geo.erasesize; size_t nblkpererase = erasesize / stream->geo.blocksize; + FAR const unsigned char *ptr = buf; size_t remain = len; ssize_t ret; @@ -113,14 +113,14 @@ static ssize_t mtdoutstream_puts(FAR struct lib_outstream_s *self, if (offset == erasesize) { - ret = MTD_ERASE(inode->u.i_mtd, sblock, 1); + ret = MTD_ERASE(i_mtd, sblock, 1); if (ret < 0) { return ret; } - ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblkpererase, - nblkpererase, stream->cache); + ret = MTD_BWRITE(i_mtd, sblock * nblkpererase, + nblkpererase, stream->cache); if (ret < 0) { return ret; @@ -129,8 +129,8 @@ static ssize_t mtdoutstream_puts(FAR struct lib_outstream_s *self, } else if (remain < erasesize) { - ret = MTD_READ(stream->inode->u.i_mtd, sblock * erasesize, - erasesize, stream->cache); + ret = MTD_BREAD(i_mtd, sblock * nblkpererase, + nblkpererase, stream->cache); if (ret < 0) { return ret; @@ -145,14 +145,14 @@ static ssize_t mtdoutstream_puts(FAR struct lib_outstream_s *self, size_t nblock = remain / erasesize; size_t copyin = nblock * erasesize; - ret = MTD_ERASE(inode->u.i_mtd, sblock, nblock); + ret = MTD_ERASE(i_mtd, sblock, nblock); if (ret < 0) { return ret; } - ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblkpererase, - nblock * nblkpererase, ptr); + ret = MTD_BWRITE(i_mtd, sblock * nblkpererase, + nblock * nblkpererase, ptr); if (ret < 0) { return ret; @@ -171,12 +171,91 @@ static ssize_t mtdoutstream_puts(FAR struct lib_outstream_s *self, * Name: mtdoutstream_putc ****************************************************************************/ -static void mtdoutstream_putc(FAR struct lib_outstream_s *self, int ch) +static void mtdoutstream_putc(FAR struct lib_sostream_s *self, int ch) { char tmp = ch; mtdoutstream_puts(self, &tmp, 1); } +/**************************************************************************** + * Name: mtdoutstream_seek + ****************************************************************************/ + +static off_t mtdoutstream_seek(FAR struct lib_sostream_s *self, + off_t offset, int whence) +{ + FAR struct lib_mtdoutstream_s *stream = + (FAR struct lib_mtdoutstream_s *)self; + FAR struct mtd_dev_s *i_mtd = stream->inode->u.i_mtd; + size_t erasesize = stream->geo.erasesize; + off_t streamsize = erasesize * stream->geo.neraseblocks; + size_t nblkpererase = erasesize / stream->geo.blocksize; + size_t block; + off_t ret; + + switch (whence) + { + case SEEK_SET: + break; + case SEEK_END: + offset += streamsize; + break; + case SEEK_CUR: + offset += self->nput; + break; + default: + return -ENOTSUP; + } + + /* Seek to negative value or value larger than maximum size shall fail */ + + if (offset < 0 || offset > streamsize) + { + return -EINVAL; + } + + if (self->nput % erasesize) + { + block = self->nput / erasesize; + if (offset >= block * erasesize && + offset < (block + 1) * erasesize) + { + /* Inside same erase block */ + + goto out; + } + + ret = MTD_ERASE(i_mtd, block, 1); + if (ret < 0) + { + return ret; + } + + ret = MTD_BWRITE(i_mtd, block * nblkpererase, + nblkpererase, stream->cache); + if (ret < 0) + { + return ret; + } + } + + if (offset % erasesize) + { + block = offset / erasesize; + + ret = MTD_BREAD(i_mtd, block * nblkpererase, + nblkpererase, stream->cache); + if (ret < 0) + { + return ret; + } + } + +out: + self->nput = offset; + return offset; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -274,6 +353,7 @@ int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream, stream->common.putc = mtdoutstream_putc; stream->common.puts = mtdoutstream_puts; stream->common.flush = mtdoutstream_flush; + stream->common.seek = mtdoutstream_seek; return OK; }