!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/fs/udf/   drwxr-xr-x
Free 318.34 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     namei.c (32.18 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 * namei.c
 *
 * PURPOSE
 *      Inode name handling routines for the OSTA-UDF(tm) filesystem.
 *
 * CONTACTS
 *      E-mail regarding any portion of the Linux UDF file system should be
 *      directed to the development team mailing list (run by majordomo):
 *              linux_udf@hpesjro.fc.hp.com
 *
 * COPYRIGHT
 *      This file is distributed under the terms of the GNU General Public
 *      License (GPL). Copies of the GPL can be obtained from:
 *              ftp://prep.ai.mit.edu/pub/gnu/GPL
 *      Each contributing author retains all rights to their own work.
 *
 *  (C) 1998-2000 Ben Fennema
 *  (C) 1999-2000 Stelias Computing Inc
 *
 * HISTORY
 *
 *  12/12/98 blf  Created. Split out the lookup code from dir.c
 *  04/19/99 blf  link, mknod, symlink support
 */

#include "udfdecl.h"

#include "udf_i.h"
#include "udf_sb.h"
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/quotaops.h>
#include <linux/locks.h>
#include <linux/smp_lock.h>
#include <linux/udf_fs.h>

static inline int udf_match(int len, const char * const name, struct qstr *qs)
{
    if (len != qs->len)
        return 0;
    return !memcmp(name, qs->name, len);
}

int udf_write_fi(struct inode *inode, struct FileIdentDesc *cfi,
    struct FileIdentDesc *sfi, struct udf_fileident_bh *fibh,
    Uint8 *impuse, Uint8 *fileident)
{
    Uint16 crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
    Uint16 crc;
    Uint8 checksum = 0;
    int i;
    int offset;
    Uint16 liu = le16_to_cpu(cfi->lengthOfImpUse);
    Uint8 lfi = cfi->lengthFileIdent;
    int padlen = fibh->eoffset - fibh->soffset - liu - lfi -
        sizeof(struct FileIdentDesc);

    offset = fibh->soffset + sizeof(struct FileIdentDesc);

    if (impuse)
    {
        if (offset + liu < 0)
            memcpy((Uint8 *)sfi->impUse, impuse, liu);
        else if (offset >= 0)
            memcpy(fibh->ebh->b_data + offset, impuse, liu);
        else
        {
            memcpy((Uint8 *)sfi->impUse, impuse, -offset);
            memcpy(fibh->ebh->b_data, impuse - offset, liu + offset);
        }
    }

    offset += liu;

    if (fileident)
    {
        if (offset + lfi < 0)
            memcpy((Uint8 *)sfi->fileIdent + liu, fileident, lfi);
        else if (offset >= 0)
            memcpy(fibh->ebh->b_data + offset, fileident, lfi);
        else
        {
            memcpy((Uint8 *)sfi->fileIdent + liu, fileident, -offset);
            memcpy(fibh->ebh->b_data, fileident - offset, lfi + offset);
        }
    }

    offset += lfi;

    if (offset + padlen < 0)
        memset((Uint8 *)sfi->padding + liu + lfi, 0x00, padlen);
    else if (offset >= 0)
        memset(fibh->ebh->b_data + offset, 0x00, padlen);
    else
    {
        memset((Uint8 *)sfi->padding + liu + lfi, 0x00, -offset);
        memset(fibh->ebh->b_data, 0x00, padlen + offset);
    }

    crc = udf_crc((Uint8 *)cfi + sizeof(tag), sizeof(struct FileIdentDesc) -
        sizeof(tag), 0);

    if (fibh->sbh == fibh->ebh)
        crc = udf_crc((Uint8 *)sfi->impUse,
            crclen + sizeof(tag) - sizeof(struct FileIdentDesc), crc);
    else if (sizeof(struct FileIdentDesc) >= -fibh->soffset)
        crc = udf_crc(fibh->ebh->b_data + sizeof(struct FileIdentDesc) + fibh->soffset,
            crclen + sizeof(tag) - sizeof(struct FileIdentDesc), crc);
    else
    {
        crc = udf_crc((Uint8 *)sfi->impUse,
            -fibh->soffset - sizeof(struct FileIdentDesc), crc);
        crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
    }

    cfi->descTag.descCRC = cpu_to_le32(crc);
    cfi->descTag.descCRCLength = cpu_to_le16(crclen);

    for (i=0; i<16; i++)
        if (i != 4)
            checksum += ((Uint8 *)&cfi->descTag)[i];

    cfi->descTag.tagChecksum = checksum;
    if (sizeof(struct FileIdentDesc) <= -fibh->soffset)
        memcpy((Uint8 *)sfi, (Uint8 *)cfi, sizeof(struct FileIdentDesc));
    else
    {
        memcpy((Uint8 *)sfi, (Uint8 *)cfi, -fibh->soffset);
        memcpy(fibh->ebh->b_data, (Uint8 *)cfi - fibh->soffset,
            sizeof(struct FileIdentDesc) + fibh->soffset);
    }

    if (fibh->sbh != fibh->ebh)
        mark_buffer_dirty_inode(fibh->ebh, inode);
    mark_buffer_dirty_inode(fibh->sbh, inode);
    return 0;
}

static struct FileIdentDesc *
udf_find_entry(struct inode *dir, struct dentry *dentry,
    struct udf_fileident_bh *fibh,
    struct FileIdentDesc *cfi)
{
    struct FileIdentDesc *fi=NULL;
    loff_t f_pos;
    int block, flen;
    char fname[255];
    char *nameptr;
    Uint8 lfi;
    Uint16 liu;
    loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
    lb_addr bloc, eloc;
    Uint32 extoffset, elen, offset;
    struct buffer_head *bh = NULL;

    if (!dir)
        return NULL;

    f_pos = (udf_ext0_offset(dir) >> 2);

    fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
    if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
        &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
    {
        offset >>= dir->i_sb->s_blocksize_bits;
        block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
        if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
        {
            if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
                extoffset -= sizeof(short_ad);
            else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
                extoffset -= sizeof(long_ad);
        }
        else
            offset = 0;
    }
    else
    {
        udf_release_data(bh);
        return NULL;
    }

    if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
    {
        udf_release_data(bh);
        return NULL;
    }

    while ( (f_pos < size) )
    {
        fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);

        if (!fi)
        {
            if (fibh->sbh != fibh->ebh)
                udf_release_data(fibh->ebh);
            udf_release_data(fibh->sbh);
            udf_release_data(bh);
            return NULL;
        }

        liu = le16_to_cpu(cfi->lengthOfImpUse);
        lfi = cfi->lengthFileIdent;

        if (fibh->sbh == fibh->ebh)
        {
            nameptr = fi->fileIdent + liu;
        }
        else
        {
            int poffset;    /* Unpaded ending offset */

            poffset = fibh->soffset + sizeof(struct FileIdentDesc) + liu + lfi;

            if (poffset >= lfi)
                nameptr = (Uint8 *)(fibh->ebh->b_data + poffset - lfi);
            else
            {
                nameptr = fname;
                memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
                memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
            }
        }

        if ( (cfi->fileCharacteristics & FILE_DELETED) != 0 )
        {
            if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
                continue;
        }
        
        if ( (cfi->fileCharacteristics & FILE_HIDDEN) != 0 )
        {
            if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
                continue;
        }

        if (!lfi)
            continue;

        if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)))
        {
            if (udf_match(flen, fname, &(dentry->d_name)))
            {
                udf_release_data(bh);
                return fi;
            }
        }
    }
    if (fibh->sbh != fibh->ebh)
        udf_release_data(fibh->ebh);
    udf_release_data(fibh->sbh);
    udf_release_data(bh);
    return NULL;
}

