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"
28 #include "torture/raw/proto.h"
30 #define BASEDIR "\\testeas"
32 #define CHECK_STATUS(status, correct) do { \
33 torture_assert_ntstatus_equal_goto(tctx, status, correct, ret, done, "Incorrect status"); \
36 static bool maxeadebug
; /* need that here, to allow no file delete in debug case */
38 static bool check_ea(struct smbcli_state
*cli
,
39 const char *fname
, const char *eaname
, const char *value
)
41 NTSTATUS status
= torture_check_ea(cli
, fname
, eaname
, value
);
42 return NT_STATUS_IS_OK(status
);
45 static bool test_eas(struct smbcli_state
*cli
, struct torture_context
*tctx
)
48 union smb_setfileinfo setfile
;
50 const char *fname
= BASEDIR
"\\ea.txt";
54 torture_comment(tctx
, "TESTING SETFILEINFO EA_SET\n");
56 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
57 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
58 io
.ntcreatex
.in
.flags
= 0;
59 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
60 io
.ntcreatex
.in
.create_options
= 0;
61 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
62 io
.ntcreatex
.in
.share_access
=
63 NTCREATEX_SHARE_ACCESS_READ
|
64 NTCREATEX_SHARE_ACCESS_WRITE
;
65 io
.ntcreatex
.in
.alloc_size
= 0;
66 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
67 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
68 io
.ntcreatex
.in
.security_flags
= 0;
69 io
.ntcreatex
.in
.fname
= fname
;
70 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
71 CHECK_STATUS(status
, NT_STATUS_OK
);
72 fnum
= io
.ntcreatex
.out
.file
.fnum
;
74 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
76 torture_comment(tctx
, "Adding first two EAs\n");
77 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
78 setfile
.generic
.in
.file
.fnum
= fnum
;
79 setfile
.ea_set
.in
.num_eas
= 2;
80 setfile
.ea_set
.in
.eas
= talloc_array(tctx
, struct ea_struct
, 2);
81 setfile
.ea_set
.in
.eas
[0].flags
= 0;
82 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
83 setfile
.ea_set
.in
.eas
[0].value
= data_blob_string_const("VALUE1");
84 setfile
.ea_set
.in
.eas
[1].flags
= 0;
85 setfile
.ea_set
.in
.eas
[1].name
.s
= "SECONDEA";
86 setfile
.ea_set
.in
.eas
[1].value
= data_blob_string_const("ValueTwo");
88 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
89 CHECK_STATUS(status
, NT_STATUS_OK
);
91 ret
&= check_ea(cli
, fname
, "EAONE", "VALUE1");
92 ret
&= check_ea(cli
, fname
, "SECONDEA", "ValueTwo");
94 torture_comment(tctx
, "Modifying 2nd EA\n");
95 setfile
.ea_set
.in
.num_eas
= 1;
96 setfile
.ea_set
.in
.eas
[0].name
.s
= "SECONDEA";
97 setfile
.ea_set
.in
.eas
[0].value
= data_blob_string_const(" Changed Value");
98 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
99 CHECK_STATUS(status
, NT_STATUS_OK
);
101 ret
&= check_ea(cli
, fname
, "EAONE", "VALUE1");
102 ret
&= check_ea(cli
, fname
, "SECONDEA", " Changed Value");
104 torture_comment(tctx
, "Setting a NULL EA\n");
105 setfile
.ea_set
.in
.eas
[0].value
= data_blob(NULL
, 0);
106 setfile
.ea_set
.in
.eas
[0].name
.s
= "NULLEA";
107 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
108 CHECK_STATUS(status
, NT_STATUS_OK
);
110 ret
&= check_ea(cli
, fname
, "EAONE", "VALUE1");
111 ret
&= check_ea(cli
, fname
, "SECONDEA", " Changed Value");
112 ret
&= check_ea(cli
, fname
, "NULLEA", NULL
);
114 torture_comment(tctx
, "Deleting first EA\n");
115 setfile
.ea_set
.in
.eas
[0].flags
= 0;
116 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
117 setfile
.ea_set
.in
.eas
[0].value
= data_blob(NULL
, 0);
118 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
119 CHECK_STATUS(status
, NT_STATUS_OK
);
121 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
122 ret
&= check_ea(cli
, fname
, "SECONDEA", " Changed Value");
124 torture_comment(tctx
, "Deleting second EA\n");
125 setfile
.ea_set
.in
.eas
[0].flags
= 0;
126 setfile
.ea_set
.in
.eas
[0].name
.s
= "SECONDEA";
127 setfile
.ea_set
.in
.eas
[0].value
= data_blob(NULL
, 0);
128 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
129 CHECK_STATUS(status
, NT_STATUS_OK
);
131 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
132 ret
&= check_ea(cli
, fname
, "SECONDEA", NULL
);
135 smbcli_close(cli
->tree
, fnum
);
141 * Helper function to retrieve the max. ea size for one ea name
143 static int test_one_eamax(struct torture_context
*tctx
,
144 struct smbcli_state
*cli
, const int fnum
,
145 const char *eaname
, DATA_BLOB eablob
,
146 const int eastart
, const int eadebug
)
149 struct ea_struct eastruct
;
150 union smb_setfileinfo setfile
;
151 int i
, high
, low
, maxeasize
;
153 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
154 setfile
.generic
.in
.file
.fnum
= fnum
;
155 setfile
.ea_set
.in
.num_eas
= 1;
156 setfile
.ea_set
.in
.eas
= &eastruct
;
157 setfile
.ea_set
.in
.eas
->flags
= 0;
158 setfile
.ea_set
.in
.eas
->name
.s
= eaname
;
159 setfile
.ea_set
.in
.eas
->value
= eablob
;
161 maxeasize
= eablob
.length
;
168 torture_comment(tctx
, "Testing EA size: %d\n", i
);
170 setfile
.ea_set
.in
.eas
->value
.length
= i
;
172 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
174 if (NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
176 torture_comment(tctx
, "[%s] EA size %d succeeded! "
177 "(high=%d low=%d)\n",
178 eaname
, i
, high
, low
);
181 if (low
== maxeasize
) {
182 torture_comment(tctx
, "Max. EA size for \"%s\"=%d "
183 "[but could be possibly larger]\n",
187 if (high
- low
== 1 && high
!= maxeasize
) {
188 torture_comment(tctx
, "Max. EA size for \"%s\"=%d\n",
192 i
+= (high
- low
+ 1) / 2;
195 torture_comment(tctx
, "[%s] EA size %d failed! "
196 "(high=%d low=%d) [%s]\n",
197 eaname
, i
, high
, low
,
201 if (high
- low
<= 1) {
202 torture_comment(tctx
, "Max. EA size for \"%s\"=%d\n",
206 i
-= (high
- low
+ 1) / 2;
214 * Test for maximum ea size - more than one ea name is checked.
216 * Additional parameters can be passed, to allow further testing:
219 * maxeasize 65536 limit the max. size for a single EA name
220 * maxeanames 101 limit of the number of tested names
221 * maxeastart 1 this EA size is used to test for the 1st EA (atm)
222 * maxeadebug 0 if set true, further debug output is done - in addition
223 * the testfile is not deleted for further inspection!
225 * Set some/all of these options on the cmdline with:
226 * --option torture:maxeasize=1024 --option torture:maxeadebug=1 ...
229 static bool test_max_eas(struct smbcli_state
*cli
, struct torture_context
*tctx
)
233 const char *fname
= BASEDIR
"\\ea_max.txt";
238 int i
, j
, k
, last
, total
;
245 torture_comment(tctx
, "TESTING SETFILEINFO MAX. EA_SET\n");
247 maxeasize
= torture_setting_int(tctx
, "maxeasize", 65536);
248 maxeanames
= torture_setting_int(tctx
, "maxeanames", 101);
249 maxeastart
= torture_setting_int(tctx
, "maxeastart", 1);
250 maxeadebug
= torture_setting_int(tctx
, "maxeadebug", 0);
252 /* Do some sanity check on possibly passed parms */
253 if (maxeasize
<= 0) {
254 torture_comment(tctx
, "Invalid parameter 'maxeasize=%d'",maxeasize
);
257 if (maxeanames
<= 0) {
258 torture_comment(tctx
, "Invalid parameter 'maxeanames=%d'",maxeanames
);
261 if (maxeastart
<= 0) {
262 torture_comment(tctx
, "Invalid parameter 'maxeastart=%d'",maxeastart
);
265 if (maxeadebug
< 0) {
266 torture_comment(tctx
, "Invalid parameter 'maxeadebug=%d'",maxeadebug
);
270 torture_comment(tctx
, "\n\n");
273 if (maxeastart
> maxeasize
) {
274 maxeastart
= maxeasize
;
275 torture_comment(tctx
, "'maxeastart' outside range - corrected to %d\n",
278 torture_comment(tctx
, "MAXEA parms: maxeasize=%d maxeanames=%d maxeastart=%d"
279 " maxeadebug=%d\n", maxeasize
, maxeanames
, maxeastart
,
282 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
283 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
284 io
.ntcreatex
.in
.flags
= 0;
285 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
286 io
.ntcreatex
.in
.create_options
= 0;
287 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
288 io
.ntcreatex
.in
.share_access
=
289 NTCREATEX_SHARE_ACCESS_READ
|
290 NTCREATEX_SHARE_ACCESS_WRITE
;
291 io
.ntcreatex
.in
.alloc_size
= 0;
292 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
293 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
294 io
.ntcreatex
.in
.security_flags
= 0;
295 io
.ntcreatex
.in
.fname
= fname
;
296 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
297 CHECK_STATUS(status
, NT_STATUS_OK
);
298 fnum
= io
.ntcreatex
.out
.file
.fnum
;
300 eablob
= data_blob_talloc(tctx
, NULL
, maxeasize
);
301 if (eablob
.data
== NULL
) {
305 * Fill in some EA data - the offset could be easily checked
308 for (i
= 0, k
= 0; i
< eablob
.length
/ 4; i
++, k
+=4) {
309 eablob
.data
[k
] = k
& 0xff;
310 eablob
.data
[k
+1] = (k
>> 8) & 0xff;
311 eablob
.data
[k
+2] = (k
>> 16) & 0xff;
312 eablob
.data
[k
+3] = (k
>> 24) & 0xff;
315 i
= eablob
.length
% 4;
317 eablob
.data
[k
] = k
& 0xff;
319 eablob
.data
[k
+1] = (k
>> 8) & 0xff;
321 eablob
.data
[k
+2] = (k
>> 16) & 0xff;
326 * Filesystems might allow max. EAs data for different EA names.
327 * So more than one EA name should be checked.
332 for (i
= 0; i
< maxeanames
; i
++) {
333 if (eaname
!= NULL
) {
336 eaname
= talloc_asprintf(tctx
, "MAX%d", i
);
340 j
= test_one_eamax(tctx
, cli
, fnum
, eaname
, eablob
, last
, maxeadebug
);
348 torture_comment(tctx
, "Total EA size:%d\n", total
);
349 if (i
== maxeanames
) {
350 torture_comment(tctx
, "NOTE: More EAs could be available!\n");
356 smbcli_close(cli
->tree
, fnum
);
361 test using NTTRANS CREATE to create a file with an initial EA set
363 static bool test_nttrans_create(struct smbcli_state
*cli
, struct torture_context
*tctx
)
367 const char *fname
= BASEDIR
"\\ea2.txt";
370 struct ea_struct eas
[3];
371 struct smb_ea_list ea_list
;
373 torture_comment(tctx
, "TESTING NTTRANS CREATE WITH EAS\n");
375 io
.generic
.level
= RAW_OPEN_NTTRANS_CREATE
;
376 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
377 io
.ntcreatex
.in
.flags
= 0;
378 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
379 io
.ntcreatex
.in
.create_options
= 0;
380 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
381 io
.ntcreatex
.in
.share_access
=
382 NTCREATEX_SHARE_ACCESS_READ
|
383 NTCREATEX_SHARE_ACCESS_WRITE
;
384 io
.ntcreatex
.in
.alloc_size
= 0;
385 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
386 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
387 io
.ntcreatex
.in
.security_flags
= 0;
388 io
.ntcreatex
.in
.fname
= fname
;
394 eas
[0].name
.s
= "1st EA";
395 eas
[0].value
= data_blob_string_const("Value One");
398 eas
[1].name
.s
= "2nd EA";
399 eas
[1].value
= data_blob_string_const("Second Value");
402 eas
[2].name
.s
= "and 3rd";
403 eas
[2].value
= data_blob_string_const("final value");
405 io
.ntcreatex
.in
.ea_list
= &ea_list
;
406 io
.ntcreatex
.in
.sec_desc
= NULL
;
408 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
409 CHECK_STATUS(status
, NT_STATUS_OK
);
410 fnum
= io
.ntcreatex
.out
.file
.fnum
;
412 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
413 ret
&= check_ea(cli
, fname
, "1st EA", "Value One");
414 ret
&= check_ea(cli
, fname
, "2nd EA", "Second Value");
415 ret
&= check_ea(cli
, fname
, "and 3rd", "final value");
417 smbcli_close(cli
->tree
, fnum
);
419 torture_comment(tctx
, "Trying to add EAs on non-create\n");
420 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
421 io
.ntcreatex
.in
.fname
= fname
;
425 eas
[0].name
.s
= "Fourth EA";
426 eas
[0].value
= data_blob_string_const("Value Four");
428 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
429 CHECK_STATUS(status
, NT_STATUS_OK
);
430 fnum
= io
.ntcreatex
.out
.file
.fnum
;
432 ret
&= check_ea(cli
, fname
, "1st EA", "Value One");
433 ret
&= check_ea(cli
, fname
, "2nd EA", "Second Value");
434 ret
&= check_ea(cli
, fname
, "and 3rd", "final value");
435 ret
&= check_ea(cli
, fname
, "Fourth EA", NULL
);
438 smbcli_close(cli
->tree
, fnum
);
443 basic testing of EA calls
445 bool torture_raw_eas(struct torture_context
*torture
, struct smbcli_state
*cli
)
449 if (!torture_setup_dir(cli
, BASEDIR
)) {
453 ret
&= test_eas(cli
, torture
);
454 ret
&= test_nttrans_create(cli
, torture
);
456 smb_raw_exit(cli
->session
);
464 bool torture_max_eas(struct torture_context
*torture
)
466 struct smbcli_state
*cli
;
469 if (!torture_open_connection(&cli
, torture
, 0)) {
473 if (!torture_setup_dir(cli
, BASEDIR
)) {
477 ret
&= test_max_eas(cli
, torture
);
479 smb_raw_exit(cli
->session
);
481 /* in no ea debug case, all files are gone now */
482 smbcli_deltree(cli
->tree
, BASEDIR
);
485 torture_close_connection(cli
);