]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs/adfs: dir: add generic copy functions
authorRussell King <rmk+kernel@armlinux.org.uk>
Mon, 9 Dec 2019 11:09:30 +0000 (11:09 +0000)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 21 Jan 2020 01:12:41 +0000 (20:12 -0500)
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>
fs/adfs/adfs.h
fs/adfs/dir.c
fs/adfs/dir_f.c
fs/adfs/dir_fplus.c

index 5f1acee768f51eea2730b00c29786bef0c3e52aa..92cbc4b1d902d378d6c4429c91c92f5461d007cf 100644 (file)
@@ -165,6 +165,10 @@ extern const struct dentry_operations adfs_dentry_operations;
 extern const struct adfs_dir_ops adfs_f_dir_ops;
 extern const struct adfs_dir_ops adfs_fplus_dir_ops;
 
+int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset,
+                     size_t len);
+int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
+                   size_t len);
 void adfs_dir_relse(struct adfs_dir *dir);
 void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj);
 extern int adfs_dir_update(struct super_block *sb, struct object_info *obj,
index 16a2639d3ca5f7f192e3731fbede52cf6b1c805f..3c303074aa5ec1bc51781ea4f675e3e1c885ac98 100644 (file)
  */
 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;
index 80ac261b9ec4f22969e7b598a52e7ad609d8e1df..3c3b423577d2dda4ce0ecc633d940fbac6bda53b 100644 (file)
@@ -224,24 +224,12 @@ adfs_obj2dir(struct adfs_direntry *de, struct object_info *obj)
 static int
 __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj)
 {
-       struct super_block *sb = dir->sb;
        struct adfs_direntry de;
-       int thissize, buffer, offset;
-
-       buffer = pos >> sb->s_blocksize_bits;
-
-       if (buffer > dir->nr_buffers)
-               return -EINVAL;
-
-       offset = pos & (sb->s_blocksize - 1);
-       thissize = sb->s_blocksize - offset;
-       if (thissize > 26)
-               thissize = 26;
+       int ret;
 
-       memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);
-       if (thissize != 26)
-               memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,
-                      26 - thissize);
+       ret = adfs_dir_copyfrom(&de, dir, pos, 26);
+       if (ret)
+               return ret;
 
        if (!de.dirobname[0])
                return -ENOENT;
@@ -254,42 +242,16 @@ __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj)
 static int
 __adfs_dir_put(struct adfs_dir *dir, int pos, struct object_info *obj)
 {
-       struct super_block *sb = dir->sb;
        struct adfs_direntry de;
-       int thissize, buffer, offset;
-
-       buffer = pos >> sb->s_blocksize_bits;
-
-       if (buffer > dir->nr_buffers)
-               return -EINVAL;
-
-       offset = pos & (sb->s_blocksize - 1);
-       thissize = sb->s_blocksize - offset;
-       if (thissize > 26)
-               thissize = 26;
+       int ret;
 
-       /*
-        * Get the entry in total
-        */
-       memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);
-       if (thissize != 26)
-               memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,
-                      26 - thissize);
+       ret = adfs_dir_copyfrom(&de, dir, pos, 26);
+       if (ret)
+               return ret;
 
-       /*
-        * update it
-        */
        adfs_obj2dir(&de, obj);
 
-       /*
-        * Put the new entry back
-        */
-       memcpy(dir->bh[buffer]->b_data + offset, &de, thissize);
-       if (thissize != 26)
-               memcpy(dir->bh[buffer + 1]->b_data, ((char *)&de) + thissize,
-                      26 - thissize);
-
-       return 0;
+       return adfs_dir_copyto(dir, pos, &de, 26);
 }
 
 /*
index 1196c8962febcc76692509fa084b949ab9ac9947..6a07c0dfcc93cda2de52d4078f13ec97052e8a12 100644 (file)
@@ -112,34 +112,6 @@ adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
        return ret;
 }
 
-static void
-dir_memcpy(struct adfs_dir *dir, unsigned int offset, void *to, int len)
-{
-       struct super_block *sb = dir->sb;
-       unsigned int buffer, partial, remainder;
-
-       buffer = offset >> sb->s_blocksize_bits;
-       offset &= sb->s_blocksize - 1;
-
-       partial = sb->s_blocksize - offset;
-
-       if (partial >= len)
-               memcpy(to, dir->bhs[buffer]->b_data + offset, len);
-       else {
-               char *c = (char *)to;
-
-               remainder = len - partial;
-
-               memcpy(c,
-                       dir->bhs[buffer]->b_data + offset,
-                       partial);
-
-               memcpy(c + partial,
-                       dir->bhs[buffer + 1]->b_data,
-                       remainder);
-       }
-}
-
 static int
 adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 {
@@ -147,16 +119,19 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
                (struct adfs_bigdirheader *) dir->bhs[0]->b_data;
        struct adfs_bigdirentry bde;
        unsigned int offset;
-       int ret = -ENOENT;
+       int ret;
 
        if (dir->pos >= le32_to_cpu(h->bigdirentries))
-               goto out;
+               return -ENOENT;
 
        offset = offsetof(struct adfs_bigdirheader, bigdirname);
        offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
        offset += dir->pos * sizeof(struct adfs_bigdirentry);
 
-       dir_memcpy(dir, offset, &bde, sizeof(struct adfs_bigdirentry));
+       ret = adfs_dir_copyfrom(&bde, dir, offset,
+                               sizeof(struct adfs_bigdirentry));
+       if (ret)
+               return ret;
 
        obj->loadaddr = le32_to_cpu(bde.bigdirload);
        obj->execaddr = le32_to_cpu(bde.bigdirexec);
@@ -170,13 +145,15 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
        offset += le32_to_cpu(h->bigdirentries) * sizeof(struct adfs_bigdirentry);
        offset += le32_to_cpu(bde.bigdirobnameptr);
 
-       dir_memcpy(dir, offset, obj->name, obj->name_len);
+       ret = adfs_dir_copyfrom(obj->name, dir, offset, obj->name_len);
+       if (ret)
+               return ret;
+
        adfs_object_fixup(dir, obj);
 
        dir->pos += 1;
-       ret = 0;
-out:
-       return ret;
+
+       return 0;
 }
 
 const struct adfs_dir_ops adfs_fplus_dir_ops = {