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