2 Unix SMB/CIFS implementation.
4 test DOS extended attributes
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Guenter Kukkukk 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "torture/torture.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/libcli.h"
27 #include "torture/util.h"
29 #define BASEDIR "\\testeas"
31 #define CHECK_STATUS(status, correct) do { \
32 torture_assert_ntstatus_equal_goto(tctx, status, correct, ret, done, "Incorrect status"); \
35 static bool maxeadebug
; /* need that here, to allow no file delete in debug case */
37 static bool check_ea(struct smbcli_state
*cli
,
38 const char *fname
, const char *eaname
, const char *value
)
40 NTSTATUS status
= torture_check_ea(cli
, fname
, eaname
, value
);
41 return NT_STATUS_IS_OK(status
);
44 static bool test_eas(struct smbcli_state
*cli
, struct torture_context
*tctx
)
47 union smb_setfileinfo setfile
;
49 const char *fname
= BASEDIR
"\\ea.txt";
53 torture_comment(tctx
, "TESTING SETFILEINFO EA_SET\n");
55 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
56 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
57 io
.ntcreatex
.in
.flags
= 0;
58 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
59 io
.ntcreatex
.in
.create_options
= 0;
60 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
61 io
.ntcreatex
.in
.share_access
=
62 NTCREATEX_SHARE_ACCESS_READ
|
63 NTCREATEX_SHARE_ACCESS_WRITE
;
64 io
.ntcreatex
.in
.alloc_size
= 0;
65 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
66 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
67 io
.ntcreatex
.in
.security_flags
= 0;
68 io
.ntcreatex
.in
.fname
= fname
;
69 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
70 CHECK_STATUS(status
, NT_STATUS_OK
);
71 fnum
= io
.ntcreatex
.out
.file
.fnum
;
73 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
75 torture_comment(tctx
, "Adding first two EAs\n");
76 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
77 setfile
.generic
.in
.file
.fnum
= fnum
;
78 setfile
.ea_set
.in
.num_eas
= 2;
79 setfile
.ea_set
.in
.eas
= talloc_array(tctx
, struct ea_struct
, 2);
80 setfile
.ea_set
.in
.eas
[0].flags
= 0;
81 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
82 setfile
.ea_set
.in
.eas
[0].value
= data_blob_string_const("VALUE1");
83 setfile
.ea_set
.in
.eas
[1].flags
= 0;
84 setfile
.ea_set
.in
.eas
[1].name
.s
= "SECONDEA";
85 setfile
.ea_set
.in
.eas
[1].value
= data_blob_string_const("ValueTwo");
87 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
88 CHECK_STATUS(status
, NT_STATUS_OK
);
90 ret
&= check_ea(cli
, fname
, "EAONE", "VALUE1");
91 ret
&= check_ea(cli
, fname
, "SECONDEA", "ValueTwo");
93 torture_comment(tctx
, "Modifying 2nd EA\n");
94 setfile
.ea_set
.in
.num_eas
= 1;
95 setfile
.ea_set
.in
.eas
[0].name
.s
= "SECONDEA";
96 setfile
.ea_set
.in
.eas
[0].value
= data_blob_string_const(" Changed Value");
97 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
98 CHECK_STATUS(status
, NT_STATUS_OK
);
100 ret
&= check_ea(cli
, fname
, "EAONE", "VALUE1");
101 ret
&= check_ea(cli
, fname
, "SECONDEA", " Changed Value");
103 torture_comment(tctx
, "Setting a NULL EA\n");
104 setfile
.ea_set
.in
.eas
[0].value
= data_blob(NULL
, 0);
105 setfile
.ea_set
.in
.eas
[0].name
.s
= "NULLEA";
106 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
107 CHECK_STATUS(status
, NT_STATUS_OK
);
109 ret
&= check_ea(cli
, fname
, "EAONE", "VALUE1");
110 ret
&= check_ea(cli
, fname
, "SECONDEA", " Changed Value");
111 ret
&= check_ea(cli
, fname
, "NULLEA", NULL
);
113 torture_comment(tctx
, "Deleting first EA\n");
114 setfile
.ea_set
.in
.eas
[0].flags
= 0;
115 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
116 setfile
.ea_set
.in
.eas
[0].value
= data_blob(NULL
, 0);
117 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
118 CHECK_STATUS(status
, NT_STATUS_OK
);
120 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
121 ret
&= check_ea(cli
, fname
, "SECONDEA", " Changed Value");
123 torture_comment(tctx
, "Deleting second EA\n");
124 setfile
.ea_set
.in
.eas
[0].flags
= 0;
125 setfile
.ea_set
.in
.eas
[0].name
.s
= "SECONDEA";
126 setfile
.ea_set
.in
.eas
[0].value
= data_blob(NULL
, 0);
127 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
128 CHECK_STATUS(status
, NT_STATUS_OK
);
130 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
131 ret
&= check_ea(cli
, fname
, "SECONDEA", NULL
);
134 smbcli_close(cli
->tree
, fnum
);
140 * Helper function to retrieve the max. ea size for one ea name
142 static int test_one_eamax(struct torture_context
*tctx
,
143 struct smbcli_state
*cli
, const int fnum
,
144 const char *eaname
, DATA_BLOB eablob
,
145 const int eastart
, const int eadebug
)
148 struct ea_struct eastruct
;
149 union smb_setfileinfo setfile
;
150 int i
, high
, low
, maxeasize
;
152 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
153 setfile
.generic
.in
.file
.fnum
= fnum
;
154 setfile
.ea_set
.in
.num_eas
= 1;
155 setfile
.ea_set
.in
.eas
= &eastruct
;
156 setfile
.ea_set
.in
.eas
->flags
= 0;
157 setfile
.ea_set
.in
.eas
->name
.s
= eaname
;
158 setfile
.ea_set
.in
.eas
->value
= eablob
;
160 maxeasize
= eablob
.length
;
167 torture_comment(tctx
, "Testing EA size: %d\n", i
);
169 setfile
.ea_set
.in
.eas
->value
.length
= i
;
171 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
173 if (NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
175 torture_comment(tctx
, "[%s] EA size %d succeeded! "
176 "(high=%d low=%d)\n",
177 eaname
, i
, high
, low
);
180 if (low
== maxeasize
) {
181 torture_comment(tctx
, "Max. EA size for \"%s\"=%d "
182 "[but could be possibly larger]\n",
186 if (high
- low
== 1 && high
!= maxeasize
) {
187 torture_comment(tctx
, "Max. EA size for \"%s\"=%d\n",
191 i
+= (high
- low
+ 1) / 2;
194 torture_comment(tctx
, "[%s] EA size %d failed! "
195 "(high=%d low=%d) [%s]\n",
196 eaname
, i
, high
, low
,
200 if (high
- low
<= 1) {
201 torture_comment(tctx
, "Max. EA size for \"%s\"=%d\n",
205 i
-= (high
- low
+ 1) / 2;
213 * Test for maximum ea size - more than one ea name is checked.
215 * Additional parameters can be passed, to allow further testing:
218 * maxeasize 65536 limit the max. size for a single EA name
219 * maxeanames 101 limit of the number of tested names
220 * maxeastart 1 this EA size is used to test for the 1st EA (atm)
221 * maxeadebug 0 if set true, further debug output is done - in addition
222 * the testfile is not deleted for further inspection!
224 * Set some/all of these options on the cmdline with:
225 * --option torture:maxeasize=1024 --option torture:maxeadebug=1 ...
228 static bool test_max_eas(struct smbcli_state
*cli
, struct torture_context
*tctx
)
232 const char *fname
= BASEDIR
"\\ea_max.txt";
237 int i
, j
, k
, last
, total
;
244 torture_comment(tctx
, "TESTING SETFILEINFO MAX. EA_SET\n");
246 maxeasize
= torture_setting_int(tctx
, "maxeasize", 65536);
247 maxeanames
= torture_setting_int(tctx
, "maxeanames", 101);
248 maxeastart
= torture_setting_int(tctx
, "maxeastart", 1);
249 maxeadebug
= torture_setting_int(tctx
, "maxeadebug", 0);
251 /* Do some sanity check on possibly passed parms */
252 if (maxeasize
<= 0) {
253 torture_comment(tctx
, "Invalid parameter 'maxeasize=%d'",maxeasize
);
256 if (maxeanames
<= 0) {
257 torture_comment(tctx
, "Invalid parameter 'maxeanames=%d'",maxeanames
);
260 if (maxeastart
<= 0) {
261 torture_comment(tctx
, "Invalid parameter 'maxeastart=%d'",maxeastart
);
264 if (maxeadebug
< 0) {
265 torture_comment(tctx
, "Invalid parameter 'maxeadebug=%d'",maxeadebug
);
269 torture_comment(tctx
, "\n\n");
272 if (maxeastart
> maxeasize
) {
273 maxeastart
= maxeasize
;
274 torture_comment(tctx
, "'maxeastart' outside range - corrected to %d\n",
277 torture_comment(tctx
, "MAXEA parms: maxeasize=%d maxeanames=%d maxeastart=%d"
278 " maxeadebug=%d\n", maxeasize
, maxeanames
, maxeastart
,
281 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
282 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
283 io
.ntcreatex
.in
.flags
= 0;
284 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
285 io
.ntcreatex
.in
.create_options
= 0;
286 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
287 io
.ntcreatex
.in
.share_access
=
288 NTCREATEX_SHARE_ACCESS_READ
|
289 NTCREATEX_SHARE_ACCESS_WRITE
;
290 io
.ntcreatex
.in
.alloc_size
= 0;
291 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
292 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
293 io
.ntcreatex
.in
.security_flags
= 0;
294 io
.ntcreatex
.in
.fname
= fname
;
295 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
296 CHECK_STATUS(status
, NT_STATUS_OK
);
297 fnum
= io
.ntcreatex
.out
.file
.fnum
;
299 eablob
= data_blob_talloc(tctx
, NULL
, maxeasize
);
300 if (eablob
.data
== NULL
) {
304 * Fill in some EA data - the offset could be easily checked
307 for (i
= 0, k
= 0; i
< eablob
.length
/ 4; i
++, k
+=4) {
308 eablob
.data
[k
] = k
& 0xff;
309 eablob
.data
[k
+1] = (k
>> 8) & 0xff;
310 eablob
.data
[k
+2] = (k
>> 16) & 0xff;
311 eablob
.data
[k
+3] = (k
>> 24) & 0xff;
314 i
= eablob
.length
% 4;
316 eablob
.data
[k
] = k
& 0xff;
318 eablob
.data
[k
+1] = (k
>> 8) & 0xff;
320 eablob
.data
[k
+2] = (k
>> 16) & 0xff;
325 * Filesystems might allow max. EAs data for different EA names.
326 * So more than one EA name should be checked.
331 for (i
= 0; i
< maxeanames
; i
++) {
332 if (eaname
!= NULL
) {
335 eaname
= talloc_asprintf(tctx
, "MAX%d", i
);
339 j
= test_one_eamax(tctx
, cli
, fnum
, eaname
, eablob
, last
, maxeadebug
);
347 torture_comment(tctx
, "Total EA size:%d\n", total
);
348 if (i
== maxeanames
) {
349 torture_comment(tctx
, "NOTE: More EAs could be available!\n");
355 smbcli_close(cli
->tree
, fnum
);
360 test using NTTRANS CREATE to create a file with an initial EA set
362 static bool test_nttrans_create(struct smbcli_state
*cli
, struct torture_context
*tctx
)
366 const char *fname
= BASEDIR
"\\ea2.txt";
369 struct ea_struct eas
[3];
370 struct smb_ea_list ea_list
;
372 torture_comment(tctx
, "TESTING NTTRANS CREATE WITH EAS\n");
374 io
.generic
.level
= RAW_OPEN_NTTRANS_CREATE
;
375 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
376 io
.ntcreatex
.in
.flags
= 0;
377 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
378 io
.ntcreatex
.in
.create_options
= 0;
379 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
380 io
.ntcreatex
.in
.share_access
=
381 NTCREATEX_SHARE_ACCESS_READ
|
382 NTCREATEX_SHARE_ACCESS_WRITE
;
383 io
.ntcreatex
.in
.alloc_size
= 0;
384 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
385 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
386 io
.ntcreatex
.in
.security_flags
= 0;
387 io
.ntcreatex
.in
.fname
= fname
;
393 eas
[0].name
.s
= "1st EA";
394 eas
[0].value
= data_blob_string_const("Value One");
397 eas
[1].name
.s
= "2nd EA";
398 eas
[1].value
= data_blob_string_const("Second Value");
401 eas
[2].name
.s
= "and 3rd";
402 eas
[2].value
= data_blob_string_const("final value");
404 io
.ntcreatex
.in
.ea_list
= &ea_list
;
405 io
.ntcreatex
.in
.sec_desc
= NULL
;
407 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
408 CHECK_STATUS(status
, NT_STATUS_OK
);
409 fnum
= io
.ntcreatex
.out
.file
.fnum
;
411 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
412 ret
&= check_ea(cli
, fname
, "1st EA", "Value One");
413 ret
&= check_ea(cli
, fname
, "2nd EA", "Second Value");
414 ret
&= check_ea(cli
, fname
, "and 3rd", "final value");
416 smbcli_close(cli
->tree
, fnum
);
418 torture_comment(tctx
, "Trying to add EAs on non-create\n");
419 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
420 io
.ntcreatex
.in
.fname
= fname
;
424 eas
[0].name
.s
= "Fourth EA";
425 eas
[0].value
= data_blob_string_const("Value Four");
427 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
428 CHECK_STATUS(status
, NT_STATUS_OK
);
429 fnum
= io
.ntcreatex
.out
.file
.fnum
;
431 ret
&= check_ea(cli
, fname
, "1st EA", "Value One");
432 ret
&= check_ea(cli
, fname
, "2nd EA", "Second Value");
433 ret
&= check_ea(cli
, fname
, "and 3rd", "final value");
434 ret
&= check_ea(cli
, fname
, "Fourth EA", NULL
);
437 smbcli_close(cli
->tree
, fnum
);
442 basic testing of EA calls
444 bool torture_raw_eas(struct torture_context
*torture
, struct smbcli_state
*cli
)
448 if (!torture_setup_dir(cli
, BASEDIR
)) {
452 ret
&= test_eas(cli
, torture
);
453 ret
&= test_nttrans_create(cli
, torture
);
455 smb_raw_exit(cli
->session
);
463 bool torture_max_eas(struct torture_context
*torture
)
465 struct smbcli_state
*cli
;
468 if (!torture_open_connection(&cli
, torture
, 0)) {
472 if (!torture_setup_dir(cli
, BASEDIR
)) {
476 ret
&= test_max_eas(cli
, torture
);
478 smb_raw_exit(cli
->session
);
480 /* in no ea debug case, all files are gone now */
481 smbcli_deltree(cli
->tree
, BASEDIR
);
484 torture_close_connection(cli
);