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

Subversion Repositories or1k_old

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

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

Rev 1765 Rev 1782
/*
/*
 *  dir.c
 *  dir.c
 *
 *
 *  Copyright (C) 1995, 1996 by Volker Lendecke
 *  Copyright (C) 1995, 1996 by Volker Lendecke
 *
 *
 */
 */
 
 
#include <linux/config.h>
#include <linux/config.h>
 
 
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs.h>
#include <asm/segment.h>
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include <linux/locks.h>
#include "ncplib_kernel.h"
#include "ncplib_kernel.h"
 
 
struct ncp_dirent {
struct ncp_dirent {
        struct nw_info_struct i;
        struct nw_info_struct i;
        struct nw_search_sequence s; /* given back for i */
        struct nw_search_sequence s; /* given back for i */
        unsigned long f_pos;
        unsigned long f_pos;
};
};
 
 
static int
static int
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
 
 
static int
static int
ncp_readdir(struct inode *inode, struct file *filp,
ncp_readdir(struct inode *inode, struct file *filp,
            void *dirent, filldir_t filldir);
            void *dirent, filldir_t filldir);
 
 
static int
static int
ncp_read_volume_list(struct ncp_server *server, int start_with,
ncp_read_volume_list(struct ncp_server *server, int start_with,
                     int cache_size);
                     int cache_size);
 
 
static int
static int
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
               int cache_size, struct ncp_dirent *entry);
               int cache_size, struct ncp_dirent *entry);
 
 
static struct inode *
static struct inode *
ncp_iget(struct inode *dir, struct nw_file_info *finfo);
ncp_iget(struct inode *dir, struct nw_file_info *finfo);
 
 
static struct ncp_inode_info *
static struct ncp_inode_info *
ncp_find_dir_inode(struct inode *dir, const char *name);
ncp_find_dir_inode(struct inode *dir, const char *name);
 
 
static int
static int
ncp_lookup(struct inode *dir, const char *__name,
ncp_lookup(struct inode *dir, const char *__name,
           int len, struct inode **result);
           int len, struct inode **result);
 
 
static int
static int
ncp_create(struct inode *dir, const char *name, int len, int mode,
ncp_create(struct inode *dir, const char *name, int len, int mode,
           struct inode **result);
           struct inode **result);
 
 
static int
static int
ncp_mkdir(struct inode *dir, const char *name, int len, int mode);
ncp_mkdir(struct inode *dir, const char *name, int len, int mode);
 
 
static int
static int
ncp_rmdir(struct inode *dir, const char *name, int len);
ncp_rmdir(struct inode *dir, const char *name, int len);
 
 
static int
static int
ncp_unlink(struct inode *dir, const char *name, int len);
ncp_unlink(struct inode *dir, const char *name, int len);
 
 
static int
static int
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
           struct inode *new_dir, const char *new_name, int new_len,
           struct inode *new_dir, const char *new_name, int new_len,
           int must_be_dir);
           int must_be_dir);
 
 
static inline void
static inline void
str_upper(char *name)
str_upper(char *name)
{
{
        while (*name)
        while (*name)
        {
        {
                if (*name >= 'a' && *name <= 'z')
                if (*name >= 'a' && *name <= 'z')
                {
                {
                        *name -= ('a' - 'A');
                        *name -= ('a' - 'A');
                }
                }
                name++;
                name++;
        }
        }
}
}
 
 
static inline void
static inline void
str_lower(char *name)
str_lower(char *name)
{
{
        while (*name)
        while (*name)
        {
        {
                if (*name >= 'A' && *name <= 'Z')
                if (*name >= 'A' && *name <= 'Z')
                {
                {
                        *name += ('a' - 'A');
                        *name += ('a' - 'A');
                }
                }
                name ++;
                name ++;
        }
        }
}
}
 
 
static inline int
static inline int
ncp_namespace(struct inode *i)
ncp_namespace(struct inode *i)
{
{
        struct ncp_server *server   = NCP_SERVER(i);
        struct ncp_server *server   = NCP_SERVER(i);
        struct nw_info_struct *info = NCP_ISTRUCT(i);
        struct nw_info_struct *info = NCP_ISTRUCT(i);
        return server->name_space[info->volNumber];
        return server->name_space[info->volNumber];
}
}
 
 
static inline int
static inline int
ncp_preserve_case(struct inode *i)
ncp_preserve_case(struct inode *i)
{
{
        return
        return
#ifdef CONFIG_NCPFS_OS2_NS
#ifdef CONFIG_NCPFS_OS2_NS
        (ncp_namespace(i) == NW_NS_OS2) ||
        (ncp_namespace(i) == NW_NS_OS2) ||
#endif  /* CONFIG_NCPFS_OS2_NS */
#endif  /* CONFIG_NCPFS_OS2_NS */
#ifdef CONFIG_NCPFS_NFS_NS
#ifdef CONFIG_NCPFS_NFS_NS
        (ncp_namespace(i) == NW_NS_NFS) ||
        (ncp_namespace(i) == NW_NS_NFS) ||
#endif  /* CONFIG_NCPFS_NFS_NS */
#endif  /* CONFIG_NCPFS_NFS_NS */
        0;
        0;
}
}
 
 
static struct file_operations ncp_dir_operations = {
static struct file_operations ncp_dir_operations = {
        NULL,                   /* lseek - default */
        NULL,                   /* lseek - default */
        ncp_dir_read,           /* read - bad */
        ncp_dir_read,           /* read - bad */
        NULL,                   /* write - bad */
        NULL,                   /* write - bad */
        ncp_readdir,            /* readdir */
        ncp_readdir,            /* readdir */
        NULL,                   /* select - default */
        NULL,                   /* select - default */
        ncp_ioctl,              /* ioctl */
        ncp_ioctl,              /* ioctl */
        NULL,                   /* mmap */
        NULL,                   /* mmap */
        NULL,                   /* no special open code */
        NULL,                   /* no special open code */
        NULL,                   /* no special release code */
        NULL,                   /* no special release code */
        NULL                    /* fsync */
        NULL                    /* fsync */
};
};
 
 
struct inode_operations ncp_dir_inode_operations = {
struct inode_operations ncp_dir_inode_operations = {
        &ncp_dir_operations,    /* default directory file ops */
        &ncp_dir_operations,    /* default directory file ops */
        ncp_create,             /* create */
        ncp_create,             /* create */
        ncp_lookup,             /* lookup */
        ncp_lookup,             /* lookup */
        NULL,                   /* link */
        NULL,                   /* link */
        ncp_unlink,             /* unlink */
        ncp_unlink,             /* unlink */
        NULL,                   /* symlink */
        NULL,                   /* symlink */
        ncp_mkdir,              /* mkdir */
        ncp_mkdir,              /* mkdir */
        ncp_rmdir,              /* rmdir */
        ncp_rmdir,              /* rmdir */
        NULL,                   /* mknod */
        NULL,                   /* mknod */
        ncp_rename,             /* rename */
        ncp_rename,             /* rename */
        NULL,                   /* readlink */
        NULL,                   /* readlink */
        NULL,                   /* follow_link */
        NULL,                   /* follow_link */
        NULL,                   /* bmap */
        NULL,                   /* bmap */
        NULL,                   /* truncate */
        NULL,                   /* truncate */
        NULL,                   /* permission */
        NULL,                   /* permission */
        NULL                    /* smap */
        NULL                    /* smap */
};
};
 
 
 
 
/* Here we encapsulate the inode number handling that depends upon the
/* Here we encapsulate the inode number handling that depends upon the
 * mount mode: When we mount a complete server, the memory address of
 * mount mode: When we mount a complete server, the memory address of
 * the ncp_inode_info is used as the inode number. When only a single
 * the ncp_inode_info is used as the inode number. When only a single
 * volume is mounted, then the dirEntNum is used as the inode
 * volume is mounted, then the dirEntNum is used as the inode
 * number. As this is unique for the complete volume, this should
 * number. As this is unique for the complete volume, this should
 * enable the NFS exportability of a ncpfs-mounted volume.
 * enable the NFS exportability of a ncpfs-mounted volume.
 */
 */
 
 
