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        ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n",
 343                dentry, NCP_GET_AGE(dentry));
 344
 345        len = sizeof(__name);
 346        if (ncp_is_server_root(dir)) {
 347                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 348                                 dentry->d_name.len, 1);
 349                if (!res) {
 350                        res = ncp_lookup_volume(server, __name, &(finfo.i));
 351                        if (!res)
 352                                ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
 353                }
 354        } else {
 355                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 356                                 dentry->d_name.len, !ncp_preserve_case(dir));
 357                if (!res)
 358                        res = ncp_obtain_info(server, dir, __name, &(finfo.i));
 359        }
 360        finfo.volume = finfo.i.volNumber;
 361        ncp_dbg(2, "looked for %pd/%s, res=%d\n",
 362                dentry->d_parent, __name, res);
 363        /*
 364         * If we didn't find it, or if it has a different dirEntNum to
 365         * what we remember, it's not valid any more.
 366         */
 367        if (!res) {
 368                struct inode *inode = dentry->d_inode;
 369
 370                mutex_lock(&inode->i_mutex);
 371                if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
 372                        ncp_new_dentry(dentry);
 373                        val=1;
 374                } else
 375                        ncp_dbg(2, "found, but dirEntNum changed\n");
 376
 377                ncp_update_inode2(inode, &finfo);
 378                mutex_unlock(&inode->i_mutex);
 379        }
 380
 381finished:
 382        ncp_dbg(2, "result=%d\n", val);
 383        dput(parent);
 384        return val;
 385}
 386
 387static struct dentry *
 388ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
 389{
 390        struct dentry *dent = dentry;
 391
 392        if (d_validate(dent, parent)) {
 393                if (dent->d_name.len <= NCP_MAXPATHLEN &&
 394                    (unsigned long)dent->d_fsdata == fpos) {
 395                        if (!dent->d_inode) {
 396                                dput(dent);
 397                                dent = NULL;
 398                        }
 399                        return dent;
 400                }
 401                dput(dent);
 402        }
 403
 404        /* If a pointer is invalid, we search the dentry. */
 405        spin_lock(&parent->d_lock);
 406        list_for_each_entry(dent, &parent->d_subdirs, d_u.d_child) {
 407                if ((unsigned long)dent->d_fsdata == fpos) {
 408                        if (dent->d_inode)
 409                                dget(dent);
 410                        else
 411                                dent = NULL;
 412                        spin_unlock(&parent->d_lock);
 413                        goto out;
 414                }
 415        }
 416        spin_unlock(&parent->d_lock);
 417        return NULL;
 418
 419out:
 420        return dent;
 421}
 422
 423static time_t ncp_obtain_mtime(struct dentry *dentry)
 424{
 425        struct inode *inode = dentry->d_inode;
 426        struct ncp_server *server = NCP_SERVER(inode);
 427        struct nw_info_struct i;
 428
 429        if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
 430                return 0;
 431
 432        if (ncp_obtain_info(server, inode, NULL, &i))
 433                return 0;
 434
 435        return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
 436}
 437
 438static int ncp_readdir(struct file *file, struct dir_context *ctx)
 439{
 440        struct dentry *dentry = file->f_path.dentry;
 441        struct inode *inode = dentry->d_inode;
 442        struct page *page = NULL;
 443        struct ncp_server *server = NCP_SERVER(inode);
 444        union  ncp_dir_cache *cache = NULL;
 445        struct ncp_cache_control ctl;
 446        int result, mtime_valid = 0;
 447        time_t mtime = 0;
 448
 449        ctl.page  = NULL;
 450        ctl.cache = NULL;
 451
 452        ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
 453
 454        result = -EIO;
 455        /* Do not generate '.' and '..' when server is dead. */
 456        if (!ncp_conn_valid(server))
 457                goto out;
 458
 459        result = 0;
 460        if (!dir_emit_dots(file, ctx))
 461                goto out;
 462
 463        page = grab_cache_page(&inode->i_data, 0);
 464        if (!page)
 465                goto read_really;
 466
 467        ctl.cache = cache = kmap(page);
 468        ctl.head  = cache->head;
 469
 470        if (!PageUptodate(page) || !ctl.head.eof)
 471                goto init_cache;
 472
 473        if (ctx->pos == 2) {
 474                if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
 475                        goto init_cache;
 476
 477                mtime = ncp_obtain_mtime(dentry);
 478                mtime_valid = 1;
 479                if ((!mtime) || (mtime != ctl.head.mtime))
 480                        goto init_cache;
 481        }
 482
 483        if (ctx->pos > ctl.head.end)
 484                goto finished;
 485
 486        ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
 487        ctl.ofs  = ctl.fpos / NCP_DIRCACHE_SIZE;
 488        ctl.idx  = ctl.fpos % NCP_DIRCACHE_SIZE;
 489
 490        for (;;) {
 491                if (ctl.ofs != 0) {
 492                        ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
 493                        if (!ctl.page)
 494                                goto invalid_cache;
 495                        ctl.cache = kmap(ctl.page);
 496                        if (!PageUptodate(ctl.page))
 497                                goto invalid_cache;
 498                }
 499                while (ctl.idx < NCP_DIRCACHE_SIZE) {
 500                        struct dentry *dent;
 501                        bool over;
 502
 503                        dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
 504                                                dentry, ctx->pos);
 505                        if (!dent)
 506                                goto invalid_cache;
 507                        over = !dir_emit(ctx, dent->d_name.name,
 508                                        dent->d_name.len,
 509                                        dent->d_inode->i_ino, DT_UNKNOWN);
 510                        dput(dent);
 511                        if (over)
 512                                goto finished;
 513                        ctx->pos += 1;
 514                        ctl.idx += 1;
 515                        if (ctx->pos > ctl.head.end)
 516                                goto finished;
 517                }
 518                if (ctl.page) {
 519                        kunmap(ctl.page);
 520                        SetPageUptodate(ctl.page);
 521                        unlock_page(ctl.page);
 522                        page_cache_release(ctl.page);
 523                        ctl.page = NULL;
 524                }
 525                ctl.idx  = 0;
 526                ctl.ofs += 1;
 527        }
 528invalid_cache:
 529        if (ctl.page) {
 530                kunmap(ctl.page);
 531                unlock_page(ctl.page);
 532                page_cache_release(ctl.page);
 533                ctl.page = NULL;
 534        }
 535        ctl.cache = cache;
 536init_cache:
 537        ncp_invalidate_dircache_entries(dentry);
 538        if (!mtime_valid) {
 539                mtime = ncp_obtain_mtime(dentry);
 540                mtime_valid = 1;
 541        }
 542        ctl.head.mtime = mtime;
 543        ctl.head.time = jiffies;
 544        ctl.head.eof = 0;
 545        ctl.fpos = 2;
 546        ctl.ofs = 0;
 547        ctl.idx = NCP_DIRCACHE_START;
 548        ctl.filled = 0;
 549        ctl.valid  = 1;
 550read_really:
 551        if (ncp_is_server_root(inode)) {
 552                ncp_read_volume_list(file, ctx, &ctl);
 553        } else {
 554                ncp_do_readdir(file, ctx, &ctl);
 555        }
 556        ctl.head.end = ctl.fpos - 1;
 557        ctl.head.eof = ctl.valid;
 558finished:
 559        if (ctl.page) {
 560                kunmap(ctl.page);
 561                SetPageUptodate(ctl.page);
 562                unlock_page(ctl.page);
 563                page_cache_release(ctl.page);
 564        }
 565        if (page) {
 566                cache->head = ctl.head;
 567                kunmap(page);
 568                SetPageUptodate(page);
 569                unlock_page(page);
 570                page_cache_release(page);
 571        }
 572out:
 573        return result;
 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 = dentry->d_inode;
 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 (unlikely(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 (!newdent->d_inode) {
 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                }
 634        } else {
 635                struct inode *inode = newdent->d_inode;
 636
 637                mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
 638                ncp_update_inode2(inode, entry);
 639                mutex_unlock(&inode->i_mutex);
 640        }
 641
 642        if (newdent->d_inode) {
 643                ino = newdent->d_inode->i_ino;
 644                newdent->d_fsdata = (void *) ctl.fpos;
 645                ncp_new_dentry(newdent);
 646        }
 647
 648        if (ctl.idx >= NCP_DIRCACHE_SIZE) {
 649                if (ctl.page) {
 650                        kunmap(ctl.page);
 651                        SetPageUptodate(ctl.page);
 652                        unlock_page(ctl.page);
 653                        page_cache_release(ctl.page);
 654                }
 655                ctl.cache = NULL;
 656                ctl.idx  -= NCP_DIRCACHE_SIZE;
 657                ctl.ofs  += 1;
 658                ctl.page  = grab_cache_page(&dir->i_data, ctl.ofs);
 659                if (ctl.page)
 660                        ctl.cache = kmap(ctl.page);
 661        }
 662        if (ctl.cache) {
 663                ctl.cache->dentry[ctl.idx] = newdent;
 664                valid = 1;
 665        }
 666        dput(newdent);
 667end_advance:
 668        if (!valid)
 669                ctl.valid = 0;
 670        if (!ctl.filled && (ctl.fpos == ctx->pos)) {
 671                if (!ino)
 672                        ino = iunique(dir->i_sb, 2);
 673                ctl.filled = !dir_emit(ctx, qname.name, qname.len,
 674                                     ino, DT_UNKNOWN);
 675                if (!ctl.filled)
 676                        ctx->pos += 1;
 677        }
 678        ctl.fpos += 1;
 679        ctl.idx  += 1;
 680        *ctrl = ctl;
 681        return (ctl.valid || !ctl.filled);
 682}
 683
 684static void
 685ncp_read_volume_list(struct file *file, struct dir_context *ctx,
 686                        struct ncp_cache_control *ctl)
 687{
 688        struct dentry *dentry = file->f_path.dentry;
 689        struct inode *inode = dentry->d_inode;
 690        struct ncp_server *server = NCP_SERVER(inode);
 691        struct ncp_volume_info info;
 692        struct ncp_entry_info entry;
 693        int i;
 694
 695        ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
 696
 697        for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
 698                int inval_dentry;
 699
 700                if (ncp_get_volume_info_with_number(server, i, &info) != 0)
 701                        return;
 702                if (!strlen(info.volume_name))
 703                        continue;
 704
 705                ncp_dbg(1, "found vol: %s\n", info.volume_name);
 706
 707                if (ncp_lookup_volume(server, info.volume_name,
 708                                        &entry.i)) {
 709                        ncp_dbg(1, "could not lookup vol %s\n",
 710                                info.volume_name);
 711                        continue;
 712                }
 713                inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
 714                entry.volume = entry.i.volNumber;
 715                if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
 716                        return;
 717        }
 718}
 719
 720static void
 721ncp_do_readdir(struct file *file, struct dir_context *ctx,
 722                                                struct ncp_cache_control *ctl)
 723{
 724        struct dentry *dentry = file->f_path.dentry;
 725        struct inode *dir = dentry->d_inode;
 726        struct ncp_server *server = NCP_SERVER(dir);
 727        struct nw_search_sequence seq;
 728        struct ncp_entry_info entry;
 729        int err;
 730        void* buf;
 731        int more;
 732        size_t bufsize;
 733
 734        ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
 735        ncp_vdbg("init %pD, volnum=%d, dirent=%u\n",
 736                 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
 737
 738        err = ncp_initialize_search(server, dir, &seq);
 739        if (err) {
 740                ncp_dbg(1, "init failed, err=%d\n", err);
 741                return;
 742        }
 743        /* We MUST NOT use server->buffer_size handshaked with server if we are
 744           using UDP, as for UDP server uses max. buffer size determined by
 745           MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). 
 746           So we use 128KB, just to be sure, as there is no way how to know
 747           this value in advance. */
 748        bufsize = 131072;
 749        buf = vmalloc(bufsize);
 750        if (!buf)
 751                return;
 752        do {
 753                int cnt;
 754                char* rpl;
 755                size_t rpls;
 756
 757                err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
 758                if (err)                /* Error */
 759                        break;
 760                if (!cnt)               /* prevent endless loop */
 761                        break;
 762                while (cnt--) {
 763                        size_t onerpl;
 764                        
 765                        if (rpls < offsetof(struct nw_info_struct, entryName))
 766                                break;  /* short packet */
 767                        ncp_extract_file_info(rpl, &entry.i);
 768                        onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
 769                        if (rpls < onerpl)
 770                                break;  /* short packet */
 771                        (void)ncp_obtain_nfs_info(server, &entry.i);
 772                        rpl += onerpl;
 773                        rpls -= onerpl;
 774                        entry.volume = entry.i.volNumber;
 775                        if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
 776                                break;
 777                }
 778        } while (more);
 779        vfree(buf);
 780        return;
 781}
 782
 783int ncp_conn_logged_in(struct super_block *sb)
 784{
 785        struct ncp_server* server = NCP_SBP(sb);
 786        int result;
 787
 788        if (ncp_single_volume(server)) {
 789                int len;
 790                struct dentry* dent;
 791                __u32 volNumber;
 792                __le32 dirEntNum;
 793                __le32 DosDirNum;
 794                __u8 __name[NCP_MAXPATHLEN + 1];
 795
 796                len = sizeof(__name);
 797                result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
 798                                    strlen(server->m.mounted_vol), 1);
 799                if (result)
 800                        goto out;
 801                result = -ENOENT;
 802                if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
 803                        ncp_vdbg("%s not found\n", server->m.mounted_vol);
 804                        goto out;
 805                }
 806                dent = sb->s_root;
 807                if (dent) {
 808                        struct inode* ino = dent->d_inode;
 809                        if (ino) {
 810                                ncp_update_known_namespace(server, volNumber, NULL);
 811                                NCP_FINFO(ino)->volNumber = volNumber;
 812                                NCP_FINFO(ino)->dirEntNum = dirEntNum;
 813                                NCP_FINFO(ino)->DosDirNum = DosDirNum;
 814                                result = 0;
 815                        } else {
 816                                ncp_dbg(1, "sb->s_root->d_inode == NULL!\n");
 817                        }
 818                } else {
 819                        ncp_dbg(1, "sb->s_root == NULL!\n");
 820                }
 821        } else
 822                result = 0;
 823
 824out:
 825        return result;
 826}
 827
 828static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 829{
 830        struct ncp_server *server = NCP_SERVER(dir);
 831        struct inode *inode = NULL;
 832        struct ncp_entry_info finfo;
 833        int error, res, len;
 834        __u8 __name[NCP_MAXPATHLEN + 1];
 835
 836        error = -EIO;
 837        if (!ncp_conn_valid(server))
 838                goto finished;
 839
 840        ncp_vdbg("server lookup for %pd2\n", dentry);
 841
 842        len = sizeof(__name);
 843        if (ncp_is_server_root(dir)) {
 844                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 845                                 dentry->d_name.len, 1);
 846                if (!res)
 847                        res = ncp_lookup_volume(server, __name, &(finfo.i));
 848                if (!res)
 849                        ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
 850        } else {
 851                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 852                                 dentry->d_name.len, !ncp_preserve_case(dir));
 853                if (!res)
 854                        res = ncp_obtain_info(server, dir, __name, &(finfo.i));
 855        }
 856        ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
 857        /*
 858         * If we didn't find an entry, make a negative dentry.
 859         */
 860        if (res)
 861                goto add_entry;
 862
 863        /*
 864         * Create an inode for the entry.
 865         */
 866        finfo.opened = 0;
 867        finfo.ino = iunique(dir->i_sb, 2);
 868        finfo.volume = finfo.i.volNumber;
 869        error = -EACCES;
 870        inode = ncp_iget(dir->i_sb, &finfo);
 871
 872        if (inode) {
 873                ncp_new_dentry(dentry);
 874add_entry:
 875                d_add(dentry, inode);
 876                error = 0;
 877        }
 878
 879finished:
 880        ncp_vdbg("result=%d\n", error);
 881        return ERR_PTR(error);
 882}
 883
 884/*
 885 * This code is common to create, mkdir, and mknod.
 886 */
 887static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
 888                        struct ncp_entry_info *finfo)
 889{
 890        struct inode *inode;
 891        int error = -EINVAL;
 892
 893        finfo->ino = iunique(dir->i_sb, 2);
 894        inode = ncp_iget(dir->i_sb, finfo);
 895        if (!inode)
 896                goto out_close;
 897        d_instantiate(dentry,inode);
 898        error = 0;
 899out:
 900        return error;
 901
 902out_close:
 903        ncp_vdbg("%pd2 failed, closing file\n", dentry);
 904        ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
 905        goto out;
 906}
 907
 908int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
 909                   dev_t rdev, __le32 attributes)
 910{
 911        struct ncp_server *server = NCP_SERVER(dir);
 912        struct ncp_entry_info finfo;
 913        int error, result, len;
 914        int opmode;
 915        __u8 __name[NCP_MAXPATHLEN + 1];
 916        
 917        ncp_vdbg("creating %pd2, mode=%hx\n", dentry, mode);
 918
 919        ncp_age_dentry(server, dentry);
 920        len = sizeof(__name);
 921        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 922                           dentry->d_name.len, !ncp_preserve_case(dir));
 923        if (error)
 924                goto out;
 925
 926        error = -EACCES;
 927        
 928        if (S_ISREG(mode) && 
 929            (server->m.flags & NCP_MOUNT_EXTRAS) && 
 930            (mode & S_IXUGO))
 931                attributes |= aSYSTEM | aSHARED;
 932        
 933        result = ncp_open_create_file_or_subdir(server, dir, __name,
 934                                OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
 935                                attributes, AR_READ | AR_WRITE, &finfo);
 936        opmode = O_RDWR;
 937        if (result) {
 938                result = ncp_open_create_file_or_subdir(server, dir, __name,
 939                                OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
 940                                attributes, AR_WRITE, &finfo);
 941                if (result) {
 942                        if (result == 0x87)
 943                                error = -ENAMETOOLONG;
 944                        else if (result < 0)
 945                                error = result;
 946                        ncp_dbg(1, "%pd2 failed\n", dentry);
 947                        goto out;
 948                }
 949                opmode = O_WRONLY;
 950        }
 951        finfo.access = opmode;
 952        if (ncp_is_nfs_extras(server, finfo.volume)) {
 953                finfo.i.nfs.mode = mode;
 954                finfo.i.nfs.rdev = new_encode_dev(rdev);
 955                if (ncp_modify_nfs_info(server, finfo.volume,
 956                                        finfo.i.dirEntNum,
 957                                        mode, new_encode_dev(rdev)) != 0)
 958                        goto out;
 959        }
 960
 961        error = ncp_instantiate(dir, dentry, &finfo);
 962out:
 963        return error;
 964}
 965
 966static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 967                bool excl)
 968{
 969        return ncp_create_new(dir, dentry, mode, 0, 0);
 970}
 971
 972static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 973{
 974        struct ncp_entry_info finfo;
 975        struct ncp_server *server = NCP_SERVER(dir);
 976        int error, len;
 977        __u8 __name[NCP_MAXPATHLEN + 1];
 978
 979        ncp_dbg(1, "making %pd2\n", dentry);
 980
 981        ncp_age_dentry(server, dentry);
 982        len = sizeof(__name);
 983        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
 984                           dentry->d_name.len, !ncp_preserve_case(dir));
 985        if (error)
 986                goto out;
 987
 988        error = ncp_open_create_file_or_subdir(server, dir, __name,
 989                                           OC_MODE_CREATE, aDIR,
 990                                           cpu_to_le16(0xffff),
 991                                           &finfo);
 992        if (error == 0) {
 993                if (ncp_is_nfs_extras(server, finfo.volume)) {
 994                        mode |= S_IFDIR;
 995                        finfo.i.nfs.mode = mode;
 996                        if (ncp_modify_nfs_info(server,
 997                                                finfo.volume,
 998                                                finfo.i.dirEntNum,
 999                                                mode, 0) != 0)
1000                                goto out;
1001                }
1002                error = ncp_instantiate(dir, dentry, &finfo);
1003        } else if (error > 0) {
1004                error = -EACCES;
1005        }
1006out:
1007        return error;
1008}
1009
1010static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1011{
1012        struct ncp_server *server = NCP_SERVER(dir);
1013        int error, result, len;
1014        __u8 __name[NCP_MAXPATHLEN + 1];
1015
1016        ncp_dbg(1, "removing %pd2\n", dentry);
1017
1018        len = sizeof(__name);
1019        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1020                           dentry->d_name.len, !ncp_preserve_case(dir));
1021        if (error)
1022                goto out;
1023
1024        result = ncp_del_file_or_subdir(server, dir, __name);
1025        switch (result) {
1026                case 0x00:
1027                        error = 0;
1028                        break;
1029                case 0x85:      /* unauthorized to delete file */
1030                case 0x8A:      /* unauthorized to delete file */
1031                        error = -EACCES;
1032                        break;
1033                case 0x8F:
1034                case 0x90:      /* read only */
1035                        error = -EPERM;
1036                        break;
1037                case 0x9F:      /* in use by another client */
1038                        error = -EBUSY;
1039                        break;
1040                case 0xA0:      /* directory not empty */
1041                        error = -ENOTEMPTY;
1042                        break;
1043                case 0xFF:      /* someone deleted file */
1044                        error = -ENOENT;
1045                        break;
1046                default:
1047                        error = result < 0 ? result : -EACCES;
1048                        break;
1049        }
1050out:
1051        return error;
1052}
1053
1054static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1055{
1056        struct inode *inode = dentry->d_inode;
1057        struct ncp_server *server;
1058        int error;
1059
1060        server = NCP_SERVER(dir);
1061        ncp_dbg(1, "unlinking %pd2\n", dentry);
1062        
1063        /*
1064         * Check whether to close the file ...
1065         */
1066        if (inode) {
1067                ncp_vdbg("closing file\n");
1068                ncp_make_closed(inode);
1069        }
1070
1071        error = ncp_del_file_or_subdir2(server, dentry);
1072#ifdef CONFIG_NCPFS_STRONG
1073        /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1074           it is not :-( */
1075        if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1076                error = ncp_force_unlink(dir, dentry);
1077        }
1078#endif
1079        switch (error) {
1080                case 0x00:
1081                        ncp_dbg(1, "removed %pd2\n", dentry);
1082                        break;
1083                case 0x85:
1084                case 0x8A:
1085                        error = -EACCES;
1086                        break;
1087                case 0x8D:      /* some files in use */
1088                case 0x8E:      /* all files in use */
1089                        error = -EBUSY;
1090                        break;
1091                case 0x8F:      /* some read only */
1092                case 0x90:      /* all read only */
1093                case 0x9C:      /* !!! returned when in-use or read-only by NW4 */
1094                        error = -EPERM;
1095                        break;
1096                case 0xFF:
1097                        error = -ENOENT;
1098                        break;
1099                default:
1100                        error = error < 0 ? error : -EACCES;
1101                        break;
1102        }
1103        return error;
1104}
1105
1106static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1107                      struct inode *new_dir, struct dentry *new_dentry)
1108{
1109        struct ncp_server *server = NCP_SERVER(old_dir);
1110        int error;
1111        int old_len, new_len;
1112        __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1113
1114        ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
1115
1116        ncp_age_dentry(server, old_dentry);
1117        ncp_age_dentry(server, new_dentry);
1118
1119        old_len = sizeof(__old_name);
1120        error = ncp_io2vol(server, __old_name, &old_len,
1121                           old_dentry->d_name.name, old_dentry->d_name.len,
1122                           !ncp_preserve_case(old_dir));
1123        if (error)
1124                goto out;
1125
1126        new_len = sizeof(__new_name);
1127        error = ncp_io2vol(server, __new_name, &new_len,
1128                           new_dentry->d_name.name, new_dentry->d_name.len,
1129                           !ncp_preserve_case(new_dir));
1130        if (error)
1131                goto out;
1132
1133        error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1134                                                      new_dir, __new_name);
1135#ifdef CONFIG_NCPFS_STRONG
1136        if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1137                        server->m.flags & NCP_MOUNT_STRONG) {   /* RO */
1138                error = ncp_force_rename(old_dir, old_dentry, __old_name,
1139                                         new_dir, new_dentry, __new_name);
1140        }
1141#endif
1142        switch (error) {
1143                case 0x00:
1144                        ncp_dbg(1, "renamed %pd -> %pd\n",
1145                                old_dentry, new_dentry);
1146                        break;
1147                case 0x9E:
1148                        error = -ENAMETOOLONG;
1149                        break;
1150                case 0xFF:
1151                        error = -ENOENT;
1152                        break;
1153                default:
1154                        error = error < 0 ? error : -EACCES;
1155                        break;
1156        }
1157out:
1158        return error;
1159}
1160
1161static int ncp_mknod(struct inode * dir, struct dentry *dentry,
1162                     umode_t mode, dev_t rdev)
1163{
1164        if (!new_valid_dev(rdev))
1165                return -EINVAL;
1166        if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
1167                ncp_dbg(1, "mode = 0%ho\n", mode);
1168                return ncp_create_new(dir, dentry, mode, rdev, 0);
1169        }
1170        return -EPERM; /* Strange, but true */
1171}
1172
1173/* The following routines are taken directly from msdos-fs */
1174
1175/* Linear day numbers of the respective 1sts in non-leap years. */
1176
1177static int day_n[] =
1178{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1179/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1180
1181static int utc2local(int time)
1182{
1183        return time - sys_tz.tz_minuteswest * 60;
1184}
1185
1186static int local2utc(int time)
1187{
1188        return time + sys_tz.tz_minuteswest * 60;
1189}
1190
1191/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1192int
1193ncp_date_dos2unix(__le16 t, __le16 d)
1194{
1195        unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1196        int month, year, secs;
1197
1198        /* first subtract and mask after that... Otherwise, if
1199           date == 0, bad things happen */
1200        month = ((date >> 5) - 1) & 15;
1201        year = date >> 9;
1202        secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1203                86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + 
1204                year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1205        /* days since 1.1.70 plus 80's leap day */
1206        return local2utc(secs);
1207}
1208
1209
1210/* Convert linear UNIX date to a MS-DOS time/date pair. */
1211void
1212ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1213{
1214        int day, year, nl_day, month;
1215
1216        unix_date = utc2local(unix_date);
1217        *time = cpu_to_le16(
1218                (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1219                (((unix_date / 3600) % 24) << 11));
1220        day = unix_date / 86400 - 3652;
1221        year = day / 365;
1222        if ((year + 3) / 4 + 365 * year > day)
1223                year--;
1224        day -= (year + 3) / 4 + 365 * year;
1225        if (day == 59 && !(year & 3)) {
1226                nl_day = day;
1227                month = 2;
1228        } else {
1229                nl_day = (year & 3) || day <= 59 ? day : day - 1;
1230                for (month = 1; month < 12; month++)
1231                        if (day_n[month] > nl_day)
1232                                break;
1233        }
1234        *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1235}
1236