diff -r -c --new-file linux-2.4.0-pre4/Documentation/Configure.help linux-2.4.0-pre4.smb/Documentation/Configure.help *** linux-2.4.0-pre4/Documentation/Configure.help Fri Jul 28 15:36:48 2000 --- linux-2.4.0-pre4.smb/Documentation/Configure.help Fri Jul 28 15:04:03 2000 *************** *** 11170,11175 **** --- 11170,11186 ---- 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 diff -r -c --new-file linux-2.4.0-pre4/fs/Config.in linux-2.4.0-pre4.smb/fs/Config.in *** linux-2.4.0-pre4/fs/Config.in Fri Jul 28 15:36:48 2000 --- linux-2.4.0-pre4.smb/fs/Config.in Fri Jul 28 15:38:04 2000 *************** *** 96,101 **** --- 96,104 ---- fi dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET + if [ "$CONFIG_SMB_FS" = "y" -o "$CONFIG_SMB_FS" = "m" ]; then + bool 'SMB devel symlink support (EXPERIMENTAL)' CONFIG_SMB_SYMLINKS + fi if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS diff -r -c --new-file linux-2.4.0-pre4/fs/smbfs/Makefile linux-2.4.0-pre4.smb/fs/smbfs/Makefile *** linux-2.4.0-pre4/fs/smbfs/Makefile Fri Jul 28 15:36:48 2000 --- linux-2.4.0-pre4.smb/fs/smbfs/Makefile Sat Jul 29 23:22:47 2000 *************** *** 8,14 **** # 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 M_OBJS := $(O_TARGET) # If you want debugging output, please uncomment the following line --- 8,18 ---- # 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 ! 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 -r -c --new-file linux-2.4.0-pre4/fs/smbfs/dir.c linux-2.4.0-pre4.smb/fs/smbfs/dir.c *** linux-2.4.0-pre4/fs/smbfs/dir.c Fri Jul 28 15:36:48 2000 --- linux-2.4.0-pre4.smb/fs/smbfs/dir.c Sat Jul 29 15:17:14 2000 *************** *** 15,21 **** #include #define SMBFS_PARANOIA 1 ! /* #define SMBFS_DEBUG_VERBOSE 1 */ /* #define pr_debug printk */ #define SMBFS_MAX_AGE 5*HZ --- 15,23 ---- #include #define SMBFS_PARANOIA 1 ! #ifdef DEBUG ! #define SMBFS_DEBUG_VERBOSE 1 ! #endif /* #define pr_debug printk */ #define SMBFS_MAX_AGE 5*HZ *************** *** 29,34 **** --- 31,40 ---- 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 + struct file_operations smb_dir_operations = { *************** *** 43,48 **** --- 49,57 ---- create: smb_create, lookup: smb_lookup, unlink: smb_unlink, + #ifdef CONFIG_SMB_SYMLINKS + symlink: smb_symlink, + #endif mkdir: smb_mkdir, rmdir: smb_rmdir, rename: smb_rename, *************** *** 405,411 **** --- 414,424 ---- #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 -r -c --new-file linux-2.4.0-pre4/fs/smbfs/file.c linux-2.4.0-pre4.smb/fs/smbfs/file.c *** linux-2.4.0-pre4/fs/smbfs/file.c Fri Jul 21 02:16:47 2000 --- linux-2.4.0-pre4.smb/fs/smbfs/file.c Sat Jul 29 23:22:29 2000 *************** *** 95,101 **** --- 95,112 ---- smb_readpage(struct file *file, struct page *page) { int error; + #ifndef CONFIG_SMB_SYMLINKS struct dentry *dentry = file->f_dentry; + #else + /* shame over me, occasionally fresh symlinks end up here and there + is no file to point to ... */ + struct dentry *dentry; + + if (file != NULL) + dentry = file->f_dentry; + else + return smb_symlink_readpage(file,page); + #endif pr_debug("SMB: smb_readpage %08lx\n", page_address(page)); #ifdef SMBFS_PARANOIA diff -r -c --new-file linux-2.4.0-pre4/fs/smbfs/inode.c linux-2.4.0-pre4.smb/fs/smbfs/inode.c *** linux-2.4.0-pre4/fs/smbfs/inode.c Fri Jul 28 15:36:48 2000 --- linux-2.4.0-pre4.smb/fs/smbfs/inode.c Sat Jul 29 22:52:25 2000 *************** *** 28,34 **** #include #define SMBFS_PARANOIA 1 ! /* #define SMBFS_DEBUG_VERBOSE 1 */ static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); --- 28,40 ---- #include #define SMBFS_PARANOIA 1 ! ! #ifdef DEBUG ! #define SMBFS_DEBUG_VERBOSE 1 ! #endif ! #ifdef CONFIG_SMB_SYMLINKS ! #include "symlink.h" ! #endif static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); *************** *** 43,48 **** --- 49,63 ---- statfs: smb_statfs, }; + #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*); + + extern struct inode_operations smb_symlink_inode_operations; + #endif + /* FIXME: Look at all inodes whether so that we do not get duplicate * inode numbers. */ *************** *** 83,88 **** --- 98,108 ---- } else if (S_ISDIR(result->i_mode)) { result->i_op = &smb_dir_inode_operations; result->i_fop = &smb_dir_operations; + #ifdef CONFIG_SMB_SYMLINKS + } else if (S_ISLNK(result->i_mode)) { + result->i_op = &smb_symlink_inode_operations; + result->i_data.a_ops = &smb_symlink_aops; + #endif } insert_inode_hash(result); return result; *************** *** 116,126 **** --- 136,161 ---- 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; *************** *** 139,144 **** --- 174,190 ---- 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 = fattr->f_mode = S_IFLNK | S_IRWXUGO; + }; + #endif inode->u.smbfs_i.attr = fattr->attr; /* *************** *** 227,234 **** int error = 0; pr_debug("smb_revalidate_inode\n"); ! /* ! * If this is a file opened with write permissions, * the inode will be up-to-date. */ lock_kernel(); --- 273,279 ---- int error = 0; pr_debug("smb_revalidate_inode\n"); ! /* If this is a file opened with write permissions, * the inode will be up-to-date. */ lock_kernel(); *************** *** 411,417 **** --- 456,466 ---- { 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; diff -r -c --new-file linux-2.4.0-pre4/fs/smbfs/proc.c linux-2.4.0-pre4.smb/fs/smbfs/proc.c *** linux-2.4.0-pre4/fs/smbfs/proc.c Wed Jul 19 20:23:36 2000 --- linux-2.4.0-pre4.smb/fs/smbfs/proc.c Sat Jul 29 20:04:30 2000 *************** *** 23,34 **** #include #include #include #define SMBFS_PARANOIA 1 ! /* #define SMBFS_DEBUG_TIMESTAMP 1 */ ! /* #define SMBFS_DEBUG_VERBOSE 1 */ ! /* #define pr_debug printk */ #define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN) #define SMB_CMD(packet) (*(packet+8)) --- 23,40 ---- #include #include + #ifdef CONFIG_SMB_SYMLINKS + #include "symlink.h" + #endif + #include #define SMBFS_PARANOIA 1 ! #ifdef DEBUG ! #define SMBFS_DEBUG_TIMESTAMP 1 ! #define SMBFS_DEBUG_VERBOSE 1 ! #define pr_debug printk ! #endif #define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN) #define SMB_CMD(packet) (*(packet+8)) *************** *** 1215,1220 **** --- 1221,1232 ---- /* Check the read-only flag */ if (fattr->attr & aRONLY) fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + + #ifdef CONFIG_SMB_SYMLINKS + /* set link bit */ + if ((fattr->attr & aSYSTEM) && (fattr->f_size == SMB_MAX_SYMLINK_SIZE)) + fattr->f_mode = S_IFLNK | S_IRWXUGO; + #endif fattr->f_blocks = 0; if ((fattr->f_blksize != 0) && (fattr->f_size != 0)) diff -r -c --new-file linux-2.4.0-pre4/fs/smbfs/symlink.c linux-2.4.0-pre4.smb/fs/smbfs/symlink.c *** linux-2.4.0-pre4/fs/smbfs/symlink.c Thu Jan 1 01:00:00 1970 --- linux-2.4.0-pre4.smb/fs/smbfs/symlink.c Sat Jul 29 23:27:01 2000 *************** *** 0 **** --- 1,272 ---- + /* + * symlink.c + * v 0.6, Fri Jul 28 16:12:58 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" + + /* + 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); + extern struct inode_operations smb_symlink_inode_operations; + + static inline int + min(int a, int b) + { + return a < b ? a : b; + } + + /* ----- read a symbolic link ------------------------------------------ */ + + static int smb_symlink_readpage(struct file *file, struct page *page) + { + + struct dentry *dentry; + struct inode *inode; + int error, length, len, cnt; + char *link; + char *buf; + + #ifdef SMBFS_DEBUG_VERBOSE + printk("smb_symlink_readpage: "); + #endif + error = -EIO; + inode= (struct inode*)page->mapping->host; + if (!page) { + #ifdef SMBFS_DEBUG_VERBOSE + printk("readpage called with null page\n"); + #endif + goto fail; + } + buf = (char*)kmap(page); + if (!inode) { + #ifdef SMBFS_DEBUG_VERBOSE + printk("no inode mapped\n"); + #endif + goto fail; + } + + dentry = d_find_alias(inode); + if (!dentry) { + #ifdef SMBFS_DEBUG_VERBOSE + printk("no dentry found"); + #endif + goto fail; + } + + if (smb_open(dentry,O_RDONLY)) { + #ifdef SMBFS_DEBUG_VERBOSE + printk("EIO at open\n"); + #endif + goto fail; + } + #ifdef SMBFS_DEBUG_VERBOSE + printk("open, "); + #endif + + 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_symlink_readpage: ENOMEM at kmalloc\n"); + #endif + goto fail; + schedule(); + } + #ifdef SMBFS_DEBUG_VERBOSE + printk("malloc, "); + #endif + + error = 0; + length = smb_proc_read(dentry, 0, SMB_MAX_SYMLINK_SIZE, link); + #ifdef SMBFS_DEBUG_VERBOSE + printk("read, "); + #endif + + #if defined(SMBFS_DEBUG_VERBOSE) && 1 + printk("smb_symlink_readpage: %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_symlink_readpage: got bad link, giving -EIO\n"); + #endif + error = -EIO; + goto fail; + }; + if ((length != SMB_MAX_SYMLINK_SIZE) || + ((__u32 *)link)[0]!=SMB_SYMLINK_MAGIC0 || + ((__u32 *)link)[1]!=SMB_SYMLINK_MAGIC1) { + error = -EIO; + #ifdef SMBFS_DEBUG_VERBOSE + printk("smb_symlink_readpage: EIO for %s\n", link); + #endif + kfree(link); + goto fail; + } + #ifdef SMBFS_DEBUG_VERBOSE + printk("check, "); + #endif + + len = SMB_MAX_SYMLINK_SIZE; + if (strncpy(buf,link+8,length-8) != buf) { + error = -EIO; + #ifdef SMBFS_DEBUG_VERBOSE + printk("smb_symlink_readpage: EIO for strncpy of %s\n", link); + #endif + } + buf[SMB_MAX_SYMLINK_SIZE-8]='\0'; + #ifdef SMBFS_DEBUG_VERBOSE + printk("copy, "); + #endif + kfree(link); + if (error) + goto fail; + SetPageUptodate(page); + kunmap(page); + UnlockPage(page); + + #ifdef SMBFS_DEBUG_VERBOSE + printk("all ok\n"); + #endif + return 0; + + fail: + + SetPageError(page); + kunmap(page); + UnlockPage(page); + + return error; + } + + /* + * symlinks can't do much... + */ + + + struct address_space_operations smb_symlink_aops = { + readpage: smb_symlink_readpage, + }; + + /* ----- 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; + } + inode=dentry->d_inode; + inode->i_size=SMB_MAX_SYMLINK_SIZE; + inode->u.smbfs_i.cache_valid |= SMB_F_LOCALWRITE; + inode->i_mode=S_IRWXUGO | S_IFLNK; + inode->i_op = &smb_symlink_inode_operations; + memset(link,0,SMB_MAX_SYMLINK_SIZE); + ((__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) != (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; + } + + + /* smb_refresh_inode(dentry); */ + smb_revalidate_inode(dentry); + + + #ifdef SMBFS_DEBUG_VERBOSE + printk("smb_symlink: success (%s)\n",link+8); + #endif + kfree(link); + return 0; + } + + struct inode_operations smb_symlink_inode_operations = { + readlink: page_readlink, + follow_link: page_follow_link, + revalidate: smb_revalidate_inode, + setattr: smb_notify_change, + }; + diff -r -c --new-file linux-2.4.0-pre4/fs/smbfs/symlink.h linux-2.4.0-pre4.smb/fs/smbfs/symlink.h *** linux-2.4.0-pre4/fs/smbfs/symlink.h Thu Jan 1 01:00:00 1970 --- linux-2.4.0-pre4.smb/fs/smbfs/symlink.h Sat Jul 29 15:37:52 2000 *************** *** 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 */