283 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * QNX6 file system, Linux implementation.4 *5 * Version : 1.0.06 *7 * History :8 *9 * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.10 * 16-02-2012 pagemap extension by Al Viro11 *12 */13 14#include "qnx6.h"15 16static unsigned qnx6_lfile_checksum(char *name, unsigned size)17{18 unsigned crc = 0;19 char *end = name + size;20 while (name < end) {21 crc = ((crc >> 1) + *(name++)) ^22 ((crc & 0x00000001) ? 0x80000000 : 0);23 }24 return crc;25}26 27static void *qnx6_get_folio(struct inode *dir, unsigned long n,28 struct folio **foliop)29{30 struct folio *folio = read_mapping_folio(dir->i_mapping, n, NULL);31 32 if (IS_ERR(folio))33 return folio;34 *foliop = folio;35 return kmap_local_folio(folio, 0);36}37 38static unsigned last_entry(struct inode *inode, unsigned long page_nr)39{40 unsigned long last_byte = inode->i_size;41 last_byte -= page_nr << PAGE_SHIFT;42 if (last_byte > PAGE_SIZE)43 last_byte = PAGE_SIZE;44 return last_byte / QNX6_DIR_ENTRY_SIZE;45}46 47static struct qnx6_long_filename *qnx6_longname(struct super_block *sb,48 struct qnx6_long_dir_entry *de,49 struct folio **foliop)50{51 struct qnx6_sb_info *sbi = QNX6_SB(sb);52 u32 s = fs32_to_cpu(sbi, de->de_long_inode); /* in block units */53 u32 n = s >> (PAGE_SHIFT - sb->s_blocksize_bits); /* in pages */54 u32 offs;55 struct address_space *mapping = sbi->longfile->i_mapping;56 struct folio *folio = read_mapping_folio(mapping, n, NULL);57 58 if (IS_ERR(folio))59 return ERR_CAST(folio);60 offs = offset_in_folio(folio, s << sb->s_blocksize_bits);61 *foliop = folio;62 return kmap_local_folio(folio, offs);63}64 65static int qnx6_dir_longfilename(struct inode *inode,66 struct qnx6_long_dir_entry *de,67 struct dir_context *ctx,68 unsigned de_inode)69{70 struct qnx6_long_filename *lf;71 struct super_block *s = inode->i_sb;72 struct qnx6_sb_info *sbi = QNX6_SB(s);73 struct folio *folio;74 int lf_size;75 76 if (de->de_size != 0xff) {77 /* error - long filename entries always have size 0xff78 in direntry */79 pr_err("invalid direntry size (%i).\n", de->de_size);80 return 0;81 }82 lf = qnx6_longname(s, de, &folio);83 if (IS_ERR(lf)) {84 pr_err("Error reading longname\n");85 return 0;86 }87 88 lf_size = fs16_to_cpu(sbi, lf->lf_size);89 90 if (lf_size > QNX6_LONG_NAME_MAX) {91 pr_debug("file %s\n", lf->lf_fname);92 pr_err("Filename too long (%i)\n", lf_size);93 folio_release_kmap(folio, lf);94 return 0;95 }96 97 /* calc & validate longfilename checksum98 mmi 3g filesystem does not have that checksum */99 if (!test_opt(s, MMI_FS) && fs32_to_cpu(sbi, de->de_checksum) !=100 qnx6_lfile_checksum(lf->lf_fname, lf_size))101 pr_info("long filename checksum error.\n");102 103 pr_debug("qnx6_readdir:%.*s inode:%u\n",104 lf_size, lf->lf_fname, de_inode);105 if (!dir_emit(ctx, lf->lf_fname, lf_size, de_inode, DT_UNKNOWN)) {106 folio_release_kmap(folio, lf);107 return 0;108 }109 110 folio_release_kmap(folio, lf);111 /* success */112 return 1;113}114 115static int qnx6_readdir(struct file *file, struct dir_context *ctx)116{117 struct inode *inode = file_inode(file);118 struct super_block *s = inode->i_sb;119 struct qnx6_sb_info *sbi = QNX6_SB(s);120 loff_t pos = ctx->pos & ~(QNX6_DIR_ENTRY_SIZE - 1);121 unsigned long npages = dir_pages(inode);122 unsigned long n = pos >> PAGE_SHIFT;123 unsigned offset = (pos & ~PAGE_MASK) / QNX6_DIR_ENTRY_SIZE;124 bool done = false;125 126 ctx->pos = pos;127 if (ctx->pos >= inode->i_size)128 return 0;129 130 for ( ; !done && n < npages; n++, offset = 0) {131 struct qnx6_dir_entry *de;132 struct folio *folio;133 char *kaddr = qnx6_get_folio(inode, n, &folio);134 char *limit;135 136 if (IS_ERR(kaddr)) {137 pr_err("%s(): read failed\n", __func__);138 ctx->pos = (n + 1) << PAGE_SHIFT;139 return PTR_ERR(kaddr);140 }141 de = (struct qnx6_dir_entry *)(kaddr + offset);142 limit = kaddr + last_entry(inode, n);143 for (; (char *)de < limit; 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 detected152 get the filename from long filename153 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 folio_release_kmap(folio, kaddr);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 folio *folio;185 int thislen;186 struct qnx6_long_filename *lf = qnx6_longname(s, de, &folio);187 188 if (IS_ERR(lf))189 return 0;190 191 thislen = fs16_to_cpu(sbi, lf->lf_size);192 if (len != thislen) {193 folio_release_kmap(folio, lf);194 return 0;195 }196 if (memcmp(name, lf->lf_fname, len) == 0) {197 folio_release_kmap(folio, lf);198 return fs32_to_cpu(sbi, de->de_inode);199 }200 folio_release_kmap(folio, lf);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_ino(int len, struct inode *dir, const char *name)218{219 struct super_block *s = dir->i_sb;220 struct qnx6_inode_info *ei = QNX6_I(dir);221 struct folio *folio;222 unsigned long start, n;223 unsigned long npages = dir_pages(dir);224 unsigned ino;225 struct qnx6_dir_entry *de;226 struct qnx6_long_dir_entry *lde;227 228 if (npages == 0)229 return 0;230 start = ei->i_dir_start_lookup;231 if (start >= npages)232 start = 0;233 n = start;234 235 do {236 de = qnx6_get_folio(dir, n, &folio);237 if (!IS_ERR(de)) {238 int limit = last_entry(dir, n);239 int i;240 241 for (i = 0; i < limit; i++, de++) {242 if (len <= QNX6_SHORT_NAME_MAX) {243 /* short filename */244 if (len != de->de_size)245 continue;246 ino = qnx6_match(s, len, name, de);247 if (ino)248 goto found;249 } else if (de->de_size == 0xff) {250 /* deal with long filename */251 lde = (struct qnx6_long_dir_entry *)de;252 ino = qnx6_long_match(len,253 name, lde, dir);254 if (ino)255 goto found;256 } else257 pr_err("undefined filename size in inode.\n");258 }259 folio_release_kmap(folio, de - i);260 }261 262 if (++n >= npages)263 n = 0;264 } while (n != start);265 return 0;266 267found:268 ei->i_dir_start_lookup = n;269 folio_release_kmap(folio, de);270 return ino;271}272 273const struct file_operations qnx6_dir_operations = {274 .llseek = generic_file_llseek,275 .read = generic_read_dir,276 .iterate_shared = qnx6_readdir,277 .fsync = generic_file_fsync,278};279 280const struct inode_operations qnx6_dir_inode_operations = {281 .lookup = qnx6_lookup,282};283