linux/fs/ncpfs/inode.c
<<
>>
Prefs
   1/*
   2 *  inode.c
   3 *
   4 *  Copyright (C) 1995, 1996 by Volker Lendecke
   5 *  Modified for big endian by J.F. Chadima and David S. Miller
   6 *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
   7 *  Modified 1998 Wolfram Pienkoss for NLS
   8 *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
   9 *
  10 */
  11
  12#include <linux/module.h>
  13
  14#include <asm/uaccess.h>
  15#include <asm/byteorder.h>
  16
  17#include <linux/time.h>
  18#include <linux/kernel.h>
  19#include <linux/mm.h>
  20#include <linux/string.h>
  21#include <linux/stat.h>
  22#include <linux/errno.h>
  23#include <linux/file.h>
  24#include <linux/fcntl.h>
  25#include <linux/slab.h>
  26#include <linux/vmalloc.h>
  27#include <linux/init.h>
  28#include <linux/vfs.h>
  29#include <linux/mount.h>
  30#include <linux/seq_file.h>
  31#include <linux/namei.h>
  32
  33#include <net/sock.h>
  34
  35#include "ncp_fs.h"
  36#include "getopt.h"
  37
  38#define NCP_DEFAULT_FILE_MODE 0600
  39#define NCP_DEFAULT_DIR_MODE 0700
  40#define NCP_DEFAULT_TIME_OUT 10
  41#define NCP_DEFAULT_RETRY_COUNT 20
  42
  43static void ncp_evict_inode(struct inode *);
  44static void ncp_put_super(struct super_block *);
  45static int  ncp_statfs(struct dentry *, struct kstatfs *);
  46static int  ncp_show_options(struct seq_file *, struct dentry *);
  47
  48static struct kmem_cache * ncp_inode_cachep;
  49
  50static struct inode *ncp_alloc_inode(struct super_block *sb)
  51{
  52        struct ncp_inode_info *ei;
  53        ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
  54        if (!ei)
  55                return NULL;
  56        return &ei->vfs_inode;
  57}
  58
  59static void ncp_i_callback(struct rcu_head *head)
  60{
  61        struct inode *inode = container_of(head, struct inode, i_rcu);
  62        kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
  63}
  64
  65static void ncp_destroy_inode(struct inode *inode)
  66{
  67        call_rcu(&inode->i_rcu, ncp_i_callback);
  68}
  69
  70static void init_once(void *foo)
  71{
  72        struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
  73
  74        mutex_init(&ei->open_mutex);
  75        inode_init_once(&ei->vfs_inode);
  76}
  77
  78static int init_inodecache(void)
  79{
  80        ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
  81                                             sizeof(struct ncp_inode_info),
  82                                             0, (SLAB_RECLAIM_ACCOUNT|
  83                                                SLAB_MEM_SPREAD),
  84                                             init_once);
  85        if (ncp_inode_cachep == NULL)
  86                return -ENOMEM;
  87        return 0;
  88}
  89
  90static void destroy_inodecache(void)
  91{
  92        /*
  93         * Make sure all delayed rcu free inodes are flushed before we
  94         * destroy cache.
  95         */
  96        rcu_barrier();
  97        kmem_cache_destroy(ncp_inode_cachep);
  98}
  99
 100static int ncp_remount(struct super_block *sb, int *flags, char* data)
 101{
 102        *flags |= MS_NODIRATIME;
 103        return 0;
 104}
 105
 106static const struct super_operations ncp_sops =
 107{
 108        .alloc_inode    = ncp_alloc_inode,
 109        .destroy_inode  = ncp_destroy_inode,
 110        .drop_inode     = generic_delete_inode,
 111        .evict_inode    = ncp_evict_inode,
 112        .put_super      = ncp_put_super,
 113        .statfs         = ncp_statfs,
 114        .remount_fs     = ncp_remount,
 115        .show_options   = ncp_show_options,
 116};
 117
 118/*
 119 * Fill in the ncpfs-specific information in the inode.
 120 */
 121static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
 122{
 123        NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
 124        NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
 125        NCP_FINFO(inode)->volNumber = nwinfo->volume;
 126}
 127
 128void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
 129{
 130        ncp_update_dirent(inode, nwinfo);
 131        NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
 132        NCP_FINFO(inode)->access = nwinfo->access;
 133        memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
 134                        sizeof(nwinfo->file_handle));
 135        DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
 136                nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
 137                NCP_FINFO(inode)->dirEntNum);
 138}
 139
 140static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
 141{
 142        /* NFS namespace mode overrides others if it's set. */
 143        DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
 144                nwi->entryName, nwi->nfs.mode);
 145        if (nwi->nfs.mode) {
 146                /* XXX Security? */
 147                inode->i_mode = nwi->nfs.mode;
 148        }
 149
 150        inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
 151
 152        inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
 153        inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
 154        inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
 155        inode->i_atime.tv_nsec = 0;
 156        inode->i_mtime.tv_nsec = 0;
 157        inode->i_ctime.tv_nsec = 0;
 158}
 159
 160static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
 161{
 162        struct nw_info_struct *nwi = &nwinfo->i;
 163        struct ncp_server *server = NCP_SERVER(inode);
 164
 165        if (nwi->attributes & aDIR) {
 166                inode->i_mode = server->m.dir_mode;
 167                /* for directories dataStreamSize seems to be some
 168                   Object ID ??? */
 169                i_size_write(inode, NCP_BLOCK_SIZE);
 170        } else {
 171                u32 size;
 172
 173                inode->i_mode = server->m.file_mode;
 174                size = le32_to_cpu(nwi->dataStreamSize);
 175                i_size_write(inode, size);
 176#ifdef CONFIG_NCPFS_EXTRAS
 177                if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) 
 178                 && (nwi->attributes & aSHARED)) {
 179                        switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
 180                                case aHIDDEN:
 181                                        if (server->m.flags & NCP_MOUNT_SYMLINKS) {
 182                                                if (/* (size >= NCP_MIN_SYMLINK_SIZE)
 183                                                 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
 184                                                        inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
 185                                                        NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
 186                                                        break;
 187                                                }
 188                                        }
 189                                        /* FALLTHROUGH */
 190                                case 0:
 191                                        if (server->m.flags & NCP_MOUNT_EXTRAS)
 192                                                inode->i_mode |= S_IRUGO;
 193                                        break;
 194                                case aSYSTEM:
 195                                        if (server->m.flags & NCP_MOUNT_EXTRAS)
 196                                                inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
 197                                        break;
 198                                /* case aSYSTEM|aHIDDEN: */
 199                                default:
 200                                        /* reserved combination */
 201                                        break;
 202                        }
 203                }
 204#endif
 205        }
 206        if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
 207}
 208
 209void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
 210{
 211        NCP_FINFO(inode)->flags = 0;
 212        if (!atomic_read(&NCP_FINFO(inode)->opened)) {
 213                NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
 214                ncp_update_attrs(inode, nwinfo);
 215        }
 216
 217        ncp_update_dates(inode, &nwinfo->i);
 218        ncp_update_dirent(inode, nwinfo);
 219}
 220
 221/*
 222 * Fill in the inode based on the ncp_entry_info structure.  Used only for brand new inodes.
 223 */
 224static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
 225{
 226        struct ncp_server *server = NCP_SERVER(inode);
 227
 228        NCP_FINFO(inode)->flags = 0;
 229        
 230        ncp_update_attrs(inode, nwinfo);
 231
 232        DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
 233
 234        set_nlink(inode, 1);
 235        inode->i_uid = server->m.uid;
 236        inode->i_gid = server->m.gid;
 237
 238        ncp_update_dates(inode, &nwinfo->i);
 239        ncp_update_inode(inode, nwinfo);
 240}
 241
 242#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
 243static const struct inode_operations ncp_symlink_inode_operations = {
 244        .readlink       = generic_readlink,
 245        .follow_link    = page_follow_link_light,
 246        .put_link       = page_put_link,
 247        .setattr        = ncp_notify_change,
 248};
 249#endif
 250
 251/*
 252 * Get a new inode.
 253 */
 254struct inode * 
 255ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
 256{
 257        struct inode *inode;
 258
 259        if (info == NULL) {
 260                printk(KERN_ERR "ncp_iget: info is NULL\n");
 261                return NULL;
 262        }
 263
 264        inode = new_inode(sb);
 265        if (inode) {
 266                atomic_set(&NCP_FINFO(inode)->opened, info->opened);
 267
 268                inode->i_mapping->backing_dev_info = sb->s_bdi;
 269                inode->i_ino = info->ino;
 270                ncp_set_attr(inode, info);
 271                if (S_ISREG(inode->i_mode)) {
 272                        inode->i_op = &ncp_file_inode_operations;
 273                        inode->i_fop = &ncp_file_operations;
 274                } else if (S_ISDIR(inode->i_mode)) {
 275                        inode->i_op = &ncp_dir_inode_operations;
 276                        inode->i_fop = &ncp_dir_operations;
 277#ifdef CONFIG_NCPFS_NFS_NS
 278                } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
 279                        init_special_inode(inode, inode->i_mode,
 280                                new_decode_dev(info->i.nfs.rdev));
 281#endif
 282#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
 283                } else if (S_ISLNK(inode->i_mode)) {
 284                        inode->i_op = &ncp_symlink_inode_operations;
 285                        inode->i_data.a_ops = &ncp_symlink_aops;
 286#endif
 287                } else {
 288                        make_bad_inode(inode);
 289                }
 290                insert_inode_hash(inode);
 291        } else
 292                printk(KERN_ERR "ncp_iget: iget failed!\n");
 293        return inode;
 294}
 295
 296static void
 297ncp_evict_inode(struct inode *inode)
 298{
 299        truncate_inode_pages(&inode->i_data, 0);
 300        clear_inode(inode);
 301
 302        if (S_ISDIR(inode->i_mode)) {
 303                DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
 304        }
 305
 306        if (ncp_make_closed(inode) != 0) {
 307                /* We can't do anything but complain. */
 308                printk(KERN_ERR "ncp_evict_inode: could not close\n");
 309        }
 310}
 311
 312static void ncp_stop_tasks(struct ncp_server *server) {
 313        struct sock* sk = server->ncp_sock->sk;
 314
 315        lock_sock(sk);
 316        sk->sk_error_report = server->error_report;
 317        sk->sk_data_ready   = server->data_ready;
 318        sk->sk_write_space  = server->write_space;
 319        release_sock(sk);
 320        del_timer_sync(&server->timeout_tm);
 321
 322        flush_work(&server->rcv.tq);
 323        if (sk->sk_socket->type == SOCK_STREAM)
 324                flush_work(&server->tx.tq);
 325        else
 326                flush_work(&server->timeout_tq);
 327}
 328
 329static int  ncp_show_options(struct seq_file *seq, struct dentry *root)
 330{
 331        struct ncp_server *server = NCP_SBP(root->d_sb);
 332        unsigned int tmp;
 333
 334        if (!uid_eq(server->m.uid, GLOBAL_ROOT_UID))
 335                seq_printf(seq, ",uid=%u",
 336                           from_kuid_munged(&init_user_ns, server->m.uid));
 337        if (!gid_eq(server->m.gid, GLOBAL_ROOT_GID))
 338                seq_printf(seq, ",gid=%u",
 339                           from_kgid_munged(&init_user_ns, server->m.gid));
 340        if (!uid_eq(server->m.mounted_uid, GLOBAL_ROOT_UID))
 341                seq_printf(seq, ",owner=%u",
 342                           from_kuid_munged(&init_user_ns, server->m.mounted_uid));
 343        tmp = server->m.file_mode & S_IALLUGO;
 344        if (tmp != NCP_DEFAULT_FILE_MODE)
 345                seq_printf(seq, ",mode=0%o", tmp);
 346        tmp = server->m.dir_mode & S_IALLUGO;
 347        if (tmp != NCP_DEFAULT_DIR_MODE)
 348                seq_printf(seq, ",dirmode=0%o", tmp);
 349        if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
 350                tmp = server->m.time_out * 100 / HZ;
 351                seq_printf(seq, ",timeout=%u", tmp);
 352        }
 353        if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
 354                seq_printf(seq, ",retry=%u", server->m.retry_count);
 355        if (server->m.flags != 0)
 356                seq_printf(seq, ",flags=%lu", server->m.flags);
 357        if (server->m.wdog_pid != NULL)
 358                seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
 359
 360        return 0;
 361}
 362
 363static const struct ncp_option ncp_opts[] = {
 364        { "uid",        OPT_INT,        'u' },
 365        { "gid",        OPT_INT,        'g' },
 366        { "owner",      OPT_INT,        'o' },
 367        { "mode",       OPT_INT,        'm' },
 368        { "dirmode",    OPT_INT,        'd' },
 369        { "timeout",    OPT_INT,        't' },
 370        { "retry",      OPT_INT,        'r' },
 371        { "flags",      OPT_INT,        'f' },
 372        { "wdogpid",    OPT_INT,        'w' },
 373        { "ncpfd",      OPT_INT,        'n' },
 374        { "infofd",     OPT_INT,        'i' },  /* v5 */
 375        { "version",    OPT_INT,        'v' },
 376        { NULL,         0,              0 } };
 377
 378static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
 379        int optval;
 380        char *optarg;
 381        unsigned long optint;
 382        int version = 0;
 383        int ret;
 384
 385        data->flags = 0;
 386        data->int_flags = 0;
 387        data->mounted_uid = GLOBAL_ROOT_UID;
 388        data->wdog_pid = NULL;
 389        data->ncp_fd = ~0;
 390        data->time_out = NCP_DEFAULT_TIME_OUT;
 391        data->retry_count = NCP_DEFAULT_RETRY_COUNT;
 392        data->uid = GLOBAL_ROOT_UID;
 393        data->gid = GLOBAL_ROOT_GID;
 394        data->file_mode = NCP_DEFAULT_FILE_MODE;
 395        data->dir_mode = NCP_DEFAULT_DIR_MODE;
 396        data->info_fd = -1;
 397        data->mounted_vol[0] = 0;
 398        
 399        while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
 400                ret = optval;
 401                if (ret < 0)
 402                        goto err;
 403                switch (optval) {
 404                        case 'u':
 405                                data->uid = make_kuid(current_user_ns(), optint);
 406                                if (!uid_valid(data->uid))
 407                                        goto err;
 408                                break;
 409                        case 'g':
 410                                data->gid = make_kgid(current_user_ns(), optint);
 411                                if (!gid_valid(data->gid))
 412                                        goto err;
 413                                break;
 414                        case 'o':
 415                                data->mounted_uid = make_kuid(current_user_ns(), optint);
 416                                if (!uid_valid(data->mounted_uid))
 417                                        goto err;
 418                                break;
 419                        case 'm':
 420                                data->file_mode = optint;
 421                                break;
 422                        case 'd':
 423                                data->dir_mode = optint;
 424                                break;
 425                        case 't':
 426                                data->time_out = optint;
 427                                break;
 428                        case 'r':
 429                                data->retry_count = optint;
 430                                break;
 431                        case 'f':
 432                                data->flags = optint;
 433                                break;
 434                        case 'w':
 435                                data->wdog_pid = find_get_pid(optint);
 436                                break;
 437                        case 'n':
 438                                data->ncp_fd = optint;
 439                                break;
 440                        case 'i':
 441                                data->info_fd = optint;
 442                                break;
 443                        case 'v':
 444                                ret = -ECHRNG;
 445                                if (optint < NCP_MOUNT_VERSION_V4)
 446                                        goto err;
 447                                if (optint > NCP_MOUNT_VERSION_V5)
 448                                        goto err;
 449                                version = optint;
 450                                break;
 451                        
 452                }
 453        }
 454        return 0;
 455err:
 456        put_pid(data->wdog_pid);
 457        data->wdog_pid = NULL;
 458        return ret;
 459}
 460
 461static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
 462{
 463        struct ncp_mount_data_kernel data;
 464        struct ncp_server *server;
 465        struct file *ncp_filp;
 466        struct inode *root_inode;
 467        struct inode *sock_inode;
 468        struct socket *sock;
 469        int error;
 470        int default_bufsize;
 471#ifdef CONFIG_NCPFS_PACKET_SIGNING
 472        int options;
 473#endif
 474        struct ncp_entry_info finfo;
 475
 476        memset(&data, 0, sizeof(data));
 477        server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
 478        if (!server)
 479                return -ENOMEM;
 480        sb->s_fs_info = server;
 481
 482        error = -EFAULT;
 483        if (raw_data == NULL)
 484                goto out;
 485        switch (*(int*)raw_data) {
 486                case NCP_MOUNT_VERSION:
 487                        {
 488                                struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
 489
 490                                data.flags = md->flags;
 491                                data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
 492                                data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
 493                                data.wdog_pid = find_get_pid(md->wdog_pid);
 494                                data.ncp_fd = md->ncp_fd;
 495                                data.time_out = md->time_out;
 496                                data.retry_count = md->retry_count;
 497                                data.uid = make_kuid(current_user_ns(), md->uid);
 498                                data.gid = make_kgid(current_user_ns(), md->gid);
 499                                data.file_mode = md->file_mode;
 500                                data.dir_mode = md->dir_mode;
 501                                data.info_fd = -1;
 502                                memcpy(data.mounted_vol, md->mounted_vol,
 503                                        NCP_VOLNAME_LEN+1);
 504                        }
 505                        break;
 506                case NCP_MOUNT_VERSION_V4:
 507                        {
 508                                struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
 509
 510                                data.flags = md->flags;
 511                                data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
 512                                data.wdog_pid = find_get_pid(md->wdog_pid);
 513                                data.ncp_fd = md->ncp_fd;
 514                                data.time_out = md->time_out;
 515                                data.retry_count = md->retry_count;
 516                                data.uid = make_kuid(current_user_ns(), md->uid);
 517                                data.gid = make_kgid(current_user_ns(), md->gid);
 518                                data.file_mode = md->file_mode;
 519                                data.dir_mode = md->dir_mode;
 520                                data.info_fd = -1;
 521                        }
 522                        break;
 523                default:
 524                        error = -ECHRNG;
 525                        if (memcmp(raw_data, "vers", 4) == 0) {
 526                                error = ncp_parse_options(&data, raw_data);
 527                        }
 528                        if (error)
 529                                goto out;
 530                        break;
 531        }
 532        error = -EINVAL;
 533        if (!uid_valid(data.mounted_uid) || !uid_valid(data.uid) ||
 534            !gid_valid(data.gid))
 535                goto out;
 536        error = -EBADF;
 537        ncp_filp = fget(data.ncp_fd);
 538        if (!ncp_filp)
 539                goto out;
 540        error = -ENOTSOCK;
 541        sock_inode = file_inode(ncp_filp);
 542        if (!S_ISSOCK(sock_inode->i_mode))
 543                goto out_fput;
 544        sock = SOCKET_I(sock_inode);
 545        if (!sock)
 546                goto out_fput;
 547                
 548        if (sock->type == SOCK_STREAM)
 549                default_bufsize = 0xF000;
 550        else
 551                default_bufsize = 1024;
 552
 553        sb->s_flags |= MS_NODIRATIME;   /* probably even noatime */
 554        sb->s_maxbytes = 0xFFFFFFFFU;
 555        sb->s_blocksize = 1024; /* Eh...  Is this correct? */
 556        sb->s_blocksize_bits = 10;
 557        sb->s_magic = NCP_SUPER_MAGIC;
 558        sb->s_op = &ncp_sops;
 559        sb->s_d_op = &ncp_dentry_operations;
 560        sb->s_bdi = &server->bdi;
 561
 562        server = NCP_SBP(sb);
 563        memset(server, 0, sizeof(*server));
 564
 565        error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
 566        if (error)
 567                goto out_fput;
 568
 569        server->ncp_filp = ncp_filp;
 570        server->ncp_sock = sock;
 571        
 572        if (data.info_fd != -1) {
 573                struct socket *info_sock;
 574
 575                error = -EBADF;
 576                server->info_filp = fget(data.info_fd);
 577                if (!server->info_filp)
 578                        goto out_bdi;
 579                error = -ENOTSOCK;
 580                sock_inode = file_inode(server->info_filp);
 581                if (!S_ISSOCK(sock_inode->i_mode))
 582                        goto out_fput2;
 583                info_sock = SOCKET_I(sock_inode);
 584                if (!info_sock)
 585                        goto out_fput2;
 586                error = -EBADFD;
 587                if (info_sock->type != SOCK_STREAM)
 588                        goto out_fput2;
 589                server->info_sock = info_sock;
 590        }
 591
 592/*      server->lock = 0;       */
 593        mutex_init(&server->mutex);
 594        server->packet = NULL;
 595/*      server->buffer_size = 0;        */
 596/*      server->conn_status = 0;        */
 597/*      server->root_dentry = NULL;     */
 598/*      server->root_setuped = 0;       */
 599        mutex_init(&server->root_setup_lock);
 600#ifdef CONFIG_NCPFS_PACKET_SIGNING
 601/*      server->sign_wanted = 0;        */
 602/*      server->sign_active = 0;        */
 603#endif
 604        init_rwsem(&server->auth_rwsem);
 605        server->auth.auth_type = NCP_AUTH_NONE;
 606/*      server->auth.object_name_len = 0;       */
 607/*      server->auth.object_name = NULL;        */
 608/*      server->auth.object_type = 0;           */
 609/*      server->priv.len = 0;                   */
 610/*      server->priv.data = NULL;               */
 611
 612        server->m = data;
 613        /* Although anything producing this is buggy, it happens
 614           now because of PATH_MAX changes.. */
 615        if (server->m.time_out < 1) {
 616                server->m.time_out = 10;
 617                printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
 618        }
 619        server->m.time_out = server->m.time_out * HZ / 100;
 620        server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
 621        server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
 622
 623#ifdef CONFIG_NCPFS_NLS
 624        /* load the default NLS charsets */
 625        server->nls_vol = load_nls_default();
 626        server->nls_io = load_nls_default();
 627#endif /* CONFIG_NCPFS_NLS */
 628
 629        atomic_set(&server->dentry_ttl, 0);     /* no caching */
 630
 631        INIT_LIST_HEAD(&server->tx.requests);
 632        mutex_init(&server->rcv.creq_mutex);
 633        server->tx.creq         = NULL;
 634        server->rcv.creq        = NULL;
 635
 636        init_timer(&server->timeout_tm);
 637#undef NCP_PACKET_SIZE
 638#define NCP_PACKET_SIZE 131072
 639        error = -ENOMEM;
 640        server->packet_size = NCP_PACKET_SIZE;
 641        server->packet = vmalloc(NCP_PACKET_SIZE);
 642        if (server->packet == NULL)
 643                goto out_nls;
 644        server->txbuf = vmalloc(NCP_PACKET_SIZE);
 645        if (server->txbuf == NULL)
 646                goto out_packet;
 647        server->rxbuf = vmalloc(NCP_PACKET_SIZE);
 648        if (server->rxbuf == NULL)
 649                goto out_txbuf;
 650
 651        lock_sock(sock->sk);
 652        server->data_ready      = sock->sk->sk_data_ready;
 653        server->write_space     = sock->sk->sk_write_space;
 654        server->error_report    = sock->sk->sk_error_report;
 655        sock->sk->sk_user_data  = server;
 656        sock->sk->sk_data_ready   = ncp_tcp_data_ready;
 657        sock->sk->sk_error_report = ncp_tcp_error_report;
 658        if (sock->type == SOCK_STREAM) {
 659                server->rcv.ptr = (unsigned char*)&server->rcv.buf;
 660                server->rcv.len = 10;
 661                server->rcv.state = 0;
 662                INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
 663                INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
 664                sock->sk->sk_write_space = ncp_tcp_write_space;
 665        } else {
 666                INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
 667                INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
 668                server->timeout_tm.data = (unsigned long)server;
 669                server->timeout_tm.function = ncpdgram_timeout_call;
 670        }
 671        release_sock(sock->sk);
 672
 673        ncp_lock_server(server);
 674        error = ncp_connect(server);
 675        ncp_unlock_server(server);
 676        if (error < 0)
 677                goto out_rxbuf;
 678        DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
 679
 680        error = -EMSGSIZE;      /* -EREMOTESIDEINCOMPATIBLE */
 681#ifdef CONFIG_NCPFS_PACKET_SIGNING
 682        if (ncp_negotiate_size_and_options(server, default_bufsize,
 683                NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
 684        {
 685                if (options != NCP_DEFAULT_OPTIONS)
 686                {
 687                        if (ncp_negotiate_size_and_options(server, 
 688                                default_bufsize,
 689                                options & 2, 
 690                                &(server->buffer_size), &options) != 0)
 691                                
 692                        {
 693                                goto out_disconnect;
 694                        }
 695                }
 696                ncp_lock_server(server);
 697                if (options & 2)
 698                        server->sign_wanted = 1;
 699                ncp_unlock_server(server);
 700        }
 701        else 
 702#endif  /* CONFIG_NCPFS_PACKET_SIGNING */
 703        if (ncp_negotiate_buffersize(server, default_bufsize,
 704                                     &(server->buffer_size)) != 0)
 705                goto out_disconnect;
 706        DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
 707
 708        memset(&finfo, 0, sizeof(finfo));
 709        finfo.i.attributes      = aDIR;
 710        finfo.i.dataStreamSize  = 0;    /* ignored */
 711        finfo.i.dirEntNum       = 0;
 712        finfo.i.DosDirNum       = 0;
 713#ifdef CONFIG_NCPFS_SMALLDOS
 714        finfo.i.NSCreator       = NW_NS_DOS;
 715#endif
 716        finfo.volume            = NCP_NUMBER_OF_VOLUMES;
 717        /* set dates of mountpoint to Jan 1, 1986; 00:00 */
 718        finfo.i.creationTime    = finfo.i.modifyTime
 719                                = cpu_to_le16(0x0000);
 720        finfo.i.creationDate    = finfo.i.modifyDate
 721                                = finfo.i.lastAccessDate
 722                                = cpu_to_le16(0x0C21);
 723        finfo.i.nameLen         = 0;
 724        finfo.i.entryName[0]    = '\0';
 725
 726        finfo.opened            = 0;
 727        finfo.ino               = 2;    /* tradition */
 728
 729        server->name_space[finfo.volume] = NW_NS_DOS;
 730
 731        error = -ENOMEM;
 732        root_inode = ncp_iget(sb, &finfo);
 733        if (!root_inode)
 734                goto out_disconnect;
 735        DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
 736        sb->s_root = d_make_root(root_inode);
 737        if (!sb->s_root)
 738                goto out_disconnect;
 739        return 0;
 740
 741out_disconnect:
 742        ncp_lock_server(server);
 743        ncp_disconnect(server);
 744        ncp_unlock_server(server);
 745out_rxbuf:
 746        ncp_stop_tasks(server);
 747        vfree(server->rxbuf);
 748out_txbuf:
 749        vfree(server->txbuf);
 750out_packet:
 751        vfree(server->packet);
 752out_nls:
 753#ifdef CONFIG_NCPFS_NLS
 754        unload_nls(server->nls_io);
 755        unload_nls(server->nls_vol);
 756#endif
 757        mutex_destroy(&server->rcv.creq_mutex);
 758        mutex_destroy(&server->root_setup_lock);
 759        mutex_destroy(&server->mutex);
 760out_fput2:
 761        if (server->info_filp)
 762                fput(server->info_filp);
 763out_bdi:
 764        bdi_destroy(&server->bdi);
 765out_fput:
 766        /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
 767         * 
 768         * The previously used put_filp(ncp_filp); was bogus, since
 769         * it doesn't perform proper unlocking.
 770         */
 771        fput(ncp_filp);
 772out:
 773        put_pid(data.wdog_pid);
 774        sb->s_fs_info = NULL;
 775        kfree(server);
 776        return error;
 777}
 778
 779static void ncp_put_super(struct super_block *sb)
 780{
 781        struct ncp_server *server = NCP_SBP(sb);
 782
 783        ncp_lock_server(server);
 784        ncp_disconnect(server);
 785        ncp_unlock_server(server);
 786
 787        ncp_stop_tasks(server);
 788
 789#ifdef CONFIG_NCPFS_NLS
 790        /* unload the NLS charsets */
 791        unload_nls(server->nls_vol);
 792        unload_nls(server->nls_io);
 793#endif /* CONFIG_NCPFS_NLS */
 794        mutex_destroy(&server->rcv.creq_mutex);
 795        mutex_destroy(&server->root_setup_lock);
 796        mutex_destroy(&server->mutex);
 797
 798        if (server->info_filp)
 799                fput(server->info_filp);
 800        fput(server->ncp_filp);
 801        kill_pid(server->m.wdog_pid, SIGTERM, 1);
 802        put_pid(server->m.wdog_pid);
 803
 804        bdi_destroy(&server->bdi);
 805        kfree(server->priv.data);
 806        kfree(server->auth.object_name);
 807        vfree(server->rxbuf);
 808        vfree(server->txbuf);
 809        vfree(server->packet);
 810        sb->s_fs_info = NULL;
 811        kfree(server);
 812}
 813
 814static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
 815{
 816        struct dentry* d;
 817        struct inode* i;
 818        struct ncp_inode_info* ni;
 819        struct ncp_server* s;
 820        struct ncp_volume_info vi;
 821        struct super_block *sb = dentry->d_sb;
 822        int err;
 823        __u8 dh;
 824        
 825        d = sb->s_root;
 826        if (!d) {
 827                goto dflt;
 828        }
 829        i = d->d_inode;
 830        if (!i) {
 831                goto dflt;
 832        }
 833        ni = NCP_FINFO(i);
 834        if (!ni) {
 835                goto dflt;
 836        }
 837        s = NCP_SBP(sb);
 838        if (!s) {
 839                goto dflt;
 840        }
 841        if (!s->m.mounted_vol[0]) {
 842                goto dflt;
 843        }
 844
 845        err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
 846        if (err) {
 847                goto dflt;
 848        }
 849        err = ncp_get_directory_info(s, dh, &vi);
 850        ncp_dirhandle_free(s, dh);
 851        if (err) {
 852                goto dflt;
 853        }
 854        buf->f_type = NCP_SUPER_MAGIC;
 855        buf->f_bsize = vi.sectors_per_block * 512;
 856        buf->f_blocks = vi.total_blocks;
 857        buf->f_bfree = vi.free_blocks;
 858        buf->f_bavail = vi.free_blocks;
 859        buf->f_files = vi.total_dir_entries;
 860        buf->f_ffree = vi.available_dir_entries;
 861        buf->f_namelen = 12;
 862        return 0;
 863
 864        /* We cannot say how much disk space is left on a mounted
 865           NetWare Server, because free space is distributed over
 866           volumes, and the current user might have disk quotas. So
 867           free space is not that simple to determine. Our decision
 868           here is to err conservatively. */
 869
 870dflt:;
 871        buf->f_type = NCP_SUPER_MAGIC;
 872        buf->f_bsize = NCP_BLOCK_SIZE;
 873        buf->f_blocks = 0;
 874        buf->f_bfree = 0;
 875        buf->f_bavail = 0;
 876        buf->f_namelen = 12;
 877        return 0;
 878}
 879
 880int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
 881{
 882        struct inode *inode = dentry->d_inode;
 883        int result = 0;
 884        __le32 info_mask;
 885        struct nw_modify_dos_info info;
 886        struct ncp_server *server;
 887
 888        result = -EIO;
 889
 890        server = NCP_SERVER(inode);
 891        if (!server)    /* How this could happen? */
 892                goto out;
 893
 894        /* ageing the dentry to force validation */
 895        ncp_age_dentry(server, dentry);
 896
 897        result = inode_change_ok(inode, attr);
 898        if (result < 0)
 899                goto out;
 900
 901        result = -EPERM;
 902        if ((attr->ia_valid & ATTR_UID) && !uid_eq(attr->ia_uid, server->m.uid))
 903                goto out;
 904
 905        if ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, server->m.gid))
 906                goto out;
 907
 908        if (((attr->ia_valid & ATTR_MODE) &&
 909             (attr->ia_mode &
 910              ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
 911                goto out;
 912
 913        info_mask = 0;
 914        memset(&info, 0, sizeof(info));
 915
 916#if 1 
 917        if ((attr->ia_valid & ATTR_MODE) != 0)
 918        {
 919                umode_t newmode = attr->ia_mode;
 920
 921                info_mask |= DM_ATTRIBUTES;
 922
 923                if (S_ISDIR(inode->i_mode)) {
 924                        newmode &= server->m.dir_mode;
 925                } else {
 926#ifdef CONFIG_NCPFS_EXTRAS                      
 927                        if (server->m.flags & NCP_MOUNT_EXTRAS) {
 928                                /* any non-default execute bit set */
 929                                if (newmode & ~server->m.file_mode & S_IXUGO)
 930                                        info.attributes |= aSHARED | aSYSTEM;
 931                                /* read for group/world and not in default file_mode */
 932                                else if (newmode & ~server->m.file_mode & S_IRUGO)
 933                                        info.attributes |= aSHARED;
 934                        } else
 935#endif
 936                                newmode &= server->m.file_mode;                 
 937                }
 938                if (newmode & S_IWUGO)
 939                        info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
 940                else
 941                        info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
 942
 943#ifdef CONFIG_NCPFS_NFS_NS
 944                if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
 945                        result = ncp_modify_nfs_info(server,
 946                                                     NCP_FINFO(inode)->volNumber,
 947                                                     NCP_FINFO(inode)->dirEntNum,
 948                                                     attr->ia_mode, 0);
 949                        if (result != 0)
 950                                goto out;
 951                        info.attributes &= ~(aSHARED | aSYSTEM);
 952                        {
 953                                /* mark partial success */
 954                                struct iattr tmpattr;
 955                                
 956                                tmpattr.ia_valid = ATTR_MODE;
 957                                tmpattr.ia_mode = attr->ia_mode;
 958
 959                                setattr_copy(inode, &tmpattr);
 960                                mark_inode_dirty(inode);
 961                        }
 962                }
 963#endif
 964        }
 965#endif
 966
 967        /* Do SIZE before attributes, otherwise mtime together with size does not work...
 968         */
 969        if ((attr->ia_valid & ATTR_SIZE) != 0) {
 970                int written;
 971
 972                DPRINTK("ncpfs: trying to change size to %ld\n",
 973                        attr->ia_size);
 974
 975                if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
 976                        result = -EACCES;
 977                        goto out;
 978                }
 979                ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
 980                          attr->ia_size, 0, "", &written);
 981
 982                /* According to ndir, the changes only take effect after
 983                   closing the file */
 984                ncp_inode_close(inode);
 985                result = ncp_make_closed(inode);
 986                if (result)
 987                        goto out;
 988
 989                if (attr->ia_size != i_size_read(inode)) {
 990                        truncate_setsize(inode, attr->ia_size);
 991                        mark_inode_dirty(inode);
 992                }
 993        }
 994        if ((attr->ia_valid & ATTR_CTIME) != 0) {
 995                info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
 996                ncp_date_unix2dos(attr->ia_ctime.tv_sec,
 997                             &info.creationTime, &info.creationDate);
 998        }
 999        if ((attr->ia_valid & ATTR_MTIME) != 0) {
1000                info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
1001                ncp_date_unix2dos(attr->ia_mtime.tv_sec,
1002                                  &info.modifyTime, &info.modifyDate);
1003        }
1004        if ((attr->ia_valid & ATTR_ATIME) != 0) {
1005                __le16 dummy;
1006                info_mask |= (DM_LAST_ACCESS_DATE);
1007                ncp_date_unix2dos(attr->ia_atime.tv_sec,
1008                                  &dummy, &info.lastAccessDate);
1009        }
1010        if (info_mask != 0) {
1011                result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1012                                      inode, info_mask, &info);
1013                if (result != 0) {
1014                        if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1015                                /* NetWare seems not to allow this. I
1016                                   do not know why. So, just tell the
1017                                   user everything went fine. This is
1018                                   a terrible hack, but I do not know
1019                                   how to do this correctly. */
1020                                result = 0;
1021                        } else
1022                                goto out;
1023                }
1024#ifdef CONFIG_NCPFS_STRONG              
1025                if ((!result) && (info_mask & DM_ATTRIBUTES))
1026                        NCP_FINFO(inode)->nwattr = info.attributes;
1027#endif
1028        }
1029        if (result)
1030                goto out;
1031
1032        setattr_copy(inode, attr);
1033        mark_inode_dirty(inode);
1034
1035out:
1036        if (result > 0)
1037                result = -EACCES;
1038        return result;
1039}
1040
1041static struct dentry *ncp_mount(struct file_system_type *fs_type,
1042        int flags, const char *dev_name, void *data)
1043{
1044        return mount_nodev(fs_type, flags, data, ncp_fill_super);
1045}
1046
1047static struct file_system_type ncp_fs_type = {
1048        .owner          = THIS_MODULE,
1049        .name           = "ncpfs",
1050        .mount          = ncp_mount,
1051        .kill_sb        = kill_anon_super,
1052        .fs_flags       = FS_BINARY_MOUNTDATA,
1053};
1054MODULE_ALIAS_FS("ncpfs");
1055
1056static int __init init_ncp_fs(void)
1057{
1058        int err;
1059        DPRINTK("ncpfs: init_ncp_fs called\n");
1060
1061        err = init_inodecache();
1062        if (err)
1063                goto out1;
1064        err = register_filesystem(&ncp_fs_type);
1065        if (err)
1066                goto out;
1067        return 0;
1068out:
1069        destroy_inodecache();
1070out1:
1071        return err;
1072}
1073
1074static void __exit exit_ncp_fs(void)
1075{
1076        DPRINTK("ncpfs: exit_ncp_fs called\n");
1077        unregister_filesystem(&ncp_fs_type);
1078        destroy_inodecache();
1079}
1080
1081module_init(init_ncp_fs)
1082module_exit(exit_ncp_fs)
1083MODULE_LICENSE("GPL");
1084