linux/fs/ncpfs/dir.c
<<
>>
Prefs
   1/*
   2 *  dir.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, 1999 Wolfram Pienkoss for NLS
   8 *  Modified 1999 Wolfram Pienkoss for directory caching
   9 *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
  10 *
  11 */
  12
  13
  14#include <linux/time.h>
  15#include <linux/errno.h>
  16#include <linux/stat.h>
  17#include <linux/kernel.h>
  18#include <linux/vmalloc.h>
  19#include <linux/mm.h>
  20#include <linux/namei.h>
  21#include <asm/uaccess.h>
  22#include <asm/byteorder.h>
  23
  24#include "ncp_fs.h"
  25
  26static void ncp_read_volume_list(struct file *, struct dir_context *,
  27                                struct ncp_cache_control *);
  28static void ncp_do_readdir(struct file *, struct dir_context *,
  29                                struct ncp_cache_control *);
  30
  31static int ncp_readdir(struct file *, struct dir_context *);
  32
  33static int ncp_create(struct inode *, struct dentry *, umode_t, bool);
  34static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int);
  35static int ncp_unlink(struct inode *, struct dentry *);
  36static int ncp_mkdir(struct inode *, struct dentry *, umode_t);
  37static int ncp_rmdir(struct inode *, struct dentry *);
  38static int ncp_rename(struct inode *, struct dentry *,
  39                      struct inode *, struct dentry *);
  40static int ncp_mknod(struct inode * dir, struct dentry *dentry,
  41                     umode_t mode, dev_t rdev);
  42#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
  43extern int ncp_symlink(struct inode *, struct dentry *, const char *);
  44#else
  45#define ncp_symlink NULL
  46#endif
  47                      
  48const struct file_operations ncp_dir_operations =
  49{
  50        .llseek         = generic_file_llseek,
  51        .read           = generic_read_dir,
  52        .iterate        = ncp_readdir,
  53        .unlocked_ioctl = ncp_ioctl,
  54#ifdef CONFIG_COMPAT
  55        .compat_ioctl   = ncp_compat_ioctl,
  56#endif
  57};
  58
  59const struct inode_operations ncp_dir_inode_operations =
  60{
  61        .create         = ncp_create,
  62        .lookup         = ncp_lookup,
  63        .unlink         = ncp_unlink,
  64        .symlink        = ncp_symlink,
  65        .mkdir          = ncp_mkdir,
  66        .rmdir          = ncp_rmdir,
  67        .mknod          = ncp_mknod,
  68        .rename         = ncp_rename,
  69        .setattr        = ncp_notify_change,
  70};
  71
  72/*
  73 * Dentry operations routines
  74 */
  75static int ncp_lookup_validate(struct dentry *, unsigned int);
  76static int ncp_hash_dentry(const struct dentry *, struct qstr *);
  77static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
  78                unsigned int, const char *, const struct qstr *);
  79static int ncp_delete_dentry(const struct dentry *);
  80
  81const struct dentry_operations ncp_dentry_operations =
  82{
  83        .d_revalidate   = ncp_lookup_validate,
  84        .d_hash         = ncp_hash_dentry,
  85        .d_compare      = ncp_compare_dentry,
  86        .d_delete       = ncp_delete_dentry,
  87};
  88
  89#define ncp_namespace(i)        (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
  90
  91static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
  92{
  93#ifdef CONFIG_NCPFS_SMALLDOS
  94        int ns = ncp_namespace(i);
  95
  96        if ((ns == NW_NS_DOS)
  97#ifdef CONFIG_NCPFS_OS2_NS
  98                || ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
  99#endif /* CONFIG_NCPFS_OS2_NS */
 100           )
 101                return 0;
 102#endif /* CONFIG_NCPFS_SMALLDOS */
 103        return 1;
 104}
 105
 106#define ncp_preserve_case(i)    (ncp_namespace(i) != NW_NS_DOS)
 107
 108static inline int ncp_case_sensitive(const struct inode *i)
 109{
 110#ifdef CONFIG_NCPFS_NFS_NS
 111        return ncp_namespace(i) == NW_NS_NFS;
 112#else
 113        return 0;
 114#endif /* CONFIG_NCPFS_NFS_NS */
 115}
 116
 117/*
 118 * Note: leave the hash unchanged if the directory
 119 * is case-sensitive.
 120 *
 121 * Accessing the parent inode can be racy under RCU pathwalking.
 122 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
 123 * the callers will handle races.
 124 */
 125static int 
 126ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
 127{
 128        struct inode *inode = ACCESS_ONCE(dentry->d_inode);
 129
 130        if (!inode)
 131                return 0;
 132
 133        if (!ncp_case_sensitive(inode)) {
 134                struct super_block *sb = dentry->d_sb;
 135                struct nls_table *t;
 136                unsigned long hash;
 137                int i;
 138
 139                t = NCP_IO_TABLE(sb);
 140                hash = init_name_hash();
 141                for (i=0; i<this->len ; i++)
 142                        hash = partial_name_hash(ncp_tolower(t, this->name[i]),
 143                                                                        hash);
 144                this->hash = end_name_hash(hash);
 145        }
 146        return 0;
 147}
 148
 149/*
 150 * Accessing the parent inode can be racy under RCU pathwalking.
 151 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
 152 * the callers will handle races.
 153 */
 154static int
 155ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
 156                unsigned int len, const char *str, const struct qstr *name)
 157{
 158        struct inode *pinode;
 159
 160        if (len != name->len)
 161                return 1;
 162
 163        pinode = ACCESS_ONCE(parent->d_inode);
 164        if (!pinode)
 165                return 1;
 166
 167        if (ncp_case_sensitive(pinode))
 168                return strncmp(str, name->name, len);
 169
 170        return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
 171}
 172
 173/*
 174 * This is the callback from dput() when d_count is going to 0.
 175 * We use this to unhash dentries with bad inodes.
 176 * Closing files can be safely postponed until iput() - it's done there anyway.
 177 */
 178static int
 179ncp_delete_dentry(const struct dentry * dentry)
 180{
 181        struct inode *inode = dentry->d_inode;
 182
 183        if (inode) {
 184                if (is_bad_inode(inode))
 185                        return 1;
 186        } else
 187        {
 188        /* N.B. Unhash negative dentries? */
 189        }
 190        return 0;
 191}
 192
 193static inline int
 194ncp_single_volume(struct ncp_server *server)
 195{
 196        return (server->m.mounted_vol[0] != '\0');
 197}
 198
 199static inline int ncp_is_server_root(struct inode *inode)
 200{
 201        return (!ncp_single_volume(NCP_SERVER(inode)) &&
 202                inode == inode->i_sb->s_root->d_inode);
 203}
 204
 205
 206/*
 207 * This is the callback when the dcache has a lookup hit.
 208 */
 209
 210
 211#ifdef CONFIG_NCPFS_STRONG
 212/* try to delete a readonly file (NW R bit set) */
 213
 214static int
 215ncp_force_unlink(struct inode *dir, struct dentry* dentry)
 216{
 217        int res=0x9c,res2;
 218        struct nw_modify_dos_info info;
 219        __le32 old_nwattr;
 220        struct inode *inode;
 221
 222        memset(&info, 0, sizeof(info));
 223        
 224        /* remove the Read-Only flag on the NW server */
 225        inode = dentry->d_inode;
 226
 227        old_nwattr = NCP_FINFO(inode)->nwattr;
 228        info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
 229        res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
 230        if (res2)
 231                goto leave_me;
 232
 233        /* now try again the delete operation */
 234        res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
 235
 236        if (res)  /* delete failed, set R bit again */
 237        {
 238                info.attributes = old_nwattr;
 239                res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
 240                if (res2)
 241                        goto leave_me;
 242        }
 243leave_me:
 244        return(res);
 245}
 246#endif  /* CONFIG_NCPFS_STRONG */
 247
 248#ifdef CONFIG_NCPFS_STRONG
 249static int
 250ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
 251                 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
 252{
 253        struct nw_modify_dos_info info;
 254        int res=0x90,res2;
 255        struct inode *old_inode = old_dentry->d_inode;
 256        __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
 257        __le32 new_nwattr = 0; /* shut compiler warning */
 258        int old_nwattr_changed = 0;
 259        int new_nwattr_changed = 0;
 260
 261        memset(&info, 0, sizeof(info));
 262        
 263        /* remove the Read-Only flag on the NW server */
 264
 265        info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
 266        res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
 267        if (!res2)
 268                old_nwattr_changed = 1;
 269        if (new_dentry && new_dentry->d_inode) {
 270                new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
 271                info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
 272                res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
 273                if (!res2)
 274                        new_nwattr_changed = 1;
 275        }
 276        /* now try again the rename operation */
 277        /* but only if something really happened */
 278        if (new_nwattr_changed || old_nwattr_changed) {
 279                res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
 280                                                    old_dir, _old_name,
 281                                                    new_dir, _new_name);
 282        } 
 283        if (res)
 284                goto leave_me;
 285        /* file was successfully renamed, so:
 286           do not set attributes on old file - it no longer exists
 287           copy attributes from old file to new */
 288        new_nwattr_changed = old_nwattr_changed;
 289        new_nwattr = old_nwattr;
 290        old_nwattr_changed = 0;
 291        
 292leave_me:;
 293        if (old_nwattr_changed) {
 294                info.attributes = old_nwattr;
 295                res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
 296                /* ignore errors */
 297        }
 298        if (new_nwattr_changed) {
 299                info.attributes = new_nwattr;
 300                res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
 301                /* ignore errors */
 302        }
 303        return(res);
 304}
 305#endif  /* CONFIG_NCPFS_STRONG */
 306
 307
 308static int
 309ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
 310{
 311        struct ncp_server *server;
 312        struct dentry *parent;
 313        struct inode *dir;
 314        struct ncp_entry_info finfo;
 315        int res, val = 0, len;
 316        __u8 __name[NCP_MAXPATHLEN + 1];
 317
 318        if (dentry == dentry->d_sb->s_root)
 319                return 1;
 320
 321        if (flags & LOOKUP_RCU)
 322                return -ECHILD;
 323
 324        parent = dget_parent(dentry);
 325        dir = parent->d_inode;
 326
 327        if (!dentry->d_inode)
 328                goto finished;
 329
 330        server = NCP_SERVER(dir);
 331
 332        /*
 333         * Inspired by smbfs:
 334         * The default validation is based on dentry age:
 335         * We set the max age at mount time.  (But each
 336         * successful server lookup renews the timestamp.)
 337         */
 338        val = NCP_TEST_AGE(server, dentry);
 339        if (val)
 340                goto finished;
 341
 342        DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n",
 343                dentry->d_parent->d_name.name, dentry->d_name.name,
 344                NCP_GET_AGE(dentry));
 345
 346        len = sizeof(__name);
 347        if (ncp_is_server_root(dir)) {
 348                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 349                                 dentry->d_name.len, 1);
 350                if (!res) {
 351                        res = ncp_lookup_volume(server, __name, &(finfo.i));
 352                        if (!res)
 353                                ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
 354                }
 355        } else {
 356                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 357                                 dentry->d_name.len, !ncp_preserve_case(dir));
 358                if (!res)
 359                        res = ncp_obtain_info(server, dir, __name, &(finfo.i));
 360        }
 361        finfo.volume = finfo.i.volNumber;
 362        DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n",
 363                dentry->d_parent->d_name.name, __name, res);
 364        /*
 365         * If we didn't find it, or if it has a different dirEntNum to
 366         * what we remember, it's not valid any more.
 367         */
 368        if (!res) {
 369                struct inode *inode = dentry->d_inode;
 370
 371                mutex_lock(&inode->i_mutex);
 372                if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
 373                        ncp_new_dentry(dentry);
 374                        val=1;
 375                } else
 376                        DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
 377
 378                ncp_update_inode2(inode, &finfo);
 379                mutex_unlock(&inode->i_mutex);
 380        }
 381
 382finished:
 383        DDPRINTK("ncp_lookup_validate: result=%d\n", val);
 384        dput(parent);
 385        return val;
 386}
 387
 388static struct dentry *
 389ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
 390{
 391        struct dentry *dent = dentry;
 392        struct list_head *next;
 393
 394        if (d_validate(dent, parent)) {
 395                if (dent->d_name.len <= NCP_MAXPATHLEN &&
 396                    (unsigned long)dent->d_fsdata == fpos) {
 397                        if (!dent->d_inode) {
 398                                dput(dent);
 399                                dent = NULL;
 400                        }
 401                        return dent;
 402                }
 403                dput(dent);
 404        }
 405
 406        /* If a pointer is invalid, we search the dentry. */
 407        spin_lock(&parent->d_lock);
 408        next = parent->d_subdirs.next;
 409        while (next != &parent->d_subdirs) {
 410                dent = list_entry(next, struct dentry, d_u.d_child);
 411                if ((unsigned long)dent->d_fsdata == fpos) {
 412                        if (dent->d_inode)
 413                                dget(dent);
 414                        else
 415                                dent = NULL;
 416                        spin_unlock(&parent->d_lock);
 417                        goto out;
 418                }
 419                next = next->next;
 420        }
 421        spin_unlock(&parent->d_lock);
 422        return NULL;
 423
 424out:
 425        return dent;
 426}
 427
 428static time_t ncp_obtain_mtime(struct dentry *dentry)
 429{
 430        struct inode *inode = dentry->d_inode;
 431        struct ncp_server *server = NCP_SERVER(inode);
 432        struct nw_info_struct i;
 433
 434        if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
 435                return 0;
 436
 437        if (ncp_obtain_info(server, inode, NULL, &i))
 438                return 0;
 439
 440        return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
 441}
 442
 443static int ncp_readdir(struct file *file, struct dir_context *ctx)
 444{
 445        struct dentry *dentry = file->f_path.dentry;
 446        struct inode *inode = dentry->d_inode;
 447        struct page *page = NULL;
 448        struct ncp_server *server = NCP_SERVER(inode);
 449        union  ncp_dir_cache *cache = NULL;
 450        struct ncp_cache_control ctl;
 451        int result, mtime_valid = 0;
 452        time_t mtime = 0;
 453
 454        ctl.page  = NULL;
 455        ctl.cache = NULL;
 456
 457        DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n",
 458                dentry->d_parent->d_name.name, dentry->d_name.name,
 459                (int) ctx->pos);
 460
 461        result = -EIO;
 462        /* Do not generate '.' and '..' when server is dead. */
 463        if (!ncp_conn_valid(server))
 464                goto out;
 465
 466        result = 0;
 467        if (!dir_emit_dots(file, ctx))
 468                goto out;
 469
 470        page = grab_cache_page(&inode->i_data, 0);
 471        if (!page)
 472                goto read_really;
 473
 474        ctl.cache = cache = kmap(page);
 475        ctl.head  = cache->head;
 476
 477        if (!PageUptodate(page) || !ctl.head.eof)
 478                goto init_cache;
 479
 480        if (ctx->pos == 2) {
 481                if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
 482                        goto init_cache;
 483
 484                mtime = ncp_obtain_mtime(dentry);
 485                mtime_valid = 1;
 486                if ((!mtime) || (mtime != ctl.head.mtime))
 487                        goto init_cache;
 488        }
 489
 490        if (ctx->pos > ctl.head.end)
 491                goto finished;
 492
 493        ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
 494        ctl.ofs  = ctl.fpos / NCP_DIRCACHE_SIZE;
 495        ctl.idx  = ctl.fpos % NCP_DIRCACHE_SIZE;
 496
 497        for (;;) {
 498                if (ctl.ofs != 0) {
 499                        ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
 500                        if (!ctl.page)
 501                                goto invalid_cache;
 502                        ctl.cache = kmap(ctl.page);
 503                        if (!PageUptodate(ctl.page))
 504                                goto invalid_cache;
 505                }
 506                while (ctl.idx < NCP_DIRCACHE_SIZE) {
 507                        struct dentry *dent;
 508                        bool over;
 509
 510                        dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
 511                                                dentry, ctx->pos);
 512                        if (!dent)
 513                                goto invalid_cache;
 514                        over = !dir_emit(ctx, dent->d_name.name,
 515                                        dent->d_name.len,
 516                                        dent->d_inode->i_ino, DT_UNKNOWN);
 517                        dput(dent);
 518                        if (over)
 519                                goto finished;
 520                        ctx->pos += 1;
 521                        ctl.idx += 1;
 522                        if (ctx->pos > ctl.head.end)
 523                                goto finished;
 524                }
 525                if (ctl.page) {
 526                        kunmap(ctl.page);
 527                        SetPageUptodate(ctl.page);
 528                        unlock_page(ctl.page);
 529                        page_cache_release(ctl.page);
 530                        ctl.page = NULL;
 531                }
 532                ctl.idx  = 0;
 533                ctl.ofs += 1;
 534        }
 535invalid_cache:
 536        if (ctl.page) {
 537                kunmap(ctl.page);
 538                unlock_page(ctl.page);
 539                page_cache_release(ctl.page);
 540                ctl.page = NULL;
 541        }
 542        ctl.cache = cache;
 543init_cache:
 544        ncp_invalidate_dircache_entries(dentry);
 545        if (!mtime_valid) {
 546                mtime = ncp_obtain_mtime(dentry);
 547                mtime_valid = 1;
 548        }
 549        ctl.head.mtime = mtime;
 550        ctl.head.time = jiffies;
 551        ctl.head.eof = 0;
 552        ctl.fpos = 2;
 553        ctl.ofs = 0;
 554        ctl.idx = NCP_DIRCACHE_START;
 555        ctl.filled = 0;
 556        ctl.valid  = 1;
 557read_really:
 558        if (ncp_is_server_root(inode)) {
 559                ncp_read_volume_list(file, ctx, &ctl);
 560        } else {
 561                ncp_do_readdir(file, ctx, &ctl);
 562        }
 563        ctl.head.end = ctl.fpos - 1;
 564        ctl.head.eof = ctl.valid;
 565finished:
 566        if (ctl.page) {
 567                kunmap(ctl.page);
 568                SetPageUptodate(ctl.page);
 569                unlock_page(ctl.page);
 570                page_cache_release(ctl.page);
 571        }
 572        if (page) {
 573                cache->head = ctl.head;
 574                kunmap(page);
 575                SetPageUptodate(page);
 576                unlock_page(page);
 577                page_cache_release(page);
 578        }
 579out:
 580        return result;
 581}
 582
 583static int
 584ncp_fill_cache(struct file *file, struct dir_context *ctx,
 585                struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
 586                int inval_childs)
 587{
 588        struct dentry *newdent, *dentry = file->f_path.dentry;
 589        struct inode *dir = dentry->d_inode;
 590        struct ncp_cache_control ctl = *ctrl;
 591        struct qstr qname;
 592        int valid = 0;
 593        int hashed = 0;
 594        ino_t ino = 0;
 595        __u8 __name[NCP_MAXPATHLEN + 1];
 596
 597        qname.len = sizeof(__name);
 598        if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
 599                        entry->i.entryName, entry->i.nameLen,
 600                        !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
 601                return 1; /* I'm not sure */
 602
 603        qname.name = __name;
 604
 605        newdent = d_hash_and_lookup(dentry, &qname);
 606        if (unlikely(IS_ERR(newdent)))
 607                goto end_advance;
 608        if (!newdent) {
 609                newdent = d_alloc(dentry, &qname);
 610                if (!newdent)
 611                        goto end_advance;
 612        } else {
 613                hashed = 1;
 614
 615                /* If case sensitivity changed for this volume, all entries below this one
 616                   should be thrown away.  This entry itself is not affected, as its case
 617                   sensitivity is controlled by its own parent. */
 618                if (inval_childs)
 619                        shrink_dcache_parent(newdent);
 620
 621                /*
 622                 * NetWare's OS2 namespace is case preserving yet case
 623                 * insensitive.  So we update dentry's name as received from
 624                 * server. Parent dir's i_mutex is locked because we're in
 625                 * readdir.
 626                 */
 627                dentry_update_name_case(newdent, &qname);
 628        }
 629
 630        if (!newdent->d_inode) {
 631                struct inode *inode;
 632
 633                entry->opened = 0;
 634                entry->ino = iunique(dir->i_sb, 2);
 635                inode = ncp_iget(dir->i_sb, entry);
 636                if (inode) {
 637                        d_instantiate(newdent, inode);
 638                        if (!hashed)
 639                                d_rehash(newdent);
 640                }
 641        } else {
 642                struct inode *inode = newdent->d_inode;
 643
 644                mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
 645                ncp_update_inode2(inode, entry);
 646                mutex_unlock(&inode->i_mutex);
 647        }
 648
 649        if (newdent->d_inode) {
 650                ino = newdent->d_inode->i_ino;
 651                newdent->d_fsdata = (void *) ctl.fpos;
 652                ncp_new_dentry(newdent);
 653        }
 654
 655        if (ctl.idx >= NCP_DIRCACHE_SIZE) {
 656                if (ctl.page) {
 657                        kunmap(ctl.page);
 658                        SetPageUptodate(ctl.page);
 659                        unlock_page(ctl.page);
 660                        page_cache_release(ctl.page);
 661                }
 662                ctl.cache = NULL;
 663                ctl.idx  -= NCP_DIRCACHE_SIZE;
 664                ctl.ofs  += 1;
 665                ctl.page  = grab_cache_page(&dir->i_data, ctl.ofs);
 666                if (ctl.page)
 667                        ctl.cache = kmap(ctl.page);
 668        }
 669        if (ctl.cache) {
 670                ctl.cache->dentry[ctl.idx] = newdent;
 671                valid = 1;
 672        }
 673        dput(newdent);
 674end_advance:
 675        if (!valid)
 676                ctl.valid = 0;
 677        if (!ctl.filled && (ctl.fpos == ctx->pos)) {
 678                if (!ino)
 679                        ino = iunique(dir->i_sb, 2);
 680                ctl.filled = !dir_emit(ctx, qname.name, qname.len,
 681                                     ino, DT_UNKNOWN);
 682                if (!ctl.filled)
 683                        ctx->pos += 1;
 684        }
 685        ctl.fpos += 1;
 686        ctl.idx  += 1;
 687        *ctrl = ctl;
 688        return (ctl.valid || !ctl.filled);
 689}
 690
 691static void
 692ncp_read_volume_list(struct file *file, struct dir_context *ctx,
 693                        struct ncp_cache_control *ctl)
 694{
 695        struct dentry *dentry = file->f_path.dentry;
 696        struct inode *inode = dentry->d_inode;
 697        struct ncp_server *server = NCP_SERVER(inode);
 698        struct ncp_volume_info info;
 699        struct ncp_entry_info entry;
 700        int i;
 701
 702        DPRINTK("ncp_read_volume_list: pos=%ld\n",
 703                        (unsigned long) ctx->pos);
 704
 705        for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
 706                int inval_dentry;
 707
 708                if (ncp_get_volume_info_with_number(server, i, &info) != 0)
 709                        return;
 710                if (!strlen(info.volume_name))
 711                        continue;
 712
 713                DPRINTK("ncp_read_volume_list: found vol: %s\n",
 714                        info.volume_name);
 715
 716                if (ncp_lookup_volume(server, info.volume_name,
 717                                        &entry.i)) {
 718                        DPRINTK("ncpfs: could not lookup vol %s\n",
 719                                info.volume_name);
 720                        continue;
 721                }
 722                inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
 723                entry.volume = entry.i.volNumber;
 724                if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
 725                        return;
 726        }
 727}
 728
 729static void
 730ncp_do_readdir(struct file *file, struct dir_context *ctx,
 731                                                struct ncp_cache_control *ctl)
 732{
 733        struct dentry *dentry = file->f_path.dentry;
 734        struct inode *dir = dentry->d_inode;
 735        struct ncp_server *server = NCP_SERVER(dir);
 736        struct nw_search_sequence seq;
 737        struct ncp_entry_info entry;
 738        int err;
 739        void* buf;
 740        int more;
 741        size_t bufsize;
 742
 743        DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n",
 744                dentry->d_parent->d_name.name, dentry->d_name.name,
 745                (unsigned long) ctx->pos);
 746        PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
 747                dentry->d_name.name, NCP_FINFO(dir)->volNumber,
 748                NCP_FINFO(dir)->dirEntNum);
 749
 750        err = ncp_initialize_search(server, dir, &seq);
 751        if (err) {
 752                DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
 753                return;
 754        }
 755        /* We MUST NOT use server->buffer_size handshaked with server if we are
 756           using UDP, as for UDP server uses max. buffer size determined by
 757           MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). 
 758           So we use 128KB, just to be sure, as there is no way how to know
 759           this value in advance. */
 760        bufsize = 131072;
 761        buf = vmalloc(bufsize);
 762        if (!buf)
 763                return;
 764        do {
 765                int cnt;
 766                char* rpl;
 767                size_t rpls;
 768
 769                err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
 770                if (err)                /* Error */
 771                        break;
 772                if (!cnt)               /* prevent endless loop */
 773                        break;
 774                while (cnt--) {
 775                        size_t onerpl;
 776                        
 777                        if (rpls < offsetof(struct nw_info_struct, entryName))
 778                                break;  /* short packet */
 779                        ncp_extract_file_info(rpl, &entry.i);
 780                        onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
 781                        if (rpls < onerpl)
 782                                break;  /* short packet */
 783                        (void)ncp_obtain_nfs_info(server, &entry.i);
 784                        rpl += onerpl;
 785                        rpls -= onerpl;
 786                        entry.volume = entry.i.volNumber;
 787                        if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
 788                                break;
 789                }
 790        } while (more);
 791        vfree(buf);
 792        return;
 793}
 794
 795int ncp_conn_logged_in(struct super_block *sb)
 796{
 797        struct ncp_server* server = NCP_SBP(sb);
 798        int result;
 799
 800        if (ncp_single_volume(server)) {
 801                int len;
 802                struct dentry* dent;
 803                __u32 volNumber;
 804                __le32 dirEntNum;
 805                __le32 DosDirNum;
 806                __u8 __name[NCP_MAXPATHLEN + 1];
 807
 808                len = sizeof(__name);
 809                result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
 810                                    strlen(server->m.mounted_vol), 1);
 811                if (result)
 812                        goto out;
 813                result = -ENOENT;
 814                if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
 815                        PPRINTK("ncp_conn_logged_in: %s not found\n",
 816                                server->m.mounted_vol);
 817                        goto out;
 818                }
 819                dent = sb->s_root;
 820                if (dent) {
 821                        struct inode* ino = dent->d_inode;
 822                        if (ino) {
 823                                ncp_update_known_namespace(server, volNumber, NULL);
 824                                NCP_FINFO(ino)->volNumber = volNumber;
 825                                NCP_FINFO(ino)->dirEntNum = dirEntNum;
 826                                NCP_FINFO(ino)->DosDirNum = DosDirNum;
 827                                result = 0;
 828                        } else {
 829                                DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
 830                        }
 831                } else {
 832                        DPRINTK("ncpfs: sb->s_root == NULL!\n");
 833                }
 834        } else
 835                result = 0;
 836
 837out:
 838        return result;
 839}
 840
 841static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 842{
 843        struct ncp_server *server = NCP_SERVER(dir);
 844        struct inode *inode = NULL;
 845        struct ncp_entry_info finfo;
 846        int error, res, len;
 847        __u8 __name[NCP_MAXPATHLEN + 1];
 848
 849        error = -EIO;
 850        if (!ncp_conn_valid(server))
 851                goto finished;
 852
 853        PPRINTK("ncp_lookup: server lookup for %s/%s\n",
 854                dentry->d_parent->d_name.name, dentry->d_name.name);
 855
 856        len = sizeof(__name);
 857        if (ncp_is_server_root(dir)) {
 858                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 859                                 dentry->d_name.len, 1);
 860                if (!res)
 861                        res = ncp_lookup_volume(server, __name, &(finfo.i));
 862                        if (!res)
 863                                ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
 864        } else {
 865                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 866                                 dentry->d_name.len, !ncp_preserve_case(dir));
 867                if (!res)
 868                        res = ncp_obtain_info(server, dir, __name, &(finfo.i));
 869        }
 870        PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n",
 871                dentry->d_parent->d_name.name, __name, res);
 872        /*
 873         * If we didn't find an entry, make a negative dentry.
 874         */
 875        if (res)
 876                goto add_entry;
 877
 878        /*
 879         * Create an inode for the entry.
 880         */
 881        finfo.opened = 0;
 882        finfo.ino = iunique(dir->i_sb, 2);
 883        finfo.volume = finfo.i.volNumber;
 884        error = -EACCES;
 885        inode = ncp_iget(dir->i_sb, &finfo);
 886
 887        if (inode) {
 888                ncp_new_dentry(dentry);
 889add_entry:
 890                d_add(dentry, inode);
 891                error = 0;
 892        }
 893
 894finished:
 895        PPRINTK("ncp_lookup: result=%d\n", error);
 896        return ERR_PTR(error);
 897}
 898
 899/*
 900 * This code is common to create, mkdir, and mknod.
 901 */
 902static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
 903                        struct ncp_entry_info *finfo)
 904{
 905        struct inode *inode;
 906        int error = -EINVAL;
 907
 908        finfo->ino = iunique(dir->i_sb, 2);
 909        inode = ncp_iget(dir->i_sb, finfo);
 910        if (!inode)
 911                goto out_close;
 912        d_instantiate(dentry,inode);
 913        error = 0;
 914out:
 915        return error;
 916
 917out_close:
 918        PPRINTK("ncp_instantiate: %s/%s failed, closing file\n",
 919                dentry->d_parent->d_name.name, dentry->d_name.name);
 920        ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
 921        goto out;
 922}
 923
 924int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
 925                   dev_t rdev, __le32 attributes)
 926{
 927        struct ncp_server *server = NCP_SERVER(dir);
 928        struct ncp_entry_info finfo;
 929        int error, result, len;
 930        int opmode;
 931        __u8 __name[NCP_MAXPATHLEN + 1];
 932        
 933        PPRINTK("ncp_create_new: creating %s/%s, mode=%hx\n",
 934                dentry->d_parent->d_name.name, dentry->d_name.name, mode);
 935
 936        ncp_age_dentry(server, dentry);
 937        len = sizeof(__name);
 938        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 939                           dentry->d_name.len, !ncp_preserve_case(dir));
 940        if (error)
 941                goto out;
 942
 943        error = -EACCES;
 944        
 945        if (S_ISREG(mode) && 
 946            (server->m.flags & NCP_MOUNT_EXTRAS) && 
 947            (mode & S_IXUGO))
 948                attributes |= aSYSTEM | aSHARED;
 949        
 950        result = ncp_open_create_file_or_subdir(server, dir, __name,
 951                                OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
 952                                attributes, AR_READ | AR_WRITE, &finfo);
 953        opmode = O_RDWR;
 954        if (result) {
 955                result = ncp_open_create_file_or_subdir(server, dir, __name,
 956                                OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
 957                                attributes, AR_WRITE, &finfo);
 958                if (result) {
 959                        if (result == 0x87)
 960                                error = -ENAMETOOLONG;
 961                        else if (result < 0)
 962                                error = result;
 963                        DPRINTK("ncp_create: %s/%s failed\n",
 964                                dentry->d_parent->d_name.name, dentry->d_name.name);
 965                        goto out;
 966                }
 967                opmode = O_WRONLY;
 968        }
 969        finfo.access = opmode;
 970        if (ncp_is_nfs_extras(server, finfo.volume)) {
 971                finfo.i.nfs.mode = mode;
 972                finfo.i.nfs.rdev = new_encode_dev(rdev);
 973                if (ncp_modify_nfs_info(server, finfo.volume,
 974                                        finfo.i.dirEntNum,
 975                                        mode, new_encode_dev(rdev)) != 0)
 976                        goto out;
 977        }
 978
 979        error = ncp_instantiate(dir, dentry, &finfo);
 980out:
 981        return error;
 982}
 983
 984static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 985                bool excl)
 986{
 987        return ncp_create_new(dir, dentry, mode, 0, 0);
 988}
 989
 990static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 991{
 992        struct ncp_entry_info finfo;
 993        struct ncp_server *server = NCP_SERVER(dir);
 994        int error, len;
 995        __u8 __name[NCP_MAXPATHLEN + 1];
 996
 997        DPRINTK("ncp_mkdir: making %s/%s\n",
 998                dentry->d_parent->d_name.name, dentry->d_name.name);
 999
1000        ncp_age_dentry(server, dentry);
1001        len = sizeof(__name);
1002        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1003                           dentry->d_name.len, !ncp_preserve_case(dir));
1004        if (error)
1005                goto out;
1006
1007        error = ncp_open_create_file_or_subdir(server, dir, __name,
1008                                           OC_MODE_CREATE, aDIR,
1009                                           cpu_to_le16(0xffff),
1010                                           &finfo);
1011        if (error == 0) {
1012                if (ncp_is_nfs_extras(server, finfo.volume)) {
1013                        mode |= S_IFDIR;
1014                        finfo.i.nfs.mode = mode;
1015                        if (ncp_modify_nfs_info(server,
1016                                                finfo.volume,
1017                                                finfo.i.dirEntNum,
1018                                                mode, 0) != 0)
1019                                goto out;
1020                }
1021                error = ncp_instantiate(dir, dentry, &finfo);
1022        } else if (error > 0) {
1023                error = -EACCES;
1024        }
1025out:
1026        return error;
1027}
1028
1029static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1030{
1031        struct ncp_server *server = NCP_SERVER(dir);
1032        int error, result, len;
1033        __u8 __name[NCP_MAXPATHLEN + 1];
1034
1035        DPRINTK("ncp_rmdir: removing %s/%s\n",
1036                dentry->d_parent->d_name.name, dentry->d_name.name);
1037
1038        len = sizeof(__name);
1039        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1040                           dentry->d_name.len, !ncp_preserve_case(dir));
1041        if (error)
1042                goto out;
1043
1044        result = ncp_del_file_or_subdir(server, dir, __name);
1045        switch (result) {
1046                case 0x00:
1047                        error = 0;
1048                        break;
1049                case 0x85:      /* unauthorized to delete file */
1050                case 0x8A:      /* unauthorized to delete file */
1051                        error = -EACCES;
1052                        break;
1053                case 0x8F:
1054                case 0x90:      /* read only */
1055                        error = -EPERM;
1056                        break;
1057                case 0x9F:      /* in use by another client */
1058                        error = -EBUSY;
1059                        break;
1060                case 0xA0:      /* directory not empty */
1061                        error = -ENOTEMPTY;
1062                        break;
1063                case 0xFF:      /* someone deleted file */
1064                        error = -ENOENT;
1065                        break;
1066                default:
1067                        error = result < 0 ? result : -EACCES;
1068                        break;
1069        }
1070out:
1071        return error;
1072}
1073
1074static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1075{
1076        struct inode *inode = dentry->d_inode;
1077        struct ncp_server *server;
1078        int error;
1079
1080        server = NCP_SERVER(dir);
1081        DPRINTK("ncp_unlink: unlinking %s/%s\n",
1082                dentry->d_parent->d_name.name, dentry->d_name.name);
1083        
1084        /*
1085         * Check whether to close the file ...
1086         */
1087        if (inode) {
1088                PPRINTK("ncp_unlink: closing file\n");
1089                ncp_make_closed(inode);
1090        }
1091
1092        error = ncp_del_file_or_subdir2(server, dentry);
1093#ifdef CONFIG_NCPFS_STRONG
1094        /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1095           it is not :-( */
1096        if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1097                error = ncp_force_unlink(dir, dentry);
1098        }
1099#endif
1100        switch (error) {
1101                case 0x00:
1102                        DPRINTK("ncp: removed %s/%s\n",
1103                                dentry->d_parent->d_name.name, dentry->d_name.name);
1104                        break;
1105                case 0x85:
1106                case 0x8A:
1107                        error = -EACCES;
1108                        break;
1109                case 0x8D:      /* some files in use */
1110                case 0x8E:      /* all files in use */
1111                        error = -EBUSY;
1112                        break;
1113                case 0x8F:      /* some read only */
1114                case 0x90:      /* all read only */
1115                case 0x9C:      /* !!! returned when in-use or read-only by NW4 */
1116                        error = -EPERM;
1117                        break;
1118                case 0xFF:
1119                        error = -ENOENT;
1120                        break;
1121                default:
1122                        error = error < 0 ? error : -EACCES;
1123                        break;
1124        }
1125        return error;
1126}
1127
1128static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1129                      struct inode *new_dir, struct dentry *new_dentry)
1130{
1131        struct ncp_server *server = NCP_SERVER(old_dir);
1132        int error;
1133        int old_len, new_len;
1134        __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1135
1136        DPRINTK("ncp_rename: %s/%s to %s/%s\n",
1137                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
1138                new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
1139
1140        ncp_age_dentry(server, old_dentry);
1141        ncp_age_dentry(server, new_dentry);
1142
1143        old_len = sizeof(__old_name);
1144        error = ncp_io2vol(server, __old_name, &old_len,
1145                           old_dentry->d_name.name, old_dentry->d_name.len,
1146                           !ncp_preserve_case(old_dir));
1147        if (error)
1148                goto out;
1149
1150        new_len = sizeof(__new_name);
1151        error = ncp_io2vol(server, __new_name, &new_len,
1152                           new_dentry->d_name.name, new_dentry->d_name.len,
1153                           !ncp_preserve_case(new_dir));
1154        if (error)
1155                goto out;
1156
1157        error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1158                                                      new_dir, __new_name);
1159#ifdef CONFIG_NCPFS_STRONG
1160        if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1161                        server->m.flags & NCP_MOUNT_STRONG) {   /* RO */
1162                error = ncp_force_rename(old_dir, old_dentry, __old_name,
1163                                         new_dir, new_dentry, __new_name);
1164        }
1165#endif
1166        switch (error) {
1167                case 0x00:
1168                        DPRINTK("ncp renamed %s -> %s.\n",
1169                                old_dentry->d_name.name,new_dentry->d_name.name);
1170                        break;
1171                case 0x9E:
1172                        error = -ENAMETOOLONG;
1173                        break;
1174                case 0xFF:
1175                        error = -ENOENT;
1176                        break;
1177                default:
1178                        error = error < 0 ? error : -EACCES;
1179                        break;
1180        }
1181out:
1182        return error;
1183}
1184
1185static int ncp_mknod(struct inode * dir, struct dentry *dentry,
1186                     umode_t mode, dev_t rdev)
1187{
1188        if (!new_valid_dev(rdev))
1189                return -EINVAL;
1190        if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
1191                DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%ho\n", mode);
1192                return ncp_create_new(dir, dentry, mode, rdev, 0);
1193        }
1194        return -EPERM; /* Strange, but true */
1195}
1196
1197/* The following routines are taken directly from msdos-fs */
1198
1199/* Linear day numbers of the respective 1sts in non-leap years. */
1200
1201static int day_n[] =
1202{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1203/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1204
1205
1206extern struct timezone sys_tz;
1207
1208static int utc2local(int time)
1209{
1210        return time - sys_tz.tz_minuteswest * 60;
1211}
1212
1213static int local2utc(int time)
1214{
1215        return time + sys_tz.tz_minuteswest * 60;
1216}
1217
1218/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1219int
1220ncp_date_dos2unix(__le16 t, __le16 d)
1221{
1222        unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1223        int month, year, secs;
1224
1225        /* first subtract and mask after that... Otherwise, if
1226           date == 0, bad things happen */
1227        month = ((date >> 5) - 1) & 15;
1228        year = date >> 9;
1229        secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1230                86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + 
1231                year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1232        /* days since 1.1.70 plus 80's leap day */
1233        return local2utc(secs);
1234}
1235
1236
1237/* Convert linear UNIX date to a MS-DOS time/date pair. */
1238void
1239ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1240{
1241        int day, year, nl_day, month;
1242
1243        unix_date = utc2local(unix_date);
1244        *time = cpu_to_le16(
1245                (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1246                (((unix_date / 3600) % 24) << 11));
1247        day = unix_date / 86400 - 3652;
1248        year = day / 365;
1249        if ((year + 3) / 4 + 365 * year > day)
1250                year--;
1251        day -= (year + 3) / 4 + 365 * year;
1252        if (day == 59 && !(year & 3)) {
1253                nl_day = day;
1254                month = 2;
1255        } else {
1256                nl_day = (year & 3) || day <= 59 ? day : day - 1;
1257                for (month = 1; month < 12; month++)
1258                        if (day_n[month] > nl_day)
1259                                break;
1260        }
1261        *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1262}
1263