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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
/* namei.c
name lookup for EFS filesystem
(C)95,96 Christian Vogelgsang
*/
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/efs_fs.h>
#include <linux/efs_fs_i.h>
#include <linux/efs_fs_sb.h>
#include <linux/stat.h>
#include <asm/uaccess.h>
/* ----- efs_find_entry -----
search a raw efs dir entry for the given name
dir - inode of directory
oname - name to search for
onamelen- length of name
return - inode number of the found entry or 0 on error
*/
static struct buffer_head * efs_find_entry(struct inode *dir,
const char *oname,
int onamelen,
struct efs_dir_entry *res_dir)
{
struct efs_inode_info *ini = &dir->u.efs_i;
struct buffer_head *bh = NULL;
__u32 inode;
__u16 i;
__u8 *name;
__u16 namelen;
__u32 blknum,b;
struct efs_dirblk *db;
/* Warnings */
if(ini->efs_total!=1)
printk("efs_find: More than one extent!\n");
if(dir->i_size & (EFS_BLOCK_SIZE-1))
printk("efs_find: dirsize != blocklen * n\n");
/* Search in every dirblock */
inode = 0;
blknum = dir->i_size >> EFS_BLOCK_SIZE_BITS;
#ifdef DEBUG_EFS_DIRS
printk("EFS: directory with inode %#xd has %d blocks\n",
dir->i_ino, blknum);
#endif
for(b=0;b<blknum;b++) {
int db_offset;
#ifdef DEBUG_EFS_DIRS
printk("EFS: trying block %d\n", b);
#endif
/* Read a raw dirblock */
bh = bread(dir->i_dev,efs_bmap(dir,b),EFS_BLOCK_SIZE);
if(!bh) {
printk("EFS: efs_bmap returned NULL!\n");
return 0;
}
db = (struct efs_dirblk *)bh->b_data;
if (db->db_magic != EFS_DIRBLK_MAGIC) {
printk("EFS: dirblk has bad magic (%#xl)!\n",
db->db_magic);
return NULL;
}
#ifdef DEBUG_EFS_DIRS
printk("EFS: db %d has %d entries, starting at offset %#x\n",
b, db->db_slots, (__u16)db->db_firstused << 1);
#endif
for(i = 0 ; i < db->db_slots ; i++) {
struct efs_dent * de;
int entry_inode;
db_offset = ((__u16)db->db_space[i] << 1)
- EFS_DIRBLK_HEADERSIZE;
de = (struct efs_dent *)(&db->db_space[db_offset]);
/* inode, namelen and name of direntry */
entry_inode = EFS_DE_GET_INUM(de);
namelen = de->d_namelen;
name = de->d_name;
#ifdef DEBUG_EFS_DIRS
printk("EFS: entry %d @ %#lx has inode %#x: \"%*s\"\n",
i, db_offset, entry_inode, namelen, name);
#endif
/* we found the name! */
if((namelen==onamelen)&&
(!memcmp(oname,name,onamelen))) {
res_dir->inode = entry_inode;
#ifdef DEBUG_EFS_DIRS
printk("EFS: found inode %d\n",
entry_inode);
#endif
return bh;
}
}
}
#ifdef DEBUG_EFS_DIRS
printk("EFS: efs_find_entry didn't find inode for \"%s\"/%d!\n",
oname, onamelen);
#endif
return NULL;
/* not reached */
}
/* ----- efs_lookup -----
lookup inode operation:
check if a given name is in the dir directory
dir - pointer to inode of directory
name - name we must search for
len - length of name
result - pointer to inode struct if we found it or NULL on error
return - 0 everything is ok or <0 on error
*/
int efs_lookup(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = NULL;
struct buffer_head *bh;
struct efs_dir_entry de;
bh = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
if (bh) {
int ino = de.inode;
brelse(bh);
inode = iget(dir->i_sb, ino);
if (!inode)
return -EACCES;
}
d_add(dentry, inode);
return 0;
}
|