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