r3441: some include file cleanups and general housekeeping
[jelmer/samba4-debian.git] / source / torture / torture_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester utility functions
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "libcli/raw/libcliraw.h"
23
24
25 static struct timeval tp1,tp2;
26
27 void start_timer(void)
28 {
29         gettimeofday(&tp1,NULL);
30 }
31
32 double end_timer(void)
33 {
34         gettimeofday(&tp2,NULL);
35         return((tp2.tv_sec - tp1.tv_sec) + 
36                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
37 }
38
39
40 /*
41   create a directory, returning a handle to it
42 */
43 int create_directory_handle(struct smbcli_tree *tree, const char *dname)
44 {
45         NTSTATUS status;
46         union smb_open io;
47         TALLOC_CTX *mem_ctx;
48
49         mem_ctx = talloc_init("create_directory_handle");
50
51         io.generic.level = RAW_OPEN_NTCREATEX;
52         io.ntcreatex.in.root_fid = 0;
53         io.ntcreatex.in.flags = 0;
54         io.ntcreatex.in.access_mask = SA_RIGHT_FILE_ALL_ACCESS;
55         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
56         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
57         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
58         io.ntcreatex.in.alloc_size = 0;
59         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
60         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
61         io.ntcreatex.in.security_flags = 0;
62         io.ntcreatex.in.fname = dname;
63
64         status = smb_raw_open(tree, mem_ctx, &io);
65         if (!NT_STATUS_IS_OK(status)) {
66                 talloc_destroy(mem_ctx);
67                 return -1;
68         }
69
70         talloc_destroy(mem_ctx);
71         return io.ntcreatex.out.fnum;
72 }
73
74 /*
75   sometimes we need a fairly complex file to work with, so we can test
76   all possible attributes. 
77 */
78 int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
79 {
80         int fnum;
81         char buf[7] = "abc";
82         union smb_setfileinfo setfile;
83         union smb_fileinfo fileinfo;
84         time_t t = (time(NULL) & ~1);
85         NTSTATUS status;
86
87         smbcli_unlink(cli->tree, fname);
88         fnum = smbcli_nt_create_full(cli->tree, fname, 0, GENERIC_RIGHTS_FILE_ALL_ACCESS,
89                                   FILE_ATTRIBUTE_NORMAL,
90                                   NTCREATEX_SHARE_ACCESS_DELETE|
91                                   NTCREATEX_SHARE_ACCESS_READ|
92                                   NTCREATEX_SHARE_ACCESS_WRITE, 
93                                   NTCREATEX_DISP_OVERWRITE_IF,
94                                   0, 0);
95         if (fnum == -1) return -1;
96
97         smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
98
99         /* setup some EAs */
100         setfile.generic.level = RAW_SFILEINFO_EA_SET;
101         setfile.generic.file.fnum = fnum;
102         setfile.ea_set.in.ea.flags = 0;
103         setfile.ea_set.in.ea.name.s = "EAONE";
104         setfile.ea_set.in.ea.value = data_blob_talloc(mem_ctx, "VALUE1", 6);
105
106         status = smb_raw_setfileinfo(cli->tree, &setfile);
107         if (!NT_STATUS_IS_OK(status)) {
108                 printf("Failed to setup EAs\n");
109         }
110
111         setfile.ea_set.in.ea.name.s = "SECONDEA";
112         setfile.ea_set.in.ea.value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
113         status = smb_raw_setfileinfo(cli->tree, &setfile);
114         if (!NT_STATUS_IS_OK(status)) {
115                 printf("Failed to setup EAs\n");
116         }
117
118         /* make sure all the timestamps aren't the same, and are also 
119            in different DST zones*/
120         setfile.generic.level = RAW_SFILEINFO_SETATTRE;
121         setfile.generic.file.fnum = fnum;
122
123         setfile.setattre.in.create_time = t + 9*30*24*60*60;
124         setfile.setattre.in.access_time = t + 6*30*24*60*60;
125         setfile.setattre.in.write_time  = t + 3*30*24*60*60;
126
127         status = smb_raw_setfileinfo(cli->tree, &setfile);
128         if (!NT_STATUS_IS_OK(status)) {
129                 printf("Failed to setup file times - %s\n", nt_errstr(status));
130         }
131
132         /* make sure all the timestamps aren't the same */
133         fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
134         fileinfo.generic.in.fnum = fnum;
135
136         status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
137         if (!NT_STATUS_IS_OK(status)) {
138                 printf("Failed to query file times - %s\n", nt_errstr(status));
139         }
140
141         if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
142                 printf("create_time not setup correctly\n");
143         }
144         if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
145                 printf("access_time not setup correctly\n");
146         }
147         if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
148                 printf("write_time not setup correctly\n");
149         }
150
151         return fnum;
152 }
153
154
155
156 /* return a pointer to a anonymous shared memory segment of size "size"
157    which will persist across fork() but will disappear when all processes
158    exit 
159
160    The memory is not zeroed 
161
162    This function uses system5 shared memory. It takes advantage of a property
163    that the memory is not destroyed if it is attached when the id is removed
164    */
165 void *shm_setup(int size)
166 {
167         int shmid;
168         void *ret;
169
170 /* NetBSD doesn't have these */
171 #ifndef SHM_R
172 #define SHM_R 0400
173 #endif
174
175 #ifndef SHM_W
176 #define SHM_W 0200
177 #endif
178
179         shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
180         if (shmid == -1) {
181                 printf("can't get shared memory\n");
182                 exit(1);
183         }
184         ret = (void *)shmat(shmid, 0, 0);
185         if (!ret || ret == (void *)-1) {
186                 printf("can't attach to shared memory\n");
187                 return NULL;
188         }
189         /* the following releases the ipc, but note that this process
190            and all its children will still have access to the memory, its
191            just that the shmid is no longer valid for other shm calls. This
192            means we don't leave behind lots of shm segments after we exit 
193
194            See Stevens "advanced programming in unix env" for details
195            */
196         shmctl(shmid, IPC_RMID, 0);
197         
198         return ret;
199 }
200
201
202 /*
203   check that a wire string matches the flags specified 
204   not 100% accurate, but close enough for testing
205 */
206 BOOL wire_bad_flags(WIRE_STRING *str, int flags, struct smbcli_state *cli)
207 {
208         BOOL server_unicode;
209         int len;
210         if (!str || !str->s) return True;
211         len = strlen(str->s);
212         if (flags & STR_TERMINATE) len++;
213
214         server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
215         if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
216                 server_unicode = False;
217         }
218
219         if ((flags & STR_UNICODE) || server_unicode) {
220                 len *= 2;
221         } else if (flags & STR_TERMINATE_ASCII) {
222                 len++;
223         }
224         if (str->private_length != len) {
225                 printf("Expected wire_length %d but got %d for '%s'\n", 
226                        len, str->private_length, str->s);
227                 return True;
228         }
229         return False;
230 }
231
232 /*
233   check if 2 NTTIMEs are equal
234 */
235 BOOL nt_time_equal(NTTIME *t1, NTTIME *t2)
236 {
237         return *t1 == *t2;
238 }
239
240 /*
241   dump a all_info QFILEINFO structure
242 */
243 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
244 {
245         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
246         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
247         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
248         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
249         d_printf("\tattrib:         0x%x\n", finfo->all_info.out.attrib);
250         d_printf("\talloc_size:     %llu\n", (uint64_t)finfo->all_info.out.alloc_size);
251         d_printf("\tsize:           %llu\n", (uint64_t)finfo->all_info.out.size);
252         d_printf("\tnlink:          %u\n", finfo->all_info.out.nlink);
253         d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
254         d_printf("\tdirectory:      %u\n", finfo->all_info.out.directory);
255         d_printf("\tea_size:        %u\n", finfo->all_info.out.ea_size);
256         d_printf("\tfname:          '%s'\n", finfo->all_info.out.fname.s);
257 }
258
259 /*
260   dump file infor by name
261 */
262 void torture_all_info(struct smbcli_tree *tree, const char *fname)
263 {
264         TALLOC_CTX *mem_ctx = talloc_init("%s", fname);
265         union smb_fileinfo finfo;
266         NTSTATUS status;
267
268         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
269         finfo.generic.in.fname = fname;
270         status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
271         if (!NT_STATUS_IS_OK(status)) {
272                 d_printf("%s - %s\n", fname, nt_errstr(status));
273                 return;
274         }
275
276         d_printf("%s:\n", fname);
277         dump_all_info(mem_ctx, &finfo);
278         talloc_destroy(mem_ctx);
279 }
280
281
282 /*
283   split a UNC name into server and share names
284 */
285 BOOL split_unc_name(const char *unc, char **server, char **share)
286 {
287         char *p = strdup(unc);
288         if (!p) return False;
289         all_string_sub(p, "\\", "/", 0);
290         if (strncmp(p, "//", 2) != 0) return False;
291
292         (*server) = p+2;
293         p = strchr(*server, '/');
294         if (!p) return False;
295
296         *p = 0;
297         (*share) = p+1;
298         
299         return True;
300 }
301
302 /*
303   split a USER%PASS pair into username and password
304 */
305 BOOL split_username(const char *pair, char **user, char **pass)
306 {
307         char *p = strdup(pair);
308         if (!p) return False;
309
310         (*user) = p;
311
312         p = strchr(*user, '%');
313         if (!p) return False;
314
315         *p = 0;
316         (*pass) = p+1;
317         
318         return True;
319 }
320
321 /*
322   set a attribute on a file
323 */
324 BOOL torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
325 {
326         union smb_setfileinfo sfinfo;
327         NTSTATUS status;
328
329         sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
330         sfinfo.generic.file.fname = fname;
331
332         ZERO_STRUCT(sfinfo.basic_info.in);
333         sfinfo.basic_info.in.attrib = attrib;
334         status = smb_raw_setpathinfo(tree, &sfinfo);
335         return NT_STATUS_IS_OK(status);
336 }
337
338
339 /*
340   set a file descriptor as sparse
341 */
342 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
343 {
344         union smb_ioctl nt;
345         NTSTATUS status;
346         TALLOC_CTX *mem_ctx;
347
348         mem_ctx = talloc_init("torture_set_sparse");
349         if (!mem_ctx) {
350                 return NT_STATUS_NO_MEMORY;
351         }
352
353         nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
354         nt.ntioctl.in.function = 0x900c4;
355         nt.ntioctl.in.fnum = fnum;
356         nt.ntioctl.in.fsctl = True;
357         nt.ntioctl.in.filter = 0;
358
359         status = smb_raw_ioctl(tree, mem_ctx, &nt);
360
361         talloc_destroy(mem_ctx);
362
363         return status;
364 }