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