OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [isofs/] [namei.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 *  linux/fs/isofs/namei.c
 *  linux/fs/isofs/namei.c
 *
 *
 *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
 *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
 *
 *
 *  (C) 1991  Linus Torvalds - minix filesystem
 *  (C) 1991  Linus Torvalds - minix filesystem
 */
 */
 
 
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/iso_fs.h>
#include <linux/iso_fs.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/fcntl.h>
#include <asm/segment.h>
#include <asm/segment.h>
#include <linux/malloc.h>
#include <linux/malloc.h>
 
 
#include <linux/errno.h>
#include <linux/errno.h>
 
 
/*
/*
 * ok, we cannot use strncmp, as the name is not in our data space.
 * ok, we cannot use strncmp, as the name is not in our data space.
 * Thus we'll have to use isofs_match. No big problem. Match also makes
 * Thus we'll have to use isofs_match. No big problem. Match also makes
 * some sanity tests.
 * some sanity tests.
 *
 *
 * NOTE! unlike strncmp, isofs_match returns 1 for success, 0 for failure.
 * NOTE! unlike strncmp, isofs_match returns 1 for success, 0 for failure.
 */
 */
static int isofs_match(int len,const char * name, const char * compare, int dlen)
static int isofs_match(int len,const char * name, const char * compare, int dlen)
{
{
        if (!compare)
        if (!compare)
                return 0;
                return 0;
 
 
        /* check special "." and ".." files */
        /* check special "." and ".." files */
        if (dlen == 1) {
        if (dlen == 1) {
                /* "." */
                /* "." */
                if (compare[0] == 0) {
                if (compare[0] == 0) {
                        if (!len)
                        if (!len)
                                return 1;
                                return 1;
                        compare = ".";
                        compare = ".";
                } else if (compare[0] == 1) {
                } else if (compare[0] == 1) {
                        compare = "..";
                        compare = "..";
                        dlen = 2;
                        dlen = 2;
                }
                }
        }
        }
#if 0
#if 0
        if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
        if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
#endif
#endif
 
 
        if (dlen != len)
        if (dlen != len)
                return 0;
                return 0;
        return !memcmp(name, compare, len);
        return !memcmp(name, compare, len);
}
}
 
 
/*
/*
 *      isofs_find_entry()
 *      isofs_find_entry()
 *
 *
 * finds an entry in the specified directory with the wanted name. It
 * finds an entry in the specified directory with the wanted name. It
 * returns the cache buffer in which the entry was found, and the entry
 * returns the cache buffer in which the entry was found, and the entry
 * itself (as an inode number). It does NOT read the inode of the
 * itself (as an inode number). It does NOT read the inode of the
 * entry - you'll have to do that yourself if you want to.
 * entry - you'll have to do that yourself if you want to.
 */
 */
static struct buffer_head *
static struct buffer_head *
isofs_find_entry(struct inode * dir, const char * name, int namelen,
isofs_find_entry(struct inode * dir, const char * name, int namelen,
                 unsigned long * ino, unsigned long * ino_back)
                 unsigned long * ino, unsigned long * ino_back)
{
{
        unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
        unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
        unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
        unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
        unsigned int block, i, f_pos, offset, inode_number;
        unsigned int block, i, f_pos, offset, inode_number;
        struct buffer_head * bh;
        struct buffer_head * bh;
        void * cpnt = NULL;
        void * cpnt = NULL;
        unsigned int old_offset;
        unsigned int old_offset;
        unsigned int backlink;
        unsigned int backlink;
        int dlen, match;
        int dlen, match;
        char * dpnt;
        char * dpnt;
        unsigned char *page = NULL;
        unsigned char *page = NULL;
        struct iso_directory_record * de;
        struct iso_directory_record * de;
        char c;
        char c;
 
 
        *ino = 0;
        *ino = 0;
        if (!dir) return NULL;
        if (!dir) return NULL;
 
 
        if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
        if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
 
 
        f_pos = 0;
        f_pos = 0;
 
 
        offset = f_pos & (bufsize - 1);
        offset = f_pos & (bufsize - 1);
        block = isofs_bmap(dir,f_pos >> bufbits);
        block = isofs_bmap(dir,f_pos >> bufbits);
 
 
        if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
        if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
 
 
        while (f_pos < dir->i_size) {
        while (f_pos < dir->i_size) {
                de = (struct iso_directory_record *) (bh->b_data + offset);
                de = (struct iso_directory_record *) (bh->b_data + offset);
                backlink = dir->i_ino;
                backlink = dir->i_ino;
                inode_number = (block << bufbits) + (offset & (bufsize - 1));
                inode_number = (block << bufbits) + (offset & (bufsize - 1));
 
 
                /* If byte is zero, this is the end of file, or time to move to
                /* If byte is zero, this is the end of file, or time to move to
                   the next sector. Usually 2048 byte boundaries. */
                   the next sector. Usually 2048 byte boundaries. */
 
 
                if (*((unsigned char *) de) == 0) {
                if (*((unsigned char *) de) == 0) {
                        brelse(bh);
                        brelse(bh);
                        offset = 0;
                        offset = 0;
                        f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
                        f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
                                 + ISOFS_BLOCK_SIZE);
                                 + ISOFS_BLOCK_SIZE);
                        block = isofs_bmap(dir,f_pos>>bufbits);
                        block = isofs_bmap(dir,f_pos>>bufbits);
                        if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
                        if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
                                return NULL;
                                return NULL;
                        continue; /* Will kick out if past end of directory */
                        continue; /* Will kick out if past end of directory */
                }
                }
 
 
                old_offset = offset;
                old_offset = offset;
                offset += *((unsigned char *) de);
                offset += *((unsigned char *) de);
                f_pos += *((unsigned char *) de);
                f_pos += *((unsigned char *) de);
 
 
                /* Handle case where the directory entry spans two blocks.
                /* Handle case where the directory entry spans two blocks.
                   Usually 1024 byte boundaries */
                   Usually 1024 byte boundaries */
                if (offset >= bufsize) {
                if (offset >= bufsize) {
                        unsigned int frag1;
                        unsigned int frag1;
                        frag1 = bufsize - old_offset;
                        frag1 = bufsize - old_offset;
                        cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
                        cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
                        if (!cpnt) return NULL;
                        if (!cpnt) return NULL;
                        memcpy(cpnt, bh->b_data + old_offset, frag1);
                        memcpy(cpnt, bh->b_data + old_offset, frag1);
 
 
                        de = (struct iso_directory_record *) cpnt;
                        de = (struct iso_directory_record *) cpnt;
                        brelse(bh);
                        brelse(bh);
                        offset = f_pos & (bufsize - 1);
                        offset = f_pos & (bufsize - 1);
                        block = isofs_bmap(dir,f_pos>>bufbits);
                        block = isofs_bmap(dir,f_pos>>bufbits);
                        if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
                        if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
                                kfree(cpnt);
                                kfree(cpnt);
                                return NULL;
                                return NULL;
                        };
                        };
                        memcpy((char *)cpnt+frag1, bh->b_data, offset);
                        memcpy((char *)cpnt+frag1, bh->b_data, offset);
                }
                }
 
 
                dlen = de->name_len[0];
                dlen = de->name_len[0];
                dpnt = de->name;
                dpnt = de->name;
 
 
                /* Handle the '.' case */
                /* Handle the '.' case */
 
 
                if (*dpnt==0 && dlen==1) {
                if (*dpnt==0 && dlen==1) {
                        inode_number = dir->i_ino;
                        inode_number = dir->i_ino;
                        backlink = 0;
                        backlink = 0;
                }
                }
 
 
                /* Handle the '..' case */
                /* Handle the '..' case */
 
 
                else if (*dpnt==1 && dlen==1) {
                else if (*dpnt==1 && dlen==1) {
#if 0
#if 0
                        printk("Doing .. (%d %d)",
                        printk("Doing .. (%d %d)",
                               dir->i_sb->s_firstdatazone,
                               dir->i_sb->s_firstdatazone,
                               dir->i_ino);
                               dir->i_ino);
#endif
#endif
                        if((dir->i_sb->u.isofs_sb.s_firstdatazone) != dir->i_ino)
                        if((dir->i_sb->u.isofs_sb.s_firstdatazone) != dir->i_ino)
                                inode_number = dir->u.isofs_i.i_backlink;
                                inode_number = dir->u.isofs_i.i_backlink;
                        else
                        else
                                inode_number = dir->i_ino;
                                inode_number = dir->i_ino;
                        backlink = 0;
                        backlink = 0;
                } else {
                } else {
                        if (dir->i_sb->u.isofs_sb.s_rock ||
                        if (dir->i_sb->u.isofs_sb.s_rock ||
                            dir->i_sb->u.isofs_sb.s_joliet_level) {
                            dir->i_sb->u.isofs_sb.s_joliet_level) {
                                page = (unsigned char *)
                                page = (unsigned char *)
                                        __get_free_page(GFP_KERNEL);
                                        __get_free_page(GFP_KERNEL);
                                if (!page) return NULL;
                                if (!page) return NULL;
                        }
                        }
                        if (dir->i_sb->u.isofs_sb.s_rock &&
                        if (dir->i_sb->u.isofs_sb.s_rock &&
                            ((i = get_rock_ridge_filename(de, page, dir)))){
                            ((i = get_rock_ridge_filename(de, page, dir)))){
                                if (i == -1)
                                if (i == -1)
                                        goto out;/* Relocated deep directory */
                                        goto out;/* Relocated deep directory */
                                dlen = i;
                                dlen = i;
                                dpnt = page;
                                dpnt = page;
                        } else if (dir->i_sb->u.isofs_sb.s_joliet_level) {
                        } else if (dir->i_sb->u.isofs_sb.s_joliet_level) {
                                dlen = get_joliet_filename(de, dir, page);
                                dlen = get_joliet_filename(de, dir, page);
                                dpnt = page;
                                dpnt = page;
                        } else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
                        } else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
                                for (i = 0; i < dlen; i++) {
                                for (i = 0; i < dlen; i++) {
                                        c = dpnt[i];
                                        c = dpnt[i];
                                        /* lower case */
                                        /* lower case */
                                        if (c >= 'A' && c <= 'Z') c |= 0x20;
                                        if (c >= 'A' && c <= 'Z') c |= 0x20;
                                        if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
                                        if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
                                                dlen -= 2;
                                                dlen -= 2;
                                                break;
                                                break;
                                        }
                                        }
                                        if (c == ';') c = '.';
                                        if (c == ';') c = '.';
                                        dpnt[i] = c;
                                        dpnt[i] = c;
                                }
                                }
                                /* This allows us to match with and without
                                /* This allows us to match with and without
                                 * a trailing period. */
                                 * a trailing period. */
                                if(dpnt[dlen-1] == '.' && namelen == dlen-1)
                                if(dpnt[dlen-1] == '.' && namelen == dlen-1)
                                        dlen--;
                                        dlen--;
                        }
                        }
                }
                }
                /*
                /*
                 * Skip hidden or associated files unless unhide is set
                 * Skip hidden or associated files unless unhide is set
                 */
                 */
                match = 0;
                match = 0;
                if(   !(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
                if(   !(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
                   || dir->i_sb->u.isofs_sb.s_unhide == 'y' )
                   || dir->i_sb->u.isofs_sb.s_unhide == 'y' )
                {
                {
                        match = isofs_match(namelen,name,dpnt,dlen);
                        match = isofs_match(namelen,name,dpnt,dlen);
                }
                }
 
 
                if (cpnt)
                if (cpnt)
                {
                {
                        kfree(cpnt);
                        kfree(cpnt);
                        cpnt = NULL;
                        cpnt = NULL;
                }
                }
 
 
                if (page) free_page((unsigned long) page);
                if (page) free_page((unsigned long) page);
                if (match) {
                if (match) {
                        if(inode_number == -1) {
                        if(inode_number == -1) {
                                /* Should only happen for the '..' entry */
                                /* Should only happen for the '..' entry */
                                inode_number =
                                inode_number =
                                        isofs_lookup_grandparent(dir,
                                        isofs_lookup_grandparent(dir,
                                           find_rock_ridge_relocation(de,dir));
                                           find_rock_ridge_relocation(de,dir));
                                if(inode_number == -1){
                                if(inode_number == -1){
                                        /* Should never happen */
                                        /* Should never happen */
                                        printk("Backlink not properly set %x %lx.\n",
                                        printk("Backlink not properly set %x %lx.\n",
                                               isonum_733(de->extent),
                                               isonum_733(de->extent),
                                               dir->i_ino);
                                               dir->i_ino);
                                        goto out;
                                        goto out;
                                }
                                }
                        }
                        }
                        *ino = inode_number;
                        *ino = inode_number;
                        *ino_back = backlink;
                        *ino_back = backlink;
                        return bh;
                        return bh;
                }
                }
        }
        }
 out:
 out:
        if (cpnt)
        if (cpnt)
                kfree(cpnt);
                kfree(cpnt);
        brelse(bh);
        brelse(bh);
        return NULL;
        return NULL;
}
}
 
 
int isofs_lookup(struct inode * dir,const char * name, int len,
int isofs_lookup(struct inode * dir,const char * name, int len,
        struct inode ** result)
        struct inode ** result)
{
{
        unsigned long ino, ino_back;
        unsigned long ino, ino_back;
        struct buffer_head * bh;
        struct buffer_head * bh;
 
 
#ifdef DEBUG
#ifdef DEBUG
        printk("lookup: %x %d\n",dir->i_ino, len);
        printk("lookup: %x %d\n",dir->i_ino, len);
#endif
#endif
        *result = NULL;
        *result = NULL;
        if (!dir)
        if (!dir)
                return -ENOENT;
                return -ENOENT;
 
 
        if (!S_ISDIR(dir->i_mode)) {
        if (!S_ISDIR(dir->i_mode)) {
                iput(dir);
                iput(dir);
                return -ENOENT;
                return -ENOENT;
        }
        }
 
 
        ino = 0;
        ino = 0;
 
 
        if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino;
        if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino;
 
 
 
 
        if (!ino) {
        if (!ino) {
                char *lcname;
                char *lcname;
 
 
                /* First try the original name. If that doesn't work and the fs
                /* First try the original name. If that doesn't work and the fs
                 * was mounted with check=relaxed, convert the name to lower
                 * was mounted with check=relaxed, convert the name to lower
                 * case and try again.
                 * case and try again.
                 */
                 */
                if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))
                if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))
                    && dir->i_sb->u.isofs_sb.s_name_check == 'r'
                    && dir->i_sb->u.isofs_sb.s_name_check == 'r'
                    && (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
                    && (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
                        int i;
                        int i;
                        char c;
                        char c;
 
 
                        for (i=0; i<len; i++) {
                        for (i=0; i<len; i++) {
                                c = name[i];
                                c = name[i];
                                if (c >= 'A' && c <= 'Z') c |= 0x20;
                                if (c >= 'A' && c <= 'Z') c |= 0x20;
                                lcname[i] = c;
                                lcname[i] = c;
                        }
                        }
                        bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
                        bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
                        kfree(lcname);
                        kfree(lcname);
                }
                }
 
 
                if (!bh) {
                if (!bh) {
                        iput(dir);
                        iput(dir);
                        return -ENOENT;
                        return -ENOENT;
                }
                }
                if (ino_back == dir->i_ino) {
                if (ino_back == dir->i_ino) {
                        dcache_add(dir, name, len, ino);
                        dcache_add(dir, name, len, ino);
                }
                }
                brelse(bh);
                brelse(bh);
        }
        }
 
 
        if (!(*result = iget(dir->i_sb,ino))) {
        if (!(*result = iget(dir->i_sb,ino))) {
                iput(dir);
                iput(dir);
                return -EACCES;
                return -EACCES;
        }
        }
 
 
        /* We need this backlink for the ".." entry unless the name that we
        /* We need this backlink for the ".." entry unless the name that we
           are looking up traversed a mount point (in which case the inode
           are looking up traversed a mount point (in which case the inode
           may not even be on an iso9660 filesystem, and writing to
           may not even be on an iso9660 filesystem, and writing to
           u.isofs_i would only cause memory corruption).
           u.isofs_i would only cause memory corruption).
        */
        */
 
 
        if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
        if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
                (*result)->u.isofs_i.i_backlink = ino_back;
                (*result)->u.isofs_i.i_backlink = ino_back;
        }
        }
 
 
        iput(dir);
        iput(dir);
        return 0;
        return 0;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.