root/fs/isofs/dir.c

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

DEFINITIONS

This source file includes following definitions.
  1. isofs_name_translate
  2. get_acorn_filename
  3. do_isofs_readdir
  4. isofs_readdir

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *  linux/fs/isofs/dir.c
   4  *
   5  *  (C) 1992, 1993, 1994  Eric Youngdale Modified for ISO 9660 filesystem.
   6  *
   7  *  (C) 1991  Linus Torvalds - minix filesystem
   8  *
   9  *  Steve Beynon                       : Missing last directory entries fixed
  10  *  (stephen@askone.demon.co.uk)      : 21st June 1996
  11  *
  12  *  isofs directory handling functions
  13  */
  14 #include <linux/gfp.h>
  15 #include "isofs.h"
  16 
  17 int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
  18 {
  19         char * old = de->name;
  20         int len = de->name_len[0];
  21         int i;
  22 
  23         for (i = 0; i < len; i++) {
  24                 unsigned char c = old[i];
  25                 if (!c)
  26                         break;
  27 
  28                 if (c >= 'A' && c <= 'Z')
  29                         c |= 0x20;      /* lower case */
  30 
  31                 /* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
  32                 if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
  33                         break;
  34 
  35                 /* Drop trailing ';1' */
  36                 if (c == ';' && i == len - 2 && old[i + 1] == '1')
  37                         break;
  38 
  39                 /* Convert remaining ';' to '.' */
  40                 /* Also '/' to '.' (broken Acorn-generated ISO9660 images) */
  41                 if (c == ';' || c == '/')
  42                         c = '.';
  43 
  44                 new[i] = c;
  45         }
  46         return i;
  47 }
  48 
  49 /* Acorn extensions written by Matthew Wilcox <willy@infradead.org> 1998 */
  50 int get_acorn_filename(struct iso_directory_record *de,
  51                             char *retname, struct inode *inode)
  52 {
  53         int std;
  54         unsigned char *chr;
  55         int retnamlen = isofs_name_translate(de, retname, inode);
  56 
  57         if (retnamlen == 0)
  58                 return 0;
  59         std = sizeof(struct iso_directory_record) + de->name_len[0];
  60         if (std & 1)
  61                 std++;
  62         if (de->length[0] - std != 32)
  63                 return retnamlen;
  64         chr = ((unsigned char *) de) + std;
  65         if (strncmp(chr, "ARCHIMEDES", 10))
  66                 return retnamlen;
  67         if ((*retname == '_') && ((chr[19] & 1) == 1))
  68                 *retname = '!';
  69         if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
  70                 && ((chr[12] & 0xf0) == 0xf0)) {
  71                 retname[retnamlen] = ',';
  72                 sprintf(retname+retnamlen+1, "%3.3x",
  73                         ((chr[12] & 0xf) << 8) | chr[11]);
  74                 retnamlen += 4;
  75         }
  76         return retnamlen;
  77 }
  78 
  79 /*
  80  * This should _really_ be cleaned up some day..
  81  */
  82 static int do_isofs_readdir(struct inode *inode, struct file *file,
  83                 struct dir_context *ctx,
  84                 char *tmpname, struct iso_directory_record *tmpde)
  85 {
  86         unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
  87         unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
  88         unsigned long block, offset, block_saved, offset_saved;
  89         unsigned long inode_number = 0; /* Quiet GCC */
  90         struct buffer_head *bh = NULL;
  91         int len;
  92         int map;
  93         int first_de = 1;
  94         char *p = NULL;         /* Quiet GCC */
  95         struct iso_directory_record *de;
  96         struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
  97 
  98         offset = ctx->pos & (bufsize - 1);
  99         block = ctx->pos >> bufbits;
 100 
 101         while (ctx->pos < inode->i_size) {
 102                 int de_len;
 103 
 104                 if (!bh) {
 105                         bh = isofs_bread(inode, block);
 106                         if (!bh)
 107                                 return 0;
 108                 }
 109 
 110                 de = (struct iso_directory_record *) (bh->b_data + offset);
 111 
 112                 de_len = *(unsigned char *)de;
 113 
 114                 /*
 115                  * If the length byte is zero, we should move on to the next
 116                  * CDROM sector.  If we are at the end of the directory, we
 117                  * kick out of the while loop.
 118                  */
 119 
 120                 if (de_len == 0) {
 121                         brelse(bh);
 122                         bh = NULL;
 123                         ctx->pos = (ctx->pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
 124                         block = ctx->pos >> bufbits;
 125                         offset = 0;
 126                         continue;
 127                 }
 128 
 129                 block_saved = block;
 130                 offset_saved = offset;
 131                 offset += de_len;
 132 
 133                 /* Make sure we have a full directory entry */
 134                 if (offset >= bufsize) {
 135                         int slop = bufsize - offset + de_len;
 136                         memcpy(tmpde, de, slop);
 137                         offset &= bufsize - 1;
 138                         block++;
 139                         brelse(bh);
 140                         bh = NULL;
 141                         if (offset) {
 142                                 bh = isofs_bread(inode, block);
 143                                 if (!bh)
 144                                         return 0;
 145                                 memcpy((void *) tmpde + slop, bh->b_data, offset);
 146                         }
 147                         de = tmpde;
 148                 }
 149                 /* Basic sanity check, whether name doesn't exceed dir entry */
 150                 if (de_len < de->name_len[0] +
 151                                         sizeof(struct iso_directory_record)) {
 152                         printk(KERN_NOTICE "iso9660: Corrupted directory entry"
 153                                " in block %lu of inode %lu\n", block,
 154                                inode->i_ino);
 155                         return -EIO;
 156                 }
 157 
 158                 if (first_de) {
 159                         isofs_normalize_block_and_offset(de,
 160                                                         &block_saved,
 161                                                         &offset_saved);
 162                         inode_number = isofs_get_ino(block_saved,
 163                                                         offset_saved, bufbits);
 164                 }
 165 
 166                 if (de->flags[-sbi->s_high_sierra] & 0x80) {
 167                         first_de = 0;
 168                         ctx->pos += de_len;
 169                         continue;
 170                 }
 171                 first_de = 1;
 172 
 173                 /* Handle the case of the '.' directory */
 174                 if (de->name_len[0] == 1 && de->name[0] == 0) {
 175                         if (!dir_emit_dot(file, ctx))
 176                                 break;
 177                         ctx->pos += de_len;
 178                         continue;
 179                 }
 180 
 181                 len = 0;
 182 
 183                 /* Handle the case of the '..' directory */
 184                 if (de->name_len[0] == 1 && de->name[0] == 1) {
 185                         if (!dir_emit_dotdot(file, ctx))
 186                                 break;
 187                         ctx->pos += de_len;
 188                         continue;
 189                 }
 190 
 191                 /* Handle everything else.  Do name translation if there
 192                    is no Rock Ridge NM field. */
 193 
 194                 /*
 195                  * Do not report hidden files if so instructed, or associated
 196                  * files unless instructed to do so
 197                  */
 198                 if ((sbi->s_hide && (de->flags[-sbi->s_high_sierra] & 1)) ||
 199                     (!sbi->s_showassoc &&
 200                                 (de->flags[-sbi->s_high_sierra] & 4))) {
 201                         ctx->pos += de_len;
 202                         continue;
 203                 }
 204 
 205                 map = 1;
 206                 if (sbi->s_rock) {
 207                         len = get_rock_ridge_filename(de, tmpname, inode);
 208                         if (len != 0) {         /* may be -1 */
 209                                 p = tmpname;
 210                                 map = 0;
 211                         }
 212                 }
 213                 if (map) {
 214 #ifdef CONFIG_JOLIET
 215                         if (sbi->s_joliet_level) {
 216                                 len = get_joliet_filename(de, tmpname, inode);
 217                                 p = tmpname;
 218                         } else
 219 #endif
 220                         if (sbi->s_mapping == 'a') {
 221                                 len = get_acorn_filename(de, tmpname, inode);
 222                                 p = tmpname;
 223                         } else
 224                         if (sbi->s_mapping == 'n') {
 225                                 len = isofs_name_translate(de, tmpname, inode);
 226                                 p = tmpname;
 227                         } else {
 228                                 p = de->name;
 229                                 len = de->name_len[0];
 230                         }
 231                 }
 232                 if (len > 0) {
 233                         if (!dir_emit(ctx, p, len, inode_number, DT_UNKNOWN))
 234                                 break;
 235                 }
 236                 ctx->pos += de_len;
 237 
 238                 continue;
 239         }
 240         if (bh)
 241                 brelse(bh);
 242         return 0;
 243 }
 244 
 245 /*
 246  * Handle allocation of temporary space for name translation and
 247  * handling split directory entries.. The real work is done by
 248  * "do_isofs_readdir()".
 249  */
 250 static int isofs_readdir(struct file *file, struct dir_context *ctx)
 251 {
 252         int result;
 253         char *tmpname;
 254         struct iso_directory_record *tmpde;
 255         struct inode *inode = file_inode(file);
 256 
 257         tmpname = (char *)__get_free_page(GFP_KERNEL);
 258         if (tmpname == NULL)
 259                 return -ENOMEM;
 260 
 261         tmpde = (struct iso_directory_record *) (tmpname+1024);
 262 
 263         result = do_isofs_readdir(inode, file, ctx, tmpname, tmpde);
 264 
 265         free_page((unsigned long) tmpname);
 266         return result;
 267 }
 268 
 269 const struct file_operations isofs_dir_operations =
 270 {
 271         .llseek = generic_file_llseek,
 272         .read = generic_read_dir,
 273         .iterate_shared = isofs_readdir,
 274 };
 275 
 276 /*
 277  * directories can handle most operations...
 278  */
 279 const struct inode_operations isofs_dir_inode_operations =
 280 {
 281         .lookup = isofs_lookup,
 282 };
 283 
 284 

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