1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-10 04:23:50 +03:00

r21710: Add client support for the UNIX_INFO2 info level in the QueryFile,

QueryPath and FindFirst calls. Add a new torture test to verify the
server side.
This commit is contained in:
James Peach
2007-03-05 22:26:38 +00:00
committed by Gerald (Jerry) Carter
parent 01befd5211
commit 7f56da2d1f
11 changed files with 688 additions and 29 deletions

View File

@@ -3,6 +3,7 @@
SMB request interface structures SMB request interface structures
Copyright (C) Andrew Tridgell 2003 Copyright (C) Andrew Tridgell 2003
Copyright (C) James J Myers 2003 <myersjj@samba.org> Copyright (C) James J Myers 2003 <myersjj@samba.org>
Copyright (C) James Peach 2007
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -426,6 +427,7 @@ enum smb_fileinfo_level {
RAW_FILEINFO_STREAM_INFO = SMB_QFILEINFO_STREAM_INFO, RAW_FILEINFO_STREAM_INFO = SMB_QFILEINFO_STREAM_INFO,
RAW_FILEINFO_COMPRESSION_INFO = SMB_QFILEINFO_COMPRESSION_INFO, RAW_FILEINFO_COMPRESSION_INFO = SMB_QFILEINFO_COMPRESSION_INFO,
RAW_FILEINFO_UNIX_BASIC = SMB_QFILEINFO_UNIX_BASIC, RAW_FILEINFO_UNIX_BASIC = SMB_QFILEINFO_UNIX_BASIC,
RAW_FILEINFO_UNIX_INFO2 = SMB_QFILEINFO_UNIX_INFO2,
RAW_FILEINFO_UNIX_LINK = SMB_QFILEINFO_UNIX_LINK, RAW_FILEINFO_UNIX_LINK = SMB_QFILEINFO_UNIX_LINK,
RAW_FILEINFO_BASIC_INFORMATION = SMB_QFILEINFO_BASIC_INFORMATION, RAW_FILEINFO_BASIC_INFORMATION = SMB_QFILEINFO_BASIC_INFORMATION,
RAW_FILEINFO_STANDARD_INFORMATION = SMB_QFILEINFO_STANDARD_INFORMATION, RAW_FILEINFO_STANDARD_INFORMATION = SMB_QFILEINFO_STANDARD_INFORMATION,
@@ -745,6 +747,32 @@ union smb_fileinfo {
} out; } out;
} unix_basic_info; } unix_basic_info;
/* RAW_FILEINFO_UNIX_INFO2 interface */
struct {
enum smb_fileinfo_level level;
struct {
union smb_handle_or_path file;
} in;
struct {
uint64_t end_of_file;
uint64_t num_bytes;
NTTIME status_change_time;
NTTIME access_time;
NTTIME change_time;
uint64_t uid;
uint64_t gid;
uint32_t file_type;
uint64_t dev_major;
uint64_t dev_minor;
uint64_t unique_id;
uint64_t permissions;
uint64_t nlink;
NTTIME create_time;
uint32_t file_flags;
uint32_t flags_mask;
} out;
} unix_info2;
/* RAW_FILEINFO_UNIX_LINK interface */ /* RAW_FILEINFO_UNIX_LINK interface */
struct { struct {
enum smb_fileinfo_level level; enum smb_fileinfo_level level;
@@ -867,6 +895,7 @@ enum smb_setfileinfo_level {
RAW_SFILEINFO_ALLOCATION_INFO = SMB_SFILEINFO_ALLOCATION_INFO, RAW_SFILEINFO_ALLOCATION_INFO = SMB_SFILEINFO_ALLOCATION_INFO,
RAW_SFILEINFO_END_OF_FILE_INFO = SMB_SFILEINFO_END_OF_FILE_INFO, RAW_SFILEINFO_END_OF_FILE_INFO = SMB_SFILEINFO_END_OF_FILE_INFO,
RAW_SFILEINFO_UNIX_BASIC = SMB_SFILEINFO_UNIX_BASIC, RAW_SFILEINFO_UNIX_BASIC = SMB_SFILEINFO_UNIX_BASIC,
RAW_SFILEINFO_UNIX_INFO2 = SMB_SFILEINFO_UNIX_INFO2,
RAW_SFILEINFO_UNIX_LINK = SMB_SFILEINFO_UNIX_LINK, RAW_SFILEINFO_UNIX_LINK = SMB_SFILEINFO_UNIX_LINK,
RAW_SFILEINFO_UNIX_HLINK = SMB_SFILEINFO_UNIX_HLINK, RAW_SFILEINFO_UNIX_HLINK = SMB_SFILEINFO_UNIX_HLINK,
RAW_SFILEINFO_BASIC_INFORMATION = SMB_SFILEINFO_BASIC_INFORMATION, RAW_SFILEINFO_BASIC_INFORMATION = SMB_SFILEINFO_BASIC_INFORMATION,
@@ -1003,8 +1032,6 @@ union smb_setfileinfo {
} in; } in;
} mode_information; } mode_information;
/* RAW_SFILEINFO_UNIX_BASIC interface */ /* RAW_SFILEINFO_UNIX_BASIC interface */
struct { struct {
enum smb_setfileinfo_level level; enum smb_setfileinfo_level level;
@@ -1027,6 +1054,30 @@ union smb_setfileinfo {
} in; } in;
} unix_basic; } unix_basic;
/* RAW_SFILEINFO_UNIX_INFO2 interface */
struct {
enum smb_setfileinfo_level level;
struct {
union smb_handle_or_path file;
uint64_t end_of_file;
uint64_t num_bytes;
NTTIME status_change_time;
NTTIME access_time;
NTTIME change_time;
uint64_t uid;
uint64_t gid;
uint32_t file_type;
uint64_t dev_major;
uint64_t dev_minor;
uint64_t unique_id;
uint64_t permissions;
uint64_t nlink;
NTTIME create_time;
uint32_t file_flags;
uint32_t flags_mask;
} in;
} unix_info2;
/* RAW_SFILEINFO_UNIX_LINK, RAW_SFILEINFO_UNIX_HLINK interface */ /* RAW_SFILEINFO_UNIX_LINK, RAW_SFILEINFO_UNIX_HLINK interface */
struct { struct {
enum smb_setfileinfo_level level; enum smb_setfileinfo_level level;
@@ -2204,7 +2255,8 @@ enum smb_search_data_level {
RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO = SMB_FIND_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO = SMB_FIND_BOTH_DIRECTORY_INFO,
RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO = SMB_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO = SMB_FIND_ID_FULL_DIRECTORY_INFO,
RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO = SMB_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO = SMB_FIND_ID_BOTH_DIRECTORY_INFO,
RAW_SEARCH_DATA_UNIX_INFO = SMB_FIND_UNIX_INFO RAW_SEARCH_DATA_UNIX_INFO = SMB_FIND_UNIX_INFO,
RAW_SEARCH_DATA_UNIX_INFO2 = SMB_FIND_UNIX_INFO2
}; };
/* union for file search */ /* union for file search */
@@ -2504,8 +2556,32 @@ union smb_search_data {
uint64_t nlink; uint64_t nlink;
const char *name; const char *name;
} unix_info; } unix_info;
/* RAW_SEARCH_DATA_UNIX_INFO2 interface */
struct {
uint32_t file_index;
uint64_t end_of_file;
uint64_t num_bytes;
NTTIME status_change_time;
NTTIME access_time;
NTTIME change_time;
uint64_t uid;
uint64_t gid;
uint32_t file_type;
uint64_t dev_major;
uint64_t dev_minor;
uint64_t unique_id;
uint64_t permissions;
uint64_t nlink;
NTTIME create_time;
uint32_t file_flags;
uint32_t flags_mask;
const char *name;
} unix_info2;
}; };
/* Callback function passed to the raw search interface. */
typedef BOOL (*smbcli_search_callback)(void *private, const union smb_search_data *file);
enum smb_search_close_level {RAW_FINDCLOSE_GENERIC, RAW_FINDCLOSE_FCLOSE, RAW_FINDCLOSE_FINDCLOSE}; enum smb_search_close_level {RAW_FINDCLOSE_GENERIC, RAW_FINDCLOSE_FCLOSE, RAW_FINDCLOSE_FINDCLOSE};

