Subversion Repositories SvarDOS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2019 mateusz.vi 1
/****************************************************************************
2
 
2026 mateusz.vi 3
  Win32 File compatibility for DOS.
2019 mateusz.vi 4
  [This version does support LFNs, if available.]
5
 
6
  Written by: Kenneth J. Davis
7
  Date:       August, 2000
8
  Contact:    jeremyd@computer.org
9
 
10
 
11
Copyright (c): Public Domain [United States Definition]
12
 
13
Permission is hereby granted, free of charge, to any person obtaining a copy
14
of this software and associated documentation files (the "Software"), to deal
15
in the Software without restriction, including without limitation the rights
16
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
copies of the Software, and to permit persons to whom the Software is
18
furnished to do so, subject to the following conditions:
19
 
20
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR AUTHORS BE
24
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
26
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
DEALINGS IN THE SOFTWARE.
28
 
29
****************************************************************************/
30
 
31
 
32
/*** Expects Pointers to be near (Tiny, Small, and Medium models ONLY) ***/
33
 
2035 mateusz.vi 34
#include "dosdisk.h"
2019 mateusz.vi 35
#include <stdlib.h>
36
#include <string.h>
37
 
38
#define searchAttr ( FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | \
39
   FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_ARCHIVE )
40
 
2026 mateusz.vi 41
/* If this variable is nonzero then will 1st attempt LFN findfirst
2019 mateusz.vi 42
 * (findfirst calls sets flag, so findnext/findclose know proper method to continue)
43
 * else if 0 then only attempt old 0x4E findfirst.
44
 * This is mostly a debugging tool, may be useful during runtime.
45
 * Default is LFN_ENABLE.
46
 */
47
int LFN_Enable_Flag = LFN_ENABLE;
48
 
49
 
2026 mateusz.vi 50
/* copy old style findfirst data FFDTA to a WIN32_FIND_DATA
51
 * NOTE: does not map exactly.
2019 mateusz.vi 52
 * internal to this module only.
53
 */
2040 mateusz.vi 54
static void copyFileData(struct WIN32_FIND_DATA *findData, FFDTA *finfo)
2019 mateusz.vi 55
{
56
  /* Copy requried contents over into required structure */
57
  strcpy(findData->cFileName, finfo->ff_name);
58
  findData->dwFileAttributes = (DWORD)finfo->ff_attrib;
59
 
60
  /* copy over rest (not quite properly) */
61
  findData->ftCreationTime.ldw[0] = finfo->ff_ftime;
62
  findData->ftLastAccessTime.ldw[0] = finfo->ff_ftime;
63
  findData->ftLastWriteTime.ldw[0] = finfo->ff_ftime;
64
  findData->ftCreationTime.ldw[1] = finfo->ff_fdate;
65
  findData->ftLastAccessTime.ldw[1] = finfo->ff_fdate;
66
  findData->ftLastWriteTime.ldw[1] = finfo->ff_fdate;
67
  findData->ftCreationTime.hdw = 0;
68
  findData->ftLastAccessTime.hdw = 0;
69
  findData->ftLastWriteTime.hdw = 0;
70
  findData->nFileSizeHigh = 0;
71
  findData->nFileSizeLow = (DWORD)finfo->ff_fsize;
72
  findData->dwReserved0 = 0;
73
  findData->dwReserved1 = 0;
74
}
75
 
