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