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