smb_rename.c revision ccc71be50bb49efb4e31004c77fb3e065e9c0596
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_fsops.h>
/*
* NT_RENAME InformationLevels:
*
* SMB_NT_RENAME_MOVE_CLUSTER_INFO Server returns invalid parameter.
* SMB_NT_RENAME_SET_LINK_INFO Create a hard link to a file.
* SMB_NT_RENAME_RENAME_FILE In-place rename of a file.
* SMB_NT_RENAME_MOVE_FILE Move (rename) a file.
*/
#define SMB_NT_RENAME_MOVE_CLUSTER_INFO 0x0102
#define SMB_NT_RENAME_SET_LINK_INFO 0x0103
#define SMB_NT_RENAME_RENAME_FILE 0x0104
#define SMB_NT_RENAME_MOVE_FILE 0x0105
/*
* SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
*/
#define SMB_RENAME_FLAG_OVERWRITE 0x001
static void smb_rename_set_error(smb_request_t *, int);
static int smb_rename_lookup_src(smb_request_t *);
static void smb_rename_release_src(smb_request_t *);
/*
* smb_com_rename
*
* Rename a file. Files OldFileName must exist and NewFileName must not.
* Both pathnames must be relative to the Tid specified in the request.
* Open files may be renamed.
*
* Multiple files may be renamed in response to a single request as Rename
* File supports wildcards in the file name (last component of the path).
* NOTE: we don't support rename with wildcards.
*
* SearchAttributes indicates the attributes that the target file(s) must
* have. If SearchAttributes is zero then only normal files are renamed.
* If the system file or hidden attributes are specified then the rename
* is inclusive - both the specified type(s) of files and normal files are
* renamed.
*/
{
int rc;
}
}
void
{
}
{
int rc;
return (SDRC_ERROR);
}
return (SDRC_ERROR);
}
if (rc != 0) {
return (SDRC_ERROR);
}
}
/*
* smb_com_nt_rename
*
* Rename a file. Files OldFileName must exist and NewFileName must not.
* Both pathnames must be relative to the Tid specified in the request.
* Open files may be renamed.
*
* SearchAttributes indicates the attributes that the target file(s) must
* have. If SearchAttributes is zero then only normal files are renamed.
* If the system file or hidden attributes are specified then the rename
* is inclusive - both the specified type(s) of files and normal files are
* renamed.
*/
{
int rc;
if (rc == 0) {
}
}
void
{
}
{
int rc;
return (SDRC_ERROR);
}
return (SDRC_ERROR);
}
return (SDRC_ERROR);
}
break;
case SMB_NT_RENAME_MOVE_FILE:
break;
break;
default:
break;
}
if (rc != 0) {
return (SDRC_ERROR);
}
}
/*
* smb_nt_transact_rename
*
* Windows servers return SUCCESS without renaming file.
* The only check required is to check that the handle (fid) is valid.
*/
{
return (SDRC_ERROR);
return (SDRC_ERROR);
}
return (SDRC_SUCCESS);
}
/*
* smb_trans2_rename
*
* Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
* and Trans2_Set_PathInfo.
* If the new filename (dst_fqi) already exists it may be overwritten
* if flags == 1.
*/
int
{
int rc = 0;
char *path;
int len;
/* costruct and validate the dst pathname */
} else {
path, MAXPATHLEN);
if (rc != 0) {
return (-1);
}
}
return (-1);
if (rc != 0) {
return (-1);
}
return (0);
}
/*
* smb_common_rename
*
* Common code for renaming a file.
*
* If the source and destination are identical, we go through all
* the checks but we don't actually do the rename. If the source
* and destination files differ only in case, we do a case-sensitive
* rename. Otherwise, we do a full case-insensitive rename.
*
* Returns errno values.
*/
static int
{
/* Check if attempting to rename a stream - not yet supported */
if (rc != 0)
return (rc);
/* The source node may already have been provided */
} else {
/* lookup and validate src node */
if (rc != 0)
return (rc);
}
/* Find destination dnode and last_comp */
} else {
if (rc != 0) {
return (rc);
}
}
/* If exact name match in same directory, we're done */
return (0);
}
/* Lookup destination node */
/* If the destination node doesn't already exist, validate new_name. */
if (smb_is_invalid_filename(new_name)) {
return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */
}
}
/*
* Handle case where changing case of the same directory entry.
*
* If we found the dst node in the same directory as the src node,
* and their names differ only in case:
*
* If the tree is case sensitive (or mixed):
* Do case sensitive lookup to see if exact match exists.
* If the exact match is the same node as src_node we're done.
*
* If the tree is case insensitive:
* There is currently no way to tell if the case is different
* or not, so do the rename (unless the specified new name was
* mangled).
*/
if ((rc == 0) &&
dst_fqi->fq_last_comp, 0) != 0) {
return (0);
}
} else {
if ((rc == 0) &&
return (0);
}
}
}
return (rc);
}
return (EEXIST);
}
if (count) {
}
if (status != NT_STATUS_SHARING_VIOLATION)
break;
}
if (status != NT_STATUS_SHARING_VIOLATION)
0, UINT64_MAX, B_TRUE);
if (status != NT_STATUS_SUCCESS) {
return (EACCES);
}
}
if (rc == 0) {
/*
* Note that renames in the same directory are normally
* delivered in {old,new} pairs, and clients expect them
* in that order, if both events are delivered.
*/
} else {
}
}
}
return (rc);
}
/*
* smb_rename_check_stream
*
* For a stream rename the dst path must begin with ':', or "\\:".
* We don't yet support stream rename, Return EACCES.
*
* If not a stream rename, in accordance with the above rule,
* it is not valid for either the src or dst to be a stream.
* Return EINVAL.
*/
static int
{
/* We do not yet support named stream rename - ACCESS DENIED */
if ((dst_path[0] == ':') ||
return (EACCES);
}
/*
* If not stream rename (above) neither src or dst can be
* a named stream.
*/
if (smb_is_stream_name(dst_path))
return (EINVAL);
if (SMB_IS_STREAM(src_fnode))
return (EINVAL);
} else {
if (smb_is_stream_name(src_path))
return (EINVAL);
}
return (0);
}
/*
* smb_make_link
*
* Creating a hard link (adding an additional name) for a file.
*
* If the source and destination are identical, we go through all
* the checks but we don't create a link.
*
* If the file is a symlink we create the hardlink on the target
* of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src).
* If the target of the symlink does not exist we fail with ENOENT.
*
* Returns errno values.
*/
static int
{
char *path;
int rc;
/* Cannnot create link on named stream */
return (EINVAL);
}
/* lookup and validate src node */
if (rc != 0)
return (rc);
/* if src and dest paths match we're done */
return (0);
}
/* find the destination dnode and last_comp */
if (rc != 0) {
return (rc);
}
/* If name match in same directory, we're done */
dst_fqi->fq_last_comp, 0) == 0)) {
return (0);
}
return (EILSEQ); /* NT_STATUS_INVALID_OBJECT_NAME */
}
/* Lookup the destination node. It MUST NOT exist. */
if (rc == 0) {
}
return (rc);
}
if (rc == 0) {
}
return (rc);
}
/*
* smb_rename_lookup_src
*
* Lookup the src node, checking for sharing violations and
* breaking any existing BATCH oplock.
* Populate sr->arg.dirop.fqi
*
* Upon success, the dnode and fnode will have holds and the
* fnode will be in a critical section. These should be
* released using smb_rename_release_src().
*
* Returns errno values.
*/
static int
{
int rc;
int count;
char *path;
return (EINVAL);
/* Lookup the source node */
if (rc != 0)
return (rc);
if (rc != 0) {
return (rc);
}
/* Not valid to create hardlink for directory */
return (EISDIR);
}
if (rc != 0) {
return (rc);
}
/*
* Break BATCH oplock before access checks. If a client
* has a file open, this will force a flush or close,
* which may affect the outcome of any share checking.
*/
if (count) {
}
if (status != NT_STATUS_SHARING_VIOLATION)
break;
}
if (status == NT_STATUS_SHARING_VIOLATION) {
return (EPIPE); /* = ERRbadshare */
}
if (status != NT_STATUS_SUCCESS) {
return (EACCES);
}
return (0);
}
/*
* smb_rename_release_src
*/
static void
{
}
static int
{
return (EIO);
!(SMB_SEARCH_HIDDEN(sattr)))
return (ESRCH);
!(SMB_SEARCH_SYSTEM(sattr)))
return (ESRCH);
return (0);
}
/*
* The following values are based on observed WFWG, Windows 9x, Windows NT
* and Windows 2000 behaviour.
*
* ERROR_FILE_EXISTS doesn't work for Windows 98 clients.
*
* Windows 95 clients don't see the problem because the target is deleted
* before the rename request.
*/
static void
{
static struct {
int errnum;
} rc_map[] = {
};
int i;
if (errnum == 0)
return;
return;
}
}
}