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