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 struct dir_context *ctx, 69 unsigned de_inode) 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 (!dir_emit(ctx, lf->lf_fname, lf_size, de_inode, DT_UNKNOWN)) { 108 qnx6_put_page(page); 109 return 0; 110 } 111 112 qnx6_put_page(page); 113 /* success */ 114 return 1; 115 } 116 117 static int qnx6_readdir(struct file *file, struct dir_context *ctx) 118 { 119 struct inode *inode = file_inode(file); 120 struct super_block *s = inode->i_sb; 121 struct qnx6_sb_info *sbi = QNX6_SB(s); 122 loff_t pos = ctx->pos & ~(QNX6_DIR_ENTRY_SIZE - 1); 123 unsigned long npages = dir_pages(inode); 124 unsigned long n = pos >> PAGE_CACHE_SHIFT; 125 unsigned start = (pos & ~PAGE_CACHE_MASK) / QNX6_DIR_ENTRY_SIZE; 126 bool done = false; 127 128 ctx->pos = pos; 129 if (ctx->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 ctx->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++, ctx->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 ctx, no_inode)) { 158 done = true; 159 break; 160 } 161 } else { 162 QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s" 163 " inode:%u\n", size, de->de_fname, 164 no_inode)); 165 if (!dir_emit(ctx, de->de_fname, size, 166 no_inode, DT_UNKNOWN)) { 167 done = true; 168 break; 169 } 170 } 171 } 172 qnx6_put_page(page); 173 } 174 return 0; 175 } 176 177 /* 178 * check if the long filename is correct. 179 */ 180 static unsigned qnx6_long_match(int len, const char *name, 181 struct qnx6_long_dir_entry *de, struct inode *dir) 182 { 183 struct super_block *s = dir->i_sb; 184 struct qnx6_sb_info *sbi = QNX6_SB(s); 185 struct page *page; 186 int thislen; 187 struct qnx6_long_filename *lf = qnx6_longname(s, de, &page); 188 189 if (IS_ERR(lf)) 190 return 0; 191 192 thislen = fs16_to_cpu(sbi, lf->lf_size); 193 if (len != thislen) { 194 qnx6_put_page(page); 195 return 0; 196 } 197 if (memcmp(name, lf->lf_fname, len) == 0) { 198 qnx6_put_page(page); 199 return fs32_to_cpu(sbi, de->de_inode); 200 } 201 qnx6_put_page(page); 202 return 0; 203 } 204 205 /* 206 * check if the filename is correct. 207 */ 208 static unsigned qnx6_match(struct super_block *s, int len, const char *name, 209 struct qnx6_dir_entry *de) 210 { 211 struct qnx6_sb_info *sbi = QNX6_SB(s); 212 if (memcmp(name, de->de_fname, len) == 0) 213 return fs32_to_cpu(sbi, de->de_inode); 214 return 0; 215 } 216 217 218 unsigned qnx6_find_entry(int len, struct inode *dir, const char *name, 219 struct page **res_page) 220 { 221 struct super_block *s = dir->i_sb; 222 struct qnx6_inode_info *ei = QNX6_I(dir); 223 struct page *page = NULL; 224 unsigned long start, n; 225 unsigned long npages = dir_pages(dir); 226 unsigned ino; 227 struct qnx6_dir_entry *de; 228 struct qnx6_long_dir_entry *lde; 229 230 *res_page = NULL; 231 232 if (npages == 0) 233 return 0; 234 start = ei->i_dir_start_lookup; 235 if (start >= npages) 236 start = 0; 237 n = start; 238 239 do { 240 page = qnx6_get_page(dir, n); 241 if (!IS_ERR(page)) { 242 int limit = last_entry(dir, n); 243 int i; 244 245 de = (struct qnx6_dir_entry *)page_address(page); 246 for (i = 0; i < limit; i++, de++) { 247 if (len <= QNX6_SHORT_NAME_MAX) { 248 /* short filename */ 249 if (len != de->de_size) 250 continue; 251 ino = qnx6_match(s, len, name, de); 252 if (ino) 253 goto found; 254 } else if (de->de_size == 0xff) { 255 /* deal with long filename */ 256 lde = (struct qnx6_long_dir_entry *)de; 257 ino = qnx6_long_match(len, 258 name, lde, dir); 259 if (ino) 260 goto found; 261 } else 262 printk(KERN_ERR "qnx6: undefined " 263 "filename size in inode.\n"); 264 } 265 qnx6_put_page(page); 266 } 267 268 if (++n >= npages) 269 n = 0; 270 } while (n != start); 271 return 0; 272 273 found: 274 *res_page = page; 275 ei->i_dir_start_lookup = n; 276 return ino; 277 } 278 279 const struct file_operations qnx6_dir_operations = { 280 .llseek = generic_file_llseek, 281 .read = generic_read_dir, 282 .iterate = qnx6_readdir, 283 .fsync = generic_file_fsync, 284 }; 285 286 const struct inode_operations qnx6_dir_inode_operations = { 287 .lookup = qnx6_lookup, 288 }; 289