1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/*
* linux/fs/adfs/namei.c
*
* Copyright (C) 1997 Russell King
*/
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/adfs_fs.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/locks.h>
/*
* NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure
*/
static int adfs_match (int len, const char * const name, struct adfs_idir_entry *de)
{
int i;
if (!de || len > ADFS_NAME_LEN)
return 0;
/*
* "" means "." ---> so paths like "/usr/lib//libc.a" work
*/
if (!len && de->name_len == 1 && de->name[0] == '.' &&
de->name[1] == '\0')
return 1;
if (len != de->name_len)
return 0;
for (i = 0; i < len; i++)
if ((de->name[i] ^ name[i]) & 0x5f)
return 0;
return 1;
}
static int adfs_find_entry (struct inode *dir, const char * const name, int namelen,
struct adfs_idir_entry *ide)
{
struct super_block *sb;
struct buffer_head *bh[4];
union adfs_dirtail dt;
unsigned long parent_object_id, dir_object_id;
int buffers, pos;
sb = dir->i_sb;
if (adfs_inode_validate (dir)) {
adfs_error (sb, "adfs_find_entry",
"invalid inode number: %lu", dir->i_ino);
return 0;
}
if (!(buffers = adfs_dir_read (dir, bh))) {
adfs_error (sb, "adfs_find_entry", "unable to read directory");
return 0;
}
if (adfs_dir_check (dir, bh, buffers, &dt)) {
adfs_dir_free (bh, buffers);
return 0;
}
parent_object_id = adfs_val (dt.new.dirparent, 3);
dir_object_id = adfs_inode_objid (dir);
if (namelen == 2 && name[0] == '.' && name[1] == '.') {
ide->name_len = 2;
ide->name[0] = ide->name[1] = '.';
ide->name[2] = '\0';
ide->inode_no = adfs_inode_generate (parent_object_id, 0);
adfs_dir_free (bh, buffers);
return 1;
}
pos = 5;
do {
if (!adfs_dir_get (sb, bh, buffers, pos, dir_object_id, ide))
break;
if (adfs_match (namelen, name, ide)) {
adfs_dir_free (bh, buffers);
return pos;
}
pos += 26;
} while (1);
adfs_dir_free (bh, buffers);
return 0;
}
struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry)
{
struct inode *inode = NULL;
struct adfs_idir_entry de;
unsigned long ino;
if (dentry->d_name.len > ADFS_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
if (adfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de)) {
ino = de.inode_no;
inode = iget (dir->i_sb, ino);
if (!inode)
return ERR_PTR(-EACCES);
}
d_add(dentry, inode);
return NULL;
}
|