2040 mateusz.vi 76
HANDLE FindFirstFile(const char *pathname, struct WIN32_FIND_DATA *findData)
2019 mateusz.vi 77
{
78
  char path[1024];
79
  HANDLE hnd;
80
  short cflag = 0;  /* used to indicate if findfirst is succesful or not */
81
 
82
  /* verify findData is valid */
83
  if (findData == NULL)
84
    return INVALID_HANDLE_VALUE;
85
 
86
  /* allocate memory for the handle */
87
  if ((hnd = (HANDLE)malloc(sizeof(struct FindFileStruct))) == NULL)
88
    return INVALID_HANDLE_VALUE;
89
 
90
  /* initialize structure (clear) */
91
  /* hnd->handle = 0;  hnd->ffdtaptr = NULL; */
92
  memset(hnd, 0, sizeof(struct FindFileStruct));
93
 
94
  /* Clear findData, this is to fix a glitch under NT, with 'special' $???? files */
95
  memset(findData, 0, sizeof(struct WIN32_FIND_DATA));
96
 
97
  /* First try DOS LFN (0x714E) findfirst, going to old (0x4E) if error */
98
  if (LFN_Enable_Flag)
99
  {
100
    hnd->flag = FINDFILELFN;
101
 
102
    asm {
103
      STC                          //; In case not supported
104
      PUSH SI                      //; Ensure borlands registers unmodified
105
      PUSH DI
106
      MOV SI, 1                    //; same format as when old style used, set to 0 for 64bit value
107
      MOV AX, DS                   //; Set address of findData into ES:DI
108
      MOV ES, AX
109
      MOV DI, [findData]
110
      MOV AX, 714Eh                //; LFN version of FindFirst
111
      MOV DX, [pathname]           //; Load DS:DX with pointer to path for Findfirt
112
    }
113
    _CX = searchAttr;
114
    asm {
115
      INT 21h                      //; Execute interrupt
116
      POP DI                       //; Restore DI
117
      POP SI                       //; Restore SI
118
      JC lfnerror
119
    }
120
    hnd->fhnd.handle = _AX;  /* store handle finally :) */
121
    return hnd;
122
 
123
lfnerror:
124
    /* AX is supposed to contain 7100h if function not supported, else real error */
125
    /* However, FreeDOS returns AX = 1 = Invalid function number instead.         */
126
    if ((_AX != 0x7100) && (_AX != 0x0001))
127
    {
128
      free(hnd);
129
      return INVALID_HANDLE_VALUE;
130
    }
131
  }
132
 
133
  /* Use DOS (0x4E) findfirst, returning if error */
134
  hnd->flag = FINDFILEOLD;
135
 
136
  /* allocate memory for the FFDTA */
137
  if ((hnd->fhnd.ffdtaptr = (FFDTA *)malloc(sizeof(struct FFDTA))) == NULL)
138
  {
139
    free(hnd);
140
    return INVALID_HANDLE_VALUE;
141
  }
142
 
143
  /* if pathname ends in \* convert to \*.* */
144
  strcpy(path, pathname);
2032 mateusz.vi 145
  {
146
  int eos = strlen(path) - 1;
147
  if ((path[eos] == '*') && (path[eos - 1] == '\\')) strcat(path, ".*");
148
  }
2019 mateusz.vi 149
 
150
  asm {
151
    MOV AH, 2Fh                    //; Get Current DTA
152
    INT 21h                        //; Execute interrupt, returned in ES:BX
153
    PUSH BX                        //; Store its Offset, then Segment
154
    PUSH ES
155
    MOV AH, 1Ah                    //; Set Current DTA to our buffer, DS:DX
156
 }
157
    _DX = (WORD)(*hnd).fhnd.ffdtaptr;   //; Load our buffer for new DTA.
158
 asm {
159
    INT 21h                        //; Execute interrupt
160
    MOV AX, 4E00h                  //; Actual findfirst call
161
    LEA DX, path                   //; Load DS:DX with pointer to path for Findfirt
162
  }
163
    _CX = searchAttr;
164
  asm {
165
    INT 21h                        //; Execute interrupt
166
    JNC success                    //; If carry is not set then succesful
167
    MOV [cflag], AX                //; Set flag with error.
168
  }
169
success:
170
  asm {
171
    MOV AH, 1Ah               //; Set Current DTA back to original, DS:DX
172
    MOV DX, DS                //; Store DS, must be preserved
173
    POP DS                    //; Popping ES into DS since thats where we need it.
174
    POP BX                    //; Now DS:BX points to original DTA
175
    INT 21h                   //; Execute interrupt to restore.
176
    MOV DS, DX                //; Restore DS
177
  }
178
 
179
  if (cflag)
180
  {
181
    free(hnd->fhnd.ffdtaptr);
182
    free(hnd);
183
    return INVALID_HANDLE_VALUE;
184
  }
185
 
186
  /* copy its results over */
187
  copyFileData(findData, hnd->fhnd.ffdtaptr);
188
 
189
  return hnd;
190
}
191
 
