summaryrefslogtreecommitdiffstats
path: root/fs/efs/namei.c
blob: f96a962e6e5448d5e3de509aab4506ab1a0e1451 (plain)
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;
}