2021-06-18 05:31:49 +00:00
|
|
|
// SPDX-License-Identifier: LGPL-2.1
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
*
|
2010-04-21 04:12:10 +00:00
|
|
|
* Copyright (C) International Business Machines Corp., 2002,2010
|
2005-04-16 22:20:36 +00:00
|
|
|
* Author(s): Steve French (sfrench@us.ibm.com)
|
|
|
|
*
|
|
|
|
* Contains the routines for constructing the SMB PDUs themselves
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
|
|
|
|
/* These are mostly routines that operate on a pathname, or on a tree id */
|
|
|
|
/* (mounted volume), but there are eight handle based routines which must be */
|
2007-04-23 22:07:35 +00:00
|
|
|
/* treated slightly differently for reconnection purposes since we never */
|
|
|
|
/* want to reuse a stale file handle and only the caller knows the file info */
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
#include <linux/fs.h>
|
2022-11-20 14:15:34 +00:00
|
|
|
#include <linux/filelock.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/vfs.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/posix_acl_xattr.h>
|
2011-05-19 20:22:56 +00:00
|
|
|
#include <linux/pagemap.h>
|
2011-10-19 19:30:07 +00:00
|
|
|
#include <linux/swap.h>
|
|
|
|
#include <linux/task_io_accounting_ops.h>
|
2016-12-24 19:46:01 +00:00
|
|
|
#include <linux/uaccess.h>
|
2022-03-09 11:01:12 +00:00
|
|
|
#include <linux/netfs.h>
|
|
|
|
#include <trace/events/netfs.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "cifspdu.h"
|
cifs: Change the I/O paths to use an iterator rather than a page list
Currently, the cifs I/O paths hand lists of pages from the VM interface
routines at the top all the way through the intervening layers to the
socket interface at the bottom.
This is a problem, however, for interfacing with netfslib which passes an
iterator through to the ->issue_read() method (and will pass an iterator
through to the ->issue_write() method in future). Netfslib takes over
bounce buffering for direct I/O, async I/O and encrypted content, so cifs
doesn't need to do that. Netfslib also converts IOVEC-type iterators into
BVEC-type iterators if necessary.
Further, cifs needs foliating - and folios may come in a variety of sizes,
so a page list pointing to an array of heterogeneous pages may cause
problems in places such as where crypto is done.
Change the cifs I/O paths to hand iov_iter iterators all the way through
instead.
Notes:
(1) Some old routines are #if'd out to be removed in a follow up patch so
as to avoid confusing diff, thereby making the diff output easier to
follow. I've removed functions that don't overlap with anything
added.
(2) struct smb_rqst loses rq_pages, rq_offset, rq_npages, rq_pagesz and
rq_tailsz which describe the pages forming the buffer; instead there's
an rq_iter describing the source buffer and an rq_buffer which is used
to hold the buffer for encryption.
(3) struct cifs_readdata and cifs_writedata are similarly modified to
smb_rqst. The ->read_into_pages() and ->copy_into_pages() are then
replaced with passing the iterator directly to the socket.
The iterators are stored in these structs so that they are persistent
and don't get deallocated when the function returns (unlike if they
were stack variables).
(4) Buffered writeback is overhauled, borrowing the code from the afs
filesystem to gather up contiguous runs of folios. The XARRAY-type
iterator is then used to refer directly to the pagecache and can be
passed to the socket to transmit data directly from there.
This includes:
cifs_extend_writeback()
cifs_write_back_from_locked_folio()
cifs_writepages_region()
cifs_writepages()
(5) Pages are converted to folios.
(6) Direct I/O uses netfs_extract_user_iter() to create a BVEC-type
iterator from an IOBUF/UBUF-type source iterator.
(7) smb2_get_aead_req() uses netfs_extract_iter_to_sg() to extract page
fragments from the iterator into the scatterlists that the crypto
layer prefers.
(8) smb2_init_transform_rq() attached pages to smb_rqst::rq_buffer, an
xarray, to use as a bounce buffer for encryption. An XARRAY-type
iterator can then be used to pass the bounce buffer to lower layers.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Shyam Prasad N <nspmangalore@gmail.com>
cc: Rohith Surabattula <rohiths.msft@gmail.com>
cc: Paulo Alcantara <pc@cjr.nz>
cc: Jeff Layton <jlayton@kernel.org>
cc: linux-cifs@vger.kernel.org
Link: https://lore.kernel.org/r/164311907995.2806745.400147335497304099.stgit@warthog.procyon.org.uk/ # rfc
Link: https://lore.kernel.org/r/164928620163.457102.11602306234438271112.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/165211420279.3154751.15923591172438186144.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/165348880385.2106726.3220789453472800240.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/165364827111.3334034.934805882842932881.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/166126396180.708021.271013668175370826.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/166697259595.61150.5982032408321852414.stgit@warthog.procyon.org.uk/ # rfc
Link: https://lore.kernel.org/r/166732031756.3186319.12528413619888902872.stgit@warthog.procyon.org.uk/ # rfc
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-01-24 21:13:24 +00:00
|
|
|
#include "cifsfs.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "cifsglob.h"
|
2007-10-03 18:22:19 +00:00
|
|
|
#include "cifsacl.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
#include "cifsproto.h"
|
|
|
|
#include "cifs_unicode.h"
|
|
|
|
#include "cifs_debug.h"
|
2011-10-19 19:30:07 +00:00
|
|
|
#include "fscache.h"
|
2017-11-23 00:38:45 +00:00
|
|
|
#include "smbdirect.h"
|
2018-11-14 19:24:29 +00:00
|
|
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
|
|
|
#include "dfs_cache.h"
|
|
|
|
#endif
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_CIFS_POSIX
|
|
|
|
static struct {
|
|
|
|
int index;
|
|
|
|
char *name;
|
|
|
|
} protocols[] = {
|
2007-07-13 00:33:32 +00:00
|
|
|
{CIFS_PROT, "\2NT LM 0.12"},
|
2006-05-31 22:40:51 +00:00
|
|
|
{POSIX_PROT, "\2POSIX 2"},
|
2005-04-16 22:20:36 +00:00
|
|
|
{BAD_PROT, "\2"}
|
|
|
|
};
|
|
|
|
#else
|
|
|
|
static struct {
|
|
|
|
int index;
|
|
|
|
char *name;
|
|
|
|
} protocols[] = {
|
2007-07-07 19:25:05 +00:00
|
|
|
{CIFS_PROT, "\2NT LM 0.12"},
|
2005-04-16 22:20:36 +00:00
|
|
|
{BAD_PROT, "\2"}
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2006-05-31 22:40:51 +00:00
|
|
|
/* define the number of elements in the cifs dialect array */
|
|
|
|
#ifdef CONFIG_CIFS_POSIX
|
|
|
|
#define CIFS_NUM_PROT 2
|
|
|
|
#else /* not posix */
|
|
|
|
#define CIFS_NUM_PROT 1
|
|
|
|
#endif /* CIFS_POSIX */
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2009-09-03 16:07:17 +00:00
|
|
|
/* reconnect the socket, tcon, and smb session if needed */
|
|
|
|
static int
|
2011-05-27 04:34:02 +00:00
|
|
|
cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
2009-09-03 16:07:17 +00:00
|
|
|
{
|
|
|
|
struct TCP_Server_Info *server;
|
2024-11-26 20:40:11 +00:00
|
|
|
struct cifs_ses *ses;
|
|
|
|
int rc;
|
2009-09-03 16:07:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
|
|
|
|
* tcp and smb session status done differently for those three - in the
|
|
|
|
* calling routine
|
|
|
|
*/
|
|
|
|
if (!tcon)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ses = tcon->ses;
|
|
|
|
server = ses->server;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* only tree disconnect, open, and write, (and ulogoff which does not
|
2023-03-23 21:20:02 +00:00
|
|
|
* have tcon) are allowed as we start umount
|
2009-09-03 16:07:17 +00:00
|
|
|
*/
|
2022-07-27 19:49:56 +00:00
|
|
|
spin_lock(&tcon->tc_lock);
|
smb3: cleanup and clarify status of tree connections
Currently the way the tid (tree connection) status is tracked
is confusing. The same enum is used for structs cifs_tcon
and cifs_ses and TCP_Server_info, but each of these three has
different states that they transition among. The current
code also unnecessarily uses camelCase.
Convert from use of statusEnum to a new tid_status_enum for
tree connections. The valid states for a tid are:
TID_NEW = 0,
TID_GOOD,
TID_EXITING,
TID_NEED_RECON,
TID_NEED_TCON,
TID_IN_TCON,
TID_NEED_FILES_INVALIDATE, /* unused, considering removing in future */
TID_IN_FILES_INVALIDATE
It also removes CifsNeedTcon, CifsInTcon, CifsNeedFilesInvalidate and
CifsInFilesInvalidate from the statusEnum used for session and
TCP_Server_Info since they are not relevant for those.
A follow on patch will fix the places where we use the
tcon->need_reconnect flag to be more consistent with the tid->status.
Also fixes a bug that was:
Reported-by: kernel test robot <lkp@intel.com>
Reviewed-by: Shyam Prasad N <sprasad@microsoft.com>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-27 21:07:30 +00:00
|
|
|
if (tcon->status == TID_EXITING) {
|
2023-03-23 21:20:02 +00:00
|
|
|
if (smb_command != SMB_COM_TREE_DISCONNECT) {
|
2022-07-27 19:49:56 +00:00
|
|
|
spin_unlock(&tcon->tc_lock);
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "can not send cmd %d while umounting\n",
|
|
|
|
smb_command);
|
2009-09-03 16:07:17 +00:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
}
|
2022-07-27 19:49:56 +00:00
|
|
|
spin_unlock(&tcon->tc_lock);
|
2009-09-03 16:07:17 +00:00
|
|
|
|
2023-03-29 20:14:21 +00:00
|
|
|
again:
|
2023-02-28 22:01:55 +00:00
|
|
|
rc = cifs_wait_for_server_reconnect(server, tcon->retry);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
2009-09-03 16:07:17 +00:00
|
|
|
|
2021-07-19 12:46:53 +00:00
|
|
|
spin_lock(&ses->chan_lock);
|
|
|
|
if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) {
|
|
|
|
spin_unlock(&ses->chan_lock);
|
2009-09-03 16:07:17 +00:00
|
|
|
return 0;
|
2021-07-19 12:46:53 +00:00
|
|
|
}
|
|
|
|
spin_unlock(&ses->chan_lock);
|
2009-09-03 16:07:17 +00:00
|
|
|
|
2023-03-29 20:14:21 +00:00
|
|
|
mutex_lock(&ses->session_mutex);
|
2017-07-11 10:44:39 +00:00
|
|
|
/*
|
|
|
|
* Recheck after acquire mutex. If another thread is negotiating
|
|
|
|
* and the server never sends an answer the socket will be closed
|
|
|
|
* and tcpStatus set to reconnect.
|
|
|
|
*/
|
2022-07-27 19:49:56 +00:00
|
|
|
spin_lock(&server->srv_lock);
|
2017-07-11 10:44:39 +00:00
|
|
|
if (server->tcpStatus == CifsNeedReconnect) {
|
2022-07-27 19:49:56 +00:00
|
|
|
spin_unlock(&server->srv_lock);
|
2023-04-06 08:55:47 +00:00
|
|
|
mutex_unlock(&ses->session_mutex);
|
2023-03-29 20:14:21 +00:00
|
|
|
|
|
|
|
if (tcon->retry)
|
|
|
|
goto again;
|
2017-07-11 10:44:39 +00:00
|
|
|
rc = -EHOSTDOWN;
|
|
|
|
goto out;
|
|
|
|
}
|
2022-07-27 19:49:56 +00:00
|
|
|
spin_unlock(&server->srv_lock);
|
2017-07-11 10:44:39 +00:00
|
|
|
|
2021-07-19 12:46:53 +00:00
|
|
|
/*
|
|
|
|
* need to prevent multiple threads trying to simultaneously
|
|
|
|
* reconnect the same SMB session
|
|
|
|
*/
|
2023-03-29 20:14:21 +00:00
|
|
|
spin_lock(&ses->ses_lock);
|
2021-07-19 12:46:53 +00:00
|
|
|
spin_lock(&ses->chan_lock);
|
2023-03-29 20:14:21 +00:00
|
|
|
if (!cifs_chan_needs_reconnect(ses, server) &&
|
|
|
|
ses->ses_status == SES_GOOD) {
|
2021-07-19 12:46:53 +00:00
|
|
|
spin_unlock(&ses->chan_lock);
|
2023-03-29 20:14:21 +00:00
|
|
|
spin_unlock(&ses->ses_lock);
|
2021-07-19 13:54:16 +00:00
|
|
|
|
|
|
|
/* this means that we only need to tree connect */
|
2021-07-19 12:46:53 +00:00
|
|
|
if (tcon->need_reconnect)
|
|
|
|
goto skip_sess_setup;
|
|
|
|
|
2023-03-29 20:14:21 +00:00
|
|
|
mutex_unlock(&ses->session_mutex);
|
2021-07-19 12:46:53 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
spin_unlock(&ses->chan_lock);
|
2023-03-29 20:14:21 +00:00
|
|
|
spin_unlock(&ses->ses_lock);
|
2021-07-19 12:46:53 +00:00
|
|
|
|
2021-07-19 13:54:16 +00:00
|
|
|
rc = cifs_negotiate_protocol(0, ses, server);
|
2021-07-19 12:46:53 +00:00
|
|
|
if (!rc)
|
2024-11-26 20:40:11 +00:00
|
|
|
rc = cifs_setup_session(0, ses, server, ses->local_nls);
|
2009-09-03 16:07:17 +00:00
|
|
|
|
|
|
|
/* do we need to reconnect tcon? */
|
|
|
|
if (rc || !tcon->need_reconnect) {
|
2010-02-25 05:36:46 +00:00
|
|
|
mutex_unlock(&ses->session_mutex);
|
2009-09-03 16:07:17 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2021-07-19 12:46:53 +00:00
|
|
|
skip_sess_setup:
|
2011-12-27 12:23:34 +00:00
|
|
|
cifs_mark_open_files_invalid(tcon);
|
2024-11-26 20:40:11 +00:00
|
|
|
rc = cifs_tree_connect(0, tcon);
|
2010-02-25 05:36:46 +00:00
|
|
|
mutex_unlock(&ses->session_mutex);
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
2009-09-03 16:07:17 +00:00
|
|
|
|
2018-04-04 19:08:52 +00:00
|
|
|
if (rc) {
|
2020-04-15 05:42:53 +00:00
|
|
|
pr_warn_once("reconnect tcon failed rc = %d\n", rc);
|
2009-09-03 16:07:17 +00:00
|
|
|
goto out;
|
2018-04-04 19:08:52 +00:00
|
|
|
}
|
2009-09-03 16:07:17 +00:00
|
|
|
|
|
|
|
atomic_inc(&tconInfoReconnectCount);
|
|
|
|
|
|
|
|
/* tell server Unix caps we support */
|
2020-02-24 13:15:00 +00:00
|
|
|
if (cap_unix(ses))
|
2009-09-03 16:07:17 +00:00
|
|
|
reset_cifs_unix_caps(0, tcon, NULL, NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Removed call to reopen open files here. It is safer (and faster) to
|
|
|
|
* reopen files one at a time as needed in read and write.
|
|
|
|
*
|
|
|
|
* FIXME: what about file locks? don't we need to reclaim them ASAP?
|
|
|
|
*/
|
|
|
|
|
|
|
|
out:
|
|
|
|
/*
|
|
|
|
* Check if handle based operation so we know whether we can continue
|
|
|
|
* or not without returning to caller to reset file handle
|
|
|
|
*/
|
|
|
|
switch (smb_command) {
|
|
|
|
case SMB_COM_READ_ANDX:
|
|
|
|
case SMB_COM_WRITE_ANDX:
|
|
|
|
case SMB_COM_CLOSE:
|
|
|
|
case SMB_COM_FIND_CLOSE2:
|
|
|
|
case SMB_COM_LOCKING_ANDX:
|
|
|
|
rc = -EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-02-07 23:25:02 +00:00
|
|
|
/* Allocate and return pointer to an SMB request buffer, and set basic
|
|
|
|
SMB information in the SMB header. If the return code is zero, this
|
|
|
|
function must have filled in request_buf pointer */
|
2005-04-16 22:20:36 +00:00
|
|
|
static int
|
2011-05-27 04:34:02 +00:00
|
|
|
small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
|
2008-02-07 23:25:02 +00:00
|
|
|
void **request_buf)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2010-09-29 19:27:08 +00:00
|
|
|
int rc;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2009-09-03 16:07:17 +00:00
|
|
|
rc = cifs_reconnect_tcon(tcon, smb_command);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (rc)
|
2005-04-16 22:20:36 +00:00
|
|
|
return rc;
|
|
|
|
|
|
|
|
*request_buf = cifs_small_buf_get();
|
|
|
|
if (*request_buf == NULL) {
|
|
|
|
/* BB should we add a retry in here if not a writepage? */
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2007-07-17 17:34:02 +00:00
|
|
|
header_assemble((struct smb_hdr *) *request_buf, smb_command,
|
2007-07-18 23:21:09 +00:00
|
|
|
tcon, wct);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if (tcon != NULL)
|
|
|
|
cifs_stats_inc(&tcon->num_smbs_sent);
|
2005-08-24 20:59:35 +00:00
|
|
|
|
2010-09-29 19:27:08 +00:00
|
|
|
return 0;
|
2006-02-14 01:36:20 +00:00
|
|
|
}
|
|
|
|
|
2006-02-09 21:12:47 +00:00
|
|
|
int
|
2007-07-13 00:33:32 +00:00
|
|
|
small_smb_init_no_tc(const int smb_command, const int wct,
|
2011-05-27 04:34:02 +00:00
|
|
|
struct cifs_ses *ses, void **request_buf)
|
2006-02-09 21:12:47 +00:00
|
|
|
{
|
|
|
|
int rc;
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_hdr *buffer;
|
2006-02-09 21:12:47 +00:00
|
|
|
|
2006-02-14 01:36:20 +00:00
|
|
|
rc = small_smb_init(smb_command, wct, NULL, request_buf);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (rc)
|
2006-02-09 21:12:47 +00:00
|
|
|
return rc;
|
|
|
|
|
2006-02-10 05:52:50 +00:00
|
|
|
buffer = (struct smb_hdr *)*request_buf;
|
2012-05-23 10:01:59 +00:00
|
|
|
buffer->Mid = get_next_mid(ses->server);
|
2006-02-09 21:12:47 +00:00
|
|
|
if (ses->capabilities & CAP_UNICODE)
|
|
|
|
buffer->Flags2 |= SMBFLG2_UNICODE;
|
2006-02-10 05:52:50 +00:00
|
|
|
if (ses->capabilities & CAP_STATUS32)
|
2006-02-09 21:12:47 +00:00
|
|
|
buffer->Flags2 |= SMBFLG2_ERR_STATUS;
|
|
|
|
|
|
|
|
/* uid, tid can stay at zero as set in header assemble */
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/* BB add support for turning on the signing when
|
2006-02-09 21:12:47 +00:00
|
|
|
this function is used after 1st of session setup requests */
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* If the return code is zero, this function must fill in request_buf pointer */
|
|
|
|
static int
|
2011-05-27 04:34:02 +00:00
|
|
|
__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
|
2010-09-29 19:27:08 +00:00
|
|
|
void **request_buf, void **response_buf)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
*request_buf = cifs_buf_get();
|
|
|
|
if (*request_buf == NULL) {
|
|
|
|
/* BB should we add a retry in here if not a writepage? */
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
/* Although the original thought was we needed the response buf for */
|
|
|
|
/* potential retries of smb operations it turns out we can determine */
|
|
|
|
/* from the mid flags when the request buffer can be resent without */
|
|
|
|
/* having to use a second distinct buffer for the response */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (response_buf)
|
2007-07-13 00:33:32 +00:00
|
|
|
*response_buf = *request_buf;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
|
2008-02-07 23:25:02 +00:00
|
|
|
wct);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if (tcon != NULL)
|
|
|
|
cifs_stats_inc(&tcon->num_smbs_sent);
|
2005-08-24 20:59:35 +00:00
|
|
|
|
2010-09-29 19:27:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the return code is zero, this function must fill in request_buf pointer */
|
|
|
|
static int
|
2011-05-27 04:34:02 +00:00
|
|
|
smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
|
2010-09-29 19:27:08 +00:00
|
|
|
void **request_buf, void **response_buf)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = cifs_reconnect_tcon(tcon, smb_command);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-05-27 04:34:02 +00:00
|
|
|
smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
|
2010-09-29 19:27:08 +00:00
|
|
|
void **request_buf, void **response_buf)
|
|
|
|
{
|
2021-07-19 12:46:53 +00:00
|
|
|
spin_lock(&tcon->ses->chan_lock);
|
|
|
|
if (cifs_chan_needs_reconnect(tcon->ses, tcon->ses->server) ||
|
|
|
|
tcon->need_reconnect) {
|
|
|
|
spin_unlock(&tcon->ses->chan_lock);
|
2010-09-29 19:27:08 +00:00
|
|
|
return -EHOSTDOWN;
|
2021-07-19 12:46:53 +00:00
|
|
|
}
|
|
|
|
spin_unlock(&tcon->ses->chan_lock);
|
2010-09-29 19:27:08 +00:00
|
|
|
|
|
|
|
return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
static int validate_t2(struct smb_t2_rsp *pSMB)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2011-01-20 18:36:51 +00:00
|
|
|
unsigned int total_size;
|
|
|
|
|
|
|
|
/* check for plausible wct */
|
|
|
|
if (pSMB->hdr.WordCount < 10)
|
|
|
|
goto vt2_err;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* check for parm and data offset going beyond end of smb */
|
2011-01-20 18:36:51 +00:00
|
|
|
if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
|
|
|
|
get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
|
|
|
|
goto vt2_err;
|
|
|
|
|
|
|
|
total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
|
|
|
|
if (total_size >= 512)
|
|
|
|
goto vt2_err;
|
|
|
|
|
2011-03-31 21:22:07 +00:00
|
|
|
/* check that bcc is at least as big as parms + data, and that it is
|
|
|
|
* less than negotiated smb buffer
|
|
|
|
*/
|
2011-01-20 18:36:51 +00:00
|
|
|
total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
|
|
|
|
if (total_size > get_bcc(&pSMB->hdr) ||
|
|
|
|
total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
|
|
|
|
goto vt2_err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
vt2_err:
|
2007-07-13 00:33:32 +00:00
|
|
|
cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
|
2005-04-16 22:20:36 +00:00
|
|
|
sizeof(struct smb_t2_rsp) + 16);
|
2011-01-20 18:36:51 +00:00
|
|
|
return -EINVAL;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2011-01-20 18:36:51 +00:00
|
|
|
|
2013-05-26 11:00:57 +00:00
|
|
|
static int
|
2013-06-13 00:52:14 +00:00
|
|
|
decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
|
2013-05-26 11:00:57 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
u16 count;
|
|
|
|
char *guid = pSMBr->u.extended_response.GUID;
|
2013-06-13 00:52:14 +00:00
|
|
|
struct TCP_Server_Info *server = ses->server;
|
2013-05-26 11:00:57 +00:00
|
|
|
|
|
|
|
count = get_bcc(&pSMBr->hdr);
|
|
|
|
if (count < SMB1_CLIENT_GUID_SIZE)
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
spin_lock(&cifs_tcp_ses_lock);
|
|
|
|
if (server->srv_count > 1) {
|
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
|
|
|
if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
|
|
|
|
cifs_dbg(FYI, "server UID changed\n");
|
|
|
|
memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
|
|
|
memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count == SMB1_CLIENT_GUID_SIZE) {
|
2013-06-13 00:52:14 +00:00
|
|
|
server->sec_ntlmssp = true;
|
2013-05-26 11:00:57 +00:00
|
|
|
} else {
|
|
|
|
count -= SMB1_CLIENT_GUID_SIZE;
|
|
|
|
rc = decode_negTokenInit(
|
|
|
|
pSMBr->u.extended_response.SecurityBlob, count, server);
|
|
|
|
if (rc != 1)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-26 11:00:58 +00:00
|
|
|
static bool
|
2013-06-13 00:52:14 +00:00
|
|
|
should_set_ext_sec_flag(enum securityEnum sectype)
|
2013-05-26 11:00:58 +00:00
|
|
|
{
|
2013-06-13 00:52:14 +00:00
|
|
|
switch (sectype) {
|
|
|
|
case RawNTLMSSP:
|
|
|
|
case Kerberos:
|
2013-05-26 11:00:58 +00:00
|
|
|
return true;
|
2013-06-13 00:52:14 +00:00
|
|
|
case Unspecified:
|
|
|
|
if (global_secflags &
|
|
|
|
(CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
|
|
|
|
return true;
|
2020-08-23 22:36:59 +00:00
|
|
|
fallthrough;
|
2013-06-13 00:52:14 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2013-05-26 11:00:58 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2021-07-19 13:54:16 +00:00
|
|
|
CIFSSMBNegotiate(const unsigned int xid,
|
|
|
|
struct cifs_ses *ses,
|
|
|
|
struct TCP_Server_Info *server)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
NEGOTIATE_REQ *pSMB;
|
|
|
|
NEGOTIATE_RSP *pSMBr;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
2006-05-31 22:40:51 +00:00
|
|
|
int i;
|
2005-04-16 22:20:36 +00:00
|
|
|
u16 count;
|
|
|
|
|
2013-05-24 11:41:01 +00:00
|
|
|
if (!server) {
|
|
|
|
WARN(1, "%s: server is NULL!\n", __func__);
|
|
|
|
return -EIO;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2013-05-24 11:41:01 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
|
|
|
|
(void **) &pSMB, (void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
2006-06-27 06:28:30 +00:00
|
|
|
|
2012-05-23 10:01:59 +00:00
|
|
|
pSMB->hdr.Mid = get_next_mid(server);
|
2007-06-05 21:31:16 +00:00
|
|
|
pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
|
2007-10-04 20:05:09 +00:00
|
|
|
|
2013-06-13 00:52:14 +00:00
|
|
|
if (should_set_ext_sec_flag(ses->sectype)) {
|
2020-04-15 05:42:53 +00:00
|
|
|
cifs_dbg(FYI, "Requesting extended security\n");
|
2009-05-06 04:16:04 +00:00
|
|
|
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
|
|
|
}
|
2007-07-13 00:33:32 +00:00
|
|
|
|
2006-05-31 22:40:51 +00:00
|
|
|
count = 0;
|
2018-09-03 03:15:58 +00:00
|
|
|
/*
|
|
|
|
* We know that all the name entries in the protocols array
|
|
|
|
* are short (< 16 bytes anyway) and are NUL terminated.
|
|
|
|
*/
|
2007-07-13 00:33:32 +00:00
|
|
|
for (i = 0; i < CIFS_NUM_PROT; i++) {
|
2018-09-03 03:15:58 +00:00
|
|
|
size_t len = strlen(protocols[i].name) + 1;
|
|
|
|
|
2022-10-05 01:51:39 +00:00
|
|
|
memcpy(&pSMB->DialectsArray[count], protocols[i].name, len);
|
2018-09-03 03:15:58 +00:00
|
|
|
count += len;
|
2006-05-31 22:40:51 +00:00
|
|
|
}
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2007-07-13 00:33:32 +00:00
|
|
|
if (rc != 0)
|
2006-06-04 05:53:15 +00:00
|
|
|
goto neg_err_exit;
|
|
|
|
|
2010-04-24 11:57:46 +00:00
|
|
|
server->dialect = le16_to_cpu(pSMBr->DialectIndex);
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
|
2006-06-04 05:53:15 +00:00
|
|
|
/* Check wct = 1 error case */
|
2021-08-19 10:34:58 +00:00
|
|
|
if ((pSMBr->hdr.WordCount <= 13) || (server->dialect == BAD_PROT)) {
|
2006-06-04 05:53:15 +00:00
|
|
|
/* core returns wct = 1, but we do not ask for core - otherwise
|
2007-07-13 00:33:32 +00:00
|
|
|
small wct just comes when dialect index is -1 indicating we
|
2006-06-04 05:53:15 +00:00
|
|
|
could not negotiate a common dialect */
|
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
goto neg_err_exit;
|
2007-07-07 19:25:05 +00:00
|
|
|
} else if (pSMBr->hdr.WordCount != 17) {
|
2006-06-04 05:53:15 +00:00
|
|
|
/* unknown wct */
|
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
goto neg_err_exit;
|
|
|
|
}
|
2013-05-26 11:00:57 +00:00
|
|
|
/* else wct == 17, NTLM or better */
|
|
|
|
|
2011-05-27 04:34:02 +00:00
|
|
|
server->sec_mode = pSMBr->SecurityMode;
|
|
|
|
if ((server->sec_mode & SECMODE_USER) == 0)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "share mode security\n");
|
2006-06-02 22:57:13 +00:00
|
|
|
|
2006-06-04 05:53:15 +00:00
|
|
|
/* one byte, so no need to convert this or EncryptionKeyLen from
|
|
|
|
little endian */
|
2012-03-20 09:55:09 +00:00
|
|
|
server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
|
|
|
|
cifs_max_pending);
|
2012-05-17 13:53:29 +00:00
|
|
|
set_credits(server, server->maxReq);
|
2006-06-04 05:53:15 +00:00
|
|
|
/* probably no need to store and check maxvcs */
|
2011-10-11 10:41:32 +00:00
|
|
|
server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
|
2022-03-24 01:29:04 +00:00
|
|
|
/* set up max_read for readahead check */
|
cifs: improve read performance for page size 64KB & cache=strict & vers=2.1+
Found a read performance issue when linux kernel page size is 64KB.
If linux kernel page size is 64KB and mount options cache=strict &
vers=2.1+, it does not support cifs_readpages(). Instead, it is using
cifs_readpage() and cifs_read() with maximum read IO size 16KB, which is
much slower than read IO size 1MB when negotiated SMB 2.1+. Since modern
SMB server supported SMB 2.1+ and Max Read Size can reach more than 64KB
(for example 1MB ~ 8MB), this patch check max_read instead of maxBuf to
determine whether server support readpages() and improve read performance
for page size 64KB & cache=strict & vers=2.1+, and for SMB1 it is more
cleaner to initialize server->max_read to server->maxBuf.
The client is a linux box with linux kernel 4.2.8,
page size 64KB (CONFIG_ARM64_64K_PAGES=y),
cpu arm 1.7GHz, and use mount.cifs as smb client.
The server is another linux box with linux kernel 4.2.8,
share a file '10G.img' with size 10GB,
and use samba-4.7.12 as smb server.
The client mount a share from the server with different
cache options: cache=strict and cache=none,
mount -tcifs //<server_ip>/Public /cache_strict -overs=3.0,cache=strict,username=<xxx>,password=<yyy>
mount -tcifs //<server_ip>/Public /cache_none -overs=3.0,cache=none,username=<xxx>,password=<yyy>
The client download a 10GbE file from the server across 1GbE network,
dd if=/cache_strict/10G.img of=/dev/null bs=1M count=10240
dd if=/cache_none/10G.img of=/dev/null bs=1M count=10240
Found that cache=strict (without patch) is slower read throughput and
smaller read IO size than cache=none.
cache=strict (without patch): read throughput 40MB/s, read IO size is 16KB
cache=strict (with patch): read throughput 113MB/s, read IO size is 1MB
cache=none: read throughput 109MB/s, read IO size is 1MB
Looks like if page size is 64KB,
cifs_set_ops() would use cifs_addr_ops_smallbuf instead of cifs_addr_ops,
/* check if server can support readpages */
if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
PAGE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
inode->i_data.a_ops = &cifs_addr_ops;
maxBuf is came from 2 places, SMB2_negotiate() and CIFSSMBNegotiate(),
(SMB2_MAX_BUFFER_SIZE is 64KB)
SMB2_negotiate():
/* set it to the maximum buffer size value we can send with 1 credit */
server->maxBuf = min_t(unsigned int, le32_to_cpu(rsp->MaxTransactSize),
SMB2_MAX_BUFFER_SIZE);
CIFSSMBNegotiate():
server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Page size 64KB and cache=strict lead to read_pages() use cifs_readpage()
instead of cifs_readpages(), and then cifs_read() using maximum read IO
size 16KB, which is much slower than maximum read IO size 1MB.
(CIFSMaxBufSize is 16KB by default)
/* FIXME: set up handlers for larger reads and/or convert to async */
rsize = min_t(unsigned int, cifs_sb->rsize, CIFSMaxBufSize);
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Jones Syue <jonessyue@qnap.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
2020-04-13 01:37:23 +00:00
|
|
|
server->max_read = server->maxBuf;
|
[CIFS] Fix multiuser mounts so server does not invalidate earlier security contexts
When two different users mount the same Windows 2003 Server share using CIFS,
the first session mounted can be invalidated. Some servers invalidate the first
smb session when a second similar user (e.g. two users who get mapped by server to "guest")
authenticates an smb session from the same client.
By making sure that we set the 2nd and subsequent vc numbers to nonzero values,
this ensures that we will not have this problem.
Fixes Samba bug 6004, problem description follows:
How to reproduce:
- configure an "open share" (full permissions to Guest user) on Windows 2003
Server (I couldn't reproduce the problem with Samba server or Windows older
than 2003)
- mount the share twice with different users who will be authenticated as guest.
noacl,noperm,user=john,dir_mode=0700,domain=DOMAIN,rw
noacl,noperm,user=jeff,dir_mode=0700,domain=DOMAIN,rw
Result:
- just the mount point mounted last is accessible:
Signed-off-by: Steve French <sfrench@us.ibm.com>
2009-02-20 05:43:09 +00:00
|
|
|
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
|
2006-06-04 05:53:15 +00:00
|
|
|
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
|
2006-10-02 05:53:29 +00:00
|
|
|
server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
|
|
|
|
server->timeAdj *= 60;
|
2013-05-26 11:00:57 +00:00
|
|
|
|
2013-05-26 11:00:59 +00:00
|
|
|
if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
|
|
|
|
server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
|
2010-10-27 20:20:36 +00:00
|
|
|
memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
|
2006-06-04 05:53:15 +00:00
|
|
|
CIFS_CRYPTO_KEY_SIZE);
|
2015-05-27 08:22:10 +00:00
|
|
|
} else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
|
|
|
|
server->capabilities & CAP_EXTENDED_SECURITY) {
|
2013-05-26 11:00:59 +00:00
|
|
|
server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
|
2013-06-13 00:52:14 +00:00
|
|
|
rc = decode_ext_sec_blob(ses, pSMBr);
|
2013-05-26 11:00:59 +00:00
|
|
|
} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
|
2011-05-27 04:12:29 +00:00
|
|
|
rc = -EIO; /* no crypt key only if plain text pwd */
|
2013-05-26 11:00:59 +00:00
|
|
|
} else {
|
|
|
|
server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
|
2006-06-04 05:53:15 +00:00
|
|
|
server->capabilities &= ~CAP_EXTENDED_SECURITY;
|
2013-05-26 11:00:59 +00:00
|
|
|
}
|
2006-06-04 05:53:15 +00:00
|
|
|
|
2013-05-26 11:00:58 +00:00
|
|
|
if (!rc)
|
2013-05-26 11:01:00 +00:00
|
|
|
rc = cifs_enable_signing(server, ses->sign);
|
2007-07-13 00:33:32 +00:00
|
|
|
neg_err_exit:
|
2005-08-13 15:15:54 +00:00
|
|
|
cifs_buf_release(pSMB);
|
2006-06-04 05:53:15 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "negprot rc %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-05-25 07:11:39 +00:00
|
|
|
CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct smb_hdr *smb_buffer;
|
|
|
|
int rc = 0;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In tree disconnect\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-11-15 16:12:47 +00:00
|
|
|
/* BB: do we need to check this? These should never be NULL. */
|
|
|
|
if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
|
|
|
|
return -EIO;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-11-15 16:12:47 +00:00
|
|
|
/*
|
|
|
|
* No need to return error on this operation if tid invalidated and
|
|
|
|
* closed on server already e.g. due to tcp session crashing. Also,
|
|
|
|
* the tcon is no longer on the list, so no need to take lock before
|
|
|
|
* checking this.
|
|
|
|
*/
|
2021-07-19 12:46:53 +00:00
|
|
|
spin_lock(&tcon->ses->chan_lock);
|
|
|
|
if ((tcon->need_reconnect) || CIFS_ALL_CHANS_NEED_RECONNECT(tcon->ses)) {
|
|
|
|
spin_unlock(&tcon->ses->chan_lock);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
spin_unlock(&tcon->ses->chan_lock);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
|
2005-04-29 05:41:08 +00:00
|
|
|
(void **)&smb_buffer);
|
2008-11-15 16:12:47 +00:00
|
|
|
if (rc)
|
2005-04-16 22:20:36 +00:00
|
|
|
return rc;
|
2007-11-13 22:41:37 +00:00
|
|
|
|
2012-03-23 18:28:02 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(smb_buffer);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/* No need to return error on this operation if tid invalidated and
|
2008-11-15 16:12:47 +00:00
|
|
|
closed on server already e.g. due to tcp session crashing */
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc == -EAGAIN)
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-01-11 12:24:21 +00:00
|
|
|
/*
|
|
|
|
* This is a no-op for now. We're not really interested in the reply, but
|
|
|
|
* rather in the fact that the server sent one and that server->lstrp
|
|
|
|
* gets updated.
|
|
|
|
*
|
|
|
|
* FIXME: maybe we should consider checking that the reply matches request?
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
cifs_echo_callback(struct mid_q_entry *mid)
|
|
|
|
{
|
|
|
|
struct TCP_Server_Info *server = mid->callback_data;
|
2019-01-16 19:22:29 +00:00
|
|
|
struct cifs_credits credits = { .value = 1, .instance = 0 };
|
2011-01-11 12:24:21 +00:00
|
|
|
|
2022-08-05 14:47:38 +00:00
|
|
|
release_mid(mid);
|
2019-01-16 19:22:29 +00:00
|
|
|
add_credits(server, &credits, CIFS_ECHO_OP);
|
2011-01-11 12:24:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
CIFSSMBEcho(struct TCP_Server_Info *server)
|
|
|
|
{
|
|
|
|
ECHO_REQ *smb;
|
|
|
|
int rc = 0;
|
2016-11-23 23:14:57 +00:00
|
|
|
struct kvec iov[2];
|
|
|
|
struct smb_rqst rqst = { .rq_iov = iov,
|
|
|
|
.rq_nvec = 2 };
|
2011-01-11 12:24:21 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In echo request\n");
|
2011-01-11 12:24:21 +00:00
|
|
|
|
|
|
|
rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2017-05-02 18:35:20 +00:00
|
|
|
if (server->capabilities & CAP_UNICODE)
|
|
|
|
smb->hdr.Flags2 |= SMBFLG2_UNICODE;
|
|
|
|
|
2011-01-11 12:24:21 +00:00
|
|
|
/* set up echo request */
|
2011-03-13 05:08:25 +00:00
|
|
|
smb->hdr.Tid = 0xffff;
|
2011-01-21 02:19:25 +00:00
|
|
|
smb->hdr.WordCount = 1;
|
|
|
|
put_unaligned_le16(1, &smb->EchoCount);
|
2011-05-04 12:05:26 +00:00
|
|
|
put_bcc(1, &smb->hdr);
|
2011-01-11 12:24:21 +00:00
|
|
|
smb->Data[0] = 'a';
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(smb, 3);
|
2016-11-23 23:14:57 +00:00
|
|
|
|
|
|
|
iov[0].iov_len = 4;
|
|
|
|
iov[0].iov_base = smb;
|
|
|
|
iov[1].iov_len = get_rfc1002_length(smb);
|
|
|
|
iov[1].iov_base = (char *)smb + 4;
|
2011-01-11 12:24:21 +00:00
|
|
|
|
2016-11-16 22:06:17 +00:00
|
|
|
rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
|
2019-05-06 00:00:02 +00:00
|
|
|
server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
|
2011-01-11 12:24:21 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Echo request failed: %d\n", rc);
|
2011-01-11 12:24:21 +00:00
|
|
|
|
|
|
|
cifs_small_buf_release(smb);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-05-25 06:54:49 +00:00
|
|
|
CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
LOGOFF_ANDX_REQ *pSMB;
|
|
|
|
int rc = 0;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
|
2008-11-13 19:45:32 +00:00
|
|
|
|
2008-11-14 18:53:46 +00:00
|
|
|
/*
|
|
|
|
* BB: do we need to check validity of ses and server? They should
|
|
|
|
* always be valid since we have an active reference. If not, that
|
|
|
|
* should probably be a BUG()
|
|
|
|
*/
|
|
|
|
if (!ses || !ses->server)
|
2008-11-13 19:45:32 +00:00
|
|
|
return -EIO;
|
|
|
|
|
2010-02-25 05:36:46 +00:00
|
|
|
mutex_lock(&ses->session_mutex);
|
2021-07-19 12:46:53 +00:00
|
|
|
spin_lock(&ses->chan_lock);
|
|
|
|
if (CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
|
|
|
|
spin_unlock(&ses->chan_lock);
|
2008-11-13 19:45:32 +00:00
|
|
|
goto session_already_dead; /* no need to send SMBlogoff if uid
|
|
|
|
already closed due to reconnect */
|
2021-07-19 12:46:53 +00:00
|
|
|
}
|
|
|
|
spin_unlock(&ses->chan_lock);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
|
|
|
|
if (rc) {
|
2010-02-25 05:36:46 +00:00
|
|
|
mutex_unlock(&ses->session_mutex);
|
2005-04-16 22:20:36 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-05-23 10:01:59 +00:00
|
|
|
pSMB->hdr.Mid = get_next_mid(ses->server);
|
2005-08-17 19:38:22 +00:00
|
|
|
|
2013-05-26 11:01:00 +00:00
|
|
|
if (ses->server->sign)
|
|
|
|
pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
pSMB->hdr.Uid = ses->Suid;
|
|
|
|
|
|
|
|
pSMB->AndXCommand = 0xFF;
|
2012-03-23 18:28:02 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2008-11-13 19:45:32 +00:00
|
|
|
session_already_dead:
|
2010-02-25 05:36:46 +00:00
|
|
|
mutex_unlock(&ses->session_mutex);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* if session dead then we do not need to do ulogoff,
|
2007-07-13 00:33:32 +00:00
|
|
|
since server closed smb session, no sense reporting
|
2005-04-16 22:20:36 +00:00
|
|
|
error */
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
rc = 0;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-07-15 01:48:57 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *fileName, __u16 type,
|
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2007-07-15 01:48:57 +00:00
|
|
|
{
|
|
|
|
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
|
|
|
struct unlink_psx_rq *pRqD;
|
|
|
|
int name_len;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, param_offset, offset, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In POSIX delete\n");
|
2007-07-15 01:48:57 +00:00
|
|
|
PsxDelete:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2007-07-15 01:48:57 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, fileName);
|
2007-07-15 01:48:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
params = 6 + name_len;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
pSMB->MaxDataCount = 0; /* BB double check this with jra */
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
|
|
|
InformationLevel) - 4;
|
|
|
|
offset = param_offset + params;
|
|
|
|
|
2021-07-22 19:35:15 +00:00
|
|
|
/* Setup pointer to Request Data (inode type).
|
|
|
|
* Note that SMB offsets are from the beginning of SMB which is 4 bytes
|
|
|
|
* in, after RFC1001 field
|
|
|
|
*/
|
|
|
|
pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset + 4);
|
2007-07-15 01:48:57 +00:00
|
|
|
pRqD->type = cpu_to_le16(type);
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
|
|
|
|
|
|
|
|
pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
|
|
|
|
pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2007-07-15 01:48:57 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Posix delete returned %d\n", rc);
|
2007-07-15 01:48:57 +00:00
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
|
2007-07-15 01:48:57 +00:00
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto PsxDelete;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-09-18 23:20:25 +00:00
|
|
|
CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
smb: client: reuse file lease key in compound operations
Currently, when a rename, unlink or set path size compound operation
is requested on a file that has a lot of dirty pages to be written
to the server, we do not send the lease key for these requests. As a
result, the server can assume that this request is from a new client, and
send a lease break notification to the same client, on the same
connection. As a response to the lease break, the client can consume
several credits to write the dirty pages to the server. Depending on the
server's credit grant implementation, the server can stop granting more
credits to this connection, and this can cause a deadlock (which can only
be resolved when the lease timer on the server expires).
One of the problems here is that the client is sending no lease key,
even if it has a lease for the file. This patch fixes the problem by
reusing the existing lease key on the file for rename, unlink and set path
size compound operations so that the client does not break its own lease.
A very trivial example could be a set of commands by a client that
maintains open handle (for write) to a file and then tries to copy the
contents of that file to another one, eg.,
tail -f /dev/null > myfile &
mv myfile myfile2
Presently, the network capture on the client shows that the move (or
rename) would trigger a lease break on the same client, for the same file.
With the lease key reused, the lease break request-response overhead is
eliminated, thereby reducing the roundtrips performed for this set of
operations.
The patch fixes the bug described above and also provides perf benefit.
Signed-off-by: Meetakshi Setiya <msetiya@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
2024-03-06 03:43:51 +00:00
|
|
|
struct cifs_sb_info *cifs_sb, struct dentry *dentry)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
DELETE_FILE_REQ *pSMB = NULL;
|
|
|
|
DELETE_FILE_RSP *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
2014-09-27 07:19:01 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
DelFileRetry:
|
|
|
|
rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
2012-09-18 23:20:25 +00:00
|
|
|
name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
|
|
|
|
PATH_MAX, cifs_sb->local_nls,
|
|
|
|
remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->fileName, name);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
pSMB->SearchAttributes =
|
|
|
|
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
|
|
|
|
pSMB->BufferFormat = 0x04;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, name_len + 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(name_len + 1);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto DelFileRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-07-10 12:14:18 +00:00
|
|
|
CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
DELETE_DIRECTORY_REQ *pSMB = NULL;
|
|
|
|
DELETE_DIRECTORY_RSP *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
2014-09-27 07:19:01 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In CIFSSMBRmDir\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
RmDirRetry:
|
|
|
|
rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
2012-07-10 12:14:18 +00:00
|
|
|
name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
|
|
|
|
PATH_MAX, cifs_sb->local_nls,
|
|
|
|
remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->DirName, name);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pSMB->BufferFormat = 0x04;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, name_len + 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(name_len + 1);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto RmDirRetry;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-09-25 05:32:13 +00:00
|
|
|
CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
|
|
|
|
struct cifs_tcon *tcon, const char *name,
|
2012-03-17 08:41:12 +00:00
|
|
|
struct cifs_sb_info *cifs_sb)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
CREATE_DIRECTORY_REQ *pSMB = NULL;
|
|
|
|
CREATE_DIRECTORY_RSP *pSMBr = NULL;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
2014-09-27 07:19:01 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In CIFSSMBMkDir\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
MkDirRetry:
|
|
|
|
rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
2012-01-19 04:32:33 +00:00
|
|
|
name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
|
2012-03-17 08:41:12 +00:00
|
|
|
PATH_MAX, cifs_sb->local_nls,
|
|
|
|
remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->DirName, name);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pSMB->BufferFormat = 0x04;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, name_len + 1);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(name_len + 1);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
|
2005-08-21 04:42:53 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto MkDirRetry;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-04-23 22:07:35 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
__u32 posix_flags, __u64 mode, __u16 *netfid,
|
|
|
|
FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
|
|
|
|
const char *name, const struct nls_table *nls_codepage,
|
|
|
|
int remap)
|
2007-04-23 22:07:35 +00:00
|
|
|
{
|
|
|
|
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
|
|
|
int name_len;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, param_offset, offset, byte_count, count;
|
2008-02-07 23:25:02 +00:00
|
|
|
OPEN_PSX_REQ *pdata;
|
|
|
|
OPEN_PSX_RSP *psx_rsp;
|
2007-04-23 22:07:35 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In POSIX Create\n");
|
2007-04-23 22:07:35 +00:00
|
|
|
PsxCreat:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2007-04-23 22:07:35 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, name);
|
2007-04-23 22:07:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
params = 6 + name_len;
|
|
|
|
count = sizeof(OPEN_PSX_REQ);
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
2007-07-13 00:33:32 +00:00
|
|
|
InformationLevel) - 4;
|
2007-04-23 22:07:35 +00:00
|
|
|
offset = param_offset + params;
|
2021-07-22 18:50:41 +00:00
|
|
|
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
|
|
|
|
pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset + 4);
|
2007-10-14 17:58:43 +00:00
|
|
|
pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
|
2007-04-23 22:07:35 +00:00
|
|
|
pdata->Permissions = cpu_to_le64(mode);
|
2007-07-13 00:33:32 +00:00
|
|
|
pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
|
2007-04-23 22:07:35 +00:00
|
|
|
pdata->OpenFlags = cpu_to_le32(*pOplock);
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + count;
|
|
|
|
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2007-04-23 22:07:35 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Posix create returned %d\n", rc);
|
2007-04-23 22:07:35 +00:00
|
|
|
goto psx_create_err;
|
|
|
|
}
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "copying inode info\n");
|
2007-04-23 22:07:35 +00:00
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
|
2007-04-23 22:07:35 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
goto psx_create_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy return information to pRetData */
|
2007-07-13 00:33:32 +00:00
|
|
|
psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
|
2007-04-23 22:07:35 +00:00
|
|
|
+ le16_to_cpu(pSMBr->t2.DataOffset));
|
2007-07-13 00:33:32 +00:00
|
|
|
|
2007-04-23 22:07:35 +00:00
|
|
|
*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (netfid)
|
2007-04-23 22:07:35 +00:00
|
|
|
*netfid = psx_rsp->Fid; /* cifs fid stays in le */
|
|
|
|
/* Let caller know file was created so we can set the mode. */
|
|
|
|
/* Do we care about the CreateAction in any other cases? */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
|
2007-04-23 22:07:35 +00:00
|
|
|
*pOplock |= CIFS_CREATE_ACTION;
|
|
|
|
/* check to make sure response data is there */
|
2007-10-14 17:58:43 +00:00
|
|
|
if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
|
|
|
|
pRetData->Type = cpu_to_le32(-1); /* unknown */
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(NOISY, "unknown type\n");
|
2007-04-25 11:46:06 +00:00
|
|
|
} else {
|
2011-05-04 12:05:26 +00:00
|
|
|
if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
|
2007-04-23 22:07:35 +00:00
|
|
|
+ sizeof(FILE_UNIX_BASIC_INFO)) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Open response data too small\n");
|
2007-10-14 17:58:43 +00:00
|
|
|
pRetData->Type = cpu_to_le32(-1);
|
2007-04-23 22:07:35 +00:00
|
|
|
goto psx_create_err;
|
|
|
|
}
|
2007-07-13 00:33:32 +00:00
|
|
|
memcpy((char *) pRetData,
|
2007-04-25 11:46:06 +00:00
|
|
|
(char *)psx_rsp + sizeof(OPEN_PSX_RSP),
|
2007-08-30 22:09:15 +00:00
|
|
|
sizeof(FILE_UNIX_BASIC_INFO));
|
2007-04-23 22:07:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
psx_create_err:
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
2009-07-10 15:27:25 +00:00
|
|
|
if (posix_flags & SMB_O_DIRECTORY)
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
|
2009-07-10 15:27:25 +00:00
|
|
|
else
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
|
2007-04-23 22:07:35 +00:00
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto PsxCreat;
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
return rc;
|
2007-04-23 22:07:35 +00:00
|
|
|
}
|
|
|
|
|
2005-08-25 06:06:05 +00:00
|
|
|
static __u16 convert_disposition(int disposition)
|
|
|
|
{
|
|
|
|
__u16 ofun = 0;
|
|
|
|
|
|
|
|
switch (disposition) {
|
|
|
|
case FILE_SUPERSEDE:
|
|
|
|
ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
|
|
|
|
break;
|
|
|
|
case FILE_OPEN:
|
|
|
|
ofun = SMBOPEN_OAPPEND;
|
|
|
|
break;
|
|
|
|
case FILE_CREATE:
|
|
|
|
ofun = SMBOPEN_OCREATE;
|
|
|
|
break;
|
|
|
|
case FILE_OPEN_IF:
|
|
|
|
ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
|
|
|
|
break;
|
|
|
|
case FILE_OVERWRITE:
|
|
|
|
ofun = SMBOPEN_OTRUNC;
|
|
|
|
break;
|
|
|
|
case FILE_OVERWRITE_IF:
|
|
|
|
ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
|
|
|
|
break;
|
|
|
|
default:
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "unknown disposition %d\n", disposition);
|
2005-08-25 06:06:05 +00:00
|
|
|
ofun = SMBOPEN_OAPPEND; /* regular open */
|
|
|
|
}
|
|
|
|
return ofun;
|
|
|
|
}
|
|
|
|
|
2008-05-14 17:22:03 +00:00
|
|
|
static int
|
|
|
|
access_flags_to_smbopen_mode(const int access_flags)
|
|
|
|
{
|
|
|
|
int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
|
|
|
|
|
|
|
|
if (masked_flags == GENERIC_READ)
|
|
|
|
return SMBOPEN_READ;
|
|
|
|
else if (masked_flags == GENERIC_WRITE)
|
|
|
|
return SMBOPEN_WRITE;
|
|
|
|
|
|
|
|
/* just go for read/write */
|
|
|
|
return SMBOPEN_READWRITE;
|
|
|
|
}
|
|
|
|
|
2005-08-25 06:06:05 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
|
2005-08-25 06:06:05 +00:00
|
|
|
const char *fileName, const int openDisposition,
|
2008-02-07 23:25:02 +00:00
|
|
|
const int access_flags, const int create_options, __u16 *netfid,
|
|
|
|
int *pOplock, FILE_ALL_INFO *pfile_info,
|
2005-08-25 06:06:05 +00:00
|
|
|
const struct nls_table *nls_codepage, int remap)
|
|
|
|
{
|
2021-06-13 14:01:23 +00:00
|
|
|
int rc;
|
2005-08-25 06:06:05 +00:00
|
|
|
OPENX_REQ *pSMB = NULL;
|
|
|
|
OPENX_RSP *pSMBr = NULL;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
|
|
|
__u16 count;
|
|
|
|
|
|
|
|
OldOpenRetry:
|
|
|
|
rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->AndXCommand = 0xFF; /* none */
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
count = 1; /* account for one byte pad to word boundary */
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
|
|
|
|
fileName, PATH_MAX, nls_codepage, remap);
|
2005-08-25 06:06:05 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
2005-08-25 06:06:05 +00:00
|
|
|
count = 0; /* no pad */
|
2019-08-26 23:30:14 +00:00
|
|
|
name_len = copy_path_name(pSMB->fileName, fileName);
|
2005-08-25 06:06:05 +00:00
|
|
|
}
|
|
|
|
if (*pOplock & REQ_OPLOCK)
|
|
|
|
pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
|
2007-08-30 22:09:15 +00:00
|
|
|
else if (*pOplock & REQ_BATCHOPLOCK)
|
2005-08-25 06:06:05 +00:00
|
|
|
pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
|
2007-08-30 22:09:15 +00:00
|
|
|
|
2005-08-25 06:06:05 +00:00
|
|
|
pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
|
2008-05-14 17:22:03 +00:00
|
|
|
pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
|
2005-08-25 06:06:05 +00:00
|
|
|
pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
|
2024-09-15 19:45:45 +00:00
|
|
|
/* set file as system file if special file such as fifo,
|
|
|
|
* socket, char or block and server expecting SFU style and
|
2005-08-25 06:06:05 +00:00
|
|
|
no Unix extensions */
|
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if (create_options & CREATE_OPTION_SPECIAL)
|
|
|
|
pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
|
2008-02-07 23:25:02 +00:00
|
|
|
else /* BB FIXME BB */
|
|
|
|
pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
|
2005-08-25 06:06:05 +00:00
|
|
|
|
2008-05-09 22:28:02 +00:00
|
|
|
if (create_options & CREATE_OPTION_READONLY)
|
|
|
|
pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
|
2005-08-25 06:06:05 +00:00
|
|
|
|
|
|
|
/* BB FIXME BB */
|
2007-07-13 00:33:32 +00:00
|
|
|
/* pSMB->CreateOptions = cpu_to_le32(create_options &
|
|
|
|
CREATE_OPTIONS_MASK); */
|
2005-08-25 06:06:05 +00:00
|
|
|
/* BB FIXME END BB */
|
2005-09-19 03:49:21 +00:00
|
|
|
|
|
|
|
pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
|
2005-09-22 23:32:06 +00:00
|
|
|
pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
|
2005-08-25 06:06:05 +00:00
|
|
|
count += name_len;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, count);
|
2005-08-25 06:06:05 +00:00
|
|
|
|
|
|
|
pSMB->ByteCount = cpu_to_le16(count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
2011-01-11 12:24:23 +00:00
|
|
|
(struct smb_hdr *)pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
|
2005-08-25 06:06:05 +00:00
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Error in Open = %d\n", rc);
|
2005-08-25 06:06:05 +00:00
|
|
|
} else {
|
|
|
|
/* BB verify if wct == 15 */
|
|
|
|
|
2008-05-13 04:54:12 +00:00
|
|
|
/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
|
2005-08-25 06:06:05 +00:00
|
|
|
|
|
|
|
*netfid = pSMBr->Fid; /* cifs fid stays in le */
|
|
|
|
/* Let caller know file was created so we can set the mode. */
|
|
|
|
/* Do we care about the CreateAction in any other cases? */
|
|
|
|
/* BB FIXME BB */
|
2007-07-07 19:25:05 +00:00
|
|
|
/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
|
2005-08-25 06:06:05 +00:00
|
|
|
*pOplock |= CIFS_CREATE_ACTION; */
|
|
|
|
/* BB FIXME END */
|
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if (pfile_info) {
|
2005-08-25 06:06:05 +00:00
|
|
|
pfile_info->CreationTime = 0; /* BB convert CreateTime*/
|
|
|
|
pfile_info->LastAccessTime = 0; /* BB fixme */
|
|
|
|
pfile_info->LastWriteTime = 0; /* BB fixme */
|
|
|
|
pfile_info->ChangeTime = 0; /* BB fixme */
|
2005-09-22 23:32:06 +00:00
|
|
|
pfile_info->Attributes =
|
2007-07-13 00:33:32 +00:00
|
|
|
cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
|
2005-08-25 06:06:05 +00:00
|
|
|
/* the file_info buf is endian converted by caller */
|
2005-09-22 23:32:06 +00:00
|
|
|
pfile_info->AllocationSize =
|
|
|
|
cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
|
|
|
|
pfile_info->EndOfFile = pfile_info->AllocationSize;
|
2005-08-25 06:06:05 +00:00
|
|
|
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
2008-10-18 01:03:20 +00:00
|
|
|
pfile_info->DeletePending = 0;
|
2005-08-25 06:06:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto OldOpenRetry;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2014-01-16 11:53:36 +00:00
|
|
|
CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
|
|
|
|
FILE_ALL_INFO *buf)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2019-07-23 15:09:19 +00:00
|
|
|
int rc;
|
2014-01-16 11:53:33 +00:00
|
|
|
OPEN_REQ *req = NULL;
|
|
|
|
OPEN_RSP *rsp = NULL;
|
2005-04-16 22:20:36 +00:00
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
|
|
|
__u16 count;
|
2014-01-16 11:53:36 +00:00
|
|
|
struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
|
|
|
|
struct cifs_tcon *tcon = oparms->tcon;
|
2014-09-27 07:19:01 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
2014-01-16 11:53:36 +00:00
|
|
|
const struct nls_table *nls = cifs_sb->local_nls;
|
|
|
|
int create_options = oparms->create_options;
|
|
|
|
int desired_access = oparms->desired_access;
|
|
|
|
int disposition = oparms->disposition;
|
|
|
|
const char *path = oparms->path;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
openRetry:
|
2014-01-16 11:53:33 +00:00
|
|
|
rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
|
|
|
|
(void **)&rsp);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2014-01-16 11:53:33 +00:00
|
|
|
/* no commands go after this */
|
|
|
|
req->AndXCommand = 0xFF;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2014-01-16 11:53:33 +00:00
|
|
|
if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
/* account for one byte pad to word boundary */
|
|
|
|
count = 1;
|
|
|
|
name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
|
|
|
|
path, PATH_MAX, nls, remap);
|
|
|
|
/* trailing null */
|
|
|
|
name_len++;
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len *= 2;
|
2014-01-16 11:53:33 +00:00
|
|
|
req->NameLength = cpu_to_le16(name_len);
|
|
|
|
} else {
|
|
|
|
/* BB improve check for buffer overruns BB */
|
|
|
|
/* no pad */
|
|
|
|
count = 0;
|
2019-08-26 23:30:14 +00:00
|
|
|
name_len = copy_path_name(req->fileName, path);
|
2014-01-16 11:53:33 +00:00
|
|
|
req->NameLength = cpu_to_le16(name_len);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2014-01-16 11:53:33 +00:00
|
|
|
|
|
|
|
if (*oplock & REQ_OPLOCK)
|
|
|
|
req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
|
|
|
|
else if (*oplock & REQ_BATCHOPLOCK)
|
|
|
|
req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
|
|
|
|
|
|
|
|
req->DesiredAccess = cpu_to_le32(desired_access);
|
|
|
|
req->AllocationSize = 0;
|
|
|
|
|
|
|
|
/*
|
2024-09-15 19:45:45 +00:00
|
|
|
* Set file as system file if special file such as fifo, socket, char
|
|
|
|
* or block and server expecting SFU style and no Unix extensions.
|
2014-01-16 11:53:33 +00:00
|
|
|
*/
|
2007-07-07 19:25:05 +00:00
|
|
|
if (create_options & CREATE_OPTION_SPECIAL)
|
2014-01-16 11:53:33 +00:00
|
|
|
req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
|
2005-07-21 22:20:28 +00:00
|
|
|
else
|
2014-01-16 11:53:33 +00:00
|
|
|
req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
|
2008-05-09 22:28:02 +00:00
|
|
|
|
2014-01-16 11:53:33 +00:00
|
|
|
/*
|
|
|
|
* XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
|
|
|
|
* sensitive checks for other servers such as Samba.
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
if (tcon->ses->capabilities & CAP_UNIX)
|
2014-01-16 11:53:33 +00:00
|
|
|
req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-05-09 22:28:02 +00:00
|
|
|
if (create_options & CREATE_OPTION_READONLY)
|
2014-01-16 11:53:33 +00:00
|
|
|
req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
|
|
|
|
|
|
|
|
req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
|
|
|
|
req->CreateDisposition = cpu_to_le32(disposition);
|
|
|
|
req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
|
2008-05-09 22:28:02 +00:00
|
|
|
|
2024-09-25 06:55:43 +00:00
|
|
|
/* BB Experiment with various impersonation levels and verify */
|
2014-01-16 11:53:33 +00:00
|
|
|
req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
|
|
|
|
req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
count += name_len;
|
2014-01-16 11:53:33 +00:00
|
|
|
inc_rfc1001_len(req, count);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2014-01-16 11:53:33 +00:00
|
|
|
req->ByteCount = cpu_to_le16(count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
|
|
|
|
(struct smb_hdr *)rsp, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Error in Open = %d\n", rc);
|
2014-01-16 11:53:33 +00:00
|
|
|
cifs_buf_release(req);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto openRetry;
|
|
|
|
return rc;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2005-08-21 04:42:53 +00:00
|
|
|
|
2014-01-16 11:53:33 +00:00
|
|
|
/* 1 byte no need to le_to_cpu */
|
|
|
|
*oplock = rsp->OplockLevel;
|
|
|
|
/* cifs fid stays in le */
|
2014-01-16 11:53:36 +00:00
|
|
|
oparms->fid->netfid = rsp->Fid;
|
cifs: fix rename() by ensuring source handle opened with DELETE bit
To rename a file in SMB2 we open it with the DELETE access and do a
special SetInfo on it. If the handle is missing the DELETE bit the
server will fail the SetInfo with STATUS_ACCESS_DENIED.
We currently try to reuse any existing opened handle we have with
cifs_get_writable_path(). That function looks for handles with WRITE
access but doesn't check for DELETE, making rename() fail if it finds
a handle to reuse. Simple reproducer below.
To select handles with the DELETE bit, this patch adds a flag argument
to cifs_get_writable_path() and find_writable_file() and the existing
'bool fsuid_only' argument is converted to a flag.
The cifsFileInfo struct only stores the UNIX open mode but not the
original SMB access flags. Since the DELETE bit is not mapped in that
mode, this patch stores the access mask in cifs_fid on file open,
which is accessible from cifsFileInfo.
Simple reproducer:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define E(s) perror(s), exit(1)
int main(int argc, char *argv[])
{
int fd, ret;
if (argc != 3) {
fprintf(stderr, "Usage: %s A B\n"
"create&open A in write mode, "
"rename A to B, close A\n", argv[0]);
return 0;
}
fd = openat(AT_FDCWD, argv[1], O_WRONLY|O_CREAT|O_SYNC, 0666);
if (fd == -1) E("openat()");
ret = rename(argv[1], argv[2]);
if (ret) E("rename()");
ret = close(fd);
if (ret) E("close()");
return ret;
}
$ gcc -o bugrename bugrename.c
$ ./bugrename /mnt/a /mnt/b
rename(): Permission denied
Fixes: 8de9e86c67ba ("cifs: create a helper to find a writeable handle by path name")
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
2020-02-21 10:19:06 +00:00
|
|
|
oparms->fid->access = desired_access;
|
2014-01-16 11:53:33 +00:00
|
|
|
|
|
|
|
/* Let caller know file was created so we can set the mode. */
|
|
|
|
/* Do we care about the CreateAction in any other cases? */
|
|
|
|
if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
|
|
|
|
*oplock |= CIFS_CREATE_ACTION;
|
|
|
|
|
|
|
|
if (buf) {
|
smb: client, common: fix fortify warnings
When compiling with gcc version 14.0.0 20231126 (experimental)
and CONFIG_FORTIFY_SOURCE=y, I've noticed the following:
In file included from ./include/linux/string.h:295,
from ./include/linux/bitmap.h:12,
from ./include/linux/cpumask.h:12,
from ./arch/x86/include/asm/paravirt.h:17,
from ./arch/x86/include/asm/cpuid.h:62,
from ./arch/x86/include/asm/processor.h:19,
from ./arch/x86/include/asm/cpufeature.h:5,
from ./arch/x86/include/asm/thread_info.h:53,
from ./include/linux/thread_info.h:60,
from ./arch/x86/include/asm/preempt.h:9,
from ./include/linux/preempt.h:79,
from ./include/linux/spinlock.h:56,
from ./include/linux/wait.h:9,
from ./include/linux/wait_bit.h:8,
from ./include/linux/fs.h:6,
from fs/smb/client/smb2pdu.c:18:
In function 'fortify_memcpy_chk',
inlined from '__SMB2_close' at fs/smb/client/smb2pdu.c:3480:4:
./include/linux/fortify-string.h:588:25: warning: call to '__read_overflow2_field'
declared with attribute warning: detected read beyond size of field (2nd parameter);
maybe use struct_group()? [-Wattribute-warning]
588 | __read_overflow2_field(q_size_field, size);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
and:
In file included from ./include/linux/string.h:295,
from ./include/linux/bitmap.h:12,
from ./include/linux/cpumask.h:12,
from ./arch/x86/include/asm/paravirt.h:17,
from ./arch/x86/include/asm/cpuid.h:62,
from ./arch/x86/include/asm/processor.h:19,
from ./arch/x86/include/asm/cpufeature.h:5,
from ./arch/x86/include/asm/thread_info.h:53,
from ./include/linux/thread_info.h:60,
from ./arch/x86/include/asm/preempt.h:9,
from ./include/linux/preempt.h:79,
from ./include/linux/spinlock.h:56,
from ./include/linux/wait.h:9,
from ./include/linux/wait_bit.h:8,
from ./include/linux/fs.h:6,
from fs/smb/client/cifssmb.c:17:
In function 'fortify_memcpy_chk',
inlined from 'CIFS_open' at fs/smb/client/cifssmb.c:1248:3:
./include/linux/fortify-string.h:588:25: warning: call to '__read_overflow2_field'
declared with attribute warning: detected read beyond size of field (2nd parameter);
maybe use struct_group()? [-Wattribute-warning]
588 | __read_overflow2_field(q_size_field, size);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In both cases, the fortification logic inteprets calls to 'memcpy()' as an
attempts to copy an amount of data which exceeds the size of the specified
field (i.e. more than 8 bytes from __le64 value) and thus issues an overread
warning. Both of these warnings may be silenced by using the convenient
'struct_group()' quirk.
Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
2023-11-28 10:53:47 +00:00
|
|
|
/* copy commonly used attributes */
|
|
|
|
memcpy(&buf->common_attributes,
|
|
|
|
&rsp->common_attributes,
|
|
|
|
sizeof(buf->common_attributes));
|
2014-01-16 11:53:33 +00:00
|
|
|
/* the file_info buf is endian converted by caller */
|
|
|
|
buf->AllocationSize = rsp->AllocationSize;
|
|
|
|
buf->EndOfFile = rsp->EndOfFile;
|
|
|
|
buf->NumberOfLinks = cpu_to_le32(1);
|
|
|
|
buf->DeletePending = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cifs_buf_release(req);
|
2005-04-16 22:20:36 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2024-09-03 10:15:41 +00:00
|
|
|
static void cifs_readv_worker(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct cifs_io_subrequest *rdata =
|
|
|
|
container_of(work, struct cifs_io_subrequest, subreq.work);
|
|
|
|
|
cifs: Fix cifs readv callback merge resolution issue
Fix an upstream merge resolution issue[1]. Prior to the netfs read
healpers, the SMB1 asynchronous read callback, cifs_readv_worker()
performed the cleanup for the operation in the network message processing
loop, potentially slowing down the processing of incoming SMB messages.
With commit a68c74865f51 ("cifs: Fix SMB1 readv/writev callback in the same
way as SMB2/3"), this was moved to a worker thread (as is done in the
SMB2/3 transport variant). However, the "was_async" argument to
netfs_subreq_terminated (which was originally incorrectly "false" got
flipped to "true" - which was then incorrect because, being in a kernel
thread, it's not in an async context).
This got corrected in the sample merge[2], but Linus, not unreasonably,
switched it back to its previous value.
Note that this value tells netfslib whether or not it can run sleepable
stuff or stuff that takes a long time, such as retries and cleanups, in the
calling thread, or whether it should offload to a worker thread.
Fix this so that it is "false". The callback to netfslib in both SMB1 and
SMB2/3 now gets offloaded from the network message thread to a separate
worker thread and thus it's fine to do the slow work in this thread.
Fixes: 35219bc5c71f ("Merge tag 'vfs-6.12.netfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs")
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <stfrench@microsoft.com>
cc: Paulo Alcantara <pc@manguebit.com>
cc: Christian Brauner <brauner@kernel.org>
cc: Jeff Layton <jlayton@kernel.org>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Link: https://lore.kernel.org/r/CAHk-=wjr8fxk20-wx=63mZruW1LTvBvAKya1GQ1EhyzXb-okMA@mail.gmail.com/ [1]
Link: https://lore.kernel.org/linux-fsdevel/20240913-vfs-netfs-39ef6f974061@brauner/ [2]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2024-09-16 13:50:16 +00:00
|
|
|
netfs_read_subreq_terminated(&rdata->subreq, rdata->result, false);
|
2024-09-03 10:15:41 +00:00
|
|
|
}
|
|
|
|
|
2011-10-19 19:30:07 +00:00
|
|
|
static void
|
|
|
|
cifs_readv_callback(struct mid_q_entry *mid)
|
|
|
|
{
|
2022-03-09 11:01:12 +00:00
|
|
|
struct cifs_io_subrequest *rdata = mid->callback_data;
|
2024-09-03 10:15:41 +00:00
|
|
|
struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
|
2023-10-06 17:29:59 +00:00
|
|
|
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
|
2011-10-19 19:30:07 +00:00
|
|
|
struct TCP_Server_Info *server = tcon->ses->server;
|
2016-11-23 23:14:57 +00:00
|
|
|
struct smb_rqst rqst = { .rq_iov = rdata->iov,
|
|
|
|
.rq_nvec = 2,
|
2023-10-06 15:55:20 +00:00
|
|
|
.rq_iter = rdata->subreq.io_iter };
|
2024-09-03 10:15:41 +00:00
|
|
|
struct cifs_credits credits = {
|
|
|
|
.value = 1,
|
|
|
|
.instance = 0,
|
|
|
|
.rreq_debug_id = rdata->rreq->debug_id,
|
|
|
|
.rreq_debug_index = rdata->subreq.debug_index,
|
|
|
|
};
|
2011-10-19 19:30:07 +00:00
|
|
|
|
2023-10-06 15:55:20 +00:00
|
|
|
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n",
|
2013-05-05 03:12:25 +00:00
|
|
|
__func__, mid->mid, mid->mid_state, rdata->result,
|
2023-10-06 15:55:20 +00:00
|
|
|
rdata->subreq.len);
|
2011-10-19 19:30:07 +00:00
|
|
|
|
2012-03-23 18:28:03 +00:00
|
|
|
switch (mid->mid_state) {
|
2011-10-19 19:30:07 +00:00
|
|
|
case MID_RESPONSE_RECEIVED:
|
|
|
|
/* result already set, check signature */
|
2013-05-26 11:01:00 +00:00
|
|
|
if (server->sign) {
|
2012-08-03 14:42:45 +00:00
|
|
|
int rc = 0;
|
|
|
|
|
2024-09-03 10:15:41 +00:00
|
|
|
iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes);
|
2012-09-18 23:20:34 +00:00
|
|
|
rc = cifs_verify_signature(&rqst, server,
|
2013-04-03 15:55:03 +00:00
|
|
|
mid->sequence_number);
|
2012-08-03 14:42:45 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
|
|
|
|
rc);
|
2011-10-19 19:30:07 +00:00
|
|
|
}
|
|
|
|
/* FIXME: should this be counted toward the initiating task? */
|
2014-07-10 06:03:29 +00:00
|
|
|
task_io_account_read(rdata->got_bytes);
|
|
|
|
cifs_stats_bytes_read(tcon, rdata->got_bytes);
|
2011-10-19 19:30:07 +00:00
|
|
|
break;
|
|
|
|
case MID_REQUEST_SUBMITTED:
|
|
|
|
case MID_RETRY_NEEDED:
|
|
|
|
rdata->result = -EAGAIN;
|
2014-07-10 07:31:48 +00:00
|
|
|
if (server->sign && rdata->got_bytes)
|
|
|
|
/* reset bytes number since we can not check a sign */
|
|
|
|
rdata->got_bytes = 0;
|
|
|
|
/* FIXME: should this be counted toward the initiating task? */
|
|
|
|
task_io_account_read(rdata->got_bytes);
|
|
|
|
cifs_stats_bytes_read(tcon, rdata->got_bytes);
|
2011-10-19 19:30:07 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rdata->result = -EIO;
|
|
|
|
}
|
|
|
|
|
2024-09-03 10:15:41 +00:00
|
|
|
if (rdata->result == -ENODATA) {
|
|
|
|
__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
|
|
|
|
rdata->result = 0;
|
|
|
|
} else {
|
vfs-6.12.netfs
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCZuQEvgAKCRCRxhvAZXjc
onQWAQD6IxAKPU0zom2FoWNilvSzPs7WglTtvddX9pu/lT1RNAD/YC/wOLW8mvAv
9oTAmigQDQQhEWdJA9RgLZBiw7k+DAw=
=zWFb
-----END PGP SIGNATURE-----
Merge tag 'vfs-6.12.netfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull netfs updates from Christian Brauner:
"This contains the work to improve read/write performance for the new
netfs library.
The main performance enhancing changes are:
- Define a structure, struct folio_queue, and a new iterator type,
ITER_FOLIOQ, to hold a buffer as a replacement for ITER_XARRAY. See
that patch for questions about naming and form.
ITER_FOLIOQ is provided as a replacement for ITER_XARRAY. The
problem with an xarray is that accessing it requires the use of a
lock (typically the RCU read lock) - and this means that we can't
supply iterate_and_advance() with a step function that might sleep
(crypto for example) without having to drop the lock between pages.
ITER_FOLIOQ is the iterator for a chain of folio_queue structs,
where each folio_queue holds a small list of folios. A folio_queue
struct is a simpler structure than xarray and is not subject to
concurrent manipulation by the VM. folio_queue is used rather than
a bvec[] as it can form lists of indefinite size, adding to one end
and removing from the other on the fly.
- Provide a copy_folio_from_iter() wrapper.
- Make cifs RDMA support ITER_FOLIOQ.
- Use folio queues in the write-side helpers instead of xarrays.
- Add a function to reset the iterator in a subrequest.
- Simplify the write-side helpers to use sheaves to skip gaps rather
than trying to work out where gaps are.
- In afs, make the read subrequests asynchronous, putting them into
work items to allow the next patch to do progressive
unlocking/reading.
- Overhaul the read-side helpers to improve performance.
- Fix the caching of a partial block at the end of a file.
- Allow a store to be cancelled.
Then some changes for cifs to make it use folio queues instead of
xarrays for crypto bufferage:
- Use raw iteration functions rather than manually coding iteration
when hashing data.
- Switch to using folio_queue for crypto buffers.
- Remove the xarray bits.
Make some adjustments to the /proc/fs/netfs/stats file such that:
- All the netfs stats lines begin 'Netfs:' but change this to
something a bit more useful.
- Add a couple of stats counters to track the numbers of skips and
waits on the per-inode writeback serialisation lock to make it
easier to check for this as a source of performance loss.
Miscellaneous work:
- Ensure that the sb_writers lock is taken around
vfs_{set,remove}xattr() in the cachefiles code.
- Reduce the number of conditional branches in netfs_perform_write().
- Move the CIFS_INO_MODIFIED_ATTR flag to the netfs_inode struct and
remove cifs_post_modify().
- Move the max_len/max_nr_segs members from netfs_io_subrequest to
netfs_io_request as they're only needed for one subreq at a time.
- Add an 'unknown' source value for tracing purposes.
- Remove NETFS_COPY_TO_CACHE as it's no longer used.
- Set the request work function up front at allocation time.
- Use bh-disabling spinlocks for rreq->lock as cachefiles completion
may be run from block-filesystem DIO completion in softirq context.
- Remove fs/netfs/io.c"
* tag 'vfs-6.12.netfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (25 commits)
docs: filesystems: corrected grammar of netfs page
cifs: Don't support ITER_XARRAY
cifs: Switch crypto buffer to use a folio_queue rather than an xarray
cifs: Use iterate_and_advance*() routines directly for hashing
netfs: Cancel dirty folios that have no storage destination
cachefiles, netfs: Fix write to partial block at EOF
netfs: Remove fs/netfs/io.c
netfs: Speed up buffered reading
afs: Make read subreqs async
netfs: Simplify the writeback code
netfs: Provide an iterator-reset function
netfs: Use new folio_queue data type and iterator instead of xarray iter
cifs: Provide the capability to extract from ITER_FOLIOQ to RDMA SGEs
iov_iter: Provide copy_folio_from_iter()
mm: Define struct folio_queue and ITER_FOLIOQ to handle a sequence of folios
netfs: Use bh-disabling spinlocks for rreq->lock
netfs: Set the request work function upon allocation
netfs: Remove NETFS_COPY_TO_CACHE
netfs: Reserve netfs_sreq_source 0 as unset/unknown
netfs: Move max_len/max_nr_segs from netfs_io_subrequest to netfs_io_stream
...
2024-09-16 10:13:31 +00:00
|
|
|
size_t trans = rdata->subreq.transferred + rdata->got_bytes;
|
|
|
|
if (trans < rdata->subreq.len &&
|
|
|
|
rdata->subreq.start + trans == ictx->remote_i_size) {
|
2024-09-03 10:15:41 +00:00
|
|
|
__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
|
|
|
|
rdata->result = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-06 17:29:59 +00:00
|
|
|
rdata->credits.value = 0;
|
2024-07-01 23:40:22 +00:00
|
|
|
rdata->subreq.transferred += rdata->got_bytes;
|
2024-09-03 10:15:41 +00:00
|
|
|
INIT_WORK(&rdata->subreq.work, cifs_readv_worker);
|
|
|
|
queue_work(cifsiod_wq, &rdata->subreq.work);
|
2022-08-05 14:47:38 +00:00
|
|
|
release_mid(mid);
|
2019-01-16 19:22:29 +00:00
|
|
|
add_credits(server, &credits, 0);
|
2011-10-19 19:30:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* cifs_async_readv - send an async write, and set up mid to handle result */
|
|
|
|
int
|
2022-03-09 11:01:12 +00:00
|
|
|
cifs_async_readv(struct cifs_io_subrequest *rdata)
|
2011-10-19 19:30:07 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
READ_REQ *smb = NULL;
|
|
|
|
int wct;
|
2023-10-06 17:29:59 +00:00
|
|
|
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
|
2016-11-23 23:14:57 +00:00
|
|
|
struct smb_rqst rqst = { .rq_iov = rdata->iov,
|
|
|
|
.rq_nvec = 2 };
|
2011-10-19 19:30:07 +00:00
|
|
|
|
2023-10-06 15:55:20 +00:00
|
|
|
cifs_dbg(FYI, "%s: offset=%llu bytes=%zu\n",
|
|
|
|
__func__, rdata->subreq.start, rdata->subreq.len);
|
2011-10-19 19:30:07 +00:00
|
|
|
|
|
|
|
if (tcon->ses->capabilities & CAP_LARGE_FILES)
|
|
|
|
wct = 12;
|
|
|
|
else {
|
|
|
|
wct = 10; /* old style read */
|
2023-10-06 15:55:20 +00:00
|
|
|
if ((rdata->subreq.start >> 32) > 0) {
|
2011-10-19 19:30:07 +00:00
|
|
|
/* can not handle this big offset for old */
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2024-06-20 17:31:29 +00:00
|
|
|
smb->hdr.Pid = cpu_to_le16((__u16)rdata->req->pid);
|
|
|
|
smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->req->pid >> 16));
|
2011-10-19 19:30:07 +00:00
|
|
|
|
|
|
|
smb->AndXCommand = 0xFF; /* none */
|
2023-10-06 17:29:59 +00:00
|
|
|
smb->Fid = rdata->req->cfile->fid.netfid;
|
2023-10-06 15:55:20 +00:00
|
|
|
smb->OffsetLow = cpu_to_le32(rdata->subreq.start & 0xFFFFFFFF);
|
2011-10-19 19:30:07 +00:00
|
|
|
if (wct == 12)
|
2023-10-06 15:55:20 +00:00
|
|
|
smb->OffsetHigh = cpu_to_le32(rdata->subreq.start >> 32);
|
2011-10-19 19:30:07 +00:00
|
|
|
smb->Remaining = 0;
|
2023-10-06 15:55:20 +00:00
|
|
|
smb->MaxCount = cpu_to_le16(rdata->subreq.len & 0xFFFF);
|
|
|
|
smb->MaxCountHigh = cpu_to_le32(rdata->subreq.len >> 16);
|
2011-10-19 19:30:07 +00:00
|
|
|
if (wct == 12)
|
|
|
|
smb->ByteCount = 0;
|
|
|
|
else {
|
|
|
|
/* old style read */
|
|
|
|
struct smb_com_readx_req *smbr =
|
|
|
|
(struct smb_com_readx_req *)smb;
|
|
|
|
smbr->ByteCount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 4 for RFC1001 length + 1 for BCC */
|
2016-11-23 23:14:57 +00:00
|
|
|
rdata->iov[0].iov_base = smb;
|
|
|
|
rdata->iov[0].iov_len = 4;
|
|
|
|
rdata->iov[1].iov_base = (char *)smb + 4;
|
|
|
|
rdata->iov[1].iov_len = get_rfc1002_length(smb);
|
2011-10-19 19:30:07 +00:00
|
|
|
|
2012-09-18 23:20:35 +00:00
|
|
|
rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
|
2019-01-15 23:52:29 +00:00
|
|
|
cifs_readv_callback, NULL, rdata, 0, NULL);
|
2011-10-19 19:30:07 +00:00
|
|
|
|
|
|
|
if (rc == 0)
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
|
2011-10-19 19:30:07 +00:00
|
|
|
cifs_small_buf_release(smb);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|
|
|
unsigned int *nbytes, char **buf, int *pbuf_type)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int rc = -EACCES;
|
|
|
|
READ_REQ *pSMB = NULL;
|
|
|
|
READ_RSP *pSMBr = NULL;
|
|
|
|
char *pReadData = NULL;
|
2005-09-01 04:50:37 +00:00
|
|
|
int wct;
|
2005-12-13 04:53:18 +00:00
|
|
|
int resp_buf_type = 0;
|
|
|
|
struct kvec iov[1];
|
2016-10-25 18:38:47 +00:00
|
|
|
struct kvec rsp_iov;
|
2011-05-26 06:02:00 +00:00
|
|
|
__u32 pid = io_parms->pid;
|
|
|
|
__u16 netfid = io_parms->netfid;
|
|
|
|
__u64 offset = io_parms->offset;
|
2011-05-27 04:34:02 +00:00
|
|
|
struct cifs_tcon *tcon = io_parms->tcon;
|
2011-05-26 06:02:00 +00:00
|
|
|
unsigned int count = io_parms->length;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (tcon->ses->capabilities & CAP_LARGE_FILES)
|
2005-09-01 04:50:37 +00:00
|
|
|
wct = 12;
|
2008-12-09 00:28:16 +00:00
|
|
|
else {
|
2005-09-01 04:50:37 +00:00
|
|
|
wct = 10; /* old style read */
|
2011-05-26 06:02:00 +00:00
|
|
|
if ((offset >> 32) > 0) {
|
2008-12-09 00:28:16 +00:00
|
|
|
/* can not handle this big offset for old */
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
*nbytes = 0;
|
2005-12-13 04:53:18 +00:00
|
|
|
rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2011-05-26 06:02:00 +00:00
|
|
|
pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
|
|
|
|
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/* tcon and ses pointer are checked in smb_init */
|
|
|
|
if (tcon->ses->server == NULL)
|
|
|
|
return -ECONNABORTED;
|
|
|
|
|
2005-12-13 04:53:18 +00:00
|
|
|
pSMB->AndXCommand = 0xFF; /* none */
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->Fid = netfid;
|
2011-05-26 06:02:00 +00:00
|
|
|
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (wct == 12)
|
2011-05-26 06:02:00 +00:00
|
|
|
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
|
2005-09-01 04:50:37 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->Remaining = 0;
|
|
|
|
pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
|
|
|
|
pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (wct == 12)
|
2005-09-01 04:50:37 +00:00
|
|
|
pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
|
|
|
|
else {
|
|
|
|
/* old style read */
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_readx_req *pSMBW =
|
2005-09-01 04:50:37 +00:00
|
|
|
(struct smb_com_readx_req *)pSMB;
|
2005-12-13 04:53:18 +00:00
|
|
|
pSMBW->ByteCount = 0;
|
2005-09-01 04:50:37 +00:00
|
|
|
}
|
2005-12-13 04:53:18 +00:00
|
|
|
|
|
|
|
iov[0].iov_base = (char *)pSMB;
|
2011-04-29 05:40:20 +00:00
|
|
|
iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
|
2016-10-25 18:38:47 +00:00
|
|
|
rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
|
|
|
|
CIFS_LOG_ERROR, &rsp_iov);
|
|
|
|
cifs_small_buf_release(pSMB);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
|
2016-10-25 18:38:47 +00:00
|
|
|
pSMBr = (READ_RSP *)rsp_iov.iov_base;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Send error in read = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
|
|
|
|
data_length = data_length << 16;
|
|
|
|
data_length += le16_to_cpu(pSMBr->DataLength);
|
|
|
|
*nbytes = data_length;
|
|
|
|
|
|
|
|
/*check that DataLength would not go beyond end of SMB */
|
2005-12-13 04:53:18 +00:00
|
|
|
if ((data_length > CIFSMaxBufSize)
|
2005-04-16 22:20:36 +00:00
|
|
|
|| (data_length > count)) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "bad length %d for count %d\n",
|
2010-04-21 03:50:45 +00:00
|
|
|
data_length, count);
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = -EIO;
|
|
|
|
*nbytes = 0;
|
|
|
|
} else {
|
2005-12-13 04:53:18 +00:00
|
|
|
pReadData = (char *) (&pSMBr->hdr.Protocol) +
|
2007-08-30 22:09:15 +00:00
|
|
|
le16_to_cpu(pSMBr->DataOffset);
|
|
|
|
/* if (rc = copy_to_user(buf, pReadData, data_length)) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
|
2007-07-13 00:33:32 +00:00
|
|
|
rc = -EFAULT;
|
2007-08-30 22:09:15 +00:00
|
|
|
}*/ /* can not use copy_to_user when using page cache*/
|
2007-07-07 19:25:05 +00:00
|
|
|
if (*buf)
|
2007-07-13 00:33:32 +00:00
|
|
|
memcpy(*buf, pReadData, data_length);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if (*buf) {
|
2016-10-25 18:38:47 +00:00
|
|
|
free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
|
2007-07-07 19:25:05 +00:00
|
|
|
} else if (resp_buf_type != CIFS_NO_BUFFER) {
|
2007-07-13 00:33:32 +00:00
|
|
|
/* return buffer to caller to free */
|
2016-10-25 18:38:47 +00:00
|
|
|
*buf = rsp_iov.iov_base;
|
2007-07-07 19:25:05 +00:00
|
|
|
if (resp_buf_type == CIFS_SMALL_BUFFER)
|
2005-12-13 04:53:18 +00:00
|
|
|
*pbuf_type = CIFS_SMALL_BUFFER;
|
2007-07-07 19:25:05 +00:00
|
|
|
else if (resp_buf_type == CIFS_LARGE_BUFFER)
|
2005-12-13 04:53:18 +00:00
|
|
|
*pbuf_type = CIFS_LARGE_BUFFER;
|
2006-02-22 23:31:52 +00:00
|
|
|
} /* else no valid buffer on return - leave as null */
|
2005-12-13 04:53:18 +00:00
|
|
|
|
|
|
|
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
2005-04-16 22:20:36 +00:00
|
|
|
since file handle passed in no longer valid */
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-12-13 04:53:18 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
|
2016-09-05 21:53:43 +00:00
|
|
|
unsigned int *nbytes, const char *buf)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int rc = -EACCES;
|
|
|
|
WRITE_REQ *pSMB = NULL;
|
|
|
|
WRITE_RSP *pSMBr = NULL;
|
2005-08-31 03:58:07 +00:00
|
|
|
int bytes_returned, wct;
|
2005-04-16 22:20:36 +00:00
|
|
|
__u32 bytes_sent;
|
|
|
|
__u16 byte_count;
|
2011-05-26 06:01:59 +00:00
|
|
|
__u32 pid = io_parms->pid;
|
|
|
|
__u16 netfid = io_parms->netfid;
|
|
|
|
__u64 offset = io_parms->offset;
|
2011-05-27 04:34:02 +00:00
|
|
|
struct cifs_tcon *tcon = io_parms->tcon;
|
2011-05-26 06:01:59 +00:00
|
|
|
unsigned int count = io_parms->length;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2010-04-03 17:20:21 +00:00
|
|
|
*nbytes = 0;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
/* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
|
2007-07-07 19:25:05 +00:00
|
|
|
if (tcon->ses == NULL)
|
2005-08-31 03:58:07 +00:00
|
|
|
return -ECONNABORTED;
|
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if (tcon->ses->capabilities & CAP_LARGE_FILES)
|
2005-08-31 03:58:07 +00:00
|
|
|
wct = 14;
|
2008-12-09 00:28:16 +00:00
|
|
|
else {
|
2005-08-31 03:58:07 +00:00
|
|
|
wct = 12;
|
2008-12-09 00:28:16 +00:00
|
|
|
if ((offset >> 32) > 0) {
|
|
|
|
/* can not handle big offset for old srv */
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
}
|
2005-08-31 03:58:07 +00:00
|
|
|
|
|
|
|
rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
|
2005-04-16 22:20:36 +00:00
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
2011-05-26 06:01:59 +00:00
|
|
|
|
|
|
|
pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
|
|
|
|
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/* tcon and ses pointer are checked in smb_init */
|
|
|
|
if (tcon->ses->server == NULL)
|
|
|
|
return -ECONNABORTED;
|
|
|
|
|
|
|
|
pSMB->AndXCommand = 0xFF; /* none */
|
|
|
|
pSMB->Fid = netfid;
|
|
|
|
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (wct == 14)
|
2005-08-31 03:58:07 +00:00
|
|
|
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
|
2007-07-13 00:33:32 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->Reserved = 0xFFFFFFFF;
|
|
|
|
pSMB->WriteMode = 0;
|
|
|
|
pSMB->Remaining = 0;
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/* Can increase buffer size if buffer is big enough in some cases ie we
|
2005-04-16 22:20:36 +00:00
|
|
|
can send more if LARGE_WRITE_X capability returned by the server and if
|
|
|
|
our buffer is big enough or if we convert to iovecs on socket writes
|
|
|
|
and eliminate the copy to the CIFS buffer */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
|
2005-04-16 22:20:36 +00:00
|
|
|
bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
|
|
|
|
} else {
|
|
|
|
bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
|
|
|
|
& ~0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bytes_sent > count)
|
|
|
|
bytes_sent = count;
|
|
|
|
pSMB->DataOffset =
|
2007-07-13 00:33:32 +00:00
|
|
|
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (buf)
|
2008-12-03 00:57:54 +00:00
|
|
|
memcpy(pSMB->Data, buf, bytes_sent);
|
2016-09-05 21:53:43 +00:00
|
|
|
else if (count != 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
/* No buffer */
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
return -EINVAL;
|
2005-09-21 03:49:16 +00:00
|
|
|
} /* else setting file size with write of zero bytes */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (wct == 14)
|
2005-09-21 03:49:16 +00:00
|
|
|
byte_count = bytes_sent + 1; /* pad */
|
2008-02-07 23:25:02 +00:00
|
|
|
else /* wct == 12 */
|
2005-09-21 03:49:16 +00:00
|
|
|
byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
|
2008-02-07 23:25:02 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
|
|
|
|
pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-08-31 03:58:07 +00:00
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if (wct == 14)
|
2005-08-31 03:58:07 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
2007-07-13 00:33:32 +00:00
|
|
|
else { /* old style write has byte count 4 bytes earlier
|
|
|
|
so 4 bytes pad */
|
|
|
|
struct smb_com_writex_req *pSMBW =
|
2005-08-31 03:58:07 +00:00
|
|
|
(struct smb_com_writex_req *)pSMB;
|
|
|
|
pSMBW->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
2016-09-05 21:53:43 +00:00
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in write = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
*nbytes = le16_to_cpu(pSMBr->CountHigh);
|
|
|
|
*nbytes = (*nbytes) << 16;
|
|
|
|
*nbytes += le16_to_cpu(pSMBr->Count);
|
2010-03-31 06:30:03 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Mask off high 16 bits when bytes written as returned by the
|
|
|
|
* server is greater than bytes requested by the client. Some
|
|
|
|
* OS/2 servers are known to set incorrect CountHigh values.
|
|
|
|
*/
|
|
|
|
if (*nbytes > count)
|
|
|
|
*nbytes &= 0xFFFF;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
2005-04-16 22:20:36 +00:00
|
|
|
since file handle passed in no longer valid */
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-05-19 20:22:56 +00:00
|
|
|
/*
|
2012-03-23 18:28:03 +00:00
|
|
|
* Check the mid_state and signature on received buffer (if any), and queue the
|
2011-05-19 20:22:56 +00:00
|
|
|
* workqueue completion task.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
cifs_writev_callback(struct mid_q_entry *mid)
|
|
|
|
{
|
2023-10-06 15:27:41 +00:00
|
|
|
struct cifs_io_subrequest *wdata = mid->callback_data;
|
2024-09-03 10:15:41 +00:00
|
|
|
struct TCP_Server_Info *server = wdata->server;
|
2023-10-06 17:29:59 +00:00
|
|
|
struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
|
2011-05-19 20:22:56 +00:00
|
|
|
WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
|
2024-09-03 10:15:41 +00:00
|
|
|
struct cifs_credits credits = {
|
|
|
|
.value = 1,
|
|
|
|
.instance = 0,
|
|
|
|
.rreq_debug_id = wdata->rreq->debug_id,
|
|
|
|
.rreq_debug_index = wdata->subreq.debug_index,
|
|
|
|
};
|
2023-10-06 17:29:59 +00:00
|
|
|
ssize_t result;
|
|
|
|
size_t written;
|
2011-05-19 20:22:56 +00:00
|
|
|
|
2012-03-23 18:28:03 +00:00
|
|
|
switch (mid->mid_state) {
|
2011-05-19 20:22:56 +00:00
|
|
|
case MID_RESPONSE_RECEIVED:
|
2023-10-06 17:29:59 +00:00
|
|
|
result = cifs_check_receive(mid, tcon->ses->server, 0);
|
|
|
|
if (result != 0)
|
2011-05-19 20:22:56 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
written = le16_to_cpu(smb->CountHigh);
|
|
|
|
written <<= 16;
|
|
|
|
written += le16_to_cpu(smb->Count);
|
|
|
|
/*
|
|
|
|
* Mask off high 16 bits when bytes written as returned
|
|
|
|
* by the server is greater than bytes requested by the
|
|
|
|
* client. OS/2 servers are known to set incorrect
|
|
|
|
* CountHigh values.
|
|
|
|
*/
|
2023-10-06 15:55:20 +00:00
|
|
|
if (written > wdata->subreq.len)
|
2011-05-19 20:22:56 +00:00
|
|
|
written &= 0xFFFF;
|
|
|
|
|
2023-10-06 15:55:20 +00:00
|
|
|
if (written < wdata->subreq.len)
|
2023-10-06 17:29:59 +00:00
|
|
|
result = -ENOSPC;
|
2011-05-19 20:22:56 +00:00
|
|
|
else
|
2023-10-06 17:29:59 +00:00
|
|
|
result = written;
|
2011-05-19 20:22:56 +00:00
|
|
|
break;
|
|
|
|
case MID_REQUEST_SUBMITTED:
|
|
|
|
case MID_RETRY_NEEDED:
|
2023-10-06 17:29:59 +00:00
|
|
|
result = -EAGAIN;
|
2011-05-19 20:22:56 +00:00
|
|
|
break;
|
|
|
|
default:
|
2023-10-06 17:29:59 +00:00
|
|
|
result = -EIO;
|
2011-05-19 20:22:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-09-03 10:15:41 +00:00
|
|
|
trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index,
|
|
|
|
wdata->credits.value,
|
|
|
|
server->credits, server->in_flight,
|
|
|
|
0, cifs_trace_rw_credits_write_response_clear);
|
2023-10-06 17:29:59 +00:00
|
|
|
wdata->credits.value = 0;
|
|
|
|
cifs_write_subrequest_terminated(wdata, result, true);
|
2022-08-05 14:47:38 +00:00
|
|
|
release_mid(mid);
|
2024-09-03 10:15:41 +00:00
|
|
|
trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index, 0,
|
|
|
|
server->credits, server->in_flight,
|
|
|
|
credits.value, cifs_trace_rw_credits_write_response_add);
|
2019-01-16 19:22:29 +00:00
|
|
|
add_credits(tcon->ses->server, &credits, 0);
|
2011-05-19 20:22:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* cifs_async_writev - send an async write, and set up mid to handle result */
|
2023-10-06 17:29:59 +00:00
|
|
|
void
|
2023-10-06 15:27:41 +00:00
|
|
|
cifs_async_writev(struct cifs_io_subrequest *wdata)
|
2011-05-19 20:22:56 +00:00
|
|
|
{
|
2012-09-18 23:20:35 +00:00
|
|
|
int rc = -EACCES;
|
2011-05-19 20:22:56 +00:00
|
|
|
WRITE_REQ *smb = NULL;
|
|
|
|
int wct;
|
2023-10-06 17:29:59 +00:00
|
|
|
struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
|
2016-11-23 23:14:57 +00:00
|
|
|
struct kvec iov[2];
|
2012-09-18 23:20:35 +00:00
|
|
|
struct smb_rqst rqst = { };
|
2011-05-19 20:22:56 +00:00
|
|
|
|
|
|
|
if (tcon->ses->capabilities & CAP_LARGE_FILES) {
|
|
|
|
wct = 14;
|
|
|
|
} else {
|
|
|
|
wct = 12;
|
2023-10-06 15:55:20 +00:00
|
|
|
if (wdata->subreq.start >> 32 > 0) {
|
2011-05-19 20:22:56 +00:00
|
|
|
/* can not handle big offset for old srv */
|
2023-10-06 17:29:59 +00:00
|
|
|
rc = -EIO;
|
|
|
|
goto out;
|
2011-05-19 20:22:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
|
|
|
|
if (rc)
|
|
|
|
goto async_writev_out;
|
|
|
|
|
2024-06-20 17:31:29 +00:00
|
|
|
smb->hdr.Pid = cpu_to_le16((__u16)wdata->req->pid);
|
|
|
|
smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->req->pid >> 16));
|
2011-05-26 06:01:59 +00:00
|
|
|
|
2011-05-19 20:22:56 +00:00
|
|
|
smb->AndXCommand = 0xFF; /* none */
|
2023-10-06 17:29:59 +00:00
|
|
|
smb->Fid = wdata->req->cfile->fid.netfid;
|
2023-10-06 15:55:20 +00:00
|
|
|
smb->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF);
|
2011-05-19 20:22:56 +00:00
|
|
|
if (wct == 14)
|
2023-10-06 15:55:20 +00:00
|
|
|
smb->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32);
|
2011-05-19 20:22:56 +00:00
|
|
|
smb->Reserved = 0xFFFFFFFF;
|
|
|
|
smb->WriteMode = 0;
|
|
|
|
smb->Remaining = 0;
|
|
|
|
|
|
|
|
smb->DataOffset =
|
|
|
|
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
|
|
|
|
|
|
|
|
/* 4 for RFC1001 length + 1 for BCC */
|
2016-11-23 23:14:57 +00:00
|
|
|
iov[0].iov_len = 4;
|
|
|
|
iov[0].iov_base = smb;
|
|
|
|
iov[1].iov_len = get_rfc1002_length(smb) + 1;
|
|
|
|
iov[1].iov_base = (char *)smb + 4;
|
2011-05-19 20:22:56 +00:00
|
|
|
|
2016-11-23 23:14:57 +00:00
|
|
|
rqst.rq_iov = iov;
|
|
|
|
rqst.rq_nvec = 2;
|
2023-10-06 15:55:20 +00:00
|
|
|
rqst.rq_iter = wdata->subreq.io_iter;
|
2011-05-19 20:22:56 +00:00
|
|
|
|
2023-10-06 15:55:20 +00:00
|
|
|
cifs_dbg(FYI, "async write at %llu %zu bytes\n",
|
|
|
|
wdata->subreq.start, wdata->subreq.len);
|
2011-05-19 20:22:56 +00:00
|
|
|
|
2023-10-06 15:55:20 +00:00
|
|
|
smb->DataLengthLow = cpu_to_le16(wdata->subreq.len & 0xFFFF);
|
|
|
|
smb->DataLengthHigh = cpu_to_le16(wdata->subreq.len >> 16);
|
2011-05-19 20:22:56 +00:00
|
|
|
|
|
|
|
if (wct == 14) {
|
2023-10-06 15:55:20 +00:00
|
|
|
inc_rfc1001_len(&smb->hdr, wdata->subreq.len + 1);
|
|
|
|
put_bcc(wdata->subreq.len + 1, &smb->hdr);
|
2011-05-19 20:22:56 +00:00
|
|
|
} else {
|
|
|
|
/* wct == 12 */
|
|
|
|
struct smb_com_writex_req *smbw =
|
|
|
|
(struct smb_com_writex_req *)smb;
|
2023-10-06 15:55:20 +00:00
|
|
|
inc_rfc1001_len(&smbw->hdr, wdata->subreq.len + 5);
|
|
|
|
put_bcc(wdata->subreq.len + 5, &smbw->hdr);
|
2016-11-23 23:14:57 +00:00
|
|
|
iov[1].iov_len += 4; /* pad bigger by four bytes */
|
2011-05-19 20:22:56 +00:00
|
|
|
}
|
|
|
|
|
2012-09-18 23:20:35 +00:00
|
|
|
rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
|
2019-01-15 23:52:29 +00:00
|
|
|
cifs_writev_callback, NULL, wdata, 0, NULL);
|
2023-10-06 17:29:59 +00:00
|
|
|
/* Can't touch wdata if rc == 0 */
|
2011-05-19 20:22:56 +00:00
|
|
|
if (rc == 0)
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
|
2011-05-19 20:22:56 +00:00
|
|
|
|
|
|
|
async_writev_out:
|
|
|
|
cifs_small_buf_release(smb);
|
2023-10-06 17:29:59 +00:00
|
|
|
out:
|
|
|
|
if (rc) {
|
|
|
|
add_credits_and_wake_if(wdata->server, &wdata->credits, 0);
|
|
|
|
cifs_write_subrequest_terminated(wdata, rc, false);
|
|
|
|
}
|
2011-05-19 20:22:56 +00:00
|
|
|
}
|
|
|
|
|
2005-06-13 18:24:43 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
|
2012-09-18 23:20:30 +00:00
|
|
|
unsigned int *nbytes, struct kvec *iov, int n_vec)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2020-05-27 12:50:31 +00:00
|
|
|
int rc;
|
2005-04-16 22:20:36 +00:00
|
|
|
WRITE_REQ *pSMB = NULL;
|
2005-12-13 04:53:18 +00:00
|
|
|
int wct;
|
2005-06-13 18:24:43 +00:00
|
|
|
int smb_hdr_len;
|
2005-12-13 04:53:18 +00:00
|
|
|
int resp_buf_type = 0;
|
2011-05-26 06:01:59 +00:00
|
|
|
__u32 pid = io_parms->pid;
|
|
|
|
__u16 netfid = io_parms->netfid;
|
|
|
|
__u64 offset = io_parms->offset;
|
2011-05-27 04:34:02 +00:00
|
|
|
struct cifs_tcon *tcon = io_parms->tcon;
|
2011-05-26 06:01:59 +00:00
|
|
|
unsigned int count = io_parms->length;
|
2016-10-25 18:38:47 +00:00
|
|
|
struct kvec rsp_iov;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2009-04-03 17:44:00 +00:00
|
|
|
*nbytes = 0;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
|
2005-11-16 00:45:16 +00:00
|
|
|
|
2008-12-09 00:28:16 +00:00
|
|
|
if (tcon->ses->capabilities & CAP_LARGE_FILES) {
|
2005-10-03 20:49:43 +00:00
|
|
|
wct = 14;
|
2008-12-09 00:28:16 +00:00
|
|
|
} else {
|
2005-10-03 20:49:43 +00:00
|
|
|
wct = 12;
|
2008-12-09 00:28:16 +00:00
|
|
|
if ((offset >> 32) > 0) {
|
|
|
|
/* can not handle big offset for old srv */
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
}
|
2005-10-03 20:49:43 +00:00
|
|
|
rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
2011-05-26 06:01:59 +00:00
|
|
|
|
|
|
|
pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
|
|
|
|
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/* tcon and ses pointer are checked in smb_init */
|
|
|
|
if (tcon->ses->server == NULL)
|
|
|
|
return -ECONNABORTED;
|
|
|
|
|
2005-06-13 18:24:43 +00:00
|
|
|
pSMB->AndXCommand = 0xFF; /* none */
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->Fid = netfid;
|
|
|
|
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (wct == 14)
|
2005-10-03 20:49:43 +00:00
|
|
|
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->Reserved = 0xFFFFFFFF;
|
|
|
|
pSMB->WriteMode = 0;
|
|
|
|
pSMB->Remaining = 0;
|
2005-06-13 18:24:43 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataOffset =
|
2007-07-13 00:33:32 +00:00
|
|
|
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2005-10-03 20:37:24 +00:00
|
|
|
pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
|
|
|
|
pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
|
2011-04-29 05:40:20 +00:00
|
|
|
/* header + 1 byte pad */
|
|
|
|
smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
|
2007-07-07 19:25:05 +00:00
|
|
|
if (wct == 14)
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, count + 1);
|
2005-10-03 20:49:43 +00:00
|
|
|
else /* wct == 12 */
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (wct == 14)
|
2005-10-03 20:49:43 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(count + 1);
|
|
|
|
else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_writex_req *pSMBW =
|
2005-10-03 20:49:43 +00:00
|
|
|
(struct smb_com_writex_req *)pSMB;
|
|
|
|
pSMBW->ByteCount = cpu_to_le16(count + 5);
|
|
|
|
}
|
2005-10-03 20:37:24 +00:00
|
|
|
iov[0].iov_base = pSMB;
|
2007-07-07 19:25:05 +00:00
|
|
|
if (wct == 14)
|
2005-12-13 04:53:18 +00:00
|
|
|
iov[0].iov_len = smb_hdr_len + 4;
|
|
|
|
else /* wct == 12 pad bigger by four bytes */
|
|
|
|
iov[0].iov_len = smb_hdr_len + 8;
|
2007-07-13 00:33:32 +00:00
|
|
|
|
2016-10-25 18:38:47 +00:00
|
|
|
rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
|
|
|
|
&rsp_iov);
|
|
|
|
cifs_small_buf_release(pSMB);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
|
2007-07-07 19:25:05 +00:00
|
|
|
} else if (resp_buf_type == 0) {
|
2005-12-13 04:53:18 +00:00
|
|
|
/* presumably this can not happen, but best to be safe */
|
|
|
|
rc = -EIO;
|
2005-06-13 18:24:43 +00:00
|
|
|
} else {
|
2016-10-25 18:38:47 +00:00
|
|
|
WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
|
2005-06-13 18:24:43 +00:00
|
|
|
*nbytes = le16_to_cpu(pSMBr->CountHigh);
|
|
|
|
*nbytes = (*nbytes) << 16;
|
|
|
|
*nbytes += le16_to_cpu(pSMBr->Count);
|
2010-03-31 06:30:03 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Mask off high 16 bits when bytes written as returned by the
|
|
|
|
* server is greater than bytes requested by the client. OS/2
|
|
|
|
* servers are known to set incorrect CountHigh values.
|
|
|
|
*/
|
|
|
|
if (*nbytes > count)
|
|
|
|
*nbytes &= 0xFFFF;
|
2007-07-13 00:33:32 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2016-10-25 18:38:47 +00:00
|
|
|
free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
2005-04-16 22:20:36 +00:00
|
|
|
since file handle passed in no longer valid */
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2005-06-13 18:24:43 +00:00
|
|
|
|
2012-06-20 07:21:16 +00:00
|
|
|
int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
|
2011-10-22 11:33:31 +00:00
|
|
|
const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
LOCK_REQ *pSMB = NULL;
|
|
|
|
struct kvec iov[2];
|
2016-10-25 18:38:47 +00:00
|
|
|
struct kvec rsp_iov;
|
2011-10-22 11:33:31 +00:00
|
|
|
int resp_buf_type;
|
|
|
|
__u16 count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
|
|
|
|
num_lock, num_unlock);
|
2011-10-22 11:33:31 +00:00
|
|
|
|
|
|
|
rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->NumberOfLocks = cpu_to_le16(num_lock);
|
|
|
|
pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
|
|
|
|
pSMB->LockType = lock_type;
|
|
|
|
pSMB->AndXCommand = 0xFF; /* none */
|
|
|
|
pSMB->Fid = netfid; /* netfid stays le */
|
|
|
|
|
|
|
|
count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
|
|
|
|
inc_rfc1001_len(pSMB, count);
|
|
|
|
pSMB->ByteCount = cpu_to_le16(count);
|
|
|
|
|
|
|
|
iov[0].iov_base = (char *)pSMB;
|
|
|
|
iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
|
|
|
|
(num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
|
|
|
|
iov[1].iov_base = (char *)buf;
|
|
|
|
iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
|
|
|
|
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
|
2019-05-06 00:00:02 +00:00
|
|
|
rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
|
|
|
|
CIFS_NO_RSP_BUF, &rsp_iov);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2011-10-22 11:33:31 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
|
2011-10-22 11:33:31 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2005-06-13 18:24:43 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
|
2010-08-17 07:26:00 +00:00
|
|
|
const __u16 smb_file_id, const __u32 netpid, const __u64 len,
|
2005-04-16 22:20:36 +00:00
|
|
|
const __u64 offset, const __u32 numUnlock,
|
2011-01-17 17:15:44 +00:00
|
|
|
const __u32 numLock, const __u8 lockType,
|
|
|
|
const bool waitFlag, const __u8 oplock_level)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
LOCK_REQ *pSMB = NULL;
|
2008-05-23 17:38:32 +00:00
|
|
|
/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
|
2005-04-16 22:20:36 +00:00
|
|
|
int bytes_returned;
|
2012-05-23 12:14:34 +00:00
|
|
|
int flags = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
__u16 count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
|
|
|
|
(int)waitFlag, numLock);
|
2005-04-29 05:41:09 +00:00
|
|
|
rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
|
2012-05-23 12:14:34 +00:00
|
|
|
/* no response expected */
|
2019-05-06 00:00:02 +00:00
|
|
|
flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->Timeout = 0;
|
2008-04-29 00:06:05 +00:00
|
|
|
} else if (waitFlag) {
|
2012-05-23 12:14:34 +00:00
|
|
|
flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
|
|
|
|
} else {
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pSMB->NumberOfLocks = cpu_to_le16(numLock);
|
|
|
|
pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
|
|
|
|
pSMB->LockType = lockType;
|
2011-01-17 17:15:44 +00:00
|
|
|
pSMB->OplockLevel = oplock_level;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->AndXCommand = 0xFF; /* none */
|
|
|
|
pSMB->Fid = smb_file_id; /* netfid stays le */
|
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if ((numLock != 0) || (numUnlock != 0)) {
|
2010-08-17 07:26:00 +00:00
|
|
|
pSMB->Locks[0].Pid = cpu_to_le16(netpid);
|
2005-04-16 22:20:36 +00:00
|
|
|
/* BB where to store pid high? */
|
|
|
|
pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
|
|
|
|
pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
|
|
|
|
pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
|
|
|
|
pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
|
|
|
|
count = sizeof(LOCKING_ANDX_RANGE);
|
|
|
|
} else {
|
|
|
|
/* oplock break */
|
|
|
|
count = 0;
|
|
|
|
}
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(count);
|
|
|
|
|
2016-10-25 18:38:47 +00:00
|
|
|
if (waitFlag)
|
2006-08-02 21:56:33 +00:00
|
|
|
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
|
2008-05-23 17:38:32 +00:00
|
|
|
(struct smb_hdr *) pSMB, &bytes_returned);
|
2016-10-25 18:38:47 +00:00
|
|
|
else
|
2012-05-23 12:14:34 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
2005-04-16 22:20:36 +00:00
|
|
|
since file handle passed in no longer valid */
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2006-02-28 22:39:25 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
|
2012-07-23 17:28:37 +00:00
|
|
|
const __u16 smb_file_id, const __u32 netpid,
|
|
|
|
const loff_t start_offset, const __u64 len,
|
|
|
|
struct file_lock *pLockData, const __u16 lock_type,
|
|
|
|
const bool waitFlag)
|
2006-02-28 22:39:25 +00:00
|
|
|
{
|
|
|
|
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
|
|
|
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
|
|
|
|
struct cifs_posix_lock *parm_data;
|
|
|
|
int rc = 0;
|
2006-07-14 22:37:11 +00:00
|
|
|
int timeout = 0;
|
2006-02-28 22:39:25 +00:00
|
|
|
int bytes_returned = 0;
|
2007-11-13 22:41:37 +00:00
|
|
|
int resp_buf_type = 0;
|
2006-02-28 22:39:25 +00:00
|
|
|
__u16 params, param_offset, offset, byte_count, count;
|
2007-11-13 22:41:37 +00:00
|
|
|
struct kvec iov[1];
|
2016-10-25 18:38:47 +00:00
|
|
|
struct kvec rsp_iov;
|
2006-02-28 22:39:25 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Posix Lock\n");
|
2006-05-30 18:03:32 +00:00
|
|
|
|
2006-02-28 22:39:25 +00:00
|
|
|
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
|
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
params = 6;
|
2006-02-28 22:39:25 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
|
|
|
offset = param_offset + params;
|
|
|
|
|
|
|
|
count = sizeof(struct cifs_posix_lock);
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-02-07 23:25:02 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
|
2006-02-28 22:39:25 +00:00
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
2012-07-23 17:28:37 +00:00
|
|
|
if (pLockData)
|
2006-02-28 22:39:25 +00:00
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
|
|
|
|
else
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + count;
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
2021-07-07 19:03:54 +00:00
|
|
|
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
|
2007-07-13 00:33:32 +00:00
|
|
|
parm_data = (struct cifs_posix_lock *)
|
2021-07-07 19:03:54 +00:00
|
|
|
(((char *)pSMB) + offset + 4);
|
2006-02-28 22:39:25 +00:00
|
|
|
|
|
|
|
parm_data->lock_type = cpu_to_le16(lock_type);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (waitFlag) {
|
2007-11-13 22:41:37 +00:00
|
|
|
timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
|
2006-05-30 18:07:17 +00:00
|
|
|
parm_data->lock_flags = cpu_to_le16(1);
|
2006-07-14 22:37:11 +00:00
|
|
|
pSMB->Timeout = cpu_to_le32(-1);
|
|
|
|
} else
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
|
2011-10-22 11:33:30 +00:00
|
|
|
parm_data->pid = cpu_to_le32(netpid);
|
2012-07-23 17:28:37 +00:00
|
|
|
parm_data->start = cpu_to_le64(start_offset);
|
2006-05-30 18:07:17 +00:00
|
|
|
parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
|
2006-02-28 22:39:25 +00:00
|
|
|
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
2006-03-01 09:17:37 +00:00
|
|
|
pSMB->Fid = smb_file_id;
|
2006-02-28 22:39:25 +00:00
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2006-02-28 22:39:25 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
2006-08-02 21:56:33 +00:00
|
|
|
if (waitFlag) {
|
|
|
|
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned);
|
|
|
|
} else {
|
2007-11-13 22:41:37 +00:00
|
|
|
iov[0].iov_base = (char *)pSMB;
|
2011-04-29 05:40:20 +00:00
|
|
|
iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
|
2007-11-13 22:41:37 +00:00
|
|
|
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
|
2016-10-25 18:38:47 +00:00
|
|
|
&resp_buf_type, timeout, &rsp_iov);
|
|
|
|
pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
|
2006-08-02 21:56:33 +00:00
|
|
|
}
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2006-08-02 21:56:33 +00:00
|
|
|
|
2006-02-28 22:39:25 +00:00
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
|
2012-07-23 17:28:37 +00:00
|
|
|
} else if (pLockData) {
|
2006-05-30 18:03:32 +00:00
|
|
|
/* lock structure can be returned on get */
|
|
|
|
__u16 data_offset;
|
|
|
|
__u16 data_count;
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
|
2006-05-30 18:03:32 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
goto plk_err_exit;
|
|
|
|
}
|
|
|
|
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
data_count = le16_to_cpu(pSMBr->t2.DataCount);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (data_count < sizeof(struct cifs_posix_lock)) {
|
2006-05-30 18:03:32 +00:00
|
|
|
rc = -EIO;
|
|
|
|
goto plk_err_exit;
|
|
|
|
}
|
|
|
|
parm_data = (struct cifs_posix_lock *)
|
|
|
|
((char *)&pSMBr->hdr.Protocol + data_offset);
|
2014-12-10 23:41:15 +00:00
|
|
|
if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
|
2024-01-31 23:02:25 +00:00
|
|
|
pLockData->c.flc_type = F_UNLCK;
|
2010-04-05 05:59:14 +00:00
|
|
|
else {
|
|
|
|
if (parm_data->lock_type ==
|
2014-12-10 23:41:15 +00:00
|
|
|
cpu_to_le16(CIFS_RDLCK))
|
2024-01-31 23:02:25 +00:00
|
|
|
pLockData->c.flc_type = F_RDLCK;
|
2010-04-05 05:59:14 +00:00
|
|
|
else if (parm_data->lock_type ==
|
2014-12-10 23:41:15 +00:00
|
|
|
cpu_to_le16(CIFS_WRLCK))
|
2024-01-31 23:02:25 +00:00
|
|
|
pLockData->c.flc_type = F_WRLCK;
|
2010-04-05 05:59:14 +00:00
|
|
|
|
2011-03-13 05:08:25 +00:00
|
|
|
pLockData->fl_start = le64_to_cpu(parm_data->start);
|
|
|
|
pLockData->fl_end = pLockData->fl_start +
|
2022-05-19 15:18:37 +00:00
|
|
|
(le64_to_cpu(parm_data->length) ?
|
|
|
|
le64_to_cpu(parm_data->length) - 1 : 0);
|
2024-01-31 23:02:25 +00:00
|
|
|
pLockData->c.flc_pid = -le32_to_cpu(parm_data->pid);
|
2010-04-05 05:59:14 +00:00
|
|
|
}
|
2006-02-28 22:39:25 +00:00
|
|
|
}
|
2007-07-13 00:33:32 +00:00
|
|
|
|
2006-05-30 18:03:32 +00:00
|
|
|
plk_err_exit:
|
2016-10-25 18:38:47 +00:00
|
|
|
free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
|
2007-11-13 22:41:37 +00:00
|
|
|
|
2006-02-28 22:39:25 +00:00
|
|
|
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
|
|
|
since file handle passed in no longer valid */
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
CLOSE_REQ *pSMB = NULL;
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In CIFSSMBClose\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* do not retry on dead session on close */
|
|
|
|
rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (rc == -EAGAIN)
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->FileID = (__u16) smb_file_id;
|
2006-10-02 05:53:29 +00:00
|
|
|
pSMB->LastWriteTime = 0xFFFFFFFF;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = 0;
|
2012-03-23 18:28:02 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc) {
|
2007-07-07 19:25:05 +00:00
|
|
|
if (rc != -EINTR) {
|
2005-04-16 22:20:36 +00:00
|
|
|
/* EINTR is expected when user ctl-c to kill app */
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Send error in Close = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Since session is dead, file will be closed on server already */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (rc == -EAGAIN)
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2009-02-21 21:17:43 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
|
2009-02-21 21:17:43 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
FLUSH_REQ *pSMB = NULL;
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In CIFSSMBFlush\n");
|
2009-02-21 21:17:43 +00:00
|
|
|
|
|
|
|
rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->FileID = (__u16) smb_file_id;
|
|
|
|
pSMB->ByteCount = 0;
|
2012-03-23 18:28:02 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
|
2009-02-21 21:17:43 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
|
2009-02-21 21:17:43 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2023-11-26 02:55:06 +00:00
|
|
|
int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct dentry *source_dentry,
|
|
|
|
const char *from_name, const char *to_name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
RENAME_REQ *pSMB = NULL;
|
|
|
|
RENAME_RSP *pSMBr = NULL;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len, name_len2;
|
|
|
|
__u16 count;
|
2014-09-27 07:19:01 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In CIFSSMBRename\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
renameRetry:
|
|
|
|
rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->BufferFormat = 0x04;
|
|
|
|
pSMB->SearchAttributes =
|
|
|
|
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
|
|
|
|
ATTR_DIRECTORY);
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
2012-09-18 23:20:30 +00:00
|
|
|
name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
|
|
|
|
from_name, PATH_MAX,
|
|
|
|
cifs_sb->local_nls, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
|
|
|
pSMB->OldFileName[name_len] = 0x04; /* pad */
|
|
|
|
/* protocol requires ASCII signature byte on Unicode string */
|
|
|
|
pSMB->OldFileName[name_len + 1] = 0x00;
|
|
|
|
name_len2 =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
|
2012-09-18 23:20:30 +00:00
|
|
|
to_name, PATH_MAX, cifs_sb->local_nls,
|
|
|
|
remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
|
|
|
|
name_len2 *= 2; /* convert to bytes */
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->OldFileName, from_name);
|
|
|
|
name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
|
|
|
|
name_len2++; /* signature byte */
|
|
|
|
}
|
|
|
|
|
|
|
|
count = 1 /* 1st signature byte */ + name_len + name_len2;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in rename = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto renameRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-06-20 07:21:16 +00:00
|
|
|
int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
|
2008-09-24 15:32:59 +00:00
|
|
|
int netfid, const char *target_name,
|
2007-07-13 00:33:32 +00:00
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
|
|
|
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
|
2007-07-13 00:33:32 +00:00
|
|
|
struct set_file_rename *rename_info;
|
2005-04-16 22:20:36 +00:00
|
|
|
char *data_offset;
|
|
|
|
char dummy_string[30];
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
int len_of_str;
|
|
|
|
__u16 params, param_offset, offset, count, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Rename to File by handle\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 6;
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
|
|
|
offset = param_offset + params;
|
|
|
|
|
2021-07-07 18:34:47 +00:00
|
|
|
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
|
|
|
|
data_offset = (char *)(pSMB) + offset + 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
rename_info = (struct set_file_rename *) data_offset;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-02-07 23:25:02 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params;
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
/* construct random name ".cifs_tmp<inodenum><mid>" */
|
|
|
|
rename_info->overwrite = cpu_to_le32(1);
|
|
|
|
rename_info->root_fid = 0;
|
|
|
|
/* unicode only call */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (target_name == NULL) {
|
2007-07-13 00:33:32 +00:00
|
|
|
sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
|
2012-01-19 04:32:33 +00:00
|
|
|
len_of_str =
|
|
|
|
cifsConvertToUTF16((__le16 *)rename_info->target_name,
|
2005-04-29 05:41:06 +00:00
|
|
|
dummy_string, 24, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2012-01-19 04:32:33 +00:00
|
|
|
len_of_str =
|
|
|
|
cifsConvertToUTF16((__le16 *)rename_info->target_name,
|
2007-07-13 00:33:32 +00:00
|
|
|
target_name, PATH_MAX, nls_codepage,
|
|
|
|
remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
|
2022-10-13 03:53:09 +00:00
|
|
|
count = sizeof(struct set_file_rename) + (2 * len_of_str);
|
2005-04-16 22:20:36 +00:00
|
|
|
byte_count += count;
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->Fid = netfid;
|
|
|
|
pSMB->InformationLevel =
|
|
|
|
cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
|
2007-07-13 00:33:32 +00:00
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
|
|
|
|
rc);
|
2005-08-21 04:42:53 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
|
|
|
since file handle passed in no longer valid */
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
|
2005-04-16 22:20:36 +00:00
|
|
|
const char *fromName, const char *toName,
|
2015-02-13 06:35:58 +00:00
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
|
|
|
char *data_offset;
|
|
|
|
int name_len;
|
|
|
|
int name_len_target;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, param_offset, offset, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In Symlink Unix style\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
createSymLinkRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2015-02-13 06:35:58 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
|
|
|
|
/* find define for this maxpathcomponent */
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
|
|
|
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, fromName);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
params = 6 + name_len;
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
2007-07-13 00:33:32 +00:00
|
|
|
InformationLevel) - 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
offset = param_offset + params;
|
|
|
|
|
2021-07-02 01:44:27 +00:00
|
|
|
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
|
|
|
|
data_offset = (char *)pSMB + offset + 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len_target =
|
2015-02-13 06:35:58 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) data_offset, toName,
|
|
|
|
/* find define for this maxpathcomponent */
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len_target++; /* trailing null */
|
|
|
|
name_len_target *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len_target = copy_path_name(data_offset, toName);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
/* BB find exact max on data count below from sess */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + name_len_target;
|
|
|
|
pSMB->DataCount = cpu_to_le16(name_len_target);
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
|
|
|
|
rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-05-22 02:02:03 +00:00
|
|
|
cifs_buf_release(pSMB);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto createSymLinkRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
|
2005-04-16 22:20:36 +00:00
|
|
|
const char *fromName, const char *toName,
|
2005-04-29 05:41:06 +00:00
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
|
|
|
char *data_offset;
|
|
|
|
int name_len;
|
|
|
|
int name_len_target;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, param_offset, offset, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In Create Hard link Unix style\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
createHardLinkRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
2012-01-19 04:32:33 +00:00
|
|
|
name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
|
|
|
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, toName);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
params = 6 + name_len;
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
2007-07-13 00:33:32 +00:00
|
|
|
InformationLevel) - 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
offset = param_offset + params;
|
|
|
|
|
2021-07-01 22:46:23 +00:00
|
|
|
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
|
|
|
|
data_offset = (char *)pSMB + offset + 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len_target =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) data_offset, fromName,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len_target++; /* trailing null */
|
|
|
|
name_len_target *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len_target = copy_path_name(data_offset, fromName);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
/* BB find exact max on data count below from sess*/
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + name_len_target;
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->DataCount = cpu_to_le16(name_len_target);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
|
|
|
|
rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto createHardLinkRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2023-11-26 02:55:07 +00:00
|
|
|
int CIFSCreateHardLink(const unsigned int xid,
|
|
|
|
struct cifs_tcon *tcon,
|
|
|
|
struct dentry *source_dentry,
|
|
|
|
const char *from_name, const char *to_name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
NT_RENAME_REQ *pSMB = NULL;
|
|
|
|
RENAME_RSP *pSMBr = NULL;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len, name_len2;
|
|
|
|
__u16 count;
|
2014-09-27 07:19:01 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In CIFSCreateHardLink\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
winCreateHardLinkRetry:
|
|
|
|
|
|
|
|
rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->SearchAttributes =
|
|
|
|
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
|
|
|
|
ATTR_DIRECTORY);
|
|
|
|
pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
|
|
|
|
pSMB->ClusterCount = 0;
|
|
|
|
|
|
|
|
pSMB->BufferFormat = 0x04;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-09-18 23:20:31 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
|
|
|
|
PATH_MAX, cifs_sb->local_nls, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2009-02-28 17:59:03 +00:00
|
|
|
|
|
|
|
/* protocol specifies ASCII buffer format (0x04) for unicode */
|
|
|
|
pSMB->OldFileName[name_len] = 0x04;
|
|
|
|
pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len2 =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
|
2012-09-18 23:20:31 +00:00
|
|
|
to_name, PATH_MAX, cifs_sb->local_nls,
|
|
|
|
remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
|
|
|
|
name_len2 *= 2; /* convert to bytes */
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->OldFileName, from_name);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
|
2019-08-26 23:30:14 +00:00
|
|
|
name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len2++; /* signature byte */
|
|
|
|
}
|
|
|
|
|
|
|
|
count = 1 /* string type byte */ + name_len + name_len2;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
|
2008-02-07 23:25:02 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto winCreateHardLinkRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
|
2009-04-30 11:17:56 +00:00
|
|
|
const unsigned char *searchName, char **symlinkinfo,
|
2015-02-13 06:35:58 +00:00
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* SMB_QUERY_FILE_UNIX_LINK */
|
|
|
|
TRANSACTION2_QPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QPI_RSP *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
|
|
|
__u16 params, byte_count;
|
2009-04-30 11:17:56 +00:00
|
|
|
char *data_start;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
querySymLinkRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2015-02-13 06:35:58 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName,
|
|
|
|
searchName, PATH_MAX, nls_codepage,
|
|
|
|
remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, searchName);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2009-05-24 22:45:17 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
/* decode response */
|
|
|
|
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
/* BB also check enough total bytes returned */
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 2)
|
2009-04-30 11:17:56 +00:00
|
|
|
rc = -EIO;
|
2005-04-16 22:20:36 +00:00
|
|
|
else {
|
2009-05-01 05:27:32 +00:00
|
|
|
bool is_unicode;
|
2009-04-30 11:17:56 +00:00
|
|
|
u16 count = le16_to_cpu(pSMBr->t2.DataCount);
|
|
|
|
|
|
|
|
data_start = ((char *) &pSMBr->hdr.Protocol) +
|
|
|
|
le16_to_cpu(pSMBr->t2.DataOffset);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2009-05-01 05:27:32 +00:00
|
|
|
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
|
|
|
|
is_unicode = true;
|
|
|
|
else
|
|
|
|
is_unicode = false;
|
|
|
|
|
2005-04-29 05:41:06 +00:00
|
|
|
/* BB FIXME investigate remapping reserved chars here */
|
2012-01-19 04:32:33 +00:00
|
|
|
*symlinkinfo = cifs_strndup_from_utf16(data_start,
|
|
|
|
count, is_unicode, nls_codepage);
|
2009-05-19 13:57:03 +00:00
|
|
|
if (!*symlinkinfo)
|
2009-04-30 11:17:56 +00:00
|
|
|
rc = -ENOMEM;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto querySymLinkRetry;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2023-11-21 23:12:52 +00:00
|
|
|
int cifs_query_reparse_point(const unsigned int xid,
|
|
|
|
struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb,
|
|
|
|
const char *full_path,
|
|
|
|
u32 *tag, struct kvec *rsp,
|
|
|
|
int *rsp_buftype)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2024-01-06 23:05:18 +00:00
|
|
|
struct reparse_data_buffer *buf;
|
2023-11-21 23:12:52 +00:00
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
TRANSACT_IOCTL_REQ *io_req = NULL;
|
|
|
|
TRANSACT_IOCTL_RSP *io_rsp = NULL;
|
|
|
|
struct cifs_fid fid;
|
2024-01-06 23:05:18 +00:00
|
|
|
__u32 data_offset, data_count, len;
|
2023-11-21 23:12:52 +00:00
|
|
|
__u8 *start, *end;
|
|
|
|
int io_rsp_len;
|
|
|
|
int oplock = 0;
|
|
|
|
int rc;
|
2013-08-14 15:25:22 +00:00
|
|
|
|
2023-11-21 23:12:52 +00:00
|
|
|
cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
|
|
|
|
|
|
|
|
if (cap_unix(tcon->ses))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
oparms = (struct cifs_open_parms) {
|
|
|
|
.tcon = tcon,
|
|
|
|
.cifs_sb = cifs_sb,
|
|
|
|
.desired_access = FILE_READ_ATTRIBUTES,
|
|
|
|
.create_options = cifs_create_options(cifs_sb,
|
|
|
|
OPEN_REPARSE_POINT),
|
|
|
|
.disposition = FILE_OPEN,
|
|
|
|
.path = full_path,
|
|
|
|
.fid = &fid,
|
|
|
|
};
|
|
|
|
|
|
|
|
rc = CIFS_open(xid, &oparms, &oplock, NULL);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2023-11-21 23:12:52 +00:00
|
|
|
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon,
|
|
|
|
(void **)&io_req, (void **)&io_rsp);
|
|
|
|
if (rc)
|
|
|
|
goto error;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-11-21 23:12:52 +00:00
|
|
|
io_req->TotalParameterCount = 0;
|
|
|
|
io_req->TotalDataCount = 0;
|
|
|
|
io_req->MaxParameterCount = cpu_to_le32(2);
|
|
|
|
/* BB find exact data count max from sess structure BB */
|
|
|
|
io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
|
|
|
|
io_req->MaxSetupCount = 4;
|
|
|
|
io_req->Reserved = 0;
|
|
|
|
io_req->ParameterOffset = 0;
|
|
|
|
io_req->DataCount = 0;
|
|
|
|
io_req->DataOffset = 0;
|
|
|
|
io_req->SetupCount = 4;
|
|
|
|
io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
|
|
|
|
io_req->ParameterCount = io_req->TotalParameterCount;
|
|
|
|
io_req->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
|
|
|
|
io_req->IsFsctl = 1;
|
|
|
|
io_req->IsRootFlag = 0;
|
|
|
|
io_req->Fid = fid.netfid;
|
|
|
|
io_req->ByteCount = 0;
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req,
|
|
|
|
(struct smb_hdr *)io_rsp, &io_rsp_len, 0);
|
|
|
|
if (rc)
|
|
|
|
goto error;
|
2013-08-14 15:25:22 +00:00
|
|
|
|
2023-11-21 23:12:52 +00:00
|
|
|
data_offset = le32_to_cpu(io_rsp->DataOffset);
|
|
|
|
data_count = le32_to_cpu(io_rsp->DataCount);
|
|
|
|
if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 ||
|
|
|
|
!data_count || data_count > 2048) {
|
2013-08-14 15:25:22 +00:00
|
|
|
rc = -EIO;
|
2023-11-21 23:12:52 +00:00
|
|
|
goto error;
|
2013-08-14 15:25:22 +00:00
|
|
|
}
|
2013-09-28 23:24:12 +00:00
|
|
|
|
2023-11-21 23:12:52 +00:00
|
|
|
end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount;
|
|
|
|
start = (__u8 *)&io_rsp->hdr.Protocol + data_offset;
|
|
|
|
if (start >= end) {
|
2013-08-14 15:25:22 +00:00
|
|
|
rc = -EIO;
|
2023-11-21 23:12:52 +00:00
|
|
|
goto error;
|
2013-08-14 15:25:22 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2024-01-06 23:05:18 +00:00
|
|
|
data_count = le16_to_cpu(io_rsp->ByteCount);
|
|
|
|
buf = (struct reparse_data_buffer *)start;
|
|
|
|
len = sizeof(*buf);
|
|
|
|
if (data_count < len ||
|
|
|
|
data_count < le16_to_cpu(buf->ReparseDataLength) + len) {
|
|
|
|
rc = -EIO;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
*tag = le32_to_cpu(buf->ReparseTag);
|
2023-11-21 23:12:52 +00:00
|
|
|
rsp->iov_base = io_rsp;
|
|
|
|
rsp->iov_len = io_rsp_len;
|
|
|
|
*rsp_buftype = CIFS_LARGE_BUFFER;
|
|
|
|
CIFSSMBClose(xid, tcon, fid.netfid);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
cifs_buf_release(io_req);
|
|
|
|
CIFSSMBClose(xid, tcon, fid.netfid);
|
2005-04-16 22:20:36 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-10-14 20:27:32 +00:00
|
|
|
int
|
|
|
|
CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
__u16 fid)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
struct smb_com_transaction_compr_ioctl_req *pSMB;
|
|
|
|
struct smb_com_transaction_ioctl_rsp *pSMBr;
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "Set compression for %u\n", fid);
|
|
|
|
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
|
|
|
|
|
|
|
|
pSMB->TotalParameterCount = 0;
|
2014-12-10 23:41:15 +00:00
|
|
|
pSMB->TotalDataCount = cpu_to_le32(2);
|
2013-10-14 20:27:32 +00:00
|
|
|
pSMB->MaxParameterCount = 0;
|
|
|
|
pSMB->MaxDataCount = 0;
|
|
|
|
pSMB->MaxSetupCount = 4;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->ParameterOffset = 0;
|
2014-12-10 23:41:15 +00:00
|
|
|
pSMB->DataCount = cpu_to_le32(2);
|
2013-10-14 20:27:32 +00:00
|
|
|
pSMB->DataOffset =
|
|
|
|
cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
|
|
|
|
compression_state) - 4); /* 84 */
|
|
|
|
pSMB->SetupCount = 4;
|
2014-12-10 23:41:15 +00:00
|
|
|
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
|
2013-10-14 20:27:32 +00:00
|
|
|
pSMB->ParameterCount = 0;
|
2014-12-10 23:41:15 +00:00
|
|
|
pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
|
2013-10-14 20:27:32 +00:00
|
|
|
pSMB->IsFsctl = 1; /* FSCTL */
|
|
|
|
pSMB->IsRootFlag = 0;
|
|
|
|
pSMB->Fid = fid; /* file handle always le */
|
|
|
|
/* 3 byte pad, followed by 2 byte compress state */
|
2014-12-10 23:41:15 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(5);
|
2013-10-14 20:27:32 +00:00
|
|
|
inc_rfc1001_len(pSMB, 5);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc)
|
|
|
|
cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
|
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: On -EAGAIN error only caller can retry on handle based calls
|
|
|
|
* since file handle passed in no longer valid.
|
|
|
|
*/
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef CONFIG_CIFS_POSIX
|
|
|
|
|
2022-09-22 15:17:02 +00:00
|
|
|
#ifdef CONFIG_FS_POSIX_ACL
|
|
|
|
/**
|
|
|
|
* cifs_init_posix_acl - convert ACL from cifs to POSIX ACL format
|
|
|
|
* @ace: POSIX ACL entry to store converted ACL into
|
|
|
|
* @cifs_ace: ACL in cifs format
|
|
|
|
*
|
|
|
|
* Convert an Access Control Entry from wire format to local POSIX xattr
|
|
|
|
* format.
|
|
|
|
*
|
|
|
|
* Note that the @cifs_uid member is used to store both {g,u}id_t.
|
|
|
|
*/
|
|
|
|
static void cifs_init_posix_acl(struct posix_acl_entry *ace,
|
|
|
|
struct cifs_posix_ace *cifs_ace)
|
|
|
|
{
|
|
|
|
/* u8 cifs fields do not need le conversion */
|
|
|
|
ace->e_perm = cifs_ace->cifs_e_perm;
|
|
|
|
ace->e_tag = cifs_ace->cifs_e_tag;
|
|
|
|
|
|
|
|
switch (ace->e_tag) {
|
|
|
|
case ACL_USER:
|
|
|
|
ace->e_uid = make_kuid(&init_user_ns,
|
|
|
|
le64_to_cpu(cifs_ace->cifs_uid));
|
|
|
|
break;
|
|
|
|
case ACL_GROUP:
|
|
|
|
ace->e_gid = make_kgid(&init_user_ns,
|
|
|
|
le64_to_cpu(cifs_ace->cifs_uid));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* cifs_to_posix_acl - copy cifs ACL format to POSIX ACL format
|
|
|
|
* @acl: ACLs returned in POSIX ACL format
|
|
|
|
* @src: ACLs in cifs format
|
|
|
|
* @acl_type: type of POSIX ACL requested
|
|
|
|
* @size_of_data_area: size of SMB we got
|
|
|
|
*
|
|
|
|
* This function converts ACLs from cifs format to POSIX ACL format.
|
|
|
|
* If @acl is NULL then the size of the buffer required to store POSIX ACLs in
|
|
|
|
* their uapi format is returned.
|
|
|
|
*/
|
|
|
|
static int cifs_to_posix_acl(struct posix_acl **acl, char *src,
|
|
|
|
const int acl_type, const int size_of_data_area)
|
|
|
|
{
|
|
|
|
int size = 0;
|
|
|
|
__u16 count;
|
|
|
|
struct cifs_posix_ace *pACE;
|
|
|
|
struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
|
|
|
|
struct posix_acl *kacl = NULL;
|
|
|
|
struct posix_acl_entry *pa, *pe;
|
|
|
|
|
|
|
|
if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (acl_type == ACL_TYPE_ACCESS) {
|
|
|
|
count = le16_to_cpu(cifs_acl->access_entry_count);
|
|
|
|
pACE = &cifs_acl->ace_array[0];
|
|
|
|
size = sizeof(struct cifs_posix_acl);
|
|
|
|
size += sizeof(struct cifs_posix_ace) * count;
|
|
|
|
/* check if we would go beyond end of SMB */
|
|
|
|
if (size_of_data_area < size) {
|
|
|
|
cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
|
|
|
|
size_of_data_area, size);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
} else if (acl_type == ACL_TYPE_DEFAULT) {
|
|
|
|
count = le16_to_cpu(cifs_acl->access_entry_count);
|
|
|
|
size = sizeof(struct cifs_posix_acl);
|
|
|
|
size += sizeof(struct cifs_posix_ace) * count;
|
|
|
|
/* skip past access ACEs to get to default ACEs */
|
|
|
|
pACE = &cifs_acl->ace_array[count];
|
|
|
|
count = le16_to_cpu(cifs_acl->default_entry_count);
|
|
|
|
size += sizeof(struct cifs_posix_ace) * count;
|
|
|
|
/* check if we would go beyond end of SMB */
|
|
|
|
if (size_of_data_area < size)
|
|
|
|
return -EINVAL;
|
|
|
|
} else {
|
|
|
|
/* illegal type */
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate number of POSIX ACLs to store in VFS format. */
|
|
|
|
kacl = posix_acl_alloc(count, GFP_NOFS);
|
|
|
|
if (!kacl)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
FOREACH_ACL_ENTRY(pa, kacl, pe) {
|
|
|
|
cifs_init_posix_acl(pa, pACE);
|
|
|
|
pACE++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*acl = kacl;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-09-22 15:17:03 +00:00
|
|
|
/**
|
|
|
|
* cifs_init_ace - convert ACL entry from POSIX ACL to cifs format
|
|
|
|
* @cifs_ace: the cifs ACL entry to store into
|
|
|
|
* @local_ace: the POSIX ACL entry to convert
|
|
|
|
*/
|
|
|
|
static void cifs_init_ace(struct cifs_posix_ace *cifs_ace,
|
|
|
|
const struct posix_acl_entry *local_ace)
|
|
|
|
{
|
|
|
|
cifs_ace->cifs_e_perm = local_ace->e_perm;
|
|
|
|
cifs_ace->cifs_e_tag = local_ace->e_tag;
|
|
|
|
|
|
|
|
switch (local_ace->e_tag) {
|
|
|
|
case ACL_USER:
|
|
|
|
cifs_ace->cifs_uid =
|
|
|
|
cpu_to_le64(from_kuid(&init_user_ns, local_ace->e_uid));
|
|
|
|
break;
|
|
|
|
case ACL_GROUP:
|
|
|
|
cifs_ace->cifs_uid =
|
|
|
|
cpu_to_le64(from_kgid(&init_user_ns, local_ace->e_gid));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cifs_ace->cifs_uid = cpu_to_le64(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* posix_acl_to_cifs - convert ACLs from POSIX ACL to cifs format
|
2024-09-25 06:55:43 +00:00
|
|
|
* @parm_data: ACLs in cifs format to convert to
|
2022-09-22 15:17:03 +00:00
|
|
|
* @acl: ACLs in POSIX ACL format to convert from
|
|
|
|
* @acl_type: the type of POSIX ACLs stored in @acl
|
|
|
|
*
|
|
|
|
* Return: the number cifs ACL entries after conversion
|
|
|
|
*/
|
|
|
|
static __u16 posix_acl_to_cifs(char *parm_data, const struct posix_acl *acl,
|
|
|
|
const int acl_type)
|
|
|
|
{
|
|
|
|
__u16 rc = 0;
|
|
|
|
struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
|
|
|
|
const struct posix_acl_entry *pa, *pe;
|
|
|
|
int count;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if ((acl == NULL) || (cifs_acl == NULL))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
count = acl->a_count;
|
|
|
|
cifs_dbg(FYI, "setting acl with %d entries\n", count);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note that the uapi POSIX ACL version is verified by the VFS and is
|
|
|
|
* independent of the cifs ACL version. Changing the POSIX ACL version
|
|
|
|
* is a uapi change and if it's changed we will pass down the POSIX ACL
|
|
|
|
* version in struct posix_acl from the VFS. For now there's really
|
|
|
|
* only one that all filesystems know how to deal with.
|
|
|
|
*/
|
|
|
|
cifs_acl->version = cpu_to_le16(1);
|
|
|
|
if (acl_type == ACL_TYPE_ACCESS) {
|
|
|
|
cifs_acl->access_entry_count = cpu_to_le16(count);
|
|
|
|
cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
|
|
|
|
} else if (acl_type == ACL_TYPE_DEFAULT) {
|
|
|
|
cifs_acl->default_entry_count = cpu_to_le16(count);
|
|
|
|
cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
|
|
|
|
} else {
|
|
|
|
cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
FOREACH_ACL_ENTRY(pa, acl, pe) {
|
|
|
|
cifs_init_ace(&cifs_acl->ace_array[i++], pa);
|
|
|
|
}
|
|
|
|
if (rc == 0) {
|
|
|
|
rc = (__u16)(count * sizeof(struct cifs_posix_ace));
|
|
|
|
rc += sizeof(struct cifs_posix_acl);
|
|
|
|
/* BB add check to make sure ACL does not overflow SMB */
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-09-22 15:17:02 +00:00
|
|
|
int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const unsigned char *searchName, struct posix_acl **acl,
|
|
|
|
const int acl_type, const struct nls_table *nls_codepage,
|
|
|
|
int remap)
|
|
|
|
{
|
|
|
|
/* SMB_QUERY_POSIX_ACL */
|
|
|
|
TRANSACTION2_QPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QPI_RSP *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
|
|
|
|
|
|
|
|
queryAclRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName,
|
|
|
|
searchName, PATH_MAX, nls_codepage,
|
|
|
|
remap);
|
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
|
|
|
pSMB->FileName[name_len] = 0;
|
|
|
|
pSMB->FileName[name_len+1] = 0;
|
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, searchName);
|
|
|
|
}
|
|
|
|
|
|
|
|
params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
/* BB find exact max data count below from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(4000);
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(
|
|
|
|
offsetof(struct smb_com_transaction2_qpi_req,
|
|
|
|
InformationLevel) - 4);
|
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
|
|
|
|
pSMB->Reserved4 = 0;
|
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
|
|
|
|
if (rc) {
|
|
|
|
cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
|
|
|
|
} else {
|
|
|
|
/* decode response */
|
|
|
|
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
/* BB also check enough total bytes returned */
|
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 2)
|
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
|
|
|
|
rc = cifs_to_posix_acl(acl,
|
|
|
|
(char *)&pSMBr->hdr.Protocol+data_offset,
|
|
|
|
acl_type, count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
/*
|
|
|
|
* The else branch after SendReceive() doesn't return EAGAIN so if we
|
|
|
|
* allocated @acl in cifs_to_posix_acl() we are guaranteed to return
|
|
|
|
* here and don't leak POSIX ACLs.
|
|
|
|
*/
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto queryAclRetry;
|
|
|
|
return rc;
|
|
|
|
}
|
2022-09-22 15:17:03 +00:00
|
|
|
|
|
|
|
int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const unsigned char *fileName, const struct posix_acl *acl,
|
|
|
|
const int acl_type, const struct nls_table *nls_codepage,
|
|
|
|
int remap)
|
|
|
|
{
|
|
|
|
struct smb_com_transaction2_spi_req *pSMB = NULL;
|
|
|
|
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
|
|
|
|
char *parm_data;
|
|
|
|
int name_len;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, byte_count, data_count, param_offset, offset;
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
|
|
|
|
setAclRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, fileName);
|
|
|
|
}
|
|
|
|
params = 6 + name_len;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
/* BB find max SMB size from sess */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
|
|
|
InformationLevel) - 4;
|
|
|
|
offset = param_offset + params;
|
smb: client: Fix -Wstringop-overflow issues
pSMB->hdr.Protocol is an array of size 4 bytes, hence when the compiler
analyzes this line of code
parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
it legitimately complains about the fact that offset points outside the
bounds of the array. Notice that the compiler gives priority to the object
as an array, rather than merely the address of one more byte in a structure
to wich offset should be added (which seems to be the actual intention of
the original implementation).
Fix this by explicitly instructing the compiler to treat the code as a
sequence of bytes in struct smb_com_transaction2_spi_req, and not as an
array accessed through pointer notation.
Notice that ((char *)pSMB) + sizeof(pSMB->hdr.smb_buf_length) points to
the same address as ((char *) &pSMB->hdr.Protocol), therefore this results
in no differences in binary output.
Fixes the following -Wstringop-overflow warnings when built s390
architecture with defconfig (GCC 13):
CC [M] fs/smb/client/cifssmb.o
In function 'cifs_init_ace',
inlined from 'posix_acl_to_cifs' at fs/smb/client/cifssmb.c:3046:3,
inlined from 'cifs_do_set_acl' at fs/smb/client/cifssmb.c:3191:15:
fs/smb/client/cifssmb.c:2987:31: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
2987 | cifs_ace->cifs_e_perm = local_ace->e_perm;
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
In file included from fs/smb/client/cifssmb.c:27:
fs/smb/client/cifspdu.h: In function 'cifs_do_set_acl':
fs/smb/client/cifspdu.h:384:14: note: at offset [7, 11] into destination object 'Protocol' of size 4
384 | __u8 Protocol[4];
| ^~~~~~~~
In function 'cifs_init_ace',
inlined from 'posix_acl_to_cifs' at fs/smb/client/cifssmb.c:3046:3,
inlined from 'cifs_do_set_acl' at fs/smb/client/cifssmb.c:3191:15:
fs/smb/client/cifssmb.c:2988:30: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
2988 | cifs_ace->cifs_e_tag = local_ace->e_tag;
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
fs/smb/client/cifspdu.h: In function 'cifs_do_set_acl':
fs/smb/client/cifspdu.h:384:14: note: at offset [6, 10] into destination object 'Protocol' of size 4
384 | __u8 Protocol[4];
| ^~~~~~~~
This helps with the ongoing efforts to globally enable
-Wstringop-overflow.
Link: https://github.com/KSPP/linux/issues/310
Fixes: dc1af4c4b472 ("cifs: implement set acl method")
Cc: stable@vger.kernel.org
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
2023-07-11 23:12:31 +00:00
|
|
|
parm_data = ((char *)pSMB) + sizeof(pSMB->hdr.smb_buf_length) + offset;
|
2022-09-22 15:17:03 +00:00
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
|
|
|
|
/* convert to on the wire format for POSIX ACL */
|
|
|
|
data_count = posix_acl_to_cifs(parm_data, acl, acl_type);
|
|
|
|
|
|
|
|
if (data_count == 0) {
|
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
goto setACLerrorExit;
|
|
|
|
}
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
|
|
|
|
byte_count = 3 /* pad */ + params + data_count;
|
|
|
|
pSMB->DataCount = cpu_to_le16(data_count);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->Reserved4 = 0;
|
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc)
|
|
|
|
cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
|
|
|
|
|
|
|
|
setACLerrorExit:
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto setAclRetry;
|
|
|
|
return rc;
|
|
|
|
}
|
2022-09-22 15:17:02 +00:00
|
|
|
#else
|
|
|
|
int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const unsigned char *searchName, struct posix_acl **acl,
|
|
|
|
const int acl_type, const struct nls_table *nls_codepage,
|
|
|
|
int remap)
|
|
|
|
{
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2022-09-22 15:17:03 +00:00
|
|
|
|
|
|
|
int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const unsigned char *fileName, const struct posix_acl *acl,
|
|
|
|
const int acl_type, const struct nls_table *nls_codepage,
|
|
|
|
int remap)
|
|
|
|
{
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2022-09-22 15:17:02 +00:00
|
|
|
#endif /* CONFIG_FS_POSIX_ACL */
|
|
|
|
|
2005-04-29 05:41:04 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
|
2008-02-07 23:25:02 +00:00
|
|
|
const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
|
2005-04-29 05:41:04 +00:00
|
|
|
{
|
2007-07-13 00:33:32 +00:00
|
|
|
int rc = 0;
|
|
|
|
struct smb_t2_qfi_req *pSMB = NULL;
|
|
|
|
struct smb_t2_qfi_rsp *pSMBr = NULL;
|
|
|
|
int bytes_returned;
|
|
|
|
__u16 params, byte_count;
|
2005-04-29 05:41:04 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In GetExtAttr\n");
|
2007-07-07 19:25:05 +00:00
|
|
|
if (tcon == NULL)
|
|
|
|
return -ENODEV;
|
2005-04-29 05:41:04 +00:00
|
|
|
|
|
|
|
GetExtAttrRetry:
|
2007-07-07 19:25:05 +00:00
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
2022-08-01 16:17:46 +00:00
|
|
|
(void **) &pSMBr);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
2005-04-29 05:41:04 +00:00
|
|
|
|
2008-02-07 23:25:02 +00:00
|
|
|
params = 2 /* level */ + 2 /* fid */;
|
2007-07-07 19:25:05 +00:00
|
|
|
pSMB->t2.TotalDataCount = 0;
|
|
|
|
pSMB->t2.MaxParameterCount = cpu_to_le16(4);
|
|
|
|
/* BB find exact max data count below from sess structure BB */
|
|
|
|
pSMB->t2.MaxDataCount = cpu_to_le16(4000);
|
|
|
|
pSMB->t2.MaxSetupCount = 0;
|
|
|
|
pSMB->t2.Reserved = 0;
|
|
|
|
pSMB->t2.Flags = 0;
|
|
|
|
pSMB->t2.Timeout = 0;
|
|
|
|
pSMB->t2.Reserved2 = 0;
|
|
|
|
pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
|
|
|
|
Fid) - 4);
|
|
|
|
pSMB->t2.DataCount = 0;
|
|
|
|
pSMB->t2.DataOffset = 0;
|
|
|
|
pSMB->t2.SetupCount = 1;
|
|
|
|
pSMB->t2.Reserved3 = 0;
|
|
|
|
pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->t2.TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
|
|
|
|
pSMB->Pad = 0;
|
2005-04-29 05:41:04 +00:00
|
|
|
pSMB->Fid = netfid;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2007-07-07 19:25:05 +00:00
|
|
|
pSMB->t2.ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
|
2007-07-07 19:25:05 +00:00
|
|
|
} else {
|
|
|
|
/* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
/* BB also check enough total bytes returned */
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 2)
|
2007-07-07 19:25:05 +00:00
|
|
|
/* If rc should we check for EOPNOSUPP and
|
|
|
|
disable the srvino flag? or in caller? */
|
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
|
|
|
|
struct file_chattr_info *pfinfo;
|
2022-08-01 16:17:46 +00:00
|
|
|
|
2007-07-07 19:25:05 +00:00
|
|
|
if (count != 16) {
|
2020-04-15 05:42:53 +00:00
|
|
|
cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
|
2007-07-07 19:25:05 +00:00
|
|
|
rc = -EIO;
|
|
|
|
goto GetExtAttrOut;
|
|
|
|
}
|
|
|
|
pfinfo = (struct file_chattr_info *)
|
|
|
|
(data_offset + (char *) &pSMBr->hdr.Protocol);
|
|
|
|
*pExtAttrBits = le64_to_cpu(pfinfo->mode);
|
2005-04-29 05:41:04 +00:00
|
|
|
*pMask = le64_to_cpu(pfinfo->mask);
|
2007-07-07 19:25:05 +00:00
|
|
|
}
|
|
|
|
}
|
2005-04-29 05:41:04 +00:00
|
|
|
GetExtAttrOut:
|
2007-07-07 19:25:05 +00:00
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto GetExtAttrRetry;
|
|
|
|
return rc;
|
2005-04-29 05:41:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_POSIX */
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2010-12-06 17:52:08 +00:00
|
|
|
/*
|
|
|
|
* Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
|
|
|
|
* all NT TRANSACTS that we init here have total parm and data under about 400
|
|
|
|
* bytes (to fit in small cifs buffer size), which is the case so far, it
|
|
|
|
* easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
|
|
|
|
* returned setup area) and MaxParameterCount (returned parms size) must be set
|
|
|
|
* by caller
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
smb_init_nttransact(const __u16 sub_command, const int setup_count,
|
2011-05-27 04:34:02 +00:00
|
|
|
const int parm_len, struct cifs_tcon *tcon,
|
2010-12-06 17:52:08 +00:00
|
|
|
void **ret_buf)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__u32 temp_offset;
|
|
|
|
struct smb_com_ntransact_req *pSMB;
|
|
|
|
|
|
|
|
rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
|
|
|
|
(void **)&pSMB);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
*ret_buf = (void *)pSMB;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le32(parm_len);
|
|
|
|
pSMB->TotalDataCount = 0;
|
2011-10-11 10:41:32 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
|
2010-12-06 17:52:08 +00:00
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->DataCount = pSMB->TotalDataCount;
|
|
|
|
temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
|
|
|
|
(setup_count * 2) - 4 /* for rfc1001 length itself */;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le32(temp_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
|
|
|
|
pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
|
|
|
|
pSMB->SubCommand = cpu_to_le16(sub_command);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
validate_ntransact(char *buf, char **ppparm, char **ppdata,
|
|
|
|
__u32 *pparmlen, __u32 *pdatalen)
|
|
|
|
{
|
|
|
|
char *end_of_smb;
|
|
|
|
__u32 data_count, data_offset, parm_count, parm_offset;
|
|
|
|
struct smb_com_ntransact_rsp *pSMBr;
|
2011-05-04 12:05:26 +00:00
|
|
|
u16 bcc;
|
2010-12-06 17:52:08 +00:00
|
|
|
|
|
|
|
*pdatalen = 0;
|
|
|
|
*pparmlen = 0;
|
|
|
|
|
|
|
|
if (buf == NULL)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
pSMBr = (struct smb_com_ntransact_rsp *)buf;
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
bcc = get_bcc(&pSMBr->hdr);
|
|
|
|
end_of_smb = 2 /* sizeof byte count */ + bcc +
|
2010-12-06 17:52:08 +00:00
|
|
|
(char *)&pSMBr->ByteCount;
|
|
|
|
|
|
|
|
data_offset = le32_to_cpu(pSMBr->DataOffset);
|
|
|
|
data_count = le32_to_cpu(pSMBr->DataCount);
|
|
|
|
parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
|
|
|
|
parm_count = le32_to_cpu(pSMBr->ParameterCount);
|
|
|
|
|
|
|
|
*ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
|
|
|
|
*ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
|
|
|
|
|
|
|
|
/* should we also check that parm and data areas do not overlap? */
|
|
|
|
if (*ppparm > end_of_smb) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "parms start after end of smb\n");
|
2010-12-06 17:52:08 +00:00
|
|
|
return -EINVAL;
|
|
|
|
} else if (parm_count + *ppparm > end_of_smb) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "parm end after end of smb\n");
|
2010-12-06 17:52:08 +00:00
|
|
|
return -EINVAL;
|
|
|
|
} else if (*ppdata > end_of_smb) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "data starts after end of smb\n");
|
2010-12-06 17:52:08 +00:00
|
|
|
return -EINVAL;
|
|
|
|
} else if (data_count + *ppdata > end_of_smb) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
|
|
|
|
*ppdata, data_count, (data_count + *ppdata),
|
|
|
|
end_of_smb, pSMBr);
|
2010-12-06 17:52:08 +00:00
|
|
|
return -EINVAL;
|
2011-05-04 12:05:26 +00:00
|
|
|
} else if (parm_count + data_count > bcc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "parm count and data count larger than SMB\n");
|
2010-12-06 17:52:08 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
*pdatalen = data_count;
|
|
|
|
*pparmlen = parm_count;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-01-12 23:44:21 +00:00
|
|
|
/* Get Security Descriptor (by handle) from remote server for a file or dir */
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
|
2024-08-22 08:20:55 +00:00
|
|
|
struct smb_ntsd **acl_inf, __u32 *pbuflen)
|
2006-01-12 23:44:21 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
int buf_type = 0;
|
2008-02-07 23:25:02 +00:00
|
|
|
QUERY_SEC_DESC_REQ *pSMB;
|
2006-01-12 23:44:21 +00:00
|
|
|
struct kvec iov[1];
|
2016-10-25 18:38:47 +00:00
|
|
|
struct kvec rsp_iov;
|
2006-01-12 23:44:21 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "GetCifsACL\n");
|
2006-01-12 23:44:21 +00:00
|
|
|
|
2007-10-25 21:17:17 +00:00
|
|
|
*pbuflen = 0;
|
|
|
|
*acl_inf = NULL;
|
|
|
|
|
2007-10-26 23:40:20 +00:00
|
|
|
rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
|
2006-01-12 23:44:21 +00:00
|
|
|
8 /* parm len */, tcon, (void **) &pSMB);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le32(4);
|
|
|
|
/* BB TEST with big acls that might need to be e.g. larger than 16K */
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Fid = fid; /* file handle always le */
|
|
|
|
pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
|
|
|
|
CIFS_ACL_DACL);
|
|
|
|
pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, 11);
|
2006-01-12 23:44:21 +00:00
|
|
|
iov[0].iov_base = (char *)pSMB;
|
2011-04-29 05:40:20 +00:00
|
|
|
iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
|
2006-01-12 23:44:21 +00:00
|
|
|
|
2007-10-18 21:45:27 +00:00
|
|
|
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
|
2016-10-25 18:38:47 +00:00
|
|
|
0, &rsp_iov);
|
|
|
|
cifs_small_buf_release(pSMB);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
|
2006-01-12 23:44:21 +00:00
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
|
2006-01-12 23:44:21 +00:00
|
|
|
} else { /* decode response */
|
2008-02-07 23:25:02 +00:00
|
|
|
__le32 *parm;
|
2007-10-25 21:17:17 +00:00
|
|
|
__u32 parm_len;
|
|
|
|
__u32 acl_len;
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_ntransact_rsp *pSMBr;
|
2007-10-25 21:17:17 +00:00
|
|
|
char *pdata;
|
2006-01-12 23:44:21 +00:00
|
|
|
|
|
|
|
/* validate_nttransact */
|
2016-10-25 18:38:47 +00:00
|
|
|
rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
|
2007-10-25 21:17:17 +00:00
|
|
|
&pdata, &parm_len, pbuflen);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (rc)
|
2006-01-12 23:44:21 +00:00
|
|
|
goto qsec_out;
|
2016-10-25 18:38:47 +00:00
|
|
|
pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
|
2006-01-12 23:44:21 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "smb %p parm %p data %p\n",
|
|
|
|
pSMBr, parm, *acl_inf);
|
2006-01-12 23:44:21 +00:00
|
|
|
|
|
|
|
if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
|
|
|
|
rc = -EIO; /* bad smb */
|
2007-10-25 21:17:17 +00:00
|
|
|
*pbuflen = 0;
|
2006-01-12 23:44:21 +00:00
|
|
|
goto qsec_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* BB check that data area is minimum length and as big as acl_len */
|
|
|
|
|
2007-10-16 18:40:37 +00:00
|
|
|
acl_len = le32_to_cpu(*parm);
|
2007-10-25 21:17:17 +00:00
|
|
|
if (acl_len != *pbuflen) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "acl length %d does not match %d\n",
|
|
|
|
acl_len, *pbuflen);
|
2007-10-25 21:17:17 +00:00
|
|
|
if (*pbuflen > acl_len)
|
|
|
|
*pbuflen = acl_len;
|
|
|
|
}
|
2006-01-12 23:44:21 +00:00
|
|
|
|
2007-10-25 21:17:17 +00:00
|
|
|
/* check if buffer is big enough for the acl
|
|
|
|
header followed by the smallest SID */
|
2024-08-22 08:20:55 +00:00
|
|
|
if ((*pbuflen < sizeof(struct smb_ntsd) + 8) ||
|
2007-10-25 21:17:17 +00:00
|
|
|
(*pbuflen >= 64 * 1024)) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
|
2007-10-25 21:17:17 +00:00
|
|
|
rc = -EINVAL;
|
|
|
|
*pbuflen = 0;
|
|
|
|
} else {
|
2013-03-11 16:22:32 +00:00
|
|
|
*acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
|
2007-10-25 21:17:17 +00:00
|
|
|
if (*acl_inf == NULL) {
|
|
|
|
*pbuflen = 0;
|
|
|
|
rc = -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
2006-01-12 23:44:21 +00:00
|
|
|
}
|
|
|
|
qsec_out:
|
2016-10-25 18:38:47 +00:00
|
|
|
free_rsp_buf(buf_type, rsp_iov.iov_base);
|
2006-01-12 23:44:21 +00:00
|
|
|
return rc;
|
|
|
|
}
|
2007-12-31 07:47:21 +00:00
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
|
2024-08-22 08:20:55 +00:00
|
|
|
struct smb_ntsd *pntsd, __u32 acllen, int aclflag)
|
2007-12-31 07:47:21 +00:00
|
|
|
{
|
|
|
|
__u16 byte_count, param_count, data_count, param_offset, data_offset;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
SET_SEC_DESC_REQ *pSMB = NULL;
|
2012-03-26 13:55:29 +00:00
|
|
|
void *pSMBr;
|
2007-12-31 07:47:21 +00:00
|
|
|
|
|
|
|
setCifsAclRetry:
|
2012-03-26 13:55:29 +00:00
|
|
|
rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
|
2007-12-31 07:47:21 +00:00
|
|
|
if (rc)
|
2012-03-26 13:55:29 +00:00
|
|
|
return rc;
|
2007-12-31 07:47:21 +00:00
|
|
|
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
|
|
|
|
param_count = 8;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
|
|
|
|
data_count = acllen;
|
|
|
|
data_offset = param_offset + param_count;
|
|
|
|
byte_count = 3 /* pad */ + param_count;
|
|
|
|
|
|
|
|
pSMB->DataCount = cpu_to_le32(data_count);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le32(4);
|
|
|
|
pSMB->MaxDataCount = cpu_to_le32(16384);
|
|
|
|
pSMB->ParameterCount = cpu_to_le32(param_count);
|
|
|
|
pSMB->ParameterOffset = cpu_to_le32(param_offset);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->DataOffset = cpu_to_le32(data_offset);
|
|
|
|
pSMB->SetupCount = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
|
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
|
|
|
|
|
|
|
|
pSMB->Fid = fid; /* file handle always le */
|
|
|
|
pSMB->Reserved2 = 0;
|
2011-10-13 15:26:03 +00:00
|
|
|
pSMB->AclFlags = cpu_to_le32(aclflag);
|
2007-12-31 07:47:21 +00:00
|
|
|
|
|
|
|
if (pntsd && acllen) {
|
2012-03-26 13:55:29 +00:00
|
|
|
memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
|
|
|
|
data_offset, pntsd, acllen);
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count + data_count);
|
2007-12-31 07:47:21 +00:00
|
|
|
} else
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2007-12-31 07:47:21 +00:00
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
|
|
|
|
bytes_returned, rc);
|
2007-12-31 07:47:21 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
|
2007-12-31 07:47:21 +00:00
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto setCifsAclRetry;
|
|
|
|
|
|
|
|
return (rc);
|
|
|
|
}
|
|
|
|
|
2006-01-12 23:44:21 +00:00
|
|
|
|
2005-08-24 03:26:03 +00:00
|
|
|
/* Legacy Query Path Information call for lookup to old servers such
|
|
|
|
as Win9x/WinME */
|
2012-05-25 10:40:22 +00:00
|
|
|
int
|
|
|
|
SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *search_name, FILE_ALL_INFO *data,
|
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-08-24 03:26:03 +00:00
|
|
|
{
|
2008-02-07 23:25:02 +00:00
|
|
|
QUERY_INFORMATION_REQ *pSMB;
|
|
|
|
QUERY_INFORMATION_RSP *pSMBr;
|
2005-08-24 03:26:03 +00:00
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
|
2005-08-24 03:26:03 +00:00
|
|
|
QInfRetry:
|
|
|
|
rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
|
2007-07-13 00:33:32 +00:00
|
|
|
(void **) &pSMBr);
|
2005-08-24 03:26:03 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName,
|
2012-05-25 10:40:22 +00:00
|
|
|
search_name, PATH_MAX, nls_codepage,
|
2012-01-19 04:32:33 +00:00
|
|
|
remap);
|
2005-08-24 03:26:03 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2007-07-13 00:33:32 +00:00
|
|
|
} else {
|
2019-08-26 23:30:14 +00:00
|
|
|
name_len = copy_path_name(pSMB->FileName, search_name);
|
2005-08-24 03:26:03 +00:00
|
|
|
}
|
|
|
|
pSMB->BufferFormat = 0x04;
|
2007-07-13 00:33:32 +00:00
|
|
|
name_len++; /* account for buffer type byte */
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, (__u16)name_len);
|
2005-08-24 03:26:03 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(name_len);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
2007-07-13 00:33:32 +00:00
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2005-08-24 03:26:03 +00:00
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
|
2012-05-25 10:40:22 +00:00
|
|
|
} else if (data) {
|
2018-06-19 15:27:58 +00:00
|
|
|
struct timespec64 ts;
|
2006-09-28 03:35:57 +00:00
|
|
|
__u32 time = le32_to_cpu(pSMBr->last_write_time);
|
2008-02-07 23:25:02 +00:00
|
|
|
|
|
|
|
/* decode response */
|
2006-09-28 03:35:57 +00:00
|
|
|
/* BB FIXME - add time zone adjustment BB */
|
2012-05-25 10:40:22 +00:00
|
|
|
memset(data, 0, sizeof(FILE_ALL_INFO));
|
2006-09-28 03:35:57 +00:00
|
|
|
ts.tv_nsec = 0;
|
|
|
|
ts.tv_sec = time;
|
|
|
|
/* decode time fields */
|
2012-05-25 10:40:22 +00:00
|
|
|
data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
|
|
|
|
data->LastWriteTime = data->ChangeTime;
|
|
|
|
data->LastAccessTime = 0;
|
|
|
|
data->AllocationSize =
|
2005-09-22 23:32:06 +00:00
|
|
|
cpu_to_le64(le32_to_cpu(pSMBr->size));
|
2012-05-25 10:40:22 +00:00
|
|
|
data->EndOfFile = data->AllocationSize;
|
|
|
|
data->Attributes =
|
2005-09-22 23:32:06 +00:00
|
|
|
cpu_to_le32(le16_to_cpu(pSMBr->attr));
|
2005-08-24 03:26:03 +00:00
|
|
|
} else
|
|
|
|
rc = -EIO; /* bad buffer passed in */
|
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto QInfRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-02-12 12:44:16 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
2010-02-12 12:44:16 +00:00
|
|
|
u16 netfid, FILE_ALL_INFO *pFindData)
|
|
|
|
{
|
|
|
|
struct smb_t2_qfi_req *pSMB = NULL;
|
|
|
|
struct smb_t2_qfi_rsp *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
|
|
|
QFileInfoRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 2 /* level */ + 2 /* fid */;
|
|
|
|
pSMB->t2.TotalDataCount = 0;
|
|
|
|
pSMB->t2.MaxParameterCount = cpu_to_le16(4);
|
|
|
|
/* BB find exact max data count below from sess structure BB */
|
|
|
|
pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
|
|
|
|
pSMB->t2.MaxSetupCount = 0;
|
|
|
|
pSMB->t2.Reserved = 0;
|
|
|
|
pSMB->t2.Flags = 0;
|
|
|
|
pSMB->t2.Timeout = 0;
|
|
|
|
pSMB->t2.Reserved2 = 0;
|
|
|
|
pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
|
|
|
|
Fid) - 4);
|
|
|
|
pSMB->t2.DataCount = 0;
|
|
|
|
pSMB->t2.DataOffset = 0;
|
|
|
|
pSMB->t2.SetupCount = 1;
|
|
|
|
pSMB->t2.Reserved3 = 0;
|
|
|
|
pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->t2.TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
|
|
|
|
pSMB->Pad = 0;
|
|
|
|
pSMB->Fid = netfid;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2013-06-28 09:47:33 +00:00
|
|
|
pSMB->t2.ByteCount = cpu_to_le16(byte_count);
|
2005-08-24 03:26:03 +00:00
|
|
|
|
2010-02-12 12:44:16 +00:00
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2020-04-15 05:42:53 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
|
2010-02-12 12:44:16 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
2005-08-24 03:26:03 +00:00
|
|
|
|
2010-02-12 12:44:16 +00:00
|
|
|
if (rc) /* BB add auto retry on EOPNOTSUPP? */
|
|
|
|
rc = -EIO;
|
2011-05-04 12:05:26 +00:00
|
|
|
else if (get_bcc(&pSMBr->hdr) < 40)
|
2010-02-12 12:44:16 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
else if (pFindData) {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
memcpy((char *) pFindData,
|
|
|
|
(char *) &pSMBr->hdr.Protocol +
|
|
|
|
data_offset, sizeof(FILE_ALL_INFO));
|
|
|
|
} else
|
|
|
|
rc = -ENOMEM;
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto QFileInfoRetry;
|
2005-08-24 03:26:03 +00:00
|
|
|
|
2010-02-12 12:44:16 +00:00
|
|
|
return rc;
|
|
|
|
}
|
2005-08-24 03:26:03 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
2012-05-25 10:40:22 +00:00
|
|
|
const char *search_name, FILE_ALL_INFO *data,
|
2006-10-12 03:28:28 +00:00
|
|
|
int legacy /* old style infolevel */,
|
2005-04-29 05:41:06 +00:00
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2012-05-25 10:40:22 +00:00
|
|
|
/* level 263 SMB_QUERY_FILE_ALL_INFO */
|
2005-04-16 22:20:36 +00:00
|
|
|
TRANSACTION2_QPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QPI_RSP *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
/* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
|
2005-04-16 22:20:36 +00:00
|
|
|
QPathInfoRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-05-25 10:40:22 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
|
2012-01-19 04:32:33 +00:00
|
|
|
PATH_MAX, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, search_name);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(4000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
2007-07-07 19:25:05 +00:00
|
|
|
if (legacy)
|
2006-10-12 03:28:28 +00:00
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
|
|
|
|
else
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2006-10-12 03:28:28 +00:00
|
|
|
if (rc) /* BB add auto retry on EOPNOTSUPP? */
|
|
|
|
rc = -EIO;
|
2011-05-04 12:05:26 +00:00
|
|
|
else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
2011-05-04 12:05:26 +00:00
|
|
|
else if (legacy && get_bcc(&pSMBr->hdr) < 24)
|
2007-07-13 00:33:32 +00:00
|
|
|
rc = -EIO; /* 24 or 26 expected but we do not read
|
|
|
|
last field */
|
2012-05-25 10:40:22 +00:00
|
|
|
else if (data) {
|
2006-10-12 03:28:28 +00:00
|
|
|
int size;
|
2005-04-16 22:20:36 +00:00
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
2008-02-07 23:25:02 +00:00
|
|
|
|
2012-05-25 10:40:22 +00:00
|
|
|
/*
|
|
|
|
* On legacy responses we do not read the last field,
|
|
|
|
* EAsize, fortunately since it varies by subdialect and
|
|
|
|
* also note it differs on Set vs Get, ie two bytes or 4
|
|
|
|
* bytes depending but we don't care here.
|
|
|
|
*/
|
2008-02-07 23:25:02 +00:00
|
|
|
if (legacy)
|
2006-10-12 03:28:28 +00:00
|
|
|
size = sizeof(FILE_INFO_STANDARD);
|
|
|
|
else
|
|
|
|
size = sizeof(FILE_ALL_INFO);
|
2012-05-25 10:40:22 +00:00
|
|
|
memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
|
2006-10-12 03:28:28 +00:00
|
|
|
data_offset, size);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else
|
|
|
|
rc = -ENOMEM;
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto QPathInfoRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-02-12 12:44:17 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
2010-02-12 12:44:17 +00:00
|
|
|
u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
|
|
|
|
{
|
|
|
|
struct smb_t2_qfi_req *pSMB = NULL;
|
|
|
|
struct smb_t2_qfi_rsp *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
|
|
|
UnixQFileInfoRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 2 /* level */ + 2 /* fid */;
|
|
|
|
pSMB->t2.TotalDataCount = 0;
|
|
|
|
pSMB->t2.MaxParameterCount = cpu_to_le16(4);
|
|
|
|
/* BB find exact max data count below from sess structure BB */
|
|
|
|
pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
|
|
|
|
pSMB->t2.MaxSetupCount = 0;
|
|
|
|
pSMB->t2.Reserved = 0;
|
|
|
|
pSMB->t2.Flags = 0;
|
|
|
|
pSMB->t2.Timeout = 0;
|
|
|
|
pSMB->t2.Reserved2 = 0;
|
|
|
|
pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
|
|
|
|
Fid) - 4);
|
|
|
|
pSMB->t2.DataCount = 0;
|
|
|
|
pSMB->t2.DataOffset = 0;
|
|
|
|
pSMB->t2.SetupCount = 1;
|
|
|
|
pSMB->t2.Reserved3 = 0;
|
|
|
|
pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->t2.TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
|
|
|
|
pSMB->Pad = 0;
|
|
|
|
pSMB->Fid = netfid;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2013-06-28 09:47:33 +00:00
|
|
|
pSMB->t2.ByteCount = cpu_to_le16(byte_count);
|
2010-02-12 12:44:17 +00:00
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2020-04-15 05:42:53 +00:00
|
|
|
cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
|
2010-02-12 12:44:17 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
|
2010-02-12 12:44:17 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
} else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
memcpy((char *) pFindData,
|
|
|
|
(char *) &pSMBr->hdr.Protocol +
|
|
|
|
data_offset,
|
|
|
|
sizeof(FILE_UNIX_BASIC_INFO));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto UnixQFileInfoRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
2005-04-16 22:20:36 +00:00
|
|
|
const unsigned char *searchName,
|
2008-05-13 04:54:12 +00:00
|
|
|
FILE_UNIX_BASIC_INFO *pFindData,
|
2005-04-29 05:41:06 +00:00
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* SMB_QUERY_FILE_UNIX_BASIC */
|
|
|
|
TRANSACTION2_QPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QPI_RSP *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
int name_len;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
|
2005-04-16 22:20:36 +00:00
|
|
|
UnixQPathInfoRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, searchName);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
2007-07-13 00:33:32 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le16(4000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2020-04-15 05:42:53 +00:00
|
|
|
cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
} else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
memcpy((char *) pFindData,
|
|
|
|
(char *) &pSMBr->hdr.Protocol +
|
|
|
|
data_offset,
|
2007-10-25 21:17:17 +00:00
|
|
|
sizeof(FILE_UNIX_BASIC_INFO));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto UnixQPathInfoRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* xid, tcon, searchName and codepage are input parms, rest are returned */
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
|
2012-09-28 17:21:14 +00:00
|
|
|
const char *searchName, struct cifs_sb_info *cifs_sb,
|
2012-05-15 15:19:16 +00:00
|
|
|
__u16 *pnetfid, __u16 search_flags,
|
2012-09-28 17:21:14 +00:00
|
|
|
struct cifs_search_info *psrch_inf, bool msearch)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* level 257 SMB_ */
|
|
|
|
TRANSACTION2_FFIRST_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
|
2008-02-07 23:25:02 +00:00
|
|
|
T2_FFIRST_RSP_PARMS *parms;
|
2023-06-19 20:58:52 +00:00
|
|
|
struct nls_table *nls_codepage;
|
|
|
|
unsigned int lnoff;
|
|
|
|
__u16 params, byte_count;
|
2005-04-16 22:20:36 +00:00
|
|
|
int bytes_returned = 0;
|
2012-09-28 17:21:14 +00:00
|
|
|
int name_len, remap;
|
2023-06-19 20:58:52 +00:00
|
|
|
int rc = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
findFirstRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2012-09-28 17:21:14 +00:00
|
|
|
nls_codepage = cifs_sb->local_nls;
|
2014-09-27 07:19:01 +00:00
|
|
|
remap = cifs_remap(cifs_sb);
|
2012-09-28 17:21:14 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2024-09-25 06:55:43 +00:00
|
|
|
/* We can not add the asterisk earlier in case
|
2005-04-29 05:41:06 +00:00
|
|
|
it got remapped to 0xF03A as if it were part of the
|
|
|
|
directory name instead of a wildcard */
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len *= 2;
|
2012-09-28 17:21:14 +00:00
|
|
|
if (msearch) {
|
|
|
|
pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
|
|
|
|
pSMB->FileName[name_len+1] = 0;
|
|
|
|
pSMB->FileName[name_len+2] = '*';
|
|
|
|
pSMB->FileName[name_len+3] = 0;
|
|
|
|
name_len += 4; /* now the trailing null */
|
|
|
|
/* null terminate just in case */
|
|
|
|
pSMB->FileName[name_len] = 0;
|
|
|
|
pSMB->FileName[name_len+1] = 0;
|
|
|
|
name_len += 2;
|
|
|
|
}
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, searchName);
|
2012-09-28 17:21:14 +00:00
|
|
|
if (msearch) {
|
2019-08-26 23:30:14 +00:00
|
|
|
if (WARN_ON_ONCE(name_len > PATH_MAX-2))
|
|
|
|
name_len = PATH_MAX-2;
|
|
|
|
/* overwrite nul byte */
|
|
|
|
pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
|
|
|
|
pSMB->FileName[name_len] = '*';
|
|
|
|
pSMB->FileName[name_len+1] = 0;
|
|
|
|
name_len += 2;
|
2012-09-28 17:21:14 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
params = 12 + name_len /* includes null */ ;
|
|
|
|
pSMB->TotalDataCount = 0; /* no EAs */
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(10);
|
2011-10-11 10:41:32 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(
|
2006-03-09 22:21:45 +00:00
|
|
|
offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
|
|
|
|
- 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
|
|
|
|
pSMB->SearchAttributes =
|
|
|
|
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
|
|
|
|
ATTR_DIRECTORY);
|
2007-07-13 00:33:32 +00:00
|
|
|
pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
|
2012-05-15 15:19:16 +00:00
|
|
|
pSMB->SearchFlags = cpu_to_le16(search_flags);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
|
|
|
|
|
|
|
|
/* BB what should we set StorageType to? Does it matter? BB */
|
|
|
|
pSMB->SearchStorageType = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-06-19 20:58:52 +00:00
|
|
|
if (rc) {
|
|
|
|
/*
|
|
|
|
* BB: add logic to retry regular search if Unix search rejected
|
|
|
|
* unexpectedly by server.
|
|
|
|
*/
|
|
|
|
/* BB: add code to handle unsupported level rc */
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
|
2006-03-09 22:21:45 +00:00
|
|
|
cifs_buf_release(pSMB);
|
2023-06-19 20:58:52 +00:00
|
|
|
/*
|
|
|
|
* BB: eventually could optimize out free and realloc of buf for
|
|
|
|
* this case.
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto findFirstRetry;
|
2023-06-19 20:58:52 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
/* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
if (rc) {
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
return rc;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2023-06-19 20:58:52 +00:00
|
|
|
psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
|
|
|
|
psrch_inf->ntwrk_buf_start = (char *)pSMBr;
|
|
|
|
psrch_inf->smallBuf = false;
|
|
|
|
psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol +
|
|
|
|
le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
|
|
|
|
parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol +
|
|
|
|
le16_to_cpu(pSMBr->t2.ParameterOffset));
|
|
|
|
psrch_inf->endOfSearch = !!parms->EndofSearch;
|
|
|
|
|
|
|
|
psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
|
|
|
|
psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
|
|
|
|
psrch_inf->entries_in_buffer;
|
|
|
|
lnoff = le16_to_cpu(parms->LastNameOffset);
|
|
|
|
if (CIFSMaxBufSize < lnoff) {
|
|
|
|
cifs_dbg(VFS, "ignoring corrupt resume name\n");
|
|
|
|
psrch_inf->last_entry = NULL;
|
|
|
|
} else {
|
|
|
|
psrch_inf->last_entry = psrch_inf->srch_entries_start + lnoff;
|
|
|
|
if (pnetfid)
|
|
|
|
*pnetfid = parms->SearchHandle;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2012-06-20 07:21:16 +00:00
|
|
|
int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
__u16 searchHandle, __u16 search_flags,
|
|
|
|
struct cifs_search_info *psrch_inf)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
TRANSACTION2_FNEXT_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
|
2008-02-07 23:25:02 +00:00
|
|
|
T2_FNEXT_RSP_PARMS *parms;
|
2011-08-23 11:21:28 +00:00
|
|
|
unsigned int name_len;
|
2023-06-19 21:41:00 +00:00
|
|
|
unsigned int lnoff;
|
2005-04-16 22:20:36 +00:00
|
|
|
__u16 params, byte_count;
|
2023-06-19 21:41:00 +00:00
|
|
|
char *response_data;
|
|
|
|
int bytes_returned;
|
|
|
|
int rc = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In FindNext\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-04-29 00:06:05 +00:00
|
|
|
if (psrch_inf->endOfSearch)
|
2005-04-16 22:20:36 +00:00
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
params = 14; /* includes 2 bytes of null string, converted to LE below*/
|
2005-04-16 22:20:36 +00:00
|
|
|
byte_count = 0;
|
|
|
|
pSMB->TotalDataCount = 0; /* no EAs */
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(8);
|
2011-10-11 10:41:32 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(
|
|
|
|
offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
|
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
|
|
|
|
pSMB->SearchHandle = searchHandle; /* always kept as le */
|
|
|
|
pSMB->SearchCount =
|
2007-10-25 21:17:17 +00:00
|
|
|
cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
|
|
|
|
pSMB->ResumeKey = psrch_inf->resume_key;
|
2012-05-15 15:19:16 +00:00
|
|
|
pSMB->SearchFlags = cpu_to_le16(search_flags);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
name_len = psrch_inf->resume_name_len;
|
|
|
|
params += name_len;
|
2007-07-07 19:25:05 +00:00
|
|
|
if (name_len < PATH_MAX) {
|
2005-04-16 22:20:36 +00:00
|
|
|
memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
|
|
|
|
byte_count += name_len;
|
2005-08-03 04:31:05 +00:00
|
|
|
/* 14 byte parm len above enough for 2 byte null terminator */
|
|
|
|
pSMB->ResumeFileName[name_len] = 0;
|
|
|
|
pSMB->ResumeFileName[name_len+1] = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
2023-06-19 21:41:00 +00:00
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
return -EINVAL;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
2007-07-13 00:33:32 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
|
2023-06-19 21:41:00 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc) {
|
2023-06-19 21:41:00 +00:00
|
|
|
cifs_buf_release(pSMB);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc == -EBADF) {
|
2008-04-29 00:06:05 +00:00
|
|
|
psrch_inf->endOfSearch = true;
|
2007-07-13 00:33:32 +00:00
|
|
|
rc = 0; /* search probably was closed at end of search*/
|
2023-06-19 21:41:00 +00:00
|
|
|
} else {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "FindNext returned = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2023-06-19 21:41:00 +00:00
|
|
|
return rc;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-06-19 21:41:00 +00:00
|
|
|
/* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
if (rc) {
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
return rc;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2023-06-19 21:41:00 +00:00
|
|
|
/* BB fixme add lock for file (srch_info) struct here */
|
|
|
|
psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
|
|
|
|
response_data = (char *)&pSMBr->hdr.Protocol +
|
|
|
|
le16_to_cpu(pSMBr->t2.ParameterOffset);
|
|
|
|
parms = (T2_FNEXT_RSP_PARMS *)response_data;
|
|
|
|
response_data = (char *)&pSMBr->hdr.Protocol +
|
|
|
|
le16_to_cpu(pSMBr->t2.DataOffset);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-06-19 21:41:00 +00:00
|
|
|
if (psrch_inf->smallBuf)
|
|
|
|
cifs_small_buf_release(psrch_inf->ntwrk_buf_start);
|
|
|
|
else
|
|
|
|
cifs_buf_release(psrch_inf->ntwrk_buf_start);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-06-19 21:41:00 +00:00
|
|
|
psrch_inf->srch_entries_start = response_data;
|
|
|
|
psrch_inf->ntwrk_buf_start = (char *)pSMB;
|
|
|
|
psrch_inf->smallBuf = false;
|
|
|
|
psrch_inf->endOfSearch = !!parms->EndofSearch;
|
|
|
|
psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
|
|
|
|
psrch_inf->index_of_last_entry += psrch_inf->entries_in_buffer;
|
|
|
|
lnoff = le16_to_cpu(parms->LastNameOffset);
|
|
|
|
if (CIFSMaxBufSize < lnoff) {
|
|
|
|
cifs_dbg(VFS, "ignoring corrupt resume name\n");
|
|
|
|
psrch_inf->last_entry = NULL;
|
|
|
|
} else {
|
|
|
|
psrch_inf->last_entry =
|
|
|
|
psrch_inf->srch_entries_start + lnoff;
|
|
|
|
}
|
|
|
|
/* BB fixme add unlock here */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BB: On error, should we leave previous search buf
|
|
|
|
* (and count and last entry fields) intact or free the previous one?
|
|
|
|
*
|
|
|
|
* Note: On -EAGAIN error only caller can retry on handle based calls
|
|
|
|
* since file handle passed in no longer valid.
|
|
|
|
*/
|
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
|
2007-07-13 00:33:32 +00:00
|
|
|
const __u16 searchHandle)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
FINDCLOSE_REQ *pSMB = NULL;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In CIFSSMBFindClose\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
|
|
|
|
|
|
|
|
/* no sense returning error if session restarted
|
|
|
|
as file handle has been closed */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (rc == -EAGAIN)
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->FileID = searchHandle;
|
|
|
|
pSMB->ByteCount = 0;
|
2012-03-23 18:28:02 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
|
2008-02-07 23:25:02 +00:00
|
|
|
|
2012-05-28 10:16:31 +00:00
|
|
|
cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* Since session is dead, search handle closed on server already */
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
|
2012-05-27 13:34:43 +00:00
|
|
|
const char *search_name, __u64 *inode_number,
|
2007-07-13 00:33:32 +00:00
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
TRANSACTION2_QPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QPI_RSP *pSMBr = NULL;
|
|
|
|
int name_len, bytes_returned;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (tcon == NULL)
|
2007-07-13 00:33:32 +00:00
|
|
|
return -ENODEV;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
GetInodeNumberRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
2007-07-13 00:33:32 +00:00
|
|
|
(void **) &pSMBr);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName,
|
2012-05-27 13:34:43 +00:00
|
|
|
search_name, PATH_MAX, nls_codepage,
|
2012-01-19 04:32:33 +00:00
|
|
|
remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, search_name);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
/* BB find exact max data count below from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(4000);
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else {
|
|
|
|
/* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
/* BB also check enough total bytes returned */
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 2)
|
2005-04-16 22:20:36 +00:00
|
|
|
/* If rc should we check for EOPNOSUPP and
|
|
|
|
disable the srvino flag? or in caller? */
|
|
|
|
rc = -EIO; /* bad smb */
|
2007-07-13 00:33:32 +00:00
|
|
|
else {
|
2005-04-16 22:20:36 +00:00
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
|
2007-07-13 00:33:32 +00:00
|
|
|
struct file_internal_info *pfinfo;
|
2005-04-16 22:20:36 +00:00
|
|
|
/* BB Do we need a cast or hash here ? */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (count < 8) {
|
2020-04-15 05:42:53 +00:00
|
|
|
cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = -EIO;
|
|
|
|
goto GetInodeNumOut;
|
|
|
|
}
|
|
|
|
pfinfo = (struct file_internal_info *)
|
|
|
|
(data_offset + (char *) &pSMBr->hdr.Protocol);
|
2009-04-01 05:22:00 +00:00
|
|
|
*inode_number = le64_to_cpu(pfinfo->UniqueId);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
GetInodeNumOut:
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto GetInodeNumberRetry;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
|
2012-05-27 16:21:53 +00:00
|
|
|
const char *search_name, struct dfs_info3_param **target_nodes,
|
2008-05-15 06:20:02 +00:00
|
|
|
unsigned int *num_of_nodes,
|
2005-04-29 05:41:06 +00:00
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* TRANS2_GET_DFS_REFERRAL */
|
|
|
|
TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
|
|
|
int name_len;
|
|
|
|
__u16 params, byte_count;
|
2008-05-15 06:20:02 +00:00
|
|
|
*num_of_nodes = 0;
|
|
|
|
*target_nodes = NULL;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
|
2018-01-24 12:46:10 +00:00
|
|
|
if (ses == NULL || ses->tcon_ipc == NULL)
|
2005-04-16 22:20:36 +00:00
|
|
|
return -ENODEV;
|
2018-01-24 12:46:10 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
getDFSRetry:
|
2023-03-29 20:14:22 +00:00
|
|
|
/*
|
|
|
|
* Use smb_init_no_reconnect() instead of smb_init() as
|
|
|
|
* CIFSGetDFSRefer() may be called from cifs_reconnect_tcon() and thus
|
|
|
|
* causing an infinite recursion.
|
|
|
|
*/
|
2024-11-26 20:11:47 +00:00
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc,
|
|
|
|
(void **)&pSMB, (void **)&pSMBr);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
2007-07-13 00:33:32 +00:00
|
|
|
|
|
|
|
/* server pointer checked in called function,
|
2005-08-17 19:38:22 +00:00
|
|
|
but should never be null here anyway */
|
2012-05-23 10:01:59 +00:00
|
|
|
pSMB->hdr.Mid = get_next_mid(ses->server);
|
2018-01-24 12:46:10 +00:00
|
|
|
pSMB->hdr.Tid = ses->tcon_ipc->tid;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->hdr.Uid = ses->Suid;
|
2007-08-30 22:09:15 +00:00
|
|
|
if (ses->capabilities & CAP_STATUS32)
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
|
2007-08-30 22:09:15 +00:00
|
|
|
if (ses->capabilities & CAP_DFS)
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->hdr.Flags2 |= SMBFLG2_DFS;
|
|
|
|
|
|
|
|
if (ses->capabilities & CAP_UNICODE) {
|
|
|
|
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
|
2012-05-27 16:21:53 +00:00
|
|
|
search_name, PATH_MAX, nls_codepage,
|
2012-01-19 04:32:33 +00:00
|
|
|
remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2007-07-13 00:33:32 +00:00
|
|
|
} else { /* BB improve the check for buffer overruns BB */
|
2019-08-26 23:30:14 +00:00
|
|
|
name_len = copy_path_name(pSMB->RequestFileName, search_name);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2015-04-30 14:30:24 +00:00
|
|
|
if (ses->server->sign)
|
2013-05-26 11:01:00 +00:00
|
|
|
pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
|
2006-10-12 21:33:51 +00:00
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
pSMB->hdr.Uid = ses->Suid;
|
2006-10-12 21:33:51 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
params = 2 /* level */ + name_len /*includes null */ ;
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->MaxParameterCount = 0;
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(4000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
|
|
|
|
byte_count = params + 3 /* pad */ ;
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->MaxReferralLevel = cpu_to_le16(3);
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
|
2008-05-15 06:20:02 +00:00
|
|
|
goto GetDFSRefExit;
|
|
|
|
}
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-05-15 06:20:02 +00:00
|
|
|
/* BB Also check if enough total bytes returned? */
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 17) {
|
2008-05-15 06:20:02 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
2008-05-16 09:06:30 +00:00
|
|
|
goto GetDFSRefExit;
|
|
|
|
}
|
2008-05-15 06:20:02 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
|
|
|
|
get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-05-16 09:06:30 +00:00
|
|
|
/* parse returned result into more usable form */
|
2017-02-13 15:03:47 +00:00
|
|
|
rc = parse_dfs_referrals(&pSMBr->dfs_data,
|
|
|
|
le16_to_cpu(pSMBr->t2.DataCount),
|
|
|
|
num_of_nodes, target_nodes, nls_codepage,
|
|
|
|
remap, search_name,
|
2017-03-02 21:42:48 +00:00
|
|
|
(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
|
2008-05-15 06:20:02 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
GetDFSRefExit:
|
2008-05-22 02:02:03 +00:00
|
|
|
cifs_buf_release(pSMB);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto getDFSRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-09-22 05:05:57 +00:00
|
|
|
/* Query File System Info such as free space to old servers such as Win 9x */
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct kstatfs *FSData)
|
2005-09-22 05:05:57 +00:00
|
|
|
{
|
|
|
|
/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
|
|
|
|
TRANSACTION2_QFSI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
|
|
|
|
FILE_SYSTEM_ALLOC_INFO *response_data;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "OldQFSInfo\n");
|
2005-09-22 05:05:57 +00:00
|
|
|
oldQFSInfoRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 2; /* level */
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
|
|
|
struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
|
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-09-22 05:05:57 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
|
2005-09-22 05:05:57 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 18)
|
2005-09-22 05:05:57 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
|
2011-05-04 12:05:26 +00:00
|
|
|
get_bcc(&pSMBr->hdr), data_offset);
|
2005-09-22 05:05:57 +00:00
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
response_data = (FILE_SYSTEM_ALLOC_INFO *)
|
2005-09-22 05:05:57 +00:00
|
|
|
(((char *) &pSMBr->hdr.Protocol) + data_offset);
|
|
|
|
FSData->f_bsize =
|
|
|
|
le16_to_cpu(response_data->BytesPerSector) *
|
|
|
|
le32_to_cpu(response_data->
|
|
|
|
SectorsPerAllocationUnit);
|
2018-09-15 19:07:09 +00:00
|
|
|
/*
|
|
|
|
* much prefer larger but if server doesn't report
|
|
|
|
* a valid size than 4K is a reasonable minimum
|
|
|
|
*/
|
|
|
|
if (FSData->f_bsize < 512)
|
|
|
|
FSData->f_bsize = 4096;
|
|
|
|
|
2005-09-22 05:05:57 +00:00
|
|
|
FSData->f_blocks =
|
2007-07-13 00:33:32 +00:00
|
|
|
le32_to_cpu(response_data->TotalAllocationUnits);
|
2005-09-22 05:05:57 +00:00
|
|
|
FSData->f_bfree = FSData->f_bavail =
|
|
|
|
le32_to_cpu(response_data->FreeAllocationUnits);
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
|
|
|
|
(unsigned long long)FSData->f_blocks,
|
|
|
|
(unsigned long long)FSData->f_bfree,
|
|
|
|
FSData->f_bsize);
|
2005-09-22 05:05:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto oldQFSInfoRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct kstatfs *FSData)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
|
|
|
|
TRANSACTION2_QFSI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
|
|
|
|
FILE_SYSTEM_INFO *response_data;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In QFSInfo\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
QFSInfoRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 2; /* level */
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2005-09-22 05:05:57 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else { /* decode response */
|
2007-07-13 00:33:32 +00:00
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 24)
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
|
|
|
|
response_data =
|
|
|
|
(FILE_SYSTEM_INFO
|
|
|
|
*) (((char *) &pSMBr->hdr.Protocol) +
|
|
|
|
data_offset);
|
|
|
|
FSData->f_bsize =
|
|
|
|
le32_to_cpu(response_data->BytesPerSector) *
|
|
|
|
le32_to_cpu(response_data->
|
|
|
|
SectorsPerAllocationUnit);
|
2018-09-15 19:07:09 +00:00
|
|
|
/*
|
|
|
|
* much prefer larger but if server doesn't report
|
|
|
|
* a valid size than 4K is a reasonable minimum
|
|
|
|
*/
|
|
|
|
if (FSData->f_bsize < 512)
|
|
|
|
FSData->f_bsize = 4096;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
FSData->f_blocks =
|
|
|
|
le64_to_cpu(response_data->TotalAllocationUnits);
|
|
|
|
FSData->f_bfree = FSData->f_bavail =
|
|
|
|
le64_to_cpu(response_data->FreeAllocationUnits);
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
|
|
|
|
(unsigned long long)FSData->f_blocks,
|
|
|
|
(unsigned long long)FSData->f_bfree,
|
|
|
|
FSData->f_bsize);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto QFSInfoRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
|
|
|
|
TRANSACTION2_QFSI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
|
|
|
|
FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In QFSAttributeInfo\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
QFSAttributeRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 2; /* level */
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 13) {
|
2007-07-13 00:33:32 +00:00
|
|
|
/* BB also check if enough bytes returned */
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
} else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
response_data =
|
|
|
|
(FILE_SYSTEM_ATTRIBUTE_INFO
|
|
|
|
*) (((char *) &pSMBr->hdr.Protocol) +
|
|
|
|
data_offset);
|
|
|
|
memcpy(&tcon->fsAttrInfo, response_data,
|
2007-08-30 22:09:15 +00:00
|
|
|
sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto QFSAttributeRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
|
|
|
|
TRANSACTION2_QFSI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
|
|
|
|
FILE_SYSTEM_DEVICE_INFO *response_data;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In QFSDeviceInfo\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
QFSDeviceRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 2; /* level */
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) <
|
|
|
|
sizeof(FILE_SYSTEM_DEVICE_INFO))
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
response_data =
|
2005-04-29 05:41:06 +00:00
|
|
|
(FILE_SYSTEM_DEVICE_INFO *)
|
|
|
|
(((char *) &pSMBr->hdr.Protocol) +
|
2005-04-16 22:20:36 +00:00
|
|
|
data_offset);
|
|
|
|
memcpy(&tcon->fsDevInfo, response_data,
|
2007-08-30 22:09:15 +00:00
|
|
|
sizeof(FILE_SYSTEM_DEVICE_INFO));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto QFSDeviceRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
|
|
|
|
TRANSACTION2_QFSI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
|
|
|
|
FILE_SYSTEM_UNIX_INFO *response_data;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In QFSUnixInfo\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
QFSUnixRetry:
|
2010-09-29 19:27:08 +00:00
|
|
|
rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
|
|
|
|
(void **) &pSMB, (void **) &pSMBr);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 2; /* level */
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(100);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
2007-07-13 00:33:32 +00:00
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
|
|
|
|
smb_com_transaction2_qfsi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 13) {
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
} else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
response_data =
|
|
|
|
(FILE_SYSTEM_UNIX_INFO
|
|
|
|
*) (((char *) &pSMBr->hdr.Protocol) +
|
|
|
|
data_offset);
|
|
|
|
memcpy(&tcon->fsUnixInfo, response_data,
|
2007-08-30 22:09:15 +00:00
|
|
|
sizeof(FILE_SYSTEM_UNIX_INFO));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto QFSUnixRetry;
|
|
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-06-23 00:26:35 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
|
2005-06-23 00:26:35 +00:00
|
|
|
{
|
|
|
|
/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
|
|
|
|
TRANSACTION2_SETFSI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, param_offset, offset, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In SETFSUnixInfo\n");
|
2005-06-23 00:26:35 +00:00
|
|
|
SETFSUnixRetry:
|
2006-03-01 09:17:37 +00:00
|
|
|
/* BB switch to small buf init to save memory */
|
2010-09-29 19:27:08 +00:00
|
|
|
rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
|
|
|
|
(void **) &pSMB, (void **) &pSMBr);
|
2005-06-23 00:26:35 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 4; /* 2 bytes zero followed by info level. */
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
2007-07-13 00:33:32 +00:00
|
|
|
param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
|
|
|
|
- 4;
|
2005-06-23 00:26:35 +00:00
|
|
|
offset = param_offset + params;
|
|
|
|
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(4);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(100);
|
2005-06-23 00:26:35 +00:00
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
|
|
|
|
byte_count = 1 /* pad */ + params + 12;
|
|
|
|
|
|
|
|
pSMB->DataCount = cpu_to_le16(12);
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
|
|
|
|
/* Params. */
|
|
|
|
pSMB->FileNum = 0;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
|
|
|
|
|
|
|
|
/* Data. */
|
|
|
|
pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
|
|
|
|
pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
|
|
|
|
pSMB->ClientUnixCap = cpu_to_le64(cap);
|
|
|
|
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-06-23 00:26:35 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
|
2005-06-23 00:26:35 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2005-06-23 00:26:35 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto SETFSUnixRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
2005-04-29 05:41:06 +00:00
|
|
|
struct kstatfs *FSData)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
|
|
|
|
TRANSACTION2_QFSI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QFSI_RSP *pSMBr = NULL;
|
|
|
|
FILE_SYSTEM_POSIX_INFO *response_data;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In QFSPosixInfo\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
QFSPosixRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
params = 2; /* level */
|
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(100);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
2007-07-13 00:33:32 +00:00
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
|
|
|
|
smb_com_transaction2_qfsi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
} else { /* decode response */
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 13) {
|
2005-04-16 22:20:36 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
} else {
|
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
response_data =
|
|
|
|
(FILE_SYSTEM_POSIX_INFO
|
|
|
|
*) (((char *) &pSMBr->hdr.Protocol) +
|
|
|
|
data_offset);
|
|
|
|
FSData->f_bsize =
|
|
|
|
le32_to_cpu(response_data->BlockSize);
|
2018-09-15 19:07:09 +00:00
|
|
|
/*
|
|
|
|
* much prefer larger but if server doesn't report
|
|
|
|
* a valid size than 4K is a reasonable minimum
|
|
|
|
*/
|
|
|
|
if (FSData->f_bsize < 512)
|
|
|
|
FSData->f_bsize = 4096;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
FSData->f_blocks =
|
|
|
|
le64_to_cpu(response_data->TotalBlocks);
|
|
|
|
FSData->f_bfree =
|
|
|
|
le64_to_cpu(response_data->BlocksAvail);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
FSData->f_bavail = FSData->f_bfree;
|
|
|
|
} else {
|
|
|
|
FSData->f_bavail =
|
2007-07-13 00:33:32 +00:00
|
|
|
le64_to_cpu(response_data->UserBlocksAvail);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2007-07-07 19:25:05 +00:00
|
|
|
if (response_data->TotalFileNodes != cpu_to_le64(-1))
|
2005-04-16 22:20:36 +00:00
|
|
|
FSData->f_files =
|
2007-07-13 00:33:32 +00:00
|
|
|
le64_to_cpu(response_data->TotalFileNodes);
|
2007-07-07 19:25:05 +00:00
|
|
|
if (response_data->FreeFileNodes != cpu_to_le64(-1))
|
2005-04-16 22:20:36 +00:00
|
|
|
FSData->f_ffree =
|
2007-07-13 00:33:32 +00:00
|
|
|
le64_to_cpu(response_data->FreeFileNodes);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto QFSPosixRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-18 23:20:31 +00:00
|
|
|
/*
|
|
|
|
* We can not use write of zero bytes trick to set file size due to need for
|
|
|
|
* large file support. Also note that this SetPathInfo is preferred to
|
|
|
|
* SetFileInfo based method in next routine which is only needed to work around
|
|
|
|
* a sharing violation bugin Samba which this routine can run into.
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
|
2012-09-18 23:20:31 +00:00
|
|
|
const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
|
smb: client: reuse file lease key in compound operations
Currently, when a rename, unlink or set path size compound operation
is requested on a file that has a lot of dirty pages to be written
to the server, we do not send the lease key for these requests. As a
result, the server can assume that this request is from a new client, and
send a lease break notification to the same client, on the same
connection. As a response to the lease break, the client can consume
several credits to write the dirty pages to the server. Depending on the
server's credit grant implementation, the server can stop granting more
credits to this connection, and this can cause a deadlock (which can only
be resolved when the lease timer on the server expires).
One of the problems here is that the client is sending no lease key,
even if it has a lease for the file. This patch fixes the problem by
reusing the existing lease key on the file for rename, unlink and set path
size compound operations so that the client does not break its own lease.
A very trivial example could be a set of commands by a client that
maintains open handle (for write) to a file and then tries to copy the
contents of that file to another one, eg.,
tail -f /dev/null > myfile &
mv myfile myfile2
Presently, the network capture on the client shows that the move (or
rename) would trigger a lease break on the same client, for the same file.
With the lease key reused, the lease break request-response overhead is
eliminated, thereby reducing the roundtrips performed for this set of
operations.
The patch fixes the bug described above and also provides perf benefit.
Signed-off-by: Meetakshi Setiya <msetiya@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
2024-03-06 03:43:51 +00:00
|
|
|
bool set_allocation, struct dentry *dentry)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct smb_com_transaction2_spi_req *pSMB = NULL;
|
|
|
|
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
|
|
|
|
struct file_end_of_file_info *parm_data;
|
|
|
|
int name_len;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
2014-09-27 07:19:01 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
2012-09-18 23:20:31 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
__u16 params, byte_count, data_count, param_offset, offset;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In SetEOF\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
SetEOFRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-09-18 23:20:31 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
|
|
|
|
PATH_MAX, cifs_sb->local_nls, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, file_name);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
params = 6 + name_len;
|
2007-08-30 22:09:15 +00:00
|
|
|
data_count = sizeof(struct file_end_of_file_info);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2005-09-19 03:49:21 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le16(4100);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
2007-07-13 00:33:32 +00:00
|
|
|
InformationLevel) - 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
offset = param_offset + params;
|
2012-09-18 23:20:31 +00:00
|
|
|
if (set_allocation) {
|
2007-07-13 00:33:32 +00:00
|
|
|
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
|
|
|
|
pSMB->InformationLevel =
|
|
|
|
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
|
|
|
|
else
|
|
|
|
pSMB->InformationLevel =
|
|
|
|
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
|
|
|
|
} else /* Set File Size */ {
|
2005-04-16 22:20:36 +00:00
|
|
|
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
|
|
|
|
pSMB->InformationLevel =
|
2007-07-13 00:33:32 +00:00
|
|
|
cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
|
2005-04-16 22:20:36 +00:00
|
|
|
else
|
|
|
|
pSMB->InformationLevel =
|
2007-07-13 00:33:32 +00:00
|
|
|
cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
parm_data =
|
|
|
|
(struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
|
|
|
|
offset);
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + data_count;
|
|
|
|
pSMB->DataCount = cpu_to_le16(data_count);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
parm_data->FileSize = cpu_to_le64(size);
|
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto SetEOFRetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-09-18 23:20:31 +00:00
|
|
|
CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
|
|
|
struct file_end_of_file_info *parm_data;
|
|
|
|
int rc = 0;
|
|
|
|
__u16 params, param_offset, offset, byte_count, count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
|
|
|
|
(long long)size);
|
2005-04-29 05:41:10 +00:00
|
|
|
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2012-09-18 23:20:31 +00:00
|
|
|
pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
|
|
|
|
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
|
2007-07-13 00:33:32 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
params = 6;
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
|
|
|
offset = param_offset + params;
|
|
|
|
|
|
|
|
count = sizeof(struct file_end_of_file_info);
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + count;
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
2021-07-07 02:27:26 +00:00
|
|
|
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
|
2005-04-16 22:20:36 +00:00
|
|
|
parm_data =
|
2021-07-07 02:27:26 +00:00
|
|
|
(struct file_end_of_file_info *)(((char *)pSMB) + offset + 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
parm_data->FileSize = cpu_to_le64(size);
|
2012-09-18 23:20:31 +00:00
|
|
|
pSMB->Fid = cfile->fid.netfid;
|
|
|
|
if (set_allocation) {
|
2005-04-16 22:20:36 +00:00
|
|
|
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
|
|
|
|
pSMB->InformationLevel =
|
|
|
|
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
|
|
|
|
else
|
|
|
|
pSMB->InformationLevel =
|
|
|
|
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
|
2007-07-13 00:33:32 +00:00
|
|
|
} else /* Set File Size */ {
|
2005-04-16 22:20:36 +00:00
|
|
|
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
|
|
|
|
pSMB->InformationLevel =
|
2007-07-13 00:33:32 +00:00
|
|
|
cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
|
2005-04-16 22:20:36 +00:00
|
|
|
else
|
|
|
|
pSMB->InformationLevel =
|
2007-07-13 00:33:32 +00:00
|
|
|
cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
2012-03-23 18:28:02 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
|
|
|
|
rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
2005-04-16 22:20:36 +00:00
|
|
|
since file handle passed in no longer valid */
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/* Some legacy servers such as NT4 require that the file times be set on
|
2005-04-16 22:20:36 +00:00
|
|
|
an open handle, rather than by pathname - this is awkward due to
|
|
|
|
potential access conflicts on the open, but it is unavoidable for these
|
|
|
|
old servers since the only other choice is to go from 100 nanosecond DCE
|
|
|
|
time and resort to the original setpathinfo level which takes the ancient
|
|
|
|
DOS time format with 2 second granularity */
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
2008-08-02 11:26:12 +00:00
|
|
|
const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
|
|
|
char *data_offset;
|
|
|
|
int rc = 0;
|
|
|
|
__u16 params, param_offset, offset, byte_count, count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
|
2005-04-29 05:41:10 +00:00
|
|
|
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2008-08-02 11:26:12 +00:00
|
|
|
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
|
|
|
|
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
|
2007-07-13 00:33:32 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
params = 6;
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
|
|
|
offset = param_offset + params;
|
|
|
|
|
2012-03-26 13:55:29 +00:00
|
|
|
data_offset = (char *)pSMB +
|
|
|
|
offsetof(struct smb_hdr, Protocol) + offset;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-08-30 22:09:15 +00:00
|
|
|
count = sizeof(FILE_BASIC_INFO);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find max SMB PDU from sess */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + count;
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->Fid = fid;
|
|
|
|
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
|
|
|
|
else
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
2007-07-13 00:33:32 +00:00
|
|
|
memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
|
2012-03-23 18:28:02 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
|
|
|
|
rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
2005-04-16 22:20:36 +00:00
|
|
|
since file handle passed in no longer valid */
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-09-23 15:48:35 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
|
2008-09-23 15:48:35 +00:00
|
|
|
bool delete_file, __u16 fid, __u32 pid_of_opener)
|
|
|
|
{
|
|
|
|
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
|
|
|
char *data_offset;
|
|
|
|
int rc = 0;
|
|
|
|
__u16 params, param_offset, offset, byte_count, count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
|
2008-09-23 15:48:35 +00:00
|
|
|
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
|
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
|
|
|
|
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
|
|
|
|
|
|
|
|
params = 6;
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
|
|
|
offset = param_offset + params;
|
|
|
|
|
2021-07-07 02:42:08 +00:00
|
|
|
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
|
|
|
|
data_offset = (char *)(pSMB) + offset + 4;
|
2008-09-23 15:48:35 +00:00
|
|
|
|
|
|
|
count = 1;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
/* BB find max SMB PDU from sess */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + count;
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->Fid = fid;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2008-09-23 15:48:35 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
*data_offset = delete_file ? 1 : 0;
|
2012-03-23 18:28:02 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2008-09-23 15:48:35 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
|
2008-09-23 15:48:35 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2020-07-14 22:18:05 +00:00
|
|
|
static int
|
|
|
|
CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *fileName, const FILE_BASIC_INFO *data,
|
|
|
|
const struct nls_table *nls_codepage,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
|
|
|
int oplock = 0;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct cifs_fid fid;
|
|
|
|
int rc;
|
|
|
|
|
2023-01-11 11:37:58 +00:00
|
|
|
oparms = (struct cifs_open_parms) {
|
|
|
|
.tcon = tcon,
|
|
|
|
.cifs_sb = cifs_sb,
|
|
|
|
.desired_access = GENERIC_WRITE,
|
|
|
|
.create_options = cifs_create_options(cifs_sb, 0),
|
|
|
|
.disposition = FILE_OPEN,
|
|
|
|
.path = fileName,
|
|
|
|
.fid = &fid,
|
|
|
|
};
|
2020-07-14 22:18:05 +00:00
|
|
|
|
|
|
|
rc = CIFS_open(xid, &oparms, &oplock, NULL);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
|
|
|
|
CIFSSMBClose(xid, tcon, fid.netfid);
|
|
|
|
out:
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
2008-08-02 11:26:12 +00:00
|
|
|
const char *fileName, const FILE_BASIC_INFO *data,
|
2020-07-14 22:18:05 +00:00
|
|
|
const struct nls_table *nls_codepage,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
|
|
|
int name_len;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
char *data_offset;
|
|
|
|
__u16 params, param_offset, offset, byte_count, count;
|
2020-07-14 22:18:05 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In SetTimes\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
SetTimesRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, fileName);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
params = 6 + name_len;
|
2007-08-30 22:09:15 +00:00
|
|
|
count = sizeof(FILE_BASIC_INFO);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
2007-07-13 00:33:32 +00:00
|
|
|
InformationLevel) - 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
offset = param_offset + params;
|
2024-11-17 11:32:09 +00:00
|
|
|
data_offset = (char *)pSMB + offsetof(typeof(*pSMB), hdr.Protocol) + offset;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + count;
|
|
|
|
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
|
|
|
|
else
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2007-08-30 22:09:15 +00:00
|
|
|
memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto SetTimesRetry;
|
|
|
|
|
2020-07-14 22:18:05 +00:00
|
|
|
if (rc == -EOPNOTSUPP)
|
|
|
|
return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
|
|
|
|
nls_codepage, cifs_sb);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2009-07-10 00:02:49 +00:00
|
|
|
static void
|
|
|
|
cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
|
|
|
|
const struct cifs_unix_set_info_args *args)
|
|
|
|
{
|
2013-02-06 08:57:56 +00:00
|
|
|
u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
|
2009-07-10 00:02:49 +00:00
|
|
|
u64 mode = args->mode;
|
|
|
|
|
2013-02-06 08:57:56 +00:00
|
|
|
if (uid_valid(args->uid))
|
|
|
|
uid = from_kuid(&init_user_ns, args->uid);
|
|
|
|
if (gid_valid(args->gid))
|
|
|
|
gid = from_kgid(&init_user_ns, args->gid);
|
|
|
|
|
2009-07-10 00:02:49 +00:00
|
|
|
/*
|
|
|
|
* Samba server ignores set of file size to zero due to bugs in some
|
|
|
|
* older clients, but we should be precise - we use SetFileSize to
|
|
|
|
* set file size and do not want to truncate file size to zero
|
2011-03-31 01:57:33 +00:00
|
|
|
* accidentally as happened on one Samba server beta by putting
|
2009-07-10 00:02:49 +00:00
|
|
|
* zero instead of -1 here
|
|
|
|
*/
|
|
|
|
data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
|
|
|
|
data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
|
|
|
|
data_offset->LastStatusChange = cpu_to_le64(args->ctime);
|
|
|
|
data_offset->LastAccessTime = cpu_to_le64(args->atime);
|
|
|
|
data_offset->LastModificationTime = cpu_to_le64(args->mtime);
|
2013-02-06 08:57:56 +00:00
|
|
|
data_offset->Uid = cpu_to_le64(uid);
|
|
|
|
data_offset->Gid = cpu_to_le64(gid);
|
2009-07-10 00:02:49 +00:00
|
|
|
/* better to leave device as zero when it is */
|
|
|
|
data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
|
|
|
|
data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
|
|
|
|
data_offset->Permissions = cpu_to_le64(mode);
|
|
|
|
|
|
|
|
if (S_ISREG(mode))
|
|
|
|
data_offset->Type = cpu_to_le32(UNIX_FILE);
|
|
|
|
else if (S_ISDIR(mode))
|
|
|
|
data_offset->Type = cpu_to_le32(UNIX_DIR);
|
|
|
|
else if (S_ISLNK(mode))
|
|
|
|
data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
|
|
|
|
else if (S_ISCHR(mode))
|
|
|
|
data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
|
|
|
|
else if (S_ISBLK(mode))
|
|
|
|
data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
|
|
|
|
else if (S_ISFIFO(mode))
|
|
|
|
data_offset->Type = cpu_to_le32(UNIX_FIFO);
|
|
|
|
else if (S_ISSOCK(mode))
|
|
|
|
data_offset->Type = cpu_to_le32(UNIX_SOCKET);
|
|
|
|
}
|
|
|
|
|
2009-07-10 00:02:50 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
2009-07-10 00:02:50 +00:00
|
|
|
const struct cifs_unix_set_info_args *args,
|
|
|
|
u16 fid, u32 pid_of_opener)
|
|
|
|
{
|
|
|
|
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
2012-03-26 13:55:29 +00:00
|
|
|
char *data_offset;
|
2009-07-10 00:02:50 +00:00
|
|
|
int rc = 0;
|
|
|
|
u16 params, param_offset, offset, byte_count, count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
|
2009-07-10 00:02:50 +00:00
|
|
|
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
|
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
|
|
|
|
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
|
|
|
|
|
|
|
|
params = 6;
|
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
|
|
|
offset = param_offset + params;
|
|
|
|
|
2012-03-26 13:55:29 +00:00
|
|
|
data_offset = (char *)pSMB +
|
|
|
|
offsetof(struct smb_hdr, Protocol) + offset;
|
|
|
|
|
2009-07-10 00:02:50 +00:00
|
|
|
count = sizeof(FILE_UNIX_BASIC_INFO);
|
|
|
|
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
|
|
|
/* BB find max SMB PDU from sess */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + count;
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->Fid = fid;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2009-07-10 00:02:50 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
2012-03-26 13:55:29 +00:00
|
|
|
cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
|
2009-07-10 00:02:50 +00:00
|
|
|
|
2012-03-23 18:28:02 +00:00
|
|
|
rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
|
2016-10-25 18:38:47 +00:00
|
|
|
cifs_small_buf_release(pSMB);
|
2009-07-10 00:02:50 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
|
|
|
|
rc);
|
2009-07-10 00:02:50 +00:00
|
|
|
|
|
|
|
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
|
|
|
since file handle passed in no longer valid */
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
2012-07-13 10:04:46 +00:00
|
|
|
const char *file_name,
|
2009-07-10 00:02:49 +00:00
|
|
|
const struct cifs_unix_set_info_args *args,
|
|
|
|
const struct nls_table *nls_codepage, int remap)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
|
|
|
int name_len;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
FILE_UNIX_BASIC_INFO *data_offset;
|
|
|
|
__u16 params, param_offset, offset, count, byte_count;
|
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In SetUID/GID/Mode\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
setPermsRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-07-13 10:04:46 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
|
2012-01-19 04:32:33 +00:00
|
|
|
PATH_MAX, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, file_name);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
params = 6 + name_len;
|
2007-08-30 22:09:15 +00:00
|
|
|
count = sizeof(FILE_UNIX_BASIC_INFO);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find max SMB PDU from sess structure BB */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
2007-07-13 00:33:32 +00:00
|
|
|
InformationLevel) - 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
offset = param_offset + params;
|
2021-07-02 02:01:19 +00:00
|
|
|
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
|
|
|
|
data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
memset(data_offset, 0, count);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + count;
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2009-07-10 00:02:49 +00:00
|
|
|
cifs_fill_unix_set_info(data_offset, args);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-05-22 02:02:03 +00:00
|
|
|
cifs_buf_release(pSMB);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto setPermsRetry;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_CIFS_XATTR
|
2010-02-10 21:18:26 +00:00
|
|
|
/*
|
|
|
|
* Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
|
|
|
|
* function used by listxattr and getxattr type calls. When ea_name is set,
|
|
|
|
* it looks for that attribute name and stuffs that value into the EAData
|
|
|
|
* buffer. When ea_name is NULL, it stuffs a list of attribute names into the
|
|
|
|
* buffer. In both cases, the return value is either the length of the
|
|
|
|
* resulting data or a negative error code. If EAData is a NULL pointer then
|
|
|
|
* the data isn't copied to it, but the length is returned.
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
ssize_t
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
|
2010-02-10 21:18:26 +00:00
|
|
|
const unsigned char *searchName, const unsigned char *ea_name,
|
|
|
|
char *EAData, size_t buf_size,
|
2017-05-13 01:59:10 +00:00
|
|
|
struct cifs_sb_info *cifs_sb)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/* BB assumes one setup word */
|
|
|
|
TRANSACTION2_QPI_REQ *pSMB = NULL;
|
|
|
|
TRANSACTION2_QPI_RSP *pSMBr = NULL;
|
2017-05-13 01:59:10 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
|
|
|
struct nls_table *nls_codepage = cifs_sb->local_nls;
|
2005-04-16 22:20:36 +00:00
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned;
|
2010-02-10 21:18:26 +00:00
|
|
|
int list_len;
|
2010-02-10 21:18:26 +00:00
|
|
|
struct fealist *ea_response_data;
|
2007-07-13 00:33:32 +00:00
|
|
|
struct fea *temp_fea;
|
|
|
|
char *temp_ptr;
|
2010-02-10 21:18:26 +00:00
|
|
|
char *end_of_smb;
|
2010-02-10 21:18:26 +00:00
|
|
|
__u16 params, byte_count, data_offset;
|
2011-07-28 16:48:26 +00:00
|
|
|
unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
|
2005-04-16 22:20:36 +00:00
|
|
|
QAllEAsRetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
2010-02-10 21:18:26 +00:00
|
|
|
list_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2010-02-10 21:18:26 +00:00
|
|
|
list_len++; /* trailing null */
|
|
|
|
list_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
list_len = copy_path_name(pSMB->FileName, searchName);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2010-02-10 21:18:26 +00:00
|
|
|
params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find exact max SMB PDU from sess structure BB */
|
2010-02-10 21:18:26 +00:00
|
|
|
pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
pSMB->ParameterOffset = cpu_to_le16(offsetof(
|
2007-07-13 00:33:32 +00:00
|
|
|
struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->DataCount = 0;
|
|
|
|
pSMB->DataOffset = 0;
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
|
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
|
pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
|
if (rc) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
|
2010-02-10 21:18:26 +00:00
|
|
|
goto QAllEAsOut;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2010-02-10 21:18:26 +00:00
|
|
|
|
|
|
|
/* BB also check enough total bytes returned */
|
|
|
|
/* BB we need to improve the validity checking
|
|
|
|
of these trans2 responses */
|
|
|
|
|
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
2011-05-04 12:05:26 +00:00
|
|
|
if (rc || get_bcc(&pSMBr->hdr) < 4) {
|
2010-02-10 21:18:26 +00:00
|
|
|
rc = -EIO; /* bad smb */
|
|
|
|
goto QAllEAsOut;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check that length of list is not more than bcc */
|
|
|
|
/* check that each entry does not go beyond length
|
|
|
|
of list */
|
|
|
|
/* check that each element of each entry does not
|
|
|
|
go beyond end of list */
|
|
|
|
/* validate_trans2_offsets() */
|
|
|
|
/* BB check if start of smb + data_offset > &bcc+ bcc */
|
|
|
|
|
|
|
|
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
ea_response_data = (struct fealist *)
|
|
|
|
(((char *) &pSMBr->hdr.Protocol) + data_offset);
|
|
|
|
|
2010-02-10 21:18:26 +00:00
|
|
|
list_len = le32_to_cpu(ea_response_data->list_len);
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "ea length %d\n", list_len);
|
2010-02-10 21:18:26 +00:00
|
|
|
if (list_len <= 8) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "empty EA list returned from server\n");
|
2014-03-26 00:46:36 +00:00
|
|
|
/* didn't find the named attribute */
|
|
|
|
if (ea_name)
|
|
|
|
rc = -ENODATA;
|
2010-02-10 21:18:26 +00:00
|
|
|
goto QAllEAsOut;
|
|
|
|
}
|
|
|
|
|
2010-02-10 21:18:26 +00:00
|
|
|
/* make sure list_len doesn't go past end of SMB */
|
2011-01-20 18:36:51 +00:00
|
|
|
end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
|
2010-02-10 21:18:26 +00:00
|
|
|
if ((char *)ea_response_data + list_len > end_of_smb) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
|
2010-02-10 21:18:26 +00:00
|
|
|
rc = -EIO;
|
|
|
|
goto QAllEAsOut;
|
|
|
|
}
|
|
|
|
|
2010-02-10 21:18:26 +00:00
|
|
|
/* account for ea list len */
|
2010-02-10 21:18:26 +00:00
|
|
|
list_len -= 4;
|
2023-02-15 00:08:39 +00:00
|
|
|
temp_fea = &ea_response_data->list;
|
2010-02-10 21:18:26 +00:00
|
|
|
temp_ptr = (char *)temp_fea;
|
2010-02-10 21:18:26 +00:00
|
|
|
while (list_len > 0) {
|
2010-02-24 21:56:48 +00:00
|
|
|
unsigned int name_len;
|
2010-02-10 21:18:26 +00:00
|
|
|
__u16 value_len;
|
2010-02-10 21:18:26 +00:00
|
|
|
|
2010-02-10 21:18:26 +00:00
|
|
|
list_len -= 4;
|
2010-02-10 21:18:26 +00:00
|
|
|
temp_ptr += 4;
|
2010-02-10 21:18:26 +00:00
|
|
|
/* make sure we can read name_len and value_len */
|
|
|
|
if (list_len < 0) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
|
2010-02-10 21:18:26 +00:00
|
|
|
rc = -EIO;
|
|
|
|
goto QAllEAsOut;
|
|
|
|
}
|
|
|
|
|
|
|
|
name_len = temp_fea->name_len;
|
|
|
|
value_len = le16_to_cpu(temp_fea->value_len);
|
|
|
|
list_len -= name_len + 1 + value_len;
|
|
|
|
if (list_len < 0) {
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
|
2010-02-10 21:18:26 +00:00
|
|
|
rc = -EIO;
|
|
|
|
goto QAllEAsOut;
|
|
|
|
}
|
|
|
|
|
2010-02-10 21:18:26 +00:00
|
|
|
if (ea_name) {
|
2011-07-26 22:23:47 +00:00
|
|
|
if (ea_name_len == name_len &&
|
2011-10-11 10:41:32 +00:00
|
|
|
memcmp(ea_name, temp_ptr, name_len) == 0) {
|
2010-02-10 21:18:26 +00:00
|
|
|
temp_ptr += name_len + 1;
|
|
|
|
rc = value_len;
|
|
|
|
if (buf_size == 0)
|
|
|
|
goto QAllEAsOut;
|
|
|
|
if ((size_t)value_len > buf_size) {
|
|
|
|
rc = -ERANGE;
|
|
|
|
goto QAllEAsOut;
|
|
|
|
}
|
|
|
|
memcpy(EAData, temp_ptr, value_len);
|
|
|
|
goto QAllEAsOut;
|
|
|
|
}
|
2010-02-10 21:18:26 +00:00
|
|
|
} else {
|
2010-02-10 21:18:26 +00:00
|
|
|
/* account for prefix user. and trailing null */
|
|
|
|
rc += (5 + 1 + name_len);
|
|
|
|
if (rc < (int) buf_size) {
|
|
|
|
memcpy(EAData, "user.", 5);
|
|
|
|
EAData += 5;
|
|
|
|
memcpy(EAData, temp_ptr, name_len);
|
|
|
|
EAData += name_len;
|
|
|
|
/* null terminate name */
|
|
|
|
*EAData = 0;
|
|
|
|
++EAData;
|
|
|
|
} else if (buf_size == 0) {
|
|
|
|
/* skip copy - calc size only */
|
|
|
|
} else {
|
|
|
|
/* stop before overrun buffer */
|
|
|
|
rc = -ERANGE;
|
|
|
|
break;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2010-02-10 21:18:26 +00:00
|
|
|
temp_ptr += name_len + 1 + value_len;
|
2010-02-10 21:18:26 +00:00
|
|
|
temp_fea = (struct fea *)temp_ptr;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2010-02-10 21:18:26 +00:00
|
|
|
|
2010-02-10 21:18:26 +00:00
|
|
|
/* didn't find the named attribute */
|
|
|
|
if (ea_name)
|
|
|
|
rc = -ENODATA;
|
|
|
|
|
2010-02-10 21:18:26 +00:00
|
|
|
QAllEAsOut:
|
2008-05-22 02:02:03 +00:00
|
|
|
cifs_buf_release(pSMB);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto QAllEAsRetry;
|
|
|
|
|
|
|
|
return (ssize_t)rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-20 07:21:16 +00:00
|
|
|
CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *fileName, const char *ea_name, const void *ea_value,
|
2007-07-13 00:33:32 +00:00
|
|
|
const __u16 ea_value_len, const struct nls_table *nls_codepage,
|
2017-08-24 01:24:56 +00:00
|
|
|
struct cifs_sb_info *cifs_sb)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct smb_com_transaction2_spi_req *pSMB = NULL;
|
|
|
|
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
|
|
|
|
struct fealist *parm_data;
|
|
|
|
int name_len;
|
|
|
|
int rc = 0;
|
|
|
|
int bytes_returned = 0;
|
|
|
|
__u16 params, param_offset, byte_count, offset, count;
|
2017-08-24 01:24:56 +00:00
|
|
|
int remap = cifs_remap(cifs_sb);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "In SetEA\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
SetEARetry:
|
|
|
|
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
|
|
|
|
(void **) &pSMBr);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
|
name_len =
|
2012-01-19 04:32:33 +00:00
|
|
|
cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
|
|
|
|
PATH_MAX, nls_codepage, remap);
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len++; /* trailing null */
|
|
|
|
name_len *= 2;
|
2019-08-26 23:30:14 +00:00
|
|
|
} else {
|
|
|
|
name_len = copy_path_name(pSMB->FileName, fileName);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
params = 6 + name_len;
|
|
|
|
|
|
|
|
/* done calculating parms using name_len of file name,
|
|
|
|
now use name_len to calculate length of ea name
|
|
|
|
we are going to create in the inode xattrs */
|
2007-07-07 19:25:05 +00:00
|
|
|
if (ea_name == NULL)
|
2005-04-16 22:20:36 +00:00
|
|
|
name_len = 0;
|
|
|
|
else
|
2007-07-13 00:33:32 +00:00
|
|
|
name_len = strnlen(ea_name, 255);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-02-15 00:08:39 +00:00
|
|
|
count = sizeof(*parm_data) + 1 + ea_value_len + name_len;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
2008-05-13 04:54:12 +00:00
|
|
|
/* BB find max SMB PDU from sess */
|
|
|
|
pSMB->MaxDataCount = cpu_to_le16(1000);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->MaxSetupCount = 0;
|
|
|
|
pSMB->Reserved = 0;
|
|
|
|
pSMB->Flags = 0;
|
|
|
|
pSMB->Timeout = 0;
|
|
|
|
pSMB->Reserved2 = 0;
|
|
|
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
2007-07-13 00:33:32 +00:00
|
|
|
InformationLevel) - 4;
|
2005-04-16 22:20:36 +00:00
|
|
|
offset = param_offset + params;
|
|
|
|
pSMB->InformationLevel =
|
|
|
|
cpu_to_le16(SMB_SET_FILE_EA);
|
|
|
|
|
2018-02-02 15:48:47 +00:00
|
|
|
parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
|
|
|
pSMB->DataOffset = cpu_to_le16(offset);
|
|
|
|
pSMB->SetupCount = 1;
|
|
|
|
pSMB->Reserved3 = 0;
|
|
|
|
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
|
|
|
|
byte_count = 3 /* pad */ + params + count;
|
|
|
|
pSMB->DataCount = cpu_to_le16(count);
|
|
|
|
parm_data->list_len = cpu_to_le32(count);
|
2023-02-15 00:08:39 +00:00
|
|
|
parm_data->list.EA_flags = 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
/* we checked above that name len is less than 255 */
|
2023-02-15 00:08:39 +00:00
|
|
|
parm_data->list.name_len = (__u8)name_len;
|
2024-03-28 21:44:48 +00:00
|
|
|
/* EA names are always ASCII and NUL-terminated */
|
|
|
|
strscpy(parm_data->list.name, ea_name ?: "", name_len + 1);
|
2023-02-15 00:08:39 +00:00
|
|
|
parm_data->list.value_len = cpu_to_le16(ea_value_len);
|
2005-04-16 22:20:36 +00:00
|
|
|
/* caller ensures that ea_value_len is less than 64K but
|
|
|
|
we need to ensure that it fits within the smb */
|
|
|
|
|
2007-07-13 00:33:32 +00:00
|
|
|
/*BB add length check to see if it would fit in
|
|
|
|
negotiated SMB buffer size BB */
|
2007-07-07 19:25:05 +00:00
|
|
|
/* if (ea_value_len > buffer_size - 512 (enough for header)) */
|
|
|
|
if (ea_value_len)
|
2023-02-15 00:08:39 +00:00
|
|
|
memcpy(parm_data->list.name + name_len + 1,
|
2007-07-13 00:33:32 +00:00
|
|
|
ea_value, ea_value_len);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
pSMB->TotalDataCount = pSMB->DataCount;
|
|
|
|
pSMB->ParameterCount = cpu_to_le16(params);
|
|
|
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
|
|
|
pSMB->Reserved4 = 0;
|
2011-04-29 05:40:20 +00:00
|
|
|
inc_rfc1001_len(pSMB, byte_count);
|
2005-04-16 22:20:36 +00:00
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
2008-02-07 23:25:02 +00:00
|
|
|
if (rc)
|
2013-05-05 03:12:25 +00:00
|
|
|
cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
goto SetEARetry;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
#endif
|