192
 
2040 mateusz.vi 193
int FindNextFile(HANDLE hnd, struct WIN32_FIND_DATA *findData)
2019 mateusz.vi 194
{
195
  short cflag = 0;  /* used to indicate if dos findnext succesful or not */
196
 
197
  /* if bad handle given return */
198
  if ((hnd == NULL) || (hnd == INVALID_HANDLE_VALUE)) return 0;
199
 
200
  /* verify findData is valid */
201
  if (findData == NULL) return 0;
202
 
203
  /* Clear findData, this is to fix a glitch under NT, with 'special' $???? files */
204
  memset(findData, 0, sizeof(struct WIN32_FIND_DATA));
205
 
206
  /* Flag indicate if using LFN DOS (0x714F) or not */
207
  if (hnd->flag == FINDFILELFN)
208
  {
209
    _BX = hnd->fhnd.handle;        //; Move the Handle returned by previous findfirst into BX
210
    asm {
211
      STC                          //; In case not supported
212
      PUSH SI                      //; Ensure borlands registers unmodified
213
      PUSH DI
214
      MOV SI, 1                    //; same format as when old style used, set to 0 for 64bit value
215
      MOV AX, DS                   //; Set address of findData into ES:DI
216
      MOV ES, AX
217
      MOV DI, [findData]
218
      MOV AX, 714Fh                //; LFN version of FindNext
219
      INT 21h                      //; Execute interrupt
220
      POP DI                       //; Restore DI
221
      POP SI                       //; Restore SI
222
      JC lfnerror
223
    }
224
    return 1;   /* success */
225
 
226
lfnerror:
227
    return 0;   /* Any errors here, no other option but to return error/no more files */
228
  }
229
  else  /* Use DOS (0x4F) findnext, returning if error */
230
  {
231
    asm {
232
      MOV AH, 2Fh                   //; Get Current DTA
233
      INT 21h                       //; Execute interrupt, returned in ES:BX
234
      PUSH BX                       //; Store its Offset, then Segment
235
      PUSH ES
236
    }
237
    _DX = (WORD)(*hnd).fhnd.ffdtaptr;    //; Load our buffer for new DTA.
238
    asm {
239
      MOV AX, 1A00h                 //; Set Current DTA to our buffer, DS:DX
240
      INT 21h                       //; Execute interrupt
241
      MOV AX, 4F00h                 //; Actual findnext call
242
      INT 21h                       //; Execute interrupt
243
      JNC success                   //; If carry is not set then succesful
244
      MOV [cflag], AX               //; Set flag with error.
245
    }
246
success:
247
    asm {
248
      MOV AH, 1Ah                   //; Set Current DTA back to original, DS:DX
249
      MOV DX, DS                    //; Store DS, must be preserved
250
      POP DS                        //; Popping ES into DS since thats where we need it.
251
      POP BX                        //; Now DS:BX points to original DTA
252
      INT 21h                       //; Execute interrupt to restore.
253
      MOV DS, DX                    //; Restore DS
254
    }
255
 
256
  if (cflag)
257
    return 0;
258
 
259
  /* copy its results over */
260
  copyFileData(findData, hnd->fhnd.ffdtaptr);
261
 
262
  return 1;
263
  }
264
}
265
 
266
 
