diff -r -c --new-file linux-2.3.99-pre3/Documentation/Configure.help linux-2.3.99-pre3.smb/Documentation/Configure.help *** linux-2.3.99-pre3/Documentation/Configure.help Tue Apr 11 01:41:37 2000 --- linux-2.3.99-pre3.smb/Documentation/Configure.help Fri Apr 21 22:38:38 2000 *************** *** 10007,10012 **** --- 10007,10023 ---- 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.3.99-pre3/fs/Config.in linux-2.3.99-pre3.smb/fs/Config.in *** linux-2.3.99-pre3/fs/Config.in Fri Apr 21 21:54:53 2000 --- linux-2.3.99-pre3.smb/fs/Config.in Sat Apr 15 15:17:53 2000 *************** *** 113,118 **** --- 113,121 ---- define_bool CONFIG_LOCKD_V4 y fi tristate 'SMB file system support (to mount Windows 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 file system support (to mount NetWare volumes)' CONFIG_NCP_FS diff -r -c --new-file linux-2.3.99-pre3/fs/smbfs/Makefile linux-2.3.99-pre3.smb/fs/smbfs/Makefile *** linux-2.3.99-pre3/fs/smbfs/Makefile Sun Oct 12 19:17:05 1997 --- linux-2.3.99-pre3.smb/fs/smbfs/Makefile Wed Apr 19 12:06:23 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.3.99-pre3/fs/smbfs/dir.c linux-2.3.99-pre3.smb/fs/smbfs/dir.c *** linux-2.3.99-pre3/fs/smbfs/dir.c Wed Mar 8 18:04:09 2000 --- linux-2.3.99-pre3.smb/fs/smbfs/dir.c Wed Apr 19 15:32:09 2000 *************** *** 28,33 **** --- 28,37 ---- 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 = { *************** *** 42,47 **** --- 46,54 ---- 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, *************** *** 399,405 **** --- 406,416 ---- #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.3.99-pre3/fs/smbfs/inode.c linux-2.3.99-pre3.smb/fs/smbfs/inode.c *** linux-2.3.99-pre3/fs/smbfs/inode.c Wed Apr 19 12:01:11 2000 --- linux-2.3.99-pre3.smb/fs/smbfs/inode.c Fri Apr 21 21:53:01 2000 *************** *** 27,33 **** #include #define SMBFS_PARANOIA 1 ! /* #define SMBFS_DEBUG_VERBOSE 1 */ static void smb_put_inode(struct inode *); static void smb_delete_inode(struct inode *); --- 27,39 ---- #include #define SMBFS_PARANOIA 1 ! ! #ifdef DEBUG ! #define SMBFS_DEBUG_VERBOSE 1 ! #endif ! #ifdef CONFIG_SMB_SYMLINKS ! #include "symlink.h" ! #endif static void smb_put_inode(struct inode *); static void smb_delete_inode(struct inode *); *************** *** 43,48 **** --- 49,67 ---- 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*); + + 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. */ *************** *** 83,88 **** --- 102,112 ---- } 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 **** --- 140,165 ---- 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 **** --- 178,194 ---- 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) { + #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 = (inode->i_mode & ~S_IFMT) | S_IFLNK; + }; + #endif inode->u.smbfs_i.attr = fattr->attr; /* *************** *** 419,425 **** --- 469,479 ---- { 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.3.99-pre3/fs/smbfs/symlink.c linux-2.3.99-pre3.smb/fs/smbfs/symlink.c *** linux-2.3.99-pre3/fs/smbfs/symlink.c Thu Jan 1 01:00:00 1970 --- linux-2.3.99-pre3.smb/fs/smbfs/symlink.c Fri Apr 28 01:51:02 2000 *************** *** 0 **** --- 1,205 ---- + /* + * symlink.c + * + * 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); + + static inline int + min(int a, int b) + { + return a < b ? a : b; + } + + /* ----- read a symbolic link ------------------------------------------ */ + + static int smb_symlink_readpage(struct dentry *dentry, struct page *page) + { + + struct inode *inode=dentry->d_inode; + int error, length, len, cnt; + char *link; + char *buf = (char*)kmap(page); + + error = -EIO; + if (smb_open(dentry,O_RDONLY)) { + #ifdef SMBFS_DEBUG_VERBOSE + printk("smb_symlink_readpage: 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_symlink_readpage: ENOMEM at kmalloc\n"); + #endif + goto fail; + schedule(); + } + + error = 0; + length = smb_proc_read(dentry, 0, SMB_MAX_SYMLINK_SIZE, link); + + #if defined(SMBFS_DEBUG_VERBOSE) + 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 (lengthm.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(length+9,GFP_NFS))==NULL) + return -ENOMEM; + if (smb_create(dir, dentry, aSYSTEM)){ + kfree(link); + return -EIO; + } + 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; + } + link[8+length]='\0'; + /* 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, length+9, link)) != length+9) { + #ifdef SMBFS_DEBUG_VERBOSE + printk("smb_symlink: bombed on write (%s) error %i\n",link+8, err); + #endif + kfree(link); + return -EIO; + } + + #ifdef SMBFS_DEBUG_VERBOSE + printk("smb_symlink: success (%s)\n",link+8); + #endif + kfree(link); + return 0; + } diff -r -c --new-file linux-2.3.99-pre3/fs/smbfs/symlink.h linux-2.3.99-pre3.smb/fs/smbfs/symlink.h *** linux-2.3.99-pre3/fs/smbfs/symlink.h Thu Jan 1 01:00:00 1970 --- linux-2.3.99-pre3.smb/fs/smbfs/symlink.h Wed Apr 19 12:06:18 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 512 + + #define TWENTY_YEARS 631152043 /* wtf? yields 631152000 on my clock */ + #define TEN_YEARS (TWENTY_YEARS/2) + + #endif /* _FS_SMBFS_SYMLINK_H */