diff options
Diffstat (limited to 'fs/qnx4/namei.c')
-rw-r--r-- | fs/qnx4/namei.c | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c new file mode 100644 index 000000000000..4af4951d7f54 --- /dev/null +++ b/fs/qnx4/namei.c | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | * QNX4 file system, Linux implementation. | ||
3 | * | ||
4 | * Version : 0.2.1 | ||
5 | * | ||
6 | * Using parts of the xiafs filesystem. | ||
7 | * | ||
8 | * History : | ||
9 | * | ||
10 | * 01-06-1998 by Richard Frowijn : first release. | ||
11 | * 21-06-1998 by Frank Denis : dcache support, fixed error codes. | ||
12 | * 04-07-1998 by Frank Denis : first step for rmdir/unlink. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/time.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/qnx4_fs.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/stat.h> | ||
22 | #include <linux/fcntl.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/smp_lock.h> | ||
25 | #include <linux/buffer_head.h> | ||
26 | |||
27 | |||
28 | /* | ||
29 | * check if the filename is correct. For some obscure reason, qnx writes a | ||
30 | * new file twice in the directory entry, first with all possible options at 0 | ||
31 | * and for a second time the way it is, they want us not to access the qnx | ||
32 | * filesystem when whe are using linux. | ||
33 | */ | ||
34 | static int qnx4_match(int len, const char *name, | ||
35 | struct buffer_head *bh, unsigned long *offset) | ||
36 | { | ||
37 | struct qnx4_inode_entry *de; | ||
38 | int namelen, thislen; | ||
39 | |||
40 | if (bh == NULL) { | ||
41 | printk("qnx4: matching unassigned buffer !\n"); | ||
42 | return 0; | ||
43 | } | ||
44 | de = (struct qnx4_inode_entry *) (bh->b_data + *offset); | ||
45 | *offset += QNX4_DIR_ENTRY_SIZE; | ||
46 | if ((de->di_status & QNX4_FILE_LINK) != 0) { | ||
47 | namelen = QNX4_NAME_MAX; | ||
48 | } else { | ||
49 | namelen = QNX4_SHORT_NAME_MAX; | ||
50 | } | ||
51 | /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ | ||
52 | if (!len && (de->di_fname[0] == '.') && (de->di_fname[1] == '\0')) { | ||
53 | return 1; | ||
54 | } | ||
55 | thislen = strlen( de->di_fname ); | ||
56 | if ( thislen > namelen ) | ||
57 | thislen = namelen; | ||
58 | if (len != thislen) { | ||
59 | return 0; | ||
60 | } | ||
61 | if (strncmp(name, de->di_fname, len) == 0) { | ||
62 | if ((de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK)) != 0) { | ||
63 | return 1; | ||
64 | } | ||
65 | } | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static struct buffer_head *qnx4_find_entry(int len, struct inode *dir, | ||
70 | const char *name, struct qnx4_inode_entry **res_dir, int *ino) | ||
71 | { | ||
72 | unsigned long block, offset, blkofs; | ||
73 | struct buffer_head *bh; | ||
74 | |||
75 | *res_dir = NULL; | ||
76 | if (!dir->i_sb) { | ||
77 | printk("qnx4: no superblock on dir.\n"); | ||
78 | return NULL; | ||
79 | } | ||
80 | bh = NULL; | ||
81 | block = offset = blkofs = 0; | ||
82 | while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) { | ||
83 | if (!bh) { | ||
84 | bh = qnx4_bread(dir, blkofs, 0); | ||
85 | if (!bh) { | ||
86 | blkofs++; | ||
87 | continue; | ||
88 | } | ||
89 | } | ||
90 | *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset); | ||
91 | if (qnx4_match(len, name, bh, &offset)) { | ||
92 | block = qnx4_block_map( dir, blkofs ); | ||
93 | *ino = block * QNX4_INODES_PER_BLOCK + | ||
94 | (offset / QNX4_DIR_ENTRY_SIZE) - 1; | ||
95 | return bh; | ||
96 | } | ||
97 | if (offset < bh->b_size) { | ||
98 | continue; | ||
99 | } | ||
100 | brelse(bh); | ||
101 | bh = NULL; | ||
102 | offset = 0; | ||
103 | blkofs++; | ||
104 | } | ||
105 | brelse(bh); | ||
106 | *res_dir = NULL; | ||
107 | return NULL; | ||
108 | } | ||
109 | |||
110 | struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | ||
111 | { | ||
112 | int ino; | ||
113 | struct qnx4_inode_entry *de; | ||
114 | struct qnx4_link_info *lnk; | ||
115 | struct buffer_head *bh; | ||
116 | const char *name = dentry->d_name.name; | ||
117 | int len = dentry->d_name.len; | ||
118 | struct inode *foundinode = NULL; | ||
119 | |||
120 | lock_kernel(); | ||
121 | if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) | ||
122 | goto out; | ||
123 | /* The entry is linked, let's get the real info */ | ||
124 | if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) { | ||
125 | lnk = (struct qnx4_link_info *) de; | ||
126 | ino = (le32_to_cpu(lnk->dl_inode_blk) - 1) * | ||
127 | QNX4_INODES_PER_BLOCK + | ||
128 | lnk->dl_inode_ndx; | ||
129 | } | ||
130 | brelse(bh); | ||
131 | |||
132 | if ((foundinode = iget(dir->i_sb, ino)) == NULL) { | ||
133 | unlock_kernel(); | ||
134 | QNX4DEBUG(("qnx4: lookup->iget -> NULL\n")); | ||
135 | return ERR_PTR(-EACCES); | ||
136 | } | ||
137 | out: | ||
138 | unlock_kernel(); | ||
139 | d_add(dentry, foundinode); | ||
140 | |||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | #ifdef CONFIG_QNX4FS_RW | ||
145 | int qnx4_create(struct inode *dir, struct dentry *dentry, int mode, | ||
146 | struct nameidata *nd) | ||
147 | { | ||
148 | QNX4DEBUG(("qnx4: qnx4_create\n")); | ||
149 | if (dir == NULL) { | ||
150 | return -ENOENT; | ||
151 | } | ||
152 | return -ENOSPC; | ||
153 | } | ||
154 | |||
155 | int qnx4_rmdir(struct inode *dir, struct dentry *dentry) | ||
156 | { | ||
157 | struct buffer_head *bh; | ||
158 | struct qnx4_inode_entry *de; | ||
159 | struct inode *inode; | ||
160 | int retval; | ||
161 | int ino; | ||
162 | |||
163 | QNX4DEBUG(("qnx4: qnx4_rmdir [%s]\n", dentry->d_name.name)); | ||
164 | lock_kernel(); | ||
165 | bh = qnx4_find_entry(dentry->d_name.len, dir, dentry->d_name.name, | ||
166 | &de, &ino); | ||
167 | if (bh == NULL) { | ||
168 | unlock_kernel(); | ||
169 | return -ENOENT; | ||
170 | } | ||
171 | inode = dentry->d_inode; | ||
172 | if (inode->i_ino != ino) { | ||
173 | retval = -EIO; | ||
174 | goto end_rmdir; | ||
175 | } | ||
176 | #if 0 | ||
177 | if (!empty_dir(inode)) { | ||
178 | retval = -ENOTEMPTY; | ||
179 | goto end_rmdir; | ||
180 | } | ||
181 | #endif | ||
182 | if (inode->i_nlink != 2) { | ||
183 | QNX4DEBUG(("empty directory has nlink!=2 (%d)\n", inode->i_nlink)); | ||
184 | } | ||
185 | QNX4DEBUG(("qnx4: deleting directory\n")); | ||
186 | de->di_status = 0; | ||
187 | memset(de->di_fname, 0, sizeof de->di_fname); | ||
188 | de->di_mode = 0; | ||
189 | mark_buffer_dirty(bh); | ||
190 | inode->i_nlink = 0; | ||
191 | mark_inode_dirty(inode); | ||
192 | inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; | ||
193 | dir->i_nlink--; | ||
194 | mark_inode_dirty(dir); | ||
195 | retval = 0; | ||
196 | |||
197 | end_rmdir: | ||
198 | brelse(bh); | ||
199 | |||
200 | unlock_kernel(); | ||
201 | return retval; | ||
202 | } | ||
203 | |||
204 | int qnx4_unlink(struct inode *dir, struct dentry *dentry) | ||
205 | { | ||
206 | struct buffer_head *bh; | ||
207 | struct qnx4_inode_entry *de; | ||
208 | struct inode *inode; | ||
209 | int retval; | ||
210 | int ino; | ||
211 | |||
212 | QNX4DEBUG(("qnx4: qnx4_unlink [%s]\n", dentry->d_name.name)); | ||
213 | lock_kernel(); | ||
214 | bh = qnx4_find_entry(dentry->d_name.len, dir, dentry->d_name.name, | ||
215 | &de, &ino); | ||
216 | if (bh == NULL) { | ||
217 | unlock_kernel(); | ||
218 | return -ENOENT; | ||
219 | } | ||
220 | inode = dentry->d_inode; | ||
221 | if (inode->i_ino != ino) { | ||
222 | retval = -EIO; | ||
223 | goto end_unlink; | ||
224 | } | ||
225 | retval = -EPERM; | ||
226 | if (!inode->i_nlink) { | ||
227 | QNX4DEBUG(("Deleting nonexistent file (%s:%lu), %d\n", | ||
228 | inode->i_sb->s_id, | ||
229 | inode->i_ino, inode->i_nlink)); | ||
230 | inode->i_nlink = 1; | ||
231 | } | ||
232 | de->di_status = 0; | ||
233 | memset(de->di_fname, 0, sizeof de->di_fname); | ||
234 | de->di_mode = 0; | ||
235 | mark_buffer_dirty(bh); | ||
236 | dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; | ||
237 | mark_inode_dirty(dir); | ||
238 | inode->i_nlink--; | ||
239 | inode->i_ctime = dir->i_ctime; | ||
240 | mark_inode_dirty(inode); | ||
241 | retval = 0; | ||
242 | |||
243 | end_unlink: | ||
244 | unlock_kernel(); | ||
245 | brelse(bh); | ||
246 | |||
247 | return retval; | ||
248 | } | ||
249 | #endif | ||