5fdc7fa813252e2f4189ce0289db792627c3922c
[tridge/dbench.git] / fileio.c
1 /* 
2    dbench version 2
3    Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
4    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
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 "dbench.h"
22
23 #define MAX_FILES 200
24
25 char *server = NULL;
26 extern int sync_open, sync_dirs;
27
28 static struct {
29         char *name;
30         int fd;
31         int handle;
32 } ftable[MAX_FILES];
33
34 static int find_handle(struct child_struct *child, int handle)
35 {
36         int i;
37         for (i=0;i<MAX_FILES;i++) {
38                 if (ftable[i].handle == handle) return i;
39         }
40         printf("(%d) ERROR: handle %d was not found\n", 
41                child->line, handle);
42         exit(1);
43 }
44
45
46 /* Find the directory holding a file, and flush it to disk.  We do
47    this in -S mode after a directory-modifying mode, to simulate the
48    way knfsd tries to flush directories.  MKDIR and similar operations
49    are meant to be synchronous on NFSv2. */
50 static void sync_parent(char *fname)
51 {
52         char *copy_name;
53         int dir_fd;
54         char *slash;
55
56         if (strchr(fname, '/')) {
57                 copy_name = strdup(fname);
58                 slash = strrchr(copy_name, '/');
59                 *slash = '\0';
60         } else {
61                 copy_name = strdup(".");
62         } 
63         
64         dir_fd = open(copy_name, O_RDONLY);
65         if (dir_fd == -1) {
66                 printf("open directory \"%s\" for sync failed: %s\n",
67                        copy_name,
68                        strerror(errno));
69         } else {
70                 if (fdatasync(dir_fd) == -1) {
71                         printf("datasync directory \"%s\" failed: %s\n",
72                                copy_name,
73                                strerror(errno));
74                 }
75                 if (close(dir_fd) == -1) {
76                         printf("close directory failed: %s\n",
77                                strerror(errno));
78                 }
79         }
80         free(copy_name);
81 }
82
83 static void xattr_fd_read_hook(int fd)
84 {
85 #if HAVE_XATTR_SUPPORT
86         extern int xattr_enable;
87         char buf[44];
88         if (xattr_enable) {
89                 memset(buf, 0, sizeof(buf));
90                 fgetxattr(fd, "user.DosAttrib", buf, sizeof(buf));
91         }
92 #else
93         (void)fd;
94 #endif
95 }
96
97 static void xattr_fname_read_hook(const char *fname)
98 {
99 #if HAVE_XATTR_SUPPORT
100         extern int xattr_enable;
101         if (xattr_enable) {
102                 char buf[44];
103                 getxattr(fname, "user.DosAttrib", buf, sizeof(buf));
104         }
105 #else
106         (void)fname;
107 #endif
108 }
109
110 static void xattr_fd_write_hook(int fd)
111 {
112 #if HAVE_XATTR_SUPPORT
113         extern int xattr_enable;
114         if (xattr_enable) {
115                 struct timeval tv;
116                 char buf[44];
117                 memset(buf, 0, sizeof(buf));
118                 fgetxattr(fd, "user.DosAttrib", buf, sizeof(buf));
119                 gettimeofday(&tv, NULL);
120                 memcpy(buf, &tv, sizeof(tv));
121                 if (fsetxattr(fd, "user.DosAttrib", buf, sizeof(buf), 0) != 0) {
122                         printf("fsetxattr failed - %s\n", strerror(errno));
123                         exit(1);
124                 }
125         }
126 #else
127         (void)fd;
128 #endif
129 }
130
131 static int expected_status(const char *status)
132 {
133         if (strcmp(status, "NT_STATUS_OK") == 0) return 0;
134         return -1;
135 }
136
137 /*
138   simulate pvfs_resolve_name()
139 */
140 static void resolve_name(const char *name)
141 {
142         struct stat st;
143         char *dname, *fname;
144         DIR *dir;
145         char *p;
146         struct dirent *d;
147
148         if (stat(name, &st) == 0) {
149                 xattr_fname_read_hook(name);
150                 return;
151         }
152
153         dname = strdup(name);
154         p = strrchr(dname, '/');
155         if (!p) return;
156         *p = 0;
157         fname = p+1;
158
159         dir = opendir(dname);
160         if (!dir) {
161                 free(dname);
162                 return;
163         }
164         while ((d = readdir(dir))) {
165                 if (strcasecmp(fname, d->d_name) == 0) break;
166         }
167         closedir(dir);
168         free(dname);
169 }
170
171 static void failed(struct child_struct *child)
172 {
173         child->failed = 1;
174         printf("ERROR: child %d failed\n", child->id);
175         exit(1);
176 }
177
178 void nb_setup(struct child_struct *child)
179 {
180         (void)child;
181 }
182
183 void nb_unlink(struct child_struct *child, char *fname, int attr, const char *status)
184 {
185         (void)attr;
186
187         resolve_name(fname);
188
189         if (unlink(fname) != expected_status(status)) {
190                 printf("(%d) unlink %s failed (%s) - expected %s\n", 
191                        child->line, fname, strerror(errno), status);
192                 failed(child);
193         }
194         if (sync_dirs) sync_parent(fname);
195 }
196
197 void nb_mkdir(struct child_struct *child, char *dname, const char *status)
198 {
199         (void)child;
200         (void)status;
201         resolve_name(dname);
202         mkdir(dname, 0777);
203 }
204
205 void nb_rmdir(struct child_struct *child, char *fname, const char *status)
206 {
207         resolve_name(fname);
208
209         if (rmdir(fname) != expected_status(status)) {
210                 printf("(%d) rmdir %s failed (%s) - expected %s\n", 
211                        child->line, fname, strerror(errno), status);
212                 failed(child);
213         }
214         if (sync_dirs) sync_parent(fname);
215 }
216
217 void nb_createx(struct child_struct *child, const char *fname, 
218                 uint32_t create_options, uint32_t create_disposition, int fnum,
219                 const char *status)
220 {
221         int fd, i;
222         int flags = O_RDWR;
223         struct stat st;
224
225         resolve_name(fname);
226
227         if (sync_open) flags |= O_SYNC;
228
229         if (create_disposition == FILE_CREATE) {
230                 flags |= O_CREAT;
231         }
232
233         if (create_disposition == FILE_OVERWRITE ||
234             create_disposition == FILE_OVERWRITE_IF) {
235                 flags |= O_CREAT | O_TRUNC;
236         }
237
238         if (create_options & FILE_DIRECTORY_FILE) {
239                 /* not strictly correct, but close enough */
240                 mkdir(fname, 0700);
241         }
242
243         if (create_options & FILE_DIRECTORY_FILE) flags = O_RDONLY|O_DIRECTORY;
244
245         fd = open(fname, flags, 0600);
246         if (fd == -1) {
247                 if (strcmp(status, "NT_STATUS_OK") == 0) {
248                         printf("(%d) open %s failed for handle %d (%s)\n", 
249                                child->line, fname, fnum, strerror(errno));
250                 }
251                 return;
252         }
253         if (strcmp(status, "NT_STATUS_OK") != 0) {
254                 printf("(%d) open %s succeeded for handle %d\n", 
255                        child->line, fname, fnum);
256                 close(fd);
257                 return;
258         }
259         
260         for (i=0;i<MAX_FILES;i++) {
261                 if (ftable[i].handle == 0) break;
262         }
263         if (i == MAX_FILES) {
264                 printf("file table full for %s\n", fname);
265                 exit(1);
266         }
267         ftable[i].name = strdup(fname);
268         ftable[i].handle = fnum;
269         ftable[i].fd = fd;
270
271         fstat(fd, &st);
272
273         if (!S_ISDIR(st.st_mode)) {
274                 xattr_fd_write_hook(fd);
275         }
276 }
277
278 void nb_writex(struct child_struct *child, int handle, int offset, 
279                int size, int ret_size, const char *status)
280 {
281         int i = find_handle(child, handle);
282         void *buf;
283
284         (void)status;
285
286         buf = calloc(size, 1);
287
288         if (pwrite(ftable[i].fd, buf, size, offset) != ret_size) {
289                 printf("write failed on handle %d\n", handle);
290                 exit(1);
291         }
292
293         free(buf);
294
295         child->bytes += size;
296 }
297
298 void nb_readx(struct child_struct *child, int handle, int offset, 
299               int size, int ret_size, const char *status)
300 {
301         int i = find_handle(child, handle);
302         void *buf;
303
304         (void)status;
305
306         buf = malloc(size);
307
308         if (pread(ftable[i].fd, buf, size, offset) != ret_size) {
309                 printf("read failed on handle %d\n", handle);
310         }
311
312         free(buf);
313
314         child->bytes += size;
315 }
316
317 void nb_close(struct child_struct *child, int handle, const char *status)
318 {
319         int i = find_handle(child, handle);
320         (void)status;
321         close(ftable[i].fd);
322         ftable[i].handle = 0;
323         if (ftable[i].name) free(ftable[i].name);
324         ftable[i].name = NULL;
325 }
326
327 void nb_rename(struct child_struct *child, char *old, char *new, const char *status)
328 {
329         resolve_name(old);
330         resolve_name(new);
331
332         if (rename(old, new) != expected_status(status)) {
333                 printf("rename %s %s failed (%s) - expected %s\n", 
334                        old, new, strerror(errno), status);
335                 failed(child);
336         }
337         if (sync_dirs) sync_parent(new);
338 }
339
340 void nb_flush(struct child_struct *child, int handle, const char *status)
341 {
342         (void)status;
343         find_handle(child, handle);
344         /* noop */
345 }
346
347 void nb_qpathinfo(struct child_struct *child, const char *fname, int level, 
348                   const char *status)
349 {
350         (void)child;
351         (void)level;
352         (void)status;
353         resolve_name(fname);
354 }
355
356 void nb_qfileinfo(struct child_struct *child, int handle, int level, const char *status)
357 {
358         struct stat st;
359         int i = find_handle(child, handle);
360         (void)child;
361         (void)level;
362         (void)status;
363         fstat(ftable[i].fd, &st);
364         xattr_fd_read_hook(ftable[i].fd);
365 }
366
367 void nb_qfsinfo(struct child_struct *child, int level, const char *status)
368 {
369         struct statfs st;
370
371         (void)level;
372         (void)status;
373
374         statfs(child->directory, &st);
375 }
376
377 void nb_findfirst(struct child_struct *child, char *fname, int level, int maxcnt, 
378                   int count, const char *status)
379 {
380         DIR *dir;
381         struct dirent *d;
382         char *p;
383
384         (void)child;
385         (void)level;
386         (void)count;
387         (void)status;
388
389         resolve_name(fname);
390
391         if (strpbrk(fname, "<>*?\"") == NULL) {
392                 return;
393         }
394
395         p = strrchr(fname, '/');
396         if (!p) return;
397         *p = 0;
398         dir = opendir(fname);
399         if (!dir) return;
400         while (maxcnt && (d = readdir(dir))) maxcnt--;
401         closedir(dir);
402 }
403
404 void nb_cleanup(struct child_struct *child)
405 {
406         char *dname;
407
408         asprintf(&dname, "%s/clients/client%d", child->directory, child->id);
409         nb_deltree(child, dname);
410         free(dname);
411
412         asprintf(&dname, "%s%s", child->directory, "/clients");
413         rmdir(dname);
414         free(dname);
415 }
416
417 void nb_deltree(struct child_struct *child, char *dname)
418 {
419         char *path;
420         (void)child;
421         asprintf(&path, "/bin/rm -rf %s", dname);
422         system(path);
423         free(path);
424 }
425
426 void nb_sfileinfo(struct child_struct *child, int handle, int level, const char *status)
427 {
428         int i = find_handle(child, handle);
429         struct utimbuf tm;
430         struct stat st;
431         (void)child;
432         (void)handle;
433         (void)level;
434         (void)status;
435         xattr_fd_read_hook(ftable[i].fd);
436
437         fstat(ftable[i].fd, &st);
438
439         tm.actime = st.st_atime - 10;
440         tm.modtime = st.st_mtime - 12;
441
442         utime(ftable[i].name, &tm);
443
444         if (!S_ISDIR(st.st_mode)) {
445                 xattr_fd_write_hook(ftable[i].fd);
446         }
447 }
448
449 void nb_lockx(struct child_struct *child, int handle, uint32_t offset, int size, 
450               const char *status)
451 {
452         int i = find_handle(child, handle);
453         struct flock lock;
454
455         (void)child;
456         (void)status;
457
458         lock.l_type = F_WRLCK;
459         lock.l_whence = SEEK_SET;
460         lock.l_start = offset;
461         lock.l_len = size;
462         lock.l_pid = 0;
463
464         fcntl(ftable[i].fd, F_SETLKW, &lock);
465 }
466
467 void nb_unlockx(struct child_struct *child,
468                 int handle, uint32_t offset, int size, const char *status)
469 {
470         int i = find_handle(child, handle);
471         struct flock lock;
472
473         (void)child;
474         (void)status;
475
476         lock.l_type = F_UNLCK;
477         lock.l_whence = SEEK_SET;
478         lock.l_start = offset;
479         lock.l_len = size;
480         lock.l_pid = 0;
481
482         fcntl(ftable[i].fd, F_SETLKW, &lock);
483 }
484
485 void nb_sleep(struct child_struct *child, int usec, const char *status)
486 {
487         (void)child;
488         (void)usec;
489         (void)status;
490         usleep(usec);
491 }