!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/umsdos/   drwxr-xr-x
Free 318.35 GB of 458.09 GB (69.5%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     emd.c (15.62 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *  linux/fs/umsdos/emd.c
 *
 *  Written 1993 by Jacques Gelinas
 *
 *  Extended MS-DOS directory handling functions
 */

#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/msdos_fs.h>
#include <linux/umsdos_fs.h>
#include <linux/dcache.h>
#include <linux/pagemap.h>
#include <linux/delay.h>

void put_entry (struct umsdos_dirent *p, struct umsdos_dirent *q)
{
    p->name_len = q->name_len;
    p->flags = q->flags;
    p->nlink = cpu_to_le16(q->nlink);
    p->uid = cpu_to_le16(q->uid);
    p->gid = cpu_to_le16(q->gid);
    p->atime = cpu_to_le32(q->atime);
    p->mtime = cpu_to_le32(q->mtime);
    p->ctime = cpu_to_le32(q->ctime);
    p->rdev = cpu_to_le16(q->rdev);
    p->mode = cpu_to_le16(q->mode);
}

static void get_entry(struct umsdos_dirent *p, struct umsdos_dirent *q)
{
    p->name_len = q->name_len;
    p->name[p->name_len]='\0';
    p->flags = q->flags;
    p->nlink = le16_to_cpu (q->nlink);
    /* FIXME -- 32bit UID/GID issues */
    p->uid = le16_to_cpu (q->uid);
    p->gid = le16_to_cpu (q->gid);
    p->atime = le32_to_cpu (q->atime);
    p->mtime = le32_to_cpu (q->mtime);
    p->ctime = le32_to_cpu (q->ctime);
    p->rdev = le16_to_cpu (q->rdev);
    p->mode = le16_to_cpu (q->mode);
}

/*
 * Lookup the EMD dentry for a directory.
 *
 * Note: the caller must hold a lock on the parent directory.
 */
struct dentry *umsdos_get_emd_dentry(struct dentry *parent)
{
    struct dentry *demd;

    demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE, 
                    UMSDOS_EMD_NAMELEN, 1);
    return demd;
}

/*
 * Check whether a directory has an EMD file.
 *
 * Note: the caller must hold a lock on the parent directory.
 */
int umsdos_have_emd(struct dentry *dir)
{
    struct dentry *demd = umsdos_get_emd_dentry (dir);
    int found = 0;

    if (!IS_ERR(demd)) {
        if (demd->d_inode)
            found = 1;
        dput(demd);
    }
    return found;
}

/*
 * Create the EMD file for a directory if it doesn't
 * already exist. Returns 0 or an error code.
 *
 * Note: the caller must hold a lock on the parent directory.
 */
int umsdos_make_emd(struct dentry *parent)
{
    struct dentry *demd = umsdos_get_emd_dentry(parent);
    int err = PTR_ERR(demd);

    if (IS_ERR(demd)) {
        printk("umsdos_make_emd: can't get dentry in %s, err=%d\n",
            parent->d_name.name, err);
        goto out;
    }

    /* already created? */
    err = 0;
    if (demd->d_inode)
        goto out_set;

Printk(("umsdos_make_emd: creating EMD %s/%s\n",
parent->d_name.name, demd->d_name.name));

    err = msdos_create(parent->d_inode, demd, S_IFREG | 0777);
    if (err) {
        printk (KERN_WARNING
            "umsdos_make_emd: create %s/%s failed, err=%d\n",
            parent->d_name.name, demd->d_name.name, err);
    }
out_set:
    dput(demd);
out:
    return err;
}


/*
 * Read an entry from the EMD file.
 * Support variable length record.
 * Return -EIO if error, 0 if OK.
 *
 * does not change {d,i}_count
 */

int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_dirent *entry)
{
    struct address_space *mapping = demd->d_inode->i_mapping;
    struct page *page;
    struct umsdos_dirent *p;
    int offs = *pos & ~PAGE_CACHE_MASK;
    int recsize;
    int ret = 0;

    page = read_cache_page(mapping, *pos>>PAGE_CACHE_SHIFT,
            (filler_t*)mapping->a_ops->readpage, NULL);
    if (IS_ERR(page))
        goto sync_fail;
    wait_on_page(page);
    if (!Page_Uptodate(page))
        goto async_fail;
    p = (struct umsdos_dirent*)(kmap(page)+offs);

    /* if this is an invalid entry (invalid name length), ignore it */
    if( p->name_len > UMSDOS_MAXNAME )
    {
        printk (KERN_WARNING "Ignoring invalid EMD entry with size %d\n", entry->name_len);
        p->name_len = 0; 
        ret = -ENAMETOOLONG; /* notify umssync(8) code that something is wrong */
        /* FIXME: does not work if we did 'ls -l' before 'udosctl uls' ?! */
    }

    recsize = umsdos_evalrecsize(p->name_len);
    if (offs + recsize > PAGE_CACHE_SIZE) {
        struct page *page2;
        int part = (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare;
        page2 = read_cache_page(mapping, 1+(*pos>>PAGE_CACHE_SHIFT),
                (filler_t*)mapping->a_ops->readpage, NULL);
        if (IS_ERR(page2)) {
            kunmap(page);
            page_cache_release(page);
            page = page2;
            goto sync_fail;
        }
        wait_on_page(page2);
        if (!Page_Uptodate(page2)) {
            kunmap(page);
            page_cache_release(page2);
            goto async_fail;
        }
        memcpy(entry->spare,p->spare,part);
        memcpy(entry->spare+part,kmap(page2),
                recsize+offs-PAGE_CACHE_SIZE);
        kunmap(page2);
        page_cache_release(page2);
    } else
        memcpy(entry->spare,p->spare,((char*)p+recsize)-p->spare);
    get_entry(entry, p);
    kunmap(page);
    page_cache_release(page);
    *pos += recsize;
    return ret;
async_fail:
    page_cache_release(page);
    page = ERR_PTR(-EIO);
sync_fail:
    return PTR_ERR(page);
}


/*
 * Write an entry in the EMD file.
 * Return 0 if OK, -EIO if some error.
 *
 * Note: the caller must hold a lock on the parent directory.
 */
int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
                int free_entry)
{
    struct inode *dir = parent->d_inode;
    struct umsdos_dirent *entry = &info->entry;
    struct dentry *emd_dentry;
    int ret;
    struct umsdos_dirent entry0,*p;
    struct address_space *mapping;
    struct page *page, *page2 = NULL;
    int offs;

    emd_dentry = umsdos_get_emd_dentry(parent);
    ret = PTR_ERR(emd_dentry);
    if (IS_ERR(emd_dentry))
        goto out;
    /* make sure there's an EMD file */
    ret = -EIO;
    if (!emd_dentry->d_inode) {
        printk(KERN_WARNING
            "umsdos_writeentry: no EMD file in %s/%s\n",
            parent->d_parent->d_name.name, parent->d_name.name);
        goto out_dput;
    }

    if (free_entry) {
        /* #Specification: EMD file / empty entries
         * Unused entries in the EMD file are identified
         * by the name_len field equal to 0. However to
         * help future extension (or bug correction :-( ),
         * empty entries are filled with 0.
         */
        memset (&entry0, 0, sizeof (entry0));
        entry = &entry0;
    } else if (entry->name_len > 0) {
        memset (entry->name + entry->name_len, '\0', 
            sizeof (entry->name) - entry->name_len);
        /* #Specification: EMD file / spare bytes
         * 10 bytes are unused in each record of the EMD. They
         * are set to 0 all the time, so it will be possible
         * to do new stuff and rely on the state of those
         * bytes in old EMD files.
         */
        memset (entry->spare, 0, sizeof (entry->spare));
    }

    /* write the entry and update the parent timestamps */
    mapping = emd_dentry->d_inode->i_mapping;
    offs = info->f_pos & ~PAGE_CACHE_MASK;
    ret = -ENOMEM;
    page = grab_cache_page(mapping, info->f_pos>>PAGE_CACHE_SHIFT);
    if (!page)
        goto out_dput;
    p = (struct umsdos_dirent *) (page_address(page) + offs);
    if (offs + info->recsize > PAGE_CACHE_SIZE) {
        ret = mapping->a_ops->prepare_write(NULL,page,offs,
                    PAGE_CACHE_SIZE);
        if (ret)
            goto out_unlock;
        page2 = grab_cache_page(mapping,
                    (info->f_pos>>PAGE_CACHE_SHIFT)+1);
        if (!page2)
            goto out_unlock2;
        ret = mapping->a_ops->prepare_write(NULL,page2,0,
                    offs+info->recsize-PAGE_CACHE_SIZE);
        if (ret)
            goto out_unlock3;
        put_entry (p, entry);
        memcpy(p->spare,entry->spare,
            (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare);
        memcpy(page_address(page2),
                ((char*)entry)+PAGE_CACHE_SIZE-offs,
                offs+info->recsize-PAGE_CACHE_SIZE);
        ret = mapping->a_ops->commit_write(NULL,page2,0,
                    offs+info->recsize-PAGE_CACHE_SIZE);
        if (ret)
            goto out_unlock3;
        ret = mapping->a_ops->commit_write(NULL,page,offs,
                    PAGE_CACHE_SIZE);
        UnlockPage(page2);
        page_cache_release(page2);
        if (ret)
            goto out_unlock;
    } else {
        ret = mapping->a_ops->prepare_write(NULL,page,offs,
                    offs + info->recsize);
        if (ret)
            goto out_unlock;
        put_entry (p, entry);
        memcpy(p->spare,entry->spare,((char*)p+info->recsize)-p->spare);
        ret = mapping->a_ops->commit_write(NULL,page,offs,
                    offs + info->recsize);
        if (ret)
            goto out_unlock;
    }
    UnlockPage(page);
    page_cache_release(page);
        
    dir->i_ctime = dir->i_mtime = CURRENT_TIME;
    mark_inode_dirty(dir);

out_dput:
    dput(emd_dentry);
out:
    Printk (("umsdos_writeentry /mn/: returning %d...\n", ret));
    return ret;
out_unlock3:
    UnlockPage(page2);
    page_cache_release(page2);
out_unlock2:
    ClearPageUptodate(page);
    kunmap(page);
out_unlock:
    UnlockPage(page);
    page_cache_release(page);
    printk ("UMSDOS:  problem with EMD file:  can't write\n");
    goto out_dput;
}

/*
 * General search, locate a name in the EMD file or an empty slot to
 * store it. if info->entry.name_len == 0, search the first empty
 * slot (of the proper size).
 * 
 * Return 0 if found, -ENOENT if not found, another error code if
 * other problem.
 * 
 * So this routine is used to either find an existing entry or to
 * create a new one, while making sure it is a new one. After you
 * get -ENOENT, you make sure the entry is stuffed correctly and
 * call umsdos_writeentry().
 * 
 * To delete an entry, you find it, zero out the entry (memset)
 * and call umsdos_writeentry().
 * 
 * All this to say that umsdos_writeentry must be called after this
 * function since it relies on the f_pos field of info.
 *
 * Note: the caller must hold a lock on the parent directory.
 */
/* #Specification: EMD file structure
 * The EMD file uses a fairly simple layout.  It is made of records
 * (UMSDOS_REC_SIZE == 64).  When a name can't be written in a single
 * record, multiple contiguous records are allocated.
 */

static int umsdos_find (struct dentry *demd, struct umsdos_info *info)
{
    struct umsdos_dirent *entry = &info->entry;
    int recsize = info->recsize;
    struct inode *emd_dir;
    int ret = -ENOENT;
    struct {
        off_t posok;    /* Position available to store the entry */
        off_t one;    /* One empty position -> maybe <- large enough */
    } empty;
    int found = 0;
    int empty_size = 0;
    struct address_space *mapping;
    filler_t *readpage;
    struct page *page = NULL;
    int index = -1;
    int offs = PAGE_CACHE_SIZE,max_offs = PAGE_CACHE_SIZE;
    char *p = NULL;
    loff_t pos = 0;

    /* make sure there's an EMD file ... */
    ret = -ENOENT;
    emd_dir = demd->d_inode;
    if (!emd_dir)
        goto out_dput;
    mapping = emd_dir->i_mapping;
    readpage = (filler_t*)mapping->a_ops->readpage;

    empty.posok = emd_dir->i_size;
    while (1) {
        struct umsdos_dirent *rentry;
        int entry_size;

        if (offs >= max_offs) {
            if (page) {
                kunmap(page);
                page_cache_release(page);
                page = NULL;
            }
            if (pos >= emd_dir->i_size) {
                info->f_pos = empty.posok;
                break;
            }
            if (++index == (emd_dir->i_size>>PAGE_CACHE_SHIFT))
                max_offs = emd_dir->i_size & ~PAGE_CACHE_MASK;
            offs -= PAGE_CACHE_SIZE;
            page = read_cache_page(mapping,index,readpage,NULL);
            if (IS_ERR(page))
                goto sync_fail;
            wait_on_page(page);
            if (!Page_Uptodate(page))
                goto async_fail;
            p = kmap(page);
        }

        rentry = (struct umsdos_dirent *)(p+offs);

        if (rentry->name_len == 0) {
            /* We are looking for an empty section at least */
            /* as large as recsize. */
            if (entry->name_len == 0) {
                info->f_pos = pos;
                ret = 0;
                break;
            }
            offs += UMSDOS_REC_SIZE;
            pos += UMSDOS_REC_SIZE;
            if (found)
                continue;
            if (!empty_size)
                empty.one = pos-UMSDOS_REC_SIZE;
            empty_size += UMSDOS_REC_SIZE;
            if (empty_size == recsize) {
                /* Here is a large enough section. */
                empty.posok = empty.one;
                found = 1;
            }
            continue;
        }

        entry_size = umsdos_evalrecsize(rentry->name_len);
        if (entry_size > PAGE_CACHE_SIZE)
            goto async_fail;
        empty_size = 0;
        if (entry->name_len != rentry->name_len)
            goto skip_it;

        if (entry_size + offs > PAGE_CACHE_SIZE) {
            /* Sucker spans the page boundary */
            int len = (p+PAGE_CACHE_SIZE)-rentry->name;
            struct page *next_page;
            char *q;
            next_page = read_cache_page(mapping,index+1,readpage,NULL);
            if (IS_ERR(next_page)) {
                page_cache_release(page);
                page = next_page;
                goto sync_fail;
            }
            wait_on_page(next_page);
            if (!Page_Uptodate(next_page)) {
                page_cache_release(page);
                page = next_page;
                goto async_fail;
            }
            q = kmap(next_page);
            if (memcmp(entry->name, rentry->name, len) ||
                memcmp(entry->name+len, q, entry->name_len-len)) {
                kunmap(next_page);
                page_cache_release(next_page);
                goto skip_it;
            }
            kunmap(next_page);
            page_cache_release(next_page);
        } else if (memcmp (entry->name, rentry->name, entry->name_len))
            goto skip_it;

        info->f_pos = pos;
        get_entry(entry, rentry);
        ret = 0;
        break;
skip_it:
        offs+=entry_size;
        pos+=entry_size;
    }
    if (page) {
        kunmap(page);
        page_cache_release(page);
    }
    umsdos_manglename (info);

out_dput:
    dput(demd);
    return ret;

async_fail:
    page_cache_release(page);
    page = ERR_PTR(-EIO);
sync_fail:
    return PTR_ERR(page);
}


/*
 * Add a new entry in the EMD file.
 * Return 0 if OK or a negative error code.
 * Return -EEXIST if the entry already exists.
 *
 * Complete the information missing in info.
 * 
 * N.B. What if the EMD file doesn't exist?
 */

int umsdos_newentry (struct dentry *parent, struct umsdos_info *info)
{
    int err, ret = -EEXIST;
    struct dentry *demd = umsdos_get_emd_dentry(parent);

    ret = PTR_ERR(demd);
    if (IS_ERR(demd))
        goto out;
    err = umsdos_find (demd, info);
    if (err && err == -ENOENT) {
        ret = umsdos_writeentry (parent, info, 0);
        Printk (("umsdos_writeentry EMD ret = %d\n", ret));
    }
out:
    return ret;
}


/*
 * Create a new hidden link.
 * Return 0 if OK, an error code if not.
 */

/* #Specification: hard link / hidden name
 * When a hard link is created, the original file is renamed
 * to a hidden name. The name is "..LINKNNN" where NNN is a
 * number define from the entry offset in the EMD file.
 */
int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info)
{
    int ret;
    struct dentry *demd = umsdos_get_emd_dentry(parent);
    ret = PTR_ERR(demd);
    if (IS_ERR(demd))
        goto out;

    umsdos_parse ("..LINK", 6, info);
    info->entry.name_len = 0;
    ret = umsdos_find (demd, info);
    if (ret == -ENOENT || ret == 0) {
        info->entry.name_len = sprintf (info->entry.name,
                        "..LINK%ld", info->f_pos);
        ret = 0;
    }
out:
    return ret;
}


