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