LCOV - code coverage report
Current view: top level - lkbce/fs/isofs - dir.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 154 154 100.0 %
Date: 2017-01-25 Functions: 4 4 100.0 %

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

Generated by: LCOV version 1.10