19000abe90f678fa319948aedb81e0a7d1e1a748
[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 HANDLE 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, HANDLE fd, 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 intptr_t  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     intptr_t   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     HANDLE  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 == INVALID_HANDLE_VALUE && handle != -1)
496     {
497         if (create_options & FILE_DIRECTORY_FILE)
498         {
499             DWORD rc = GetLastError();
500             if ((rc != ERROR_FILE_NOT_FOUND) && (rc != ERROR_PATH_NOT_FOUND) && (rc != ERROR_ALREADY_EXISTS))
501             {
502                 EndFirstTimer(CMD_NTCREATEX, 0);
503                 SetLastError(rc);
504                 LeaveThread(0, "", CMD_NTCREATEX);
505                 sprintf(temp, "Directory: unable to create directory %s\n", path);
506                 if (verbose)
507                     printf("%s", temp);
508                 LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
509                 return(-1);
510             }
511             fd = 0;
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 (create_options & FILE_DIRECTORY_FILE)
528         fd = 0;
529
530     if (fd != INVALID_HANDLE_VALUE && handle == -1)
531     {
532         CloseHandle(fd);
533         nb_unlink(fname);
534         return(0);
535     }
536
537     if (fd == INVALID_HANDLE_VALUE && handle == -1)
538         return(0);
539
540     for (i = 0; i < MAX_FILES; i++) 
541     {
542         if (ftable[i].handle == 0) 
543             break;
544     }
545     if (i == MAX_FILES) 
546     {
547         printf("(%d) file table full for %s\n", LineCount, path);
548         return(LeaveThread(1, "file table is full\n", CMD_NTCREATEX));
549     }
550     ftable[i].handle = handle;
551     ftable[i].fd = fd;
552     if (ftable[i].name) 
553         free(ftable[i].name);
554     ftable[i].name = strdup(path);
555     ftable[i].reads = ftable[i].writes = 0;
556     return(0);
557 }
558
559 int nb_writex(int handle, int offset, int size, int ret_size)
560 {
561     int     i;
562     ssize_t status;
563     char    FileName[128];
564     char    temp[512];
565
566     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
567
568     if (IoBuffer[0] == 0) 
569         memset(IoBuffer, 1, sizeof(IoBuffer));
570
571     if ((i = FindHandle(handle)) == -1)
572         return(-1);
573     StartFirstTimer();
574     status = nb_write(ftable[i].fd, IoBuffer, offset, size);
575     if (status != ret_size) 
576     {
577         EndFirstTimer(CMD_WRITEX, 0);
578                 LeaveThread(0, "", CMD_WRITEX);
579         if (status == 0)
580             sprintf(temp, "File: %s. wrote %d bytes, got %d bytes\n", ftable[i].name, size, status);
581         if (status == -1)
582             sprintf(temp, "File: %s. On write, cannot set file pointer\n", ftable[i].name);
583         if (verbose)
584             printf("%s", temp);
585         nb_close(handle);
586         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
587         return(-1);
588         }
589     EndFirstTimer(CMD_WRITEX, 1);
590
591     ftable[i].writes++;
592     return(0);
593 }
594
595 int nb_lock(int handle, int offset, int size, int timeout, unsigned char locktype, NTSTATUS exp)
596 {
597 /*
598     int         i;
599     NTSTATUS    ret;
600     char        FileName[128];
601     char        temp[512];
602
603     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
604
605     if ((i = FindHandle(handle)) == -1)
606     {
607         LeaveThread(0, "", CMD_LOCKINGX);
608         sprintf(temp, "File unlock: Cannot find handle for %s", ftable[i].name);
609         if (verbose)
610             printf("%s", temp);
611         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
612         return(-1);
613     }
614
615     StartFirstTimer();
616     ret = cli_locktype(c, i, offset, size, timeout, locktype);
617
618     if (ret != exp)
619     {
620         EndFirstTimer(CMD_LOCKINGX, 0);
621         LeaveThread(0, "", CMD_LOCKINGX);
622         sprintf(temp, "(%d) ERROR: lock failed on handle %d ofs=%d size=%d timeout= %d exp=%d fd %d errno %d (%s)\n",
623                LineCount, handle, offset, size, timeout, exp, ftable[i].fd, exp, "");
624         sprintf(temp, "File unlock: lock failed %s", ftable[i].name);
625         if (verbose)
626             printf("%s", temp);
627         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
628         return(-1);
629     }
630     EndFirstTimer(CMD_LOCKINGX, 1);
631 */
632     return(0);
633 }
634
635 int nb_readx(int handle, int offset, int size, int ret_size)
636 {
637     int     i;
638     ssize_t ret;
639     char    FileName[128];
640     char    temp[512];
641
642     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
643
644     if ((i = FindHandle(handle)) == -1)
645         return(-1);
646
647     StartFirstTimer();
648     ret = nb_read(ftable[i].fd, IoBuffer, offset, size);
649
650     if ((ret != size) && (ret != ret_size))
651     {
652         EndFirstTimer(CMD_READX, 0);
653         LeaveThread(0, "", CMD_READX);
654         if (ret == 0)
655             sprintf(temp, "File: read failed on index=%d, offset=%d ReadSize=%d ActualRead=%d handle=%p\n",
656                     handle, offset, size, ret, ftable[i].fd);
657         if (ret == -1)
658             sprintf(temp, "File: %s. On read, cannot set file pointer\n", ftable[i].name);
659         if (verbose)
660             printf("%s", temp);
661         nb_close(handle);
662         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
663         return(-1);
664     }
665     EndFirstTimer(CMD_READX, 1);
666     ftable[i].reads++;
667     return(0);
668 }
669
670 int nb_close(int handle)
671 {
672     int     i;
673     int     ret;
674     char    FileName[128];
675     char    temp[512];
676
677     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
678
679     if ((i = FindHandle(handle)) == -1)
680         return(0);
681
682     StartFirstTimer();
683     ret = nb_close1(ftable[i].fd); 
684     EndFirstTimer(CMD_CLOSE, ret);
685     if (!ret) 
686     {
687         LeaveThread(0, "", CMD_CLOSE);
688         sprintf(temp, "(%d) close failed on handle %d\n", LineCount, handle);
689         if (verbose)
690             printf("%s", temp);
691         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
692         return(-1);
693     }
694
695     ftable[i].handle = 0;
696     ftable[i].fd = 0;
697     if (ftable[i].name) 
698         free(ftable[i].name);
699     ftable[i].name = NULL;
700     return(0);   
701 }
702
703 int nb_rmdir(char *fname)
704 {
705     int     rc;
706     pstring path;
707     char    FileName[128];
708     char    temp[512];
709
710     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
711
712     strcpy(path, AfsLocker);
713     strcat(path, fname);
714
715     StartFirstTimer();
716     rc = RemoveDirectory(path);
717     EndFirstTimer(CMD_RMDIR, rc);
718
719     if (!rc)
720     {
721         LeaveThread(0, "", CMD_RMDIR);
722         sprintf(temp, "Directory: RemoveDirectory %s failed\n", fname);
723         if (verbose)
724             printf("%s", temp);
725         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
726         return(-1);
727     }
728     return(0);
729 }
730
731 int nb_rename(char *old, char *New)
732 {
733     int     rc;
734     pstring opath;
735     pstring npath;
736     char    FileName[128];
737     char    temp[512];
738
739     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
740
741     strcpy(opath, AfsLocker);
742     strcat(opath, old);
743     strcpy(npath, AfsLocker);
744     strcat(npath, New); 
745
746     StartFirstTimer();
747     rc = MoveFileEx(opath, npath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
748     EndFirstTimer(CMD_RENAME, rc);
749
750     if (!rc)
751     {
752         LeaveThread(0, "", CMD_RENAME);
753         sprintf(temp, "File: rename %s %s failed\n", old, New);
754         if (verbose)
755             printf("%s", temp);
756         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
757         return(-1);
758     }
759     return(0);
760 }
761
762
763 int nb_qpathinfo(char *fname, int Type)
764 {
765     pstring path;
766     int     rc;
767     char    FileName[128];
768     char    temp[512];
769 static Flag = 0;
770
771     if (Type == 1111)
772         Flag = 1;
773
774     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
775
776     strcpy(path, AfsLocker);
777     strcat(path, fname);
778
779     StartFirstTimer();
780     rc = GetPathInfo(path, NULL, NULL, NULL, NULL, NULL);
781
782     if (strstr(fname, "~TS"))
783     {
784         if (rc == 0)
785             rc = 1;
786         else
787             rc = 0;
788     }
789
790 if (!Flag)
791 {
792     if (Type)
793     {
794         if (rc)
795             rc = 0;
796         else
797             rc = 1;
798     }
799     if (!rc)
800     {
801         EndFirstTimer(CMD_QUERY_PATH_INFO, 0);
802         LeaveThread(0, "", CMD_QUERY_PATH_INFO);
803         sprintf(temp, "File: qpathinfo failed for %s\n", path);
804         if (verbose)
805             printf("%s", temp);
806         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
807         return(-1);
808     }
809 }
810     EndFirstTimer(CMD_QUERY_PATH_INFO, 1);
811     return(0);
812 }
813
814 int nb_qfileinfo(int handle)
815 {
816     int     i;
817     int     rc;
818     char    FileName[128];
819     char    temp[512];
820
821     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
822
823     if ((i = FindHandle(handle)) == -1)
824         return(-1);
825
826     StartFirstTimer();
827     rc = GetFileInfo(ftable[i].name, ftable[i].fd, NULL, NULL, NULL, NULL, NULL, NULL);
828
829     if (!rc)
830     {
831         EndFirstTimer(CMD_QUERY_FILE_INFO, 0);
832         LeaveThread(0, "", CMD_QUERY_FILE_INFO);
833         sprintf(temp, "File: qfileinfo failed for %s\n", ftable[i].name);
834         if (verbose)
835             printf("%s", temp);
836         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
837         return(-1);
838     }
839     EndFirstTimer(CMD_QUERY_FILE_INFO, 1);
840
841     return(0);
842 }
843
844 int nb_qfsinfo(int level)
845 {
846
847 //      int     bsize;
848 //    int     total;
849 //    int     avail;
850     int     rc;
851     char    FileName[128];
852     char    temp[512];
853     char    Path[512];
854     ULARGE_INTEGER FreeBytesAvailable;
855     ULARGE_INTEGER TotalNumberOfBytes;
856     ULARGE_INTEGER TotalNumberOfFreeBytes;
857  
858     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
859     sprintf(Path, "%s\\%s%05d", AfsLocker, HostName, LogID);
860
861     StartFirstTimer();
862     rc = GetDiskFreeSpaceEx(Path, &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes);
863 //    rc = cli_dskattr(c, &bsize, &total, &avail);
864
865     if (!rc)
866     {
867         EndFirstTimer(CMD_QUERY_FS_INFO, 0);
868         LeaveThread(0, "", CMD_QUERY_FS_INFO);
869         strcpy(temp, "File: Disk free space failed\n");
870         if (verbose)
871             printf("%s", temp);
872         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
873         return(-1);
874     }
875     EndFirstTimer(CMD_QUERY_FS_INFO, 1);
876
877     return(0);
878 }
879
880 void find_fn(file_info *finfo, char *name, void *state)
881 {
882         /* noop */
883 }
884
885 int nb_findfirst(char *mask)
886 {
887     int     rc;
888     char    FileName[128];
889     char    NewMask[512];
890     char    temp[512];
891
892     if (strstr(mask, "<.JNK"))
893         return(0);
894
895     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
896
897     strcpy(NewMask, AfsLocker);
898     strcat(NewMask, mask);
899
900     StartFirstTimer();
901     rc = GetFileList(NewMask, (void *)find_fn, NULL);
902
903     if (!rc)
904     {
905         EndFirstTimer(CMD_FIND_FIRST, 0);
906         sprintf(temp, "File: findfirst cannot find for %s\n", mask);
907         if (verbose)
908             printf("%s", temp);
909         LeaveThread(1, temp, CMD_FIND_FIRST);
910         LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
911         return(-1);
912     }
913     EndFirstTimer(CMD_FIND_FIRST, 1);
914     return(0);
915 }
916
917 int nb_flush(int handle)
918 {
919     int i;
920
921     if ((i = FindHandle(handle)) == -1)
922         return(-1);
923
924     FlushFileBuffers(ftable[i].fd);
925     return(0);
926 }
927
928 static int total_deleted;
929
930 void delete_fn(file_info *finfo, const char *name, void *state)
931 {
932     int     rc;
933     char    temp[256];
934     char    s[1024];
935     char    FileName[128];
936
937     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
938
939     if (finfo->mode & aDIR) 
940     {
941         char s2[1024];
942         sprintf(s2, "%s\\*", name);
943         GetFileList(s2, delete_fn, NULL);
944         sprintf(s, "%s", &name[strlen(AfsLocker)]);
945         nb_rmdir(s);
946     }
947     else
948     {
949         rc = DeleteFile(name);
950         if (!rc)
951         {
952             LeaveThread(0, "", CMD_UNLINK);
953             sprintf(temp, "FILE: DeleteFile %s failed\n", name);
954             if (verbose)
955                 printf("%s", temp);
956             LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
957             return;
958         }
959     }
960     return;
961 }
962
963 int nb_deltree(char *dname)
964 {
965     int     rc;
966     char    mask[1024];
967     pstring path;
968
969
970     strcpy(path, AfsLocker);
971     strcat(path, dname);
972     sprintf(mask, "%s\\*", path);
973
974     total_deleted = 0;
975
976     StartFirstTimer();
977     GetFileList(mask, delete_fn, NULL);
978
979 //    pstrcpy(path, AfsLocker);
980 //    pstrcat(path, dname);
981     rc = RemoveDirectory(path);
982     EndFirstTimer(CMD_DELTREE, rc);
983     if (!rc)
984     {
985         char FileName[256];
986         char temp[128];
987         int  rc;
988
989         rc = GetLastError();
990         if ((rc != ERROR_FILE_NOT_FOUND) && (rc != ERROR_PATH_NOT_FOUND))
991         {
992             SetLastError(rc);
993             LeaveThread(0, "", CMD_DELTREE);
994             sprintf(FileName, "Thread_%05d.log", ProcessNumber);
995             sprintf(temp, "ERROR: Thread %d - Unable to remove %s.\n", ProcessNumber, path);
996             LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
997             if (verbose)
998                 printf(temp);
999             return(-1);
1000         }
1001     }
1002     return(0);
1003 }
1004
1005
1006 int nb_cleanup(char *cname)
1007 {
1008     char temp[256];
1009
1010     strcpy(temp, "\\clients\\client1");
1011     SubstituteString(temp, "client1", cname, sizeof(temp));
1012     SubstituteString(temp, "clients", HostName, sizeof(temp));
1013     nb_deltree(temp);
1014     return(0);
1015 }
1016
1017 int LeaveThread(int status, char *Reason, int cmd)
1018 {
1019     char    FileName[256];
1020     char    temp[512];
1021     DWORD   rc;
1022
1023     if (cmd != -1)
1024         ++ThreadCommandInfo[cmd].ErrorCount;
1025
1026     if (strlen(Reason) == 0)
1027     {
1028         if (status == 0)
1029             rc = GetLastError();
1030         else
1031             rc = status;
1032         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1033                       NULL,
1034                       rc,
1035                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1036                       pExitStatus->Reason,
1037                       sizeof(pExitStatus->Reason),
1038                       NULL);
1039         LastKnownError = rc;
1040     }
1041     else
1042         strcpy(pExitStatus->Reason, Reason);
1043
1044     if (strlen(pExitStatus->Reason) == 0)
1045         strcpy(pExitStatus->Reason, "\n");
1046     if (pExitStatus->Reason[strlen(pExitStatus->Reason) - 1] != '\n')
1047         strcat(pExitStatus->Reason, "\n");
1048     sprintf(FileName, "Thread_%05d.log", ProcessNumber);
1049     if (strlen(Reason) == 0)
1050         sprintf(temp, "ERROR(%d): Thread %d - (%d) %s", LineCount, ProcessNumber, rc, pExitStatus->Reason);
1051     else
1052         sprintf(temp, "ERROR(%d): Thread %d - %s", LineCount, ProcessNumber, pExitStatus->Reason);
1053     LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
1054     if (verbose)
1055         printf("%s", temp);
1056     pExitStatus->ExitStatus = status;
1057     if (AfsTrace)
1058         DumpAFSLog(HostName, LogID);
1059     (*pThreadStatus) = 0;
1060     return(-1);
1061 }
1062
1063 void StartFirstTimer(void)
1064 {
1065
1066     EndSecondTime(CMD_NONAFS);
1067     TickCount1 = GetTickCount();
1068 }
1069
1070 void EndFirstTimer(int cmd, int Type)
1071 {
1072     DWORD   MilliTick;
1073     DWORD   cmd_time;
1074
1075     ThreadCommandInfo[cmd].count++;
1076     cmd_time = 0;
1077     MilliTick = GetTickCount() - TickCount1;
1078     if (MilliTick <= 0)
1079     {
1080         StartSecondTime(CMD_NONAFS);
1081         return;
1082     }
1083
1084     ThreadCommandInfo[cmd].MilliSeconds += MilliTick;
1085     while (ThreadCommandInfo[cmd].MilliSeconds > 1000)
1086     {
1087         ThreadCommandInfo[cmd].MilliSeconds -= 1000;
1088         cmd_time += 1;
1089     }
1090
1091     if (cmd_time == 0)
1092     {
1093         ThreadCommandInfo[cmd].min_sec = cmd_time;
1094         StartSecondTime(CMD_NONAFS);
1095         return;
1096     }
1097
1098     if (!Type)
1099         ThreadCommandInfo[cmd].ErrorTime += cmd_time;
1100     else
1101     {
1102         ThreadCommandInfo[cmd].total_sec += cmd_time;
1103         if (cmd_time < (int)ThreadCommandInfo[cmd].min_sec)
1104             ThreadCommandInfo[cmd].min_sec = cmd_time;
1105         if ((int)ThreadCommandInfo[cmd].max_sec < cmd_time)
1106             ThreadCommandInfo[cmd].max_sec = cmd_time;
1107     }
1108
1109     StartSecondTime(CMD_NONAFS);
1110 }
1111
1112 void StartSecondTime(int cmd)
1113 {
1114
1115     TickCount2 = GetTickCount();
1116
1117 }
1118
1119 void EndSecondTime(int cmd)
1120 {
1121     DWORD   MilliTick;
1122     DWORD   cmd_time;
1123
1124     ThreadCommandInfo[cmd].count++;
1125     cmd_time = 0;
1126     MilliTick = GetTickCount() - TickCount2;
1127
1128     if (MilliTick <= 0)
1129         return;
1130
1131     ThreadCommandInfo[cmd].MilliSeconds += MilliTick;
1132     while (ThreadCommandInfo[cmd].MilliSeconds > 1000)
1133     {
1134         ThreadCommandInfo[cmd].MilliSeconds -= 1000;
1135         cmd_time += 1;
1136     }
1137     if (cmd_time == 0)
1138     {
1139         ThreadCommandInfo[cmd].min_sec = cmd_time;
1140         return;
1141     }
1142     if (cmd_time < (int)ThreadCommandInfo[cmd].min_sec)
1143         ThreadCommandInfo[cmd].min_sec = cmd_time;
1144     if ((int)ThreadCommandInfo[cmd].max_sec < cmd_time)
1145         ThreadCommandInfo[cmd].max_sec = cmd_time;
1146     ThreadCommandInfo[cmd].total_sec += cmd_time;
1147 }
1148
1149
1150 intptr_t SystemCall(char *command)
1151 {
1152     intptr_t rc;
1153     char    *argv[6];
1154
1155     argv[0] = getenv("COMSPEC");
1156     argv[1] = "/q";
1157     argv[2] = "/c";
1158     argv[3] = (char *)command;
1159     argv[4] = NULL;
1160
1161     rc = spawnve(_P_WAIT,argv[0],argv,NULL);
1162 // != -1 || (errno != ENOENT && errno != EACCES))
1163     return(rc);
1164 }
1165
1166 HANDLE CreateObject(const char *fname, uint32 DesiredAccess,
1167                  uint32 FileAttributes, uint32 ShareAccess,
1168                  uint32 CreateDisposition, uint32 CreateOptions)
1169 {
1170     HANDLE   fd;
1171     DWORD dwCreateDisposition = 0;
1172     DWORD dwDesiredAccess = 0;
1173     DWORD dwShareAccess = 0;
1174
1175     if (CreateOptions & FILE_DIRECTORY_FILE)
1176     {
1177         if (!CreateDirectory(fname, NULL))
1178             fd = INVALID_HANDLE_VALUE;
1179         else 
1180             fd = 0;
1181     }
1182     else
1183     {
1184         dwDesiredAccess = 0;
1185         if (DesiredAccess & FILE_READ_DATA)
1186             dwDesiredAccess |= GENERIC_READ;
1187         if (DesiredAccess & FILE_WRITE_DATA)
1188             dwDesiredAccess |= GENERIC_WRITE;
1189         dwShareAccess = ShareAccess;
1190         dwShareAccess |= FILE_SHARE_DELETE;
1191         dwCreateDisposition = OPEN_ALWAYS;
1192         if (CreateDisposition == 1)
1193             dwCreateDisposition = OPEN_EXISTING;
1194         fd = CreateFile(fname, dwDesiredAccess, ShareAccess, NULL, dwCreateDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
1195     }
1196
1197     return(fd);
1198 }
1199
1200 BOOL nb_close1(HANDLE fd)
1201 {
1202     int dwFlags = 0;
1203     int rc = 1;
1204
1205     if (fd != INVALID_HANDLE_VALUE)
1206     {
1207         if (rc = GetHandleInformation(fd, &dwFlags))
1208             CloseHandle(fd);
1209     }
1210     return(rc);
1211 }
1212
1213 /****************************************************************************
1214   do a directory listing, calling fn on each file found
1215   this uses the old SMBsearch interface. It is needed for testing Samba,
1216   but should otherwise not be used
1217   ****************************************************************************/
1218 int nb_list_old(const char *Mask, void (*fn)(file_info *, const char *, void *), void *state)
1219 {
1220         int     num_received = 0;
1221         pstring mask;
1222     char    temp[512];
1223     char    cFileName[1024];
1224     int     dwFileAttributes;
1225     HANDLE  hFind;
1226     void    *FileData;
1227
1228         strcpy(mask,Mask);
1229
1230
1231     if (!strcmp(&mask[strlen(mask)-2], "\"*"))
1232     {
1233         strcpy(&mask[strlen(mask)-2], "*");
1234     }
1235     FileData = NULL;
1236     dwFileAttributes = 0;
1237     memset(cFileName, '\0', sizeof(cFileName));
1238     hFind = WinFindFirstFile(mask, &FileData, cFileName, &dwFileAttributes);
1239     if (hFind == INVALID_HANDLE_VALUE)
1240     {
1241         return(0);
1242     }
1243     mask[strlen(mask) - 1] = '\0';
1244     while (1)
1245     {
1246         if (cFileName[0] != '.')
1247         {
1248             file_info finfo;
1249
1250             memset(&finfo, '\0', sizeof(finfo));
1251             if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1252                 finfo.mode = aDIR;
1253             strcpy(finfo.name, cFileName);
1254             sprintf(temp, "%s%s", mask, cFileName);
1255                 fn(&finfo, temp, state);
1256             ++num_received;
1257         }
1258         memset(cFileName, '\0', sizeof(cFileName));
1259         dwFileAttributes = 0;
1260         if (!WinFindNextFile(hFind, &FileData, cFileName, &dwFileAttributes))
1261             break;
1262     }
1263     FindClose(hFind);
1264     return(num_received);
1265 }
1266
1267
1268 /****************************************************************************
1269   do a directory listing, calling fn on each file found
1270   this auto-switches between old and new style
1271   ****************************************************************************/
1272 int GetFileList(char *Mask, void (*fn)(file_info *, const char *, void *), void *state)
1273 {
1274     return(nb_list_old(Mask, fn, state));
1275 }
1276
1277 HANDLE WinFindFirstFile(char *Mask, void **FileData, char *cFileName, int *dwFileAttributes)
1278 {
1279     HANDLE  rc;
1280     static WIN32_FIND_DATAW FileDataW;
1281     static WIN32_FIND_DATAA FileDataA;
1282
1283     memset(&FileDataA, '\0', sizeof(FileDataA));
1284     rc = FindFirstFile(Mask, &FileDataA);
1285     if (rc != INVALID_HANDLE_VALUE)
1286     {
1287         (*FileData) = (void *)&FileDataA;
1288         (*dwFileAttributes) = FileDataA.dwFileAttributes;
1289         strcpy(cFileName, FileDataA.cFileName);
1290     }
1291
1292     return(rc);
1293 }
1294
1295 int WinFindNextFile(HANDLE hFind, void **FileData, char *cFileName, int *dwFileAttributes)
1296 {
1297     int     rc;
1298     WIN32_FIND_DATAA *FileDataA;
1299
1300     FileDataA = (WIN32_FIND_DATAA *)(*FileData);
1301     if (!(rc = FindNextFile(hFind, FileDataA)))
1302     {
1303         return(rc);
1304     }
1305     (*dwFileAttributes) = FileDataA->dwFileAttributes;
1306     strcpy(cFileName, FileDataA->cFileName);
1307
1308     return(rc);
1309 }
1310
1311 void SubstituteString(char *s,const char *pattern,const char *insert, size_t len)
1312 {
1313     char *p;
1314     ssize_t ls,lp,li;
1315
1316     if (!insert || !pattern || !s) return;
1317
1318     ls = (ssize_t)strlen(s);
1319     lp = (ssize_t)strlen(pattern);
1320     li = (ssize_t)strlen(insert);
1321
1322     if (!*pattern) return;
1323         
1324     while (lp <= ls && (p = strstr(s,pattern)))
1325     {
1326         if (len && (ls + (li-lp) >= (int)len)) 
1327         {
1328             break;
1329         }
1330         if (li != lp) 
1331         {
1332             memmove(p+li,p+lp,strlen(p+lp)+1);
1333         }
1334         memcpy(p, insert, li);
1335         s = p + li;
1336         ls += (li-lp);
1337     }
1338 }
1339
1340 #define CHANGE_TIME(A,B) \
1341 B.tm_hour = A.wHour; \
1342 B.tm_sec = A.wSecond; \
1343 B.tm_min = A.wMinute; \
1344 B.tm_mon = A.wMonth - 1; \
1345 B.tm_yday = 0; \
1346 B.tm_year = A.wYear - 1900; \
1347 B.tm_wday = A.wDayOfWeek - 1; \
1348 B.tm_isdst = -1; \
1349 B.tm_mday = A.wDay;
1350
1351
1352 BOOL GetPathInfo(const char *fname, 
1353                    time_t *c_time, time_t *a_time, time_t *m_time, 
1354                    size_t *size, uint16 *mode)
1355 {
1356     WIN32_FILE_ATTRIBUTE_DATA FileInfo;
1357     int         rc;
1358     SYSTEMTIME  SystemTime;
1359     struct tm   tm_time;
1360
1361     rc = GetFileAttributesEx(fname, GetFileExInfoStandard, &FileInfo);
1362     if (rc != 0)
1363     {
1364         if (c_time)
1365         {
1366             rc = FileTimeToSystemTime(&FileInfo.ftCreationTime, &SystemTime);
1367             CHANGE_TIME(SystemTime, tm_time)
1368             (*c_time) = mktime(&tm_time);
1369         }
1370         if (a_time)
1371         {
1372             rc = FileTimeToSystemTime(&FileInfo.ftLastAccessTime, &SystemTime);
1373             CHANGE_TIME(SystemTime, tm_time)
1374             (*a_time) = mktime(&tm_time);
1375         }
1376         if (m_time)
1377         {
1378             rc = FileTimeToSystemTime(&FileInfo.ftLastWriteTime, &SystemTime);
1379             CHANGE_TIME(SystemTime, tm_time)
1380             (*m_time) = mktime(&tm_time);
1381         }
1382         if (size) 
1383         {
1384             rc = 1;
1385             if (!(FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1386                 *size = FileInfo.nFileSizeLow;
1387         }
1388         if (mode)
1389         {
1390             rc = 1;
1391             (*mode) = 0;
1392         }
1393     }
1394     return(rc);
1395 }
1396
1397 /****************************************************************************
1398 send a qfileinfo call
1399 ****************************************************************************/
1400 BOOL GetFileInfo(char *FileName, HANDLE fd, 
1401                    uint16 *mode, size_t *size,
1402                    time_t *c_time, time_t *a_time, time_t *m_time, 
1403                    time_t *w_time)
1404 {
1405     WIN32_FILE_ATTRIBUTE_DATA FileInfo;
1406     int         rc;
1407     SYSTEMTIME  SystemTime;
1408     struct tm   tm_time;
1409
1410     rc = GetFileAttributesEx(FileName, GetFileExInfoStandard, &FileInfo);
1411     if (rc != 0)
1412     {
1413         if (c_time)
1414         {
1415             rc = FileTimeToSystemTime(&FileInfo.ftCreationTime, &SystemTime);
1416             CHANGE_TIME(SystemTime, tm_time)
1417             (*c_time) = mktime(&tm_time);
1418         }
1419         if (a_time)
1420         {
1421             rc = FileTimeToSystemTime(&FileInfo.ftLastAccessTime, &SystemTime);
1422             CHANGE_TIME(SystemTime, tm_time)
1423             (*a_time) = mktime(&tm_time);
1424         }
1425         if (m_time)
1426         {
1427             rc = FileTimeToSystemTime(&FileInfo.ftLastWriteTime, &SystemTime);
1428             CHANGE_TIME(SystemTime, tm_time)
1429             (*m_time) = mktime(&tm_time);
1430         }
1431         if (size) 
1432         {
1433             rc = 0;
1434             if (!(FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1435                *size = FileInfo.nFileSizeLow;
1436             }
1437             if (mode)
1438         {
1439             rc = 0;
1440             (*mode) = 0;
1441         }
1442     }
1443     return(rc);
1444 }
1445
1446 /****************************************************************************
1447   Read size bytes at offset offset using SMBreadX.
1448 ****************************************************************************/
1449
1450 ssize_t nb_read(HANDLE fd, char *IoBuffer, off_t offset, size_t size)
1451 {
1452     DWORD   total = 0;
1453     int     rc;
1454     DWORD   LowDword;
1455
1456     if (size == 0) 
1457         return(0);
1458
1459     LowDword = SetFilePointer(fd, offset, 0, FILE_BEGIN);
1460
1461     if (LowDword == INVALID_SET_FILE_POINTER)
1462         return(-1);
1463     rc = ReadFile(fd, IoBuffer, (DWORD)size, &total, NULL);
1464     if (!rc)
1465         return(rc);
1466
1467     return(total);
1468 }
1469
1470 /****************************************************************************
1471   write to a file
1472 ****************************************************************************/
1473
1474 ssize_t nb_write(HANDLE fd, char *IoBuffer, off_t offset, size_t size)
1475 {
1476     DWORD   bwritten = 0;
1477     int     rc;
1478     DWORD   LowDword;
1479
1480     LowDword = SetFilePointer(fd, offset, 0, FILE_BEGIN);
1481     if (LowDword == INVALID_SET_FILE_POINTER)
1482         return(-1);
1483     rc = WriteFile(fd, IoBuffer, (DWORD)size, &bwritten, NULL);
1484     if (!rc)
1485         return(rc);
1486     FlushFileBuffers(fd);
1487     return(bwritten);
1488 }
1489