]> git.neil.brown.name Git - history.git/commitdiff
Import 2.2.7pre1 2.2.7pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:18:38 +0000 (15:18 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:18:38 +0000 (15:18 -0500)
34 files changed:
Documentation/Configure.help
Documentation/fb/matroxfb.txt
Makefile
arch/alpha/kernel/time.c
drivers/pci/oldproc.c
drivers/video/matroxfb.c
fs/buffer.c
fs/fat/fatfs_syms.c
fs/fat/inode.c
fs/fat/misc.c
fs/msdos/namei.c
fs/ncpfs/Config.in
fs/ncpfs/Makefile
fs/ncpfs/dir.c
fs/ncpfs/inode.c
fs/ncpfs/ioctl.c
fs/ncpfs/ncplib_kernel.c
fs/ncpfs/ncplib_kernel.h
fs/ncpfs/symlink.c [new file with mode: 0644]
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nls/Config.in
include/asm-i386/bitops.h
include/linux/fs.h
include/linux/msdos_fs.h
include/linux/ncp.h
include/linux/ncp_fs.h
include/linux/ncp_fs_sb.h
include/linux/ncp_mount.h
include/linux/pagemap.h
include/linux/pci.h
init/main.c
mm/page_alloc.c

index b3831df37a62090f153d42cc7ffd81c8aff4a4b8..f4d45319da30308d6a997f60b7e73e75cc4cf71a 100644 (file)
@@ -7443,6 +7443,26 @@ CONFIG_NCPFS_OS2_NS
   case insensitive, and case in names is preserved. Say Y. You can
   disable it at mount time with the -N os2 parameter of ncpmount.
 
+Lowercase DOS filenames on LONG namespace volume
+CONFIG_NCPFS_SMALLDOS
+  Saying Y here will convert every filename with creator/owner DOS
+  namespace on NetWare servers to lowercase characters as silently
+  kernel does when you mount  NetWare file server volumes with DOS
+  namespace without OS2/LONG namespace support. Saying N here will
+  give you these filenames with uppercase characters.
+  
+  This is  only cosmetic option  because of OS2/LONG  namespace is
+  case  insensitive.  The  only major  reason for  this option  is
+  backward  compatibility when  you want  to do  step from  DOS to
+  OS2/LONG  namespace support.  Long filenames  (created by Win95)
+  will not be affected.
+
+  This  option  does not  solve a  problem that  filenames  appear
+  differently  in Linux box  and in MS  environment because  of MS
+  does an additional  conversions on client side.  You can achieve
+  simillar effects  enabling ncpfs  option "Allow  using of Native
+  Language Support" below.
+
 Allow mounting of volume subdirectories
 CONFIG_NCPFS_MOUNT_SUBDIR
   Allows you to mount not only whole servers or whole volumes, but
@@ -7461,6 +7481,25 @@ CONFIG_NCPFS_NDS_DOMAINS
   servers. Do not say Y if security is primary for you because root
   can read your session key (from /proc/kcore).
 
+Allow using of Native Language Support
+CONFIG_NCPFS_NLS
+  Allows you to use codepages and I/O charsets for file name translation
+  between file system on server and input/output. This may be useful,
+  if you want to access to the server with other operating systems,
+  e.g. Windows 95. See also NLS for more Information.
+
+  To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer.
+
+Symbolic links and mode permission bits
+CONFIG_NCPFS_EXTRAS
+  This enables the use of symbolic links and an execute permission
+  bit on NCPFS. The file server need not have long name space or NFS
+  name space loaded for these to work, they are stored using rarely
+  found combinations of Hidden, System and Shared flags.
+
+  To use the new attributes, you are recommended to use the flags
+  '-f 600 -d 755' on the ncpmount commandline.
+  
 nls codepage 437
 CONFIG_NLS_CODEPAGE_437
   The Microsoft fat filesystem family can deal with filenames in
index c7d19ced3cecb1458aafc964995f6950b77635a0..0da3859488e28e64ee8ce5a8a80487be4c5e5511 100644 (file)
@@ -1,6 +1,6 @@
 [This file is cloned from VesaFB. Thanks go to Gerd Knorr]
 
-what is matroxfb?
+What is matroxfb?
 =================
 
 This is a driver for a graphic framebuffer for Matrox devices on
@@ -221,6 +221,8 @@ pixclock:X - dotclocks, in ps (picoseconds). Default is derived from `vesa'
 sync:X   - sync. pulse - bit 0 inverts HSYNC polarity, bit 1 VSYNC polarity.
            If bit 3 (value 0x08) is set, composite sync instead of HSYNC is
           generated. If bit 5 (value 0x20) is set, sync on green is turned on.
+          Do not forget that if you want sync on green, you also probably
+          want composite sync.
           Default depends on `vesa'.
 depth:X  - Bits per pixel: 0=text, 4,8,15,16,24 or 32. Default depends on
            `vesa'.
@@ -284,8 +286,6 @@ And following features:
  + current fbset is not able to set 15bpp videomode: you must specify
    depth==16 and green.length==5. fbset does not allow you to set 
    green.length.
- + hardware cursor is available only in accelerated videomodes. Maybe that
-   this is misfeature and not feature.
  + text mode uses 6 bit VGA palette instead of 8 bit (one of 262144 colors
    instead of one of 16M colors). It is due to hardware limitation of 
    MilleniumI/II and SVGALib compatibility.
index b5777d81336ebd0eb63e6c462b33a3752a67d746..1a123ca5f2edbe4c181a8b7f01d794b0b1bb0116 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 6
+SUBLEVEL = 7
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
index eb48ff5f25da350f866e9ca2e3e094bb8dfc820f..222b8f26fadd07fa1e6bfeee27b63a7e6cfd0cd9 100644 (file)
@@ -18,6 +18,9 @@
  *      fixed tick loss calculation in timer_interrupt
  *      (round system clock to nearest tick instead of truncating)
  *      fixed algorithm in time_init for getting time from CMOS clock
+ * 1999-04-16  Thorsten Kranzkowski (dl8bcu@gmx.net)
+ *     fixed algorithm in do_gettimeofday() for calculating the precise time
+ *     from processor cycle counter (now taking lost_ticks into account)
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -314,8 +317,10 @@ time_init(void)
 void
 do_gettimeofday(struct timeval *tv)
 {
-       unsigned long flags, now, delta_cycles, delta_usec;
+       unsigned long flags, delta_cycles, delta_usec;
        unsigned long sec, usec;
+       __u32 now;
+       extern volatile unsigned long lost_ticks;       /*kernel/sched.c*/
 
        now = rpcc();
        save_and_cli(flags);
@@ -337,9 +342,15 @@ do_gettimeofday(struct timeval *tv)
         * with no clear gain.
         */
 
-       delta_usec = delta_cycles * state.scaled_ticks_per_cycle * 15625;
+       delta_usec = (delta_cycles * state.scaled_ticks_per_cycle 
+                       + state.partial_tick
+                       + (lost_ticks << FIX_SHIFT) ) * 15625;
        delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
 
+       /* the 'lost_tics' term above implements this:  
+        * delta_usec += lost_ticks * (1000000 / HZ);
+        */
+
        usec += delta_usec;
        if (usec >= 1000000) {
                sec += 1;
index b70595456cc9b5a6c306c287dc161cf80251fac3..da516f09ee6ceb593780c3eeaa01c44835ffb6d1 100644 (file)
@@ -445,6 +445,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( 3DFX,           3DFX_VOODOO2,   "Voodoo2"),
        DEVICE( 3DFX,           3DFX_BANSHEE,   "Banshee"),
        DEVICE( SIGMADES,       SIGMADES_6425,  "REALmagic64/GX"),
+       DEVICE( AVM,            AVM_A1,         "A1 (Fritz)"),
        DEVICE( STALLION,       STALLION_ECHPCI832,"EasyConnection 8/32"),
        DEVICE( STALLION,       STALLION_ECHPCI864,"EasyConnection 8/64"),
        DEVICE( STALLION,       STALLION_EIOPCI,"EasyIO"),
@@ -784,6 +785,7 @@ static const char *pci_strvendor(unsigned int vendor)
              case PCI_VENDOR_ID_O2:            return "O2 Micro";
              case PCI_VENDOR_ID_3DFX:          return "3Dfx";
              case PCI_VENDOR_ID_SIGMADES:      return "Sigma Designs";
+             case PCI_VENDOR_ID_AVM:           return "AVM";
              case PCI_VENDOR_ID_CCUBE:         return "C-Cube";
              case PCI_VENDOR_ID_DIPIX:         return "Dipix";
              case PCI_VENDOR_ID_STALLION:      return "Stallion Technologies";
index 8a58de7cc27d2504e8fcc6c7350d801ed78b099c..c26ed1e25738720b9a3f26a89b002dfb80b4dc03 100644 (file)
@@ -4,7 +4,7 @@
  *
  * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.9 1999/01/04
+ * Version: 1.15 1999/04/19
  *
  * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
  *
@@ -24,6 +24,9 @@
  *               "Daniel Haun" <haund@usa.net>
  *                     Testing, hardware cursor fixes
  *
+ *               "Scott Wood" <sawst46+@pitt.edu>
+ *                     Fixes
+ *
  *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
  *                     Betatesting
  *
@@ -452,7 +455,7 @@ struct matrox_accel_data {
 #define CPMINFO        const struct matrox_fb_info* minfo,
 #define PMINFO  minfo,
 
-static inline struct matrox_fb_info* mxinfo(struct display* p) {
+static inline struct matrox_fb_info* mxinfo(const struct display* p) {
        return (struct matrox_fb_info*)p->fb_info;
 }
 
@@ -474,7 +477,7 @@ struct display global_disp;
 #define PMINFO
 
 #if 0
-static inline struct matrox_fb_info* mxinfo(struct display* p) {
+static inline struct matrox_fb_info* mxinfo(const struct display* p) {
        return &global_mxinfo;
 }
 #endif
@@ -2191,7 +2194,7 @@ static void matrox_text_putcs(struct vc_data* conp, struct display* p, const uns
 
        step = ACCESS_FBINFO(devflags.textstep);
        offs = yy * p->next_line + xx * step;
-       attr = attr_fgcol(p,scr_readw(s)) | (attr_bgcol(p,scr_readw(s)) << 4);
+       attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
        while (count-- > 0) {
                unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8;
                if (chr & 0x10000) chr ^= 0x10008;
@@ -2395,6 +2398,10 @@ static void initMatrox(WPMINFO struct display* p) {
 
        DBG("initMatrox")
        
+       if (ACCESS_FBINFO(currcon_display) != p)
+               return;
+       if (p->dispsw && p->conp)
+               fb_con.con_cursor(p->conp, CM_ERASE);
        p->dispsw_data = NULL;
        if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
                if (p->type == FB_TYPE_TEXT) {
@@ -4274,6 +4281,17 @@ static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_
        for (i = 0; i < 21; i++) {
                outTi3026(PMINFO DACseq[i], hw->DACreg[i]);
        }
+       if (oldhw) {
+               outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+               oldhw->DACclk[0] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+               oldhw->DACclk[3] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
+               outTi3026(PMINFO TVP3026_XPLLADDR, 0x15);
+               oldhw->DACclk[1] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+               oldhw->DACclk[4] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
+               outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+               oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+               oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
+       }
        if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
                /* agrhh... setting up PLL is very slow on Millenium... */
                /* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
@@ -5296,7 +5314,7 @@ static struct board {
                "MGA-G200 (AGP)"},
        {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G200_AGP,  0xFF,
                0,                      0,
-               DEVF_VIDEO64BIT | DEVF_SWAPS,
+               DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
                230000,
                &vbG200,
                "unknown G200 (AGP)"},
@@ -5743,20 +5761,26 @@ leave:;
 }
 
 #ifndef MODULE
+static int __init initialized = 0;
+
 __initfunc(void matroxfb_init(void))
 {
        DBG("matroxfb_init")
-#if defined(CONFIG_FB_OF)
-/* Nothing to do, must be called from offb */
-#else  
-       matrox_init();
-#endif
+       
+       if (!initialized) {
+               initialized = 1;
+               matrox_init();
+       }
 }
 
 #if defined(CONFIG_FB_OF)
 __initfunc(int matrox_of_init(struct device_node *dp)) {
        DBG("matrox_of_init");
-       matrox_init();
+       
+       if (!initialized) {
+               initialized = 1;
+               matrox_init();
+       }
        if (!fb_list) return -ENXIO;
        return 0;
 }
index cac59faeb71395aa422cdff62646a14820654668..dbbff73d4af4e2749ec8bb6584c3a3582a91f17f 100644 (file)
@@ -486,33 +486,6 @@ static void remove_from_queues(struct buffer_head * bh)
        remove_from_lru_list(bh);
 }
 
-static inline void put_last_lru(struct buffer_head * bh)
-{
-       if (bh) {
-               struct buffer_head **bhp = &lru_list[bh->b_list];
-
-               if (bh == *bhp) {
-                       *bhp = bh->b_next_free;
-                       return;
-               }
-
-               if(bh->b_dev == B_FREE)
-                       panic("Wrong block for lru list");
-
-               /* Add to back of free list. */
-               remove_from_lru_list(bh);
-               if(!*bhp) {
-                       *bhp = bh;
-                       (*bhp)->b_prev_free = bh;
-               }
-
-               bh->b_next_free = *bhp;
-               bh->b_prev_free = (*bhp)->b_prev_free;
-               (*bhp)->b_prev_free->b_next_free = bh;
-               (*bhp)->b_prev_free = bh;
-       }
-}
-
 static inline void put_last_free(struct buffer_head * bh)
 {
        if (bh) {
@@ -726,8 +699,6 @@ repeat:
        bh = get_hash_table(dev, block, size);
        if (bh) {
                if (!buffer_dirty(bh)) {
-                       if (buffer_uptodate(bh))
-                                put_last_lru(bh);
                        bh->b_flushtime = 0;
                }
                return bh;
@@ -854,6 +825,7 @@ void __bforget(struct buffer_head * buf)
                return;
        }
        buf->b_count = 0;
+       buf->b_state = 0;
        remove_from_queues(buf);
        put_last_free(buf);
 }
@@ -1525,13 +1497,27 @@ void show_buffers(void)
  * Use gfp() for the hash table to decrease TLB misses, use
  * SLAB cache for buffer heads.
  */
-void __init buffer_init(void)
+void __init buffer_init(unsigned long memory_size)
 {
-       int order = 5;          /* Currently maximum order.. */
+       int order;
        unsigned int nr_hash;
 
-       nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct buffer_head *);
-       hash_table = (struct buffer_head **) __get_free_pages(GFP_ATOMIC, order);
+       /* we need to guess at the right sort of size for a buffer cache.
+          the heuristic from working with large databases and getting
+          fsync times (ext2) manageable, is the following */
+
+       memory_size >>= 20;
+       for (order = 5; (1UL << order) < memory_size; order++);
+
+       /* try to allocate something until we get it or we're asking
+           for something that is really too small */
+
+       do {
+               nr_hash = (1UL << order) * PAGE_SIZE /
+                   sizeof(struct buffer_head *);
+               hash_table = (struct buffer_head **)
+                   __get_free_pages(GFP_ATOMIC, order);
+       } while (hash_table == NULL && --order > 4);
        
        if (!hash_table)
                panic("Failed to allocate buffer hash table\n");
index f57db8bf3261d73cd9d942630a92d7443f969859..838c679d40a0fbfd9957262fc15214d74faf06cc 100644 (file)
@@ -54,6 +54,7 @@ EXPORT_SYMBOL(lock_fat);
 EXPORT_SYMBOL(unlock_fat);
 EXPORT_SYMBOL(fat_dir_ioctl);
 EXPORT_SYMBOL(fat_readpage);
+EXPORT_SYMBOL(fat_is_binary);
 
 int init_fat_fs(void)
 {
index f975a6735b9b8b6c66dc36493f18bb9c129bdd7e..39067dd1c8487de11afdb94e5090ec6badf5f27c 100644 (file)
@@ -703,8 +703,8 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o
        if(raw_entry->attr & ATTR_SYS)
                if (MSDOS_SB(sb)->options.sys_immutable)
                        inode->i_flags |= S_IMMUTABLE;
-       MSDOS_I(inode)->i_binary = is_binary(MSDOS_SB(sb)->options.conversion,
-           raw_entry->ext);
+       MSDOS_I(inode)->i_binary =
+           fat_is_binary(MSDOS_SB(sb)->options.conversion, raw_entry->ext);
        MSDOS_I(inode)->i_attrs = raw_entry->attr & ATTR_UNUSED;
        /* this is as close to the truth as we can get ... */
        inode->i_blksize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
index b398a0bbd1e8ac92866caaabb92cc4642d4c9f0f..1dfddd3c722761f3a38a5b8ec260dfd9d98a95c6 100644 (file)
@@ -51,11 +51,11 @@ void fat_fs_panic(struct super_block *s,const char *msg)
 
 
 /*
- * is_binary selects optional text conversion based on the conversion mode and
- * the extension part of the file name.
+ * fat_is_binary selects optional text conversion based on the conversion mode
+ * and the extension part of the file name.
  */
 
-int is_binary(char conversion,char *extension)
+int fat_is_binary(char conversion,char *extension)
 {
        char *walk;
 
index d2947da0b521bf626df6657789449f5472b7bf65..a364faf2117fdfa87c44f4de8b391f5797db3fc8 100644 (file)
@@ -713,7 +713,7 @@ set_hid:
        fat_cache_inval_inode(old_inode);
        old_inode->i_version = ++event;
        MSDOS_I(old_inode)->i_binary =
-               is_binary(MSDOS_SB(sb)->options.conversion, free_de->ext);
+               fat_is_binary(MSDOS_SB(sb)->options.conversion, free_de->ext);
        old_inode->i_ino = free_ino;
        fat_mark_buffer_dirty(sb, free_bh, 1);
        old_de->name[0] = DELETED_FLAG;
index 21a7af8549f2e247b2d9be6b87b3bc1c363a0eea..11a1b1d367c6e1a5438346a4dea5083f6c2761a1 100644 (file)
@@ -6,5 +6,10 @@ bool     '   Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING
 bool     '   Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG
 bool     '   Use NFS namespace if available' CONFIG_NCPFS_NFS_NS
 bool     '   Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS
+if [ "$CONFIG_NCPFS_OS2_NS" = "y" ]; then
+  bool   '      Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
+fi
 bool     '   Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
 # bool     '   NDS interserver authentication support' CONFIG_NCPFS_NDS_DOMAINS
+bool     '   Use Native Language Support' CONFIG_NCPFS_NLS
+bool     '   Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS
index 109091ef0b5976ace45b6dd715caecb775e3b5e4..2fb40609c391cd496c18c6ef93c5608e99bcae0a 100644 (file)
@@ -9,7 +9,7 @@
 
 O_TARGET := ncpfs.o
 O_OBJS   := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \
-               ncpsign_kernel.o
+               symlink.o ncpsign_kernel.o
 M_OBJS   := $(O_TARGET)
 
 # If you want debugging output, please uncomment the following line
index cee8673c555043f514a1182a0da28f128c3eb2a3..7a284742e3f132b25340ffc785e952a53ed1ff72 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1995, 1996 by Volker Lendecke
  *  Modified for big endian by J.F. Chadima and David S. Miller
  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
+ *  Modified 1998 Wolfram Pienkoss for NLS
  *
  */
 
@@ -22,6 +23,7 @@
 #include <linux/locks.h>
 
 #include <linux/ncp_fs.h>
+
 #include "ncplib_kernel.h"
 
 struct ncp_dirent {
@@ -54,7 +56,10 @@ static int ncp_mkdir(struct inode *, struct dentry *, int);
 static int ncp_rmdir(struct inode *, struct dentry *);
 static int ncp_rename(struct inode *, struct dentry *,
                      struct inode *, struct dentry *);
-
+#ifdef CONFIG_NCPFS_EXTRAS
+extern int ncp_symlink(struct inode *, struct dentry *, const char *);
+#endif
+                     
 static struct file_operations ncp_dir_operations =
 {
        NULL,                   /* lseek - default */
@@ -77,7 +82,11 @@ struct inode_operations ncp_dir_inode_operations =
        ncp_lookup,             /* lookup */
        NULL,                   /* link */
        ncp_unlink,             /* unlink */
+#ifdef CONFIG_NCPFS_EXTRAS
+       ncp_symlink,            /* symlink */
+#else
        NULL,                   /* symlink */
+#endif
        ncp_mkdir,              /* mkdir */
        ncp_rmdir,              /* rmdir */
        NULL,                   /* mknod */
@@ -191,14 +200,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
        }
 }
 
-/* Here we encapsulate the inode number handling that depends upon the
- * mount mode: When we mount a complete server, the memory address of
- * the ncp_inode_info is used as the inode number. When only a single
- * volume is mounted, then the dirEntNum is used as the inode
- * number. As this is unique for the complete volume, this should
- * enable the NFS exportability of a ncpfs-mounted volume.
- */
-
 /*
  * Generate a unique inode number.
  */
@@ -253,37 +254,30 @@ static int
 ncp_force_unlink(struct inode *dir, struct dentry* dentry)
 {
         int res=0x9c,res2;
-        struct iattr ia;
+       struct nw_modify_dos_info info;
+       __u32 old_nwattr;
+       struct inode *inode;
 
+       memset(&info, 0, sizeof(info));
+       
         /* remove the Read-Only flag on the NW server */
+       inode = dentry->d_inode;
 
-        memset(&ia,0,sizeof(struct iattr));
-        ia.ia_mode = dentry->d_inode->i_mode;
-        ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222;  /* set write bits */
-        ia.ia_valid = ATTR_MODE;
-
-        res2=ncp_notify_change(dentry, &ia);
-        if (res2)
-        {
-                goto leave_me;
-        }
+       old_nwattr = NCP_FINFO(inode)->nwattr;
+       info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
+       res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
+       if (res2)
+               goto leave_me;
 
         /* now try again the delete operation */
-
         res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
 
         if (res)  /* delete failed, set R bit again */
         {
-                memset(&ia,0,sizeof(struct iattr));
-                ia.ia_mode = dentry->d_inode->i_mode;
-                ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222);  /* clear write bits */
-                ia.ia_valid = ATTR_MODE;
-
-                res2=ncp_notify_change(dentry, &ia);
-                if (res2)
-                {
+               info.attributes = old_nwattr;
+               res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
+               if (res2)
                         goto leave_me;
-                }
         }
 leave_me:
         return(res);
@@ -293,63 +287,58 @@ leave_me:
 #ifdef CONFIG_NCPFS_STRONG
 static int
 ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
-                 struct inode *new_dir, struct dentry* new_dentry, char *_new_name,
-                 int *done_flag)
+                 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
 {
+       struct nw_modify_dos_info info;
         int res=0x90,res2;
-        struct iattr ia;
+       struct inode *old_inode = old_dentry->d_inode;
+       __u32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
+       __u32 new_nwattr = 0; /* shut compiler warning */
+       int old_nwattr_changed = 0;
+       int new_nwattr_changed = 0;
 
+       memset(&info, 0, sizeof(info));
+       
         /* remove the Read-Only flag on the NW server */
 
-        memset(&ia,0,sizeof(struct iattr));
-        ia.ia_mode = old_dentry->d_inode->i_mode;
-       if (S_ISDIR(ia.ia_mode))
-               goto leave_me;
-        ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222;  /* set write bits */
-        ia.ia_valid = ATTR_MODE;
-
-        res2=ncp_notify_change(old_dentry, &ia);
-        if (res2)
-        {
-                goto leave_me;
-        }
-
+       info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
+       res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
+       if (!res2)
+               old_nwattr_changed = 1;
+       if (new_dentry && new_dentry->d_inode) {
+               new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
+               info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
+               res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
+               if (!res2)
+                       new_nwattr_changed = 1;
+       }
         /* now try again the rename operation */
-        res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
-                                            old_dir, _old_name,
-                                            new_dir, _new_name);
-
-        if (!res) {
-                ncp_invalid_dir_cache(old_dir);
-                ncp_invalid_dir_cache(new_dir);
-                d_move(old_dentry,new_dentry);
-                *done_flag=1;
-
-                if (!old_dentry->d_inode) {
-                        DPRINTK(KERN_INFO "ncpfs: no inode -- file remains rw\n");
-                        goto leave_me;
-                }
-                if ((res2=ncp_lookup_validate(old_dentry))) {
-                        DPRINTK(KERN_DEBUG "ncpfs: ncp_lookup_validate returned %d\n",res2);
-                }
-        }
-
-        memset(&ia,0,sizeof(struct iattr));
-        ia.ia_mode = old_dentry->d_inode->i_mode;
-        ia.ia_mode &= ~(NCP_SERVER(old_dentry->d_inode)->m.file_mode & 0222);  /* clear write bits */
-        ia.ia_valid = ATTR_MODE;
-
-        DPRINTK(KERN_INFO "calling ncp_notify_change() with %s/%s\n",
-               old_dentry->d_parent->d_name.name,old_dentry->d_name.name);
-
-        res2=ncp_notify_change(old_dentry, &ia);
-        if (res2)
-        {
-                printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2);
-                /* goto leave_me; */
-        }
-
- leave_me:
+       /* but only if something really happened */
+       if (new_nwattr_changed || old_nwattr_changed) {
+               res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
+                                                   old_dir, _old_name,
+                                                   new_dir, _new_name);
+       } 
+       if (res)
+               goto leave_me;
+       /* file was successfully renamed, so:
+          do not set attributes on old file - it no longer exists
+          copy attributes from old file to new */
+       new_nwattr_changed = old_nwattr_changed;
+       new_nwattr = old_nwattr;
+       old_nwattr_changed = 0;
+       
+leave_me:;
+       if (old_nwattr_changed) {
+               info.attributes = old_nwattr;
+               res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
+               /* ignore errors */
+       }
+       if (new_nwattr_changed) {
+               info.attributes = new_nwattr;
+               res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
+               /* ignore errors */
+       }
         return(res);
 }
 #endif /* CONFIG_NCPFS_STRONG */
@@ -386,11 +375,6 @@ ncp_lookup_validate(struct dentry * dentry)
 printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
 #endif
 
-       if (!ncp_preserve_case(dir)) { 
-         str_lower(__name);
-          down_case = 1;
-       }
-       
        /* If the file is in the dir cache, we do not have to ask the
           server. */
 
@@ -400,17 +384,14 @@ dentry->d_parent->d_name.name, __name);
 #endif
                if (ncp_is_server_root(dir))
                {
-                       str_upper(__name);
+                       io2vol(server, __name, 1);
                        down_case = 1;
                        res = ncp_lookup_volume(server, __name,
                                                &(finfo.nw_info.i));
                } else
                {
-                       if (!ncp_preserve_case(dir))
-                       {
-                               str_upper(__name);
-                               down_case = 1;
-                       }
+                       down_case = !ncp_preserve_case(dir);
+                       io2vol(server, __name, down_case);
                        res = ncp_obtain_info(server, dir, __name,
                                                &(finfo.nw_info.i));
                }
@@ -429,6 +410,9 @@ dentry->d_parent->d_name.name, __name, res);
                  else
                    printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
 #endif
+                 vol2io(server, finfo.nw_info.i.entryName,
+                        !ncp_preserve_entry_case(dir,
+                        finfo.nw_info.i.NSCreator));
                  ncp_update_inode2(dentry->d_inode, &finfo.nw_info);
                }
                if (!val) ncp_invalid_dir_cache(dir);
@@ -535,10 +519,11 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        c_last_returned_index = 0;
                        index = 0;
 
-                       if (!ncp_preserve_case(inode)) {
-                               for (i = 0; i < c_size; i++) {
-                                       str_lower(c_entry[i].i.entryName);
-                               }
+                       for (i = 0; i < c_size; i++)
+                       {
+                               vol2io(server, c_entry[i].i.entryName,
+                                       !ncp_preserve_entry_case(inode,
+                                       c_entry[i].i.NSCreator));
                        }
                }
        }
@@ -730,7 +715,7 @@ int ncp_conn_logged_in(struct ncp_server *server)
                struct dentry* dent;
 
                result = -ENOENT;
-               str_upper(server->m.mounted_vol);
+               io2vol(server, server->m.mounted_vol, 1);
                if (ncp_lookup_volume(server, server->m.mounted_vol,
                                      &(server->root.finfo.i)) != 0) {
 #ifdef NCPFS_PARANOIA
@@ -738,7 +723,7 @@ printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol);
 #endif
                        goto out;
                }
-               str_lower(server->root.finfo.i.entryName);
+               vol2io(server, server->root.finfo.i.entryName, 1);
                dent = server->root_dentry;
                if (dent) {
                        struct inode* ino = dent->d_inode;
@@ -786,11 +771,6 @@ static int ncp_lookup(struct inode *dir, struct dentry *dentry)
 printk(KERN_DEBUG "ncp_lookup: %s, len %d\n", __name, len);
 #endif
 
-       if (!ncp_preserve_case(dir)) { 
-         str_lower(__name);
-          down_case = 1;
-       }
-       
        /* If the file is in the dir cache, we do not have to ask the
           server. */
 
@@ -830,17 +810,14 @@ dentry->d_parent->d_name.name, __name);
 #endif
                if (ncp_is_server_root(dir))
                {
-                       str_upper(__name);
+                       io2vol(server, __name, 1);
                        down_case = 1;
                        res = ncp_lookup_volume(server, __name,
                                                &(finfo.nw_info.i));
                } else
                {
-                       if (!ncp_preserve_case(dir))
-                       {
-                               str_upper(__name);
-                               down_case = 1;
-                       }
+                       down_case = !ncp_preserve_case(dir);
+                       io2vol(server, __name, down_case);
                        res = ncp_obtain_info(server, dir, __name,
                                                &(finfo.nw_info.i));
                }
@@ -851,8 +828,11 @@ dentry->d_parent->d_name.name, __name, res);
                /*
                 * If we didn't find an entry, make a negative dentry.
                 */
-               if (res != 0)
+               if (res != 0) {
                        goto add_entry;
+               } else vol2io(server, finfo.nw_info.i.entryName,
+                             ncp_preserve_entry_case(dir,
+                             finfo.nw_info.i.NSCreator));
        }
 
        /*
@@ -906,18 +886,19 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
        goto out;
 }
 
-static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
+int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
+               int attributes)
 {
        int error, result;
        struct ncpfs_inode_info finfo;
        __u8 _name[dentry->d_name.len + 1];
-
+       
 #ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_create: creating %s/%s, mode=%x\n",
+printk(KERN_DEBUG "ncp_create_new: creating %s/%s, mode=%x\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
 #endif
        if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk(KERN_WARNING "ncp_create: inode is NULL or not a directory\n");
+               printk(KERN_WARNING "ncp_create_new: inode is NULL or not a directory\n");
                return -ENOENT;
        }
        error = -EIO;
@@ -927,14 +908,12 @@ dentry->d_parent->d_name.name, dentry->d_name.name, mode);
        strncpy(_name, dentry->d_name.name, dentry->d_name.len);
        _name[dentry->d_name.len] = '\0';
 
-       if (!ncp_preserve_case(dir)) {
-               str_upper(_name);
-       }
+       io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
 
        error = -EACCES;
        result = ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
                           OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
-                          0, AR_READ | AR_WRITE, &finfo.nw_info);
+                          attributes, AR_READ | AR_WRITE, &finfo.nw_info);
        if (!result) {
                finfo.nw_info.access = O_RDWR;
                error = ncp_instantiate(dir, dentry, &finfo);
@@ -948,6 +927,11 @@ out:
        return error;
 }
 
+static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+       return ncp_create_new(dir, dentry, mode, 0);
+}
+
 static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
        int error;
@@ -967,9 +951,7 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        strncpy(_name, dentry->d_name.name, dentry->d_name.len);
        _name[dentry->d_name.len] = '\0';
-       if (!ncp_preserve_case(dir)) {
-               str_upper(_name);
-       }
+       io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
 
        error = -EACCES;
        if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
@@ -1008,17 +990,34 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
        strncpy(_name, dentry->d_name.name, dentry->d_name.len);
        _name[dentry->d_name.len] = '\0';
            
-       if (!ncp_preserve_case(dir))
-       {
-               str_upper(_name);
-       }
-       error = -EACCES;
+       io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
        result = ncp_del_file_or_subdir(NCP_SERVER(dir), dir, _name);
-       if (!result)
-       {
-               ncp_invalid_dir_cache(dir);
-               error = 0;
-       }
+       switch (result) {
+               case 0x00:
+                       ncp_invalid_dir_cache(dir);
+                       error = 0;
+                       break;
+               case 0x85:      /* unauthorized to delete file */
+               case 0x8A:      /* unauthorized to delete file */
+                       error = -EACCES;
+                       break;
+               case 0x8F:
+               case 0x90:      /* read only */
+                       error = -EPERM;
+                       break;
+               case 0x9F:      /* in use by another client */
+                       error = -EBUSY;
+                       break;
+               case 0xA0:      /* directory not empty */
+                       error = -ENOTEMPTY;
+                       break;
+               case 0xFF:      /* someone deleted file */
+                       error = -ENOENT;
+                       break;
+               default:
+                       error = -EACCES;
+                       break;
+               }
 out:
        return error;
 }
@@ -1052,19 +1051,38 @@ printk(KERN_DEBUG "ncp_unlink: closing file\n");
 
        error = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
 #ifdef CONFIG_NCPFS_STRONG
+       /* 9C is Invalid path.. It should be 8F, 90 - read only, but
+          it is not :-( */
        if (error == 0x9C && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) { /* R/O */
                error = ncp_force_unlink(dir, dentry);
        }
 #endif
-       if (!error) {
-               DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
-                       dentry->d_parent->d_name.name, dentry->d_name.name);
-               ncp_invalid_dir_cache(dir);
-               d_delete(dentry);
-       } else if (error == 0xFF) {
-               error = -ENOENT;
-       } else {
-               error = -EACCES;
+       switch (error) {
+               case 0x00:
+                       DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
+                               dentry->d_parent->d_name.name, dentry->d_name.name);
+                       ncp_invalid_dir_cache(dir);
+                       d_delete(dentry);
+                       break;
+               case 0x85:
+               case 0x8A:
+                       error = -EACCES;
+                       break;
+               case 0x8D:      /* some files in use */
+               case 0x8E:      /* all files in use */
+                       error = -EBUSY;
+                       break;
+               case 0x8F:      /* some read only */
+               case 0x90:      /* all read only */
+               case 0x9C:      /* !!! returned when in-use or read-only by NW4 */
+                       error = -EPERM;
+                       break;
+               case 0xFF:
+                       error = -ENOENT;
+                       break;
+               default:
+                       error = -EACCES;
+                       break;
        }
                
 out:
@@ -1076,7 +1094,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
 {
        int old_len = old_dentry->d_name.len;
        int new_len = new_dentry->d_name.len;
-       int error, done_flag=0;
+       int error;
        char _old_name[old_dentry->d_name.len + 1];
        char _new_name[new_dentry->d_name.len + 1];
 
@@ -1099,44 +1117,38 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        strncpy(_old_name, old_dentry->d_name.name, old_len);
        _old_name[old_len] = '\0';
-       if (!ncp_preserve_case(old_dir)) {
-               str_upper(_old_name);
-       }
+       io2vol(NCP_SERVER(old_dir), _old_name, !ncp_preserve_case(old_dir));
 
        strncpy(_new_name, new_dentry->d_name.name, new_len);
        _new_name[new_len] = '\0';
-       if (!ncp_preserve_case(new_dir)) {
-               str_upper(_new_name);
-       }
+       io2vol(NCP_SERVER(new_dir), _new_name, !ncp_preserve_case(new_dir));
 
        error = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
                                            old_dir, _old_name,
                                            new_dir, _new_name);
 #ifdef CONFIG_NCPFS_STRONG
-       if (error == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) { /* RO */
+       if ((error == 0x90 || error == -EACCES) && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) {   /* RO */
                error = ncp_force_rename(old_dir, old_dentry, _old_name,
-                                         new_dir, new_dentry, _new_name,
-                                         &done_flag);
+                                         new_dir, new_dentry, _new_name);
        }
 #endif
-       if (error == 0)
-       {
-                if (done_flag == 0)  /* if 1, the following already happened */
-                {                    /* in ncp_force_rename() */
-                        DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
+       switch (error) {
+               case 0x00:
+                               DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
                                 old_dentry->d_name.name,new_dentry->d_name.name);
-                        ncp_invalid_dir_cache(old_dir);
-                        ncp_invalid_dir_cache(new_dir);
-                       if (!S_ISDIR(old_dentry->d_inode->i_mode))
-                               d_move(old_dentry,new_dentry);
-                }
-       } else {
-               if (error == 0x9E)
+                               ncp_invalid_dir_cache(old_dir);
+                               ncp_invalid_dir_cache(new_dir);
+                       /* d_move(old_dentry, new_dentry); */
+                       break;
+               case 0x9E:
                        error = -ENAMETOOLONG;
-               else if (error == 0xFF)
+                       break;
+               case 0xFF:
                        error = -ENOENT;
-               else
+                       break;
+               default:
                        error = -EACCES;
+                       break;
        }
 out:
        return error;
@@ -1155,14 +1167,12 @@ extern struct timezone sys_tz;
 
 static int utc2local(int time)
 {
-       return time - sys_tz.tz_minuteswest * 60 +
-           (sys_tz.tz_dsttime ? 3600 : 0);
+       return time - sys_tz.tz_minuteswest * 60;
 }
 
 static int local2utc(int time)
 {
-       return time + sys_tz.tz_minuteswest * 60 -
-           (sys_tz.tz_dsttime ? 3600 : 0);
+       return time + sys_tz.tz_minuteswest * 60;
 }
 
 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
@@ -1171,7 +1181,9 @@ ncp_date_dos2unix(unsigned short time, unsigned short date)
 {
        int month, year, secs;
 
-       month = ((date >> 5) & 15) - 1;
+       /* first subtract and mask after that... Otherwise, if
+          date == 0, bad things happen */
+       month = ((date >> 5) - 1) & 15;
        year = date >> 9;
        secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
                86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + 
index 534ed0540a3eab5e11a665101f14ed1336d17795..1afee6c7e98cfecc83a073793a95d404965bb9c0 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1995, 1996 by Volker Lendecke
  *  Modified for big endian by J.F. Chadima and David S. Miller
  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
+ *  Modified 1998 Wolfram Pienkoss for NLS
  *
  */
 
@@ -27,6 +28,7 @@
 #include <linux/init.h>
 
 #include <linux/ncp_fs.h>
+
 #include "ncplib_kernel.h"
 
 static void ncp_read_inode(struct inode *);
@@ -49,6 +51,10 @@ static struct super_operations ncp_sops =
 };
 
 extern struct dentry_operations ncp_dentry_operations;
+#ifdef CONFIG_NCPFS_EXTRAS
+extern struct inode_operations ncp_symlink_inode_operations;
+extern int ncp_symlink(struct inode*, struct dentry*, const char*);
+#endif
 
 static struct nw_file_info *read_nwinfo = NULL;
 static struct semaphore read_sem = MUTEX;
@@ -62,6 +68,12 @@ void ncp_update_inode(struct inode *inode, struct nw_file_info *nwinfo)
        NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
        NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
 
+#ifdef CONFIG_NCPFS_SMALLDOS
+       NCP_FINFO(inode)->origNS = nwinfo->i.NSCreator;
+#endif
+#ifdef CONFIG_NCPFS_STRONG
+       NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
+#endif
        NCP_FINFO(inode)->opened = nwinfo->opened;
        NCP_FINFO(inode)->access = nwinfo->access;
        NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
@@ -79,12 +91,42 @@ void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo)
        struct ncp_server *server = NCP_SERVER(inode);
 
        if (!NCP_FINFO(inode)->opened) {
+#ifdef CONFIG_NCPFS_STRONG
+               NCP_FINFO(inode)->nwattr = nwi->attributes;
+#endif
                if (nwi->attributes & aDIR) {
                        inode->i_mode = server->m.dir_mode;
                        inode->i_size = 512;
                } else {
                        inode->i_mode = server->m.file_mode;
                        inode->i_size = le32_to_cpu(nwi->dataStreamSize);
+#ifdef CONFIG_NCPFS_EXTRAS
+                       if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) && (nwi->attributes & aSHARED)) {
+                               switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
+                                       case aHIDDEN:
+                                               if (server->m.flags & NCP_MOUNT_SYMLINKS) {
+                                                       if ((inode->i_size >= NCP_MIN_SYMLINK_SIZE)
+                                                        && (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
+                                                               inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
+                                                               break;
+                                                       }
+                                               }
+                                               /* FALLTHROUGH */
+                                       case 0:
+                                               if (server->m.flags & NCP_MOUNT_EXTRAS)
+                                                       inode->i_mode |= 0444;
+                                               break;
+                                       case aSYSTEM:
+                                               if (server->m.flags & NCP_MOUNT_EXTRAS)
+                                                       inode->i_mode |= (inode->i_mode >> 2) & 0111;
+                                               break;
+                                       /* case aSYSTEM|aHIDDEN: */
+                                       default:
+                                               /* reserved combination */
+                                               break;
+                               }
+                       }
+#endif
                }
                if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
        }
@@ -114,6 +156,34 @@ static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo)
        } else {
                inode->i_mode = server->m.file_mode;
                inode->i_size = le32_to_cpu(nwi->dataStreamSize);
+#ifdef CONFIG_NCPFS_EXTRAS
+               if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) 
+                && (nwi->attributes & aSHARED)) {
+                       switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
+                               case aHIDDEN:
+                                       if (server->m.flags & NCP_MOUNT_SYMLINKS) {
+                                               if ((inode->i_size >= NCP_MIN_SYMLINK_SIZE)
+                                                && (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
+                                                       inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
+                                                       break;
+                                               }
+                                       }
+                                       /* FALLTHROUGH */
+                               case 0:
+                                       if (server->m.flags & NCP_MOUNT_EXTRAS)
+                                               inode->i_mode |= 0444;
+                                       break;
+                               case aSYSTEM:
+                                       if (server->m.flags & NCP_MOUNT_EXTRAS)
+                                               inode->i_mode |= (inode->i_mode >> 2) & 0111;
+                                       break;
+                               /* case aSYSTEM|aHIDDEN: */
+                               default:
+                                       /* reserved combination */
+                                       break;
+                       }
+               }
+#endif
        }
        if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
 
@@ -157,6 +227,10 @@ static void ncp_read_inode(struct inode *inode)
                inode->i_op = &ncp_file_inode_operations;
        } else if (S_ISDIR(inode->i_mode)) {
                inode->i_op = &ncp_dir_inode_operations;
+#ifdef CONFIG_NCPFS_EXTRAS
+       } else if (S_ISLNK(inode->i_mode)) {
+               inode->i_op = &ncp_symlink_inode_operations;
+#endif
        } else {
                inode->i_op = NULL;
        }
@@ -211,7 +285,6 @@ static void ncp_init_root(struct ncp_server *server,
 {
        struct ncp_inode_info *root = &(server->root);
        struct nw_info_struct *i = &(root->finfo.i);
-       unsigned short dummy;
 
        DPRINTK(KERN_DEBUG "ncp_init_root: i = %x\n", (int) i);
 
@@ -219,15 +292,13 @@ static void ncp_init_root(struct ncp_server *server,
        i->dataStreamSize= 1024;
        i->dirEntNum     = 0;
        i->DosDirNum     = 0;
+#ifdef CONFIG_NCPFS_SMALLDOS
+       i->NSCreator     = NW_NS_DOS;
+#endif
        i->volNumber     = NCP_NUMBER_OF_VOLUMES + 1;   /* illegal volnum */
-       ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
-       ncp_date_unix2dos(0, &(i->modifyTime  ), &(i->modifyDate));
-       ncp_date_unix2dos(0, &(dummy          ), &(i->lastAccessDate));
-       i->creationTime  = le16_to_cpu(i->creationTime);
-       i->creationDate  = le16_to_cpu(i->creationDate);
-       i->modifyTime    = le16_to_cpu(i->modifyTime);
-       i->modifyDate    = le16_to_cpu(i->modifyDate);
-       i->lastAccessDate= le16_to_cpu(i->lastAccessDate);
+       /* set dates of mountpoint to Jan 1, 1986; 00:00 */
+       i->creationTime = i->modifyTime = cpu_to_le16(0x0000);
+       i->creationDate = i->modifyDate = i->lastAccessDate = cpu_to_le16(0x0C21);
        i->nameLen       = 0;
        i->entryName[0]  = '\0';
 
@@ -264,8 +335,6 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
 
        lock_super(sb);
 
-       sb->s_flags |= MS_ODD_RENAME; /* This should go away */
-
        sb->s_blocksize = 1024; /* Eh...  Is this correct? */
        sb->s_blocksize_bits = 10;
        sb->s_magic = NCP_SUPER_MAGIC;
@@ -310,6 +379,14 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
        server->m.dir_mode = (server->m.dir_mode &
                              (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFDIR;
 
+#ifdef CONFIG_NCPFS_NLS
+       /* load the default NLS charsets */
+       server->nls_charsets.codepage[0] = 0;
+       server->nls_charsets.iocharset[0] = 0;
+       server->nls_vol = load_nls_default();
+       server->nls_io = load_nls_default();
+#endif /* CONFIG_NCPFS_NLS */
+
        server->packet_size = NCP_PACKET_SIZE;
        server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
        if (server->packet == NULL)
@@ -379,6 +456,10 @@ out_free_packet:
 out_no_packet:
        printk(KERN_ERR "ncp_read_super: could not alloc packet\n");
 out_free_server:
+#ifdef CONFIG_NCPFS_NLS
+       unload_nls(server->nls_io);
+       unload_nls(server->nls_vol);
+#endif
        ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
        goto out_unlock;
 out_no_server:
@@ -418,6 +499,20 @@ static void ncp_put_super(struct super_block *sb)
        ncp_disconnect(server);
        ncp_unlock_server(server);
 
+#ifdef CONFIG_NCPFS_NLS
+       /* unload the NLS charsets */
+       if (server->nls_vol)
+       {
+               unload_nls(server->nls_vol);
+               server->nls_vol = NULL;
+       }
+       if (server->nls_io)
+       {
+               unload_nls(server->nls_io);
+               server->nls_io = NULL;
+       }
+#endif /* CONFIG_NCPFS_NLS */
+
        fput(server->ncp_filp);
        kill_proc(server->m.wdog_pid, SIGTERM, 1);
 
@@ -459,9 +554,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
        int result = 0;
        int info_mask;
        struct nw_modify_dos_info info;
+       struct ncp_server *server;
 
        result = -EIO;
-       if (!ncp_conn_valid(NCP_SERVER(inode)))
+
+       server = NCP_SERVER(inode);
+       if ((!server) || !ncp_conn_valid(server))
                goto out;
 
        result = inode_change_ok(inode, attr);
@@ -470,11 +568,11 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
 
        result = -EPERM;
        if (((attr->ia_valid & ATTR_UID) &&
-            (attr->ia_uid != NCP_SERVER(inode)->m.uid)))
+            (attr->ia_uid != server->m.uid)))
                goto out;
 
        if (((attr->ia_valid & ATTR_GID) &&
-            (attr->ia_gid != NCP_SERVER(inode)->m.gid)))
+            (attr->ia_gid != server->m.gid)))
                goto out;
 
        if (((attr->ia_valid & ATTR_MODE) &&
@@ -488,26 +586,53 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
 #if 1 
         if ((attr->ia_valid & ATTR_MODE) != 0)
         {
-                if (!S_ISREG(inode->i_mode))
+                if (S_ISDIR(inode->i_mode)) {
+                       umode_t newmode;
+
+                       info_mask |= DM_ATTRIBUTES;
+                       newmode = attr->ia_mode;
+                       newmode &= NCP_SERVER(inode)->m.dir_mode;
+
+                       if (newmode & 0222)
+                               info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
+                       else
+                               info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
+                } else if (!S_ISREG(inode->i_mode))
                 {
                         return -EPERM;
                 }
                 else
                 {
                        umode_t newmode;
-
+#ifdef CONFIG_NCPFS_EXTRAS                     
+                       int extras;
+                       
+                       extras = server->m.flags & NCP_MOUNT_EXTRAS;
+#endif
                         info_mask |= DM_ATTRIBUTES;
                         newmode=attr->ia_mode;
-                        newmode &= NCP_SERVER(inode)->m.file_mode;
+#ifdef CONFIG_NCPFS_EXTRAS
+                       if (!extras)
+#endif
+                               newmode &= server->m.file_mode;
 
                         if (newmode & 0222) /* any write bit set */
                         {
-                                info.attributes &= ~0x60001;
+                                info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
                         }
                         else
                         {
-                                info.attributes |= 0x60001;
+                                info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
                         }
+#ifdef CONFIG_NCPFS_EXTRAS
+                       if (extras) {
+                               if (newmode & 0111) /* any execute bit set */
+                                       info.attributes |= aSHARED | aSYSTEM;
+                               /* read for group/world and not in default file_mode */
+                               else if (newmode & ~server->m.file_mode & 0444)
+                                       info.attributes |= aSHARED;
+                       }
+#endif
                 }
         }
 #endif
@@ -548,6 +673,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
                                result = 0;
                        }
                }
+#ifdef CONFIG_NCPFS_STRONG             
+               if ((!result) && (info_mask & DM_ATTRIBUTES))
+                       NCP_FINFO(inode)->nwattr = info.attributes;
+#endif
        }
        if ((attr->ia_valid & ATTR_SIZE) != 0) {
                int written;
index 2df6fee0951006a901c184ff58ffad2ec7ec84da..8ada3752bb72f96568afc6aa367436d400320fbe 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995, 1996 by Volker Lendecke
  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
+ *  Modified 1998 Wolfram Pienkoss for NLS
  *
  */
 
@@ -17,6 +18,7 @@
 
 #include <linux/ncp.h>
 #include <linux/ncp_fs.h>
+
 #include "ncplib_kernel.h"
 
 /* maximum limit for ncp_objectname_ioctl */
@@ -485,6 +487,69 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                        return 0;
                }
 #endif /* CONFIG_NCPFS_NDS_DOMAINS */
+
+#ifdef CONFIG_NCPFS_NLS
+/* Here we are select the iocharset and the codepage for NLS.
+ * Thanks Petr Vandrovec for idea and many hints.
+ */
+       case NCP_IOC_SETCHARSETS:
+               if (   (permission(inode, MAY_WRITE) != 0)
+                   && (current->uid != server->m.mounted_uid))
+               {
+                       return -EACCES;
+               }
+               if (server->root_setuped) return -EBUSY;
+               {
+                       struct ncp_nls_ioctl user;
+                       struct nls_table *codepage;
+                       struct nls_table *iocharset;
+                       struct nls_table *oldset_io;
+                       struct nls_table *oldset_cp;
+                       
+                       if (copy_from_user(&user, 
+                                          (struct ncp_nls_ioctl*)arg,
+                                           sizeof(user))) return -EFAULT;
+
+                       codepage = NULL;
+                       if (!user.codepage[0]) {
+                               codepage = load_nls_default();
+                       }
+                       else {
+                               codepage = load_nls(user.codepage);
+                               if (! codepage) {
+                                       return -EBADRQC;
+                               }
+                       }
+
+                       iocharset = NULL;
+                       if (user.iocharset[0] == 0) {
+                               iocharset = load_nls_default();
+                       }
+                       else {
+                               iocharset = load_nls(user.iocharset);
+                               if (! iocharset) {
+                                       unload_nls(codepage);
+                                       return -EBADRQC;
+                               }
+                       }
+
+                       oldset_cp = server->nls_vol;
+                       server->nls_vol = codepage;
+                       oldset_io = server->nls_io;
+                       server->nls_io = iocharset;
+                       server->nls_charsets = user;
+                       if (oldset_cp) unload_nls(oldset_cp);
+                       if (oldset_io) unload_nls(oldset_io);
+                       return 0;
+               }
+               
+       case NCP_IOC_GETCHARSETS: /* not tested */
+               if (copy_to_user((struct ncp_nls_ioctl*)arg,
+                               &(server->nls_charsets),
+                               sizeof(server->nls_charsets))) return -EFAULT;
+               return 0;
+#endif /* CONFIG_NCPFS_NLS */
+
        default:
                return -EINVAL;
        }
index fc0bbf0136fa30eff8feba2d1d9e77d6681d0243..bb034a4e469aa4a700b48d306f29b8c677a94c30 100644 (file)
@@ -238,7 +238,8 @@ NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum, err);
 }
 
 static void ncp_add_handle_path(struct ncp_server *server, __u8 vol_num,
-                               __u32 dir_base, int have_dir_base, char *path)
+                               __u32 dir_base, int have_dir_base, 
+                               const char *path)
 {
        ncp_add_byte(server, vol_num);
        ncp_add_dword(server, dir_base);
@@ -468,12 +469,17 @@ ncp_lookup_volume(struct ncp_server *server, char *volname,
        target->nameLen = strlen(volname);
        strcpy(target->entryName, volname);
        target->attributes = aDIR;
+       /* set dates to Jan 1, 1986  00:00 */
+       target->creationTime = target->modifyTime = cpu_to_le16(0x0000);
+       target->creationDate = target->modifyDate = target->lastAccessDate = cpu_to_le16(0x0C21);
        return 0;
 }
 
-int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
-                                       struct inode *dir, __u32 info_mask,
-                                      struct nw_modify_dos_info *info)
+int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *server,
+                                           struct inode *dir,
+                                           const char *path,
+                                           __u32 info_mask,
+                                           const struct nw_modify_dos_info *info)
 {
        __u8  volnum = NCP_FINFO(dir)->volNumber;
        __u32 dirent = NCP_FINFO(dir)->dirEntNum;
@@ -487,13 +493,22 @@ int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
 
        ncp_add_dword(server, info_mask);
        ncp_add_mem(server, info, sizeof(*info));
-       ncp_add_handle_path(server, volnum, dirent, 1, NULL);
+       ncp_add_handle_path(server, volnum, dirent, 1, path);
 
        result = ncp_request(server, 87);
        ncp_unlock_server(server);
        return result;
 }
 
+int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
+                                      struct inode *dir,
+                                      __u32 info_mask,
+                                      const struct nw_modify_dos_info *info)
+{
+       return ncp_modify_file_or_subdir_dos_info_path(server, dir, NULL,
+               info_mask, info);
+}
+
 static int
 ncp_DeleteNSEntry(struct ncp_server *server,
                  __u8 have_dir_base, __u8 volnum, __u32 dirent,
@@ -788,6 +803,35 @@ out:
        return result;
 }
 
+#ifdef CONFIG_NCPFS_EXTRAS
+int
+ncp_read_kernel(struct ncp_server *server, const char *file_id,
+               __u32 offset, __u16 to_read, char *target, int *bytes_read) {
+       int error;
+       mm_segment_t old_fs;
+       
+       old_fs = get_fs();
+       set_fs(get_ds());
+       error = ncp_read(server, file_id, offset, to_read, target, bytes_read);
+       set_fs(old_fs);
+       return error;
+}
+
+int
+ncp_write_kernel(struct ncp_server *server, const char *file_id,
+                __u32 offset, __u16 to_write,
+                const char *source, int *bytes_written) {
+       int error;
+       mm_segment_t old_fs;
+       
+       old_fs = get_fs();
+       set_fs(get_ds());
+       error = ncp_write(server, file_id, offset, to_write, source, bytes_written);
+       set_fs(old_fs);
+       return error;
+}
+#endif
+
 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
 int
 ncp_LogPhysicalRecord(struct ncp_server *server, const char *file_id,
index 7834c6c4f8a855594964767f52872539fc076769..cc1df189647a71502eec0a21d53a088e89da6583 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1995, 1996 by Volker Lendecke
  *  Modified for big endian by J.F. Chadima and David S. Miller
  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
+ *  Modified 1998 Wolfram Pienkoss for NLS
  *
  */
 
 #include <asm/unaligned.h>
 #include <asm/string.h>
 
+#ifdef CONFIG_NCPFS_NLS
+#include <linux/nls.h>
+#endif
+
 #include <linux/ncp.h>
 #include <linux/ncp_fs.h>
 #include <linux/ncp_fs_sb.h>
@@ -36,12 +41,19 @@ int ncp_close_file(struct ncp_server *, const char *);
 int ncp_read(struct ncp_server *, const char *, __u32, __u16, char *, int *);
 int ncp_write(struct ncp_server *, const char *, __u32, __u16,
                const char *, int *);
+#ifdef CONFIG_NCPFS_EXTRAS
+int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16, char *, int *);
+int ncp_write_kernel(struct ncp_server *, const char *, __u32, __u16,
+               const char *, int *);
+#endif
 
 int ncp_obtain_info(struct ncp_server *server, struct inode *, char *,
                struct nw_info_struct *target);
 int ncp_lookup_volume(struct ncp_server *, char *, struct nw_info_struct *);
 int ncp_modify_file_or_subdir_dos_info(struct ncp_server *, struct inode *,
-                        __u32, struct nw_modify_dos_info *info);
+        __u32, const struct nw_modify_dos_info *info);
+int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *, struct inode *,
+        const char* path, __u32, const struct nw_modify_dos_info *info);
 
 int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*);
 int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, char *);
@@ -75,4 +87,83 @@ int
 ncp_mount_subdir(struct ncp_server* server, __u8 volNumber, 
                 __u8 srcNS, __u32 srcDirEntNum);
 #endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
+
+#ifdef CONFIG_NCPFS_NLS
+/* This are the NLS conversion routines with inspirations and code parts
+ * from the vfat file system and hints from Petr Vandrovec.
+ */
+
+/*
+ * It should be replaced by charset specifc conversion. Gordon Chaffee
+ * has prepared some things, but I don't know, what he thinks about it.
+ * The conversion tables for the io charsets should be generatable by
+ * Unicode table, shouldn't it? I have written so generation code for it.
+ * The tables for the vendor specific codepages...? Hmm. The Samba sources
+ * contains also any hints.
+ */
+
+#define toupperif(c, u) ((((u) != 0) && ((c) >= 'a') && ((c) <= 'z')) \
+                       ? (c)-('a'-'A') : (c))
+#define tolowerif(c, u) ((((u) != 0) && ((c) >= 'A') && ((c) <= 'Z')) \
+                       ? (c)-('A'-'a') : (c))
+
+static inline void
+io2vol(struct ncp_server *server, char *name, int case_trans)
+{
+       unsigned char nc;
+       unsigned char *np;
+       unsigned char *up;
+       struct nls_unicode uc;
+       struct nls_table *nls_in;
+       struct nls_table *nls_out;
+
+       nls_in = server->nls_io;
+       nls_out = server->nls_vol;
+       np = name;
+
+       while (*np)
+       {
+               nc = 0;
+               uc = nls_in->charset2uni[toupperif(*np, case_trans)];
+               up = nls_out->page_uni2charset[uc.uni2];
+               if (up != NULL) nc = up[uc.uni1];
+               if (nc != 0) *np = nc;
+               np++;
+       }
+}
+
+static inline void
+vol2io(struct ncp_server *server, char *name, int case_trans)
+{
+       unsigned char nc;
+       unsigned char *np;
+       unsigned char *up;
+       struct nls_unicode uc;
+       struct nls_table *nls_in;
+       struct nls_table *nls_out;
+
+       nls_in = server->nls_vol;
+       nls_out = server->nls_io;
+       np = name;
+
+       while (*np)
+       {
+               nc = 0;
+               uc = nls_in->charset2uni[*np];
+               up = nls_out->page_uni2charset[uc.uni2];
+               if (up != NULL) nc = up[uc.uni1];
+               if (nc == 0) nc = *np;
+               *np = tolowerif(nc, case_trans);
+               np++;
+       }
+}
+
+#else
+
+#define io2vol(S,N,U) if (U) str_upper(N)
+#define vol2io(S,N,U) if (U) str_lower(N)
+
+#endif /* CONFIG_NCPFS_NLS */
+
 #endif /* _NCPLIB_H */
+
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
new file mode 100644 (file)
index 0000000..a923c21
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ *  linux/fs/ncpfs/symlink.c
+ *
+ *  Code for allowing symbolic links on NCPFS (i.e. NetWare)
+ *  Symbolic links are not supported on native NetWare, so we use an
+ *  infrequently-used flag (Sh) and store a two-word magic header in
+ *  the file to make sure we don't accidentally use a non-link file
+ *  as a link.
+ *
+ *  from linux/fs/ext2/symlink.c
+ *
+ *  Copyright (C) 1998-99, Frank A. Vorstenbosch
+ *
+ *  ncpfs symlink handling code
+ *  NLS support (c) 1999 Petr Vandrovec
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_NCPFS_EXTRAS
+
+#include <asm/uaccess.h>
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ncp_fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/stat.h>
+#include "ncplib_kernel.h"
+
+
+/* these magic numbers must appear in the symlink file -- this makes it a bit
+   more resilient against the magic attributes being set on random files. */
+
+#define NCP_SYMLINK_MAGIC0     le32_to_cpu(0x6c6d7973)     /* "symlnk->" */
+#define NCP_SYMLINK_MAGIC1     le32_to_cpu(0x3e2d6b6e)
+
+static int ncp_readlink(struct dentry *, char *, int);
+static struct dentry *ncp_follow_link(struct dentry *, struct dentry *, unsigned int);
+int ncp_create_new(struct inode *dir, struct dentry *dentry,
+                          int mode,int attributes);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations ncp_symlink_inode_operations={
+       NULL,                   /* no file-operations */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       ncp_readlink,           /* readlink */
+       ncp_follow_link,        /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       NULL,                   /* truncate */
+       NULL,                   /* permission */
+       NULL                    /* smap */
+};
+
+/* ----- follow a symbolic link ------------------------------------------ */
+
+static struct dentry *ncp_follow_link(struct dentry *dentry,
+                                     struct dentry *base,
+                                     unsigned int follow)
+{
+       struct inode *inode=dentry->d_inode;
+       int error, length, cnt;
+       char *link;
+
+#ifdef DEBUG
+       printk("ncp_follow_link(dentry=%p,base=%p,follow=%u)\n",dentry,base,follow);
+#endif
+
+       if(!S_ISLNK(inode->i_mode)) {
+               dput(base);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if(ncp_make_open(inode,O_RDONLY)) {
+               dput(base);
+               return ERR_PTR(-EIO);
+       }
+
+       for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE+1, GFP_NFS))==NULL; cnt++) {
+               if (cnt > 10) {
+                       dput(base);
+                       return ERR_PTR(-EAGAIN); /* -ENOMEM? */
+               }
+               schedule();
+       }
+
+       error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
+                         0,NCP_MAX_SYMLINK_SIZE,link,&length);
+
+       if (error!=0 || length<NCP_MIN_SYMLINK_SIZE || 
+          ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 || ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
+               dput(base);
+               kfree(link);
+               return ERR_PTR(-EIO);
+       }
+       link[length]=0;
+
+       vol2io(NCP_SERVER(inode), link+8, 0);
+       
+       /* UPDATE_ATIME(inode); */
+       base=lookup_dentry(link+8, base, follow);
+       kfree(link);
+
+       return base;
+}
+
+/* ----- read symbolic link ---------------------------------------------- */
+
+static int ncp_readlink(struct dentry * dentry, char * buffer, int buflen)
+{
+       struct inode *inode=dentry->d_inode;
+       char *link;
+       int length,error;
+
+#ifdef DEBUG
+       printk("ncp_readlink(dentry=%p,buffer=%p,buflen=%d)\n",dentry,buffer,buflen);
+#endif
+
+       if(!S_ISLNK(inode->i_mode))
+               return -EINVAL;
+
+       if(ncp_make_open(inode,O_RDONLY))
+               return -EIO;
+
+       if((link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE+1,GFP_NFS))==NULL)
+               return -ENOMEM;
+
+       error = ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
+               0,NCP_MAX_SYMLINK_SIZE,link,&length);
+
+       if (error!=0 || length < NCP_MIN_SYMLINK_SIZE || buflen < (length-8) ||
+          ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 ||((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
+               error = -EIO;
+               goto out;
+       }
+
+       link[length] = 0;
+
+       vol2io(NCP_SERVER(inode), link+8, 0);
+       
+       error = length - 8;
+       if(copy_to_user(buffer, link+8, error))
+               error = -EFAULT;
+      
+out:;
+       kfree(link);
+       return error;
+}
+
+/* ----- create a new symbolic link -------------------------------------- */
+int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
+       int i,length;
+       struct inode *inode;
+       char *link;
+
+#ifdef DEBUG
+       printk("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);
+#endif
+
+       if (!(NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS))
+               return -EPERM;  /* EPERM is returned by VFS if symlink procedure does not exist */
+
+       if ((length=strlen(symname))>NCP_MAX_SYMLINK_SIZE)
+               return -EINVAL;
+
+       if ((link=(char *)kmalloc(length+9,GFP_NFS))==NULL)
+               return -ENOMEM;
+
+       if (ncp_create_new(dir,dentry,0,aSHARED|aHIDDEN)) {
+               kfree(link);
+               return -EIO;
+       }
+
+       inode=dentry->d_inode;
+
+       ((__u32 *)link)[0]=NCP_SYMLINK_MAGIC0;
+       ((__u32 *)link)[1]=NCP_SYMLINK_MAGIC1;
+       memcpy(link+8, symname, length+1); /* including last zero for io2vol */
+
+       /* map to/from server charset, do not touch upper/lower case as
+          symlink can point out of ncp filesystem */
+       io2vol(NCP_SERVER(inode), link+8, 0);
+       
+       if(ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, 
+                           0, length+8, link, &i) || i!=length+8) {
+               kfree(link);
+               return -EIO;
+       }
+
+       kfree(link);
+       return 0;
+}
+#endif
+
+/* ----- EOF ----- */
index 370c8b6f429e1e1bb91e7f608cdc300dea63a29c..5f06f787d1600ac307238cdd0e0a5217327cf359 100644 (file)
@@ -109,7 +109,7 @@ nfs_dir_open(struct inode *dir, struct file *file)
 
        dfprintk(VFS, "NFS: nfs_dir_open(%s/%s)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name);
-       return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+       return _nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
 }
 
 static ssize_t
@@ -439,8 +439,10 @@ parent->d_name.name, dentry->d_name.name);
                goto out_bad;
 
        /* Filehandle matches? */
-       if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh)))
-               goto out_bad;
+       if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
+               if (dentry->d_count < 2 || nfs_revalidate(dentry))
+                       goto out_bad;
+       }
 
        /* Ok, remeber that we successfully checked it.. */
        nfs_renew_times(dentry);
index c5dc24b834132e5d9013e6817fe34c08c870c82c..5d3262271e1e5add323ed9b70936ac852f4c515e 100644 (file)
@@ -37,6 +37,7 @@ static ssize_t nfs_file_read(struct file *, char *, size_t, loff_t *);
 static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
 static int  nfs_file_flush(struct file *);
 static int  nfs_fsync(struct file *, struct dentry *dentry);
+static int  nfs_file_open(struct inode *inode, struct file *filp);
 
 static struct file_operations nfs_file_operations = {
        NULL,                   /* lseek - default */
@@ -46,7 +47,7 @@ static struct file_operations nfs_file_operations = {
        NULL,                   /* select - default */
        NULL,                   /* ioctl - default */
        nfs_file_mmap,          /* mmap */
-       NULL,                   /* no special open is needed */
+       nfs_file_open,          /* open */
        nfs_file_flush,         /* flush */
        NULL,                   /* release */
        nfs_fsync,              /* fsync */
@@ -104,6 +105,19 @@ nfs_file_flush(struct file *file)
        return status;
 }
 
+/*
+ * Open the file.
+ * Just checks the cache is synchronized.
+ */
+static int
+nfs_file_open(struct inode *inode, struct file *filp)
+{
+       struct dentry *dentry = filp->f_dentry;
+
+       return _nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+}
+
+
 static ssize_t
 nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
 {
index 0a08b299961bc6f86fef8d59c246609fddeb513d..0b832e1a56ed9cc7fc841a1685f6f54a1856e5d2 100644 (file)
@@ -234,6 +234,11 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
        server->rsize    = nfs_block_size(data->rsize, NULL);
        server->wsize    = nfs_block_size(data->wsize, NULL);
        server->flags    = data->flags;
+
+       if (data->flags & NFS_MOUNT_NOAC) {
+               data->acregmin = data->acregmax = 0;
+               data->acdirmin = data->acdirmax = 0;
+       }
        server->acregmin = data->acregmin*HZ;
        server->acregmax = data->acregmax*HZ;
        server->acdirmin = data->acdirmin*HZ;
@@ -660,10 +665,6 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
        int              status = 0;
        struct nfs_fattr fattr;
 
-       /* Don't bother revalidating if we've done it recently */
-       if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode))
-               goto out;
-
        dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
                dentry->d_parent->d_name.name, dentry->d_name.name,
                inode->i_ino);
index bf17009d9c429bc4cb2c8d9f68792b39a59cf313..7e591b82af08bc3cca3c2011feb74d7111ea6f99 100644 (file)
@@ -4,7 +4,7 @@
 
 # msdos and Joliet want NLS
 if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
-       -o "$CONFIG_NTFS_FS" != "n" ]; then
+       -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" ]; then
   define_bool CONFIG_NLS y
 else
   define_bool CONFIG_NLS n
index 09f25dc78d1a8e7aecaabccb89ed81849c1e645c..08df0f278bca06f129ed8dab2b9bd54665b1fc0c 100644 (file)
@@ -46,7 +46,7 @@ extern __inline__ void set_bit(int nr, volatile void * addr)
        __asm__ __volatile__( LOCK_PREFIX
                "btsl %1,%0"
                :"=m" (ADDR)
-               :"ir" (nr));
+               :"Ir" (nr));
 }
 
 extern __inline__ void clear_bit(int nr, volatile void * addr)
@@ -54,7 +54,7 @@ extern __inline__ void clear_bit(int nr, volatile void * addr)
        __asm__ __volatile__( LOCK_PREFIX
                "btrl %1,%0"
                :"=m" (ADDR)
-               :"ir" (nr));
+               :"Ir" (nr));
 }
 
 extern __inline__ void change_bit(int nr, volatile void * addr)
@@ -62,7 +62,7 @@ extern __inline__ void change_bit(int nr, volatile void * addr)
        __asm__ __volatile__( LOCK_PREFIX
                "btcl %1,%0"
                :"=m" (ADDR)
-               :"ir" (nr));
+               :"Ir" (nr));
 }
 
 extern __inline__ int test_and_set_bit(int nr, volatile void * addr)
@@ -72,7 +72,7 @@ extern __inline__ int test_and_set_bit(int nr, volatile void * addr)
        __asm__ __volatile__( LOCK_PREFIX
                "btsl %2,%1\n\tsbbl %0,%0"
                :"=r" (oldbit),"=m" (ADDR)
-               :"ir" (nr));
+               :"Ir" (nr));
        return oldbit;
 }
 
@@ -83,7 +83,7 @@ extern __inline__ int test_and_clear_bit(int nr, volatile void * addr)
        __asm__ __volatile__( LOCK_PREFIX
                "btrl %2,%1\n\tsbbl %0,%0"
                :"=r" (oldbit),"=m" (ADDR)
-               :"ir" (nr));
+               :"Ir" (nr));
        return oldbit;
 }
 
@@ -94,7 +94,7 @@ extern __inline__ int test_and_change_bit(int nr, volatile void * addr)
        __asm__ __volatile__( LOCK_PREFIX
                "btcl %2,%1\n\tsbbl %0,%0"
                :"=r" (oldbit),"=m" (ADDR)
-               :"ir" (nr));
+               :"Ir" (nr));
        return oldbit;
 }
 
@@ -113,7 +113,7 @@ extern __inline__ int __test_bit(int nr, volatile void * addr)
        __asm__ __volatile__(
                "btl %2,%1\n\tsbbl %0,%0"
                :"=r" (oldbit)
-               :"m" (ADDR),"ir" (nr));
+               :"m" (ADDR),"Ir" (nr));
        return oldbit;
 }
 
index 9959f930be297947d7749cb1489f644c84e643d5..b6ecebbbe2da4e41f1194f560722a7ee7ddd68c6 100644 (file)
@@ -169,7 +169,7 @@ extern int max_super_blocks, nr_super_blocks;
 extern void update_atime (struct inode *inode);
 #define UPDATE_ATIME(inode) update_atime (inode)
 
-extern void buffer_init(void);
+extern void buffer_init(unsigned long);
 extern void inode_init(void);
 extern void file_table_init(void);
 extern void dcache_init(void);
index bcf4d0134333a9bee6ad495e4dbc0c1c5d8a1f3d..ab699c4edb533d4286682c67deb12fe2b5abcb66 100644 (file)
@@ -195,7 +195,7 @@ struct fat_cache {
 };
 
 /* misc.c */
-extern int is_binary(char conversion,char *extension);
+extern int fat_is_binary(char conversion,char *extension);
 extern void lock_fat(struct super_block *sb);
 extern void unlock_fat(struct super_block *sb);
 extern int fat_add_cluster(struct inode *inode);
index 83ad3f723a07181353ef650d6b6c0796f1a72da1..666ffff0fa5908b284ba90ec07e6785aff6b6f6c 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995 by Volker Lendecke
  *  Modified for sparc by J.F. Chadima
+ *  Modified for __constant_ntoh by Frank A. Vorstenbosch
  *
  */
 
@@ -58,11 +59,21 @@ struct ncp_volume_info {
 
 /* these define the attribute byte as seen by NCP */
 #define aRONLY     (ntohl(0x01000000))
-#define aHIDDEN    (ntohl(0x02000000))
-#define aSYSTEM    (ntohl(0x04000000))
+#define aHIDDEN    (__constant_ntohl(0x02000000))
+#define aSYSTEM    (__constant_ntohl(0x04000000))
 #define aEXECUTE   (ntohl(0x08000000))
 #define aDIR       (ntohl(0x10000000))
 #define aARCH      (ntohl(0x20000000))
+#define aSHARED           (ntohl(0x80000000))
+#define aDONTSUBALLOCATE (ntohl(1L<<(11+8)))
+#define aTRANSACTIONAL   (ntohl(1L<<(12+8)))
+#define aPURGE          (ntohl(1L<<(16-8)))
+#define aRENAMEINHIBIT  (ntohl(1L<<(17-8)))
+#define aDELETEINHIBIT  (ntohl(1L<<(18-8)))
+#define aDONTCOMPRESS   (nothl(1L<<(27-24)))
+
+#define NCP_MIN_SYMLINK_SIZE   8
+#define NCP_MAX_SYMLINK_SIZE   512
 
 #define AR_READ      (ntohs(0x0100))
 #define AR_WRITE     (ntohs(0x0200))
index eb83cfe0191ca9616bc32c3ef72a85fdc1e8ce6f..b30fd061067e94bd464f4d41f7e7c8a08dc20b28 100644 (file)
 #include <linux/types.h>
 
 #include <linux/ncp_mount.h>
+
+/* NLS charsets by ioctl */
+#define NCP_IOCSNAME_LEN 20
+struct ncp_nls_ioctl
+{
+       unsigned char codepage[NCP_IOCSNAME_LEN+1];
+       unsigned char iocharset[NCP_IOCSNAME_LEN+1];
+};
+                
 #include <linux/ncp_fs_sb.h>
 #include <linux/ncp_fs_i.h>
 
@@ -111,6 +120,9 @@ struct ncp_privatedata_ioctl
 #define NCP_IOC_GETPRIVATEDATA         _IOWR('n', 10, struct ncp_privatedata_ioctl)
 #define NCP_IOC_SETPRIVATEDATA         _IOR('n', 10, struct ncp_privatedata_ioctl)
 
+#define NCP_IOC_GETCHARSETS            _IOWR('n', 11, struct ncp_nls_ioctl)
+#define NCP_IOC_SETCHARSETS            _IOR('n', 11, struct ncp_nls_ioctl)
+
 /*
  * The packet size to allocate. One page should be enough.
  */
@@ -155,6 +167,12 @@ struct ncpfs_i {
        __u32   dirEntNum __attribute__((packed));
        __u32   DosDirNum __attribute__((packed));
        __u32   volNumber __attribute__((packed));
+#ifdef CONFIG_NCPFS_SMALLDOS
+       __u32   origNS;
+#endif
+#ifdef CONFIG_NCPFS_STRONG
+       __u32   nwattr;
+#endif
        int     opened;
        int     access;
        __u32   server_file_handle __attribute__((packed));
@@ -272,10 +290,13 @@ static inline int ncp_namespace(struct inode *inode)
        return server->name_space[NCP_FINFO(inode)->volNumber];
 }
 
-static inline int ncp_preserve_case(struct inode *i)
-{
+static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator) {
 #if defined(CONFIG_NCPFS_NFS_NS) || defined(CONFIG_NCPFS_OS2_NS)
        int ns = ncp_namespace(i);
+#endif
+#if defined(CONFIG_NCPFS_SMALLDOS) && defined(CONFIG_NCPFS_OS2_NS)
+       if ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
+               return 0;
 #endif
        return
 #ifdef CONFIG_NCPFS_OS2_NS
@@ -287,6 +308,11 @@ static inline int ncp_preserve_case(struct inode *i)
        0;
 }
 
+static inline int ncp_preserve_case(struct inode *i)
+{
+       return ncp_preserve_entry_case(i, NW_NS_OS2);
+}
+
 static inline int ncp_case_sensitive(struct inode *i)
 {
 #ifdef CONFIG_NCPFS_NFS_NS
index 38492fc92390179ed73dd68c712433dced42d1b0..adf1eef660e695359b87c7ee647827aaceb03891 100644 (file)
@@ -73,6 +73,10 @@ struct ncp_server {
                size_t len;
                void*  data;
        } priv;
+
+       struct ncp_nls_ioctl nls_charsets;      /* NLS user data */
+       struct nls_table *nls_vol;    /* codepage used on volume */
+       struct nls_table *nls_io;     /* charset used for input and display */
 };
 
 static inline int ncp_conn_valid(struct ncp_server *server)
index 54bc5b9435d93049a487ad66594b5f924b41ee80..a214372a5e5a95484b6763052a1104d64ed8519a 100644 (file)
 #define NCP_MOUNT_VERSION 3
 
 /* Values for flags */
-#define NCP_MOUNT_SOFT 0x0001
-#define NCP_MOUNT_INTR 0x0002
-#define NCP_MOUNT_STRONG 0x0004   /* enable delete/rename of r/o files */
-#define NCP_MOUNT_NO_OS2 0x0008
-#define NCP_MOUNT_NO_NFS 0x0010
+#define NCP_MOUNT_SOFT         0x0001
+#define NCP_MOUNT_INTR         0x0002
+#define NCP_MOUNT_STRONG       0x0004  /* enable delete/rename of r/o files */
+#define NCP_MOUNT_NO_OS2       0x0008  /* do not use OS/2 (LONG) namespace */
+#define NCP_MOUNT_NO_NFS       0x0010  /* do not use NFS namespace */
+#define NCP_MOUNT_EXTRAS       0x0020
+#define NCP_MOUNT_SYMLINKS     0x0040  /* enable symlinks */
 
 struct ncp_mount_data {
        int version;
index 71b1f2adc606cf2408ddcf98fcf71ed02a535fc2..c5b8bebb8897a0fe14853a849eef3364e7e3164c 100644 (file)
@@ -20,8 +20,6 @@ static inline unsigned long page_address(struct page * page)
 #define PAGE_HASH_BITS 12
 #define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)
 
-#define PAGE_AGE_VALUE 16
-
 extern unsigned long page_cache_size; /* # of pages currently in the hash table */
 extern struct page * page_hash_table[PAGE_HASH_SIZE];
 
index 1d4546662fc26ae8c82d54ba78023c8a030d1c20..552b9cb1f9baab9c53e19ce1448223b123d19fe3 100644 (file)
 
 #define PCI_VENDOR_ID_CCUBE            0x123f
 
+#define PCI_VENDOR_ID_AVM              0x1244
+#define PCI_DEVICE_ID_AVM_A1           0x0a00
+
 #define PCI_VENDOR_ID_DIPIX            0x1246
 
 #define PCI_VENDOR_ID_STALLION         0x124d
index 9b52a7a8baec3e663d79488332ecc8d48e1e5ad9..81d01003ffd7a6a8224b83420c83041fc91332c9 100644 (file)
@@ -1166,7 +1166,7 @@ asmlinkage void __init start_kernel(void)
        filescache_init();
        dcache_init();
        vma_init();
-       buffer_init();
+       buffer_init(memory_end-memory_start);
        signals_init();
        inode_init();
        file_table_init();
index 4a956c0850fe49eb7497b6f2fa08b8fd91bbbf13..66ef6f320022794b86c454ae4819032a6df611ac 100644 (file)
@@ -33,7 +33,7 @@ int nr_free_pages = 0;
    for the ring buffers */
 #define NR_MEM_LISTS 12
 #else
-#define NR_MEM_LISTS 6
+#define NR_MEM_LISTS 10
 #endif
 
 /* The start of this MUST match the start of "struct page" */