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 if (!NT_STATUS_EQUAL(status, correct)) { \
33 printf("(%s) Incorrect status %s - should be %s\n", \
34 __location__, nt_errstr(status), nt_errstr(correct)); \
39 static bool maxeadebug
; /* need that here, to allow no file delete in debug case */
41 static bool check_ea(struct smbcli_state
*cli
,
42 const char *fname
, const char *eaname
, const char *value
)
44 NTSTATUS status
= torture_check_ea(cli
, fname
, eaname
, value
);
45 return NT_STATUS_IS_OK(status
);
48 static bool test_eas(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
)
51 union smb_setfileinfo setfile
;
53 const char *fname
= BASEDIR
"\\ea.txt";
57 printf("TESTING SETFILEINFO EA_SET\n");
59 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
60 io
.ntcreatex
.in
.root_fid
= 0;
61 io
.ntcreatex
.in
.flags
= 0;
62 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
63 io
.ntcreatex
.in
.create_options
= 0;
64 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
65 io
.ntcreatex
.in
.share_access
=
66 NTCREATEX_SHARE_ACCESS_READ
|
67 NTCREATEX_SHARE_ACCESS_WRITE
;
68 io
.ntcreatex
.in
.alloc_size
= 0;
69 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
70 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
71 io
.ntcreatex
.in
.security_flags
= 0;
72 io
.ntcreatex
.in
.fname
= fname
;
73 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
74 CHECK_STATUS(status
, NT_STATUS_OK
);
75 fnum
= io
.ntcreatex
.out
.file
.fnum
;
77 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
79 printf("Adding first two EAs\n");
80 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
81 setfile
.generic
.in
.file
.fnum
= fnum
;
82 setfile
.ea_set
.in
.num_eas
= 2;
83 setfile
.ea_set
.in
.eas
= talloc_array(mem_ctx
, struct ea_struct
, 2);
84 setfile
.ea_set
.in
.eas
[0].flags
= 0;
85 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
86 setfile
.ea_set
.in
.eas
[0].value
= data_blob_string_const("VALUE1");
87 setfile
.ea_set
.in
.eas
[1].flags
= 0;
88 setfile
.ea_set
.in
.eas
[1].name
.s
= "SECONDEA";
89 setfile
.ea_set
.in
.eas
[1].value
= data_blob_string_const("ValueTwo");
91 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
92 CHECK_STATUS(status
, NT_STATUS_OK
);
94 ret
&= check_ea(cli
, fname
, "EAONE", "VALUE1");
95 ret
&= check_ea(cli
, fname
, "SECONDEA", "ValueTwo");
97 printf("Modifying 2nd EA\n");
98 setfile
.ea_set
.in
.num_eas
= 1;
99 setfile
.ea_set
.in
.eas
[0].name
.s
= "SECONDEA";
100 setfile
.ea_set
.in
.eas
[0].value
= data_blob_string_const(" Changed Value");
101 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
102 CHECK_STATUS(status
, NT_STATUS_OK
);
104 ret
&= check_ea(cli
, fname
, "EAONE", "VALUE1");
105 ret
&= check_ea(cli
, fname
, "SECONDEA", " Changed Value");
107 printf("Setting a NULL EA\n");
108 setfile
.ea_set
.in
.eas
[0].value
= data_blob(NULL
, 0);
109 setfile
.ea_set
.in
.eas
[0].name
.s
= "NULLEA";
110 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
111 CHECK_STATUS(status
, NT_STATUS_OK
);
113 ret
&= check_ea(cli
, fname
, "EAONE", "VALUE1");
114 ret
&= check_ea(cli
, fname
, "SECONDEA", " Changed Value");
115 ret
&= check_ea(cli
, fname
, "NULLEA", NULL
);
117 printf("Deleting first EA\n");
118 setfile
.ea_set
.in
.eas
[0].flags
= 0;
119 setfile
.ea_set
.in
.eas
[0].name
.s
= "EAONE";
120 setfile
.ea_set
.in
.eas
[0].value
= data_blob(NULL
, 0);
121 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
122 CHECK_STATUS(status
, NT_STATUS_OK
);
124 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
125 ret
&= check_ea(cli
, fname
, "SECONDEA", " Changed Value");
127 printf("Deleting second EA\n");
128 setfile
.ea_set
.in
.eas
[0].flags
= 0;
129 setfile
.ea_set
.in
.eas
[0].name
.s
= "SECONDEA";
130 setfile
.ea_set
.in
.eas
[0].value
= data_blob(NULL
, 0);
131 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
132 CHECK_STATUS(status
, NT_STATUS_OK
);
134 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
135 ret
&= check_ea(cli
, fname
, "SECONDEA", NULL
);
138 smbcli_close(cli
->tree
, fnum
);
144 * Helper function to retrieve the max. ea size for one ea name
146 static int test_one_eamax(struct smbcli_state
*cli
, const int fnum
,
147 const char *eaname
, DATA_BLOB eablob
,
148 const int eastart
, const int eadebug
)
151 struct ea_struct eastruct
;
152 union smb_setfileinfo setfile
;
153 int i
, high
, low
, maxeasize
;
155 setfile
.generic
.level
= RAW_SFILEINFO_EA_SET
;
156 setfile
.generic
.in
.file
.fnum
= fnum
;
157 setfile
.ea_set
.in
.num_eas
= 1;
158 setfile
.ea_set
.in
.eas
= &eastruct
;
159 setfile
.ea_set
.in
.eas
->flags
= 0;
160 setfile
.ea_set
.in
.eas
->name
.s
= eaname
;
161 setfile
.ea_set
.in
.eas
->value
= eablob
;
163 maxeasize
= eablob
.length
;
170 printf ("Testing EA size: %d\n", i
);
172 setfile
.ea_set
.in
.eas
->value
.length
= i
;
174 status
= smb_raw_setfileinfo(cli
->tree
, &setfile
);
176 if (NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
178 printf ("[%s] EA size %d succeeded! "
179 "(high=%d low=%d)\n",
180 eaname
, i
, high
, low
);
183 if (low
== maxeasize
) {
184 printf ("Max. EA size for \"%s\"=%d "
185 "[but could be possibly larger]\n",
189 if (high
- low
== 1 && high
!= maxeasize
) {
190 printf ("Max. EA size for \"%s\"=%d\n",
194 i
+= (high
- low
+ 1) / 2;
197 printf ("[%s] EA size %d failed! "
198 "(high=%d low=%d) [%s]\n",
199 eaname
, i
, high
, low
,
203 if (high
- low
<= 1) {
204 printf ("Max. EA size for \"%s\"=%d\n",
208 i
-= (high
- low
+ 1) / 2;
216 * Test for maximum ea size - more than one ea name is checked.
218 * Additional parameters can be passed, to allow further testing:
221 * maxeasize 65536 limit the max. size for a single EA name
222 * maxeanames 101 limit of the number of tested names
223 * maxeastart 1 this EA size is used to test for the 1st EA (atm)
224 * maxeadebug 0 if set true, further debug output is done - in addition
225 * the testfile is not deleted for further inspection!
227 * Set some/all of these options on the cmdline with:
228 * --option torture:maxeasize=1024 --option torture:maxeadebug=1 ...
231 static bool test_max_eas(struct smbcli_state
*cli
, struct torture_context
*tctx
)
235 const char *fname
= BASEDIR
"\\ea_max.txt";
240 int i
, j
, k
, last
, total
;
247 printf("TESTING SETFILEINFO MAX. EA_SET\n");
249 maxeasize
= torture_setting_int(tctx
, "maxeasize", 65536);
250 maxeanames
= torture_setting_int(tctx
, "maxeanames", 101);
251 maxeastart
= torture_setting_int(tctx
, "maxeastart", 1);
252 maxeadebug
= torture_setting_int(tctx
, "maxeadebug", 0);
254 /* Do some sanity check on possibly passed parms */
255 if (maxeasize
<= 0) {
256 printf("Invalid parameter 'maxeasize=%d'",maxeasize
);
259 if (maxeanames
<= 0) {
260 printf("Invalid parameter 'maxeanames=%d'",maxeanames
);
263 if (maxeastart
<= 0) {
264 printf("Invalid parameter 'maxeastart=%d'",maxeastart
);
267 if (maxeadebug
< 0) {
268 printf("Invalid parameter 'maxeadebug=%d'",maxeadebug
);
275 if (maxeastart
> maxeasize
) {
276 maxeastart
= maxeasize
;
277 printf ("'maxeastart' outside range - corrected to %d\n",
280 printf("MAXEA parms: maxeasize=%d maxeanames=%d maxeastart=%d"
281 " maxeadebug=%d\n", maxeasize
, maxeanames
, maxeastart
,
284 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
285 io
.ntcreatex
.in
.root_fid
= 0;
286 io
.ntcreatex
.in
.flags
= 0;
287 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
288 io
.ntcreatex
.in
.create_options
= 0;
289 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
290 io
.ntcreatex
.in
.share_access
=
291 NTCREATEX_SHARE_ACCESS_READ
|
292 NTCREATEX_SHARE_ACCESS_WRITE
;
293 io
.ntcreatex
.in
.alloc_size
= 0;
294 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
295 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
296 io
.ntcreatex
.in
.security_flags
= 0;
297 io
.ntcreatex
.in
.fname
= fname
;
298 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
299 CHECK_STATUS(status
, NT_STATUS_OK
);
300 fnum
= io
.ntcreatex
.out
.file
.fnum
;
302 eablob
= data_blob_talloc(tctx
, NULL
, maxeasize
);
303 if (eablob
.data
== NULL
) {
307 * Fill in some EA data - the offset could be easily checked
310 for (i
= 0, k
= 0; i
< eablob
.length
/ 4; i
++, k
+=4) {
311 eablob
.data
[k
] = k
& 0xff;
312 eablob
.data
[k
+1] = (k
>> 8) & 0xff;
313 eablob
.data
[k
+2] = (k
>> 16) & 0xff;
314 eablob
.data
[k
+3] = (k
>> 24) & 0xff;
317 i
= eablob
.length
% 4;
319 eablob
.data
[k
] = k
& 0xff;
321 eablob
.data
[k
+1] = (k
>> 8) & 0xff;
323 eablob
.data
[k
+2] = (k
>> 16) & 0xff;
328 * Filesystems might allow max. EAs data for different EA names.
329 * So more than one EA name should be checked.
334 for (i
= 0; i
< maxeanames
; i
++) {
335 if (eaname
!= NULL
) {
338 eaname
= talloc_asprintf(tctx
, "MAX%d", i
);
342 j
= test_one_eamax(cli
, fnum
, eaname
, eablob
, last
, maxeadebug
);
350 printf("Total EA size:%d\n", total
);
351 if (i
== maxeanames
) {
352 printf ("NOTE: More EAs could be available!\n");
358 smbcli_close(cli
->tree
, fnum
);
363 test using NTTRANS CREATE to create a file with an initial EA set
365 static bool test_nttrans_create(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
)
369 const char *fname
= BASEDIR
"\\ea2.txt";
372 struct ea_struct eas
[3];
373 struct smb_ea_list ea_list
;
375 printf("TESTING NTTRANS CREATE WITH EAS\n");
377 io
.generic
.level
= RAW_OPEN_NTTRANS_CREATE
;
378 io
.ntcreatex
.in
.root_fid
= 0;
379 io
.ntcreatex
.in
.flags
= 0;
380 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
381 io
.ntcreatex
.in
.create_options
= 0;
382 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
383 io
.ntcreatex
.in
.share_access
=
384 NTCREATEX_SHARE_ACCESS_READ
|
385 NTCREATEX_SHARE_ACCESS_WRITE
;
386 io
.ntcreatex
.in
.alloc_size
= 0;
387 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
388 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
389 io
.ntcreatex
.in
.security_flags
= 0;
390 io
.ntcreatex
.in
.fname
= fname
;
396 eas
[0].name
.s
= "1st EA";
397 eas
[0].value
= data_blob_string_const("Value One");
400 eas
[1].name
.s
= "2nd EA";
401 eas
[1].value
= data_blob_string_const("Second Value");
404 eas
[2].name
.s
= "and 3rd";
405 eas
[2].value
= data_blob_string_const("final value");
407 io
.ntcreatex
.in
.ea_list
= &ea_list
;
408 io
.ntcreatex
.in
.sec_desc
= NULL
;
410 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
411 CHECK_STATUS(status
, NT_STATUS_OK
);
412 fnum
= io
.ntcreatex
.out
.file
.fnum
;
414 ret
&= check_ea(cli
, fname
, "EAONE", NULL
);
415 ret
&= check_ea(cli
, fname
, "1st EA", "Value One");
416 ret
&= check_ea(cli
, fname
, "2nd EA", "Second Value");
417 ret
&= check_ea(cli
, fname
, "and 3rd", "final value");
419 smbcli_close(cli
->tree
, fnum
);
421 printf("Trying to add EAs on non-create\n");
422 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
423 io
.ntcreatex
.in
.fname
= fname
;
427 eas
[0].name
.s
= "Fourth EA";
428 eas
[0].value
= data_blob_string_const("Value Four");
430 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
431 CHECK_STATUS(status
, NT_STATUS_OK
);
432 fnum
= io
.ntcreatex
.out
.file
.fnum
;
434 ret
&= check_ea(cli
, fname
, "1st EA", "Value One");
435 ret
&= check_ea(cli
, fname
, "2nd EA", "Second Value");
436 ret
&= check_ea(cli
, fname
, "and 3rd", "final value");
437 ret
&= check_ea(cli
, fname
, "Fourth EA", NULL
);
440 smbcli_close(cli
->tree
, fnum
);
445 basic testing of EA calls
447 bool torture_raw_eas(struct torture_context
*torture
, struct smbcli_state
*cli
)
451 if (!torture_setup_dir(cli
, BASEDIR
)) {
455 ret
&= test_eas(cli
, torture
);
456 ret
&= test_nttrans_create(cli
, torture
);
458 smb_raw_exit(cli
->session
);
466 bool torture_max_eas(struct torture_context
*torture
)
468 struct smbcli_state
*cli
;
471 if (!torture_open_connection(&cli
, torture
, 0)) {
475 if (!torture_setup_dir(cli
, BASEDIR
)) {
479 ret
&= test_max_eas(cli
, torture
);
481 smb_raw_exit(cli
->session
);
483 /* in no ea debug case, all files are gone now */
484 smbcli_deltree(cli
->tree
, BASEDIR
);
487 torture_close_connection(cli
);