static inline int
static inline int
ncp_single_volume(struct ncp_server *server)
ncp_single_volume(struct ncp_server *server)
{
{
        return (server->m.mounted_vol[0] != '\0');
        return (server->m.mounted_vol[0] != '\0');
}
}
 
 
inline ino_t
inline ino_t
ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
{
{
        return ncp_single_volume(server)
        return ncp_single_volume(server)
                ? (info->finfo.i.dirEntNum == server->root.finfo.i.dirEntNum)?0:info->finfo.i.dirEntNum: (ino_t)info;
                ? (info->finfo.i.dirEntNum == server->root.finfo.i.dirEntNum)?0:info->finfo.i.dirEntNum: (ino_t)info;
}
}
 
 
static inline int
static inline int
ncp_is_server_root(struct inode *inode)
ncp_is_server_root(struct inode *inode)
{
{
        struct ncp_server *s = NCP_SERVER(inode);
        struct ncp_server *s = NCP_SERVER(inode);
 
 
        return (   (!ncp_single_volume(s))
        return (   (!ncp_single_volume(s))
                && (inode->i_ino == ncp_info_ino(s, &(s->root))));
                && (inode->i_ino == ncp_info_ino(s, &(s->root))));
}
}
 
 
struct ncp_inode_info *
struct ncp_inode_info *
ncp_find_inode(struct inode *inode)
ncp_find_inode(struct inode *inode)
{
{
        struct ncp_server *server = NCP_SERVER(inode);
        struct ncp_server *server = NCP_SERVER(inode);
        struct ncp_inode_info *root = &(server->root);
        struct ncp_inode_info *root = &(server->root);
        struct ncp_inode_info *this = root;
        struct ncp_inode_info *this = root;
 
 
        ino_t ino = inode->i_ino;
        ino_t ino = inode->i_ino;
 
 
        do
        do
        {
        {
                if (ino == ncp_info_ino(server, this))
                if (ino == ncp_info_ino(server, this))
                {
                {
                        return this;
                        return this;
                }
                }
                this = this->next;
                this = this->next;
        }
        }
        while (this != root);
        while (this != root);
 
 
        return NULL;
        return NULL;
}
}
 
 
static int
static int
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
{
{
        return -EISDIR;
        return -EISDIR;
}
}
 
 
static kdev_t             c_dev = 0;
static kdev_t             c_dev = 0;
static unsigned long      c_ino = 0;
static unsigned long      c_ino = 0;
static int                c_size;
static int                c_size;
static int                c_seen_eof;
static int                c_seen_eof;
static int                c_last_returned_index;
static int                c_last_returned_index;
static struct ncp_dirent* c_entry = NULL;
static struct ncp_dirent* c_entry = NULL;
static int                c_lock = 0;
static int                c_lock = 0;
static struct wait_queue *c_wait = NULL;
static struct wait_queue *c_wait = NULL;
 
 
static inline void
static inline void
ncp_lock_dircache(void)
ncp_lock_dircache(void)
{
{
        while (c_lock)
        while (c_lock)
                sleep_on(&c_wait);
                sleep_on(&c_wait);
        c_lock = 1;
        c_lock = 1;
}
}
 
 
static inline void
static inline void
ncp_unlock_dircache(void)
ncp_unlock_dircache(void)
{
{
        c_lock = 0;
        c_lock = 0;
        wake_up(&c_wait);
        wake_up(&c_wait);
}
}
 
 
static int
static int
ncp_readdir(struct inode *inode, struct file *filp,
ncp_readdir(struct inode *inode, struct file *filp,
            void *dirent, filldir_t filldir)
            void *dirent, filldir_t filldir)
{
{
        int result = 0;
        int result = 0;
        int i = 0;
        int i = 0;
        int index = 0;
        int index = 0;
        struct ncp_dirent *entry = NULL;
        struct ncp_dirent *entry = NULL;
        struct ncp_server *server = NCP_SERVER(inode);
        struct ncp_server *server = NCP_SERVER(inode);
        struct ncp_inode_info *dir = NCP_INOP(inode);
        struct ncp_inode_info *dir = NCP_INOP(inode);
 
 
        DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
        DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
        DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
        DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
                 inode->i_ino, c_ino);
                 inode->i_ino, c_ino);
 
 
        if (!inode || !S_ISDIR(inode->i_mode))
        if (!inode || !S_ISDIR(inode->i_mode))
        {
        {
                printk("ncp_readdir: inode is NULL or not a directory\n");
                printk("ncp_readdir: inode is NULL or not a directory\n");
                return -EBADF;
                return -EBADF;
        }
        }
 
 
        if (!ncp_conn_valid(server))
        if (!ncp_conn_valid(server))
        {
        {
                return -EIO;
                return -EIO;
        }
        }
 
 
        ncp_lock_dircache();
        ncp_lock_dircache();
 
 
        if (c_entry == NULL)
        if (c_entry == NULL)
        {
        {
                i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
                i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
                c_entry = (struct ncp_dirent *) vmalloc(i);
                c_entry = (struct ncp_dirent *) vmalloc(i);
                if (c_entry == NULL)
                if (c_entry == NULL)
                {
                {
                        printk("ncp_readdir: no MEMORY for cache\n");
                        printk("ncp_readdir: no MEMORY for cache\n");
                        result = -ENOMEM;
                        result = -ENOMEM;
                        goto finished;
                        goto finished;
                }
                }
        }
        }
 
 
        if (filp->f_pos == 0)
        if (filp->f_pos == 0)
        {
        {
                ncp_invalid_dir_cache(inode);
                ncp_invalid_dir_cache(inode);
                if (filldir(dirent,".",1, filp->f_pos,
                if (filldir(dirent,".",1, filp->f_pos,
                            ncp_info_ino(server, dir)) < 0)
                            ncp_info_ino(server, dir)) < 0)
                {
                {
                        goto finished;
                        goto finished;
                }
                }
                filp->f_pos += 1;
                filp->f_pos += 1;
        }
        }
 
 
        if (filp->f_pos == 1)
        if (filp->f_pos == 1)
        {
        {
                if (filldir(dirent,"..",2, filp->f_pos,
                if (filldir(dirent,"..",2, filp->f_pos,
                            ncp_info_ino(server, dir->dir)) < 0)
                            ncp_info_ino(server, dir->dir)) < 0)
                {
                {
                        goto finished;
                        goto finished;
                }
                }
                filp->f_pos += 1;
                filp->f_pos += 1;
        }
        }
 
 
        if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
        if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
        {
        {
                for (i = 0; i < c_size; i++)
                for (i = 0; i < c_size; i++)
                {
                {
                        if (filp->f_pos == c_entry[i].f_pos)
                        if (filp->f_pos == c_entry[i].f_pos)
                        {
                        {
                                entry = &c_entry[i];
                                entry = &c_entry[i];
                                c_last_returned_index = i;
                                c_last_returned_index = i;
                                index = i;
                                index = i;
                                break;
                                break;
                        }
                        }
                }
                }
                if ((entry == NULL) && c_seen_eof)
                if ((entry == NULL) && c_seen_eof)
                {
                {
                        goto finished;
                        goto finished;
                }
                }
        }
        }
 
 
        if (entry == NULL)
        if (entry == NULL)
        {
        {
                int entries;
                int entries;
                DDPRINTK("ncp_readdir: Not found in cache.\n");
                DDPRINTK("ncp_readdir: Not found in cache.\n");
 
 
                if (ncp_is_server_root(inode))
                if (ncp_is_server_root(inode))
                {
                {
                        entries = ncp_read_volume_list(server, filp->f_pos,
                        entries = ncp_read_volume_list(server, filp->f_pos,
                                                       NCP_READDIR_CACHE_SIZE);
                                                       NCP_READDIR_CACHE_SIZE);
                        DPRINTK("ncp_read_volume_list returned %d\n", entries);
                        DPRINTK("ncp_read_volume_list returned %d\n", entries);
 
 
                }
                }
                else
                else
                {
                {
                        entries = ncp_do_readdir(server, inode, filp->f_pos,
                        entries = ncp_do_readdir(server, inode, filp->f_pos,
                                                 NCP_READDIR_CACHE_SIZE,
                                                 NCP_READDIR_CACHE_SIZE,
                                                 c_entry);
                                                 c_entry);
                        DPRINTK("ncp_readdir returned %d\n", entries);
                        DPRINTK("ncp_readdir returned %d\n", entries);
                }
                }
 
 
                if (entries < 0)
                if (entries < 0)
                {
                {
                        c_dev = 0;
                        c_dev = 0;
                        c_ino = 0;
                        c_ino = 0;
                        result = entries;
                        result = entries;
                        goto finished;
                        goto finished;
                }
                }
 
 
                if (entries > 0)
                if (entries > 0)
                {
                {
                        c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
                        c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
                        c_dev  = inode->i_dev;
                        c_dev  = inode->i_dev;
                        c_ino  = inode->i_ino;
                        c_ino  = inode->i_ino;
                        c_size = entries;
                        c_size = entries;
                        entry = c_entry;
                        entry = c_entry;
                        c_last_returned_index = 0;
                        c_last_returned_index = 0;
                        index = 0;
                        index = 0;
 
 
                        if (!ncp_preserve_case(inode))
                        if (!ncp_preserve_case(inode))
                        {
                        {
                                for (i = 0; i < c_size; i++)
                                for (i = 0; i < c_size; i++)
                                {
                                {
                                        str_lower(c_entry[i].i.entryName);
                                        str_lower(c_entry[i].i.entryName);
                                }
                                }
                        }
                        }
                }
                }
        }
        }
 
 
        if (entry == NULL)
        if (entry == NULL)
        {
        {
                /* Nothing found, even from a ncp call */
                /* Nothing found, even from a ncp call */
                goto finished;
                goto finished;
        }
        }
 
 
        while (index < c_size)
        while (index < c_size)
        {
        {
                ino_t ino;
                ino_t ino;
 
 
                if (ncp_single_volume(server))
                if (ncp_single_volume(server))
                {
                {
                        ino = (ino_t)(entry->i.dirEntNum);
                        ino = (ino_t)(entry->i.dirEntNum);
                }
                }
                else
                else
                {
                {
                        /* For getwd() we have to return the correct
                        /* For getwd() we have to return the correct
                         * inode in d_ino if the inode is currently in
                         * inode in d_ino if the inode is currently in
                         * use. Otherwise the inode number does not
                         * use. Otherwise the inode number does not
                         * matter. (You can argue a lot about this..) */
                         * matter. (You can argue a lot about this..) */
                        struct ncp_inode_info *ino_info;
                        struct ncp_inode_info *ino_info;
                        ino_info = ncp_find_dir_inode(inode,
                        ino_info = ncp_find_dir_inode(inode,
                                                      entry->i.entryName);
                                                      entry->i.entryName);
 
 
                        /* Some programs seem to be confused about a
                        /* Some programs seem to be confused about a
                         * zero inode number, so we set it to one.
                         * zero inode number, so we set it to one.
                         * Thanks to Gordon Chaffee for this one. */
                         * Thanks to Gordon Chaffee for this one. */
                        if (ino_info == NULL)
                        if (ino_info == NULL)
                        {
                        {
                                ino_info = (struct ncp_inode_info *) 1;
                                ino_info = (struct ncp_inode_info *) 1;
                        }
                        }
                        ino = (ino_t)(ino_info);
                        ino = (ino_t)(ino_info);
                }
                }
 
 
                DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
                DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
                DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
                DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
 
 
                if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
                if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
                            entry->f_pos, ino) < 0)
                            entry->f_pos, ino) < 0)
                {
                {
                        break;
                        break;
                }
                }
 
 
                if (   (inode->i_dev != c_dev)
                if (   (inode->i_dev != c_dev)
                    || (inode->i_ino != c_ino)
                    || (inode->i_ino != c_ino)
                    || (entry->f_pos != filp->f_pos))
                    || (entry->f_pos != filp->f_pos))
                {
                {
                        /* Someone has destroyed the cache while we slept
                        /* Someone has destroyed the cache while we slept
                           in filldir */
                           in filldir */
                        break;
                        break;
                }
                }
                filp->f_pos += 1;
                filp->f_pos += 1;
                index += 1;
                index += 1;
                entry += 1;
                entry += 1;
        }
        }
 finished:
 finished:
        ncp_unlock_dircache();
        ncp_unlock_dircache();
        return result;
        return result;
}
}
 
 
static int
static int
ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
{
{
        struct ncp_dirent *entry = c_entry;
        struct ncp_dirent *entry = c_entry;
 
 
        int total_count = 2;
        int total_count = 2;
        int i;
        int i;
 
 
#if 1
#if 1
        if (fpos < 2)
        if (fpos < 2)
        {
        {
                printk("OOPS, we expect fpos >= 2");
                printk("OOPS, we expect fpos >= 2");
                fpos = 2;
                fpos = 2;
        }
        }
#endif
#endif
 
 
        for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++)
        for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++)
        {
        {
                struct ncp_volume_info info;
                struct ncp_volume_info info;
 
 
                if (ncp_get_volume_info_with_number(server, i, &info) != 0)
                if (ncp_get_volume_info_with_number(server, i, &info) != 0)
                {
                {
                        return (total_count - fpos);
                        return (total_count - fpos);
                }
                }
 
 
                if (strlen(info.volume_name) > 0)
                if (strlen(info.volume_name) > 0)
                {
                {
                        if (total_count < fpos)
                        if (total_count < fpos)
                        {
                        {
                                DPRINTK("ncp_read_volumes: skipped vol: %s\n",
                                DPRINTK("ncp_read_volumes: skipped vol: %s\n",
                                        info.volume_name);
                                        info.volume_name);
                        }
                        }
                        else if (total_count >= fpos + cache_size)
                        else if (total_count >= fpos + cache_size)
                        {
                        {
                                return (total_count - fpos);
                                return (total_count - fpos);
                        }
                        }
                        else
                        else
                        {
                        {
                                DPRINTK("ncp_read_volumes: found vol: %s\n",
                                DPRINTK("ncp_read_volumes: found vol: %s\n",
                                        info.volume_name);
                                        info.volume_name);
 
 
                                if (ncp_lookup_volume(server,
                                if (ncp_lookup_volume(server,
                                                      info.volume_name,
                                                      info.volume_name,
                                                      &(entry->i)) != 0)
                                                      &(entry->i)) != 0)
                                {
                                {
                                        DPRINTK("ncpfs: could not lookup vol "
                                        DPRINTK("ncpfs: could not lookup vol "
                                                "%s\n", info.volume_name);
                                                "%s\n", info.volume_name);
                                        continue;
                                        continue;
                                }
                                }
 
 
                                entry->f_pos = total_count;
                                entry->f_pos = total_count;
                                entry += 1;
                                entry += 1;
                        }
                        }
                        total_count += 1;
                        total_count += 1;
                }
                }
        }
        }
        return (total_count - fpos);
        return (total_count - fpos);
}
}
 
 
static int
static int
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
               int cache_size, struct ncp_dirent *entry)
               int cache_size, struct ncp_dirent *entry)
{
{
        static struct nw_search_sequence seq;
        static struct nw_search_sequence seq;
        static struct inode *last_dir;
        static struct inode *last_dir;
        static int total_count;
        static int total_count;
 
 
#if 1
#if 1
        if (fpos < 2)
        if (fpos < 2)
        {
        {
                printk("OOPS, we expect fpos >= 2");
                printk("OOPS, we expect fpos >= 2");
                fpos = 2;
                fpos = 2;
        }
        }
#endif
#endif
        DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);
        DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);
 
 
        if (fpos == 2)
        if (fpos == 2)
        {
        {
                last_dir = NULL;
                last_dir = NULL;
                total_count = 2;
                total_count = 2;
        }
        }
 
 
        if ((fpos != total_count) || (dir != last_dir))
        if ((fpos != total_count) || (dir != last_dir))
        {
        {
                total_count = 2;
                total_count = 2;
                last_dir = dir;
                last_dir = dir;
 
 
                DPRINTK("ncp_do_readdir: re-used seq for %s\n",
                DPRINTK("ncp_do_readdir: re-used seq for %s\n",
                        NCP_ISTRUCT(dir)->entryName);
                        NCP_ISTRUCT(dir)->entryName);
 
 
                if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0)
                if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0)
                {
                {
                        DPRINTK("ncp_init_search failed\n");
                        DPRINTK("ncp_init_search failed\n");
                        return total_count - fpos;
                        return total_count - fpos;
                }
                }
        }
        }
 
 
        while (total_count < fpos + cache_size)
        while (total_count < fpos + cache_size)
        {
        {
                if (ncp_search_for_file_or_subdir(server, &seq,
                if (ncp_search_for_file_or_subdir(server, &seq,
                                                  &(entry->i)) != 0)
                                                  &(entry->i)) != 0)
                {
                {
                        return total_count - fpos;
                        return total_count - fpos;
                }
                }
 
 
                if (total_count < fpos)
                if (total_count < fpos)
                {
                {
                        DPRINTK("ncp_do_readdir: skipped file: %s\n",
                        DPRINTK("ncp_do_readdir: skipped file: %s\n",
                                entry->i.entryName);
                                entry->i.entryName);
                }
                }
                else
                else
                {
                {
                        DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",
                        DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",
                                 entry->i.entryName, fpos, total_count);
                                 entry->i.entryName, fpos, total_count);
                        entry->s = seq;
                        entry->s = seq;
                        entry->f_pos = total_count;
                        entry->f_pos = total_count;
                        entry += 1;
                        entry += 1;
                }
                }
                total_count += 1;
                total_count += 1;
        }
        }
        return (total_count - fpos);
        return (total_count - fpos);
}
}
 
 
void
void
ncp_init_dir_cache(void)
ncp_init_dir_cache(void)
{
{
        c_dev   = 0;
        c_dev   = 0;
        c_ino   = 0;
        c_ino   = 0;
        c_entry = NULL;
        c_entry = NULL;
}
}
 
 
void
void
ncp_invalid_dir_cache(struct inode *ino)
ncp_invalid_dir_cache(struct inode *ino)
{
{
        if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino))
        if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino))
        {
        {
                c_dev = 0;
                c_dev = 0;
                c_ino = 0;
                c_ino = 0;
                c_seen_eof = 0;
                c_seen_eof = 0;
        }
        }
}
}
 
 
void
void
ncp_free_dir_cache(void)
ncp_free_dir_cache(void)
{
{
        DPRINTK("ncp_free_dir_cache: enter\n");
        DPRINTK("ncp_free_dir_cache: enter\n");
 
 
        if (c_entry == NULL)
        if (c_entry == NULL)
        {
        {
                return;
                return;
        }
        }
 
 
        vfree(c_entry);
        vfree(c_entry);
        c_entry = NULL;
        c_entry = NULL;
 
 
        DPRINTK("ncp_free_dir_cache: exit\n");
        DPRINTK("ncp_free_dir_cache: exit\n");
}
}
 
 
 
 
static struct inode *
static struct inode *
ncp_iget(struct inode *dir, struct nw_file_info *finfo)
ncp_iget(struct inode *dir, struct nw_file_info *finfo)
{
{
        struct inode *inode;
        struct inode *inode;
        struct ncp_inode_info *new_inode_info;
        struct ncp_inode_info *new_inode_info;
        struct ncp_inode_info *root;
        struct ncp_inode_info *root;
 
 
        if (dir == NULL)
        if (dir == NULL)
        {
        {
                printk("ncp_iget: dir is NULL\n");
                printk("ncp_iget: dir is NULL\n");
                return NULL;
                return NULL;
        }
        }
 
 
        if (finfo == NULL)
        if (finfo == NULL)
        {
        {
                printk("ncp_iget: finfo is NULL\n");
                printk("ncp_iget: finfo is NULL\n");
                return NULL;
                return NULL;
        }
        }
 
 
        new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),
        new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),
                                     GFP_KERNEL);
                                     GFP_KERNEL);
 
 
        if (new_inode_info == NULL)
        if (new_inode_info == NULL)
        {
        {
                printk("ncp_iget: could not alloc mem for %s\n",
                printk("ncp_iget: could not alloc mem for %s\n",
                       finfo->i.entryName);
                       finfo->i.entryName);
                return NULL;
                return NULL;
        }
        }
 
 
        new_inode_info->state = NCP_INODE_LOOKED_UP;
        new_inode_info->state = NCP_INODE_LOOKED_UP;
        new_inode_info->nused = 0;
        new_inode_info->nused = 0;
        new_inode_info->dir   = NCP_INOP(dir);
        new_inode_info->dir   = NCP_INOP(dir);
        new_inode_info->finfo = *finfo;
        new_inode_info->finfo = *finfo;
 
 
        NCP_INOP(dir)->nused += 1;
        NCP_INOP(dir)->nused += 1;
 
 
        /* We have to link the new inode_info into the doubly linked
        /* We have to link the new inode_info into the doubly linked
           list of inode_infos to make a complete linear search
           list of inode_infos to make a complete linear search
           possible. */
           possible. */
 
 
        root = &(NCP_SERVER(dir)->root);
        root = &(NCP_SERVER(dir)->root);
 
 
        new_inode_info->prev = root;
        new_inode_info->prev = root;
        new_inode_info->next = root->next;
        new_inode_info->next = root->next;
        root->next->prev = new_inode_info;
        root->next->prev = new_inode_info;
        root->next = new_inode_info;
        root->next = new_inode_info;
 
 
        if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
        if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
                                                   new_inode_info))))
                                                   new_inode_info))))
        {
        {
                printk("ncp_iget: iget failed!");
                printk("ncp_iget: iget failed!");
                return NULL;
                return NULL;
        }
        }
 
 
        return inode;
        return inode;
}
}
 
 
void
void
ncp_free_inode_info(struct ncp_inode_info *i)
ncp_free_inode_info(struct ncp_inode_info *i)
{
{
        if (i == NULL)
        if (i == NULL)
        {
        {
                printk("ncp_free_inode: i == NULL\n");
                printk("ncp_free_inode: i == NULL\n");
                return;
                return;
        }
        }
 
 
        i->state = NCP_INODE_CACHED;
        i->state = NCP_INODE_CACHED;
        while ((i->nused == 0) && (i->state == NCP_INODE_CACHED))
        while ((i->nused == 0) && (i->state == NCP_INODE_CACHED))
        {
        {
                struct ncp_inode_info *dir = i->dir;
                struct ncp_inode_info *dir = i->dir;
 
 
                i->next->prev = i->prev;
                i->next->prev = i->prev;
                i->prev->next = i->next;
                i->prev->next = i->next;
 
 
                DDPRINTK("ncp_free_inode_info: freeing %s\n",
                DDPRINTK("ncp_free_inode_info: freeing %s\n",
                         i->finfo.i.entryName);
                         i->finfo.i.entryName);
 
 
                ncp_kfree_s(i, sizeof(struct ncp_inode_info));
                ncp_kfree_s(i, sizeof(struct ncp_inode_info));
 
 
                if (dir == i) return;
                if (dir == i) return;
 
 
                (dir->nused)--;
                (dir->nused)--;
                i = dir;
                i = dir;
        }
        }
}
}
 
 
void
void
ncp_init_root(struct ncp_server *server)
ncp_init_root(struct ncp_server *server)
{
{
        struct ncp_inode_info *root = &(server->root);
        struct ncp_inode_info *root = &(server->root);
        struct nw_info_struct *i = &(root->finfo.i);
        struct nw_info_struct *i = &(root->finfo.i);
        unsigned short dummy;
        unsigned short dummy;
 
 
        DPRINTK("ncp_init_root: server %s\n", server->m.server_name);
        DPRINTK("ncp_init_root: server %s\n", server->m.server_name);
        DPRINTK("ncp_init_root: i = %x\n", (int)i);
        DPRINTK("ncp_init_root: i = %x\n", (int)i);
 
 
        root->finfo.opened = 0;
        root->finfo.opened = 0;
        i->attributes  = aDIR;
        i->attributes  = aDIR;
        i->dataStreamSize = 1024;
        i->dataStreamSize = 1024;
        i->dirEntNum = i->DosDirNum = 0;
        i->dirEntNum = i->DosDirNum = 0;
        i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
        i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
        ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
        ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
        ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
        ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
        ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
        ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
        i->nameLen = 0;
        i->nameLen = 0;
        i->entryName[0] = '\0';
        i->entryName[0] = '\0';
 
 
        root->state = NCP_INODE_LOOKED_UP;
        root->state = NCP_INODE_LOOKED_UP;
        root->nused = 1;
        root->nused = 1;
        root->dir   = root;
        root->dir   = root;
        root->next = root->prev = root;
        root->next = root->prev = root;
        return;
        return;
}
}
 
 
int
int
ncp_conn_logged_in(struct ncp_server *server)
ncp_conn_logged_in(struct ncp_server *server)
{
{
        if (server->m.mounted_vol[0] == '\0')
        if (server->m.mounted_vol[0] == '\0')
        {
        {
                return 0;
                return 0;
        }
        }
 
 
        str_upper(server->m.mounted_vol);
        str_upper(server->m.mounted_vol);
        if (ncp_lookup_volume(server, server->m.mounted_vol,
        if (ncp_lookup_volume(server, server->m.mounted_vol,
                              &(server->root.finfo.i)) != 0)
                              &(server->root.finfo.i)) != 0)
        {
        {
                return -ENOENT;
                return -ENOENT;
        }
        }
        str_lower(server->root.finfo.i.entryName);
        str_lower(server->root.finfo.i.entryName);
 
 
        return 0;
        return 0;
}
}
 
 
void
void
ncp_free_all_inodes(struct ncp_server *server)
ncp_free_all_inodes(struct ncp_server *server)
{
{
        /* Here nothing should be to do. I do not know whether it's
        /* Here nothing should be to do. I do not know whether it's
           better to leave some memory allocated or be stuck in an
           better to leave some memory allocated or be stuck in an
           endless loop */
           endless loop */
#if 1
#if 1
        struct ncp_inode_info *root = &(server->root);
        struct ncp_inode_info *root = &(server->root);
 
 
        if (root->next != root)
        if (root->next != root)
        {
        {
                printk("ncp_free_all_inodes: INODES LEFT!!!\n");
                printk("ncp_free_all_inodes: INODES LEFT!!!\n");
        }
        }
 
 
        while (root->next != root)
        while (root->next != root)
        {
        {
                printk("ncp_free_all_inodes: freeing inode\n");
                printk("ncp_free_all_inodes: freeing inode\n");
                ncp_free_inode_info(root->next);
                ncp_free_inode_info(root->next);
                /* In case we have an endless loop.. */
                /* In case we have an endless loop.. */
                schedule();
                schedule();
        }
        }
#endif        
#endif        
 
 
        return;
        return;
}
}
 
 
/* We will search the inode that belongs to this name, currently by a
/* We will search the inode that belongs to this name, currently by a
   complete linear search through the inodes belonging to this
   complete linear search through the inodes belonging to this
   filesystem. This has to be fixed. */
   filesystem. This has to be fixed. */
