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