/*
 * udf_lookup
 *
 * PURPOSE
 *    Look-up the inode for a given name.
 *
 * DESCRIPTION
 *    Required - lookup_dentry() will return -ENOTDIR if this routine is not
 *    available for a directory. The filesystem is useless if this routine is
 *    not available for at least the filesystem's root directory.
 *
 *    This routine is passed an incomplete dentry - it must be completed by
 *    calling d_add(dentry, inode). If the name does not exist, then the
 *    specified inode must be set to null. An error should only be returned
 *    when the lookup fails for a reason other than the name not existing.
 *    Note that the directory inode semaphore is held during the call.
 *
 *    Refer to lookup_dentry() in fs/namei.c
 *    lookup_dentry() -> lookup() -> real_lookup() -> .
 *
 * PRE-CONDITIONS
 *    dir            Pointer to inode of parent directory.
 *    dentry            Pointer to dentry to complete.
 *
 * POST-CONDITIONS
 *    <return>        Zero on success.
 *
 * HISTORY
 *    July 1, 1997 - Andrew E. Mileski
 *    Written, tested, and released.
 */

static struct dentry *
udf_lookup(struct inode *dir, struct dentry *dentry)
{
    struct inode *inode = NULL;
    struct FileIdentDesc cfi, *fi;
    struct udf_fileident_bh fibh;

    if (dentry->d_name.len > UDF_NAME_LEN)
        return ERR_PTR(-ENAMETOOLONG);

#ifdef UDF_RECOVERY
    /* temporary shorthand for specifying files by inode number */
    if (!strncmp(dentry->d_name.name, ".B=", 3) )
    {
        lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) };
        inode = udf_iget(dir->i_sb, lb);
        if (!inode)
            return ERR_PTR(-EACCES);
    }
    else
