Windows: Preserve GetLastError during WinTorture testing
[openafs.git] / src / WINNT / tests / torture / Source / nbio.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester
4    Copyright (C) Andrew Tridgell 1997-1998
5    Copyright (C) Richard Sharpe  2002
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "common.h"
24 #include <stdlib.h>
25
26 extern int verbose;
27
28 #define off_t DWORD
29
30 __declspec( thread ) extern int     ProcessNumber;
31 __declspec( thread ) extern int     LineCount;
32 __declspec( thread ) extern int     AfsTrace;
33 __declspec( thread ) extern int     *pThreadStatus;
34 __declspec( thread ) extern int     LogID;
35 __declspec( thread ) extern char    *IoBuffer;
36 __declspec( thread ) extern int     BufferSize;
37 __declspec( thread ) extern char    AfsLocker[256];
38 __declspec( thread ) extern char    OriginalAfsLocker[256];
39 __declspec( thread ) extern char    HostName[256];
40 __declspec( thread ) extern DWORD   TickCount1, TickCount2, MilliTickStart;
41 __declspec( thread ) extern FTABLE  ftable[MAX_FILES];
42 __declspec( thread ) extern struct  cmd_struct ThreadCommandInfo[CMD_MAX_CMD + 1];
43 __declspec( thread ) extern EXIT_STATUS *pExitStatus;
44 __declspec( thread ) extern DWORD   LastKnownError;
45 __declspec( thread ) int EnforcePathInfoErrors = 0;
46
47 extern void LogMessage(int ProcessNumber, char *HostName, char *FileName, char *message, int LogID);
48
49 HANDLE CreateObject(const char *fname, uint32 DesiredAccess,
50                   uint32 FileAttributes, uint32 ShareAccess,
51                   uint32 CreateDisposition, uint32 CreateOptions);
52 void DumpAFSLog(char * HostName, int LogID);
53 int  FindHandle(int handle);
54 int  GetFileList(char *Mask, void (*fn)(file_info *, const char *, void *), void *state);
55 BOOL GetFileInfo(char *FileName, HANDLE fd, uint16 *mode, size_t *size,
56                         time_t *c_time, time_t *a_time, time_t *m_time, 
57                         time_t *w_time);
58 BOOL GetPathInfo(const char *fname, time_t *c_time, time_t *a_time, time_t *m_time, 
59                          size_t *size, uint16 *mode);
60 int  LeaveThread(int status, char *Reason, int cmd);
61 void StartFirstTimer();
62 void EndFirstTimer(int cmd, int Type);
63 void StartSecondTime(int cmd);
64 void EndSecondTime(int cmd);
65 void SubstituteString(char *s,const char *pattern,const char *insert, size_t len);
66 intptr_t  SystemCall(char *command);
67 HANDLE WinFindFirstFile(char *Mask, void **FileData, char *cFileName, int *dwFileAttributes);
68 int  WinFindNextFile(HANDLE hFind, void **FileData, char *cFileName, int *dwFileAttributes);
69
70 int FindHandle(int handle)
71 {
72     int i;
73     for (i=0;i<MAX_FILES;i++)
74     {
75         if (ftable[i].handle == handle)
76             return(i);
77     }
78     if (verbose)
79         printf("(%d) ERROR: handle %d was not found\n", LineCount, handle);
80     return(LeaveThread(1, "", -1));
81 }
82
83 int nb_unlink(char *fname)
84 {
85     int     rc;
86     char    temp[512];
87     char    FileName[128];
88     pstring path;
89     DWORD   gle;
90
91     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
92
93     strcpy(path, AfsLocker);
94     strcat(path, fname);
95
96     StartFirstTimer();
97     rc = DeleteFile(path);
98     gle = GetLastError();
99     EndFirstTimer(CMD_UNLINK, 1);
100     if (!rc)
101     {
102         LeaveThread(0, "", CMD_UNLINK);
103         sprintf(temp, "FILE: DeleteFile %s failed GLE(0x%x)\n", path, gle);
104         if (verbose)
105             printf("%s", temp);
106         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
107         return(-1);
108     }
109
110     return(0);
111 }
112
113 int nb_SetLocker(char *Locker)
114 {
115
116     StartFirstTimer();
117     if (strlen(Locker) == 0)
118         strcpy(AfsLocker, OriginalAfsLocker);
119     else
120         strcpy(AfsLocker, Locker);
121     EndFirstTimer(CMD_SETLOCKER, 1);
122     return(0);
123 }
124
125 int nb_Xrmdir(char *Directory, char *type)
126 {
127     DWORD   rc;
128     char    FileName[128];
129     char    command[256];
130     char    NewDirectory[256];
131     char    temp[512];
132
133     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
134     if (strlen(Directory) == 0)
135     {
136         return(LeaveThread(1, "rmdir failed no path specified\n", CMD_XRMDIR));
137     }
138     strcpy(NewDirectory, Directory);
139     memset(command, '\0', sizeof(command));
140     strcpy(command,"rmdir /Q ");
141     if (!stricmp(type, "all"))
142     {
143         strcat(command, "/S ");
144     }
145     strcat(command, NewDirectory);
146
147     StartFirstTimer();
148     rc = system(command);
149
150     if ((rc) && (rc != 2) && (rc != 3))
151     {
152         EndFirstTimer(CMD_XRMDIR, 0);
153         sprintf(temp, "rmdir failed on %s\n", command);
154         LeaveThread(rc, temp, CMD_XRMDIR);
155         sprintf(temp, "FAILURE: Thread %d - Xrmdir failed on \"%s\"\n", ProcessNumber, command);
156         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
157         return(-1);
158     }
159     EndFirstTimer(CMD_XRMDIR, 1);
160     return(0);
161 }
162
163
164 int nb_Mkdir(char *Directory)
165 {
166     DWORD   rc;
167     char    FileName[128];
168     char    command[256];
169     char    NewDirectory[256];
170     char    temp[512];
171
172     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
173     if (strlen(Directory) == 0)
174     {
175         return(LeaveThread(1, "mkdir failed on no path specified\n", CMD_MKDIR));
176     }
177     strcpy(NewDirectory, Directory);
178     memset(command, '\0', sizeof(command));
179     strcpy(command,"mkdir ");
180     strcat(command, NewDirectory);
181
182     StartFirstTimer();
183     rc = system(command);
184
185     if (rc > 1)
186     {
187         EndFirstTimer(CMD_MKDIR, 0);
188         sprintf(temp,  "mkdir failed on %s\n", command);
189         LeaveThread(rc, temp, CMD_MKDIR);
190         sprintf(temp, "ERROR: Thread %d - mkdir failed on \"%s\"\n", ProcessNumber, command);
191         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
192         return(-1);
193     }
194     EndFirstTimer(CMD_MKDIR, 1);
195     return(0);
196 }
197
198 int nb_Attach(char *Locker, char *Drive)
199 {
200     DWORD   rc;
201     char    FileName[128];
202     char    command[512];
203     char    temp[512];
204
205     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
206     if (strlen(Locker) == 0)
207     {
208         return(LeaveThread(1, "attach failed no locker specified\n", CMD_ATTACH));
209     }
210     memset(command, '\0', sizeof(command));
211     strcpy(command,"attach -q ");
212     rc = 0;
213     if (strlen(Drive) != 0)
214     {
215         sprintf(temp, "-D %s ", Drive);
216         strcat(command, temp);
217     }
218     strcat(command, Locker);
219
220     StartFirstTimer();
221     rc = system(command);
222
223     if (rc)
224     {
225         EndFirstTimer(CMD_ATTACH, 0);
226         sprintf(pExitStatus->Reason, "attach failed on %s\n", command);
227         pExitStatus->ExitStatus = rc;
228         sprintf(temp, "ERROR: Thread %d - attach failed on \"%s\"\n", ProcessNumber, command);
229         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
230     }
231     EndFirstTimer(CMD_ATTACH, 1);
232     return(0);
233 }
234
235 int nb_Detach(char *Name, char *type)
236 {
237     DWORD   rc;
238     char    FileName[128];
239     char    command[512];
240     char    temp[512];
241
242     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
243     memset(command, '\0', sizeof(command));
244     strcpy(command,"detach -q ");
245     rc = 0;
246     if (!stricmp(type, "drive"))
247     {
248         sprintf(temp, "-D %s ", Name);
249         strcat(command, temp);
250     }
251     else if (!stricmp(type, "locker"))
252     {
253         strcat(command, Name);
254     }
255     else
256     {
257         return(LeaveThread(1, "nb_Detach failed unknown type: %s\n", CMD_DETACH));
258     }
259
260     StartFirstTimer();
261     rc = system(command);
262
263     if (rc)
264     {
265         EndFirstTimer(CMD_DETACH, 0);
266         sprintf(temp, "detach failed on %s\n", command);
267         LeaveThread(rc, temp, CMD_DETACH);
268         sprintf(temp, "ERROR: Thread %d - detach failed on \"%s\"\n", ProcessNumber, command);
269         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
270         return(-1);
271     }
272     EndFirstTimer(CMD_DETACH, 1);
273     return(0);
274 }
275
276 int nb_CreateFile(char *path, DWORD size)
277 {
278     char    NewPath[256];
279     char    Buffer[512];
280     char    temp[512];
281     char    FileName[128];
282     HANDLE  fHandle;
283     DWORD   Moved;
284     DWORD   BytesWritten;
285     DWORD   BytesToWrite;
286     BOOL    rc;
287     DWORD   gle;
288
289     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
290     if (strlen(path) == 0)
291     {
292         return(LeaveThread(1, "nb_CreateFile failed no path specified\n", CMD_CREATEFILE));
293     }
294
295     strcpy(NewPath, path);
296
297     StartFirstTimer();
298     fHandle = CreateFile(NewPath, 
299                          GENERIC_READ | GENERIC_WRITE | STANDARD_RIGHTS_ALL,
300                          FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
301                          NULL,
302                          CREATE_ALWAYS,
303                          FILE_ATTRIBUTE_NORMAL,
304                          NULL);
305     gle = GetLastError();
306     if (fHandle == INVALID_HANDLE_VALUE)
307     {
308         EndFirstTimer(CMD_CREATEFILE, 0);
309         sprintf(temp, "Create file failed on \"%s\" GLE(0x%x)\n", NewPath, gle);
310         LeaveThread(0, temp, CMD_CREATEFILE);
311         sprintf(temp, "ERROR: Thread %d - Create file failed on \"%s\" GLE(0x%x)\n", ProcessNumber, NewPath, gle);
312         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
313         return(-1);
314     }
315     EndFirstTimer(CMD_CREATEFILE, 1);
316     Moved = SetFilePointer(fHandle,
317                            size - sizeof(Buffer) <= 0 ? 0 : size - sizeof(Buffer),
318                            NULL,
319                            FILE_BEGIN);
320     memset(Buffer, 'A', sizeof(Buffer));
321     BytesToWrite = sizeof(Buffer);
322     rc = WriteFile(fHandle, Buffer, BytesToWrite, &BytesWritten, NULL);
323
324     FlushFileBuffers(fHandle);
325     CloseHandle(fHandle);
326
327     return(0);
328 }
329
330 int nb_CopyFile(char *Source, char *Destination)
331 {
332     DWORD   rc;
333     char    FileName[128];
334     char    temp[512];
335     char    command[256];
336     char    NewSource[256];
337     char    NewDestination[256];
338
339     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
340     if ((strlen(Source) == 0) || (strlen(Destination) == 0))
341     {
342         return(LeaveThread(1, "nb_CopyFile failed to copy files: either source or destination path not specified\n", CMD_COPYFILES));
343     }
344     strcpy(NewSource, Source);
345     strcpy(NewDestination, Destination);
346
347     memset(command, '\0', sizeof(command));
348     sprintf(command, "copy /V /Y /B %s %s > .\\test\\%s%d", NewSource, NewDestination, HostName, ProcessNumber);
349
350     StartFirstTimer();
351     rc = system(command);
352
353     if (rc)
354     {
355         EndFirstTimer(CMD_COPYFILES, 0);
356         sprintf(temp, "copy failed on \"%s\"\n", command);
357         LeaveThread(rc, temp, CMD_COPYFILES);
358         sprintf(temp, "FAILURE: Thread %d - copy failed on \"%s\"\n", ProcessNumber, command);
359         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
360         if (verbose)
361             printf("%s", temp);
362         return(-1);
363     }
364     EndFirstTimer(CMD_COPYFILES, 1);
365     return(0);
366 }
367
368 int nb_DeleteFile(char *path)
369 {
370     DWORD   rc;
371     char    FileName[128];
372     char    command[256];
373     char    NewPath[256];
374     char    temp[512];
375
376     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
377     if (strlen(path) == 0)
378     {
379         return(LeaveThread(1, "nb_DeleteFile failed to delete files: no path specified\n", CMD_DELETEFILES));
380     }
381     strcpy(NewPath, path);
382
383     memset(command, '\0', sizeof(command));
384     sprintf(command, "del /Q %s", NewPath);
385
386     StartFirstTimer();
387     rc = system(command);
388
389     if (rc)
390     {
391         EndFirstTimer(CMD_DELETEFILES, 0);
392         sprintf(temp, "del failed on \"%s\"\n", NewPath);
393         LeaveThread(rc, temp, CMD_DELETEFILES);
394         sprintf(temp, "ERROR: Thread %d - del failed on \"%s\"\n", ProcessNumber, command);
395         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
396         return(-1);
397     }
398     EndFirstTimer(CMD_DELETEFILES, 1);
399     return(0);
400 }
401
402 int nb_xcopy(char *Source, char *Destination)
403 {
404     intptr_t   rc;
405     char    FileName[128];
406     char    temp[512];
407     char    command[256];
408     char    NewSource[256];
409     char    NewDestination[256];
410
411     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
412     if ((strlen(Source) == 0) || (strlen(Destination) == 0))
413     {
414         return(LeaveThread(1, "nb_xcopy failed to xcopy: either source or destination is missing\n", CMD_XCOPY));
415     }
416     strcpy(NewSource, Source);
417     strcpy(NewDestination, Destination);
418     memset(command, '\0', sizeof(command));
419     sprintf(command, "xcopy /E /I /V /Y /Q %s %s > .\\test\\%s%d", NewSource, NewDestination, HostName, ProcessNumber);
420
421     StartFirstTimer();
422     rc = SystemCall(command);
423
424     if (rc)
425     {
426         EndFirstTimer(CMD_XCOPY, 0);
427         sprintf(temp, "xcopy failed on %s\n", command);
428         LeaveThread((int)rc, temp, CMD_XCOPY);
429         sprintf(temp, "FAIURE: Thread %d - xcopy failed on \"%s\"\n", ProcessNumber, command);
430         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
431         return(-1);
432     }
433     EndFirstTimer(CMD_XCOPY, 1);
434     return(0);
435 }
436
437 int nb_Move(char *Source, char *Destination)
438 {
439     DWORD   rc;
440     char    command[256];
441     char    FileName[128];
442     char    temp[512];
443     char    NewSource[256];
444     char    NewDestination[256];
445
446     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
447     if ((strlen(Source) == 0) || (strlen(Destination) == 0))
448     {
449         return(LeaveThread(1, "nb_Move failed to move: either source or destination is missing\n", CMD_MOVE));
450     }
451     strcpy(NewSource, Source);
452     strcpy(NewDestination, Destination);
453     memset(command, '\0', sizeof(command));
454     sprintf(command, "move /Y %s %s > .\\test\\%s%d", NewSource, NewDestination, HostName, ProcessNumber);
455     StartFirstTimer();
456     rc = system(command);
457
458     if (rc)
459     {
460         EndFirstTimer(CMD_MOVE, 0);
461         sprintf(temp, "move failed on \"%s\"\n", command);
462         LeaveThread(rc, temp, CMD_MOVE);
463         sprintf(temp, "FAILURE: Thread %d - move failed on \"%s\"\n", ProcessNumber, command);
464         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
465         return(-1);
466     }
467     EndFirstTimer(CMD_MOVE, 1);
468     return(0);
469 }
470
471 int nb_createx(char *fname, unsigned create_options, unsigned create_disposition, int handle)
472 {
473     HANDLE  fd;
474     int     i;
475     uint32  desired_access;
476     char    FileName[128];
477     char    temp[512];
478     pstring path;
479
480     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
481
482     strcpy(path, AfsLocker);
483     strcat(path, fname);
484     if (create_options & FILE_DIRECTORY_FILE)
485     {
486         desired_access = FILE_READ_DATA;
487     }
488     else
489     {
490         desired_access = FILE_READ_DATA | FILE_WRITE_DATA;
491     }
492
493     StartFirstTimer();
494     fd = CreateObject(path, 
495                        desired_access,
496                        0x0,
497                        FILE_SHARE_READ|FILE_SHARE_WRITE, 
498                        create_disposition, 
499                        create_options);
500
501     if (fd == INVALID_HANDLE_VALUE && handle != -1)
502     {
503         if (create_options & FILE_DIRECTORY_FILE)
504         {
505             EndFirstTimer(CMD_NTCREATEX, 0);
506             LeaveThread(0, "", CMD_NTCREATEX);
507             sprintf(temp, "Directory: unable to create directory %s\n", path);
508             if (verbose)
509                 printf("%s", temp);
510             LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
511             return(-1);
512         }
513         else
514         {
515             EndFirstTimer(CMD_NTCREATEX, 0);
516             LeaveThread(0, "", CMD_NTCREATEX);
517             sprintf(temp, "File: unable to create file %s\n", path);
518             if (verbose)
519                 printf("%s", temp);
520             LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
521             return(-1);
522         }
523     }
524
525     EndFirstTimer(CMD_NTCREATEX, 1);
526
527     if (fd != INVALID_HANDLE_VALUE && handle == -1)
528     {
529         CloseHandle(fd);
530         nb_unlink(fname);
531         return(0);
532     }
533
534     if (fd == INVALID_HANDLE_VALUE && handle == -1)
535         return(0);
536
537     for (i = 0; i < MAX_FILES; i++) 
538     {
539         if (ftable[i].handle == 0) 
540             break;
541     }
542     if (i == MAX_FILES) 
543     {
544         printf("(%d) file table full for %s\n", LineCount, path);
545         return(LeaveThread(1, "file table is full\n", CMD_NTCREATEX));
546     }
547     ftable[i].handle = handle;
548     ftable[i].fd = fd;
549     if (ftable[i].name) 
550         free(ftable[i].name);
551     ftable[i].name = strdup(path);
552     ftable[i].reads = ftable[i].writes = 0;
553     return(0);
554 }
555
556 int nb_writex(int handle, int offset, int size, int ret_size)
557 {
558     int     i;
559     ssize_t status;
560     char    FileName[128];
561     char    temp[512];
562     unsigned char magic = (unsigned char)getpid();
563
564     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
565
566     if (IoBuffer[0] != magic ||
567         IoBuffer[1] != magic ||
568         IoBuffer[2] != magic ||
569         IoBuffer[3] != magic)
570         memset(IoBuffer, magic, BufferSize);
571
572     if ((i = FindHandle(handle)) == -1)
573         return(-1);
574     StartFirstTimer();
575     status = nb_write(ftable[i].fd, IoBuffer, offset, size);
576     if (status != ret_size) 
577     {
578         EndFirstTimer(CMD_WRITEX, 0);
579                 LeaveThread(0, "", CMD_WRITEX);
580         if (status == 0)
581             sprintf(temp, "File: %s. wrote %d bytes, got %d bytes\n", ftable[i].name, size, status);
582         if (status == -1)
583             sprintf(temp, "File: %s. On write, cannot set file pointer\n", ftable[i].name);
584         if (verbose)
585             printf("%s", temp);
586         nb_close(handle);
587         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
588         return(-1);
589         }
590     EndFirstTimer(CMD_WRITEX, 1);
591
592     ftable[i].writes++;
593     return(0);
594 }
595
596 int nb_lock(int handle, int offset, int size, int timeout, unsigned char locktype, NTSTATUS exp)
597 {
598 /*
599     int         i;
600     NTSTATUS    ret;
601     char        FileName[128];
602     char        temp[512];
603
604     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
605
606     if ((i = FindHandle(handle)) == -1)
607     {
608         LeaveThread(0, "", CMD_LOCKINGX);
609         sprintf(temp, "File unlock: Cannot find handle for %s", ftable[i].name);
610         if (verbose)
611             printf("%s", temp);
612         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
613         return(-1);
614     }
615
616     StartFirstTimer();
617     ret = cli_locktype(c, i, offset, size, timeout, locktype);
618
619     if (ret != exp)
620     {
621         EndFirstTimer(CMD_LOCKINGX, 0);
622         LeaveThread(0, "", CMD_LOCKINGX);
623         sprintf(temp, "(%d) ERROR: lock failed on handle %d ofs=%d size=%d timeout= %d exp=%d fd %d errno %d (%s)\n",
624                LineCount, handle, offset, size, timeout, exp, ftable[i].fd, exp, "");
625         sprintf(temp, "File unlock: lock failed %s", ftable[i].name);
626         if (verbose)
627             printf("%s", temp);
628         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
629         return(-1);
630     }
631     EndFirstTimer(CMD_LOCKINGX, 1);
632 */
633     return(0);
634 }
635
636 int nb_readx(int handle, int offset, int size, int ret_size)
637 {
638     int     i;
639     ssize_t ret;
640     char    FileName[128];
641     char    temp[512];
642     DWORD   gle;
643
644     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
645
646     if ((i = FindHandle(handle)) == -1)
647         return(-1);
648
649     StartFirstTimer();
650     ret = nb_read(ftable[i].fd, IoBuffer, offset, size);
651     gle = GetLastError();
652     if ((ret != size) && (ret != ret_size))
653     {
654         EndFirstTimer(CMD_READX, 0);
655         LeaveThread(0, "", CMD_READX);
656         if (ret == 0)
657             sprintf(temp, "File: read failed on index=%d, offset=%d ReadSize=%d ActualRead=%d handle=%p GLE(0x%x)\n",
658                     handle, offset, size, ret, ftable[i].fd, gle);
659         if (ret == -1)
660             sprintf(temp, "File: %s. On read, cannot set file pointer GLE(0x%x)\n", ftable[i].name, gle);
661         if (verbose)
662             printf("%s", temp);
663         nb_close(handle);
664         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
665         return(-1);
666     }
667     EndFirstTimer(CMD_READX, 1);
668     ftable[i].reads++;
669     return(0);
670 }
671
672 int nb_close(int handle)
673 {
674     int     i;
675     int     ret;
676     char    FileName[128];
677     char    temp[512];
678
679     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
680
681     if ((i = FindHandle(handle)) == -1)
682         return(0);
683
684     StartFirstTimer();
685     ret = nb_close1(ftable[i].fd); 
686     EndFirstTimer(CMD_CLOSE, ret);
687     if (!ret) 
688     {
689         LeaveThread(0, "", CMD_CLOSE);
690         sprintf(temp, "(%d) close failed on handle %d\n", LineCount, handle);
691         if (verbose)
692             printf("%s", temp);
693         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
694         return(-1);
695     }
696
697     ftable[i].handle = 0;
698     ftable[i].fd = 0;
699     if (ftable[i].name) 
700         free(ftable[i].name);
701     ftable[i].name = NULL;
702     return(0);   
703 }
704
705 int nb_rmdir(char *fname)
706 {
707     int     rc;
708     pstring path;
709     char    FileName[128];
710     char    temp[512];
711     DWORD   gle;
712
713     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
714
715     strcpy(path, AfsLocker);
716     strcat(path, fname);
717
718     StartFirstTimer();
719     rc = RemoveDirectory(path);
720     gle = GetLastError();
721     EndFirstTimer(CMD_RMDIR, rc);
722
723     if (!rc)
724     {
725         LeaveThread(0, "", CMD_RMDIR);
726         sprintf(temp, "Directory: RemoveDirectory %s failed GLE(0x%x)\n", fname, gle);
727         if (verbose)
728             printf("%s", temp);
729         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
730         return(-1);
731     }
732     return(0);
733 }
734
735 int nb_rename(char *old, char *New)
736 {
737     int     rc;
738     pstring opath;
739     pstring npath;
740     char    FileName[128];
741     char    temp[512];
742     DWORD   gle;
743
744     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
745
746     strcpy(opath, AfsLocker);
747     strcat(opath, old);
748     strcpy(npath, AfsLocker);
749     strcat(npath, New); 
750
751     StartFirstTimer();
752     rc = MoveFileEx(opath, npath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
753     gle = GetLastError();
754     EndFirstTimer(CMD_RENAME, rc);
755
756     if (!rc)
757     {
758         LeaveThread(0, "", CMD_RENAME);
759         sprintf(temp, "File: rename %s %s failed GLE(0x%x)\n", old, New, gle);
760         if (verbose)
761             printf("%s", temp);
762         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
763         return(-1);
764     }
765     return(0);
766 }
767
768 /* 
769  * Type is used to determine whether the file is expected 
770  * to exist or not.  It is overloaded (temporarily) to control
771  * Flag which indicates whether an error is treated as an error
772  * or not.  The StreamFiles.txt script does not have the Type
773  * parameter set correctly for all 120,000+ lines.  As a result
774  * it is not possible to enforce the presence test throughout
775  * the entire script.
776  */
777 int nb_qpathinfo(char *fname, int Type)
778 {
779     pstring path;
780     int     rc;
781     char    FileName[128];
782     char    temp[512];
783     DWORD   gle = 0;
784
785     if (Type == 1111) {
786         EnforcePathInfoErrors = 1;
787         Type = 1;
788     } else if (Type == 1001) {
789         EnforcePathInfoErrors = 0;
790         Type = 1;
791     } else if (Type == 1000) {
792         EnforcePathInfoErrors = 0;
793         Type = 0;
794     } else if (Type == 1110) {
795         EnforcePathInfoErrors = 1;
796         Type = 0;
797     }
798
799     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
800
801     strcpy(path, AfsLocker);
802     strcat(path, fname);
803
804     StartFirstTimer();
805     rc = GetPathInfo(path, NULL, NULL, NULL, NULL, NULL);
806     if (rc == 0)
807         gle = GetLastError();
808     if (strstr(fname, "~TS"))
809     {
810         if (rc == 0)
811             rc = 1;
812         else
813             rc = 0;
814     }
815
816     if (!EnforcePathInfoErrors)
817     {
818         if (Type)
819         {
820             if (rc)
821                 rc = 0;
822             else
823                 rc = 1;
824         }
825         if (!rc)
826         {
827             EndFirstTimer(CMD_QUERY_PATH_INFO, 0);
828             LeaveThread(0, "", CMD_QUERY_PATH_INFO);
829             sprintf(temp, "File: qpathinfo failed for %s type %d GLE(0x%x)\n", path, Type, gle);
830             if (verbose)
831                 printf("%s", temp);
832             LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
833             return(-1);
834         }
835     }
836     EndFirstTimer(CMD_QUERY_PATH_INFO, 1);
837     return(0);
838 }
839
840 int nb_qfileinfo(int handle)
841 {
842     int     i;
843     int     rc;
844     char    FileName[128];
845     char    temp[512];
846     DWORD   gle;
847
848     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
849
850     if ((i = FindHandle(handle)) == -1)
851         return(-1);
852
853     StartFirstTimer();
854     rc = GetFileInfo(ftable[i].name, ftable[i].fd, NULL, NULL, NULL, NULL, NULL, NULL);
855     gle = GetLastError();
856     if (!rc)
857     {
858         EndFirstTimer(CMD_QUERY_FILE_INFO, 0);
859         LeaveThread(0, "", CMD_QUERY_FILE_INFO);
860         sprintf(temp, "File: qfileinfo failed for %s GLE(0x%x)\n", ftable[i].name, gle);
861         if (verbose)
862             printf("%s", temp);
863         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
864         return(-1);
865     }
866     EndFirstTimer(CMD_QUERY_FILE_INFO, 1);
867
868     return(0);
869 }
870
871 int nb_qfsinfo(int level)
872 {
873
874 //      int     bsize;
875 //    int     total;
876 //    int     avail;
877     int     rc;
878     char    FileName[128];
879     char    temp[512];
880     char    Path[512];
881     ULARGE_INTEGER FreeBytesAvailable;
882     ULARGE_INTEGER TotalNumberOfBytes;
883     ULARGE_INTEGER TotalNumberOfFreeBytes;
884     DWORD   gle;
885  
886     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
887     sprintf(Path, "%s\\%s%05d", AfsLocker, HostName, LogID);
888
889     StartFirstTimer();
890     rc = GetDiskFreeSpaceEx(Path, &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes);
891 //    rc = cli_dskattr(c, &bsize, &total, &avail);
892     gle = GetLastError();
893
894     if (!rc)
895     {
896         EndFirstTimer(CMD_QUERY_FS_INFO, 0);
897         LeaveThread(0, "", CMD_QUERY_FS_INFO);
898         sprintf(temp, "File: Disk free space failed GLE(0x%x)\n", gle);
899         if (verbose)
900             printf("%s", temp);
901         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
902         return(-1);
903     }
904     EndFirstTimer(CMD_QUERY_FS_INFO, 1);
905
906     return(0);
907 }
908
909 void find_fn(file_info *finfo, char *name, void *state)
910 {
911         /* noop */
912 }
913
914 int nb_findfirst(char *mask)
915 {
916     int     rc;
917     char    FileName[128];
918     char    NewMask[512];
919     char    temp[512];
920
921     if (strstr(mask, "<.JNK"))
922         return(0);
923
924     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
925
926     strcpy(NewMask, AfsLocker);
927     strcat(NewMask, mask);
928
929     StartFirstTimer();
930     rc = GetFileList(NewMask, (void *)find_fn, NULL);
931
932     if (!rc)
933     {
934         EndFirstTimer(CMD_FIND_FIRST, 0);
935         sprintf(temp, "File: findfirst cannot find for %s\n", mask);
936         if (verbose)
937             printf("%s", temp);
938         LeaveThread(1, temp, CMD_FIND_FIRST);
939         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
940         return(-1);
941     }
942     EndFirstTimer(CMD_FIND_FIRST, 1);
943     return(0);
944 }
945
946 int nb_flush(int handle)
947 {
948     int i;
949
950     if ((i = FindHandle(handle)) == -1)
951         return(-1);
952
953     FlushFileBuffers(ftable[i].fd);
954     return(0);
955 }
956
957 static int total_deleted;
958
959 void delete_fn(file_info *finfo, const char *name, void *state)
960 {
961     int     rc;
962     char    temp[512];
963     char    s[1024];
964     char    FileName[128];
965     DWORD   gle;
966
967     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
968
969     if (finfo->mode & aDIR) 
970     {
971         char s2[1024];
972         sprintf(s2, "%s\\*", name);
973         GetFileList(s2, delete_fn, NULL);
974         sprintf(s, "%s", &name[strlen(AfsLocker)]);
975         nb_rmdir(s);
976     }
977     else
978     {
979         rc = DeleteFile(name);
980         gle = GetLastError();
981         if (!rc)
982         {
983             LeaveThread(0, "", CMD_UNLINK);
984             sprintf(temp, "FILE: DeleteFile %s failed GLE(0x%x)\n", name, gle);
985             if (verbose)
986                 printf("%s", temp);
987             LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
988             return;
989         }
990     }
991     return;
992 }
993
994 int nb_deltree(char *dname)
995 {
996     int     rc;
997     char    mask[1024];
998     pstring path;
999     DWORD   gle;
1000
1001     strcpy(path, AfsLocker);
1002     strcat(path, dname);
1003     sprintf(mask, "%s\\*", path);
1004
1005     total_deleted = 0;
1006
1007     StartFirstTimer();
1008     GetFileList(mask, delete_fn, NULL);
1009
1010 //    pstrcpy(path, AfsLocker);
1011 //    pstrcat(path, dname);
1012     rc = RemoveDirectory(path);
1013     gle = GetLastError();
1014     EndFirstTimer(CMD_DELTREE, rc);
1015     if (!rc)
1016     {
1017         char FileName[256];
1018         char temp[512];
1019
1020         if ((gle != ERROR_FILE_NOT_FOUND) && (gle != ERROR_PATH_NOT_FOUND))
1021         {
1022             LeaveThread(0, "", CMD_DELTREE);
1023             sprintf(FileName, "Thread_%05d.log", ProcessNumber);
1024             sprintf(temp, "ERROR: Thread %d - Unable to remove %s.\n", ProcessNumber, path);
1025             LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
1026             SetLastError(gle);
1027             if (verbose)
1028                 printf(temp);
1029             return(-1);
1030         }
1031     }
1032     return(0);
1033 }
1034
1035
1036 int nb_cleanup(char *cname)
1037 {
1038     char temp[256];
1039
1040     strcpy(temp, "\\clients\\client1");
1041     SubstituteString(temp, "client1", cname, sizeof(temp));
1042     SubstituteString(temp, "clients", HostName, sizeof(temp));
1043     nb_deltree(temp);
1044     return(0);
1045 }
1046
1047 int LeaveThread(int status, char *Reason, int cmd)
1048 {
1049     char    FileName[256];
1050     char    temp[512];
1051     DWORD   rc;
1052
1053     if (cmd != -1)
1054         ++ThreadCommandInfo[cmd].ErrorCount;
1055
1056     if (strlen(Reason) == 0)
1057     {
1058         if (status == 0)
1059             rc = GetLastError();
1060         else
1061             rc = status;
1062         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1063                       NULL,
1064                       rc,
1065                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1066                       pExitStatus->Reason,
1067                       sizeof(pExitStatus->Reason),
1068                       NULL);
1069         LastKnownError = rc;
1070     }
1071     else
1072         strcpy(pExitStatus->Reason, Reason);
1073
1074     if (strlen(pExitStatus->Reason) == 0)
1075         strcpy(pExitStatus->Reason, "\n");
1076     if (pExitStatus->Reason[strlen(pExitStatus->Reason) - 1] != '\n')
1077         strcat(pExitStatus->Reason, "\n");
1078     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
1079     if (strlen(Reason) == 0)
1080         sprintf(temp, "ERROR(%d): Thread %d - (%d) %s", LineCount, ProcessNumber, rc, pExitStatus->Reason);
1081     else
1082         sprintf(temp, "ERROR(%d): Thread %d - %s", LineCount, ProcessNumber, pExitStatus->Reason);
1083     LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
1084     if (verbose)
1085         printf("%s", temp);
1086     pExitStatus->ExitStatus = status;
1087     if (AfsTrace)
1088         DumpAFSLog(HostName, LogID);
1089     (*pThreadStatus) = 0;
1090     return(-1);
1091 }
1092
1093 void StartFirstTimer(void)
1094 {
1095
1096     EndSecondTime(CMD_NONAFS);
1097     TickCount1 = GetTickCount();
1098 }
1099
1100 void EndFirstTimer(int cmd, int Type)
1101 {
1102     DWORD   MilliTick;
1103     DWORD   cmd_time;
1104
1105     ThreadCommandInfo[cmd].count++;
1106     cmd_time = 0;
1107     MilliTick = GetTickCount() - TickCount1;
1108     if (MilliTick <= 0)
1109     {
1110         StartSecondTime(CMD_NONAFS);
1111         return;
1112     }
1113
1114     ThreadCommandInfo[cmd].MilliSeconds += MilliTick;
1115     while (ThreadCommandInfo[cmd].MilliSeconds > 1000)
1116     {
1117         ThreadCommandInfo[cmd].MilliSeconds -= 1000;
1118         cmd_time += 1;
1119     }
1120
1121     if (cmd_time == 0)
1122     {
1123         ThreadCommandInfo[cmd].min_sec = cmd_time;
1124         StartSecondTime(CMD_NONAFS);
1125         return;
1126     }
1127
1128     if (!Type)
1129         ThreadCommandInfo[cmd].ErrorTime += cmd_time;
1130     else
1131     {
1132         ThreadCommandInfo[cmd].total_sec += cmd_time;
1133         if (cmd_time < (int)ThreadCommandInfo[cmd].min_sec)
1134             ThreadCommandInfo[cmd].min_sec = cmd_time;
1135         if ((int)ThreadCommandInfo[cmd].max_sec < cmd_time)
1136             ThreadCommandInfo[cmd].max_sec = cmd_time;
1137     }
1138
1139     StartSecondTime(CMD_NONAFS);
1140 }
1141
1142 void StartSecondTime(int cmd)
1143 {
1144
1145     TickCount2 = GetTickCount();
1146
1147 }
1148
1149 void EndSecondTime(int cmd)
1150 {
1151     DWORD   MilliTick;
1152     DWORD   cmd_time;
1153
1154     ThreadCommandInfo[cmd].count++;
1155     cmd_time = 0;
1156     MilliTick = GetTickCount() - TickCount2;
1157
1158     if (MilliTick <= 0)
1159         return;
1160
1161     ThreadCommandInfo[cmd].MilliSeconds += MilliTick;
1162     while (ThreadCommandInfo[cmd].MilliSeconds > 1000)
1163     {
1164         ThreadCommandInfo[cmd].MilliSeconds -= 1000;
1165         cmd_time += 1;
1166     }
1167     if (cmd_time == 0)
1168     {
1169         ThreadCommandInfo[cmd].min_sec = cmd_time;
1170         return;
1171     }
1172     if (cmd_time < (int)ThreadCommandInfo[cmd].min_sec)
1173         ThreadCommandInfo[cmd].min_sec = cmd_time;
1174     if ((int)ThreadCommandInfo[cmd].max_sec < cmd_time)
1175         ThreadCommandInfo[cmd].max_sec = cmd_time;
1176     ThreadCommandInfo[cmd].total_sec += cmd_time;
1177 }
1178
1179
1180 intptr_t SystemCall(char *command)
1181 {
1182     intptr_t rc;
1183     char    *argv[6];
1184
1185     argv[0] = getenv("COMSPEC");
1186     argv[1] = "/q";
1187     argv[2] = "/c";
1188     argv[3] = (char *)command;
1189     argv[4] = NULL;
1190
1191     rc = spawnve(_P_WAIT,argv[0],argv,NULL);
1192 // != -1 || (errno != ENOENT && errno != EACCES))
1193     return(rc);
1194 }
1195
1196 HANDLE CreateObject(const char *fname, uint32 DesiredAccess,
1197                  uint32 FileAttributes, uint32 ShareAccess,
1198                  uint32 CreateDisposition, uint32 CreateOptions)
1199 {
1200     HANDLE   fd;
1201     DWORD dwCreateDisposition = 0;
1202     DWORD dwDesiredAccess = 0;
1203     DWORD dwShareAccess = 0;
1204     DWORD dwFlags = 0;
1205
1206     if (CreateOptions & FILE_DIRECTORY_FILE)
1207     {
1208         DWORD rc;
1209
1210         if (!CreateDirectory(fname, NULL) && (rc = GetLastError()) != ERROR_ALREADY_EXISTS) 
1211         {
1212             SetLastError(rc);
1213             fd = INVALID_HANDLE_VALUE;
1214         }
1215         else
1216         {
1217             fd = CreateFile(fname, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1218         }
1219     }
1220     else
1221     {
1222         dwDesiredAccess = 0;
1223         if (DesiredAccess & FILE_READ_DATA)
1224             dwDesiredAccess |= GENERIC_READ;
1225         if (DesiredAccess & FILE_WRITE_DATA)
1226             dwDesiredAccess |= GENERIC_WRITE;
1227         dwShareAccess = ShareAccess;
1228         dwShareAccess |= FILE_SHARE_DELETE;
1229         dwCreateDisposition = OPEN_ALWAYS;
1230         if (CreateDisposition == 1)
1231             dwCreateDisposition = OPEN_EXISTING;
1232         fd = CreateFile(fname, dwDesiredAccess, ShareAccess, NULL, dwCreateDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
1233     }
1234
1235     return(fd);
1236 }
1237
1238 BOOL nb_close1(HANDLE fd)
1239 {
1240     int dwFlags = 0;
1241     int rc = 1;
1242
1243     if (fd != INVALID_HANDLE_VALUE)
1244     {
1245         if (rc = GetHandleInformation(fd, &dwFlags))
1246             CloseHandle(fd);
1247     }
1248     return(rc);
1249 }
1250
1251 /****************************************************************************
1252   do a directory listing, calling fn on each file found
1253   this uses the old SMBsearch interface. It is needed for testing Samba,
1254   but should otherwise not be used
1255   ****************************************************************************/
1256 int nb_list_old(const char *Mask, void (*fn)(file_info *, const char *, void *), void *state)
1257 {
1258     int     num_received = 0;
1259     pstring mask;
1260     char    temp[512];
1261     char    cFileName[1024];
1262     int     dwFileAttributes;
1263     HANDLE  hFind;
1264     void    *FileData;
1265
1266     strcpy(mask,Mask);
1267
1268
1269     if (!strcmp(&mask[strlen(mask)-2], "\"*"))
1270     {
1271         strcpy(&mask[strlen(mask)-2], "*");
1272     }
1273     FileData = NULL;
1274     dwFileAttributes = 0;
1275     memset(cFileName, '\0', sizeof(cFileName));
1276     hFind = WinFindFirstFile(mask, &FileData, cFileName, &dwFileAttributes);
1277     if (hFind == INVALID_HANDLE_VALUE)
1278     {
1279         return(0);
1280     }
1281     mask[strlen(mask) - 1] = '\0';
1282     while (1)
1283     {
1284         if (cFileName[0] != '.')
1285         {
1286             file_info finfo;
1287
1288             memset(&finfo, '\0', sizeof(finfo));
1289             if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1290                 finfo.mode = aDIR;
1291             strcpy(finfo.name, cFileName);
1292             sprintf(temp, "%s%s", mask, cFileName);
1293                 fn(&finfo, temp, state);
1294             ++num_received;
1295         }
1296         memset(cFileName, '\0', sizeof(cFileName));
1297         dwFileAttributes = 0;
1298         if (!WinFindNextFile(hFind, &FileData, cFileName, &dwFileAttributes))
1299             break;
1300     }
1301     FindClose(hFind);
1302     return(num_received);
1303 }
1304
1305
1306 /****************************************************************************
1307   do a directory listing, calling fn on each file found
1308   this auto-switches between old and new style
1309   ****************************************************************************/
1310 int GetFileList(char *Mask, void (*fn)(file_info *, const char *, void *), void *state)
1311 {
1312     return(nb_list_old(Mask, fn, state));
1313 }
1314
1315 HANDLE WinFindFirstFile(char *Mask, void **FileData, char *cFileName, int *dwFileAttributes)
1316 {
1317     HANDLE  rc;
1318     static WIN32_FIND_DATAW FileDataW;
1319     static WIN32_FIND_DATAA FileDataA;
1320
1321     memset(&FileDataA, '\0', sizeof(FileDataA));
1322     rc = FindFirstFile(Mask, &FileDataA);
1323     if (rc != INVALID_HANDLE_VALUE)
1324     {
1325         (*FileData) = (void *)&FileDataA;
1326         (*dwFileAttributes) = FileDataA.dwFileAttributes;
1327         strcpy(cFileName, FileDataA.cFileName);
1328     }
1329
1330     return(rc);
1331 }
1332
1333 int WinFindNextFile(HANDLE hFind, void **FileData, char *cFileName, int *dwFileAttributes)
1334 {
1335     int     rc;
1336     WIN32_FIND_DATAA *FileDataA;
1337
1338     FileDataA = (WIN32_FIND_DATAA *)(*FileData);
1339     if (!(rc = FindNextFile(hFind, FileDataA)))
1340     {
1341         return(rc);
1342     }
1343     (*dwFileAttributes) = FileDataA->dwFileAttributes;
1344     strcpy(cFileName, FileDataA->cFileName);
1345
1346     return(rc);
1347 }
1348
1349 void SubstituteString(char *s,const char *pattern,const char *insert, size_t len)
1350 {
1351     char *p;
1352     ssize_t ls,lp,li;
1353
1354     if (!insert || !pattern || !s) return;
1355
1356     ls = (ssize_t)strlen(s);
1357     lp = (ssize_t)strlen(pattern);
1358     li = (ssize_t)strlen(insert);
1359
1360     if (!*pattern) return;
1361         
1362     while (lp <= ls && (p = strstr(s,pattern)))
1363     {
1364         if (len && (ls + (li-lp) >= (int)len)) 
1365         {
1366             break;
1367         }
1368         if (li != lp) 
1369         {
1370             memmove(p+li,p+lp,strlen(p+lp)+1);
1371         }
1372         memcpy(p, insert, li);
1373         s = p + li;
1374         ls += (li-lp);
1375     }
1376 }
1377
1378 #define CHANGE_TIME(A,B) \
1379 B.tm_hour = A.wHour; \
1380 B.tm_sec = A.wSecond; \
1381 B.tm_min = A.wMinute; \
1382 B.tm_mon = A.wMonth - 1; \
1383 B.tm_yday = 0; \
1384 B.tm_year = A.wYear - 1900; \
1385 B.tm_wday = A.wDayOfWeek - 1; \
1386 B.tm_isdst = -1; \
1387 B.tm_mday = A.wDay;
1388
1389
1390 BOOL GetPathInfo(const char *fname, 
1391                    time_t *c_time, time_t *a_time, time_t *m_time, 
1392                    size_t *size, uint16 *mode)
1393 {
1394     WIN32_FILE_ATTRIBUTE_DATA FileInfo;
1395     int         rc;
1396     SYSTEMTIME  SystemTime;
1397     struct tm   tm_time;
1398
1399     rc = GetFileAttributesEx(fname, GetFileExInfoStandard, &FileInfo);
1400     if (rc != 0)
1401     {
1402         if (c_time)
1403         {
1404             rc = FileTimeToSystemTime(&FileInfo.ftCreationTime, &SystemTime);
1405             CHANGE_TIME(SystemTime, tm_time)
1406             (*c_time) = mktime(&tm_time);
1407         }
1408         if (a_time)
1409         {
1410             rc = FileTimeToSystemTime(&FileInfo.ftLastAccessTime, &SystemTime);
1411             CHANGE_TIME(SystemTime, tm_time)
1412             (*a_time) = mktime(&tm_time);
1413         }
1414         if (m_time)
1415         {
1416             rc = FileTimeToSystemTime(&FileInfo.ftLastWriteTime, &SystemTime);
1417             CHANGE_TIME(SystemTime, tm_time)
1418             (*m_time) = mktime(&tm_time);
1419         }
1420         if (size) 
1421         {
1422             rc = 1;
1423             if (!(FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1424                 *size = FileInfo.nFileSizeLow;
1425         }
1426         if (mode)
1427         {
1428             rc = 1;
1429             (*mode) = 0;
1430         }
1431     }
1432     return(rc);
1433 }
1434
1435 /****************************************************************************
1436 send a qfileinfo call
1437 ****************************************************************************/
1438 BOOL GetFileInfo(char *FileName, HANDLE fd, 
1439                    uint16 *mode, size_t *size,
1440                    time_t *c_time, time_t *a_time, time_t *m_time, 
1441                    time_t *w_time)
1442 {
1443     WIN32_FILE_ATTRIBUTE_DATA FileInfo;
1444     int         rc;
1445     SYSTEMTIME  SystemTime;
1446     struct tm   tm_time;
1447
1448     rc = GetFileAttributesEx(FileName, GetFileExInfoStandard, &FileInfo);
1449     if (rc != 0)
1450     {
1451         if (c_time)
1452         {
1453             rc = FileTimeToSystemTime(&FileInfo.ftCreationTime, &SystemTime);
1454             CHANGE_TIME(SystemTime, tm_time)
1455             (*c_time) = mktime(&tm_time);
1456         }
1457         if (a_time)
1458         {
1459             rc = FileTimeToSystemTime(&FileInfo.ftLastAccessTime, &SystemTime);
1460             CHANGE_TIME(SystemTime, tm_time)
1461             (*a_time) = mktime(&tm_time);
1462         }
1463         if (m_time)
1464         {
1465             rc = FileTimeToSystemTime(&FileInfo.ftLastWriteTime, &SystemTime);
1466             CHANGE_TIME(SystemTime, tm_time)
1467             (*m_time) = mktime(&tm_time);
1468         }
1469         if (size) 
1470         {
1471             rc = 0;
1472             if (!(FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1473                *size = FileInfo.nFileSizeLow;
1474             }
1475             if (mode)
1476         {
1477             rc = 0;
1478             (*mode) = 0;
1479         }
1480     }
1481     return(rc);
1482 }
1483
1484 /****************************************************************************
1485   Read size bytes at offset offset using SMBreadX.
1486 ****************************************************************************/
1487
1488 ssize_t nb_read(HANDLE fd, char *IoBuffer, off_t offset, size_t size)
1489 {
1490     DWORD   total = 0;
1491     int     rc;
1492     DWORD   LowDword;
1493
1494     if (size == 0) 
1495         return(0);
1496
1497     LowDword = SetFilePointer(fd, offset, 0, FILE_BEGIN);
1498
1499     if (LowDword == INVALID_SET_FILE_POINTER)
1500         return(-1);
1501     rc = ReadFile(fd, IoBuffer, (DWORD)size, &total, NULL);
1502     if (!rc)
1503         return(rc);
1504
1505     return(total);
1506 }
1507
1508 /****************************************************************************
1509   write to a file
1510 ****************************************************************************/
1511
1512 ssize_t nb_write(HANDLE fd, char *IoBuffer, off_t offset, size_t size)
1513 {
1514     DWORD   bwritten = 0;
1515     int     rc;
1516     DWORD   LowDword;
1517
1518     LowDword = SetFilePointer(fd, offset, 0, FILE_BEGIN);
1519     if (LowDword == INVALID_SET_FILE_POINTER)
1520         return(-1);
1521     rc = WriteFile(fd, IoBuffer, (DWORD)size, &bwritten, NULL);
1522     if (!rc)
1523         return(rc);
1524     FlushFileBuffers(fd);
1525     return(bwritten);
1526 }
1527