/*
 * Remove an entry from the EMD file.
 * Return 0 if OK, a negative error code otherwise.
 * 
 * Complete the information missing in info.
 */

int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir)
{
    int ret;
    struct dentry *demd = umsdos_get_emd_dentry(parent);

    ret = PTR_ERR(demd);
    if (IS_ERR(demd))
        goto out;
    ret = umsdos_find (demd, info);
    if (ret)
        goto out;
    if (info->entry.name_len == 0)
        goto out;

    if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) {
        if (S_ISDIR (info->entry.mode)) {
            ret = -EISDIR;
        } else {
            ret = -ENOTDIR;
        }
        goto out;
    }
    ret = umsdos_writeentry (parent, info, 1);

out:
    return ret;
}


/*
 * Verify that an EMD directory is empty.
 * Return: 
 * 0 if not empty,
 * 1 if empty (except for EMD file),
 * 2 if empty or no EMD file.
 */

int umsdos_isempty (struct dentry *dentry)
{
    struct dentry *demd;
    int ret = 2;
    loff_t pos = 0;

    demd = umsdos_get_emd_dentry(dentry);
    if (IS_ERR(demd))
        goto out;
    /* If the EMD file does not exist, it is certainly empty. :-) */
    if (!demd->d_inode)
        goto out_dput;

    ret = 1;
    while (pos < demd->d_inode->i_size) {
        struct umsdos_dirent entry;

        if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) {
            ret = 0;
            break;
        }
        if (entry.name_len != 0) {
            ret = 0;
            break;
        }
    }

out_dput:
    dput(demd);
out:
    return ret;
}

/*
 * Locate an entry in a EMD directory.
 * Return 0 if OK, error code if not, generally -ENOENT.
 *
 * expect argument:
 *     0: anything
 *     1: file
 *     2: directory
 */

int umsdos_findentry (struct dentry *parent, struct umsdos_info *info,
            int expect)
{        
    int ret;
    struct dentry *demd = umsdos_get_emd_dentry(parent);

    ret = PTR_ERR(demd);
    if (IS_ERR(demd))
        goto out;
    ret = umsdos_find (demd, info);
    if (ret)
        goto out;

    switch (expect) {
    case 1:
        if (S_ISDIR (info->entry.mode))
            ret = -EISDIR;
        break;
    case 2:
        if (!S_ISDIR (info->entry.mode))
            ret = -ENOTDIR;
    }

out:
    Printk (("umsdos_findentry: returning %d\n", ret));
    return ret;
}

:: 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.005 ]--