267
/* free resources to prevent memory leaks */
268
void FindClose(HANDLE hnd)
269
{
270
  /* 1st check if valid handle given */
271
  if ((hnd != NULL) && (hnd != INVALID_HANDLE_VALUE))
272
  {
273
    /* See if its for the new or old style findfirst */
274
    if (hnd->flag == FINDFILEOLD) /* Just free memory allocated */
275
    {
2026 mateusz.vi 276
      if (hnd->fhnd.ffdtaptr != NULL)
2019 mateusz.vi 277
        free(hnd->fhnd.ffdtaptr);
278
      hnd->fhnd.ffdtaptr = NULL;
279
    }
280
    else /* must call LFN findclose */
281
    {
282
      _BX = hnd->fhnd.handle;     /* Move handle returned from findfirst into BX */
283
      asm {
284
        STC
285
        MOV AX, 71A1h
286
        INT 21h                   /* carry set on error */
287
      }
288
      hnd->fhnd.handle = 0;
289
    }
290
 
291
    free(hnd);                    /* Free memory used for the handle itself */
292
  }
293
}
294
 
295
#include <stdio.h>
296
 
297
/**
298
 Try LFN getVolumeInformation 1st
299
 if successful, assume valid drive/share (ie will return 1 unless error getting label)
300
 if failed (any error other than unsupported) return 0
301
 if a drive (ie a hard drive, ram drive, network mapped to letter) [has : as second letter]
302
 {
303
   try findfirst for volume label. (The LFN api does not seem to support LABEL attribute searches.)
304
     If getVolInfo unsupported but get findfirst succeed, assume valid (ie return 1)
305
   Try Get Serial#
306
 }
307
 else a network give \\server\share and LFN getVol unsupported, assume failed 0, as the
308
   original findfirst/next I haven't seen support UNC naming, clear serial and volume.
309
*** Currently trying to find a way to get a \\server\share 's serial & volume if LFN available ***
310
*/
311
 
312
/* Only the 1st 4 arguments are used, returns zero on failure,
313
 * If lpRootPathName is NULL or "" we use current default drive.
314
 */
315
#pragma argsused
316
int GetVolumeInformation(char *lpRootPathName,char *lpVolumeNameBuffer,
317
  DWORD nVolumeNameSize, DWORD *lpVolumeSerialNumber,
318
  DWORD *lpMaximumComponentLength, DWORD *lpFileSystemFlags,
319
  char *lpFileSystemNameBuffer, DWORD nFileSystemNameSize)
