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