diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2019-12-09 11:09:30 +0000 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2020-01-20 20:12:41 -0500 |
commit | a317120bf7f8306b594ee650ee14f08a0e599602 (patch) | |
tree | 4725119a5fbeccba04b2babcc345c34fefa51478 /fs/adfs/dir.c | |
parent | acf5f0be8a520c02bfed74cfc6735bf5fdd4a9e5 (diff) |
fs/adfs: dir: add generic copy functions
Directories can span multiple buffers, and we currently open-code
memcpy access to these buffers, including dealing with entries that
are split across multiple buffers. Such code exists in both
directory format implementations.
Provide common functions to allow data to be copied from/to the
directory buffers as if they were a contiguous set of buffers, and
use them when accessing directories.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/adfs/dir.c')
-rw-r--r-- | fs/adfs/dir.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index 16a2639d3ca5..3c303074aa5e 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -14,6 +14,56 @@ */ static DEFINE_RWLOCK(adfs_dir_lock); +int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset, + size_t len) +{ + struct super_block *sb = dir->sb; + unsigned int index, remain; + + index = offset >> sb->s_blocksize_bits; + offset &= sb->s_blocksize - 1; + remain = sb->s_blocksize - offset; + if (index + (remain < len) >= dir->nr_buffers) + return -EINVAL; + + if (remain < len) { + memcpy(dst, dir->bhs[index]->b_data + offset, remain); + dst += remain; + len -= remain; + index += 1; + offset = 0; + } + + memcpy(dst, dir->bhs[index]->b_data + offset, len); + + return 0; +} + +int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src, + size_t len) +{ + struct super_block *sb = dir->sb; + unsigned int index, remain; + + index = offset >> sb->s_blocksize_bits; + offset &= sb->s_blocksize - 1; + remain = sb->s_blocksize - offset; + if (index + (remain < len) >= dir->nr_buffers) + return -EINVAL; + + if (remain < len) { + memcpy(dir->bhs[index]->b_data + offset, src, remain); + src += remain; + len -= remain; + index += 1; + offset = 0; + } + + memcpy(dir->bhs[index]->b_data + offset, src, len); + + return 0; +} + void adfs_dir_relse(struct adfs_dir *dir) { unsigned int i; |