320
{
321
  /* File info for getting  Volume Label (using directory entry) */
322
  FFDTA finfo;
323
 
324
  /* Using DOS interrupt to get serial number */
325
  struct media_info
326
  {
327
    short dummy;
328
    DWORD serial;
329
    char volume[11];
330
    short ftype[8];
331
  } media;
332
 
333
  /* buffer to store file system name in lfn get volume information */
2026 mateusz.vi 334
  char fsystem[32];
2019 mateusz.vi 335
 
336
  /* Stores the root path we use. */
337
  char pathname[260];
338
 
2026 mateusz.vi 339
  /* Used to determine if drive valid (success/failure of this function)
2019 mateusz.vi 340
   * 0 = success
341
   * 1 = failure
342
   * 2 = LFN api unsupported (tentative failure)
343
   */
344
  int cflag=2;
345
 
346
  /* validate root path to obtain info on, NULL or "" means use current */
347
  if ((lpRootPathName == NULL) || (*lpRootPathName == '\0'))
348
  {
349
    /* Assume if NULL user wants current drive, eg C:\ */
350
    asm {
351
      MOV AH, 19h             //; Get Current Default Drive
352
      INT 21h                 //; returned in AL, 0=A, 1=B,...
353
      LEA BX, pathname        //; load pointer to our buffer
354
      ADD AL, 'A'             //; Convert #returned to a letter
355
      MOV [BX], AL            //; Store drive letter
356
      INC BX                  //; point to next character
357
      MOV BYTE PTR [BX], ':'  //; Store the colon
358
      INC BX
359
      MOV BYTE PTR [BX], '\'  //; and the \ (this gets converted correctly as a single \
360
      INC BX
361
      MOV BYTE PTR [BX], 0    //; Most importantly the '\0' terminator
362
    }
363
  }
364
  else
365
    strcpy(pathname, lpRootPathName);
366
 
367
  /* Flag indicate if using LFN DOS or not */
368
  if (LFN_Enable_Flag)
369
  {
370
    asm {
371
      MOV AX, 71A0h            //; LFN GetVolumeInformation
372
      PUSH DI                  //; Preserve DI for borland
373
      MOV DX, DS               //; Load buffer for file system name into ES:DI
374
      MOV ES, DX
375
      LEA DI, fsystem
376
      MOV CX, 32               //; size of ES:DI buffer
377
      LEA DX, pathname         //; Load root name into DS:DX
378
      STC                      //; in case LFN api unsupported
379
      INT 21h
380
      POP DI                   //; restore Borland's register
381
      JC getvolerror           //; on any error skip storing any info
382
    }
383
    /* store stuff
384
	    BX = file system flags (see #01783)
385
	    CX = maximum length of file name [usually 255]
386
	    DX = maximum length of path [usually 260]
387
	    fsystem buffer filled (ASCIZ, e.g. "FAT","NTFS","CDFS")
388
    */
389
    cflag = 0;                 //; indicate no error
390
    goto endgetvol;
391
 
392
getvolerror:
393
    asm {
394
      CMP AX, 7100h            //; see if real error or unsupported
395
      JE endgetvol             //; if so skip ahead
396
      CMP AX, 0001h            //; FreeDOS returns AX = 1 = Invalid function number
397
      JE endgetvol
398
    }
399
    cflag = 1;                 //; indicate failure
400
 
401
endgetvol:
402
  }
403
 
404
 
405
  if (cflag != 1)  /* if no error validating volume info or LFN getVolInfo unsupported */
406
  {
407
    /* if a drive, test if valid, get volume, and possibly serial # */
408
    if (pathname[1] == ':')
409
    {
410
      /* assume these calls will succeed, change on an error */
411
      cflag = 0;
412
 
413
      /* get path ending in \*.*, */
414
      if (pathname[strlen(pathname)-1] != '\\')
415
	strcat(pathname, "\\*.*");
416
      else
417
	strcat(pathname, "*.*");
418
 
419
      /* Search for volume using old findfirst, as LFN version (NT5 DOS box) does
420
       * not recognize FILE_ATTRIBUTE_LABEL = 0x0008 as label attribute.
421
       */
422
      asm {
423
	MOV AH, 2Fh               //; Get Current DTA
424
	INT 21h                   //; Execute interrupt, returned in ES:BX
425
	PUSH BX                   //; Store its Offset, then Segment
426
	PUSH ES
427
	MOV AH, 1Ah               //; Set Current DTA to our buffer, DS:DX
428
	LEA DX, finfo       	    //; Load our buffer for new DTA.
429
	INT 21h                   //; Execute interrupt
430
	MOV AX, 4E00h             //; Actual findfirst call
431
	LEA DX, pathname          //; Load DS:DX with pointer to modified RootPath for Findfirt
432
	MOV CX, FILE_ATTRIBUTE_LABEL
433
	INT 21h                   //; Execute interrupt, Carry set on error, unset on success
434
	JNC success               //; If carry is not set then succesful
435
	MOV [cflag], AX           //; Set flag with error.
436
	JMP cleanup               //; Restore DTA
437
      }
438
success:                        //; True volume entry only has volume attribute set [MS' LFNspec]
439
      asm {                     //;     But they may also have archive bit set!!!
440
	LEA BX, finfo.ff_attrib   //; Load address of file's attributes returned by findfirst/next
441
	MOV AL, BYTE PTR [BX]     //; Looking for a BYTE that is FILE_ATTRIBUTE_LABEL only
442
      AND AL, 0xDF              //; Ignore Archive bit
443
	CMP AL, FILE_ATTRIBUTE_LABEL
444
	JE cleanup                //; They match, so should be true volume entry.
445
	MOV AX, 4F00h             //; Otherwise keep looking (findnext)
446
	INT 21h                   //; Execute interrupt
447
	JNC success               //; If carry is not set then succesful
448
	MOV [cflag], AX           //; Set flag with error.
449
      }
450
cleanup:
451
      asm {
452
	MOV AH, 1Ah               //; Set Current DTA back to original, DS:DX
453
	MOV DX, DS                //; Store DS, must be preserved
454
	POP DS                    //; Popping ES into DS since thats where we need it.
455
	POP BX                    //; Now DS:BX points to original DTA
456
	INT 21h                   //; Execute interrupt to restore.
457
	MOV DS, DX                //; Restore DS
458
      }
459
      /* copy over volume label, if buffer given */
460
      if (lpVolumeNameBuffer != NULL)
461
      {
462
	if (cflag != 0)    /* error or no label */
463
	  lpVolumeNameBuffer[0] = '\0';
464
	else                        /* copy up to buffer's size of label */
465
	{
466
	  strncpy(lpVolumeNameBuffer, finfo.ff_name, nVolumeNameSize);
467
	  lpVolumeNameBuffer[nVolumeNameSize-1] = '\0';
468
          /* slide characters over if longer than 8 to remove . */
469
          if (lpVolumeNameBuffer[8] == '.')
470
          {
471
            lpVolumeNameBuffer[8] = lpVolumeNameBuffer[9];
472
            lpVolumeNameBuffer[9] = lpVolumeNameBuffer[10];
473
            lpVolumeNameBuffer[10] = lpVolumeNameBuffer[11];
474
            lpVolumeNameBuffer[11] = '\0';
475
          }
476
        }
477
      }
478
      /* Test for no label found, which is not an error,
479
         Note: added the check for 0x02 as FreeDOS returns this instead
480
         at least for disks with LFN entries and no volume label.
481
      */
482
      if ((cflag == 0x12) || /* No more files or   */
483
          (cflag == 0x02))   /* File not found     */
484
        cflag = 0;       /* so assume valid drive  */
485
 
486
 
2026 mateusz.vi 487
      /* Get Serial Number, only supports drives mapped to letters */
2019 mateusz.vi 488
      media.serial = 0;         /* set to 0, stays 0 on an error */
489
 
490
      _BX = (pathname[0] & '\xDF') - 'A' + 1; /* Clear BH, drive in BL */
491
      asm {
492
        LEA DX, media           //; DS:DX pointer to media structure
493
        MOV CX, 0866h           //; CH=disk drive, CL=Get Serial #
494
        MOV AX, 440Dh           //; Generic IOCTL
495
        INT 21h
496
      }
497
 
498
/***************** Replaced with 'documented' version of Get Serial Number *********************/
2026 mateusz.vi 499
      /* NT2000pro does NOT set or clear the carry for int21h subfunction 6900h
2019 mateusz.vi 500
       *   if an error occurs, it leaves media unchanged.
501
       */
502
//      asm {
503
//        MOV AX, 0x6900
504
//        INT 21h                 //; Should set carry on error, clear on success [note NT5 does not]
505
//      }
506
/***************** End with 'undocumented' version of Get Serial Number *********************/
507
 
508
      if (lpVolumeSerialNumber != NULL)
509
        *lpVolumeSerialNumber = media.serial;
510
    }
511
    else /* a network drive, assume results of LFN getVolInfo, no volume or serial [for now] */
512
    {
513
      if (lpVolumeNameBuffer != NULL)
514
        lpVolumeNameBuffer[0] = '\0';
515
 
516
      if (lpVolumeSerialNumber != NULL)
517
        *lpVolumeSerialNumber = 0x0;
518
    }
519
  }
2026 mateusz.vi 520
 
2019 mateusz.vi 521
  /* If there was an error getting the validating drive return failure) */
522
  if (cflag)    /* cflag is nonzero on any errors */
523
    return 0;   /* zero means error! */
524
  else
525
    return 1;   /* Success (drive exists we think anyway) */
526
}
527