1 /* 2 * QNX6 file system, Linux implementation. 3 * 4 * Version : 1.0.0 5 * 6 * History : 7 * 8 * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release. 9 * 16-02-2012 pagemap extension by Al Viro 10 * 11 */ 12 13 #include "qnx6.h" 14 15 static unsigned qnx6_lfile_checksum(char *name, unsigned size) 16 { 17 unsigned crc = 0; 18 char *end = name + size; 19 while (name < end) { 20 crc = ((crc >> 1) + *(name++)) ^ 21 ((crc & 0x00000001) ? 0x80000000 : 0); 22 } 23 return crc; 24 } 25 26 static struct page *qnx6_get_page(struct inode *dir, unsigned long n) 27 { 28 struct address_space *mapping = dir->i_mapping; 29 struct page *page = read_mapping_page(mapping, n, NULL); 30 if (!IS_ERR(page)) 31 kmap(page); 32 return page; 33 } 34 35 static inline unsigned long dir_pages(struct inode *inode) 36 { 37 return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; 38 } 39 40 static unsigned last_entry(struct inode *inode, unsigned long page_nr) 41 { 42 unsigned long last_byte = inode->i_size; 43 last_byte -= page_nr << PAGE_CACHE_SHIFT; 44 if (last_byte > PAGE_CACHE_SIZE) 45 last_byte = PAGE_CACHE_SIZE; 46 return last_byte / QNX6_DIR_ENTRY_SIZE; 47 } 48 49 static struct qnx6_long_filename *qnx6_longname(struct super_block *sb, 50 struct qnx6_long_dir_entry *de, 51 struct page **p) 52 { 53 struct qnx6_sb_info *sbi = QNX6_SB(sb); 54 u32 s = fs32_to_cpu(sbi, de->de_long_inode); /* in block units */ 55 u32 n = s >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits); /* in pages */ 56 /* within page */ 57 u32 offs = (s << sb->s_blocksize_bits) & ~PAGE_CACHE_MASK; 58 struct address_space *mapping = sbi->longfile->i_mapping; 59 struct page *page = read_mapping_page(mapping, n, NULL); 60 if (IS_ERR(page)) 61 return ERR_CAST(page); 62 kmap(*p = page); 63 return (struct qnx6_long_filename *)(page_address(page) + offs); 64 } 65 66 static int qnx6_dir_longfilename(struct inode *inode, 67 struct qnx6_long_dir_entry *de, 68 void *dirent, loff_t pos, 69 unsigned de_inode, filldir_t filldir) 70 { 71 struct qnx6_long_filename *lf; 72 struct super_block *s = inode->i_sb; 73 struct qnx6_sb_info *sbi = QNX6_SB(s); 74 struct page *page; 75 int lf_size; 76 77 if (de->de_size != 0xff) { 78 /* error - long filename entries always have size 0xff 79 in direntry */ 80 printk(KERN_ERR "qnx6: invalid direntry size (%i).\n", 81 de->de_size); 82 return 0; 83 } 84 lf = qnx6_longname(s, de, &page); 85 if (IS_ERR(lf)) { 86 printk(KERN_ERR "qnx6:Error reading longname\n"); 87 return 0; 88 } 89 90 lf_size = fs16_to_cpu(sbi, lf->lf_size); 91 92 if (lf_size > QNX6_LONG_NAME_MAX) { 93 QNX6DEBUG((KERN_INFO "file %s\n", lf->lf_fname)); 94 printk(KERN_ERR "qnx6:Filename too long (%i)\n", lf_size); 95 qnx6_put_page(page); 96 return 0; 97 } 98 99 /* calc & validate longfilename checksum 100 mmi 3g filesystem does not have that checksum */ 101 if (!test_opt(s, MMI_FS) && fs32_to_cpu(sbi, de->de_checksum) != 102 qnx6_lfile_checksum(lf->lf_fname, lf_size)) 103 printk(KERN_INFO "qnx6: long filename checksum error.\n"); 104 105 QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s inode:%u\n", 106 lf_size, lf->lf_fname, de_inode)); 107 if (filldir(dirent, lf->lf_fname, lf_size, pos, de_inode, 108 DT_UNKNOWN) < 0) { 109 qnx6_put_page(page); 110 return 0; 111 } 112 113 qnx6_put_page(page); 114 /* success */ 115 return 1; 116 } 117 118 static int qnx6_readdir(struct file *filp, void *dirent, filldir_t filldir) 119 { 120 struct inode *inode = filp->f_path.dentry->d_inode; 121 struct super_block *s = inode->i_sb; 122 struct qnx6_sb_info *sbi = QNX6_SB(s); 123 loff_t pos = filp->f_pos & (QNX6_DIR_ENTRY_SIZE - 1); 124 unsigned long npages = dir_pages(inode); 125 unsigned long n = pos >> PAGE_CACHE_SHIFT; 126 unsigned start = (pos & ~PAGE_CACHE_MASK) / QNX6_DIR_ENTRY_SIZE; 127 bool done = false; 128 129 if (filp->f_pos >= inode->i_size) 130 return 0; 131 132 for ( ; !done && n < npages; n++, start = 0) { 133 struct page *page = qnx6_get_page(inode, n); 134 int limit = last_entry(inode, n); 135 struct qnx6_dir_entry *de; 136 int i = start; 137 138 if (IS_ERR(page)) { 139 printk(KERN_ERR "qnx6_readdir: read failed\n"); 140 filp->f_pos = (n + 1) << PAGE_CACHE_SHIFT; 141 return PTR_ERR(page); 142 } 143 de = ((struct qnx6_dir_entry *)page_address(page)) + start; 144 for (; i < limit; i++, de++, pos += QNX6_DIR_ENTRY_SIZE) { 145 int size = de->de_size; 146 u32 no_inode = fs32_to_cpu(sbi, de->de_inode); 147 148 if (!no_inode || !size) 149 continue; 150 151 if (size > QNX6_SHORT_NAME_MAX) { 152 /* long filename detected 153 get the filename from long filename 154 structure / block */ 155 if (!qnx6_dir_longfilename(inode, 156 (struct qnx6_long_dir_entry *)de, 157 dirent, pos, no_inode, 158 filldir)) { 159 done = true; 160 break; 161 } 162 } else { 163 QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s" 164 " inode:%u\n", size, de->de_fname, 165 no_inode)); 166 if (filldir(dirent, de->de_fname, size, 167 pos, no_inode, DT_UNKNOWN) 168 < 0) { 169 done = true; 170 break; 171 } 172 } 173 } 174 qnx6_put_page(page); 175 } 176 filp->f_pos = pos; 177 return 0; 178 } 179 180 /* 181 * check if the long filename is correct. 182 */ 183 static unsigned qnx6_long_match(int len, const char *name, 184 struct qnx6_long_dir_entry *de, struct inode *dir) 185 { 186 struct super_block *s = dir->i_sb; 187 struct qnx6_sb_info *sbi = QNX6_SB(s); 188 struct page *page; 189 int thislen; 190 struct qnx6_long_filename *lf = qnx6_longname(s, de, &page); 191 192 if (IS_ERR(lf)) 193 return 0; 194 195 thislen = fs16_to_cpu(sbi, lf->lf_size); 196 if (len != thislen) { 197 qnx6_put_page(page); 198 return 0; 199 } 200 if (memcmp(name, lf->lf_fname, len) == 0) { 201 qnx6_put_page(page); 202 return fs32_to_cpu(sbi, de->de_inode); 203 } 204 qnx6_put_page(page); 205 return 0; 206 } 207 208 /* 209 * check if the filename is correct. 210 */ 211 static unsigned qnx6_match(struct super_block *s, int len, const char *name, 212 struct qnx6_dir_entry *de) 213 { 214 struct qnx6_sb_info *sbi = QNX6_SB(s); 215 if (memcmp(name, de->de_fname, len) == 0) 216 return fs32_to_cpu(sbi, de->de_inode); 217 return 0; 218 } 219 220 221 unsigned qnx6_find_entry(int len, struct inode *dir, const char *name, 222 struct page **res_page) 223 { 224 struct super_block *s = dir->i_sb; 225 struct qnx6_inode_info *ei = QNX6_I(dir); 226 struct page *page = NULL; 227 unsigned long start, n; 228 unsigned long npages = dir_pages(dir); 229 unsigned ino; 230 struct qnx6_dir_entry *de; 231 struct qnx6_long_dir_entry *lde; 232 233 *res_page = NULL; 234 235 if (npages == 0) 236 return 0; 237 start = ei->i_dir_start_lookup; 238 if (start >= npages) 239 start = 0; 240 n = start; 241 242 do { 243 page = qnx6_get_page(dir, n); 244 if (!IS_ERR(page)) { 245 int limit = last_entry(dir, n); 246 int i; 247 248 de = (struct qnx6_dir_entry *)page_address(page); 249 for (i = 0; i < limit; i++, de++) { 250 if (len <= QNX6_SHORT_NAME_MAX) { 251 /* short filename */ 252 if (len != de->de_size) 253 continue; 254 ino = qnx6_match(s, len, name, de); 255 if (ino) 256 goto found; 257 } else if (de->de_size == 0xff) { 258 /* deal with long filename */ 259 lde = (struct qnx6_long_dir_entry *)de; 260 ino = qnx6_long_match(len, 261 name, lde, dir); 262 if (ino) 263 goto found; 264 } else 265 printk(KERN_ERR "qnx6: undefined " 266 "filename size in inode.\n"); 267 } 268 qnx6_put_page(page); 269 } 270 271 if (++n >= npages) 272 n = 0; 273 } while (n != start); 274 return 0; 275 276 found: 277 *res_page = page; 278 ei->i_dir_start_lookup = n; 279 return ino; 280 } 281 282 const struct file_operations qnx6_dir_operations = { 283 .llseek = generic_file_llseek, 284 .read = generic_read_dir, 285 .readdir = qnx6_readdir, 286 .fsync = generic_file_fsync, 287 }; 288 289 const struct inode_operations qnx6_dir_inode_operations = { 290 .lookup = qnx6_lookup, 291 }; 292