diff -u -r --new-file linux-2.2.15-raid/Documentation/Configure.help linux-2.2.15.s.v0.6-client/Documentation/Configure.help --- linux-2.2.15-raid/Documentation/Configure.help Sun May 28 17:03:19 2000 +++ linux-2.2.15.s.v0.6-client/Documentation/Configure.help Wed May 24 20:18:36 2000 @@ -7819,6 +7819,20 @@ want), say M here and read Documentation/modules.txt. The module will be called smbfs.o. Most people say N, however. +Experimental SMB Symlink work-around +CONFIG_SMB_SYMLINKS + If you have to use SMB shares e. g. for home directories, this option + provides symlinks for you. The workaround uses the system attribute, so + the server has to allow you to modify it (which on samba means "map + symlinks = yes" and "create mask = 750" (010, the group exec bit, is + usually mapped as the system bit)). + Note that if you use samba for the server, the symlinks WILL NOT be + visible as such on the server; you will just have a plain file with the + magic cookie and the content of the symlink. + + Coda file system support (advanced network fs) + CONFIG_CODA_FS + Coda is an advanced network file system, similar to NFS in that it Coda filesystem support CONFIG_CODA_FS Coda is an advanced network filesystem, similar to NFS in that it diff -u -r --new-file linux-2.2.15-raid/fs/Config.in linux-2.2.15.s.v0.6-client/fs/Config.in --- linux-2.2.15-raid/fs/Config.in Thu May 4 02:16:46 2000 +++ linux-2.2.15.s.v0.6-client/fs/Config.in Wed May 24 19:06:06 2000 @@ -91,6 +91,10 @@ fi fi tristate 'SMB filesystem support (to mount WfW shares etc.)' CONFIG_SMB_FS + if [ "$CONFIG_SMB_FS" = "y" -o "$CONFIG_SMB_FS" = "m" ]; then + bool 'SMB devel symlink support (PRE-ALPHA EXPERIMENTAL!)' CONFIG_SMB_SYMLINKS + fi + fi if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS diff -u -r --new-file linux-2.2.15-raid/fs/smbfs/Makefile linux-2.2.15.s.v0.6-client/fs/smbfs/Makefile --- linux-2.2.15-raid/fs/smbfs/Makefile Sun Oct 12 19:17:05 1997 +++ linux-2.2.15.s.v0.6-client/fs/smbfs/Makefile Fri May 26 05:31:53 2000 @@ -8,7 +8,11 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := smbfs.o -O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o +O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o +ifeq ($(CONFIG_SMB_SYMLINKS),y) + O_OBJS += symlink.o +endif + M_OBJS := $(O_TARGET) # If you want debugging output, please uncomment the following line diff -u -r --new-file linux-2.2.15-raid/fs/smbfs/dir.c linux-2.2.15.s.v0.6-client/fs/smbfs/dir.c --- linux-2.2.15-raid/fs/smbfs/dir.c Sun May 9 02:56:37 1999 +++ linux-2.2.15.s.v0.6-client/fs/smbfs/dir.c Fri May 26 00:13:10 2000 @@ -14,7 +14,9 @@ #include #define SMBFS_PARANOIA 1 -/* #define SMBFS_DEBUG_VERBOSE 1 */ +#ifdef DEBUG +#define SMBFS_DEBUG_VERBOSE 1 +#endif /* #define pr_debug printk */ #define SMBFS_MAX_AGE 5*HZ @@ -29,6 +31,10 @@ static int smb_unlink(struct inode *, struct dentry *); static int smb_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); +#ifdef CONFIG_SMB_SYMLINKS +extern int smb_symlink(struct inode *, struct dentry *, const char *); +#endif + static struct file_operations smb_dir_operations = { @@ -52,7 +58,11 @@ smb_lookup, /* lookup */ NULL, /* link */ smb_unlink, /* unlink */ +#ifdef CONFIG_SMB_SYMLINKS + smb_symlink, /* symlink */ +#else NULL, /* symlink */ +#endif smb_mkdir, /* mkdir */ smb_rmdir, /* rmdir */ NULL, /* mknod */ @@ -425,7 +435,11 @@ #endif smb_invalid_dir_cache(dir); +#ifdef CONFIG_SMB_SYMLINKS /* will it break anything to use mode here? */ + error = smb_proc_create(dentry, mode, CURRENT_TIME, &fileid); +#else error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid); +#endif if (!error) { error = smb_instantiate(dentry, fileid, 1); diff -u -r --new-file linux-2.2.15-raid/fs/smbfs/inode.c linux-2.2.15.s.v0.6-client/fs/smbfs/inode.c --- linux-2.2.15-raid/fs/smbfs/inode.c Mon Jun 14 04:54:06 1999 +++ linux-2.2.15.s.v0.6-client/fs/smbfs/inode.c Fri May 26 02:29:23 2000 @@ -29,7 +29,13 @@ #include #define SMBFS_PARANOIA 1 -/* #define SMBFS_DEBUG_VERBOSE 1 */ + +#ifdef DEBUG +#define SMBFS_DEBUG_VERBOSE 1 +#endif +#ifdef CONFIG_SMB_SYMLINKS +#include "symlink.h" +#endif static void smb_read_inode(struct inode *); static void smb_put_inode(struct inode *); @@ -51,6 +57,21 @@ NULL /* remount filesystem */ }; +#ifdef CONFIG_SMB_SYMLINKS +extern struct address_space_operations smb_symlink_aops; + +extern int smb_symlink(struct inode*, struct dentry*, const char*); +extern int check_symlink(struct inode*); +struct inode_operations smb_symlink_inode_operations; +#endif +#if 0 +static struct inode_operations smb_symlink_inode_operations = { + readlink: page_readlink, + follow_link: page_follow_link, + setattr: smb_notify_change, +}; +#endif + /* FIXME: Look at all inodes whether so that we do not get duplicate * inode numbers. */ @@ -86,6 +107,10 @@ result->i_op = &smb_file_inode_operations; else if (S_ISDIR(result->i_mode)) result->i_op = &smb_dir_inode_operations; +#ifdef CONFIG_SMB_SYMLINKS + else if (S_ISLNK(result->i_mode)) + result->i_op = &smb_symlink_inode_operations; +#endif else result->i_op = NULL; insert_inode_hash(result); @@ -120,11 +145,26 @@ fattr->attr &= ~aRONLY; else fattr->attr |= aRONLY; +#ifdef CONFIG_SMB_SYMLINKS + if (inode->i_mode & S_IFLNK) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_get_inode_attr: setting system attribute of symlink, make sure your server supports it!\n"); +#endif + fattr->attr = fattr->attr | aSYSTEM; + fattr->f_mode = S_IFLNK; +// inode->u.smbfs_i.attr = inode->u.smbfs_i.attr | aSYSTEM; + } else { + fattr->attr = fattr->attr & ~aSYSTEM; + }; +#endif + } static void smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr) { + int error; + inode->i_mode = fattr->f_mode; inode->i_nlink = fattr->f_nlink; inode->i_uid = fattr->f_uid; @@ -143,6 +183,17 @@ inode->i_mtime = fattr->f_mtime; inode->i_atime = fattr->f_atime; } +#ifdef CONFIG_SMB_SYMLINKS +#if defined( SMBFS_DEBUG_VERBOSE) +printk("smb_set_inode_attr: testing inode for system attribute\n"); +#endif + if ((fattr->attr & aSYSTEM) && (fattr->f_size == SMB_MAX_SYMLINK_SIZE)) { +#if defined( SMBFS_DEBUG_VERBOSE) +printk("smb_set_inode_attr: supposing symlink for inode %08x with attributes %08x (A %02x S %02x)\n", inode->i_ino, fattr->attr, aARCH, aSYSTEM); +#endif + inode->i_mode = S_IRWXUGO | (inode->i_mode & ~S_IFMT) | S_IFLNK; + }; +#endif inode->u.smbfs_i.attr = fattr->attr; /* @@ -447,7 +498,11 @@ { struct inode *inode = dentry->d_inode; struct smb_sb_info *server = server_from_dentry(dentry); +#ifdef CONFIG_SMB_SYMLINKS /* this shouldn't do any harm, but anyways */ unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); +#else + unsigned int mask = (S_IFREG | S_IFDIR | S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); +#endif /* CONFIG_SMB_SYMLINKS */ int error, changed, refresh = 0; struct smb_fattr fattr; @@ -530,7 +585,7 @@ { #ifdef SMBFS_DEBUG_VERBOSE printk("smb_notify_change: %s/%s mode change, old=%x, new=%lx\n", -dentry->d_parent->d_name.name, dentry->d_name.name, fattr.f_mode,attr->ia_mode); +dentry->d_parent->d_name.name, dentry->d_name.name, (int)fattr.f_mode,(int)attr->ia_mode); #endif changed = 0; if (attr->ia_mode & S_IWUSR) diff -u -r --new-file linux-2.2.15-raid/fs/smbfs/symlink.c linux-2.2.15.s.v0.6-client/fs/smbfs/symlink.c --- linux-2.2.15-raid/fs/smbfs/symlink.c Thu Jan 1 01:00:00 1970 +++ linux-2.2.15.s.v0.6-client/fs/smbfs/symlink.c Sun May 28 14:50:31 2000 @@ -0,0 +1,317 @@ +/* + * symlink.c + * v 0.6, Sun May 28 14:49:53 CEST 2000 + * + * built using parts of smbfs/file.c + * Copyright (C) 1995, 1996, 1997 by Paal-Kr. Engstad and Volker Lendecke + * Copyright (C) 1997 by Volker Lendecke + * and linux/fs/ncpfs/symlink.c + * Copyright (C) 1998-99, Frank A. Vorstenbosch + * + * (C) 2000 alexander@oelzant.priv.at + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define SMBFS_PARANOIA 1 + +#ifdef DEBUG +#define SMBFS_DEBUG_VERBOSE 1 +#undef pr_debug +#define pr_debug printk +#endif +#include "symlink.h" + +extern int smb_refresh_inode(struct dentry *dentry); + +static int smb_readlink(struct dentry *, char *, int); +static struct dentry *smb_follow_link(struct dentry *dentry, + struct dentry *base, unsigned int follow); + + +/* +int smb_create_new(struct inode *dir, struct dentry *dentry, + int mode,int attributes); +*/ +int smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish); +int smb_create(struct inode *dir, struct dentry *dentry, int mode); +int smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid); + +static inline int +min(int a, int b) +{ + return a < b ? a : b; +} + +/* ----- read a symbolic link ------------------------------------------ */ + +static int smb_readlink(struct dentry *dentry, char *buf, int buflen) +{ + struct inode *inode=dentry->d_inode; + int error, length, cnt; + char *link,c; + + printk("smb_readlink: called ..."); + if(!S_ISLNK(inode->i_mode)) + return -EINVAL; + + error = -EIO; + if (smb_open(dentry,O_RDONLY)) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_readlink: EIO at open\n"); +#endif + goto fail; + } + + error = -ENOMEM; + for (cnt = 0; (link=(char *)kmalloc(SMB_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) { + if (cnt > 10) +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_readlink: ENOMEM at kmalloc\n"); +#endif + goto fail; + schedule(); + } + + error = -EIO; + length = smb_proc_read(dentry, 0, SMB_MAX_SYMLINK_SIZE, link); + +#if defined(SMBFS_DEBUG_VERBOSE) +printk("smb_readlink: %s, %i inode size, %i read length\n", link, (int)inode->i_size,(int)length); +#endif + + if ((link == NULL) || length < SMB_MIN_SYMLINK_SIZE) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_readlink: got bad link, giving -EIO\n"); +#endif + goto fail; + }; + if (length!=SMB_MAX_SYMLINK_SIZE || + ((__u32 *)link)[0]!=SMB_SYMLINK_MAGIC0 || + ((__u32 *)link)[1]!=SMB_SYMLINK_MAGIC1) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_readlink: EIO for %s\n", link); +#endif + kfree(link); + goto fail; + } + + error = -EFAULT; + + cnt=8; + while (cnt < length&& (c = link[cnt])) { + cnt++; + if (cnt>buflen) + goto fail; + put_user (c, buf++); + }; + if (cnt>buflen) + goto fail; + put_user ('\0',buf); +/* + if(cnt=copy_to_user(buf, link+8, strnlen(link+8,(buflend_inode; + int error, length, len, cnt; + char *link; + + + if(!S_ISLNK(inode->i_mode)) { + dput(base); + return ERR_PTR(-EINVAL); + } + + if (smb_open(dentry,O_RDONLY)) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_follow_link: EIO at open\n"); +#endif + dput(base); + return ERR_PTR(-EIO); + } + + for (cnt = 0; (link=(char *)kmalloc(SMB_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) { + if (cnt > 10) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_follow_link: ENOMEM at kmalloc\n"); +#endif + dput(base); + return ERR_PTR(-ENOMEM); + } + schedule(); + } + + error = 0; + length = smb_proc_read(dentry, 0, SMB_MAX_SYMLINK_SIZE, link); + +#if defined(SMBFS_DEBUG_VERBOSE) +printk("smb_follow_link: %s, %i inode size, %i read length\n", link, (int)inode->i_size, (int)length); +#endif + + if ((link == NULL) || length < SMB_MIN_SYMLINK_SIZE) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_follow_link: got bad link, giving -EIO\n"); +#endif + kfree(link); + return ERR_PTR(-EIO); + }; + if (length!=SMB_MAX_SYMLINK_SIZE || + ((__u32 *)link)[0]!=SMB_SYMLINK_MAGIC0 || + ((__u32 *)link)[1]!=SMB_SYMLINK_MAGIC1) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_follow_link: EIO for %s\n", link); +#endif + kfree(link); + return ERR_PTR(-EIO); + } + + len = SMB_MAX_SYMLINK_SIZE; + + base=lookup_dentry(link+8, base, follow); + kfree(link); + return base; + +} + +/* ----- create a new symbolic link -------------------------------------- */ + +int smb_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { + struct inode *inode; + char *link; + int length, err; + +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname); +#endif +/* activate this hook for symlink mount flag + if (!(SMB_SERVER(dir)->m.flags & SMB_MOUNT_SYMLINKS)) + return -EPERM; * EPERM is returned by VFS if symlink procedure + does not exist * +*/ + if ((length=strlen(symname))>SMB_MAX_SYMLINK_SIZE-8) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_symlink: symlink too long, raising SMB_MAX_SYMLINK_SIZE might help\n"); +#endif + return -EINVAL; + } + + if ((link=(char *)kmalloc(SMB_MAX_SYMLINK_SIZE,GFP_NFS))==NULL) + return -ENOMEM; + if (smb_create(dir, dentry, aSYSTEM)){ + kfree(link); + return -EIO; + } + memset(link,0,SMB_MAX_SYMLINK_SIZE); + inode=dentry->d_inode; + ((__u32 *)link)[0]=SMB_SYMLINK_MAGIC0; + ((__u32 *)link)[1]=SMB_SYMLINK_MAGIC1; + + /* map to/from server charset, do not touch upper/lower case as + symlink can point out of ncp filesystem +obsolete for smb? + length += 1; + err = smb_io2vol(SMB_SERVER(inode),link+8,&length,symname,length-1,0); + if (err) { + kfree(link); + return err; + } +*/ + + if (strncpy(link+8,symname,length+1) != (link+8)) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_symlink: bombed on copy (%s)\n",link+8); +#endif + kfree(link); + return -EIO; + } +/* if(smb_write_kernel(SMB_SERVER(inode), SMB_FINFO(inode)->file_handle, + 0, length+8, link, &i) || i!=length+8) { +*/ + if ((err = smb_proc_write(dentry, 0, SMB_MAX_SYMLINK_SIZE, link)) != SMB_MAX_SYMLINK_SIZE) { +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_symlink: bombed on write (%s) error %i\n",link+8, err); +#endif + kfree(link); + return -EIO; + } + inode->i_mode = inode->i_mode = S_IFLNK | S_IRWXUGO; + inode->i_nlink++; + inode->i_ctime = CURRENT_TIME; + inode->i_count++; + inode->i_size = SMB_MAX_SYMLINK_SIZE; + +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_symlink: success (%s)\n",link+8); +#endif + + smb_refresh_inode(dentry); + inode->i_version = ++global_event; + dir->i_version = global_event; + + kfree(link); + return 0; +} + +/* + * symlinks can't do much... + */ + +struct inode_operations smb_symlink_inode_operations = +{ + NULL, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + smb_readlink, /* readlink */ + smb_follow_link, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL /* truncate */ +}; +/* +fs/smbfs/inode.c:static struct inode_operations smb_symlink_inode_operations = { +fs/smbfs/inode.c: result->i_op = &smb_symlink_inode_operations; +fs/smbfs/symlink.c:struct inode_operations smb_symlink_inode_operations = +*/ diff -u -r --new-file linux-2.2.15-raid/fs/smbfs/symlink.h linux-2.2.15.s.v0.6-client/fs/smbfs/symlink.h --- linux-2.2.15-raid/fs/smbfs/symlink.h Thu Jan 1 01:00:00 1970 +++ linux-2.2.15.s.v0.6-client/fs/smbfs/symlink.h Thu May 25 23:15:13 2000 @@ -0,0 +1,21 @@ +#ifndef _FS_SMBFS_SYMLINK_H +#define _FS_SMBFS_SYMLINK_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. + +taken from fs/ncpfs/symlinks.c; this should really be in an include +file so interested parties can just share it +-aoe */ + +#define SMB_SYMLINK_MAGIC0 le32_to_cpu(0x6c6d7973) /* "symlnk->" */ +#define SMB_SYMLINK_MAGIC1 le32_to_cpu(0x3e2d6b6e) + +/* adopted from fs/ncpfs/ncplib_kernel.h */ + +#define SMB_MIN_SYMLINK_SIZE 8 +#define SMB_MAX_SYMLINK_SIZE 269 + +#define TWENTY_YEARS 631152043 /* wtf? yields 631152000 on my clock */ +#define TEN_YEARS (TWENTY_YEARS/2) + +#endif /* _FS_SMBFS_SYMLINK_H */