mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +03:00
r3717: - expanded the RAW-RENAME test a little
- added support for wildcard rename in pvfs
- made more consistent use of pvfs_map_errno()
(This used to be commit e255d1c3a8
)
This commit is contained in:
parent
1158268287
commit
1c59d825af
@ -937,7 +937,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
|
||||
mode_t mode = pvfs_fileperms(pvfs, attrib);
|
||||
if (fchmod(fd, mode) == -1) {
|
||||
talloc_free(lck);
|
||||
return map_nt_error_from_unix(errno);
|
||||
return pvfs_map_errno(pvfs, errno);
|
||||
}
|
||||
name->dos.attrib = attrib;
|
||||
status = pvfs_dosattrib_save(pvfs, name, fd);
|
||||
|
@ -23,6 +23,223 @@
|
||||
#include "includes.h"
|
||||
#include "vfs_posix.h"
|
||||
|
||||
|
||||
/*
|
||||
resolve a wildcard rename pattern. This works on one component of the name
|
||||
*/
|
||||
static const char *pvfs_resolve_wildcard_component(TALLOC_CTX *mem_ctx,
|
||||
const char *fname,
|
||||
const char *pattern)
|
||||
{
|
||||
const char *p1, *p2;
|
||||
char *dest, *d;
|
||||
|
||||
/* the length is bounded by the length of the two strings combined */
|
||||
dest = talloc(mem_ctx, strlen(fname) + strlen(pattern) + 1);
|
||||
if (dest == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p1 = fname;
|
||||
p2 = pattern;
|
||||
d = dest;
|
||||
|
||||
while (*p2) {
|
||||
codepoint_t c1, c2;
|
||||
size_t c_size1, c_size2;
|
||||
c1 = next_codepoint(p1, &c_size1);
|
||||
c2 = next_codepoint(p2, &c_size2);
|
||||
if (c2 == '?') {
|
||||
d += push_codepoint(d, c1);
|
||||
} else if (c2 == '*') {
|
||||
memcpy(d, p1, strlen(p1));
|
||||
d += strlen(p1);
|
||||
break;
|
||||
} else {
|
||||
d += push_codepoint(d, c2);
|
||||
}
|
||||
|
||||
p1 += c_size1;
|
||||
p2 += c_size2;
|
||||
}
|
||||
|
||||
*d = 0;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/*
|
||||
resolve a wildcard rename pattern.
|
||||
*/
|
||||
static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx,
|
||||
const char *fname,
|
||||
const char *pattern)
|
||||
{
|
||||
const char *base1, *base2;
|
||||
const char *ext1, *ext2;
|
||||
char *p;
|
||||
|
||||
/* break into base part plus extension */
|
||||
p = strrchr_m(fname, '.');
|
||||
if (p == NULL) {
|
||||
ext1 = "";
|
||||
base1 = fname;
|
||||
} else {
|
||||
ext1 = talloc_strdup(mem_ctx, p+1);
|
||||
base1 = talloc_strndup(mem_ctx, fname, p-fname);
|
||||
}
|
||||
if (ext1 == NULL || base1 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = strrchr_m(pattern, '.');
|
||||
if (p == NULL) {
|
||||
ext2 = "";
|
||||
base2 = fname;
|
||||
} else {
|
||||
ext2 = talloc_strdup(mem_ctx, p+1);
|
||||
base2 = talloc_strndup(mem_ctx, pattern, p-pattern);
|
||||
}
|
||||
if (ext2 == NULL || base2 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
base1 = pvfs_resolve_wildcard_component(mem_ctx, base1, base2);
|
||||
ext1 = pvfs_resolve_wildcard_component(mem_ctx, ext1, ext2);
|
||||
if (base1 == NULL || ext1 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*ext1 == 0) {
|
||||
return base1;
|
||||
}
|
||||
|
||||
return talloc_asprintf(mem_ctx, "%s.%s", base1, ext1);
|
||||
}
|
||||
|
||||
/*
|
||||
rename one file from a wildcard set
|
||||
*/
|
||||
static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
|
||||
struct smbsrv_request *req,
|
||||
const char *dir_path,
|
||||
const char *fname1,
|
||||
const char *fname2,
|
||||
uint16_t attrib)
|
||||
{
|
||||
struct pvfs_filename *name1, *name2;
|
||||
TALLOC_CTX *mem_ctx = talloc(req, 0);
|
||||
NTSTATUS status;
|
||||
|
||||
/* resolve the wildcard pattern for this name */
|
||||
fname2 = pvfs_resolve_wildcard(mem_ctx, fname1, fname2);
|
||||
if (fname2 == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* get a pvfs_filename source object */
|
||||
status = pvfs_resolve_partial(pvfs, mem_ctx,
|
||||
dir_path, fname1, &name1);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(mem_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* make sure its matches the given attributes */
|
||||
status = pvfs_match_attrib(pvfs, name1, attrib, 0);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(mem_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = pvfs_can_rename(pvfs, name1);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(mem_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* get a pvfs_filename dest object */
|
||||
status = pvfs_resolve_partial(pvfs, mem_ctx,
|
||||
dir_path, fname2, &name2);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
status = pvfs_can_delete(pvfs, name2);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(mem_ctx);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
fname2 = talloc_asprintf(mem_ctx, "%s/%s", dir_path, fname2);
|
||||
if (fname2 == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* finally try the actual rename */
|
||||
if (rename(name1->full_name, fname2) == -1) {
|
||||
talloc_free(mem_ctx);
|
||||
return pvfs_map_errno(pvfs, errno);
|
||||
}
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
rename a set of files with wildcards
|
||||
*/
|
||||
static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs,
|
||||
struct smbsrv_request *req,
|
||||
union smb_rename *ren,
|
||||
struct pvfs_filename *name1,
|
||||
struct pvfs_filename *name2)
|
||||
{
|
||||
struct pvfs_dir *dir;
|
||||
NTSTATUS status;
|
||||
uint_t ofs = 0;
|
||||
const char *fname, *fname2, *dir_path;
|
||||
uint16_t attrib = ren->rename.in.attrib;
|
||||
int total_renamed = 0;
|
||||
|
||||
/* get list of matching files */
|
||||
status = pvfs_list_start(pvfs, name1, req, &dir);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = NT_STATUS_NO_SUCH_FILE;
|
||||
|
||||
dir_path = pvfs_list_unix_path(dir);
|
||||
|
||||
/* only allow wildcard renames within a directory */
|
||||
if (strncmp(dir_path, name2->full_name, strlen(dir_path)) != 0 ||
|
||||
name2->full_name[strlen(dir_path)] != '/' ||
|
||||
strchr(name2->full_name + strlen(dir_path) + 1, '/')) {
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
fname2 = talloc_strdup(name2, name2->full_name + strlen(dir_path) + 1);
|
||||
if (fname2 == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
while ((fname = pvfs_list_next(dir, &ofs))) {
|
||||
status = pvfs_rename_one(pvfs, req,
|
||||
dir_path,
|
||||
fname, fname2, attrib);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
total_renamed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (total_renamed == 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
rename a set of files
|
||||
*/
|
||||
@ -49,15 +266,17 @@ NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
|
||||
}
|
||||
|
||||
if (name1->has_wildcard || name2->has_wildcard) {
|
||||
DEBUG(3,("Rejecting wildcard rename '%s' -> '%s'\n",
|
||||
ren->rename.in.pattern1, ren->rename.in.pattern2));
|
||||
return NT_STATUS_NOT_SUPPORTED;
|
||||
return pvfs_rename_wildcard(pvfs, req, ren, name1, name2);
|
||||
}
|
||||
|
||||
if (!name1->exists) {
|
||||
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (strcmp(name1->full_name, name2->full_name) == 0) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
if (name2->exists) {
|
||||
return NT_STATUS_OBJECT_NAME_COLLISION;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
|
||||
}
|
||||
|
||||
if (rename(name->full_name, name2->full_name) == -1) {
|
||||
return map_nt_error_from_unix(errno);
|
||||
return pvfs_map_errno(pvfs, errno);
|
||||
}
|
||||
|
||||
name->full_name = talloc_steal(name, name2->full_name);
|
||||
|
@ -68,7 +68,7 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
|
||||
if (errno == EFBIG) {
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
return map_nt_error_from_unix(errno);
|
||||
return pvfs_map_errno(pvfs, errno);
|
||||
}
|
||||
|
||||
f->handle->seek_offset = wr->writex.in.offset + ret;
|
||||
|
@ -28,7 +28,8 @@
|
||||
/*
|
||||
pull a xattr as a blob, from either a file or a file descriptor
|
||||
*/
|
||||
static NTSTATUS pull_xattr_blob(TALLOC_CTX *mem_ctx,
|
||||
static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const char *attr_name,
|
||||
const char *fname,
|
||||
int fd,
|
||||
@ -61,7 +62,7 @@ again:
|
||||
|
||||
if (ret == -1) {
|
||||
data_blob_free(blob);
|
||||
return map_nt_error_from_unix(errno);
|
||||
return pvfs_map_errno(pvfs, errno);
|
||||
}
|
||||
|
||||
blob->length = ret;
|
||||
@ -75,7 +76,8 @@ again:
|
||||
/*
|
||||
push a xattr as a blob, from either a file or a file descriptor
|
||||
*/
|
||||
static NTSTATUS push_xattr_blob(const char *attr_name,
|
||||
static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
|
||||
const char *attr_name,
|
||||
const char *fname,
|
||||
int fd,
|
||||
const DATA_BLOB *blob)
|
||||
@ -89,7 +91,7 @@ static NTSTATUS push_xattr_blob(const char *attr_name,
|
||||
ret = setxattr(fname, attr_name, blob->data, blob->length, 0);
|
||||
}
|
||||
if (ret == -1) {
|
||||
return map_nt_error_from_unix(errno);
|
||||
return pvfs_map_errno(pvfs, errno);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
@ -101,14 +103,15 @@ static NTSTATUS push_xattr_blob(const char *attr_name,
|
||||
/*
|
||||
load a NDR structure from a xattr
|
||||
*/
|
||||
static NTSTATUS pvfs_xattr_ndr_load(TALLOC_CTX *mem_ctx,
|
||||
static NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const char *fname, int fd, const char *attr_name,
|
||||
void *p, ndr_pull_flags_fn_t pull_fn)
|
||||
{
|
||||
NTSTATUS status;
|
||||
DATA_BLOB blob;
|
||||
|
||||
status = pull_xattr_blob(mem_ctx, attr_name, fname,
|
||||
status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
|
||||
fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
@ -125,7 +128,8 @@ static NTSTATUS pvfs_xattr_ndr_load(TALLOC_CTX *mem_ctx,
|
||||
/*
|
||||
save a NDR structure into a xattr
|
||||
*/
|
||||
static NTSTATUS pvfs_xattr_ndr_save(const char *fname, int fd, const char *attr_name,
|
||||
static NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
|
||||
const char *fname, int fd, const char *attr_name,
|
||||
void *p, ndr_push_flags_fn_t push_fn)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx = talloc(NULL, 0);
|
||||
@ -138,7 +142,7 @@ static NTSTATUS pvfs_xattr_ndr_save(const char *fname, int fd, const char *attr_
|
||||
return status;
|
||||
}
|
||||
|
||||
status = push_xattr_blob(attr_name, fname, fd, &blob);
|
||||
status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
return status;
|
||||
@ -159,8 +163,10 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
status = pvfs_xattr_ndr_load(mem_ctx, name->full_name, fd, XATTR_DOSATTRIB_NAME,
|
||||
&attrib, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
|
||||
status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
|
||||
fd, XATTR_DOSATTRIB_NAME,
|
||||
&attrib,
|
||||
(ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
|
||||
|
||||
/* if the filesystem doesn't support them, then tell pvfs not to try again */
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
|
||||
@ -233,7 +239,8 @@ NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name
|
||||
info1->create_time = name->dos.create_time;
|
||||
info1->change_time = name->dos.change_time;
|
||||
|
||||
return pvfs_xattr_ndr_save(name->full_name, fd, XATTR_DOSATTRIB_NAME, &attrib,
|
||||
return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
|
||||
XATTR_DOSATTRIB_NAME, &attrib,
|
||||
(ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
|
||||
}
|
||||
|
||||
@ -249,7 +256,7 @@ NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, i
|
||||
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
status = pvfs_xattr_ndr_load(eas, name->full_name, fd, XATTR_DOSEAS_NAME,
|
||||
status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
|
||||
eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
|
||||
return NT_STATUS_OK;
|
||||
@ -266,6 +273,6 @@ NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, i
|
||||
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
return pvfs_xattr_ndr_save(name->full_name, fd, XATTR_DOSEAS_NAME, eas,
|
||||
return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
|
||||
(ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
int fnum;
|
||||
const char *fname1 = BASEDIR "\\test1.txt";
|
||||
const char *fname2 = BASEDIR "\\test2.txt";
|
||||
union smb_open op;
|
||||
|
||||
printf("Testing SMBmv\n");
|
||||
|
||||
@ -57,16 +58,58 @@ static BOOL test_mv(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
|
||||
|
||||
printf("Trying simple rename\n");
|
||||
|
||||
fnum = create_complex_file(cli, mem_ctx, fname1);
|
||||
|
||||
op.generic.level = RAW_OPEN_NTCREATEX;
|
||||
op.ntcreatex.in.root_fid = 0;
|
||||
op.ntcreatex.in.flags = 0;
|
||||
op.ntcreatex.in.access_mask = SEC_RIGHT_MAXIMUM_ALLOWED;
|
||||
op.ntcreatex.in.create_options = 0;
|
||||
op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
|
||||
op.ntcreatex.in.share_access =
|
||||
NTCREATEX_SHARE_ACCESS_READ |
|
||||
NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
op.ntcreatex.in.alloc_size = 0;
|
||||
op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
|
||||
op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
|
||||
op.ntcreatex.in.security_flags = 0;
|
||||
op.ntcreatex.in.fname = fname1;
|
||||
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = op.ntcreatex.out.fnum;
|
||||
|
||||
io.generic.level = RAW_RENAME_RENAME;
|
||||
io.rename.in.pattern1 = fname1;
|
||||
io.rename.in.pattern2 = fname2;
|
||||
io.rename.in.attrib = 0;
|
||||
|
||||
printf("trying rename while first file open\n");
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
|
||||
|
||||
|
||||
smbcli_close(cli->tree, fnum);
|
||||
|
||||
op.ntcreatex.in.access_mask = GENERIC_RIGHTS_FILE_READ;
|
||||
op.ntcreatex.in.share_access =
|
||||
NTCREATEX_SHARE_ACCESS_DELETE |
|
||||
NTCREATEX_SHARE_ACCESS_READ |
|
||||
NTCREATEX_SHARE_ACCESS_WRITE;
|
||||
status = smb_raw_open(cli->tree, mem_ctx, &op);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
fnum = op.ntcreatex.out.fnum;
|
||||
|
||||
printf("trying rename while first file open with SHARE_ACCESS_DELETE\n");
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
io.rename.in.pattern1 = fname2;
|
||||
io.rename.in.pattern2 = fname1;
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
||||
io.rename.in.pattern1 = fname1;
|
||||
io.rename.in.pattern2 = fname2;
|
||||
|
||||
printf("trying rename while not open\n");
|
||||
smb_raw_exit(cli->session);
|
||||
status = smb_raw_rename(cli->tree, &io);
|
||||
CHECK_STATUS(status, NT_STATUS_OK);
|
||||
|
Loading…
Reference in New Issue
Block a user