static struct ncp_inode_info *
static struct ncp_inode_info *
ncp_find_dir_inode(struct inode *dir, const char *name)
ncp_find_dir_inode(struct inode *dir, const char *name)
{
{
        struct ncp_server *server = NCP_SERVER(dir);
        struct ncp_server *server = NCP_SERVER(dir);
        struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
        struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
        struct ncp_inode_info *result = &(server->root);
        struct ncp_inode_info *result = &(server->root);
 
 
        if (name == NULL)
        if (name == NULL)
        {
        {
                return NULL;
                return NULL;
        }
        }
 
 
        do
        do
        {
        {
                if (   (result->dir->finfo.i.dirEntNum == dir_info->dirEntNum)
                if (   (result->dir->finfo.i.dirEntNum == dir_info->dirEntNum)
                    && (result->dir->finfo.i.volNumber == dir_info->volNumber)
                    && (result->dir->finfo.i.volNumber == dir_info->volNumber)
                    && (strcmp(result->finfo.i.entryName, name) == 0)
                    && (strcmp(result->finfo.i.entryName, name) == 0)
                    /* The root dir is never looked up using this
                    /* The root dir is never looked up using this
                     * routine.  Without the following test a root
                     * routine.  Without the following test a root
                     * directory 'sys' in a volume named 'sys' could
                     * directory 'sys' in a volume named 'sys' could
                     * never be looked up, because
                     * never be looked up, because
                     * server->root->dir==server->root. */
                     * server->root->dir==server->root. */
                    && (result != &(server->root)))
                    && (result != &(server->root)))
                {
                {
                        return result;
                        return result;
                }
                }
                result = result->next;
                result = result->next;
 
 
        }
        }
        while (result != &(server->root));
        while (result != &(server->root));
 
 
        return NULL;
        return NULL;
}
}
 
 
static int
static int
ncp_lookup(struct inode *dir, const char *__name, int len,
ncp_lookup(struct inode *dir, const char *__name, int len,
           struct inode **result)
           struct inode **result)
{
{
        struct nw_file_info finfo;
        struct nw_file_info finfo;
        struct ncp_server *server;
        struct ncp_server *server;
        struct ncp_inode_info *result_info;
        struct ncp_inode_info *result_info;
        int found_in_cache;
        int found_in_cache;
        int down_case = 0;
        int down_case = 0;
        char name[len+1];
        char name[len+1];
 
 
        *result = NULL;
        *result = NULL;
 
 
        if (!dir || !S_ISDIR(dir->i_mode))
        if (!dir || !S_ISDIR(dir->i_mode))
        {
        {
                printk("ncp_lookup: inode is NULL or not a directory.\n");
                printk("ncp_lookup: inode is NULL or not a directory.\n");
                iput(dir);
                iput(dir);
                return -ENOENT;
                return -ENOENT;
        }
        }
 
 
        server = NCP_SERVER(dir);
        server = NCP_SERVER(dir);
 
 
        if (!ncp_conn_valid(server))
        if (!ncp_conn_valid(server))
        {
        {
                iput(dir);
                iput(dir);
                return -EIO;
                return -EIO;
        }
        }
 
 
        DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
        DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
 
 
        /* Fast cheat for . */
        /* Fast cheat for . */
        if (len == 0 || (len == 1 && __name[0] == '.'))
        if (len == 0 || (len == 1 && __name[0] == '.'))
        {
        {
                *result = dir;
                *result = dir;
                return 0;
                return 0;
        }
        }
 
 
        /* ..and for .. */
        /* ..and for .. */
        if (len == 2 && __name[0] == '.' && __name[1] == '.')
        if (len == 2 && __name[0] == '.' && __name[1] == '.')
        {
        {
                struct ncp_inode_info *parent = NCP_INOP(dir)->dir;
                struct ncp_inode_info *parent = NCP_INOP(dir)->dir;
 
 
                if (parent->state == NCP_INODE_CACHED)
                if (parent->state == NCP_INODE_CACHED)
                {
                {
                        parent->state = NCP_INODE_LOOKED_UP;
                        parent->state = NCP_INODE_LOOKED_UP;
                }
                }
 
 
                *result = iget(dir->i_sb, ncp_info_ino(server, parent));
                *result = iget(dir->i_sb, ncp_info_ino(server, parent));
                iput(dir);
                iput(dir);
                if (*result == 0)
                if (*result == 0)
                {
                {
                        return -EACCES;
                        return -EACCES;
                }
                }
                else
                else
                {
                {
                        return 0;
                        return 0;
                }
                }
        }
        }
 
 
        memcpy(name, __name, len);
        memcpy(name, __name, len);
        name[len] = 0;
        name[len] = 0;
        lock_super(dir->i_sb);
        lock_super(dir->i_sb);
        result_info = ncp_find_dir_inode(dir, name);
        result_info = ncp_find_dir_inode(dir, name);
 
 
        if (result_info != 0)
        if (result_info != 0)
        {
        {
                if (result_info->state == NCP_INODE_CACHED)
                if (result_info->state == NCP_INODE_CACHED)
                {
                {
                        result_info->state = NCP_INODE_LOOKED_UP;
                        result_info->state = NCP_INODE_LOOKED_UP;
                }
                }
 
 
                /* Here we convert the inode_info address into an
                /* Here we convert the inode_info address into an
                   inode number */
                   inode number */
 
 
                *result = iget(dir->i_sb, ncp_info_ino(server, result_info));
                *result = iget(dir->i_sb, ncp_info_ino(server, result_info));
                unlock_super(dir->i_sb);
                unlock_super(dir->i_sb);
                iput(dir);
                iput(dir);
 
 
                if (*result == NULL)
                if (*result == NULL)
                {
                {
                        return -EACCES;
                        return -EACCES;
                }
                }
 
 
                return 0;
                return 0;
        }
        }
 
 
        /* If the file is in the dir cache, we do not have to ask the
        /* If the file is in the dir cache, we do not have to ask the
           server. */
           server. */
 
 
        found_in_cache = 0;
        found_in_cache = 0;
        ncp_lock_dircache();
        ncp_lock_dircache();
 
 
        if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
        if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
        {
        {
                int first = c_last_returned_index;
                int first = c_last_returned_index;
                int i;
                int i;
 
 
                i = first;
                i = first;
                do
                do
                {
                {
                        DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
                        DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
                                 i, c_entry[i].i.entryName);
                                 i, c_entry[i].i.entryName);
 
 
                        if (strcmp(c_entry[i].i.entryName, name) == 0)
                        if (strcmp(c_entry[i].i.entryName, name) == 0)
                        {
                        {
                                DPRINTK("ncp_lookup: found in cache!\n");
                                DPRINTK("ncp_lookup: found in cache!\n");
                                finfo.i = c_entry[i].i;
                                finfo.i = c_entry[i].i;
                                found_in_cache = 1;
                                found_in_cache = 1;
                                break;
                                break;
                        }
                        }
                        i = (i + 1) % c_size;
                        i = (i + 1) % c_size;
                }
                }
                while (i != first);
                while (i != first);
        }
        }
        ncp_unlock_dircache();
        ncp_unlock_dircache();
 
 
        if (found_in_cache == 0)
        if (found_in_cache == 0)
        {
        {
                int res;
                int res;
 
 
                DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
                DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
                         NCP_ISTRUCT(dir)->entryName, name);
                         NCP_ISTRUCT(dir)->entryName, name);
 
 
                if (ncp_is_server_root(dir))
                if (ncp_is_server_root(dir))
                {
                {
                        str_upper(name);
                        str_upper(name);
                        down_case = 1;
                        down_case = 1;
                        res = ncp_lookup_volume(server, name, &(finfo.i));
                        res = ncp_lookup_volume(server, name, &(finfo.i));
                }
                }
                else
                else
                {
                {
                        if (!ncp_preserve_case(dir))
                        if (!ncp_preserve_case(dir))
                        {
                        {
                                str_upper(name);
                                str_upper(name);
                                down_case = 1;
                                down_case = 1;
                        }
                        }
                        res = ncp_obtain_info(server,
                        res = ncp_obtain_info(server,
                                              NCP_ISTRUCT(dir)->volNumber,
                                              NCP_ISTRUCT(dir)->volNumber,
                                              NCP_ISTRUCT(dir)->dirEntNum,
                                              NCP_ISTRUCT(dir)->dirEntNum,
                                              name, &(finfo.i));
                                              name, &(finfo.i));
                }
                }
                if (res != 0)
                if (res != 0)
                {
                {
                        unlock_super(dir->i_sb);
                        unlock_super(dir->i_sb);
                        iput(dir);
                        iput(dir);
                        return -ENOENT;
                        return -ENOENT;
                }
                }
        }
        }
 
 
        finfo.opened = 0;
        finfo.opened = 0;
 
 
        if (down_case != 0)
        if (down_case != 0)
        {
        {
                str_lower(finfo.i.entryName);
                str_lower(finfo.i.entryName);
        }
        }
 
 
        if (!(*result = ncp_iget(dir, &finfo)))
        if (!(*result = ncp_iget(dir, &finfo)))
        {
        {
                unlock_super(dir->i_sb);
                unlock_super(dir->i_sb);
                iput(dir);
                iput(dir);
                return -EACCES;
                return -EACCES;
        }
        }
 
 
        unlock_super(dir->i_sb);
        unlock_super(dir->i_sb);
        iput(dir);
        iput(dir);
        return 0;
        return 0;
}
}
 
 
static int
static int
ncp_create(struct inode *dir, const char *name, int len, int mode,
ncp_create(struct inode *dir, const char *name, int len, int mode,
           struct inode **result)
           struct inode **result)
{
{
        struct nw_file_info finfo;
        struct nw_file_info finfo;
        __u8 _name[len+1];
        __u8 _name[len+1];
        int error;
        int error;
 
 
        *result = NULL;
        *result = NULL;
 
 
        if (!dir || !S_ISDIR(dir->i_mode))
        if (!dir || !S_ISDIR(dir->i_mode))
        {
        {
                printk("ncp_create: inode is NULL or not a directory\n");
                printk("ncp_create: inode is NULL or not a directory\n");
                iput(dir);
                iput(dir);
                return -ENOENT;
                return -ENOENT;
        }
        }
        if (!ncp_conn_valid(NCP_SERVER(dir)))
        if (!ncp_conn_valid(NCP_SERVER(dir)))
        {
        {
                iput(dir);
                iput(dir);
                return -EIO;
                return -EIO;
        }
        }
 
 
        strncpy(_name, name, len);
        strncpy(_name, name, len);
        _name[len] = '\0';
        _name[len] = '\0';
 
 
        if (!ncp_preserve_case(dir))
        if (!ncp_preserve_case(dir))
        {
        {
                str_upper(_name);
                str_upper(_name);
        }
        }
 
 
        lock_super(dir->i_sb);
        lock_super(dir->i_sb);
        if ((error = ncp_open_create_file_or_subdir(NCP_SERVER(dir),
        if ((error = ncp_open_create_file_or_subdir(NCP_SERVER(dir),
                                           NCP_ISTRUCT(dir), _name,
                                           NCP_ISTRUCT(dir), _name,
                                           OC_MODE_CREATE|OC_MODE_OPEN|
                                           OC_MODE_CREATE|OC_MODE_OPEN|
                                           OC_MODE_REPLACE,
                                           OC_MODE_REPLACE,
                                           0, AR_READ|AR_WRITE,
                                           0, AR_READ|AR_WRITE,
                                           &finfo)) != 0)
                                           &finfo)) != 0)
        {
        {
                unlock_super(dir->i_sb);
                unlock_super(dir->i_sb);
                iput(dir);
                iput(dir);
                if (error == 0x87) {
                if (error == 0x87) {
                        return -ENAMETOOLONG;
                        return -ENAMETOOLONG;
                }
                }
                return -EACCES;
                return -EACCES;
        }
        }
 
 
        ncp_invalid_dir_cache(dir);
        ncp_invalid_dir_cache(dir);
 
 
        if (!ncp_preserve_case(dir))
        if (!ncp_preserve_case(dir))
        {
        {
                str_lower(finfo.i.entryName);
                str_lower(finfo.i.entryName);
        }
        }
 
 
        finfo.access = O_RDWR;
        finfo.access = O_RDWR;
 
 
        if (!(*result = ncp_iget(dir, &finfo)) < 0)
        if (!(*result = ncp_iget(dir, &finfo)) < 0)
        {
        {
                ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
                ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
                unlock_super(dir->i_sb);
                unlock_super(dir->i_sb);
                iput(dir);
                iput(dir);
                return -EINVAL;
                return -EINVAL;
        }
        }
 
 
        unlock_super(dir->i_sb);
        unlock_super(dir->i_sb);
        iput(dir);
        iput(dir);
        return 0;
        return 0;
}
}
 
 
static int
static int
ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
{
{
        int error;
        int error;
        struct nw_file_info new_dir;
        struct nw_file_info new_dir;
        __u8 _name[len+1];
        __u8 _name[len+1];
 
 
        if (   (name[0] == '.')
        if (   (name[0] == '.')
            && (   (len == 1)
            && (   (len == 1)
                || (   (len == 2)
                || (   (len == 2)
                    && (name[1] == '.'))))
                    && (name[1] == '.'))))
        {
        {
                iput(dir);
                iput(dir);
                return -EEXIST;
                return -EEXIST;
        }
        }
 
 
        strncpy(_name, name, len);
        strncpy(_name, name, len);
        _name[len] = '\0';
        _name[len] = '\0';
 
 
        if (!ncp_preserve_case(dir))
        if (!ncp_preserve_case(dir))
        {
        {
                str_upper(_name);
                str_upper(_name);
        }
        }
 
 
        if (!dir || !S_ISDIR(dir->i_mode))
        if (!dir || !S_ISDIR(dir->i_mode))
        {
        {
                printk("ncp_mkdir: inode is NULL or not a directory\n");
                printk("ncp_mkdir: inode is NULL or not a directory\n");
                iput(dir);
                iput(dir);
                return -ENOENT;
                return -ENOENT;
        }
        }
        if (!ncp_conn_valid(NCP_SERVER(dir)))
        if (!ncp_conn_valid(NCP_SERVER(dir)))
        {
        {
                iput(dir);
                iput(dir);
                return -EIO;
                return -EIO;
        }
        }
 
 
        if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
        if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
                                           NCP_ISTRUCT(dir), _name,
                                           NCP_ISTRUCT(dir), _name,
                                           OC_MODE_CREATE, aDIR, 0xffff,
                                           OC_MODE_CREATE, aDIR, 0xffff,
                                           &new_dir) != 0)
                                           &new_dir) != 0)
        {
        {
                error = -EACCES;
                error = -EACCES;
        }
        }
        else
        else
        {
        {
                error = 0;
                error = 0;
                ncp_invalid_dir_cache(dir);
                ncp_invalid_dir_cache(dir);
        }
        }
 
 
        iput(dir);
        iput(dir);
        return error;
        return error;
}
}
 
 
static int
static int
ncp_rmdir(struct inode *dir, const char *name, int len)
ncp_rmdir(struct inode *dir, const char *name, int len)
{
{
        int error;
        int error;
        __u8 _name[len+1];
        __u8 _name[len+1];
 
 
        if (!dir || !S_ISDIR(dir->i_mode))
        if (!dir || !S_ISDIR(dir->i_mode))
        {
        {
                printk("ncp_rmdir: inode is NULL or not a directory\n");
                printk("ncp_rmdir: inode is NULL or not a directory\n");
                iput(dir);
                iput(dir);
                return -ENOENT;
                return -ENOENT;
        }
        }
        if (!ncp_conn_valid(NCP_SERVER(dir)))
        if (!ncp_conn_valid(NCP_SERVER(dir)))
        {
        {
                iput(dir);
                iput(dir);
                return -EIO;
                return -EIO;
        }
        }
        if (ncp_find_dir_inode(dir, name) != NULL)
        if (ncp_find_dir_inode(dir, name) != NULL)
        {
        {
                error = -EBUSY;
                error = -EBUSY;
        }
        }
        else
        else
        {
        {
 
 
                strncpy(_name, name, len);
                strncpy(_name, name, len);
                _name[len] = '\0';
                _name[len] = '\0';
 
 
                if (!ncp_preserve_case(dir))
                if (!ncp_preserve_case(dir))
                {
                {
                        str_upper(_name);
                        str_upper(_name);
                }
                }
 
 
                if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
                if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
                                                    NCP_ISTRUCT(dir),
                                                    NCP_ISTRUCT(dir),
                                                    _name)) == 0)
                                                    _name)) == 0)
                {
                {
                        ncp_invalid_dir_cache(dir);
                        ncp_invalid_dir_cache(dir);
                }
                }
                else
                else
                {
                {
                        error = -EACCES;
                        error = -EACCES;
                }
                }
        }
        }
        iput(dir);
        iput(dir);
        return error;
        return error;
}
}
 
 
 
 
#ifdef CONFIG_NCPFS_STRONG
#ifdef CONFIG_NCPFS_STRONG
/* try to delete a readonly file (NW R bit set) */
/* try to delete a readonly file (NW R bit set) */
 
 
static int
static int
ncp_force_unlink(struct inode *dir,char *name,int len)
ncp_force_unlink(struct inode *dir,char *name,int len)
{
{
        int res=0x9c,res2;
        int res=0x9c,res2;
        struct inode *_inode;
        struct inode *_inode;
        struct iattr ia;
        struct iattr ia;
 
 
        /* remove the Read-Only flag on the NW server */
        /* remove the Read-Only flag on the NW server */
 
 
        dir->i_count++;
        dir->i_count++;
        res2=ncp_lookup(dir,name,len,&_inode);
        res2=ncp_lookup(dir,name,len,&_inode);
        if (res2)
        if (res2)
        {
        {
                goto leave_me; /* abort operation */
                goto leave_me; /* abort operation */
        }
        }
        memset(&ia,0,sizeof(struct iattr));
        memset(&ia,0,sizeof(struct iattr));
        ia.ia_mode = _inode->i_mode;
        ia.ia_mode = _inode->i_mode;
        ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222;  /* set write bits */
        ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222;  /* set write bits */
        ia.ia_valid = ATTR_MODE;
        ia.ia_valid = ATTR_MODE;
 
 
        res2=ncp_notify_change(_inode,&ia);
        res2=ncp_notify_change(_inode,&ia);
        if (res2)
        if (res2)
        {
        {
                iput(_inode);
                iput(_inode);
                goto leave_me;
                goto leave_me;
        }
        }
 
 
        /* now try again the delete operation */
        /* now try again the delete operation */
 
 
        res2 = ncp_del_file_or_subdir(NCP_SERVER(dir),NCP_ISTRUCT(dir),name);
        res2 = ncp_del_file_or_subdir(NCP_SERVER(dir),NCP_ISTRUCT(dir),name);
 
 
        res=res2; /* save status to use as return value */
        res=res2; /* save status to use as return value */
 
 
        res=res2;
        res=res2;
        if (res2)  /* delete failed, set R bit again */
        if (res2)  /* delete failed, set R bit again */
        {
        {
                memset(&ia,0,sizeof(struct iattr));
                memset(&ia,0,sizeof(struct iattr));
                ia.ia_mode = _inode->i_mode;
                ia.ia_mode = _inode->i_mode;
                ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222);  /* clear write bits */
                ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222);  /* clear write bits */
                ia.ia_valid = ATTR_MODE;
                ia.ia_valid = ATTR_MODE;
 
 
                res2=ncp_notify_change(_inode,&ia);
                res2=ncp_notify_change(_inode,&ia);
                if (res2)
                if (res2)
                {
                {
                        iput(_inode);
                        iput(_inode);
                        goto leave_me;
                        goto leave_me;
                }
                }
        }
        }
        iput(_inode);
        iput(_inode);
 
 
 leave_me:
 leave_me:
        return(res);
        return(res);
}
}
#endif  /* CONFIG_NCPFS_STRONG */
#endif  /* CONFIG_NCPFS_STRONG */
 
 
static int
static int
ncp_unlink(struct inode *dir, const char *name, int len)
ncp_unlink(struct inode *dir, const char *name, int len)
{
{
        int error;
        int error;
        __u8 _name[len+1];
        __u8 _name[len+1];
 
 
        if (!dir || !S_ISDIR(dir->i_mode))
        if (!dir || !S_ISDIR(dir->i_mode))
        {
        {
                printk("ncp_unlink: inode is NULL or not a directory\n");
                printk("ncp_unlink: inode is NULL or not a directory\n");
                iput(dir);
                iput(dir);
                return -ENOENT;
                return -ENOENT;
        }
        }
        if (!ncp_conn_valid(NCP_SERVER(dir)))
        if (!ncp_conn_valid(NCP_SERVER(dir)))
        {
        {
                iput(dir);
                iput(dir);
                return -EIO;
                return -EIO;
        }
        }
        if (ncp_find_dir_inode(dir, name) != NULL)
        if (ncp_find_dir_inode(dir, name) != NULL)
        {
        {
                error = -EBUSY;
                error = -EBUSY;
        }
        }
        else
        else
        {
        {
                strncpy(_name, name, len);
                strncpy(_name, name, len);
                _name[len] = '\0';
                _name[len] = '\0';
 
 
                if (!ncp_preserve_case(dir))
                if (!ncp_preserve_case(dir))
                {
                {
                        str_upper(_name);
                        str_upper(_name);
                }
                }
 
 
                error = ncp_del_file_or_subdir(NCP_SERVER(dir),
                error = ncp_del_file_or_subdir(NCP_SERVER(dir),
                                               NCP_ISTRUCT(dir),
                                               NCP_ISTRUCT(dir),
                                               _name);
                                               _name);
#ifdef CONFIG_NCPFS_STRONG
#ifdef CONFIG_NCPFS_STRONG
                if (error == 0x9c && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG)  /* readonly */
                if (error == 0x9c && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG)  /* readonly */
                {
                {
                        error = ncp_force_unlink(dir,_name,len); /* special treatment */
                        error = ncp_force_unlink(dir,_name,len); /* special treatment */
                }
                }
#endif  /* CONFIG_NCPFS_STRONG */
#endif  /* CONFIG_NCPFS_STRONG */
 
 
                if (error == 0) {
                if (error == 0) {
                        ncp_invalid_dir_cache(dir);
                        ncp_invalid_dir_cache(dir);
                } else if (error == 0xFF) {
                } else if (error == 0xFF) {
                        error = -ENOENT;
                        error = -ENOENT;
                } else {
                } else {
                        error = -EACCES;
                        error = -EACCES;
                }
                }
        }
        }
        iput(dir);
        iput(dir);
        return error;
        return error;
}
}
 
 
#ifdef CONFIG_NCPFS_STRONG
#ifdef CONFIG_NCPFS_STRONG
static int
static int
ncp_force_rename(struct inode *old_dir, const char *old_name, char *_old_name, int old_len,
ncp_force_rename(struct inode *old_dir, const char *old_name, char *_old_name, int old_len,
                 struct inode *new_dir, const char *new_name, char *_new_name, int new_len)
                 struct inode *new_dir, const char *new_name, char *_new_name, int new_len)
{
{
        int res=0x90,res2;
        int res=0x90,res2;
        char _rename_old[old_len+1];
        char _rename_old[old_len+1];
        char _rename_new[new_len+1];
        char _rename_new[new_len+1];
        struct inode *_inode,*x_dir;
        struct inode *_inode,*x_dir;
        struct iattr ia;
        struct iattr ia;
 
 
        strncpy(_rename_old,old_name,old_len);
        strncpy(_rename_old,old_name,old_len);
        _rename_old[old_len] = 0;
        _rename_old[old_len] = 0;
        strncpy(_rename_new,new_name,new_len);
        strncpy(_rename_new,new_name,new_len);
        _rename_new[new_len] = 0;
        _rename_new[new_len] = 0;
 
 
        /* remove the Read-Only flag on the NW server */
        /* remove the Read-Only flag on the NW server */
 
 
        old_dir->i_count++;
        old_dir->i_count++;
        res2=ncp_lookup(old_dir,_rename_old,old_len,&_inode);
        res2=ncp_lookup(old_dir,_rename_old,old_len,&_inode);
        if (res2)
        if (res2)
        {
        {
                goto leave_me;
                goto leave_me;
        }
        }
        memset(&ia,0,sizeof(struct iattr));
        memset(&ia,0,sizeof(struct iattr));
        ia.ia_mode = _inode->i_mode;
        ia.ia_mode = _inode->i_mode;
        ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222;  /* set write bits */
        ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222;  /* set write bits */
        ia.ia_valid = ATTR_MODE;
        ia.ia_valid = ATTR_MODE;
 
 
        res2=ncp_notify_change(_inode,&ia);
        res2=ncp_notify_change(_inode,&ia);
        if (res2)
        if (res2)
        {
        {
                iput(_inode);
                iput(_inode);
                goto leave_me;
                goto leave_me;
        }
        }
 
 
        /* now try again the rename operation */
        /* now try again the rename operation */
        res2 = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
        res2 = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
                                             NCP_ISTRUCT(old_dir), _old_name,
                                             NCP_ISTRUCT(old_dir), _old_name,
                                             NCP_ISTRUCT(new_dir), _new_name);
                                             NCP_ISTRUCT(new_dir), _new_name);
 
 
        res=res2;
        res=res2;
        if (!res2)  /* rename succeeded, get a new inode for the new file */
        if (!res2)  /* rename succeeded, get a new inode for the new file */
        {
        {
                x_dir=new_dir;
                x_dir=new_dir;
                new_dir->i_count++;
                new_dir->i_count++;
                iput(_inode);
                iput(_inode);
                res2=ncp_lookup(new_dir,_rename_new,new_len,&_inode);
                res2=ncp_lookup(new_dir,_rename_new,new_len,&_inode);
                if (res2)
                if (res2)
                {
                {
                        goto leave_me;
                        goto leave_me;
                }
                }
        }
        }
        else
        else
        {
        {
                x_dir=old_dir;
                x_dir=old_dir;
        }
        }
 
 
        memset(&ia,0,sizeof(struct iattr));
        memset(&ia,0,sizeof(struct iattr));
        ia.ia_mode = _inode->i_mode;
        ia.ia_mode = _inode->i_mode;
        ia.ia_mode &= ~(NCP_SERVER(x_dir)->m.file_mode & 0222);  /* clear write bits */
        ia.ia_mode &= ~(NCP_SERVER(x_dir)->m.file_mode & 0222);  /* clear write bits */
        ia.ia_valid = ATTR_MODE;
        ia.ia_valid = ATTR_MODE;
 
 
        res2=ncp_notify_change(_inode,&ia);
        res2=ncp_notify_change(_inode,&ia);
        iput(_inode);
        iput(_inode);
        if (res2)
        if (res2)
        {
        {
                printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2);
                printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2);
                goto leave_me;
                goto leave_me;
        }
        }
 
 
 leave_me:
 leave_me:
        return(res);
        return(res);
}
}
#endif  /* CONFIG_NCPFS_STRONG */
#endif  /* CONFIG_NCPFS_STRONG */
 
 
 
 
static int
static int
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
           struct inode *new_dir, const char *new_name, int new_len,
           struct inode *new_dir, const char *new_name, int new_len,
           int must_be_dir)
           int must_be_dir)
{
{
        int res;
        int res;
        char _old_name[old_len+1];
        char _old_name[old_len+1];
        char _new_name[new_len+1];
        char _new_name[new_len+1];
 
 
        if (!old_dir || !S_ISDIR(old_dir->i_mode))
        if (!old_dir || !S_ISDIR(old_dir->i_mode))
        {
        {
                printk("ncp_rename: old inode is NULL or not a directory\n");
                printk("ncp_rename: old inode is NULL or not a directory\n");
                res = -ENOENT;
                res = -ENOENT;
                goto finished;
                goto finished;
        }
        }
 
 
        if (!ncp_conn_valid(NCP_SERVER(old_dir)))
        if (!ncp_conn_valid(NCP_SERVER(old_dir)))
        {
        {
                res = -EIO;
                res = -EIO;
                goto finished;
                goto finished;
        }
        }
 
 
        if (!new_dir || !S_ISDIR(new_dir->i_mode))
        if (!new_dir || !S_ISDIR(new_dir->i_mode))
        {
        {
                printk("ncp_rename: new inode is NULL or not a directory\n");
                printk("ncp_rename: new inode is NULL or not a directory\n");
                res = -ENOENT;
                res = -ENOENT;
                goto finished;
                goto finished;
        }
        }
 
 
        if (   (ncp_find_dir_inode(old_dir, old_name) != NULL)
        if (   (ncp_find_dir_inode(old_dir, old_name) != NULL)
            || (ncp_find_dir_inode(new_dir, new_name) != NULL))
            || (ncp_find_dir_inode(new_dir, new_name) != NULL))
        {
        {
                res = -EBUSY;
                res = -EBUSY;
                goto finished;
                goto finished;
        }
        }
 
 
        strncpy(_old_name, old_name, old_len);
        strncpy(_old_name, old_name, old_len);
        _old_name[old_len] = '\0';
        _old_name[old_len] = '\0';
 
 
        if (!ncp_preserve_case(old_dir))
        if (!ncp_preserve_case(old_dir))
        {
        {
                str_upper(_old_name);
                str_upper(_old_name);
        }
        }
 
 
        strncpy(_new_name, new_name, new_len);
        strncpy(_new_name, new_name, new_len);
        _new_name[new_len] = '\0';
        _new_name[new_len] = '\0';
 
 
        if (!ncp_preserve_case(new_dir))
        if (!ncp_preserve_case(new_dir))
        {
        {
                str_upper(_new_name);
                str_upper(_new_name);
        }
        }
 
 
        res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
        res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
                                            NCP_ISTRUCT(old_dir), _old_name,
                                            NCP_ISTRUCT(old_dir), _old_name,
                                            NCP_ISTRUCT(new_dir), _new_name);
                                            NCP_ISTRUCT(new_dir), _new_name);
 
 
