File: /usr/src/linux/fs/qnx4/namei.c

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