diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/ChangeLog /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/ChangeLog --- linux-2.4.9-31/fs/smbfs/ChangeLog Thu Jun 21 09:07:57 2001 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/ChangeLog Sun Apr 7 12:43:08 2002 @@ -1,5 +1,47 @@ ChangeLog for smbfs. +2001-12-31 René Scharfe + + * inode.c: added smb_show_options to show mount options in /proc/mounts + * inode.c, getopt.c, getopt.h: merged flag and has_arg in struct option + * inode.c: use S_IRWXUGO where appropriate + +2001-12-22 Urban Widmark + + * file.c, proc.c: Fix problems triggered by the "fsx test" + +2002-02-02 John Newbigin + * Clean up codeing style and CIFS Extensions for UNIX bugs + * Implement follow_link + +2002-01-28 John Newbigin + * Implementation of CIFS Extensions for UNIX systems + +2001-09-17 Urban Widmark + + * proc.c: Use 4096 (was 512) as the blocksize for better write + performance (patch originally by Jan Kratochvil) + * proc.c: Skip disconnect smb, allows umount on unreachable servers. + * proc.c: Go back to the interruptible sleep as reconnects seem to + handle it now. + * *.c: use autogenerated and private proto.h + +2000-11-22 Igor Zhbanov + + * proc.c: fixed date_unix2dos for dates earlier than 01/01/1980 + and date_dos2unix for date==0 (from 2.2) + +2001-07-13 Rob Radez + + * proc.c: make smb_errno return negative error values + +2001-07-09 Jochen Dolze + + * inode.c: smb_statfs always returned success. + * proc.c, ioctl.c: Allow smbmount to signal failure to reconnect with + a NULL argument to SMB_IOC_NEWCONN (speeds up error detection). + * proc.c: Add some of the missing error codes to smb_errno + 2001-06-12 Urban Widmark * proc.c: replace the win95-flush fix with smb_seek, when needed. diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/Makefile /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/Makefile --- linux-2.4.9-31/fs/smbfs/Makefile Sat Feb 17 11:04:24 2001 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/Makefile Sun Apr 7 12:43:08 2002 @@ -9,7 +9,7 @@ O_TARGET := smbfs.o -obj-y := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o +obj-y := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o symlink.o obj-m := $(O_TARGET) # If you want debugging output, you may add these flags to the EXTRA_CFLAGS @@ -23,3 +23,19 @@ #EXTRA_CFLAGS += -Werror include $(TOPDIR)/Rules.make + +# +# Maintainer rules +# + +# getopt.c not included. It is intentionally separate +SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c symlink.c + +proto: + -rm -f proto.h + @echo > proto2.h "/*" + @echo >> proto2.h " * Autogenerated with cproto on: " `date` + @echo >> proto2.h " */" + @echo >> proto2.h "" + cproto -E "gcc -E" -e -v -I $(TOPDIR)/include -DMAKING_PROTO -D__KERNEL__ $(SRC) >> proto2.h + mv proto2.h proto.h diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/cache.c /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/cache.c --- linux-2.4.9-31/fs/smbfs/cache.c Sat Mar 24 06:50:52 2001 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/cache.c Wed Oct 3 10:03:34 2001 @@ -20,6 +20,7 @@ #include #include "smb_debug.h" +#include "proto.h" /* * Force the next attempt to use the cache to be a timeout. diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/dir.c /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/dir.c --- linux-2.4.9-31/fs/smbfs/dir.c Wed May 16 06:40:55 2001 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/dir.c Fri Apr 12 18:09:17 2002 @@ -18,6 +18,7 @@ #include #include "smb_debug.h" +#include "proto.h" static int smb_readdir(struct file *, void *, filldir_t); static int smb_dir_open(struct inode *, struct file *); @@ -29,6 +30,8 @@ static int smb_unlink(struct inode *, struct dentry *); static int smb_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); +static int smb_make_node(struct inode *,struct dentry *,int,int); +static int smb_link(struct dentry *, struct inode *, struct dentry *); struct file_operations smb_dir_operations = { @@ -48,6 +51,9 @@ rename: smb_rename, revalidate: smb_revalidate_inode, setattr: smb_notify_change, + symlink: smb_symlink, + mknod: smb_make_node, + link: smb_link, }; /* @@ -452,8 +458,7 @@ if (!inode) goto out_no_inode; - if (have_id) - { + if (have_id) { inode->u.smbfs_i.fileid = fileid; inode->u.smbfs_i.access = SMB_O_RDWR; inode->u.smbfs_i.open = server->generation; @@ -465,8 +470,7 @@ out_no_inode: error = -EACCES; out_close: - if (have_id) - { + if (have_id) { PARANOIA("%s/%s failed, error=%d, closing %u\n", DENTRY_PATH(dentry), error, fileid); smb_close_fileid(dentry, fileid); @@ -480,12 +484,19 @@ { __u16 fileid; int error; + struct iattr attr; VERBOSE("creating %s/%s, mode=%d\n", DENTRY_PATH(dentry), mode); smb_invalid_dir_cache(dir); error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid); if (!error) { + if(server_from_dentry(dentry)->opt.capabilities & SMB_CAP_UNIX) { + /* Set attributes for new directory */ + attr.ia_valid = ATTR_MODE; + attr.ia_mode = mode; + error = smb_proc_setattr_unix(dentry, &attr); + } error = smb_instantiate(dentry, fileid, 1); } else { PARANOIA("%s/%s failed, error=%d\n", @@ -499,10 +510,17 @@ smb_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int error; + struct iattr attr; smb_invalid_dir_cache(dir); error = smb_proc_mkdir(dentry); if (!error) { + if(server_from_dentry(dentry)->opt.capabilities & SMB_CAP_UNIX) { + /* Set attributes for new directory */ + attr.ia_valid = ATTR_MODE; + attr.ia_mode = mode; + error = smb_proc_setattr_unix(dentry, &attr); + } error = smb_instantiate(dentry, 0, 0); } return error; @@ -562,12 +580,10 @@ */ if (old_dentry->d_inode) smb_close(old_dentry->d_inode); - if (new_dentry->d_inode) - { + if (new_dentry->d_inode) { smb_close(new_dentry->d_inode); error = smb_proc_unlink(new_dentry); - if (error) - { + if (error) { VERBOSE("unlink %s/%s, error=%d\n", DENTRY_PATH(new_dentry), error); goto out; @@ -579,11 +595,56 @@ smb_invalid_dir_cache(old_dir); smb_invalid_dir_cache(new_dir); error = smb_proc_mv(old_dentry, new_dentry); - if (!error) - { + if (!error) { smb_renew_times(old_dentry); smb_renew_times(new_dentry); } out: return error; } + +static +int smb_make_node(struct inode *inode,struct dentry *dentry,int mode,int dev) +{ + int error = -EPERM; + + if(S_ISCHR(mode)) { + DEBUG1("Request to make a char device node\n"); + } + else if(S_ISBLK(mode)) { + DEBUG1("Request to make a block device node\n"); + } + else if(S_ISFIFO(mode)) { + DEBUG1("Request to make a fifo node\n"); + } + else if(S_ISSOCK(mode)) { + DEBUG1("Request to make a socket node\n"); + } + else { + DEBUG1("Request to make a unsupported node\n"); + } + + return error; +} + +/* + * dentry = existing file + * new_dentry = new file + */ +static int smb_link(struct dentry *dentry, struct inode *dir, struct dentry *new_dentry) +{ + int error; + + DEBUG1("smb_link\n"); + DEBUG1("dentry1 %s/%s\n", DENTRY_PATH(dentry)); + DEBUG1("dentry2 %s/%s\n", DENTRY_PATH(new_dentry)); + + smb_invalid_dir_cache(dir); + error = smb_proc_link(server_from_dentry(dentry), dentry, new_dentry); + if (!error) { + smb_renew_times(dentry); + error = smb_instantiate(new_dentry, 0, 0); + } + return error; +} + diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/file.c /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/file.c --- linux-2.4.9-31/fs/smbfs/file.c Mon Aug 13 04:13:59 2001 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/file.c Mon Apr 8 02:34:38 2002 @@ -24,6 +24,8 @@ #include #include "smb_debug.h" +#include "proto.h" + static int smb_fsync(struct file *file, struct dentry * dentry, int datasync) @@ -269,7 +271,6 @@ static int smb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { - kmap(page); return 0; } @@ -282,7 +283,6 @@ lock_kernel(); status = smb_updatepage(file, page, offset, to-offset); unlock_kernel(); - kunmap(page); return status; } @@ -348,8 +348,14 @@ smb_file_release(struct inode *inode, struct file * file) { lock_kernel(); - if (!--inode->u.smbfs_i.openers) + if (!--inode->u.smbfs_i.openers) { + /* We must flush any dirty pages now as we won't be able to + write anything after close. mmap can trigger this. + "openers" should perhaps include mmap'ers ... */ + filemap_fdatasync(inode->i_mapping); + filemap_fdatawait(inode->i_mapping); smb_close(inode); + } unlock_kernel(); return 0; } diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/getopt.c /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/getopt.c --- linux-2.4.9-31/fs/smbfs/getopt.c Sat Apr 28 07:10:32 2001 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/getopt.c Tue Feb 26 06:38:09 2002 @@ -46,7 +46,7 @@ for (i = 0; opts[i].name != NULL; i++) { if (!strcmp(opts[i].name, token)) { - if (opts[i].has_arg && (!val || !*val)) { + if (!opts[i].flag && (!val || !*val)) { printk("%s: the %s option requires an argument\n", caller, token); return -1; diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/getopt.h /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/getopt.h --- linux-2.4.9-31/fs/smbfs/getopt.h Tue Aug 15 06:31:10 2000 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/getopt.h Tue Feb 26 06:38:09 2002 @@ -3,7 +3,6 @@ struct option { const char *name; - int has_arg; unsigned long flag; int val; }; diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/inode.c /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/inode.c --- linux-2.4.9-31/fs/smbfs/inode.c Tue Feb 26 21:50:50 2002 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/inode.c Sun Apr 7 21:39:22 2002 @@ -22,6 +22,7 @@ #include #include #include +/* #include */ #include #include @@ -32,6 +33,7 @@ #include "smb_debug.h" #include "getopt.h" +#include "proto.h" /* Always pick a default string */ #ifdef CONFIG_SMB_NLS_REMOTE @@ -40,9 +42,12 @@ #define SMB_NLS_REMOTE "" #endif +#define SMB_TTL_DEFAULT 1000 + static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); static int smb_statfs(struct super_block *, struct statfs *); +/* static int smb_show_options(struct seq_file *, struct vfsmount *); */ static struct super_operations smb_sops = { @@ -50,6 +55,7 @@ delete_inode: smb_delete_inode, put_super: smb_put_super, statfs: smb_statfs, +/* show_options: smb_show_options, */ }; @@ -59,7 +65,7 @@ { struct inode *result; - DEBUG1("smb_iget: %p\n", fattr); + VERBOSE("smb_iget: %p\n", fattr); result = new_inode(sb); if (!result) @@ -74,6 +80,12 @@ } else if (S_ISDIR(result->i_mode)) { result->i_op = &smb_dir_inode_operations; result->i_fop = &smb_dir_operations; + } else if(S_ISLNK(result->i_mode)) { + DEBUG1("iget a symlink\n"); + result->i_op = &smb_link_inode_operations; + } else { + DEBUG1("iget special node type\n"); + init_special_inode(result, result->i_mode, fattr->f_rdev); } insert_inode_hash(result); return result; @@ -181,7 +193,22 @@ * Check whether the type part of the mode changed, * and don't update the attributes if it did. */ - if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) { + + /* + * Don't dick with the root inode + */ + VERBOSE("inode no %ld\n", inode->i_ino); + if(inode->i_ino == 2) + { + return error; + } + if(S_ISLNK(inode->i_mode)) { + /* + * We don't need to do anything here because the vfs will + * call follow_link to find the target. + */ + + } else if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) { smb_set_inode_attr(inode, &fattr); } else { /* @@ -225,7 +252,7 @@ struct inode *inode = dentry->d_inode; int error = 0; - DEBUG1("smb_revalidate_inode\n"); + VERBOSE("smb_revalidate_inode\n"); lock_kernel(); /* @@ -258,21 +285,20 @@ clear_inode(ino); } -/* FIXME: flags and has_arg could probably be merged. */ -struct option opts[] = { - { "version", 1, 0, 'v' }, - { "win95", 0, SMB_MOUNT_WIN95, 1 }, - { "oldattr", 0, SMB_MOUNT_OLDATTR, 1 }, - { "dirattr", 0, SMB_MOUNT_DIRATTR, 1 }, - { "case", 0, SMB_MOUNT_CASE, 1 }, - { "uid", 1, 0, 'u' }, - { "gid", 1, 0, 'g' }, - { "file_mode", 1, 0, 'f' }, - { "dir_mode", 1, 0, 'd' }, - { "iocharset", 1, 0, 'i' }, - { "codepage", 1, 0, 'c' }, - { "ttl", 1, 0, 't' }, - { NULL, 0, 0, 0} +static struct option opts[] = { + { "version", 0, 'v' }, + { "win95", SMB_MOUNT_WIN95, 1 }, + { "oldattr", SMB_MOUNT_OLDATTR, 1 }, + { "dirattr", SMB_MOUNT_DIRATTR, 1 }, + { "case", SMB_MOUNT_CASE, 1 }, + { "uid", 0, 'u' }, + { "gid", 0, 'g' }, + { "file_mode", 0, 'f' }, + { "dir_mode", 0, 'd' }, + { "iocharset", 0, 'i' }, + { "codepage", 0, 'c' }, + { "ttl", 0, 't' }, + { NULL, 0, 0} }; static int @@ -309,12 +335,10 @@ mnt->gid = value; break; case 'f': - mnt->file_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->file_mode |= S_IFREG; + mnt->file_mode = (value & S_IRWXUGO) | S_IFREG; break; case 'd': - mnt->dir_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->dir_mode |= S_IFDIR; + mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR; break; case 'i': strncpy(mnt->codepage.local_name, optarg, @@ -337,6 +361,47 @@ return c; } +/* + * smb_show_options() is for displaying mount options in /proc/mounts. + * It tries to avoid showing settings that were not changed from their + * defaults. + */ +#if 0 +static int +smb_show_options(struct seq_file *s, struct vfsmount *m) +{ + struct smb_mount_data_kernel *mnt = m->mnt_sb->u.smbfs_sb.mnt; + int i; + + for (i = 0; opts[i].name != NULL; i++) + if (mnt->flags & opts[i].flag) + seq_printf(s, ",%s", opts[i].name); + + if (mnt->uid != 0) + seq_printf(s, ",uid=%d", mnt->uid); + if (mnt->gid != 0) + seq_printf(s, ",gid=%d", mnt->gid); + if (mnt->mounted_uid != 0) + seq_printf(s, ",mounted_uid=%d", mnt->mounted_uid); + + /* + * Defaults for file_mode and dir_mode are unknown to us; they + * depend on the current umask of the user doing the mount. + */ + seq_printf(s, ",file_mode=%04o", mnt->file_mode & S_IRWXUGO); + seq_printf(s, ",dir_mode=%04o", mnt->dir_mode & S_IRWXUGO); + + if (strcmp(mnt->codepage.local_name, CONFIG_NLS_DEFAULT)) + seq_printf(s, ",iocharset=%s", mnt->codepage.local_name); + if (strcmp(mnt->codepage.remote_name, SMB_NLS_REMOTE)) + seq_printf(s, ",codepage=%s", mnt->codepage.remote_name); + + if (mnt->ttl != SMB_TTL_DEFAULT) + seq_printf(s, ",ttl=%d", mnt->ttl); + + return 0; +} +#endif static void smb_put_super(struct super_block *sb) @@ -344,7 +409,6 @@ struct smb_sb_info *server = &(sb->u.smbfs_sb); if (server->sock_file) { - smb_proc_disconnect(server); smb_dont_catch_keepalive(server); fput(server->sock_file); } @@ -353,23 +417,24 @@ kill_proc(server->conn_pid, SIGTERM, 1); smb_kfree(server->mnt); - smb_kfree(sb->u.smbfs_sb.temp_buf); + smb_kfree(server->temp_buf); if (server->packet) smb_vfree(server->packet); - if(sb->u.smbfs_sb.remote_nls) { - unload_nls(sb->u.smbfs_sb.remote_nls); - sb->u.smbfs_sb.remote_nls = NULL; - } - if(sb->u.smbfs_sb.local_nls) { - unload_nls(sb->u.smbfs_sb.local_nls); - sb->u.smbfs_sb.local_nls = NULL; + if (server->remote_nls) { + unload_nls(server->remote_nls); + server->remote_nls = NULL; + } + if (server->local_nls) { + unload_nls(server->local_nls); + server->local_nls = NULL; } } struct super_block * smb_read_super(struct super_block *sb, void *raw_data, int silent) { + struct smb_sb_info *server = &sb->u.smbfs_sb; struct smb_mount_data_kernel *mnt; struct smb_mount_data *oldmnt; struct inode *root_inode; @@ -389,34 +454,34 @@ sb->s_magic = SMB_SUPER_MAGIC; sb->s_op = &smb_sops; - sb->u.smbfs_sb.mnt = NULL; - sb->u.smbfs_sb.sock_file = NULL; - init_MUTEX(&sb->u.smbfs_sb.sem); - init_waitqueue_head(&sb->u.smbfs_sb.wait); - sb->u.smbfs_sb.conn_pid = 0; - sb->u.smbfs_sb.state = CONN_INVALID; /* no connection yet */ - sb->u.smbfs_sb.generation = 0; - sb->u.smbfs_sb.packet_size = smb_round_length(SMB_INITIAL_PACKET_SIZE); - sb->u.smbfs_sb.packet = smb_vmalloc(sb->u.smbfs_sb.packet_size); - if (!sb->u.smbfs_sb.packet) + server->mnt = NULL; + server->sock_file = NULL; + init_MUTEX(&server->sem); + init_waitqueue_head(&server->wait); + server->conn_pid = 0; + server->state = CONN_INVALID; /* no connection yet */ + server->generation = 0; + server->packet_size = smb_round_length(SMB_INITIAL_PACKET_SIZE); + server->packet = smb_vmalloc(server->packet_size); + if (!server->packet) goto out_no_mem; /* Allocate the global temp buffer */ - sb->u.smbfs_sb.temp_buf = smb_kmalloc(2*SMB_MAXPATHLEN+20, GFP_KERNEL); - if (!sb->u.smbfs_sb.temp_buf) + server->temp_buf = smb_kmalloc(2*SMB_MAXPATHLEN+20, GFP_KERNEL); + if (!server->temp_buf) goto out_no_temp; /* Setup NLS stuff */ - sb->u.smbfs_sb.remote_nls = NULL; - sb->u.smbfs_sb.local_nls = NULL; - sb->u.smbfs_sb.name_buf = sb->u.smbfs_sb.temp_buf + SMB_MAXPATHLEN + 20; + server->remote_nls = NULL; + server->local_nls = NULL; + server->name_buf = server->temp_buf + SMB_MAXPATHLEN + 20; /* Allocate the mount data structure */ /* FIXME: merge this with the other malloc and get a whole page? */ mnt = smb_kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL); if (!mnt) goto out_no_mount; - sb->u.smbfs_sb.mnt = mnt; + server->mnt = mnt; memset(mnt, 0, sizeof(struct smb_mount_data_kernel)); strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, @@ -424,7 +489,7 @@ strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE, SMB_NLS_MAXNAMELEN); - mnt->ttl = 1000; + mnt->ttl = SMB_TTL_DEFAULT; if (ver == SMB_MOUNT_OLDVERSION) { mnt->version = oldmnt->version; @@ -433,12 +498,8 @@ mnt->uid = oldmnt->uid; mnt->gid = oldmnt->gid; - mnt->file_mode = - oldmnt->file_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->dir_mode = - oldmnt->dir_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->file_mode |= S_IFREG; - mnt->dir_mode |= S_IFDIR; + mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG; + mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR; mnt->flags = (oldmnt->file_mode >> 9); } else { @@ -447,9 +508,7 @@ mnt->mounted_uid = current->uid; } - smb_setcodepage(&sb->u.smbfs_sb, &mnt->codepage); - if (!sb->u.smbfs_sb.convert) - PARANOIA("convert funcptr was NULL!\n"); + smb_setcodepage(server, &mnt->codepage); /* * Display the enabled options @@ -463,7 +522,7 @@ /* * Keep the super block locked while we get the root inode. */ - smb_init_root_dirent(&(sb->u.smbfs_sb), &root); + smb_init_root_dirent(server, &root); root_inode = smb_iget(sb, &root); if (!root_inode) goto out_no_root; @@ -478,13 +537,13 @@ out_no_root: iput(root_inode); out_bad_option: - smb_kfree(sb->u.smbfs_sb.mnt); + smb_kfree(server->mnt); out_no_mount: - smb_kfree(sb->u.smbfs_sb.temp_buf); + smb_kfree(server->temp_buf); out_no_temp: - smb_vfree(sb->u.smbfs_sb.packet); + smb_vfree(server->packet); out_no_mem: - if (!sb->u.smbfs_sb.mnt) + if (!server->mnt) printk(KERN_ERR "smb_read_super: allocation failure\n"); goto out_fail; out_wrong_data: @@ -499,11 +558,11 @@ static int smb_statfs(struct super_block *sb, struct statfs *buf) { - smb_proc_dskattr(sb, buf); + int result = smb_proc_dskattr(sb, buf); buf->f_type = SMB_SUPER_MAGIC; buf->f_namelen = SMB_MAXPATHLEN; - return 0; + return result; } int @@ -511,7 +570,7 @@ { struct inode *inode = dentry->d_inode; struct smb_sb_info *server = server_from_dentry(dentry); - unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); + unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO); int error, changed, refresh = 0; struct smb_fattr fattr; @@ -532,15 +591,22 @@ if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask)) goto out; - if ((attr->ia_valid & ATTR_SIZE) != 0) - { + if ((attr->ia_valid & ATTR_SIZE) != 0) { VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n", DENTRY_PATH(dentry), (long) inode->i_size, (long) attr->ia_size); + + filemap_fdatasync(inode->i_mapping); + filemap_fdatawait(inode->i_mapping); + error = smb_open(dentry, O_WRONLY); if (error) goto out; - error = smb_proc_trunc(server, inode->u.smbfs_i.fileid, + + if(!(server_from_dentry(dentry))->opt.capabilities & SMB_CAP_UNIX) { + attr->ia_valid ^= ATTR_SIZE; + } + error = smb_proc_trunc(server, inode->u.smbfs_i.fileid, attr->ia_size); if (error) goto out; @@ -550,6 +616,23 @@ refresh = 1; } + + if((server_from_dentry(dentry))->opt.capabilities & SMB_CAP_UNIX) { + + /*if ((attr->ia_valid & ATTR_SIZE) != 0) { + error = vmtruncate(inode, attr->ia_size); + if (error) + goto out; + }*/ + + error = smb_proc_setattr_unix(dentry, attr); + if (error) + goto out; + refresh = 1; + + goto out; /* this way we don't upset the indent of the original code*/ + }; + /* * Initialize the fattr and check for changed fields. * Note: CTIME under SMB is creation time rather than @@ -558,20 +641,17 @@ smb_get_inode_attr(inode, &fattr); changed = 0; - if ((attr->ia_valid & ATTR_MTIME) != 0) - { + if ((attr->ia_valid & ATTR_MTIME) != 0) { fattr.f_mtime = attr->ia_mtime; changed = 1; } - if ((attr->ia_valid & ATTR_ATIME) != 0) - { + if ((attr->ia_valid & ATTR_ATIME) != 0) { fattr.f_atime = attr->ia_atime; /* Earlier protocols don't have an access time */ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) changed = 1; } - if (changed) - { + if (changed) { error = smb_proc_settime(dentry, &fattr); if (error) goto out; @@ -582,27 +662,22 @@ * Check for mode changes ... we're extremely limited in * what can be set for SMB servers: just the read-only bit. */ - if ((attr->ia_valid & ATTR_MODE) != 0) - { + if ((attr->ia_valid & ATTR_MODE) != 0) { VERBOSE("%s/%s mode change, old=%x, new=%x\n", DENTRY_PATH(dentry), fattr.f_mode, attr->ia_mode); changed = 0; - if (attr->ia_mode & S_IWUSR) - { - if (fattr.attr & aRONLY) - { + if (attr->ia_mode & S_IWUSR) { + if (fattr.attr & aRONLY) { fattr.attr &= ~aRONLY; changed = 1; } } else { - if (!(fattr.attr & aRONLY)) - { + if (!(fattr.attr & aRONLY)) { fattr.attr |= aRONLY; changed = 1; } } - if (changed) - { + if (changed) { error = smb_proc_setattr(dentry, &fattr); if (error) goto out; @@ -617,6 +692,7 @@ return error; } + #ifdef DEBUG_SMB_MALLOC int smb_malloced; int smb_current_kmalloced; diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/ioctl.c /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/ioctl.c --- linux-2.4.9-31/fs/smbfs/ioctl.c Wed May 16 06:40:55 2001 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/ioctl.c Wed Oct 3 10:03:34 2001 @@ -19,6 +19,8 @@ #include +#include "proto.h" + int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) @@ -37,9 +39,11 @@ break; case SMB_IOC_NEWCONN: - /* require an argument == smb_conn_opt, else it is EINVAL */ - if (!arg) + /* arg is smb_conn_opt, or NULL if no connection was made */ + if (!arg) { + result = smb_wakeup(server); break; + } result = -EFAULT; if (!copy_from_user(&opt, (void *)arg, sizeof(opt))) diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/proc.c /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/proc.c --- linux-2.4.9-31/fs/smbfs/proc.c Tue Feb 26 21:50:51 2002 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/proc.c Thu Apr 18 23:19:37 2002 @@ -23,16 +23,18 @@ #include #include +#include #include "smb_debug.h" +#include "proto.h" /* Features. Undefine if they cause problems, this should perhaps be a config option. */ #define SMBFS_POSIX_UNLINK 1 -/* Allow smb_retry to be interrupted. Not sure of the benefit ... */ -/* #define SMB_RETRY_INTR */ +/* Allow smb_retry to be interrupted. */ +#define SMB_RETRY_INTR #define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN) #define SMB_CMD(packet) (*(packet+8)) @@ -43,6 +45,9 @@ #define SMB_DIRINFO_SIZE 43 #define SMB_STATUS_SIZE 21 +#define SMB_ST_BLKSIZE (PAGE_SIZE) +#define SMB_ST_BLKSHIFT (PAGE_SHIFT) + static int smb_proc_setattr_ext(struct smb_sb_info *, struct inode *, struct smb_fattr *); @@ -53,7 +58,8 @@ smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir, struct smb_fattr *fattr); - +int +smb_proc_query_cifsunix(struct smb_sb_info *server); static void str_upper(char *name, int len) @@ -140,8 +146,7 @@ return n; } -static int setcodepage(struct smb_sb_info *server, - struct nls_table **p, char *name) +static int setcodepage(struct nls_table **p, char *name) { struct nls_table *nls; @@ -163,16 +168,20 @@ /* Handles all changes to codepage settings. */ int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp) { - int n; + int n = 0; smb_lock_server(server); - n = setcodepage(server, &server->local_nls, cp->local_name); + /* Don't load any nls_* at all, if no remote is requested */ + if (!*cp->remote_name) + goto out; + + n = setcodepage(&server->local_nls, cp->local_name); if (n != 0) goto out; - n = setcodepage(server, &server->remote_nls, cp->remote_name); + n = setcodepage(&server->remote_nls, cp->remote_name); if (n != 0) - setcodepage(server, &server->local_nls, NULL); + setcodepage(&server->local_nls, NULL); out: if (server->local_nls != NULL && server->remote_nls != NULL) @@ -191,7 +200,7 @@ /* */ /*****************************************************************************/ -__u8 * +static __u8 * smb_encode_smb_length(__u8 * p, __u32 len) { *p = 0; @@ -336,7 +345,9 @@ int month, year; time_t 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) + year * 365 - ((year & 3) == 0 && @@ -355,6 +366,9 @@ int day, year, nl_day, month; unix_date = utc2local(server, unix_date); + if (unix_date < 315532800) + unix_date = 315532800; + *time = (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) + (((unix_date / 3600) % 24) << 11); @@ -378,57 +392,145 @@ /* The following are taken from fs/ntfs/util.c */ +#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000) + /* * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) * into Unix UTC (based 1970-01-01, in seconds). - * - * This is very gross because - * 1: We must do 64-bit division on a 32-bit machine - * 2: We can't use libgcc for long long operations in the kernel - * 3: Floating point math in the kernel would corrupt user data */ static time_t -smb_ntutc2unixutc(struct smb_sb_info *server, u64 ntutc) +smb_ntutc2unixutc(u64 ntutc) { - const unsigned int D = 10000000; - unsigned int H = (unsigned int)(ntutc >> 32); - unsigned int L = (unsigned int)ntutc; - unsigned int numerator2; - unsigned int lowseconds; - unsigned int result; + /* FIXME: what about the timezone difference? */ + /* Subtract the NTFS time offset, then convert to 1s intervals. */ + u64 t = ntutc - NTFS_TIME_OFFSET; + do_div(t, 10000000); + return (time_t)t; +} - /* - * It is best to subtract 0x019db1ded53e8000 first. - * Then the 1601-based date becomes a 1970-based date. - */ - if (L < (unsigned)0xd53e8000) H--; - L -= (unsigned)0xd53e8000; - H -= (unsigned)0x019db1de; +/* Convert the Unix UTC into NT time */ +static u64 +smb_unixutc2ntutc(time_t t) +{ + /* Note: timezone conversion is probably wrong. */ + return ((u64)t) * 10000000 + NTFS_TIME_OFFSET; +} - /* - * Now divide 64-bit numbers on a 32-bit machine :-) - * With the subtraction already done, the result fits in 32 bits. - * The numerator fits in 56 bits and the denominator fits - * in 24 bits, so we can shift by 8 bits to make this work. - */ +/* + * This function will create the flags for the mode of the file + * It should do security checks on what kind of files it will allow + * + * TODO What type of file has a 0 S_IFMT ??? perhaps we could use that... + */ +static int smb_filetype_to_mode(u32 filetype) +{ + switch(filetype) { + case UNIX_TYPE_FILE: + return S_IFREG; + + case UNIX_TYPE_DIR: + return S_IFDIR; + + case UNIX_TYPE_SYMLINK: + return S_IFLNK; + + case UNIX_TYPE_CHARDEV: + return S_IFCHR; + + case UNIX_TYPE_BLKDEV: + return S_IFBLK; + + case UNIX_TYPE_FIFO: + return S_IFIFO; + + case UNIX_TYPE_SOCKET: + return S_IFSOCK; + + case UNIX_TYPE_UNKNOWN: + default: + DEBUG1("unknown type %d\n", filetype); + return S_IFREG; + } +} - numerator2 = (H<<8) | (L>>24); - result = (numerator2 / D); /* shifted 24 right!! */ - lowseconds = result << 24; +static u32 smb_filetype_from_mode(int mode) +{ + if(mode & S_IFREG) + return UNIX_TYPE_FILE; + + if(mode & S_IFDIR) + return UNIX_TYPE_DIR; + + if(mode & S_IFLNK) + return UNIX_TYPE_SYMLINK; - numerator2 = ((numerator2-result*D)<<8) | ((L>>16)&0xff); - result = (numerator2 / D); /* shifted 16 right!! */ - lowseconds |= result << 16; + if(mode & S_IFCHR) + return UNIX_TYPE_CHARDEV; - numerator2 = ((numerator2-result*D)<<8) | ((L>>8)&0xff); - result = (numerator2 / D); /* shifted 8 right!! */ - lowseconds |= result << 8; + if(mode & S_IFBLK) + return UNIX_TYPE_BLKDEV; - numerator2 = ((numerator2-result*D)<<8) | (L&0xff); - result = (numerator2 / D); /* not shifted */ - lowseconds |= result; + if(mode & S_IFIFO) + return UNIX_TYPE_FIFO; - return lowseconds; + if(mode & S_IFSOCK) + return UNIX_TYPE_SOCKET; + + return UNIX_TYPE_UNKNOWN; +} + +/* + * This function will decode the 'standard' permissions into Linux + * permissions. It should do security checks to make sure that we + * don't do silly things like make devices owned by users. + * + * TODO To do this it needs more info. + */ +static int smb_permissions_to_mode(u64 permissions) +{ + int mode = 0; + + if(permissions & UNIX_X_OTH) mode |= S_IXOTH; + if(permissions & UNIX_R_OTH) mode |= S_IROTH; + if(permissions & UNIX_W_OTH) mode |= S_IWOTH; + + if(permissions & UNIX_X_GRP) mode |= S_IXGRP; + if(permissions & UNIX_R_GRP) mode |= S_IRGRP; + if(permissions & UNIX_W_GRP) mode |= S_IWGRP; + + if(permissions & UNIX_X_USR) mode |= S_IXUSR; + if(permissions & UNIX_R_USR) mode |= S_IRUSR; + if(permissions & UNIX_W_USR) mode |= S_IWUSR; + + /* these could pose security issues.... */ + if(permissions & UNIX_STICKY) mode |= S_ISVTX; + if(permissions & UNIX_SET_GID) mode |= S_ISGID; + if(permissions & UNIX_SET_UID) mode |= S_ISUID; + + return mode; +} + +static u64 smb_permissions_from_mode(int mode) +{ + u64 perm = 0; + + if(mode & S_IXOTH) perm |= UNIX_X_OTH; + if(mode & S_IROTH) perm |= UNIX_R_OTH; + if(mode & S_IWOTH) perm |= UNIX_W_OTH; + + if(mode & S_IXGRP) perm |= UNIX_X_GRP; + if(mode & S_IRGRP) perm |= UNIX_R_GRP; + if(mode & S_IWGRP) perm |= UNIX_W_GRP; + + if(mode & S_IXUSR) perm |= UNIX_X_USR; + if(mode & S_IRUSR) perm |= UNIX_R_USR; + if(mode & S_IWUSR) perm |= UNIX_W_USR; + + if(mode & S_ISVTX) perm |= UNIX_STICKY; + if(mode & S_ISUID) perm |= UNIX_SET_UID; + if(mode & S_ISGID) perm |= UNIX_SET_GID; + + return perm; } #if 0 @@ -437,7 +539,7 @@ smb_unixutc2ntutc(struct smb_sb_info *server, time_t t) { /* Note: timezone conversion is probably wrong. */ - return ((utc2local(server, t) + (u64)(369*365+89)*24*3600) * 10000000); + return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET; } #endif @@ -547,6 +649,9 @@ return size; } +/* + * Convert SMB error codes to -E... errno values. + */ int smb_errno(struct smb_sb_info *server) { @@ -557,110 +662,117 @@ VERBOSE("errcls %d code %d from command 0x%x\n", errcls, error, SMB_CMD(server->packet)); - if (errcls == ERRDOS) - switch (error) - { + if (errcls == ERRDOS) { + switch (error) { case ERRbadfunc: - return EINVAL; + return -EINVAL; case ERRbadfile: case ERRbadpath: - return ENOENT; + return -ENOENT; case ERRnofids: - return EMFILE; + return -EMFILE; case ERRnoaccess: - return EACCES; + return -EACCES; case ERRbadfid: - return EBADF; + return -EBADF; case ERRbadmcb: - return EREMOTEIO; + return -EREMOTEIO; case ERRnomem: - return ENOMEM; + return -ENOMEM; case ERRbadmem: - return EFAULT; + return -EFAULT; case ERRbadenv: case ERRbadformat: - return EREMOTEIO; + return -EREMOTEIO; case ERRbadaccess: - return EACCES; + return -EACCES; case ERRbaddata: - return E2BIG; + return -E2BIG; case ERRbaddrive: - return ENXIO; + return -ENXIO; case ERRremcd: - return EREMOTEIO; + return -EREMOTEIO; case ERRdiffdevice: - return EXDEV; - case ERRnofiles: /* Why is this mapped to 0?? */ - return 0; + return -EXDEV; + case ERRnofiles: + return -ENOENT; case ERRbadshare: - return ETXTBSY; + return -ETXTBSY; case ERRlock: - return EDEADLK; + return -EDEADLK; case ERRfilexists: - return EEXIST; - case 87: /* should this map to 0?? */ - return 0; /* Unknown error!! */ - case 123: /* Invalid name?? e.g. .tmp* */ - return ENOENT; - case 145: /* Win NT 4.0: non-empty directory? */ - return ENOTEMPTY; - /* This next error seems to occur on an mv when - * the destination exists */ - case 183: - return EEXIST; + return -EEXIST; + case ERROR_INVALID_PARAMETER: + return -EINVAL; + case ERROR_DISK_FULL: + return -ENOSPC; + case ERROR_INVALID_NAME: + return -ENOENT; + case ERROR_DIR_NOT_EMPTY: + return -ENOTEMPTY; + case ERROR_NOT_LOCKED: + return -ENOLCK; + case ERROR_ALREADY_EXISTS: + return -EEXIST; default: class = "ERRDOS"; goto err_unknown; - } else if (errcls == ERRSRV) - switch (error) - { + } + } else if (errcls == ERRSRV) { + switch (error) { /* N.B. This is wrong ... EIO ? */ case ERRerror: - return ENFILE; + return -ENFILE; case ERRbadpw: - return EINVAL; + return -EINVAL; case ERRbadtype: - return EIO; + return -EIO; case ERRaccess: - return EACCES; + return -EACCES; /* * This is a fatal error, as it means the "tree ID" * for this connection is no longer valid. We map * to a special error code and get a new connection. */ case ERRinvnid: - return EBADSLT; + return -EBADSLT; default: class = "ERRSRV"; goto err_unknown; - } else if (errcls == ERRHRD) - switch (error) - { + } + } else if (errcls == ERRHRD) { + switch (error) { case ERRnowrite: - return EROFS; + return -EROFS; case ERRbadunit: - return ENODEV; + return -ENODEV; case ERRnotready: - return EUCLEAN; + return -EUCLEAN; case ERRbadcmd: case ERRdata: - return EIO; + return -EIO; case ERRbadreq: - return ERANGE; + return -ERANGE; case ERRbadshare: - return ETXTBSY; + return -ETXTBSY; case ERRlock: - return EDEADLK; + return -EDEADLK; + case ERRdiskfull: + return -ENOSPC; default: class = "ERRHRD"; goto err_unknown; - } else if (errcls == ERRCMD) + } + } else if (errcls == ERRCMD) { class = "ERRCMD"; + } else if (errcls == SUCCESS) { + return 0; /* This is the only valid 0 return */ + } err_unknown: printk(KERN_ERR "smb_errno: class %s, code %d from command 0x%x\n", class, error, SMB_CMD(server->packet)); - return EIO; + return -EIO; } /* @@ -777,12 +889,10 @@ } /* - * Check for server errors. The current smb_errno() routine - * is squashing some error codes, but I don't think this is - * correct: after a server error the packet won't be valid. + * Check for server errors. */ if (s->rcls != 0) { - result = -smb_errno(s); + result = smb_errno(s); if (!result) printk(KERN_DEBUG "smb_request_ok: rcls=%d, err=%d mapped to 0\n", s->rcls, s->err); @@ -876,19 +986,31 @@ } } + if(server->opt.capabilities & SMB_CAP_UNIX) + { + DEBUG1("using UNIX_CIFS extensions\n"); + smb_proc_query_cifsunix(server); + } + out: smb_unlock_server(server); + smb_wakeup(server); + return error; +out_putf: + fput(filp); + goto out; +} + +int +smb_wakeup(struct smb_sb_info *server) +{ #ifdef SMB_RETRY_INTR wake_up_interruptible(&server->wait); #else wake_up(&server->wait); #endif - return error; - -out_putf: - fput(filp); - goto out; + return 0; } /* smb_setup_header: We completely set up the packet. You only have to @@ -1130,12 +1252,19 @@ * If the file is open with write permissions, * update the time stamps to sync mtime and atime. */ - if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) && - !(ino->u.smbfs_i.access == SMB_O_RDONLY)) - { - struct smb_fattr fattr; - smb_get_inode_attr(ino, &fattr); - smb_proc_setattr_ext(server, ino, &fattr); + if(server->opt.capabilities & SMB_CAP_UNIX) { + /* + * There is nothing to do here? + */ + } + else { + if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) && + !(ino->u.smbfs_i.access == SMB_O_RDONLY)) + { + struct smb_fattr fattr; + smb_get_inode_attr(ino, &fattr); + smb_proc_setattr_ext(server, ino, &fattr); + } } result = smb_proc_close(server, ino->u.smbfs_i.fileid, @@ -1382,6 +1511,16 @@ int result; struct smb_fattr fattr; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + /* + * Perhaps we should call setattr_unix? + * The correct solution it to configure the server to have + * "delete readonly = Yes" + */ + PARANOIA("We should not be here because we are UNIX\n"); + } + /* first get current attribute */ result = smb_proc_do_getattr(server, dentry, &fattr); if (result < 0) @@ -1502,27 +1641,37 @@ fattr->f_nlink = 1; fattr->f_uid = server->mnt->uid; fattr->f_gid = server->mnt->gid; - fattr->f_blksize = 512; + fattr->f_blksize = SMB_ST_BLKSIZE; + fattr->f_unix = 0; } static void smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr) { - fattr->f_mode = server->mnt->file_mode; - if (fattr->attr & aDIR) - { - fattr->f_mode = server->mnt->dir_mode; - fattr->f_size = 512; - } - /* Check the read-only flag */ - if (fattr->attr & aRONLY) - fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); - - fattr->f_blocks = 0; - if ((fattr->f_blksize != 0) && (fattr->f_size != 0)) - { - fattr->f_blocks = - (fattr->f_size - 1) / fattr->f_blksize + 1; + if(fattr->f_unix) { + /* mask out suid and sgid */ + fattr->f_mode &= ~(S_ISGID | S_ISUID); + + /* convert nodes into regular files...*/ + /*if(S_ISCHR(fattr->f_mode) | S_ISBLK(fattr->f_mode)) { + fattr->f_mode &= ~S_IFMT; + fattr->f_mode |= S_IFREG; + }*/ + } else { + fattr->f_mode = server->mnt->file_mode; + if (fattr->attr & aDIR) + { + fattr->f_mode = server->mnt->dir_mode; + fattr->f_size = SMB_ST_BLKSIZE; + } + /* Check the read-only flag */ + if (fattr->attr & aRONLY) + fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + + /* How many 512 byte blocks do we need for this file? */ + fattr->f_blocks = 0; + if (fattr->f_size != 0) + fattr->f_blocks = 1 + ((fattr->f_size-1) >> 9); } return; } @@ -1535,6 +1684,7 @@ fattr->f_ino = 2; /* traditional root inode number */ fattr->f_mtime = CURRENT_TIME; smb_finish_dirent(server, fattr); + DEBUG1("root inode mode = %07o\n", fattr->f_mode); } /* @@ -1552,6 +1702,11 @@ { int len; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + PARANOIA("We should not be here because we are UNIX\n"); + } + /* * SMB doesn't have a concept of inode numbers ... */ @@ -1596,7 +1751,6 @@ server->remote_nls, server->local_nls); qname->name = server->name_buf; - DEBUG1("len=%d, name=%.*s\n", qname->len, qname->len, qname->name); return p + 22; } @@ -1623,6 +1777,11 @@ static struct qstr mask = { "*.*", 3, 0 }; unsigned char *last_status; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + PARANOIA("We should not be here because we are UNIX\n"); + } + VERBOSE("%s/%s\n", DENTRY_PATH(dir)); smb_lock_server(server); @@ -1732,6 +1891,48 @@ return result; } +void smb_decode_unix_basic(struct smb_fattr *fattr, char *p) +{ + __u64 devmajor, devminor; + + fattr->f_unix = 1; + fattr->f_mode = 0; + /* 0 L file size in bytes */ + fattr->f_size = LVAL(p, 0); + + /* 8 L file size on disk in bytes (block count) */ + fattr->f_blocks = LVAL(p, 8); + + /* times. */ + fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 16)); + fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 24)); + fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 32)); + + /* 40 L uid */ + fattr->f_uid = LVAL(p, 40); + /* 48 L gid */ + fattr->f_gid = LVAL(p, 48); + + /* 56 W file type enum */ + fattr->f_mode |= smb_filetype_to_mode(WVAL(p, 56)); + + if(S_ISBLK(fattr->f_mode) || S_ISCHR(fattr->f_mode)) + { + /* 60 L devmajor */ + devmajor = LVAL(p, 60); + /* 68 L devminor */ + devminor = LVAL(p, 68); + + fattr->f_rdev = ((devmajor & 0xFF) << 8) | (devminor & 0xFF); + } + /* 76 L unique ID (inode) */ + /* 84 L permissions */ + fattr->f_mode |= smb_permissions_to_mode(LVAL(p, 84)); + + /* 92 L link count */ + +} + /* * Interpret a long filename structure using the specified info level: * level 1 for anything below NT1 protocol @@ -1790,9 +1991,9 @@ if (len && qname->name[len-1] == '\0') len--; - fattr->f_ctime = smb_ntutc2unixutc(server, LVAL(p, 8)); - fattr->f_atime = smb_ntutc2unixutc(server, LVAL(p, 16)); - fattr->f_mtime = smb_ntutc2unixutc(server, LVAL(p, 24)); + fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 8)); + fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 16)); + fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 24)); /* change time (32) */ fattr->f_size = DVAL(p, 40); /* alloc size (48) */ @@ -1801,9 +2002,25 @@ VERBOSE("info 260 at %p, len=%d, name=%.*s\n", p, len, len, qname->name); break; + + case SMB_FIND_FILE_UNIX: + result = p + WVAL(p, 0); + qname->name = p + 108; + + len = strlen(qname->name); + /* TODO should we check the length?? */ + + p += 8; + smb_decode_unix_basic(fattr, p); + VERBOSE("info decoded FILE_UNIX at %p, len=%d, name=%.*s\n", + p, len, len, qname->name); + break; + default: PARANOIA("Unknown info level %d\n", level); result = p + WVAL(p, 0); + + /* TODO debug this. I got an oops */ goto out; } @@ -1886,6 +2103,10 @@ if (server->opt.protocol < SMB_PROTOCOL_NT1) info_level = 1; + if(server->opt.capabilities & SMB_CAP_UNIX) { + info_level = SMB_FILE_FILE_UNIX; + } + smb_lock_server(server); /* @@ -1960,7 +2181,7 @@ } if (server->rcls != 0) { - result = -smb_errno(server); + result = smb_errno(server); PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n", mask, result, server->rcls, server->err); break; @@ -2008,6 +2229,9 @@ if (ff_lastname + 1 + mask_len > resp_data_len) mask_len = resp_data_len - ff_lastname - 1; break; + case SMB_FIND_FILE_UNIX: + mask_len = resp_data_len - ff_lastname; + break; } /* @@ -2050,7 +2274,6 @@ if (qname.name[1] == '.' && qname.len == 2) continue; } - if (!smb_fill_cache(filp, dirent, filldir, ctl, &qname, &fattr)) ; /* stop reading? */ @@ -2099,6 +2322,11 @@ int resp_param_len = 0; int mask_len, result; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + PARANOIA("We should not be here because we are UNIX\n"); + } + retry: mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dentry, NULL); if (mask_len < 0) { @@ -2124,7 +2352,7 @@ } if (server->rcls != 0) { - result = -smb_errno(server); + result = smb_errno(server); #ifdef SMBFS_PARANOIA if (result != -ENOENT) PARANOIA("error for %s, rcls=%d, err=%d\n", @@ -2176,6 +2404,11 @@ int result; char *p; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + PARANOIA("We should not be here because we are UNIX\n"); + } + retry: p = smb_setup_header(server, SMBgetatr, 0, 0); result = smb_simple_encode_path(server, &p, dir, NULL); @@ -2222,9 +2455,14 @@ int resp_data_len = 0; int resp_param_len = 0; int result; + int level = 1; /* Info level SMB_INFO_STANDARD */ + if(server->opt.capabilities & SMB_CAP_UNIX) { + level = SMB_QUERY_FILE_UNIX_BASIC; + } retry: - WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ + + WSET(param, 0, level); DSET(param, 2, 0); result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL); if (result < 0) @@ -2245,44 +2483,53 @@ { VERBOSE("for %s: result=%d, rcls=%d, err=%d\n", ¶m[6], result, server->rcls, server->err); - result = -smb_errno(server); + result = smb_errno(server); goto out; } result = -ENOENT; - if (resp_data_len < 22) - { - PARANOIA("not enough data for %s, len=%d\n", - ¶m[6], resp_data_len); - goto out; - } + if(level == 1) { + if (resp_data_len < 22) { + PARANOIA("not enough data for %s, len=%d\n", + ¶m[6], resp_data_len); + goto out; + } - /* - * Kludge alert: Win 95 swaps the date and time field, - * contrary to the CIFS docs and Win NT practice. - */ - if (server->mnt->flags & SMB_MOUNT_WIN95) { - off_date = 2; - off_time = 0; - } - date = WVAL(resp_data, off_date); - time = WVAL(resp_data, off_time); - attr->f_ctime = date_dos2unix(server, date, time); - - date = WVAL(resp_data, 4 + off_date); - time = WVAL(resp_data, 4 + off_time); - attr->f_atime = date_dos2unix(server, date, time); - - date = WVAL(resp_data, 8 + off_date); - time = WVAL(resp_data, 8 + off_time); - attr->f_mtime = date_dos2unix(server, date, time); + /* + * Kludge alert: Win 95 swaps the date and time field, + * contrary to the CIFS docs and Win NT practice. + */ + if (server->mnt->flags & SMB_MOUNT_WIN95) { + off_date = 2; + off_time = 0; + } + date = WVAL(resp_data, off_date); + time = WVAL(resp_data, off_time); + attr->f_ctime = date_dos2unix(server, date, time); + + date = WVAL(resp_data, 4 + off_date); + time = WVAL(resp_data, 4 + off_time); + attr->f_atime = date_dos2unix(server, date, time); + + date = WVAL(resp_data, 8 + off_date); + time = WVAL(resp_data, 8 + off_time); + attr->f_mtime = date_dos2unix(server, date, time); #ifdef SMBFS_DEBUG_TIMESTAMP - printk(KERN_DEBUG "getattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n", - DENTRY_PATH(dir), date, time, attr->f_mtime); + printk(KERN_DEBUG "getattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n", + DENTRY_PATH(dir), date, time, attr->f_mtime); #endif - attr->f_size = DVAL(resp_data, 12); - attr->attr = WVAL(resp_data, 20); - result = 0; + attr->f_size = DVAL(resp_data, 12); + attr->attr = WVAL(resp_data, 20); + result = 0; + + } else if(level == SMB_QUERY_FILE_UNIX_BASIC) { + smb_decode_unix_basic(attr, resp_data); + result = 0; + + } else { + PARANOIA("unknown info level\n"); + result = -ENOENT; + } out: return result; } @@ -2364,6 +2611,11 @@ char *p; int result; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + PARANOIA("We should not be here because we are UNIX\n"); + } + retry: p = smb_setup_header(server, SMBsetatr, 8, 0); WSET(server->packet, smb_vwv0, attr); @@ -2399,6 +2651,7 @@ * Because of bugs in the trans2 setattr messages, we must set * attributes and timestamps separately. The core SMBsetatr * message seems to be the only reliable way to set attributes. + * */ int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr) @@ -2406,6 +2659,11 @@ struct smb_sb_info *server = server_from_dentry(dir); int result; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + PARANOIA("We should not be here because we are UNIX\n"); + } + VERBOSE("setting %s/%s, open=%d\n", DENTRY_PATH(dir), smb_is_open(dir->d_inode)); smb_lock_server(server); @@ -2425,6 +2683,11 @@ __u16 date, time; int result; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + PARANOIA("We should not be here because we are UNIX\n"); + } + retry: smb_setup_header(server, SMBsetattrE, 7, 0); WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid); @@ -2473,6 +2736,11 @@ int result; char data[26]; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + PARANOIA("We should not be here because we are UNIX\n"); + } + retry: WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ DSET(param, 2, 0); @@ -2510,12 +2778,150 @@ } result = 0; if (server->rcls != 0) - result = -smb_errno(server); + result = smb_errno(server); + +out: + return result; +} + +/* + * TODO Note: we must lock the server ourself + * ATTR_MODE 0x001 + * ATTR_UID 0x002 + * ATTR_GID 0x004 + * ATTR_SIZE 0x008 + * ATTR_ATIME 0x010 + * ATTR_MTIME 0x020 + * ATTR_CTIME 0x040 + * ATTR_ATIME_SET 0x080 + * ATTR_MTIME_SET 0x100 + * ATTR_FORCE 0x200 + * ATTR_ATTR_FLAG 0x400 + */ + +extern int +smb_proc_setattr_unix(struct dentry *dentry, struct iattr *attr) +{ + u64 nttime; + char *p, *param; + unsigned char *resp_data = NULL; + unsigned char *resp_param = NULL; + int resp_data_len = 0; + int resp_param_len = 0; + int result; + char data[100]; + struct smb_sb_info *server; + + server = server_from_dentry(dentry); + smb_lock_server(server); + param = server->temp_buf; + + DEBUG1("valid flags = 0x%04x\n", attr->ia_valid); + + retry: + WSET(param, 0, SMB_SET_FILE_UNIX_BASIC); + DSET(param, 2, 0); + result = smb_encode_path(server, param + 6, SMB_MAXNAMELEN+1, dentry, NULL); + if (result < 0) + goto out; + p = param + 6 + result; + + if(attr->ia_valid & ATTR_SIZE) { + /*DEBUG1("setting size = %d\n", attr->ia_size);*/ + /* 0 L file size in bytes */ + LSET(data, 0, attr->ia_size); + /* 8 L file size on disk in bytes (block count) */ + LSET(data, 8, 0); /* can't set anyway */ + } else { + LSET(data, 0, SMB_SIZE_NO_CHANGE); + LSET(data, 8, SMB_SIZE_NO_CHANGE); + } + + + /* times. TODO check the conversion function it the correct one + */ + /* we can't set ctime but we might as well pass this to the server + * and let it ignore it + */ + if(attr->ia_valid & ATTR_CTIME) { + VERBOSE("setting ctime = %d\n", attr->ia_ctime); + nttime = smb_unixutc2ntutc(attr->ia_ctime); + LSET(data, 16, nttime); + } else { + LSET(data, 16, SMB_TIME_NO_CHANGE); + } + + if(attr->ia_valid & ATTR_ATIME) { + VERBOSE("setting atime = %d\n", attr->ia_atime); + nttime = smb_unixutc2ntutc(attr->ia_atime); + LSET(data, 24, nttime); + } else { + LSET(data, 24, SMB_TIME_NO_CHANGE); + } + + if(attr->ia_valid & ATTR_MTIME) { + VERBOSE("setting mtime = %d\n", attr->ia_mtime); + nttime = smb_unixutc2ntutc(attr->ia_mtime); + LSET(data, 32, nttime); + } else { + LSET(data, 32, SMB_TIME_NO_CHANGE); + } + + if(attr->ia_valid & ATTR_UID) { + /* 40 L uid */ + LSET(data, 40, attr->ia_uid); + } else { + LSET(data, 40, SMB_UID_NO_CHANGE); + } + + if(attr->ia_valid & ATTR_GID) { + /* 48 L gid */ + LSET(data, 48, attr->ia_gid); + } else { + LSET(data, 48, SMB_GID_NO_CHANGE); + } + + /* 56 W file type enum */ + LSET(data, 56, smb_filetype_from_mode(attr->ia_mode)); + + /* 60 L devmajor */ + LSET(data, 60, 0); + /* 68 L devminor */ + LSET(data, 68, 0); + /* 76 L unique ID (inode) */ + LSET(data, 76, 0); + + if(attr->ia_valid & ATTR_MODE) { + DEBUG1("setting mode = %07o\n", attr->ia_mode); + /* 84 L permissions */ + LSET(data, 84, smb_permissions_from_mode(attr->ia_mode)); + } else { + LSET(data, 84, SMB_MODE_NO_CHANGE); + } + + /* 92 L link count */ + LSET(data, 92, 0); + + result = smb_trans2_request(server, TRANSACT2_SETPATHINFO, + sizeof(data), data, p - param, param, + &resp_data_len, &resp_data, + &resp_param_len, &resp_param); + if (result < 0) + { + if (smb_retry(server)) + goto retry; + goto out; + } + result = 0; + if (server->rcls != 0) + result = smb_errno(server); out: + smb_unlock_server(server); return result; } + /* * Set the modify and access timestamps for a file. * @@ -2536,6 +2942,11 @@ struct inode *inode = dentry->d_inode; int result; + if(server->opt.capabilities & SMB_CAP_UNIX) + { + PARANOIA("We should not be here because we are UNIX\n"); + } + VERBOSE("setting %s/%s, open=%d\n", DENTRY_PATH(dentry), smb_is_open(inode)); @@ -2579,6 +2990,7 @@ struct smb_sb_info *server = &(sb->u.smbfs_sb); int result; char *p; + long unit; smb_lock_server(server); @@ -2591,9 +3003,10 @@ goto out; } p = SMB_VWV(server->packet); - attr->f_blocks = WVAL(p, 0); - attr->f_bsize = WVAL(p, 2) * WVAL(p, 4); - attr->f_bavail = attr->f_bfree = WVAL(p, 6); + unit = (WVAL(p, 2) * WVAL(p, 4)) >> SMB_ST_BLKSHIFT; + attr->f_blocks = WVAL(p, 0) * unit; + attr->f_bsize = SMB_ST_BLKSIZE; + attr->f_bavail = attr->f_bfree = WVAL(p, 6) * unit; result = 0; out: @@ -2602,12 +3015,245 @@ } int -smb_proc_disconnect(struct smb_sb_info *server) +smb_proc_read_link(struct smb_sb_info *server, struct dentry *dentry, char *buffer, int len) { + char *p, *param = server->temp_buf; + unsigned char *resp_data = NULL; + unsigned char *resp_param = NULL; + int resp_data_len = 0; + int resp_param_len = 0; int result; + int level; + + if(!(server->opt.capabilities & SMB_CAP_UNIX)) + { + PARANOIA("We should not be here because we are not UNIX\n"); + } + + DEBUG1("readlink of %s/%s\n", DENTRY_PATH(dentry)); + smb_lock_server(server); - smb_setup_header(server, SMBtdis, 0, 0); - result = smb_request_ok(server, SMBtdis, 0, 0); + level = SMB_QUERY_FILE_UNIX_LINK; + retry: + + WSET(param, 0, level); + DSET(param, 2, 0); + result = smb_encode_path(server, param + 6, SMB_MAXNAMELEN+1, dentry, NULL); + if (result < 0) + goto out; + p = param + 6 + result; + + result = smb_trans2_request(server, TRANSACT2_QPATHINFO, + 0, NULL, p - param, param, + &resp_data_len, &resp_data, + &resp_param_len, &resp_param); + DEBUG1("for %s: result=%d, rcls=%d, err=%d\n", + ¶m[6], result, server->rcls, server->err); + if (result < 0) { + if (smb_retry(server)) + goto retry; + goto out; + } + if (server->rcls != 0) { + VERBOSE("for %s: result=%d, rcls=%d, err=%d\n", + ¶m[6], result, server->rcls, server->err); + result = smb_errno(server); + goto out; + } + + /* copy data up to the \0 or buffer length */ + result = 0; + while(result < len && resp_data[result]) { + buffer[result] = resp_data[result]; + result++; + } + buffer[result] = 0; + +out: smb_unlock_server(server); return result; } + + +/* + * Create a symlink object called dentry which points to oldpath. + * + * We need to lock server + * + * samba does not permit dangling links but returns a suitable error message + * + */ +extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *dentry,const char *oldpath) +{ + char *p, *param = server->temp_buf; + unsigned char *resp_data = NULL; + unsigned char *resp_param = NULL; + int resp_data_len = 0; + int resp_param_len = 0; + int result; + int level = SMB_SET_FILE_UNIX_LINK; + int oldpathlen = 0; + + if(!(server->opt.capabilities & SMB_CAP_UNIX)) + { + PARANOIA("We should not be here because we are not UNIX\n"); + } + + smb_lock_server(server); + oldpathlen = strlen(oldpath); + retry: + WSET(param, 0, level); + DSET(param, 2, 0); + result = smb_encode_path(server, param + 6, SMB_MAXNAMELEN+1, dentry, NULL); + if (result < 0) + goto out; + p = param + 6 + result; + + + result = smb_trans2_request(server, TRANSACT2_SETPATHINFO, + oldpathlen + 1, (char *)oldpath, p - param, param, + &resp_data_len, &resp_data, + &resp_param_len, &resp_param); + DEBUG1("for %s: result=%d, rcls=%d, err=%d\n", + ¶m[6], result, server->rcls, server->err); + if (result < 0) { + if (smb_retry(server)) + goto retry; + goto out; + } + if (server->rcls != 0) { + VERBOSE("for %s: result=%d, rcls=%d, err=%d\n", + ¶m[6], result, server->rcls, server->err); + result = smb_errno(server); + goto out; + } + + result = 0; + +out: + smb_unlock_server(server); + return result; +} + +/* + * Create a hard link object called new_dentry which points to dentry. + * + * We need to lock server + * + */ +extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry) +{ + char *p, *param = server->temp_buf; + unsigned char *resp_data = NULL; + unsigned char *resp_param = NULL; + int resp_data_len = 0; + int resp_param_len = 0; + int result; + int level = SMB_SET_FILE_UNIX_HLINK; + int newpathlen = 0; + char newpath[SMB_MAXPATHLEN+1]; + + if(!(server->opt.capabilities & SMB_CAP_UNIX)) + { + PARANOIA("We should not be here because we are not UNIX\n"); + } + + smb_lock_server(server); + + newpathlen = smb_encode_path(server, newpath, SMB_MAXPATHLEN+1, dentry, NULL); + + DEBUG1("newpathlen = %d newpath=\"%s\"\n", newpathlen, newpath); +retry: + WSET(param, 0, level); + DSET(param, 2, 0); + result = smb_encode_path(server, param + 6, SMB_MAXPATHLEN+1, new_dentry, NULL); + if (result < 0) + goto out; + p = param + 6 + result; + DEBUG1("pathlen = %d oldpath=\"%s\"\n", result, param + 6); + + + result = smb_trans2_request(server, TRANSACT2_SETPATHINFO, + newpathlen + 1, (char *)newpath, p - param, param, + &resp_data_len, &resp_data, + &resp_param_len, &resp_param); + DEBUG1("for %s: result=%d, rcls=%d, err=%d\n", + ¶m[6], result, server->rcls, server->err); + if (result < 0) { + if (smb_retry(server)) + goto retry; + goto out; + } + if (server->rcls != 0) { + VERBOSE("for %s: result=%d, rcls=%d, err=%d\n", + ¶m[6], result, server->rcls, server->err); + result = smb_errno(server); + goto out; + } + + result = 0; + +out: + smb_unlock_server(server); + return result; +} + + +/* + * We are called with the server locked + */ +int +smb_proc_query_cifsunix(struct smb_sb_info *server) +{ + char *param = server->temp_buf; + unsigned char *resp_data = NULL; + unsigned char *resp_param = NULL; + int resp_data_len = 0; + int resp_param_len = 0; + int result; + int level; + int major, minor; + u64 caps; + + if(!(server->opt.capabilities & SMB_CAP_UNIX)) { + PARANOIA("We should not be here because we are not UNIX\n"); + } + + DEBUG1("SMB_QUERY_CIFS_UNIX_INFO\n"); + + level = SMB_QUERY_CIFS_UNIX_INFO; + retry: + + WSET(param, 0, level); + + result = smb_trans2_request(server, TRANSACT2_QFSINFO, + 0, NULL, 2, param, + &resp_data_len, &resp_data, + &resp_param_len, &resp_param); + if (result < 0) { + if (smb_retry(server)) + goto retry; + goto out; + } + VERBOSE("resp_data_len = %d\n", resp_data_len); + + if(resp_data_len < 12) + { + DEBUG1("Not enough data\n"); + goto out; + } + + major = WVAL(resp_data, 0); + minor = WVAL(resp_data, 2); + + + DEBUG1("Server implements \"CIFS Extensions for UNIX systems v%d.%d\"\n", major, minor); + + caps = LVAL(resp_data, 4); + DEBUG1("Server capabilities 0x%016llx\n", caps); + +out: + return result; +} + + diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/proto.h /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/proto.h --- linux-2.4.9-31/fs/smbfs/proto.h Thu Jan 1 10:00:00 1970 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/proto.h Wed Apr 10 07:04:35 2002 @@ -0,0 +1,74 @@ +/* + * Autogenerated with cproto on: Wed Apr 10 07:04:32 EST 2002 + */ + +/* proc.c */ +extern int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp); +extern __u32 smb_len(__u8 *p); +extern int smb_get_rsize(struct smb_sb_info *server); +extern int smb_get_wsize(struct smb_sb_info *server); +extern int smb_errno(struct smb_sb_info *server); +extern int smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt); +extern int smb_wakeup(struct smb_sb_info *server); +extern __u8 *smb_setup_header(struct smb_sb_info *server, __u8 command, __u16 wct, __u16 bcc); +extern int smb_open(struct dentry *dentry, int wish); +extern int smb_close(struct inode *ino); +extern int smb_close_fileid(struct dentry *dentry, __u16 fileid); +extern int smb_proc_read(struct inode *inode, off_t offset, int count, char *data); +extern int smb_proc_write(struct inode *inode, off_t offset, int count, const char *data); +extern int smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid); +extern int smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry); +extern int smb_proc_mkdir(struct dentry *dentry); +extern int smb_proc_rmdir(struct dentry *dentry); +extern int smb_proc_unlink(struct dentry *dentry); +extern int smb_proc_flush(struct smb_sb_info *server, __u16 fileid); +extern int smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length); +extern void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr); +extern void smb_decode_unix_basic(struct smb_fattr *fattr, char *p); +extern int smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctl); +extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr); +extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr); +extern int smb_proc_setattr_unix(struct dentry *dentry, struct iattr *attr); +extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr); +extern int smb_proc_dskattr(struct super_block *sb, struct statfs *attr); +extern int smb_proc_read_link(struct smb_sb_info *server, struct dentry *dentry, char *buffer, int len); +extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *dentry, const char *oldpath); +extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry); +extern int smb_proc_query_cifsunix(struct smb_sb_info *server); +/* dir.c */ +extern struct file_operations smb_dir_operations; +extern struct inode_operations smb_dir_inode_operations; +extern void smb_new_dentry(struct dentry *dentry); +extern void smb_renew_times(struct dentry *dentry); +/* cache.c */ +extern void smb_invalid_dir_cache(struct inode *dir); +extern void smb_invalidate_dircache_entries(struct dentry *parent); +extern struct dentry *smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos); +extern int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctrl, struct qstr *qname, struct smb_fattr *entry); +/* sock.c */ +extern int smb_valid_socket(struct inode *inode); +extern int smb_catch_keepalive(struct smb_sb_info *server); +extern int smb_dont_catch_keepalive(struct smb_sb_info *server); +extern void smb_close_socket(struct smb_sb_info *server); +extern int smb_round_length(int len); +extern int smb_request(struct smb_sb_info *server); +extern int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, int ldata, unsigned char *data, int lparam, unsigned char *param, int *lrdata, unsigned char **rdata, int *lrparam, unsigned char **rparam); +/* inode.c */ +extern struct inode *smb_iget(struct super_block *sb, struct smb_fattr *fattr); +extern void smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr); +extern void smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr); +extern void smb_invalidate_inodes(struct smb_sb_info *server); +extern int smb_revalidate_inode(struct dentry *dentry); +extern struct super_block *smb_read_super(struct super_block *sb, void *raw_data, int silent); +extern int smb_notify_change(struct dentry *dentry, struct iattr *attr); +/* file.c */ +extern struct address_space_operations smb_file_aops; +extern struct file_operations smb_file_operations; +extern struct inode_operations smb_file_inode_operations; +/* ioctl.c */ +extern int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +/* symlink.c */ +extern int smb_read_link(struct dentry *dentry, char *buffer, int len); +extern int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname); +extern int smb_follow_link(struct dentry *dentry, struct nameidata *nd); +extern struct inode_operations smb_link_inode_operations; diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/sock.c /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/sock.c --- linux-2.4.9-31/fs/smbfs/sock.c Wed May 16 06:40:55 2001 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/sock.c Sun Apr 7 12:43:08 2002 @@ -27,6 +27,7 @@ #include #include "smb_debug.h" +#include "proto.h" static int @@ -218,7 +219,7 @@ server->data_ready = NULL; goto out; } - DEBUG1("sk->d_r = %x, server->d_r = %x\n", + VERBOSE("sk->d_r = %x, server->d_r = %x\n", (unsigned int) (sk->data_ready), (unsigned int) (server->data_ready)); @@ -265,7 +266,7 @@ "server->data_ready == NULL\n"); goto out; } - DEBUG1("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n", + VERBOSE("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n", (unsigned int) (sk->data_ready), (unsigned int) (server->data_ready)); @@ -674,7 +675,7 @@ */ if (server->rcls) { int error = smb_errno(server); - if (error == EBADSLT) { + if (error == -EBADSLT) { printk(KERN_ERR "smb_request: tree ID invalid\n"); result = error; goto bad_conn; @@ -866,7 +867,7 @@ */ if (server->rcls) { int error = smb_errno(server); - if (error == EBADSLT) { + if (error == -EBADSLT) { printk(KERN_ERR "smb_request: tree ID invalid\n"); result = error; goto bad_conn; diff -urN -X /root/dontdiff linux-2.4.9-31/fs/smbfs/symlink.c /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/symlink.c --- linux-2.4.9-31/fs/smbfs/symlink.c Thu Jan 1 10:00:00 1970 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/fs/smbfs/symlink.c Sun Apr 7 12:43:08 2002 @@ -0,0 +1,73 @@ +/* + * symlink.c + * + * Copyright (C) 2002 by John Newbigin + * + * Please add a note about your changes to smbfs in the ChangeLog file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "smb_debug.h" +#include "proto.h" + +int +smb_read_link(struct dentry *dentry, char *buffer, int len) +{ + char link[256]; + int r; + DEBUG1("read link buffer len = %d\n", len); + + r = smb_proc_read_link(server_from_dentry(dentry), dentry, link, sizeof(link) - 1); + if(r > 0) { + return vfs_readlink(dentry, buffer, len, link); + } else { + return -ENOENT; + } +} + +int smb_symlink(struct inode *inode,struct dentry *dentry,const char *oldname) +{ + DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry)); + + /* create a symlink object called dentry, pointing to oldname */ + return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname); +} + +int +smb_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + char link[256]; + int len; + DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry)); + + len = smb_proc_read_link(server_from_dentry(dentry), dentry, link, sizeof(link) - 1); + if(len > 0) { + link[len] = 0; + return vfs_follow_link(nd, link); + } else { + return -ENOENT; + } +} + + +struct inode_operations smb_link_inode_operations = +{ + readlink: smb_read_link, + follow_link: smb_follow_link, +}; + diff -urN -X /root/dontdiff linux-2.4.9-31/include/linux/smb.h /tmp/tmp/rhkernel/linux-2.4.9-31/include/linux/smb.h --- linux-2.4.9-31/include/linux/smb.h Tue Feb 26 22:53:53 2002 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/include/linux/smb.h Sun Apr 7 21:32:46 2002 @@ -91,6 +91,7 @@ time_t f_ctime; unsigned long f_blksize; unsigned long f_blocks; + int f_unix; }; enum smb_conn_state { diff -urN -X /root/dontdiff linux-2.4.9-31/include/linux/smb_fs.h /tmp/tmp/rhkernel/linux-2.4.9-31/include/linux/smb_fs.h --- linux-2.4.9-31/include/linux/smb_fs.h Tue Feb 26 23:00:06 2002 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/include/linux/smb_fs.h Thu Apr 18 23:22:28 2002 @@ -112,7 +112,7 @@ #define SMB_CAP_NT_FIND 0x0200 #define SMB_CAP_DFS 0x1000 #define SMB_CAP_LARGE_READX 0x4000 - +#define SMB_CAP_UNIX 0x800000 /* * This is the time we allow an inode, dentry or dir cache to live. It is bad @@ -161,84 +161,6 @@ } -/* FIXME! the prototype list is probably not correct. Automate? */ - -/* linux/fs/smbfs/file.c */ -extern struct inode_operations smb_file_inode_operations; -extern struct file_operations smb_file_operations; -extern struct address_space_operations smb_file_aops; - -/* linux/fs/smbfs/dir.c */ -extern struct inode_operations smb_dir_inode_operations; -extern struct file_operations smb_dir_operations; -void smb_new_dentry(struct dentry *dentry); -void smb_renew_times(struct dentry *); - -/* linux/fs/smbfs/ioctl.c */ -int smb_ioctl (struct inode *, struct file *, unsigned int, unsigned long); - -/* linux/fs/smbfs/inode.c */ -struct super_block *smb_read_super(struct super_block *, void *, int); -void smb_get_inode_attr(struct inode *, struct smb_fattr *); -void smb_set_inode_attr(struct inode *, struct smb_fattr *); -void smb_invalidate_inodes(struct smb_sb_info *); -int smb_revalidate_inode(struct dentry *); -int smb_notify_change(struct dentry *, struct iattr *); -struct inode *smb_iget(struct super_block *, struct smb_fattr *); - -/* linux/fs/smbfs/proc.c */ -int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp); -__u32 smb_len(unsigned char *); -__u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16); -int smb_get_rsize(struct smb_sb_info *); -int smb_get_wsize(struct smb_sb_info *); -int smb_newconn(struct smb_sb_info *, struct smb_conn_opt *); -int smb_errno(struct smb_sb_info *); -int smb_close(struct inode *); -int smb_close_fileid(struct dentry *, __u16); -int smb_open(struct dentry *, int); -int smb_proc_read(struct inode *, off_t, int, char *); -int smb_proc_write(struct inode *, off_t, int, const char *); -int smb_proc_create(struct dentry *, __u16, time_t, __u16 *); -int smb_proc_mv(struct dentry *, struct dentry *); -int smb_proc_mkdir(struct dentry *); -int smb_proc_rmdir(struct dentry *); -int smb_proc_unlink(struct dentry *); -int smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir, - struct smb_cache_control *ctl); -int smb_proc_getattr(struct dentry *, struct smb_fattr *); -int smb_proc_setattr(struct dentry *, struct smb_fattr *); -int smb_proc_settime(struct dentry *, struct smb_fattr *); -int smb_proc_dskattr(struct super_block *, struct statfs *); -int smb_proc_disconnect(struct smb_sb_info *); -int smb_proc_trunc(struct smb_sb_info *, __u16, __u32); -int smb_proc_flush(struct smb_sb_info *, __u16); -void smb_init_root_dirent(struct smb_sb_info *, struct smb_fattr *); - -/* linux/fs/smbfs/sock.c */ -int smb_round_length(int); -int smb_valid_socket(struct inode *); -void smb_close_socket(struct smb_sb_info *); -int smb_request(struct smb_sb_info *server); -int smb_catch_keepalive(struct smb_sb_info *server); -int smb_dont_catch_keepalive(struct smb_sb_info *server); -int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, - int ldata, unsigned char *data, - int lparam, unsigned char *param, - int *lrdata, unsigned char **rdata, - int *lrparam, unsigned char **rparam); - -/* fs/smbfs/cache.c */ - -void smb_invalid_dir_cache(struct inode * dir); -void smb_invalidate_dircache_entries(struct dentry *parent); -struct dentry * smb_dget_fpos(struct dentry *dentry, struct dentry *parent, - unsigned long fpos); -int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, - struct smb_cache_control *ctrl, struct qstr *qname, - struct smb_fattr *entry); - - #endif /* __KERNEL__ */ #endif /* _LINUX_SMB_FS_H */ diff -urN -X /root/dontdiff linux-2.4.9-31/include/linux/smbno.h /tmp/tmp/rhkernel/linux-2.4.9-31/include/linux/smbno.h --- linux-2.4.9-31/include/linux/smbno.h Tue Nov 25 05:30:40 1997 +++ /tmp/tmp/rhkernel/linux-2.4.9-31/include/linux/smbno.h Sun Apr 7 12:43:08 2002 @@ -39,14 +39,20 @@ #define ERRbadshare 32 /* Share mode on file conflict with open mode */ #define ERRlock 33 /* Lock request conflicts with existing lock */ #define ERRfilexists 80 /* File in operation already exists */ -#define ERRundocumented1 123 /* Invalid name?? e.g. .tmp* */ #define ERRbadpipe 230 /* Named pipe invalid */ #define ERRpipebusy 231 /* All instances of pipe are busy */ #define ERRpipeclosing 232 /* named pipe close in progress */ #define ERRnotconnected 233 /* No process on other end of named pipe */ #define ERRmoredata 234 /* More data to be returned */ -#define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */ -#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not supported */ + +#define ERROR_INVALID_PARAMETER 87 +#define ERROR_DISK_FULL 112 +#define ERROR_INVALID_NAME 123 +#define ERROR_DIR_NOT_EMPTY 145 +#define ERROR_NOT_LOCKED 158 +#define ERROR_ALREADY_EXISTS 183 /* see also 80 ? */ +#define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */ +#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not supported */ /* Error codes for the ERRSRV class */ @@ -275,4 +281,74 @@ #define TRANSACT2_FINDNOTIFYNEXT 12 #define TRANSACT2_MKDIR 13 + +/* UNIX stuff (from samba trans2.h) */ + +#define MIN_UNIX_INFO_LEVEL 0x200 +#define MAX_UNIX_INFO_LEVEL 0x2FF + +#define SMB_QUERY_FILE_UNIX_BASIC 0x200 +#define SMB_QUERY_FILE_UNIX_LINK 0x201 +#define SMB_QUERY_FILE_UNIX_HLINK 0x202 + +#define SMB_SET_FILE_UNIX_BASIC 0x200 + +#define SMB_FILE_FILE_UNIX 0x202 + +#define SMB_QUERY_CIFS_UNIX_INFO 0x200 + +#define SMB_MODE_NO_CHANGE 0xFFFFFFFF /* file mode value which */ + /* means "don't change it" */ +#define SMB_UID_NO_CHANGE 0xFFFFFFFF +#define SMB_GID_NO_CHANGE 0xFFFFFFFF + +#define SMB_TIME_NO_CHANGE 0xFFFFFFFFFFFFFFFF +#define SMB_SIZE_NO_CHANGE 0xFFFFFFFFFFFFFFFF + +/* UNIX filetype mappings. */ + +#define UNIX_TYPE_FILE 0 +#define UNIX_TYPE_DIR 1 +#define UNIX_TYPE_SYMLINK 2 +#define UNIX_TYPE_CHARDEV 3 +#define UNIX_TYPE_BLKDEV 4 +#define UNIX_TYPE_FIFO 5 +#define UNIX_TYPE_SOCKET 6 +#define UNIX_TYPE_UNKNOWN 0xFFFFFFFF + +/* + * Oh this is fun. "Standard UNIX permissions" has no + * meaning in POSIX. We need to define the mapping onto + * and off the wire as this was not done in the original HP + * spec. JRA. + */ + +#define UNIX_X_OTH 0000001 +#define UNIX_W_OTH 0000002 +#define UNIX_R_OTH 0000004 +#define UNIX_X_GRP 0000010 +#define UNIX_W_GRP 0000020 +#define UNIX_R_GRP 0000040 +#define UNIX_X_USR 0000100 +#define UNIX_W_USR 0000200 +#define UNIX_R_USR 0000400 +#define UNIX_STICKY 0001000 +#define UNIX_SET_GID 0002000 +#define UNIX_SET_UID 0004000 + +/* Masks for the above */ +#define UNIX_OTH_MASK 0000007 +#define UNIX_GRP_MASK 0000070 +#define UNIX_USR_MASK 0000700 +#define UNIX_PERM_MASK 0000777 +#define UNIX_EXTRA_MASK 0007000 +#define UNIX_ALL_MASK 0007777 + +#define SMB_QUERY_FILE_UNIX_LINK 0x201 +#define SMB_SET_FILE_UNIX_LINK 0x201 +#define SMB_SET_FILE_UNIX_HLINK 0x203 + +#define SMB_FIND_FILE_UNIX 0x202 + + #endif /* _SMBNO_H_ */