Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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