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