#endif /* UDF_RECOVERY */

    if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi)))
    {
        if (fibh.sbh != fibh.ebh)
            udf_release_data(fibh.ebh);
        udf_release_data(fibh.sbh);

        inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
        if ( !inode )
            return ERR_PTR(-EACCES);
    }
    d_add(dentry, inode);
    return NULL;
}

static struct FileIdentDesc *
udf_add_entry(struct inode *dir, struct dentry *dentry,
    struct udf_fileident_bh *fibh,
    struct FileIdentDesc *cfi, int *err)
{
    struct super_block *sb;
    struct FileIdentDesc *fi=NULL;
    struct ustr unifilename;
    char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
    int namelen;
    loff_t f_pos;
    int flen;
    char *nameptr;
    loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
    int nfidlen;
    Uint8 lfi;
    Uint16 liu;
    int block;
    lb_addr bloc, eloc;
    Uint32 extoffset, elen, offset;
    struct buffer_head *bh = NULL;

    sb = dir->i_sb;

    if (dentry)
    {
        if (!dentry->d_name.len)
        {
            *err = -EINVAL;
            return NULL;
        }

        if ( !(udf_char_to_ustr(&unifilename, dentry->d_name.name, dentry->d_name.len)) )
        {
            *err = -ENAMETOOLONG;
            return NULL;
        }

        if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
        {
            if ( !(namelen = udf_UTF8toCS0(name, &unifilename, UDF_NAME_LEN)) )
            {
                *err = -ENAMETOOLONG;
                return NULL;
            }
        }
        else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
        {
            if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, name, &unifilename, UDF_NAME_LEN)) )
            {
                *err = -ENAMETOOLONG;
                return NULL;
            }
        }
        else
            return NULL;
    }
    else
        namelen = 0;

    nfidlen = (sizeof(struct FileIdentDesc) + namelen + 3) & ~3;

    f_pos = (udf_ext0_offset(dir) >> 2);

    fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
    if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
        &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
    {
        offset >>= dir->i_sb->s_blocksize_bits;
        block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
        if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
        {
            if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
                extoffset -= sizeof(short_ad);
            else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
                extoffset -= sizeof(long_ad);
        }
        else
            offset = 0;

        if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
        {
            udf_release_data(bh);
            *err = -EIO;
            return NULL;
        }
    
        block = UDF_I_LOCATION(dir).logicalBlockNum;
    
        while ( (f_pos < size) )
        {
            fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
    
            if (!fi)
            {
                if (fibh->sbh != fibh->ebh)
                    udf_release_data(fibh->ebh);
                udf_release_data(fibh->sbh);
                udf_release_data(bh);
                *err = -EIO;
                return NULL;
            }
    
            liu = le16_to_cpu(cfi->lengthOfImpUse);
            lfi = cfi->lengthFileIdent;
    
            if (fibh->sbh == fibh->ebh)
                nameptr = fi->fileIdent + liu;
            else
            {
                int poffset;    /* Unpaded ending offset */
    
                poffset = fibh->soffset + sizeof(struct FileIdentDesc) + liu + lfi;
    
                if (poffset >= lfi)
                    nameptr = (char *)(fibh->ebh->b_data + poffset - lfi);
                else
                {
                    nameptr = fname;
                    memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
                    memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
                }
            }
    
            if ( (cfi->fileCharacteristics & FILE_DELETED) != 0 )
            {
                if (((sizeof(struct FileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen)
                {
                    udf_release_data(bh);
                    cfi->descTag.tagSerialNum = cpu_to_le16(1);
                    cfi->fileVersionNum = cpu_to_le16(1);
                    cfi->fileCharacteristics = 0;
                    cfi->lengthFileIdent = namelen;
                    cfi->lengthOfImpUse = cpu_to_le16(0);
                    if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
                        return fi;
                    else
                    {
                        *err = -EIO;
                        return NULL;
                    }
                }
            }

            if (!lfi || !dentry)
                continue;

            if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
                udf_match(flen, fname, &(dentry->d_name)))
            {
                if (fibh->sbh != fibh->ebh)
                    udf_release_data(fibh->ebh);
                udf_release_data(fibh->sbh);
                udf_release_data(bh);
                *err = -EEXIST;
                return NULL;
            }
        }
    }
    else
    {
        block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0);
        if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
        {
            fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
            fibh->soffset = fibh->eoffset = udf_file_entry_alloc_offset(dir);
        }
        else
        {
            fibh->sbh = fibh->ebh = NULL;
            fibh->soffset = fibh->eoffset = sb->s_blocksize;
        }
    }

    f_pos += nfidlen;

    if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB &&
        sb->s_blocksize - fibh->eoffset < nfidlen)
    {
        udf_release_data(bh);
        bh = NULL;
        fibh->soffset -= udf_ext0_offset(dir);
        fibh->eoffset -= udf_ext0_offset(dir);
        f_pos -= (udf_ext0_offset(dir) >> 2);
        if (fibh->sbh != fibh->ebh)
            udf_release_data(fibh->ebh);
        udf_release_data(fibh->sbh);
        if (!(fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err)))
            return NULL;
        bloc = UDF_I_LOCATION(dir);
        eloc.logicalBlockNum = block;
        eloc.partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
        elen = dir->i_sb->s_blocksize;
        extoffset = udf_file_entry_alloc_offset(dir);
        if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
            extoffset += sizeof(short_ad);
        else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
            extoffset += sizeof(long_ad);
    }

    if (sb->s_blocksize - fibh->eoffset >= nfidlen)
    {
        fibh->soffset = fibh->eoffset;
        fibh->eoffset += nfidlen;
        if (fibh->sbh != fibh->ebh)
        {
            udf_release_data(fibh->sbh);
            fibh->sbh = fibh->ebh;
        }

        if (UDF_I_ALLOCTYPE(dir) != ICB_FLAG_AD_IN_ICB)
            block = eloc.logicalBlockNum + ((elen - 1) >>
                dir->i_sb->s_blocksize_bits);
        else
            block = UDF_I_LOCATION(dir).logicalBlockNum;
                
        fi = (struct FileIdentDesc *)(fibh->sbh->b_data + fibh->soffset);
    }
    else
    {
        fibh->soffset = fibh->eoffset - sb->s_blocksize;
        fibh->eoffset += nfidlen - sb->s_blocksize;
        if (fibh->sbh != fibh->ebh)
        {
            udf_release_data(fibh->sbh);
            fibh->sbh = fibh->ebh;
        }

        block = eloc.logicalBlockNum + ((elen - 1) >>
            dir->i_sb->s_blocksize_bits);

        if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
        {
            udf_release_data(bh);
            udf_release_data(fibh->sbh);
            return NULL;
        }

        if (!(fibh->soffset))
        {
            if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) ==
                EXTENT_RECORDED_ALLOCATED)
            {
                block = eloc.logicalBlockNum + ((elen - 1) >>
                    dir->i_sb->s_blocksize_bits);
            }
            else
                block ++;

            udf_release_data(fibh->sbh);
            fibh->sbh = fibh->ebh;
            fi = (struct FileIdentDesc *)(fibh->sbh->b_data);
        }
        else
        {
            fi = (struct FileIdentDesc *)
                (fibh->sbh->b_data + sb->s_blocksize + fibh->soffset);
        }
    }

    memset(cfi, 0, sizeof(struct FileIdentDesc));
    udf_new_tag((char *)cfi, TID_FILE_IDENT_DESC, 2, 1, block, sizeof(tag));
    cfi->fileVersionNum = cpu_to_le16(1);
    cfi->lengthFileIdent = namelen;
    cfi->lengthOfImpUse = cpu_to_le16(0);
    if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
    {
        udf_release_data(bh);
        dir->i_size += nfidlen;
        if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
            UDF_I_LENALLOC(dir) += nfidlen;
        dir->i_version = ++event;
        mark_inode_dirty(dir);
        return fi;
    }
    else
    {
        udf_release_data(bh);
        if (fibh->sbh != fibh->ebh)
            udf_release_data(fibh->ebh);
        udf_release_data(fibh->sbh);
        *err = -EIO;
        return NULL;
    }
}

