[CIFS] Support deep tree mounts (e.g. mounts to //server/share/path)
Samba bugzilla #4040 Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
parent
b835bebe95
commit
2fe87f02a0
|
@ -1,3 +1,7 @@
|
|||
Version 1.46
|
||||
------------
|
||||
Support deep tree mounts. Better support OS/2, Win9x (DOS) time stamps.
|
||||
|
||||
Version 1.45
|
||||
------------
|
||||
Do not time out lockw calls when using posix extensions. Do not
|
||||
|
@ -6,7 +10,8 @@ on requests on other threads. Improve POSIX locking emulation,
|
|||
(lock cancel now works, and unlock of merged range works even
|
||||
to Windows servers now). Fix oops on mount to lanman servers
|
||||
(win9x, os/2 etc.) when null password. Do not send listxattr
|
||||
(SMB to query all EAs) if nouser_xattr specified.
|
||||
(SMB to query all EAs) if nouser_xattr specified. Fix SE Linux
|
||||
problem (instantiate inodes/dentries in right order for readdir).
|
||||
|
||||
Version 1.44
|
||||
------------
|
||||
|
|
|
@ -40,5 +40,7 @@ struct cifs_sb_info {
|
|||
mode_t mnt_file_mode;
|
||||
mode_t mnt_dir_mode;
|
||||
int mnt_cifs_flags;
|
||||
int prepathlen;
|
||||
char * prepath;
|
||||
};
|
||||
#endif /* _CIFS_FS_SB_H */
|
||||
|
|
|
@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
|
|||
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
||||
extern int cifs_ioctl (struct inode * inode, struct file * filep,
|
||||
unsigned int command, unsigned long arg);
|
||||
#define CIFS_VERSION "1.45"
|
||||
#define CIFS_VERSION "1.46"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -1344,6 +1344,7 @@ struct smb_t2_rsp {
|
|||
#define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */
|
||||
#define SMB_QUERY_POSIX_PERMISSION 0x207
|
||||
#define SMB_QUERY_POSIX_LOCK 0x208
|
||||
/* #define SMB_POSIX_OPEN 0x209 */
|
||||
#define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee
|
||||
#define SMB_QUERY_FILE_ACCESS_INFO 0x3f0
|
||||
#define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */
|
||||
|
@ -1363,6 +1364,7 @@ struct smb_t2_rsp {
|
|||
#define SMB_SET_XATTR 0x205
|
||||
#define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */
|
||||
#define SMB_SET_POSIX_LOCK 0x208
|
||||
#define SMB_POSIX_OPEN 0x209
|
||||
#define SMB_SET_FILE_BASIC_INFO2 0x3ec
|
||||
#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */
|
||||
#define SMB_FILE_ALL_INFO2 0x3fa
|
||||
|
|
|
@ -89,6 +89,7 @@ struct smb_vol {
|
|||
unsigned int wsize;
|
||||
unsigned int sockopt;
|
||||
unsigned short int port;
|
||||
char * prepath;
|
||||
};
|
||||
|
||||
static int ipv4_connect(struct sockaddr_in *psin_server,
|
||||
|
@ -993,6 +994,28 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|
|||
printk(KERN_WARNING "CIFS: domain name too long\n");
|
||||
return 1;
|
||||
}
|
||||
} else if (strnicmp(data, "prefixpath", 10) == 0) {
|
||||
if (!value || !*value) {
|
||||
printk(KERN_WARNING
|
||||
"CIFS: invalid path prefix\n");
|
||||
return 1; /* needs_arg; */
|
||||
}
|
||||
if ((temp_len = strnlen(value, 1024)) < 1024) {
|
||||
if(value[0] != '/')
|
||||
temp_len++; /* missing leading slash */
|
||||
vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
|
||||
if(vol->prepath == NULL)
|
||||
return 1;
|
||||
if(value[0] != '/') {
|
||||
vol->prepath[0] = '/';
|
||||
strcpy(vol->prepath+1,value);
|
||||
} else
|
||||
strcpy(vol->prepath,value);
|
||||
cFYI(1,("prefix path %s",vol->prepath));
|
||||
} else {
|
||||
printk(KERN_WARNING "CIFS: prefix too long\n");
|
||||
return 1;
|
||||
}
|
||||
} else if (strnicmp(data, "iocharset", 9) == 0) {
|
||||
if (!value || !*value) {
|
||||
printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
|
||||
|
@ -1605,6 +1628,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1619,6 +1643,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
locations such as env variables and files on disk */
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1639,6 +1664,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
/* we failed translating address */
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1651,6 +1677,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
cERROR(1,("Connecting to DFS root not implemented yet"));
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
} else /* which servers DFS root would we conect to */ {
|
||||
|
@ -1658,6 +1685,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1672,6 +1700,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -ELIBACC;
|
||||
}
|
||||
|
@ -1688,6 +1717,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
else {
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1710,6 +1740,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
sock_release(csocket);
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1720,6 +1751,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
sock_release(csocket);
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
} else {
|
||||
|
@ -1744,6 +1776,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
sock_release(csocket);
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1831,6 +1864,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
/* Windows ME may prefer this */
|
||||
cFYI(1,("readsize set to minimum 2048"));
|
||||
}
|
||||
/* calculate prepath */
|
||||
cifs_sb->prepath = volume_info.prepath;
|
||||
if(cifs_sb->prepath) {
|
||||
cifs_sb->prepathlen = strlen(cifs_sb->prepath);
|
||||
cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
|
||||
volume_info.prepath = NULL;
|
||||
} else
|
||||
cifs_sb->prepathlen = 0;
|
||||
cifs_sb->mnt_uid = volume_info.linux_uid;
|
||||
cifs_sb->mnt_gid = volume_info.linux_gid;
|
||||
cifs_sb->mnt_file_mode = volume_info.file_mode;
|
||||
|
@ -2008,6 +2049,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
the password ptr is put in the new session structure (in which case the
|
||||
password will be freed at unmount time) */
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
@ -3195,6 +3237,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
|
|||
int xid;
|
||||
struct cifsSesInfo *ses = NULL;
|
||||
struct task_struct *cifsd_task;
|
||||
char * tmp;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -3228,6 +3271,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
|
|||
}
|
||||
|
||||
cifs_sb->tcon = NULL;
|
||||
tmp = cifs_sb->prepath;
|
||||
cifs_sb->prepathlen = 0;
|
||||
cifs_sb->prepath = NULL;
|
||||
kfree(tmp);
|
||||
if (ses)
|
||||
schedule_timeout_interruptible(msecs_to_jiffies(500));
|
||||
if (ses)
|
||||
|
|
|
@ -46,7 +46,8 @@ char *
|
|||
build_path_from_dentry(struct dentry *direntry)
|
||||
{
|
||||
struct dentry *temp;
|
||||
int namelen = 0;
|
||||
int namelen;
|
||||
int pplen;
|
||||
char *full_path;
|
||||
char dirsep;
|
||||
|
||||
|
@ -56,7 +57,9 @@ build_path_from_dentry(struct dentry *direntry)
|
|||
when the server crashed */
|
||||
|
||||
dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
|
||||
pplen = CIFS_SB(direntry->d_sb)->prepathlen;
|
||||
cifs_bp_rename_retry:
|
||||
namelen = pplen;
|
||||
for (temp = direntry; !IS_ROOT(temp);) {
|
||||
namelen += (1 + temp->d_name.len);
|
||||
temp = temp->d_parent;
|
||||
|
@ -70,7 +73,6 @@ cifs_bp_rename_retry:
|
|||
if(full_path == NULL)
|
||||
return full_path;
|
||||
full_path[namelen] = 0; /* trailing null */
|
||||
|
||||
for (temp = direntry; !IS_ROOT(temp);) {
|
||||
namelen -= 1 + temp->d_name.len;
|
||||
if (namelen < 0) {
|
||||
|
@ -79,7 +81,7 @@ cifs_bp_rename_retry:
|
|||
full_path[namelen] = dirsep;
|
||||
strncpy(full_path + namelen + 1, temp->d_name.name,
|
||||
temp->d_name.len);
|
||||
cFYI(0, (" name: %s ", full_path + namelen));
|
||||
cFYI(0, ("name: %s", full_path + namelen));
|
||||
}
|
||||
temp = temp->d_parent;
|
||||
if(temp == NULL) {
|
||||
|
@ -88,18 +90,23 @@ cifs_bp_rename_retry:
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
if (namelen != 0) {
|
||||
if (namelen != pplen) {
|
||||
cERROR(1,
|
||||
("We did not end path lookup where we expected namelen is %d",
|
||||
("did not end path lookup where expected namelen is %d",
|
||||
namelen));
|
||||
/* presumably this is only possible if we were racing with a rename
|
||||
/* presumably this is only possible if racing with a rename
|
||||
of one of the parent directories (we can not lock the dentries
|
||||
above us to prevent this, but retrying should be harmless) */
|
||||
kfree(full_path);
|
||||
namelen = 0;
|
||||
goto cifs_bp_rename_retry;
|
||||
}
|
||||
|
||||
/* DIR_SEP already set for byte 0 / vs \ but not for
|
||||
subsequent slashes in prepath which currently must
|
||||
be entered the right way - not sure if there is an alternative
|
||||
since the '\' is a valid posix character so we can not switch
|
||||
those safely to '/' if any are found in the middle of the prepath */
|
||||
/* BB test paths to Windows with '/' in the midst of prepath */
|
||||
strncpy(full_path,CIFS_SB(direntry->d_sb)->prepath,pplen);
|
||||
return full_path;
|
||||
}
|
||||
|
||||
|
|
|
@ -269,7 +269,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
|
|||
rc = CIFSSMBGetCIFSACL(xid, pTcon, fid,
|
||||
ea_value, buf_size,
|
||||
ACL_TYPE_ACCESS);
|
||||
CIFSSMBClose(xid, pTcon, fid)
|
||||
CIFSSMBClose(xid, pTcon, fid);
|
||||
}
|
||||
} */ /* BB enable after fixing up return data */
|
||||
|
||||
|
|
Loading…
Reference in New Issue