1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/fs/adfs/dir.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1999-2000 Russell King
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Common directory handling for ADFS
81da177e4SLinus Torvalds */
91dd9f5baSRussell King #include <linux/slab.h>
101da177e4SLinus Torvalds #include "adfs.h"
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds /*
131da177e4SLinus Torvalds * For future. This should probably be per-directory.
141da177e4SLinus Torvalds */
15deed1bfdSRussell King static DECLARE_RWSEM(adfs_dir_rwsem);
161da177e4SLinus Torvalds
adfs_dir_copyfrom(void * dst,struct adfs_dir * dir,unsigned int offset,size_t len)17a317120bSRussell King int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset,
18a317120bSRussell King size_t len)
19a317120bSRussell King {
20a317120bSRussell King struct super_block *sb = dir->sb;
21a317120bSRussell King unsigned int index, remain;
22a317120bSRussell King
23a317120bSRussell King index = offset >> sb->s_blocksize_bits;
24a317120bSRussell King offset &= sb->s_blocksize - 1;
25a317120bSRussell King remain = sb->s_blocksize - offset;
26a317120bSRussell King if (index + (remain < len) >= dir->nr_buffers)
27a317120bSRussell King return -EINVAL;
28a317120bSRussell King
29a317120bSRussell King if (remain < len) {
30a317120bSRussell King memcpy(dst, dir->bhs[index]->b_data + offset, remain);
31a317120bSRussell King dst += remain;
32a317120bSRussell King len -= remain;
33a317120bSRussell King index += 1;
34a317120bSRussell King offset = 0;
35a317120bSRussell King }
36a317120bSRussell King
37a317120bSRussell King memcpy(dst, dir->bhs[index]->b_data + offset, len);
38a317120bSRussell King
39a317120bSRussell King return 0;
40a317120bSRussell King }
41a317120bSRussell King
adfs_dir_copyto(struct adfs_dir * dir,unsigned int offset,const void * src,size_t len)42a317120bSRussell King int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
43a317120bSRussell King size_t len)
44a317120bSRussell King {
45a317120bSRussell King struct super_block *sb = dir->sb;
46a317120bSRussell King unsigned int index, remain;
47a317120bSRussell King
48a317120bSRussell King index = offset >> sb->s_blocksize_bits;
49a317120bSRussell King offset &= sb->s_blocksize - 1;
50a317120bSRussell King remain = sb->s_blocksize - offset;
51a317120bSRussell King if (index + (remain < len) >= dir->nr_buffers)
52a317120bSRussell King return -EINVAL;
53a317120bSRussell King
54a317120bSRussell King if (remain < len) {
55a317120bSRussell King memcpy(dir->bhs[index]->b_data + offset, src, remain);
56a317120bSRussell King src += remain;
57a317120bSRussell King len -= remain;
58a317120bSRussell King index += 1;
59a317120bSRussell King offset = 0;
60a317120bSRussell King }
61a317120bSRussell King
62a317120bSRussell King memcpy(dir->bhs[index]->b_data + offset, src, len);
63a317120bSRussell King
64a317120bSRussell King return 0;
65a317120bSRussell King }
66a317120bSRussell King
__adfs_dir_cleanup(struct adfs_dir * dir)67f6075c79SRussell King static void __adfs_dir_cleanup(struct adfs_dir *dir)
681dd9f5baSRussell King {
691dd9f5baSRussell King dir->nr_buffers = 0;
701dd9f5baSRussell King
711dd9f5baSRussell King if (dir->bhs != dir->bh)
721dd9f5baSRussell King kfree(dir->bhs);
731dd9f5baSRussell King dir->bhs = NULL;
741dd9f5baSRussell King dir->sb = NULL;
751dd9f5baSRussell King }
761dd9f5baSRussell King
adfs_dir_relse(struct adfs_dir * dir)77f6075c79SRussell King void adfs_dir_relse(struct adfs_dir *dir)
78f6075c79SRussell King {
79f6075c79SRussell King unsigned int i;
80f6075c79SRussell King
81f6075c79SRussell King for (i = 0; i < dir->nr_buffers; i++)
82f6075c79SRussell King brelse(dir->bhs[i]);
83f6075c79SRussell King
84f6075c79SRussell King __adfs_dir_cleanup(dir);
85f6075c79SRussell King }
86f6075c79SRussell King
adfs_dir_forget(struct adfs_dir * dir)87f6075c79SRussell King static void adfs_dir_forget(struct adfs_dir *dir)
88f6075c79SRussell King {
89f6075c79SRussell King unsigned int i;
90f6075c79SRussell King
91f6075c79SRussell King for (i = 0; i < dir->nr_buffers; i++)
92f6075c79SRussell King bforget(dir->bhs[i]);
93f6075c79SRussell King
94f6075c79SRussell King __adfs_dir_cleanup(dir);
95f6075c79SRussell King }
96f6075c79SRussell King
adfs_dir_read_buffers(struct super_block * sb,u32 indaddr,unsigned int size,struct adfs_dir * dir)97419a6e5eSRussell King int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr,
98419a6e5eSRussell King unsigned int size, struct adfs_dir *dir)
99419a6e5eSRussell King {
100419a6e5eSRussell King struct buffer_head **bhs;
101419a6e5eSRussell King unsigned int i, num;
102419a6e5eSRussell King int block;
103419a6e5eSRussell King
104419a6e5eSRussell King num = ALIGN(size, sb->s_blocksize) >> sb->s_blocksize_bits;
105419a6e5eSRussell King if (num > ARRAY_SIZE(dir->bh)) {
106419a6e5eSRussell King /* We only allow one extension */
107419a6e5eSRussell King if (dir->bhs != dir->bh)
108419a6e5eSRussell King return -EINVAL;
109419a6e5eSRussell King
110419a6e5eSRussell King bhs = kcalloc(num, sizeof(*bhs), GFP_KERNEL);
111419a6e5eSRussell King if (!bhs)
112419a6e5eSRussell King return -ENOMEM;
113419a6e5eSRussell King
114419a6e5eSRussell King if (dir->nr_buffers)
115419a6e5eSRussell King memcpy(bhs, dir->bhs, dir->nr_buffers * sizeof(*bhs));
116419a6e5eSRussell King
117419a6e5eSRussell King dir->bhs = bhs;
118419a6e5eSRussell King }
119419a6e5eSRussell King
120419a6e5eSRussell King for (i = dir->nr_buffers; i < num; i++) {
121419a6e5eSRussell King block = __adfs_block_map(sb, indaddr, i);
122419a6e5eSRussell King if (!block) {
123419a6e5eSRussell King adfs_error(sb, "dir %06x has a hole at offset %u",
124419a6e5eSRussell King indaddr, i);
125419a6e5eSRussell King goto error;
126419a6e5eSRussell King }
127419a6e5eSRussell King
128419a6e5eSRussell King dir->bhs[i] = sb_bread(sb, block);
129419a6e5eSRussell King if (!dir->bhs[i]) {
130419a6e5eSRussell King adfs_error(sb,
131419a6e5eSRussell King "dir %06x failed read at offset %u, mapped block 0x%08x",
132419a6e5eSRussell King indaddr, i, block);
133419a6e5eSRussell King goto error;
134419a6e5eSRussell King }
135419a6e5eSRussell King
136419a6e5eSRussell King dir->nr_buffers++;
137419a6e5eSRussell King }
138419a6e5eSRussell King return 0;
139419a6e5eSRussell King
140419a6e5eSRussell King error:
141419a6e5eSRussell King adfs_dir_relse(dir);
142419a6e5eSRussell King
143419a6e5eSRussell King return -EIO;
144419a6e5eSRussell King }
145419a6e5eSRussell King
adfs_dir_read(struct super_block * sb,u32 indaddr,unsigned int size,struct adfs_dir * dir)14695fbadbbSRussell King static int adfs_dir_read(struct super_block *sb, u32 indaddr,
14795fbadbbSRussell King unsigned int size, struct adfs_dir *dir)
14895fbadbbSRussell King {
14995fbadbbSRussell King dir->sb = sb;
15095fbadbbSRussell King dir->bhs = dir->bh;
15195fbadbbSRussell King dir->nr_buffers = 0;
15295fbadbbSRussell King
15395fbadbbSRussell King return ADFS_SB(sb)->s_dir->read(sb, indaddr, size, dir);
15495fbadbbSRussell King }
15595fbadbbSRussell King
adfs_dir_read_inode(struct super_block * sb,struct inode * inode,struct adfs_dir * dir)15690011c7aSRussell King static int adfs_dir_read_inode(struct super_block *sb, struct inode *inode,
15790011c7aSRussell King struct adfs_dir *dir)
15890011c7aSRussell King {
15990011c7aSRussell King int ret;
16090011c7aSRussell King
161*25e5d4dfSRussell King ret = adfs_dir_read(sb, ADFS_I(inode)->indaddr, inode->i_size, dir);
16290011c7aSRussell King if (ret)
16390011c7aSRussell King return ret;
16490011c7aSRussell King
16590011c7aSRussell King if (ADFS_I(inode)->parent_id != dir->parent_id) {
16690011c7aSRussell King adfs_error(sb,
16790011c7aSRussell King "parent directory id changed under me! (%06x but got %06x)\n",
16890011c7aSRussell King ADFS_I(inode)->parent_id, dir->parent_id);
16990011c7aSRussell King adfs_dir_relse(dir);
17090011c7aSRussell King ret = -EIO;
17190011c7aSRussell King }
17290011c7aSRussell King
17390011c7aSRussell King return ret;
17490011c7aSRussell King }
17590011c7aSRussell King
adfs_dir_mark_dirty(struct adfs_dir * dir)176c3c8149bSRussell King static void adfs_dir_mark_dirty(struct adfs_dir *dir)
177c3c8149bSRussell King {
178c3c8149bSRussell King unsigned int i;
179c3c8149bSRussell King
180c3c8149bSRussell King /* Mark the buffers dirty */
181c3c8149bSRussell King for (i = 0; i < dir->nr_buffers; i++)
182c3c8149bSRussell King mark_buffer_dirty(dir->bhs[i]);
183c3c8149bSRussell King }
184c3c8149bSRussell King
adfs_dir_sync(struct adfs_dir * dir)185acf5f0beSRussell King static int adfs_dir_sync(struct adfs_dir *dir)
186acf5f0beSRussell King {
187acf5f0beSRussell King int err = 0;
188acf5f0beSRussell King int i;
189acf5f0beSRussell King
190acf5f0beSRussell King for (i = dir->nr_buffers - 1; i >= 0; i--) {
191acf5f0beSRussell King struct buffer_head *bh = dir->bhs[i];
192acf5f0beSRussell King sync_dirty_buffer(bh);
193acf5f0beSRussell King if (buffer_req(bh) && !buffer_uptodate(bh))
194acf5f0beSRussell King err = -EIO;
195acf5f0beSRussell King }
196acf5f0beSRussell King
197acf5f0beSRussell King return err;
198acf5f0beSRussell King }
199acf5f0beSRussell King
adfs_object_fixup(struct adfs_dir * dir,struct object_info * obj)200411c49bcSRussell King void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj)
201411c49bcSRussell King {
202fc722a04SRussell King unsigned int dots, i;
203adb514a4SRussell King
204adb514a4SRussell King /*
205adb514a4SRussell King * RISC OS allows the use of '/' in directory entry names, so we need
206adb514a4SRussell King * to fix these up. '/' is typically used for FAT compatibility to
207adb514a4SRussell King * represent '.', so do the same conversion here. In any case, '.'
208adb514a4SRussell King * will never be in a RISC OS name since it is used as the pathname
209fc722a04SRussell King * separator. Handle the case where we may generate a '.' or '..'
210fc722a04SRussell King * name, replacing the first character with '^' (the RISC OS "parent
211fc722a04SRussell King * directory" character.)
212adb514a4SRussell King */
213fc722a04SRussell King for (i = dots = 0; i < obj->name_len; i++)
214fc722a04SRussell King if (obj->name[i] == '/') {
215adb514a4SRussell King obj->name[i] = '.';
216fc722a04SRussell King dots++;
217fc722a04SRussell King }
218fc722a04SRussell King
219fc722a04SRussell King if (obj->name_len <= 2 && dots == obj->name_len)
220fc722a04SRussell King obj->name[0] = '^';
221adb514a4SRussell King
222411c49bcSRussell King /*
223b4ed8f75SRussell King * If the object is a file, and the user requested the ,xyz hex
224b4ed8f75SRussell King * filetype suffix to the name, check the filetype and append.
225411c49bcSRussell King */
226b4ed8f75SRussell King if (!(obj->attr & ADFS_NDA_DIRECTORY) && ADFS_SB(dir->sb)->s_ftsuffix) {
227b4ed8f75SRussell King u16 filetype = adfs_filetype(obj->loadaddr);
228411c49bcSRussell King
229b4ed8f75SRussell King if (filetype != ADFS_FILETYPE_NONE) {
2305f8de487SRussell King obj->name[obj->name_len++] = ',';
2315f8de487SRussell King obj->name[obj->name_len++] = hex_asc_lo(filetype >> 8);
2325f8de487SRussell King obj->name[obj->name_len++] = hex_asc_lo(filetype >> 4);
2335f8de487SRussell King obj->name[obj->name_len++] = hex_asc_lo(filetype >> 0);
2345f8de487SRussell King }
235411c49bcSRussell King }
236411c49bcSRussell King }
237411c49bcSRussell King
adfs_iterate(struct file * file,struct dir_context * ctx)238cdc46e99SRussell King static int adfs_iterate(struct file *file, struct dir_context *ctx)
2391da177e4SLinus Torvalds {
2402638ffbaSAl Viro struct inode *inode = file_inode(file);
2411da177e4SLinus Torvalds struct super_block *sb = inode->i_sb;
2420125f504SJulia Lawall const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
2431da177e4SLinus Torvalds struct adfs_dir dir;
2444287e4deSRussell King int ret;
2451da177e4SLinus Torvalds
246deed1bfdSRussell King down_read(&adfs_dir_rwsem);
24790011c7aSRussell King ret = adfs_dir_read_inode(sb, inode, &dir);
2481da177e4SLinus Torvalds if (ret)
249deed1bfdSRussell King goto unlock;
2501da177e4SLinus Torvalds
2512638ffbaSAl Viro if (ctx->pos == 0) {
2522638ffbaSAl Viro if (!dir_emit_dot(file, ctx))
253deed1bfdSRussell King goto unlock_relse;
2542638ffbaSAl Viro ctx->pos = 1;
2552638ffbaSAl Viro }
2562638ffbaSAl Viro if (ctx->pos == 1) {
2572638ffbaSAl Viro if (!dir_emit(ctx, "..", 2, dir.parent_id, DT_DIR))
258deed1bfdSRussell King goto unlock_relse;
2592638ffbaSAl Viro ctx->pos = 2;
2601da177e4SLinus Torvalds }
2611da177e4SLinus Torvalds
2624287e4deSRussell King ret = ops->iterate(&dir, ctx);
2631da177e4SLinus Torvalds
264deed1bfdSRussell King unlock_relse:
265deed1bfdSRussell King up_read(&adfs_dir_rwsem);
2661dd9f5baSRussell King adfs_dir_relse(&dir);
2671da177e4SLinus Torvalds return ret;
268deed1bfdSRussell King
269deed1bfdSRussell King unlock:
270deed1bfdSRussell King up_read(&adfs_dir_rwsem);
271deed1bfdSRussell King return ret;
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds
2741da177e4SLinus Torvalds int
adfs_dir_update(struct super_block * sb,struct object_info * obj,int wait)275ffdc9064SAl Viro adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
2761da177e4SLinus Torvalds {
2770125f504SJulia Lawall const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
2781da177e4SLinus Torvalds struct adfs_dir dir;
2794a0a88b6SRussell King int ret;
2801da177e4SLinus Torvalds
2814a0a88b6SRussell King if (!IS_ENABLED(CONFIG_ADFS_FS_RW))
2824a0a88b6SRussell King return -EINVAL;
2834a0a88b6SRussell King
284acf5f0beSRussell King if (!ops->update)
285acf5f0beSRussell King return -EINVAL;
2861da177e4SLinus Torvalds
287deed1bfdSRussell King down_write(&adfs_dir_rwsem);
28895fbadbbSRussell King ret = adfs_dir_read(sb, obj->parent_id, 0, &dir);
2891da177e4SLinus Torvalds if (ret)
290deed1bfdSRussell King goto unlock;
2911da177e4SLinus Torvalds
2921da177e4SLinus Torvalds ret = ops->update(&dir, obj);
293f6075c79SRussell King if (ret)
294f6075c79SRussell King goto forget;
295aacc954cSRussell King
296aacc954cSRussell King ret = ops->commit(&dir);
297aacc954cSRussell King if (ret)
298aacc954cSRussell King goto forget;
299deed1bfdSRussell King up_write(&adfs_dir_rwsem);
3001da177e4SLinus Torvalds
301c3c8149bSRussell King adfs_dir_mark_dirty(&dir);
302c3c8149bSRussell King
303f6075c79SRussell King if (wait)
304f6075c79SRussell King ret = adfs_dir_sync(&dir);
305ffdc9064SAl Viro
3061dd9f5baSRussell King adfs_dir_relse(&dir);
307deed1bfdSRussell King return ret;
308deed1bfdSRussell King
309f6075c79SRussell King /*
310f6075c79SRussell King * If the updated failed because the entry wasn't found, we can
311f6075c79SRussell King * just release the buffers. If it was any other error, forget
312f6075c79SRussell King * the dirtied buffers so they aren't written back to the media.
313f6075c79SRussell King */
314f6075c79SRussell King forget:
315f6075c79SRussell King if (ret == -ENOENT)
316f6075c79SRussell King adfs_dir_relse(&dir);
317f6075c79SRussell King else
318f6075c79SRussell King adfs_dir_forget(&dir);
319deed1bfdSRussell King unlock:
320deed1bfdSRussell King up_write(&adfs_dir_rwsem);
3214a0a88b6SRussell King
3221da177e4SLinus Torvalds return ret;
3231da177e4SLinus Torvalds }
3241da177e4SLinus Torvalds
adfs_tolower(unsigned char c)325525715d0SRussell King static unsigned char adfs_tolower(unsigned char c)
326525715d0SRussell King {
327525715d0SRussell King if (c >= 'A' && c <= 'Z')
328525715d0SRussell King c += 'a' - 'A';
329525715d0SRussell King return c;
330525715d0SRussell King }
331525715d0SRussell King
__adfs_compare(const unsigned char * qstr,u32 qlen,const char * str,u32 len)3321e504cf8SRussell King static int __adfs_compare(const unsigned char *qstr, u32 qlen,
3331e504cf8SRussell King const char *str, u32 len)
3341da177e4SLinus Torvalds {
3351e504cf8SRussell King u32 i;
3361da177e4SLinus Torvalds
3371e504cf8SRussell King if (qlen != len)
3381e504cf8SRussell King return 1;
3391da177e4SLinus Torvalds
340525715d0SRussell King for (i = 0; i < qlen; i++)
341525715d0SRussell King if (adfs_tolower(qstr[i]) != adfs_tolower(str[i]))
3421da177e4SLinus Torvalds return 1;
343525715d0SRussell King
3441e504cf8SRussell King return 0;
3451e504cf8SRussell King }
3461da177e4SLinus Torvalds
adfs_dir_lookup_byname(struct inode * inode,const struct qstr * qstr,struct object_info * obj)3471e504cf8SRussell King static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
3481e504cf8SRussell King struct object_info *obj)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds struct super_block *sb = inode->i_sb;
3510125f504SJulia Lawall const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
3521e504cf8SRussell King const unsigned char *name;
3531da177e4SLinus Torvalds struct adfs_dir dir;
3541e504cf8SRussell King u32 name_len;
3551da177e4SLinus Torvalds int ret;
3561da177e4SLinus Torvalds
357deed1bfdSRussell King down_read(&adfs_dir_rwsem);
35890011c7aSRussell King ret = adfs_dir_read_inode(sb, inode, &dir);
3591da177e4SLinus Torvalds if (ret)
360deed1bfdSRussell King goto unlock;
3611da177e4SLinus Torvalds
3621da177e4SLinus Torvalds ret = ops->setpos(&dir, 0);
3631da177e4SLinus Torvalds if (ret)
364deed1bfdSRussell King goto unlock_relse;
3651da177e4SLinus Torvalds
3661da177e4SLinus Torvalds ret = -ENOENT;
3671e504cf8SRussell King name = qstr->name;
3681e504cf8SRussell King name_len = qstr->len;
3691da177e4SLinus Torvalds while (ops->getnext(&dir, obj) == 0) {
3701e504cf8SRussell King if (!__adfs_compare(name, name_len, obj->name, obj->name_len)) {
3711da177e4SLinus Torvalds ret = 0;
3721da177e4SLinus Torvalds break;
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds }
375*25e5d4dfSRussell King obj->parent_id = ADFS_I(inode)->indaddr;
3761da177e4SLinus Torvalds
377deed1bfdSRussell King unlock_relse:
378deed1bfdSRussell King up_read(&adfs_dir_rwsem);
3791dd9f5baSRussell King adfs_dir_relse(&dir);
380deed1bfdSRussell King return ret;
381deed1bfdSRussell King
382deed1bfdSRussell King unlock:
383deed1bfdSRussell King up_read(&adfs_dir_rwsem);
3841da177e4SLinus Torvalds return ret;
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds
3874b6f5d20SArjan van de Ven const struct file_operations adfs_dir_operations = {
3881da177e4SLinus Torvalds .read = generic_read_dir,
38959af1584SAl Viro .llseek = generic_file_llseek,
390cdc46e99SRussell King .iterate_shared = adfs_iterate,
3911b061d92SChristoph Hellwig .fsync = generic_file_fsync,
3921da177e4SLinus Torvalds };
3931da177e4SLinus Torvalds
3941da177e4SLinus Torvalds static int
adfs_hash(const struct dentry * parent,struct qstr * qstr)395da53be12SLinus Torvalds adfs_hash(const struct dentry *parent, struct qstr *qstr)
3961da177e4SLinus Torvalds {
3971da177e4SLinus Torvalds const unsigned char *name;
3981da177e4SLinus Torvalds unsigned long hash;
3992eb0684fSRussell King u32 len;
4001da177e4SLinus Torvalds
4012eb0684fSRussell King if (qstr->len > ADFS_SB(parent->d_sb)->s_namelen)
4022eb0684fSRussell King return -ENAMETOOLONG;
4031da177e4SLinus Torvalds
4042eb0684fSRussell King len = qstr->len;
4051da177e4SLinus Torvalds name = qstr->name;
4068387ff25SLinus Torvalds hash = init_name_hash(parent);
4072eb0684fSRussell King while (len--)
408525715d0SRussell King hash = partial_name_hash(adfs_tolower(*name++), hash);
4091da177e4SLinus Torvalds qstr->hash = end_name_hash(hash);
4101da177e4SLinus Torvalds
4111da177e4SLinus Torvalds return 0;
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds
4141da177e4SLinus Torvalds /*
4151da177e4SLinus Torvalds * Compare two names, taking note of the name length
4161da177e4SLinus Torvalds * requirements of the underlying filesystem.
4171da177e4SLinus Torvalds */
adfs_compare(const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * qstr)4181e504cf8SRussell King static int adfs_compare(const struct dentry *dentry, unsigned int len,
4191e504cf8SRussell King const char *str, const struct qstr *qstr)
4201da177e4SLinus Torvalds {
4211e504cf8SRussell King return __adfs_compare(qstr->name, qstr->len, str, len);
4221da177e4SLinus Torvalds }
4231da177e4SLinus Torvalds
424e16404edSAl Viro const struct dentry_operations adfs_dentry_operations = {
4251da177e4SLinus Torvalds .d_hash = adfs_hash,
4261da177e4SLinus Torvalds .d_compare = adfs_compare,
4271da177e4SLinus Torvalds };
4281da177e4SLinus Torvalds
4291da177e4SLinus Torvalds static struct dentry *
adfs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)43000cd8dd3SAl Viro adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
4311da177e4SLinus Torvalds {
4321da177e4SLinus Torvalds struct inode *inode = NULL;
4331da177e4SLinus Torvalds struct object_info obj;
4341da177e4SLinus Torvalds int error;
4351da177e4SLinus Torvalds
4361da177e4SLinus Torvalds error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj);
4371da177e4SLinus Torvalds if (error == 0) {
4381da177e4SLinus Torvalds /*
4391da177e4SLinus Torvalds * This only returns NULL if get_empty_inode
4401da177e4SLinus Torvalds * fails.
4411da177e4SLinus Torvalds */
4421da177e4SLinus Torvalds inode = adfs_iget(dir->i_sb, &obj);
4439a7dddcaSAl Viro if (!inode)
4449a7dddcaSAl Viro inode = ERR_PTR(-EACCES);
4459a7dddcaSAl Viro } else if (error != -ENOENT) {
4469a7dddcaSAl Viro inode = ERR_PTR(error);
4471da177e4SLinus Torvalds }
4489a7dddcaSAl Viro return d_splice_alias(inode, dentry);
4491da177e4SLinus Torvalds }
4501da177e4SLinus Torvalds
4511da177e4SLinus Torvalds /*
4521da177e4SLinus Torvalds * directories can handle most operations...
4531da177e4SLinus Torvalds */
454754661f1SArjan van de Ven const struct inode_operations adfs_dir_inode_operations = {
4551da177e4SLinus Torvalds .lookup = adfs_lookup,
4561da177e4SLinus Torvalds .setattr = adfs_notify_change,
4571da177e4SLinus Torvalds };
458