static int udf_delete_entry(struct inode *inode, struct FileIdentDesc *fi,
    struct udf_fileident_bh *fibh, struct FileIdentDesc *cfi)
{
    cfi->fileCharacteristics |= FILE_DELETED;
    if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
        memset(&(cfi->icb), 0x00, sizeof(long_ad));
    return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
}

static int udf_create(struct inode *dir, struct dentry *dentry, int mode)
{
    struct udf_fileident_bh fibh;
    struct inode *inode;
    struct FileIdentDesc cfi, *fi;
    int err;

    inode = udf_new_inode(dir, mode, &err);
    if (!inode)
        return err;

    if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
        inode->i_data.a_ops = &udf_adinicb_aops;
    else
        inode->i_data.a_ops = &udf_aops;
    inode->i_op = &udf_file_inode_operations;
    inode->i_fop = &udf_file_operations;
    inode->i_mode = mode;
    mark_inode_dirty(inode);

    if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
    {
        inode->i_nlink --;
        mark_inode_dirty(inode);
        iput(inode);
        return err;
    }
    cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
    cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
    *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
        cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
    udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
    if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
    {
        mark_inode_dirty(dir);
        dir->i_version = ++event;
    }
    if (fibh.sbh != fibh.ebh)
        udf_release_data(fibh.ebh);
    udf_release_data(fibh.sbh);
    d_instantiate(dentry, inode);
    return 0;
}

