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 15static 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 26static 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 35static inline unsigned long dir_pages(struct inode *inode) 36{ 37 return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; 38} 39 40static 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 49static 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 66static 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 pr_err("invalid direntry size (%i).\n", de->de_size); 81 return 0; 82 } 83 lf = qnx6_longname(s, de, &page); 84 if (IS_ERR(lf)) { 85 pr_err("Error reading longname\n"); 86 return 0; 87 } 88 89 lf_size = fs16_to_cpu(sbi, lf->lf_size); 90 91 if (lf_size > QNX6_LONG_NAME_MAX) { 92 pr_debug("file %s\n", lf->lf_fname); 93 pr_err("Filename too long (%i)\n", lf_size); 94 qnx6_put_page(page); 95 return 0; 96 } 97 98 /* calc & validate longfilename checksum 99 mmi 3g filesystem does not have that checksum */ 100 if (!test_opt(s, MMI_FS) && fs32_to_cpu(sbi, de->de_checksum) != 101 qnx6_lfile_checksum(lf->lf_fname, lf_size)) 102 pr_info("long filename checksum error.\n"); 103 104 pr_debug("qnx6_readdir:%.*s inode:%u\n", 105 lf_size, lf->lf_fname, de_inode); 106 if (!dir_emit(ctx, lf->lf_fname, lf_size, de_inode, DT_UNKNOWN)) { 107 qnx6_put_page(page); 108 return 0; 109 } 110 111 qnx6_put_page(page); 112 /* success */ 113 return 1; 114} 115 116static int qnx6_readdir(struct file *file, struct dir_context *ctx) 117{ 118 struct inode *inode = file_inode(file); 119 struct super_block *s = inode->i_sb; 120 struct qnx6_sb_info *sbi = QNX6_SB(s); 121 loff_t pos = ctx->pos & ~(QNX6_DIR_ENTRY_SIZE - 1); 122 unsigned long npages = dir_pages(inode); 123 unsigned long n = pos >> PAGE_CACHE_SHIFT; 124 unsigned start = (pos & ~PAGE_CACHE_MASK) / QNX6_DIR_ENTRY_SIZE; 125 bool done = false; 126 127 ctx->pos = pos; 128 if (ctx->pos >= inode->i_size) 129 return 0; 130 131 for ( ; !done && n < npages; n++, start = 0) { 132 struct page *page = qnx6_get_page(inode, n); 133 int limit = last_entry(inode, n); 134 struct qnx6_dir_entry *de; 135 int i = start; 136 137 if (IS_ERR(page)) { 138 pr_err("%s(): read failed\n", __func__); 139 ctx->pos = (n + 1) << PAGE_CACHE_SHIFT; 140 return PTR_ERR(page); 141 } 142 de = ((struct qnx6_dir_entry *)page_address(page)) + start; 143 for (; i < limit; i++, de++, ctx->pos += QNX6_DIR_ENTRY_SIZE) { 144 int size = de->de_size; 145 u32 no_inode = fs32_to_cpu(sbi, de->de_inode); 146 147 if (!no_inode || !size) 148 continue; 149 150 if (size > QNX6_SHORT_NAME_MAX) { 151 /* long filename detected 152 get the filename from long filename 153 structure / block */ 154 if (!qnx6_dir_longfilename(inode, 155 (struct qnx6_long_dir_entry *)de, 156 ctx, no_inode)) { 157 done = true; 158 break; 159 } 160 } else { 161 pr_debug("%s():%.*s inode:%u\n", 162 __func__, size, de->de_fname, 163 no_inode); 164 if (!dir_emit(ctx, de->de_fname, size, 165 no_inode, DT_UNKNOWN)) { 166 done = true; 167 break; 168 } 169 } 170 } 171 qnx6_put_page(page); 172 } 173 return 0; 174} 175 176/* 177 * check if the long filename is correct. 178 */ 179static unsigned qnx6_long_match(int len, const char *name, 180 struct qnx6_long_dir_entry *de, struct inode *dir) 181{ 182 struct super_block *s = dir->i_sb; 183 struct qnx6_sb_info *sbi = QNX6_SB(s); 184 struct page *page; 185 int thislen; 186 struct qnx6_long_filename *lf = qnx6_longname(s, de, &page); 187 188 if (IS_ERR(lf)) 189 return 0; 190 191 thislen = fs16_to_cpu(sbi, lf->lf_size); 192 if (len != thislen) { 193 qnx6_put_page(page); 194 return 0; 195 } 196 if (memcmp(name, lf->lf_fname, len) == 0) { 197 qnx6_put_page(page); 198 return fs32_to_cpu(sbi, de->de_inode); 199 } 200 qnx6_put_page(page); 201 return 0; 202} 203 204/* 205 * check if the filename is correct. 206 */ 207static unsigned qnx6_match(struct super_block *s, int len, const char *name, 208 struct qnx6_dir_entry *de) 209{ 210 struct qnx6_sb_info *sbi = QNX6_SB(s); 211 if (memcmp(name, de->de_fname, len) == 0) 212 return fs32_to_cpu(sbi, de->de_inode); 213 return 0; 214} 215 216 217unsigned qnx6_find_entry(int len, struct inode *dir, const char *name, 218 struct page **res_page) 219{ 220 struct super_block *s = dir->i_sb; 221 struct qnx6_inode_info *ei = QNX6_I(dir); 222 struct page *page = NULL; 223 unsigned long start, n; 224 unsigned long npages = dir_pages(dir); 225 unsigned ino; 226 struct qnx6_dir_entry *de; 227 struct qnx6_long_dir_entry *lde; 228 229 *res_page = NULL; 230 231 if (npages == 0) 232 return 0; 233 start = ei->i_dir_start_lookup; 234 if (start >= npages) 235 start = 0; 236 n = start; 237 238 do { 239 page = qnx6_get_page(dir, n); 240 if (!IS_ERR(page)) { 241 int limit = last_entry(dir, n); 242 int i; 243 244 de = (struct qnx6_dir_entry *)page_address(page); 245 for (i = 0; i < limit; i++, de++) { 246 if (len <= QNX6_SHORT_NAME_MAX) { 247 /* short filename */ 248 if (len != de->de_size) 249 continue; 250 ino = qnx6_match(s, len, name, de); 251 if (ino) 252 goto found; 253 } else if (de->de_size == 0xff) { 254 /* deal with long filename */ 255 lde = (struct qnx6_long_dir_entry *)de; 256 ino = qnx6_long_match(len, 257 name, lde, dir); 258 if (ino) 259 goto found; 260 } else 261 pr_err("undefined filename size in inode.\n"); 262 } 263 qnx6_put_page(page); 264 } 265 266 if (++n >= npages) 267 n = 0; 268 } while (n != start); 269 return 0; 270 271found: 272 *res_page = page; 273 ei->i_dir_start_lookup = n; 274 return ino; 275} 276 277const struct file_operations qnx6_dir_operations = { 278 .llseek = generic_file_llseek, 279 .read = generic_read_dir, 280 .iterate = qnx6_readdir, 281 .fsync = generic_file_fsync, 282}; 283 284const struct inode_operations qnx6_dir_inode_operations = { 285 .lookup = qnx6_lookup, 286}; 287