|
@@ -24,6 +24,7 @@
|
|
|
#include "smb2proto.h"
|
|
|
#include "cifsproto.h"
|
|
|
#include "cifs_debug.h"
|
|
|
+#include "cifs_unicode.h"
|
|
|
#include "smb2status.h"
|
|
|
#include "smb2glob.h"
|
|
|
|
|
@@ -229,7 +230,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
oparms.fid = &fid;
|
|
|
oparms.reconnect = false;
|
|
|
|
|
|
- rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
|
|
|
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
|
|
|
if (rc) {
|
|
|
kfree(utf16_path);
|
|
|
return rc;
|
|
@@ -463,7 +464,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
oparms.fid = fid;
|
|
|
oparms.reconnect = false;
|
|
|
|
|
|
- rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
|
|
|
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
|
|
|
kfree(utf16_path);
|
|
|
if (rc) {
|
|
|
cifs_dbg(VFS, "open dir failed\n");
|
|
@@ -550,7 +551,7 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
oparms.fid = &fid;
|
|
|
oparms.reconnect = false;
|
|
|
|
|
|
- rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL);
|
|
|
+ rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
buf->f_type = SMB2_MAGIC_NUMBER;
|
|
@@ -596,6 +597,57 @@ smb2_new_lease_key(struct cifs_fid *fid)
|
|
|
get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
+ const char *full_path, char **target_path,
|
|
|
+ struct cifs_sb_info *cifs_sb)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ __le16 *utf16_path;
|
|
|
+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
+ struct cifs_open_parms oparms;
|
|
|
+ struct cifs_fid fid;
|
|
|
+ struct smb2_err_rsp *err_buf = NULL;
|
|
|
+ struct smb2_symlink_err_rsp *symlink;
|
|
|
+ unsigned int sub_len, sub_offset;
|
|
|
+
|
|
|
+ cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
|
|
+
|
|
|
+ utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
|
|
+ if (!utf16_path)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ oparms.tcon = tcon;
|
|
|
+ oparms.desired_access = FILE_READ_ATTRIBUTES;
|
|
|
+ oparms.disposition = FILE_OPEN;
|
|
|
+ oparms.create_options = 0;
|
|
|
+ oparms.fid = &fid;
|
|
|
+ oparms.reconnect = false;
|
|
|
+
|
|
|
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_buf);
|
|
|
+
|
|
|
+ if (!rc || !err_buf) {
|
|
|
+ kfree(utf16_path);
|
|
|
+ return -ENOENT;
|
|
|
+ }
|
|
|
+ /* open must fail on symlink - reset rc */
|
|
|
+ rc = 0;
|
|
|
+ symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
|
|
|
+ sub_len = le16_to_cpu(symlink->SubstituteNameLength);
|
|
|
+ sub_offset = le16_to_cpu(symlink->SubstituteNameOffset);
|
|
|
+ *target_path = cifs_strndup_from_utf16(
|
|
|
+ (char *)symlink->PathBuffer + sub_offset,
|
|
|
+ sub_len, true, cifs_sb->local_nls);
|
|
|
+ if (!(*target_path)) {
|
|
|
+ kfree(utf16_path);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ convert_delimiter(*target_path, '/');
|
|
|
+ cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
|
|
+ kfree(utf16_path);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
struct smb_version_operations smb21_operations = {
|
|
|
.compare_fids = smb2_compare_fids,
|
|
|
.setup_request = smb2_setup_request,
|
|
@@ -638,6 +690,7 @@ struct smb_version_operations smb21_operations = {
|
|
|
.unlink = smb2_unlink,
|
|
|
.rename = smb2_rename_path,
|
|
|
.create_hardlink = smb2_create_hardlink,
|
|
|
+ .query_symlink = smb2_query_symlink,
|
|
|
.open = smb2_open_file,
|
|
|
.set_fid = smb2_set_fid,
|
|
|
.close = smb2_close_file,
|
|
@@ -706,6 +759,7 @@ struct smb_version_operations smb30_operations = {
|
|
|
.unlink = smb2_unlink,
|
|
|
.rename = smb2_rename_path,
|
|
|
.create_hardlink = smb2_create_hardlink,
|
|
|
+ .query_symlink = smb2_query_symlink,
|
|
|
.open = smb2_open_file,
|
|
|
.set_fid = smb2_set_fid,
|
|
|
.close = smb2_close_file,
|