static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
{
    struct inode * inode;
    struct udf_fileident_bh fibh;
    int err;
    struct FileIdentDesc cfi, *fi;

    err = -EIO;
    inode = udf_new_inode(dir, mode, &err);
    if (!inode)
        goto out;

    inode->i_uid = current->fsuid;
    init_special_inode(inode, mode, rdev);
    if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
    {
        inode->i_nlink --;
        mark_inode_dirty(inode);
        iput(inode);
        return err;
    }
    cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
    cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
    *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
        cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
    udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
    if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
    {
        mark_inode_dirty(dir);
        dir->i_version = ++event;
    }
    mark_inode_dirty(inode);

    if (fibh.sbh != fibh.ebh)
        udf_release_data(fibh.ebh);
    udf_release_data(fibh.sbh);
    d_instantiate(dentry, inode);
    err = 0;
out:
    return err;
}

static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
    struct inode * inode;
    struct udf_fileident_bh fibh;
    int err;
    struct FileIdentDesc cfi, *fi;

    err = -EMLINK;
    if (dir->i_nlink >= (256<<sizeof(dir->i_nlink))-1)
        goto out;

    err = -EIO;
    inode = udf_new_inode(dir, S_IFDIR, &err);
    if (!inode)
        goto out;

    inode->i_op = &udf_dir_inode_operations;
    inode->i_fop = &udf_dir_operations;
    if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err)))
    {
        inode->i_nlink--;
        mark_inode_dirty(inode);
        iput(inode);
        goto out;
    }
    inode->i_nlink = 2;
    cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
    cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(dir));
    *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
        cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
    cfi.fileCharacteristics = FILE_DIRECTORY | FILE_PARENT;
    udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
    udf_release_data(fibh.sbh);
    inode->i_mode = S_IFDIR | mode;
    if (dir->i_mode & S_ISGID)
        inode->i_mode |= S_ISGID;
    mark_inode_dirty(inode);

    if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
    {
        inode->i_nlink = 0;
        mark_inode_dirty(inode);
        iput(inode);
        goto out;
    }
    cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
    cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
    *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
        cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
    cfi.fileCharacteristics |= FILE_DIRECTORY;
    udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
    dir->i_version = ++event;
    dir->i_nlink++;
    mark_inode_dirty(dir);
    d_instantiate(dentry, inode);
    if (fibh.sbh != fibh.ebh)
        udf_release_data(fibh.ebh);
    udf_release_data(fibh.sbh);
    err = 0;
out:
    return err;
}

static int empty_dir(struct inode *dir)
{
    struct FileIdentDesc *fi, cfi;
    struct udf_fileident_bh fibh;
    loff_t f_pos;
    loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
    int block;
    lb_addr bloc, eloc;
    Uint32 extoffset, elen, offset;
    struct buffer_head *bh = NULL;

    f_pos = (udf_ext0_offset(dir) >> 2);

    fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
    if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
        &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
    {
        offset >>= dir->i_sb->s_blocksize_bits;
        block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
        if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
        {
            if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
                extoffset -= sizeof(short_ad);
            else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
                extoffset -= sizeof(long_ad);
        }
        else
            offset = 0;
    }
    else
    {
        udf_release_data(bh);
        return 0;
    }

    if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
        return 0;

    while ( (f_pos < size) )
    {
        fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);

        if (!fi)
        {
            if (fibh.sbh != fibh.ebh)
                udf_release_data(fibh.ebh);
            udf_release_data(fibh.sbh);
            udf_release_data(bh);
            return 0;
        }

        if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FILE_DELETED) == 0)
        {
            udf_release_data(bh);
            return 0;
        }
    }
    if (fibh.sbh != fibh.ebh)
        udf_release_data(fibh.ebh);
    udf_release_data(fibh.sbh);
    udf_release_data(bh);
    return 1;
}