View File

@@ -3,6 +3,7 @@
client trans2 operations client trans2 operations
Copyright (C) James Myers 2003 Copyright (C) James Myers 2003
Copyright (C) Andrew Tridgell 2003 Copyright (C) Andrew Tridgell 2003
Copyright (C) James Peach 2007
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -403,6 +404,26 @@ static NTSTATUS smb_raw_info_backend(struct smbcli_session *session,
parms->unix_basic_info.out.nlink = BVAL(blob->data, 92); parms->unix_basic_info.out.nlink = BVAL(blob->data, 92);
return NT_STATUS_OK; return NT_STATUS_OK;
case RAW_FILEINFO_UNIX_INFO2:
FINFO_CHECK_SIZE(116);
parms->unix_info2.out.end_of_file = BVAL(blob->data, 0);
parms->unix_info2.out.num_bytes = BVAL(blob->data, 8);
parms->unix_info2.out.status_change_time = smbcli_pull_nttime(blob->data, 16);
parms->unix_info2.out.access_time = smbcli_pull_nttime(blob->data, 24);
parms->unix_info2.out.change_time = smbcli_pull_nttime(blob->data, 32);
parms->unix_info2.out.uid = BVAL(blob->data, 40);
parms->unix_info2.out.gid = BVAL(blob->data, 48);
parms->unix_info2.out.file_type = IVAL(blob->data, 52);
parms->unix_info2.out.dev_major = BVAL(blob->data, 60);
parms->unix_info2.out.dev_minor = BVAL(blob->data, 68);
parms->unix_info2.out.unique_id = BVAL(blob->data, 76);
parms->unix_info2.out.permissions = BVAL(blob->data, 84);
parms->unix_info2.out.nlink = BVAL(blob->data, 92);
parms->unix_info2.out.create_time = smbcli_pull_nttime(blob->data, 100);
parms->unix_info2.out.file_flags = IVAL(blob->data, 108);
parms->unix_info2.out.flags_mask = IVAL(blob->data, 112);
return NT_STATUS_OK;
case RAW_FILEINFO_UNIX_LINK: case RAW_FILEINFO_UNIX_LINK:
smbcli_blob_pull_string(session, mem_ctx, blob, smbcli_blob_pull_string(session, mem_ctx, blob,
&parms->unix_link_info.out.link_dest, 0, 4, STR_UNICODE); &parms->unix_link_info.out.link_dest, 0, 4, STR_UNICODE);

View File

@@ -2,6 +2,7 @@
Unix SMB/CIFS implementation. Unix SMB/CIFS implementation.
client directory search routines client directory search routines
Copyright (C) James Myers 2003 <myersjj@samba.org> Copyright (C) James Myers 2003 <myersjj@samba.org>
Copyright (C) James Peach 2007
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -28,7 +29,7 @@ static void smb_raw_search_backend(struct smbcli_request *req,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
uint16_t count, uint16_t count,
void *private, void *private,
BOOL (*callback)(void *private, union smb_search_data *file)) smbcli_search_callback callback)
{ {
union smb_search_data search_data; union smb_search_data search_data;
@@ -69,7 +70,7 @@ static void smb_raw_search_backend(struct smbcli_request *req,
static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree, static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
union smb_search_first *io, void *private, union smb_search_first *io, void *private,
BOOL (*callback)(void *private, union smb_search_data *file)) smbcli_search_callback callback)
{ {
struct smbcli_request *req; struct smbcli_request *req;
@@ -110,7 +111,7 @@ static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree,
static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree, static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
union smb_search_next *io, void *private, union smb_search_next *io, void *private,
BOOL (*callback)(void *private, union smb_search_data *file)) smbcli_search_callback callback)
{ {
struct smbcli_request *req; struct smbcli_request *req;
@@ -605,6 +606,40 @@ static int parse_trans2_search(struct smbcli_tree *tree,
} }
return ofs; return ofs;
case RAW_SEARCH_DATA_UNIX_INFO2:
if (blob->length < (116 + 8 + 1)) {
return -1;
}
ofs = IVAL(blob->data, 0);
data->unix_info2.file_index = IVAL(blob->data, 4);
data->unix_info2.end_of_file = BVAL(blob->data, 8);
data->unix_info2.num_bytes = BVAL(blob->data, 16);
data->unix_info2.status_change_time = smbcli_pull_nttime(blob->data, 24);
data->unix_info2.access_time = smbcli_pull_nttime(blob->data, 32);
data->unix_info2.change_time = smbcli_pull_nttime(blob->data, 40);
data->unix_info2.uid = IVAL(blob->data, 48);
data->unix_info2.gid = IVAL(blob->data, 56);
data->unix_info2.file_type = IVAL(blob->data, 64);
data->unix_info2.dev_major = BVAL(blob->data, 68);
data->unix_info2.dev_minor = BVAL(blob->data, 76);
data->unix_info2.unique_id = BVAL(blob->data, 84);
data->unix_info2.permissions = IVAL(blob->data, 92);
data->unix_info2.nlink = IVAL(blob->data, 100);
data->unix_info2.create_time = smbcli_pull_nttime(blob->data, 108);
data->unix_info2.file_flags = IVAL(blob->data, 116);
data->unix_info2.flags_mask = IVAL(blob->data, 120);
/* There is no length field for this name but we know it's null terminated. */
len = smbcli_blob_pull_unix_string(tree->session, mem_ctx, blob,
&data->unix_info2.name, 116 + 8, 0);
if (ofs != 0 && ofs < (116 + 8 + len)) {
return -1;
}
return ofs;
case RAW_SEARCH_DATA_DIRECTORY_INFO: case RAW_SEARCH_DATA_DIRECTORY_INFO:
case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO: case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
case RAW_SEARCH_DATA_NAME_INFO: case RAW_SEARCH_DATA_NAME_INFO:
@@ -638,7 +673,7 @@ static NTSTATUS smb_raw_t2search_backend(struct smbcli_tree *tree,
int16_t count, int16_t count,
DATA_BLOB *blob, DATA_BLOB *blob,
void *private, void *private,
BOOL (*callback)(void *private, union smb_search_data *file)) smbcli_search_callback callback)
{ {
int i; int i;
@@ -677,7 +712,7 @@ static NTSTATUS smb_raw_t2search_backend(struct smbcli_tree *tree,
NTSTATUS smb_raw_search_first(struct smbcli_tree *tree, NTSTATUS smb_raw_search_first(struct smbcli_tree *tree,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
union smb_search_first *io, void *private, union smb_search_first *io, void *private,
BOOL (*callback)(void *private, union smb_search_data *file)) smbcli_search_callback callback)
{ {
DATA_BLOB p_blob, d_blob; DATA_BLOB p_blob, d_blob;
NTSTATUS status; NTSTATUS status;
@@ -725,7 +760,7 @@ NTSTATUS smb_raw_search_first(struct smbcli_tree *tree,
NTSTATUS smb_raw_search_next(struct smbcli_tree *tree, NTSTATUS smb_raw_search_next(struct smbcli_tree *tree,
TALLOC_CTX *mem_ctx, TALLOC_CTX *mem_ctx,
union smb_search_next *io, void *private, union smb_search_next *io, void *private,
BOOL (*callback)(void *private, union smb_search_data *file)) smbcli_search_callback callback)
{ {
DATA_BLOB p_blob, d_blob; DATA_BLOB p_blob, d_blob;
NTSTATUS status; NTSTATUS status;

View File

@@ -3,6 +3,7 @@
RAW_SFILEINFO_* calls RAW_SFILEINFO_* calls
Copyright (C) James Myers 2003 Copyright (C) James Myers 2003
Copyright (C) Andrew Tridgell 2003 Copyright (C) Andrew Tridgell 2003
Copyright (C) James Peach 2007
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -166,6 +167,26 @@ static BOOL smb_raw_setinfo_backend(struct smbcli_tree *tree,
SBVAL(blob->data, 92, parms->unix_basic.in.nlink); SBVAL(blob->data, 92, parms->unix_basic.in.nlink);
return True; return True;
case RAW_SFILEINFO_UNIX_INFO2:
NEED_BLOB(116);
SBVAL(blob->data, 0, parms->unix_info2.in.end_of_file);
SBVAL(blob->data, 8, parms->unix_info2.in.num_bytes);
smbcli_push_nttime(blob->data, 16, parms->unix_info2.in.status_change_time);
smbcli_push_nttime(blob->data, 24, parms->unix_info2.in.access_time);
smbcli_push_nttime(blob->data, 32, parms->unix_info2.in.change_time);
SBVAL(blob->data, 40,parms->unix_info2.in.uid);
SBVAL(blob->data, 48,parms->unix_info2.in.gid);
SIVAL(blob->data, 52,parms->unix_info2.in.file_type);
SBVAL(blob->data, 60,parms->unix_info2.in.dev_major);
SBVAL(blob->data, 68,parms->unix_info2.in.dev_minor);
SBVAL(blob->data, 76,parms->unix_info2.in.unique_id);
SBVAL(blob->data, 84,parms->unix_info2.in.permissions);
SBVAL(blob->data, 92,parms->unix_info2.in.nlink);
smbcli_push_nttime(blob->data, 100, parms->unix_info2.in.create_time);
SIVAL(blob->data, 108, parms->unix_info2.in.file_flags);
SIVAL(blob->data, 112, parms->unix_info2.in.flags_mask);
return True;
case RAW_SFILEINFO_DISPOSITION_INFO: case RAW_SFILEINFO_DISPOSITION_INFO:
case RAW_SFILEINFO_DISPOSITION_INFORMATION: case RAW_SFILEINFO_DISPOSITION_INFORMATION:
return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_DISPOSITION_INFORMATION, return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_DISPOSITION_INFORMATION,

View File

@@ -3,6 +3,7 @@
SMB transaction2 handling SMB transaction2 handling
Copyright (C) Jeremy Allison 1994-2002. Copyright (C) Jeremy Allison 1994-2002.
Copyright (C) Andrew Tridgell 1995-2003. Copyright (C) Andrew Tridgell 1995-2003.
Copyright (C) James Peach 2007
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -141,6 +142,7 @@ Found 8 aliased levels
#define SMB_QFILEINFO_COMPRESSION_INFO 0x10b #define SMB_QFILEINFO_COMPRESSION_INFO 0x10b
#define SMB_QFILEINFO_UNIX_BASIC 0x200 #define SMB_QFILEINFO_UNIX_BASIC 0x200
#define SMB_QFILEINFO_UNIX_LINK 0x201 #define SMB_QFILEINFO_UNIX_LINK 0x201
#define SMB_QFILEINFO_UNIX_INFO2 0x20b
#define SMB_QFILEINFO_BASIC_INFORMATION 1004 #define SMB_QFILEINFO_BASIC_INFORMATION 1004
#define SMB_QFILEINFO_STANDARD_INFORMATION 1005 #define SMB_QFILEINFO_STANDARD_INFORMATION 1005
#define SMB_QFILEINFO_INTERNAL_INFORMATION 1006 #define SMB_QFILEINFO_INTERNAL_INFORMATION 1006
@@ -213,6 +215,7 @@ Found 13 valid levels
#define SMB_SPATHINFO_POSIX_ACL 0x204 #define SMB_SPATHINFO_POSIX_ACL 0x204
#define SMB_SPATHINFO_XATTR 0x205 #define SMB_SPATHINFO_XATTR 0x205
#define SMB_SFILEINFO_ATTR_FLAGS 0x206 #define SMB_SFILEINFO_ATTR_FLAGS 0x206
#define SMB_SFILEINFO_UNIX_INFO2 0x20b
#define SMB_SFILEINFO_BASIC_INFORMATION 1004 #define SMB_SFILEINFO_BASIC_INFORMATION 1004
#define SMB_SFILEINFO_RENAME_INFORMATION 1010 #define SMB_SFILEINFO_RENAME_INFORMATION 1010
#define SMB_SFILEINFO_DISPOSITION_INFORMATION 1013 #define SMB_SFILEINFO_DISPOSITION_INFORMATION 1013
@@ -267,6 +270,7 @@ Found 0 aliased levels
#define SMB_FIND_ID_FULL_DIRECTORY_INFO 0x105 #define SMB_FIND_ID_FULL_DIRECTORY_INFO 0x105
#define SMB_FIND_ID_BOTH_DIRECTORY_INFO 0x106 #define SMB_FIND_ID_BOTH_DIRECTORY_INFO 0x106
#define SMB_FIND_UNIX_INFO 0x202 #define SMB_FIND_UNIX_INFO 0x202
#define SMB_FIND_UNIX_INFO2 0x20b
/* flags on trans2 findfirst/findnext that control search */ /* flags on trans2 findfirst/findnext that control search */
#define FLAG_TRANS2_FIND_CLOSE 0x1 #define FLAG_TRANS2_FIND_CLOSE 0x1
@@ -321,9 +325,6 @@ Found 0 aliased levels
#define INFO_LEVEL_IS_UNIX(level) (((level) >= MIN_UNIX_INFO_LEVEL) && ((level) <= MAX_UNIX_INFO_LEVEL)) #define INFO_LEVEL_IS_UNIX(level) (((level) >= MIN_UNIX_INFO_LEVEL) && ((level) <= MAX_UNIX_INFO_LEVEL))
#define SMB_QFILEINFO_UNIX_BASIC 0x200 /* UNIX File Info*/
#define SMB_SFILEINFO_UNIX_BASIC 0x200
#define SMB_MODE_NO_CHANGE 0xFFFFFFFF /* file mode value which */ #define SMB_MODE_NO_CHANGE 0xFFFFFFFF /* file mode value which */
/* means "don't change it" */ /* means "don't change it" */
#define SMB_UID_NO_CHANGE 0xFFFFFFFF #define SMB_UID_NO_CHANGE 0xFFFFFFFF
@@ -336,6 +337,8 @@ Found 0 aliased levels
#define SMB_TIME_NO_CHANGE_HI 0xFFFFFFFF #define SMB_TIME_NO_CHANGE_HI 0xFFFFFFFF
/* /*
UNIX_BASIC info level:
Offset Size Name Offset Size Name
0 LARGE_INTEGER EndOfFile File size 0 LARGE_INTEGER EndOfFile File size
8 LARGE_INTEGER Blocks Number of bytes used on disk (st_blocks). 8 LARGE_INTEGER Blocks Number of bytes used on disk (st_blocks).
@@ -365,6 +368,31 @@ Offset Size Name
100 - end. 100 - end.
*/ */
/*
SMB_QUERY_FILE_UNIX_INFO2 is SMB_QUERY_FILE_UNIX_BASIC with create
time and file flags appended. The corresponding info level for
findfirst/findnext is SMB_FIND_FILE_UNIX_UNIX2.
Size Offset Value
---------------------
0 LARGE_INTEGER EndOfFile File size
8 LARGE_INTEGER Blocks Number of blocks used on disk
16 LARGE_INTEGER ChangeTime Attribute change time
24 LARGE_INTEGER LastAccessTime Last access time
32 LARGE_INTEGER LastModificationTime Last modification time
40 LARGE_INTEGER Uid Numeric user id for the owner
48 LARGE_INTEGER Gid Numeric group id of owner
56 ULONG Type Enumeration specifying the file type
60 LARGE_INTEGER devmajor Major device number if type is device
68 LARGE_INTEGER devminor Minor device number if type is device
76 LARGE_INTEGER uniqueid This is a server-assigned unique id
84 LARGE_INTEGER permissions Standard UNIX permissions
92 LARGE_INTEGER nlinks Number of hard link)
100 LARGE_INTEGER CreationTime Create/birth time
108 ULONG FileFlags File flags enumeration
112 ULONG FileFlagsMask Mask of valid flags
*/
/* UNIX filetype mappings. */ /* UNIX filetype mappings. */
#define UNIX_TYPE_FILE 0 #define UNIX_TYPE_FILE 0
@@ -404,12 +432,20 @@ Offset Size Name
#define UNIX_EXTRA_MASK 0007000 #define UNIX_EXTRA_MASK 0007000
#define UNIX_ALL_MASK 0007777 #define UNIX_ALL_MASK 0007777
/* Flags for the file_flags field in UNIX_INFO2: */
#define EXT_SECURE_DELETE 0x00000001
#define EXT_ENABLE_UNDELETE 0x00000002
#define EXT_SYNCHRONOUS 0x00000004
#define EXT_IMMUTABLE 0x00000008
#define EXT_OPEN_APPEND_ONLY 0x00000010
#define EXT_DO_NOT_BACKUP 0x00000020
#define EXT_NO_UPDATE_ATIME 0x00000040
#define EXT_HIDDEN 0x00000080
#define SMB_QFILEINFO_UNIX_LINK 0x201 #define SMB_QFILEINFO_UNIX_LINK 0x201
#define SMB_SFILEINFO_UNIX_LINK 0x201 #define SMB_SFILEINFO_UNIX_LINK 0x201
#define SMB_SFILEINFO_UNIX_HLINK 0x203 #define SMB_SFILEINFO_UNIX_HLINK 0x203
#define SMB_FIND_FILE_UNIX 0x202
/* /*
Info level for QVOLINFO - returns version of CIFS UNIX extensions, plus Info level for QVOLINFO - returns version of CIFS UNIX extensions, plus
64-bits worth of capability fun :-). 64-bits worth of capability fun :-).

View File

@@ -224,7 +224,8 @@ PRIVATE_PROTO_HEADER = \
unix/proto.h unix/proto.h
OBJ_FILES = \ OBJ_FILES = \
unix/unix.o \ unix/unix.o \
unix/whoami.o unix/whoami.o \
unix/unix_info2.o
# End MODULE TORTURE_UNIX # End MODULE TORTURE_UNIX
################################# #################################

View File

@@ -607,7 +607,7 @@ void nb_qfsinfo(int level, NTSTATUS status)
} }
/* callback function used for trans2 search */ /* callback function used for trans2 search */
static BOOL findfirst_callback(void *private, union smb_search_data *file) static BOOL findfirst_callback(void *private, const union smb_search_data *file)
{ {
return True; return True;
} }

View File

@@ -31,7 +31,7 @@
/* /*
callback function for single_search callback function for single_search
*/ */
static BOOL single_search_callback(void *private, union smb_search_data *file) static BOOL single_search_callback(void *private, const union smb_search_data *file)
{ {
union smb_search_data *data = private; union smb_search_data *data = private;

View File

@@ -245,6 +245,16 @@ void torture_result(struct torture_context *test,
} \ } \
} while(0) } while(0)
#define torture_assert_u64_equal(torture_ctx,got,expected,cmt)\
do { uint64_t __got = (got), __expected = (expected); \
if (__got != __expected) { \
torture_result(torture_ctx, TORTURE_FAIL, \
__location__": "#got" was %llu, expected %llu: %s", \
(unsigned long long)__got, (unsigned long long)__expected, cmt); \
return false; \
} \
} while(0)
#define torture_assert_errno_equal(torture_ctx,expected,cmt)\ #define torture_assert_errno_equal(torture_ctx,expected,cmt)\
do { int __expected = (expected); \ do { int __expected = (expected); \
if (errno != __expected) { \ if (errno != __expected) { \

View File

@@ -1,7 +1,7 @@
/* /*
UNIX Extensions test registration. UNIX Extensions test registration.
Copyright (C) 2006 James Peach Copyright (C) 2007 James Peach
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -32,6 +32,8 @@ NTSTATUS torture_unix_init(void)
torture_suite_add_simple_test(suite, torture_suite_add_simple_test(suite,
"WHOAMI", torture_unix_whoami); "WHOAMI", torture_unix_whoami);
torture_suite_add_simple_test(suite,
"INFO2", unix_torture_unix_info2);
return (torture_register_suite(suite)) ? NT_STATUS_OK return (torture_register_suite(suite)) ? NT_STATUS_OK
: NT_STATUS_UNSUCCESSFUL; : NT_STATUS_UNSUCCESSFUL;

View File

@@ -0,0 +1,457 @@
/*
Test the SMB_QUERY_FILE_UNIX_INFO2 Unix extension.
Copyright (C) 2007 James Peach
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "libcli/libcli.h"
#include "libcli/raw/interfaces.h"
#include "libcli/raw/raw_proto.h"
#include "torture/torture.h"
#include "torture/util.h"
#include "torture/basic/proto.h"
#include "lib/cmdline/popt_common.h"
#include "auth/credentials/credentials.h"
struct unix_info2 {
uint64_t end_of_file;
uint64_t num_bytes;
NTTIME status_change_time;
NTTIME access_time;
NTTIME change_time;
uint64_t uid;
uint64_t gid;
uint32_t file_type;
uint64_t dev_major;
uint64_t dev_minor;
uint64_t unique_id;
uint64_t permissions;
uint64_t nlink;
NTTIME create_time;
uint32_t file_flags;
uint32_t flags_mask;
};
static struct smbcli_state *connect_to_server(void *mem_ctx)
{
NTSTATUS status;
struct smbcli_state *cli;
const char *host = lp_parm_string(-1, "torture", "host");
const char *share = lp_parm_string(-1, "torture", "share");
status = smbcli_full_connection(mem_ctx, &cli,
host, share, NULL,
cmdline_credentials, NULL);
if (!NT_STATUS_IS_OK(status)) {
printf("failed to connect to //%s/%s: %s\n",
host, share, nt_errstr(status));
return NULL;
}
return cli;
}
static BOOL check_unix_info2(struct torture_context *torture,
struct unix_info2 *info2)
{
printf("\tcreate_time=0x%016llu flags=0x%08x mask=0x%08x\n",
(unsigned long long)info2->create_time,
info2->file_flags, info2->flags_mask);
if (info2->file_flags == 0) {
return True;
}
/* If we have any file_flags set, they must be within the range
* defined by flags_mask.
*/
if ((info2->flags_mask & info2->file_flags) == 0) {
torture_result(torture, TORTURE_FAIL,
__location__"%s: UNIX_INFO2 flags field 0x%08x, "
"does not match mask 0x%08x\n",
info2->file_flags, info2->flags_mask);
}
return True;
}
static NTSTATUS set_path_info2(void *mem_ctx,
struct smbcli_state *cli,
const char *fname,
struct unix_info2 *info2)
{
union smb_setfileinfo sfinfo;
sfinfo.generic.level = RAW_SFILEINFO_UNIX_INFO2;
sfinfo.generic.in.file.path = fname;
sfinfo.unix_info2.in.end_of_file = info2->end_of_file;
sfinfo.unix_info2.in.num_bytes = info2->num_bytes;
sfinfo.unix_info2.in.status_change_time = info2->status_change_time;
sfinfo.unix_info2.in.access_time = info2->access_time;
sfinfo.unix_info2.in.change_time = info2->change_time;
sfinfo.unix_info2.in.uid = info2->uid;
sfinfo.unix_info2.in.gid = info2->gid;
sfinfo.unix_info2.in.file_type = info2->file_type;
sfinfo.unix_info2.in.dev_major = info2->dev_major;
sfinfo.unix_info2.in.dev_minor = info2->dev_minor;
sfinfo.unix_info2.in.unique_id = info2->unique_id;
sfinfo.unix_info2.in.permissions = info2->permissions;
sfinfo.unix_info2.in.nlink = info2->nlink;
sfinfo.unix_info2.in.create_time = info2->create_time;
sfinfo.unix_info2.in.file_flags = info2->file_flags;
sfinfo.unix_info2.in.flags_mask = info2->flags_mask;
return smb_raw_setpathinfo(cli->tree, &sfinfo);
}
static BOOL query_file_path_info2(void *mem_ctx,
struct torture_context *torture,
struct smbcli_state *cli,
int fnum,
const char *fname,
struct unix_info2 *info2)
{
NTSTATUS result;
union smb_fileinfo finfo;
finfo.generic.level = RAW_FILEINFO_UNIX_INFO2;
if (fname) {
finfo.generic.in.file.path = fname;
result = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
} else {
finfo.generic.in.file.fnum = fnum;
result = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
}
torture_assert_ntstatus_equal(torture, result, NT_STATUS_OK,
smbcli_errstr(cli->tree));
info2->end_of_file = finfo.unix_info2.out.end_of_file;
info2->num_bytes = finfo.unix_info2.out.num_bytes;
info2->status_change_time = finfo.unix_info2.out.status_change_time;
info2->access_time = finfo.unix_info2.out.access_time;
info2->change_time = finfo.unix_info2.out.change_time;
info2->uid = finfo.unix_info2.out.uid;
info2->gid = finfo.unix_info2.out.gid;
info2->file_type = finfo.unix_info2.out.file_type;
info2->dev_major = finfo.unix_info2.out.dev_major;
info2->dev_minor = finfo.unix_info2.out.dev_minor;
info2->unique_id = finfo.unix_info2.out.unique_id;
info2->permissions = finfo.unix_info2.out.permissions;
info2->nlink = finfo.unix_info2.out.nlink;
info2->create_time = finfo.unix_info2.out.create_time;
info2->file_flags = finfo.unix_info2.out.file_flags;
info2->flags_mask = finfo.unix_info2.out.flags_mask;
if (!check_unix_info2(torture, info2)) {
return False;
}
return True;
}
static BOOL query_file_info2(void *mem_ctx,
struct torture_context *torture,
struct smbcli_state *cli,
int fnum,
struct unix_info2 *info2)
{
return query_file_path_info2(mem_ctx, torture, cli,
fnum, NULL, info2);
}
static BOOL query_path_info2(void *mem_ctx,
struct torture_context *torture,
struct smbcli_state *cli,
const char *fname,
struct unix_info2 *info2)
{
return query_file_path_info2(mem_ctx, torture, cli,
-1, fname, info2);
}
static BOOL search_callback(void *private, const union smb_search_data *fdata)
{
struct unix_info2 *info2 = (struct unix_info2 *)private;
info2->end_of_file = fdata->unix_info2.end_of_file;
info2->num_bytes = fdata->unix_info2.num_bytes;
info2->status_change_time = fdata->unix_info2.status_change_time;
info2->access_time = fdata->unix_info2.access_time;
info2->change_time = fdata->unix_info2.change_time;
info2->uid = fdata->unix_info2.uid;
info2->gid = fdata->unix_info2.gid;
info2->file_type = fdata->unix_info2.file_type;
info2->dev_major = fdata->unix_info2.dev_major;
info2->dev_minor = fdata->unix_info2.dev_minor;
info2->unique_id = fdata->unix_info2.unique_id;
info2->permissions = fdata->unix_info2.permissions;
info2->nlink = fdata->unix_info2.nlink;
info2->create_time = fdata->unix_info2.create_time;
info2->file_flags = fdata->unix_info2.file_flags;
info2->flags_mask = fdata->unix_info2.flags_mask;
return True;
}
static BOOL find_single_info2(void *mem_ctx,
struct torture_context *torture,
struct smbcli_state *cli,
const char *fname,
struct unix_info2 *info2)
{
union smb_search_first search;
NTSTATUS status;
/* Set up a new search for a single item, not using resume keys. */
ZERO_STRUCT(search);
search.t2ffirst.level = RAW_SEARCH_TRANS2;
search.t2ffirst.data_level = SMB_FIND_UNIX_INFO2;
search.t2ffirst.in.max_count = 1;
search.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
search.t2ffirst.in.pattern = fname;
status = smb_raw_search_first(cli->tree, mem_ctx,
&search, info2, search_callback);
torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
smbcli_errstr(cli->tree));
torture_assert_int_equal(torture, search.t2ffirst.out.count, 1,
"expected exactly one result");
torture_assert_int_equal(torture, search.t2ffirst.out.end_of_search, 1,
"expected end_of_search to be true");
return check_unix_info2(torture, info2);
}
#define ASSERT_FLAGS_MATCH(info2, expected) \
if ((info2)->file_flags != (1 << i)) { \
torture_result(torture, TORTURE_FAIL, \
__location__": INFO2 flags field was 0x%08x, "\
"expected 0x%08x\n",\
(info2)->file_flags, expected); \
}
static void set_no_metadata_change(struct unix_info2 *info2)
{
info2->uid = SMB_UID_NO_CHANGE;
info2->gid = SMB_GID_NO_CHANGE;
info2->permissions = SMB_MODE_NO_CHANGE;
info2->end_of_file =
((uint64_t)SMB_SIZE_NO_CHANGE_HI << 32) | SMB_SIZE_NO_CHANGE_LO;
info2->status_change_time =
info2->access_time =
info2->change_time =
info2->create_time =
((uint64_t)SMB_SIZE_NO_CHANGE_HI << 32) | SMB_SIZE_NO_CHANGE_LO;
}
static BOOL verify_setinfo_flags(void *mem_ctx,
struct torture_context *torture,
struct smbcli_state *cli,
const char *fname)
{
struct unix_info2 info2;
uint32_t smb_fmask;
int i;
BOOL ret = True;
NTSTATUS status;
if (!query_path_info2(mem_ctx, torture, cli, fname, &info2)) {
return False;
}
smb_fmask = info2.flags_mask;
/* For each possible flag, ask to set exactly 1 flag, making sure
* that flag is in our requested mask.
*/
for (i = 0; i < 32; ++i) {
info2.file_flags = (1 << i);
info2.flags_mask = smb_fmask | info2.file_flags;
set_no_metadata_change(&info2);
status = set_path_info2(mem_ctx, cli, fname, &info2);
if (info2.file_flags & smb_fmask) {
torture_assert_ntstatus_equal(torture,
status, NT_STATUS_OK,
"setting UNIX_INFO2 flags");
if (!query_path_info2(mem_ctx, torture, cli,
fname, &info2)) {
return False;
}
ASSERT_FLAGS_MATCH(&info2, 1 << i);
} else {
/* We tried to set a flag the server doesn't
* understand.
*/
torture_assert_ntstatus_equal(torture,
status, NT_STATUS_INVALID_PARAMETER,
"setting UNIX_INFO2 flags");
}
}
/* Make sure that a zero flags field does nothing. */
set_no_metadata_change(&info2);
info2.file_flags = 0xFFFFFFFF;
info2.flags_mask = 0;
status = set_path_info2(mem_ctx, cli, fname, &info2);
torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
"setting empty flags mask");
return ret;
}
static int create_file(struct smbcli_state *cli, const char * fname)
{
return smbcli_nt_create_full(cli->tree, fname, 0,
SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF,
0, 0);
}
static BOOL match_info2(struct torture_context *torture,
const struct unix_info2 *pinfo,
const struct unix_info2 *finfo)
{
printf("checking results match\n");
torture_assert_u64_equal(torture, finfo->end_of_file, 0,
"end_of_file should be 0");
torture_assert_u64_equal(torture, finfo->num_bytes, 0,
"num_bytes should be 0");
torture_assert_u64_equal(torture, finfo->end_of_file,
pinfo->end_of_file, "end_of_file mismatch");
torture_assert_u64_equal(torture, finfo->num_bytes, pinfo->num_bytes,
"num_bytes mismatch");
/* Don't match access_time. */
torture_assert_u64_equal(torture, finfo->status_change_time,
pinfo->status_change_time,
"status_change_time mismatch");
torture_assert_u64_equal(torture, finfo->change_time,
pinfo->change_time, "change_time mismatch");
torture_assert_u64_equal(torture, finfo->uid, pinfo->uid,
"UID mismatch");
torture_assert_u64_equal(torture, finfo->gid, pinfo->gid,
"GID mismatch");
torture_assert_int_equal(torture, finfo->file_type, pinfo->file_type,
"file_type mismatch");
torture_assert_u64_equal(torture, finfo->dev_major, pinfo->dev_major,
"dev_major mismatch");
torture_assert_u64_equal(torture, finfo->dev_minor, pinfo->dev_minor,
"dev_minor mismatch");
torture_assert_u64_equal(torture, finfo->unique_id, pinfo->unique_id,
"unique_id mismatch");
torture_assert_u64_equal(torture, finfo->permissions,
pinfo->permissions, "permissions mismatch");
torture_assert_u64_equal(torture, finfo->nlink, pinfo->nlink,
"nlink mismatch");
torture_assert_u64_equal(torture, finfo->create_time, pinfo->create_time,
"create_time mismatch");
return True;
}
#define FILENAME "\\smb_unix_info2.txt"
BOOL unix_torture_unix_info2(struct torture_context *torture)
{
void *mem_ctx;
struct smbcli_state *cli;
int fnum;
struct unix_info2 pinfo, finfo;
mem_ctx = talloc_init("smb_query_unix_info2");
torture_assert(torture, mem_ctx != NULL, "out of memory");
if (!(cli = connect_to_server(mem_ctx))) {
talloc_free(mem_ctx);
return False;
}
smbcli_unlink(cli->tree, FILENAME);
fnum = create_file(cli, FILENAME);
torture_assert(torture, fnum != -1, smbcli_errstr(cli->tree));
printf("checking SMB_QFILEINFO_UNIX_INFO2 for QueryFileInfo\n");
if (!query_file_info2(mem_ctx, torture, cli, fnum, &finfo)) {
goto fail;
}
printf("checking SMB_QFILEINFO_UNIX_INFO2 for QueryPathInfo\n");
if (!query_path_info2(mem_ctx, torture, cli, FILENAME, &pinfo)) {
goto fail;
}
if (!match_info2(torture, &pinfo, &finfo)) {
goto fail;
}
printf("checking SMB_FIND_UNIX_INFO2 for FindFirst\n");
if (!find_single_info2(mem_ctx, torture, cli, FILENAME, &pinfo)) {
goto fail;
}
if (!match_info2(torture, &pinfo, &finfo)) {
goto fail;
}
/* XXX: should repeat this test with SetFileInfo. */
printf("checking SMB_SFILEINFO_UNIX_INFO2 for SetPathInfo\n");
if (!verify_setinfo_flags(mem_ctx, torture, cli, FILENAME)) {
goto fail;
}
smbcli_close(cli->tree, fnum);
smbcli_unlink(cli->tree, FILENAME);
torture_close_connection(cli);
talloc_free(mem_ctx);
return True;
fail:
smbcli_close(cli->tree, fnum);
smbcli_unlink(cli->tree, FILENAME);
torture_close_connection(cli);
talloc_free(mem_ctx);
return False;
}
/* vim: set sts=8 sw=8 : */