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