static int udf_rmdir(struct inode * dir, struct dentry * dentry)
{
    int retval;
    struct inode * inode = dentry->d_inode;
    struct udf_fileident_bh fibh;
    struct FileIdentDesc *fi, cfi;

    retval = -ENOENT;
    fi = udf_find_entry(dir, dentry, &fibh, &cfi);
    if (!fi)
        goto out;

    retval = -EIO;
    if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) != inode->i_ino)
        goto end_rmdir;
    retval = -ENOTEMPTY;
    if (!empty_dir(inode))
        goto end_rmdir;
    retval = udf_delete_entry(dir, fi, &fibh, &cfi);
    dir->i_version = ++event;
    if (retval)
        goto end_rmdir;
    if (inode->i_nlink != 2)
        udf_warning(inode->i_sb, "udf_rmdir",
            "empty directory has nlink != 2 (%d)",
            inode->i_nlink);
    inode->i_version = ++event;
    inode->i_nlink = 0;
    inode->i_size = 0;
    mark_inode_dirty(inode);
    dir->i_nlink --;
    inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
    UDF_I_UCTIME(inode) = UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME;
    mark_inode_dirty(dir);

end_rmdir:
    if (fibh.sbh != fibh.ebh)
        udf_release_data(fibh.ebh);
    udf_release_data(fibh.sbh);
out:
    return retval;
}

static int udf_unlink(struct inode * dir, struct dentry * dentry)
{
    int retval;
    struct inode * inode = dentry->d_inode;
    struct udf_fileident_bh fibh;
    struct FileIdentDesc *fi;
    struct FileIdentDesc cfi;

    retval = -ENOENT;
    fi = udf_find_entry(dir, dentry, &fibh, &cfi);
    if (!fi)
        goto out;

    retval = -EIO;

    if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) !=
        inode->i_ino)
    {
        goto end_unlink;
    }

    if (!inode->i_nlink)
    {
        udf_debug("Deleting nonexistent file (%lu), %d\n",
            inode->i_ino, inode->i_nlink);
        inode->i_nlink = 1;
    }
    retval = udf_delete_entry(dir, fi, &fibh, &cfi);
    if (retval)
        goto end_unlink;
    dir->i_ctime = dir->i_mtime = CURRENT_TIME;
    UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME;
    mark_inode_dirty(dir);
    inode->i_nlink--;
    mark_inode_dirty(inode);
    inode->i_ctime = dir->i_ctime;
    retval = 0;

end_unlink:
    if (fibh.sbh != fibh.ebh)
        udf_release_data(fibh.ebh);
    udf_release_data(fibh.sbh);
out:
    return retval;
}