#ifdef CONFIG_NCPFS_STRONG
#ifdef CONFIG_NCPFS_STRONG
        if (res == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) /* file is readonly */
        if (res == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) /* file is readonly */
        {
        {
                res=ncp_force_rename(old_dir,old_name,_old_name,old_len,new_dir,new_name,_new_name,new_len);
                res=ncp_force_rename(old_dir,old_name,_old_name,old_len,new_dir,new_name,_new_name,new_len);
        }
        }
#endif  /* CONFIG_NCPFS_STRONG */
#endif  /* CONFIG_NCPFS_STRONG */
 
 
        if (res == 0)
        if (res == 0)
        {
        {
                ncp_invalid_dir_cache(old_dir);
                ncp_invalid_dir_cache(old_dir);
                ncp_invalid_dir_cache(new_dir);
                ncp_invalid_dir_cache(new_dir);
        }
        }
        else
        else
        {
        {
                if (res == 0x9E)
                if (res == 0x9E)
                        res = -ENAMETOOLONG;
                        res = -ENAMETOOLONG;
                else if (res == 0xFF)
                else if (res == 0xFF)
                        res = -ENOENT;
                        res = -ENOENT;
                else
                else
                        res = -EACCES;
                        res = -EACCES;
        }
        }
 
 
 finished:
 finished:
        iput(old_dir);
        iput(old_dir);
        iput(new_dir);
        iput(new_dir);
        return res;
        return res;
}
}
 
 
/* The following routines are taken directly from msdos-fs */
/* The following routines are taken directly from msdos-fs */
 
 
/* Linear day numbers of the respective 1sts in non-leap years. */
/* Linear day numbers of the respective 1sts in non-leap years. */
 
 
static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
                  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
                  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
 
 
 
 
