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 250