root/fs/qnx6/dir.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. qnx6_lfile_checksum
  2. qnx6_get_page
  3. last_entry
  4. qnx6_longname
  5. qnx6_dir_longfilename
  6. qnx6_readdir
  7. qnx6_long_match
  8. qnx6_match
  9. qnx6_find_entry

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

/* [<][>][^][v][top][bottom][index][help] */