extern struct timezone sys_tz;
extern struct timezone sys_tz;
 
 
static int
static int
utc2local(int time)
utc2local(int time)
{
{
        return time - sys_tz.tz_minuteswest*60 + sys_tz.tz_dsttime*3600;
        return time - sys_tz.tz_minuteswest*60 + sys_tz.tz_dsttime*3600;
}
}
 
 
static int
static int
local2utc(int time)
local2utc(int time)
{
{
        return time + sys_tz.tz_minuteswest*60 - sys_tz.tz_dsttime*3600;
        return time + sys_tz.tz_minuteswest*60 - sys_tz.tz_dsttime*3600;
}
}
 
 
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
 
 
int
int
ncp_date_dos2unix(unsigned short time,unsigned short date)
ncp_date_dos2unix(unsigned short time,unsigned short date)
{
{
        int month,year,secs;
        int month,year,secs;
 
 
        month = ((date >> 5) & 15)-1;
        month = ((date >> 5) & 15)-1;
        year = date >> 9;
        year = date >> 9;
        secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
        secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
            ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
            ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
            month < 2 ? 1 : 0)+3653);
            month < 2 ? 1 : 0)+3653);
                        /* days since 1.1.70 plus 80's leap day */
                        /* days since 1.1.70 plus 80's leap day */
        return local2utc(secs);
        return local2utc(secs);
}
}
 
 
 
 
/* Convert linear UNIX date to a MS-DOS time/date pair. */
/* Convert linear UNIX date to a MS-DOS time/date pair. */
void
void
ncp_date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
ncp_date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
{
{
        int day,year,nl_day,month;
        int day,year,nl_day,month;
 
 
        unix_date = utc2local(unix_date);
        unix_date = utc2local(unix_date);
        *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
        *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
            (((unix_date/3600) % 24) << 11);
            (((unix_date/3600) % 24) << 11);
        day = unix_date/86400-3652;
        day = unix_date/86400-3652;
        year = day/365;
        year = day/365;
        if ((year+3)/4+365*year > day) year--;
        if ((year+3)/4+365*year > day) year--;
        day -= (year+3)/4+365*year;
        day -= (year+3)/4+365*year;
        if (day == 59 && !(year & 3)) {
        if (day == 59 && !(year & 3)) {
                nl_day = day;
                nl_day = day;
                month = 2;
                month = 2;
        }
        }
        else {
        else {
                nl_day = (year & 3) || day <= 59 ? day : day-1;
                nl_day = (year & 3) || day <= 59 ? day : day-1;
                for (month = 0; month < 12; month++)
                for (month = 0; month < 12; month++)
                        if (day_n[month] > nl_day) break;
                        if (day_n[month] > nl_day) break;
        }
        }
        *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
        *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
}
}
 
 

powered by: WebSVN 2.1.0

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