static int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname)
{
    struct inode * inode;
    struct PathComponent *pc;
    char *compstart;
    struct udf_fileident_bh fibh;
    struct buffer_head *bh = NULL;
    int eoffset, elen = 0;
    struct FileIdentDesc *fi;
    struct FileIdentDesc cfi;
    char *ea;
    int err;
    int block;

    if (!(inode = udf_new_inode(dir, S_IFLNK, &err)))
        goto out;

    inode->i_mode = S_IFLNK | S_IRWXUGO;
    inode->i_data.a_ops = &udf_symlink_aops;
    inode->i_op = &page_symlink_inode_operations;

    if (UDF_I_ALLOCTYPE(inode) != ICB_FLAG_AD_IN_ICB)
    {
        struct buffer_head *bh = NULL;
        lb_addr bloc, eloc;
        Uint32 elen, extoffset;

        block = udf_new_block(inode->i_sb, inode,
            UDF_I_LOCATION(inode).partitionReferenceNum,
            UDF_I_LOCATION(inode).logicalBlockNum, &err);
        if (!block)
            goto out_no_entry;
        bloc = UDF_I_LOCATION(inode);
        eloc.logicalBlockNum = block;
        eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
        elen = inode->i_sb->s_blocksize;
        UDF_I_LENEXTENTS(inode) = elen;
        extoffset = udf_file_entry_alloc_offset(inode);
        udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 0);
        udf_release_data(bh);

        block = udf_get_pblock(inode->i_sb, block,
            UDF_I_LOCATION(inode).partitionReferenceNum, 0);
        bh = udf_tread(inode->i_sb, block);
        lock_buffer(bh);
        memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
        mark_buffer_uptodate(bh, 1);
        unlock_buffer(bh);
        mark_buffer_dirty_inode(bh, inode);
    }
    else
    {
        block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
        bh = udf_tread(inode->i_sb, block);
    }
    ea = bh->b_data + udf_ext0_offset(inode);

    eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
    pc = (struct PathComponent *)ea;

    if (*symname == '/')
    {
        do
        {
            symname++;
        } while (*symname == '/');

        pc->componentType = 1;
        pc->lengthComponentIdent = 0;
        pc->componentFileVersionNum = 0;
        pc += sizeof(struct PathComponent);
        elen += sizeof(struct PathComponent);
    }

    err = -ENAMETOOLONG;

    while (*symname)
    {
        if (elen + sizeof(struct PathComponent) > eoffset)
            goto out_no_entry;

        pc = (struct PathComponent *)(ea + elen);

        compstart = (char *)symname;

        do
        {
            symname++;
        } while (*symname && *symname != '/');

        pc->componentType = 5;
        pc->lengthComponentIdent = 0;
        pc->componentFileVersionNum = 0;
        if (pc->componentIdent[0] == '.')
        {
            if (pc->lengthComponentIdent == 1)
                pc->componentType = 4;
            else if (pc->lengthComponentIdent == 2 && pc->componentIdent[1] == '.')
                pc->componentType = 3;
        }

        if (pc->componentType == 5)
        {
            if (elen + sizeof(struct PathComponent) + symname - compstart > eoffset)
                goto out_no_entry;
            else
                pc->lengthComponentIdent = symname - compstart;

            memcpy(pc->componentIdent, compstart, pc->lengthComponentIdent);
        }

        elen += sizeof(struct PathComponent) + pc->lengthComponentIdent;

        if (*symname)
        {
            do
            {
                symname++;
            } while (*symname == '/');
        }
    }

    udf_release_data(bh);
    inode->i_size = elen;
    if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
        UDF_I_LENALLOC(inode) = inode->i_size;
    mark_inode_dirty(inode);

    if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
        goto out_no_entry;
    cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
    cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
    if (UDF_SB_LVIDBH(inode->i_sb))
    {
        struct LogicalVolHeaderDesc *lvhd;
        Uint64 uniqueID;
        lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
        uniqueID = le64_to_cpu(lvhd->uniqueID);
        *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
            cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
        if (!(++uniqueID & 0x00000000FFFFFFFFUL))
            uniqueID += 16;
        lvhd->uniqueID = cpu_to_le64(uniqueID);
        mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
    }
    udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
    if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
    {
        mark_inode_dirty(dir);
        dir->i_version = ++event;
    }
    if (fibh.sbh != fibh.ebh)
        udf_release_data(fibh.ebh);
    udf_release_data(fibh.sbh);
    d_instantiate(dentry, inode);
    err = 0;

out:
    return err;

out_no_entry:
    inode->i_nlink--;
    mark_inode_dirty(inode);
    iput(inode);
    goto out;
}

static int udf_link(struct dentry * old_dentry, struct inode * dir,
     struct dentry *dentry)
{
    struct inode *inode = old_dentry->d_inode;
    struct udf_fileident_bh fibh;
    int err;
    struct FileIdentDesc cfi, *fi;

    if (S_ISDIR(inode->i_mode))
        return -EPERM;

    if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1)
        return -EMLINK;

    if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
        return err;
    cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
    cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
    if (UDF_SB_LVIDBH(inode->i_sb))
    {
        struct LogicalVolHeaderDesc *lvhd;
        Uint64 uniqueID;
        lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
        uniqueID = le64_to_cpu(lvhd->uniqueID);
        *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
            cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
        if (!(++uniqueID & 0x00000000FFFFFFFFUL))
            uniqueID += 16;
        lvhd->uniqueID = cpu_to_le64(uniqueID);
        mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
    }
    udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
    if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
    {
        mark_inode_dirty(dir);
        dir->i_version = ++event;
    }
    if (fibh.sbh != fibh.ebh)
        udf_release_data(fibh.ebh);
    udf_release_data(fibh.sbh);
    inode->i_nlink ++;
    inode->i_ctime = CURRENT_TIME;
    UDF_I_UCTIME(inode) = CURRENT_UTIME;
    mark_inode_dirty(inode);
    atomic_inc(&inode->i_count);
    d_instantiate(dentry, inode);
    return 0;
}

/* Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
    struct inode * new_dir, struct dentry * new_dentry)
{
    struct inode * old_inode = old_dentry->d_inode;
    struct inode * new_inode = new_dentry->d_inode;
    struct udf_fileident_bh ofibh, nfibh;
    struct FileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi;
    struct buffer_head *dir_bh = NULL;
    int retval = -ENOENT;

    if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi)))
    {
        if (ofibh.sbh != ofibh.ebh)
            udf_release_data(ofibh.ebh);
        udf_release_data(ofibh.sbh);
    }
    if (!ofi || udf_get_lb_pblock(old_dir->i_sb, lelb_to_cpu(ocfi.icb.extLocation), 0) !=
        old_inode->i_ino)
    {
        goto end_rename;
    }

    nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
    if (nfi)
    {
        if (!new_inode)
        {
            if (nfibh.sbh != nfibh.ebh)
                udf_release_data(nfibh.ebh);
            udf_release_data(nfibh.sbh);
            nfi = NULL;
        }
    }
    if (S_ISDIR(old_inode->i_mode))
    {
        Uint32 offset = udf_ext0_offset(old_inode);

        if (new_inode)
        {
            retval = -ENOTEMPTY;
            if (!empty_dir(new_inode))
                goto end_rename;
        }
        retval = -EIO;
        dir_bh = udf_bread(old_inode, 0, 0, &retval);
        if (!dir_bh)
            goto end_rename;
        dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset);
        if (!dir_fi)
            goto end_rename;
        if (udf_get_lb_pblock(old_inode->i_sb, cpu_to_lelb(dir_fi->icb.extLocation), 0) !=
            old_dir->i_ino)
        {
            goto end_rename;
        }
        retval = -EMLINK;
        if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1)
            goto end_rename;
    }
    if (!nfi)
    {
        nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval);
        if (!nfi)
            goto end_rename;
    }
    new_dir->i_version = ++event;

    /*
     * Like most other Unix systems, set the ctime for inodes on a
     * rename.
     */
    old_inode->i_ctime = CURRENT_TIME;
    UDF_I_UCTIME(old_inode) = CURRENT_UTIME;
    mark_inode_dirty(old_inode);

    /*
     * ok, that's it
     */
    ncfi.fileVersionNum = ocfi.fileVersionNum;
    ncfi.fileCharacteristics = ocfi.fileCharacteristics;
    memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad));
    udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);

    /* The old fid may have moved - find it again */
    ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
    udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);

    old_dir->i_version = ++event;
    if (new_inode)
    {
        new_inode->i_nlink--;
        new_inode->i_ctime = CURRENT_TIME;
        UDF_I_UCTIME(new_inode) = CURRENT_UTIME;
        mark_inode_dirty(new_inode);
    }
    old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
    UDF_I_UCTIME(old_dir) = UDF_I_UMTIME(old_dir) = CURRENT_UTIME;
    mark_inode_dirty(old_dir);

    if (dir_bh)
    {
        dir_fi->icb.extLocation = lelb_to_cpu(UDF_I_LOCATION(new_dir));
        udf_update_tag((char *)dir_fi, (sizeof(struct FileIdentDesc) +
            cpu_to_le16(dir_fi->lengthOfImpUse) + 3) & ~3);
        if (UDF_I_ALLOCTYPE(old_inode) == ICB_FLAG_AD_IN_ICB)
        {
            mark_inode_dirty(old_inode);
            old_inode->i_version = ++event;
        }
        else
            mark_buffer_dirty_inode(dir_bh, old_inode);
        old_dir->i_nlink --;
        mark_inode_dirty(old_dir);
        if (new_inode)
        {
            new_inode->i_nlink --;
            mark_inode_dirty(new_inode);
        }
        else
        {
            new_dir->i_nlink ++;
            mark_inode_dirty(new_dir);
        }
    }

    if (ofi)
    {
        if (ofibh.sbh != ofibh.ebh)
            udf_release_data(ofibh.ebh);
        udf_release_data(ofibh.sbh);
    }

    retval = 0;

end_rename:
    udf_release_data(dir_bh);
    if (nfi)
    {
        if (nfibh.sbh != nfibh.ebh)
            udf_release_data(nfibh.ebh);
        udf_release_data(nfibh.sbh);
    }
    return retval;
}

struct inode_operations udf_dir_inode_operations = {
    lookup:                udf_lookup,
    create:                udf_create,
    link:                udf_link,
    unlink:                udf_unlink,
    symlink:            udf_symlink,
    mkdir:                udf_mkdir,
    rmdir:                udf_rmdir,
    mknod:                udf_mknod,
    rename:                udf_rename,
};

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.023 ]--