Subversion Repositories SvarDOS

Rev

Rev 2044 | Go to most recent revision | Details | Compare with Previous | 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
 
2041 mateusz.vi 34
#include <dos.h>
2019 mateusz.vi 35
#include <stdlib.h>
36
#include <string.h>
37
 
2041 mateusz.vi 38
#include "dosdisk.h"
39
 
2019 mateusz.vi 40
#define searchAttr ( FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | \
41
   FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_ARCHIVE )
42
 
43
 
2026 mateusz.vi 44
/* copy old style findfirst data FFDTA to a WIN32_FIND_DATA
45
 * NOTE: does not map exactly.
2019 mateusz.vi 46
 * internal to this module only.
47
 */
2041 mateusz.vi 48
static void copyFileData(struct WIN32_FIND_DATA *findData, const struct FFDTA *finfo)
2019 mateusz.vi 49
{
50
  /* Copy requried contents over into required structure */
51
  strcpy(findData->cFileName, finfo->ff_name);
2041 mateusz.vi 52
  findData->dwFileAttributes = (DWORD)finfo->ff_attr;
2019 mateusz.vi 53
 
54
  /* copy over rest (not quite properly) */
55
  findData->ftCreationTime.ldw[0] = finfo->ff_ftime;
56
  findData->ftLastAccessTime.ldw[0] = finfo->ff_ftime;
57
  findData->ftLastWriteTime.ldw[0] = finfo->ff_ftime;
58
  findData->ftCreationTime.ldw[1] = finfo->ff_fdate;
59
  findData->ftLastAccessTime.ldw[1] = finfo->ff_fdate;
60
  findData->ftLastWriteTime.ldw[1] = finfo->ff_fdate;
61
  findData->ftCreationTime.hdw = 0;
62
  findData->ftLastAccessTime.hdw = 0;
63
  findData->ftLastWriteTime.hdw = 0;
64
  findData->nFileSizeHigh = 0;
65
  findData->nFileSizeLow = (DWORD)finfo->ff_fsize;
66
  findData->dwReserved0 = 0;
67
  findData->dwReserved1 = 0;
68
}
69
 
2040 mateusz.vi 70
HANDLE FindFirstFile(const char *pathname, struct WIN32_FIND_DATA *findData)
2019 mateusz.vi 71
{
2044 mateusz.vi 72
  static char path[1024];
2019 mateusz.vi 73
  HANDLE hnd;
74
  short cflag = 0;  /* used to indicate if findfirst is succesful or not */
75
 
76
  /* verify findData is valid */
77
  if (findData == NULL)
78
    return INVALID_HANDLE_VALUE;
79
 
80
  /* allocate memory for the handle */
81
  if ((hnd = (HANDLE)malloc(sizeof(struct FindFileStruct))) == NULL)
82
    return INVALID_HANDLE_VALUE;
83
 
84
  /* initialize structure (clear) */
85
  /* hnd->handle = 0;  hnd->ffdtaptr = NULL; */
86
  memset(hnd, 0, sizeof(struct FindFileStruct));
87
 
88
  /* Clear findData, this is to fix a glitch under NT, with 'special' $???? files */
89
  memset(findData, 0, sizeof(struct WIN32_FIND_DATA));
90
 
91
  /* Use DOS (0x4E) findfirst, returning if error */
92
  hnd->flag = FINDFILEOLD;
93
 
94
  /* allocate memory for the FFDTA */
2041 mateusz.vi 95
  if ((hnd->fhnd.ffdtaptr = (struct FFDTA *)malloc(sizeof(struct FFDTA))) == NULL)
2019 mateusz.vi 96
  {
97
    free(hnd);
98
    return INVALID_HANDLE_VALUE;
99
  }
100
 
101
  /* if pathname ends in \* convert to \*.* */
102
  strcpy(path, pathname);
2032 mateusz.vi 103
  {
104
  int eos = strlen(path) - 1;
105
  if ((path[eos] == '*') && (path[eos - 1] == '\\')) strcat(path, ".*");
106
  }
2019 mateusz.vi 107
 
2044 mateusz.vi 108
  {
109
    unsigned short ffdta_seg, ffdta_off;
110
    unsigned short path_seg, path_off;
111
    unsigned short sattr = searchAttr;
112
    ffdta_seg = FP_SEG((*hnd).fhnd.ffdtaptr);
113
    ffdta_off = FP_OFF((*hnd).fhnd.ffdtaptr);
114
    path_seg = FP_SEG(path);
115
    path_off = FP_OFF(path);
116
 
117
  _asm {
118
    push ax
119
    push bx
120
    push cx
121
    push dx
122
    push es
123
 
124
    mov ah, 0x2F                   //; Get Current DTA
125
    int 0x21                       //; Execute interrupt, returned in ES:BX
126
    push bx                        //; Store its Offset, then Segment
127
    push es
128
    mov ah, 0x1A                   //; Set Current DTA to our buffer, DS:DX
129
    mov dx, ffdta_off
130
    push ds
131
    mov ds, ffdta_seg
132
    int 0x21                       //; Execute interrupt
133
    pop ds
134
    mov ax, 0x4E00                 //; Actual findfirst call
135
    mov cx, sattr
136
    mov dx, path_off               //; Load DS:DX with pointer to path for Findfirt
137
    push ds
138
    mov ds, path_seg
139
    int 0x21                       //; Execute interrupt
140
    pop ds
141
    jnc success                    //; If carry is not set then succesful
142
    mov [cflag], ax                //; Set flag with error.
143
success:
144
    mov ah, 0x1A              //; Set Current DTA back to original, DS:DX
145
    mov dx, ds                //; Store DS, must be preserved
146
    pop ds                    //; Popping ES into DS since thats where we need it.
147
    pop bx                    //; Now DS:BX points to original DTA
148
    int 0x21                  //; Execute interrupt to restore.
149
    mov ds, dx                //; Restore DS
150
 
151
    pop es
152
    pop dx
153
    pop cx
154
    pop bx
155
    pop ax
2019 mateusz.vi 156
  }
157
  }
158
 
159
  if (cflag)
160
  {
161
    free(hnd->fhnd.ffdtaptr);
162
    free(hnd);
163
    return INVALID_HANDLE_VALUE;
164
  }
165
 
166
  /* copy its results over */
167
  copyFileData(findData, hnd->fhnd.ffdtaptr);
168
 
169
  return hnd;
170
}
171
 
172
 
2040 mateusz.vi 173
int FindNextFile(HANDLE hnd, struct WIN32_FIND_DATA *findData)
2019 mateusz.vi 174
{
175
  short cflag = 0;  /* used to indicate if dos findnext succesful or not */
176
 
177
  /* if bad handle given return */
178
  if ((hnd == NULL) || (hnd == INVALID_HANDLE_VALUE)) return 0;
179
 
180
  /* verify findData is valid */
181
  if (findData == NULL) return 0;
182
 
183
  /* Clear findData, this is to fix a glitch under NT, with 'special' $???? files */
184
  memset(findData, 0, sizeof(struct WIN32_FIND_DATA));
185
 
186
  /* Flag indicate if using LFN DOS (0x714F) or not */
187
  if (hnd->flag == FINDFILELFN)
188
  {
2044 mateusz.vi 189
    unsigned short handle = hnd->fhnd.handle;
190
    unsigned char cf = 0;
191
    _asm {
192
      push ax
193
      push bx
194
      push cx
195
      push dx
196
      push es
197
      push si
198
      push di
199
 
200
      mov bx, handle               //; Move the Handle returned by prev findfirst into BX
201
      stc                          //; In case not supported
202
      mov si, 1                    //; same format as when old style used, set to 0 for 64bit value
203
      mov ax, ds                   //; Set address of findData into ES:DI
204
      mov es, ax
205
      mov di, [findData]
206
      mov ax, 0x714F               //; LFN version of FindNext
207
      int 0x21                     //; Execute interrupt
208
      jnc DONE
209
      mov cf, 1
210
      DONE:
211
 
212
      pop di
213
      pop si
214
      pop es
215
      pop dx
216
      pop cx
217
      pop bx
218
      pop ax
2019 mateusz.vi 219
    }
2044 mateusz.vi 220
    if (cf == 0) return 1;   /* success */
221
    return 0;   /* Any errors here, no other option but to return error/no more files */
222
  } else { /* Use DOS (0x4F) findnext, returning if error */
223
    unsigned short dta_seg = FP_SEG((*hnd).fhnd.ffdtaptr);
224
    unsigned short dta_off = FP_OFF((*hnd).fhnd.ffdtaptr);
225
    _asm {
226
      push ax
227
      push bx
228
      push cx
229
      push dx
230
      push es
2019 mateusz.vi 231
 
2044 mateusz.vi 232
      mov ah, 0x2F                  //; Get Current DTA
233
      int 0x21                      //; Execute interrupt, returned in ES:BX
234
      push bx                       //; Store its Offset, then Segment
235
      push es
236
      mov ax, 0x1A00                //; Set Current DTA to our buffer, DS:DX
237
      mov dx, dta_off
238
      push ds
239
      mov ds, dta_seg
240
      int 0x21                      //; Execute interrupt
241
      pop ds
242
      mov ax, 0x4F00                //; Actual findnext call
243
      int 0x21                      //; Execute interrupt
2019 mateusz.vi 244
      JNC success                   //; If carry is not set then succesful
2044 mateusz.vi 245
      mov [cflag], ax               //; Set flag with error.
2019 mateusz.vi 246
success:
2044 mateusz.vi 247
      mov ah, 0x1A                  //; Set Current DTA back to original, DS:DX
248
      MOV dx, ds                    //; Store DS, must be preserved
249
      pop ds                        //; Popping ES into DS since thats where we need it.
250
      pop bx                        //; Now DS:BX points to original DTA
251
      int 0x21                      //; Execute interrupt to restore.
252
      mov ds, dx                    //; Restore DS
253
 
254
      pop es
255
      pop dx
256
      pop cx
257
      pop bx
258
      pop ax
2019 mateusz.vi 259
    }
260
 
2044 mateusz.vi 261
  if (cflag) return 0;
2019 mateusz.vi 262
 
263
  /* copy its results over */
264
  copyFileData(findData, hnd->fhnd.ffdtaptr);
265
 
266
  return 1;
267
  }
268
}
269
 
270
 
271
/* free resources to prevent memory leaks */
272
void FindClose(HANDLE hnd)
273
{
274
  /* 1st check if valid handle given */
275
  if ((hnd != NULL) && (hnd != INVALID_HANDLE_VALUE))
276
  {
277
    /* See if its for the new or old style findfirst */
278
    if (hnd->flag == FINDFILEOLD) /* Just free memory allocated */
279
    {
2026 mateusz.vi 280
      if (hnd->fhnd.ffdtaptr != NULL)
2019 mateusz.vi 281
        free(hnd->fhnd.ffdtaptr);
282
      hnd->fhnd.ffdtaptr = NULL;
283
    }
284
    else /* must call LFN findclose */
285
    {
2044 mateusz.vi 286
      unsigned short handle = hnd->fhnd.handle;
287
      _asm {
288
        push ax
289
        push bx
290
 
291
        mov bx, handle            /* Move handle returned from findfirst into BX */
292
        stc
293
        mov ax, 0x71A1
294
        int 0x21                  /* carry set on error */
295
 
296
        pop bx
297
        pop ax
2019 mateusz.vi 298
      }
299
      hnd->fhnd.handle = 0;
300
    }
301
 
302
    free(hnd);                    /* Free memory used for the handle itself */
303
  }
304
}
305
 
306
#include <stdio.h>
307
 
308
/**
309
 Try LFN getVolumeInformation 1st
310
 if successful, assume valid drive/share (ie will return 1 unless error getting label)
311
 if failed (any error other than unsupported) return 0
312
 if a drive (ie a hard drive, ram drive, network mapped to letter) [has : as second letter]
313
 {
314
   try findfirst for volume label. (The LFN api does not seem to support LABEL attribute searches.)
315
     If getVolInfo unsupported but get findfirst succeed, assume valid (ie return 1)
316
   Try Get Serial#
317
 }
318
 else a network give \\server\share and LFN getVol unsupported, assume failed 0, as the
319
   original findfirst/next I haven't seen support UNC naming, clear serial and volume.
320
*** Currently trying to find a way to get a \\server\share 's serial & volume if LFN available ***
321
*/
322
 
2042 mateusz.vi 323
/* returns zero on failure, if lpRootPathName is NULL or "" we use current
324
 * default drive. */
325
int GetVolumeInformation(const char *lpRootPathName, char *lpVolumeNameBuffer,
326
  DWORD nVolumeNameSize, DWORD *lpVolumeSerialNumber) {
327
 
2019 mateusz.vi 328
  /* Using DOS interrupt to get serial number */
2044 mateusz.vi 329
  struct media_info {
2019 mateusz.vi 330
    short dummy;
331
    DWORD serial;
332
    char volume[11];
333
    short ftype[8];
334
  } media;
335
 
336
  /* Stores the root path we use. */
337
  char pathname[260];
338
 
2045 mateusz.vi 339
  unsigned short cflag;
2019 mateusz.vi 340
 
341
  /* validate root path to obtain info on, NULL or "" means use current */
2044 mateusz.vi 342
  if ((lpRootPathName == NULL) || (*lpRootPathName == '\0')) {
2019 mateusz.vi 343
    /* Assume if NULL user wants current drive, eg C:\ */
2044 mateusz.vi 344
    _asm {
345
      push ax
346
      push bx
347
 
348
      mov ah, 0x19            //; Get Current Default Drive
349
      int 0x21                //; returned in AL, 0=A, 1=B,...
350
      lea bx, pathname        //; load pointer to our buffer
351
      add al, 'A'             //; Convert #returned to a letter
352
      mov [bx], al            //; Store drive letter
353
      inc bx                  //; point to next character
354
      mov byte ptr [bx], ':'  //; Store the colon
355
      inc bx
356
      mov byte ptr [bx], '\'  //; this gets converted correctly as a single bkslsh
357
      inc bx
358
      mov byte ptr [bx], 0    //; Most importantly the '\0' terminator
359
 
360
      pop bx
361
      pop ax
2019 mateusz.vi 362
    }
2042 mateusz.vi 363
  } else {
364
    strcpy(pathname, lpRootPathName);
2019 mateusz.vi 365
  }
366
 
2045 mateusz.vi 367
  /* if a drive, test if valid, get volume, and possibly serial # */
368
 
369
  /* assume these calls will succeed, change on an error */
370
  cflag = 0;
371
 
372
  /* get path ending in \*.*, */
373
  if (pathname[strlen(pathname)-1] != '\\') {
374
    strcat(pathname, "\\*.*");
375
  } else {
376
    strcat(pathname, "*.*");
377
  }
378
 
379
  /* Search for volume using old findfirst, as LFN version (NT5 DOS box) does
380
   * not recognize FILE_ATTRIBUTE_LABEL = 0x0008 as label attribute.
381
   */
2019 mateusz.vi 382
  {
2045 mateusz.vi 383
    struct FFDTA finfo;
384
    unsigned short attr_seg = FP_SEG(finfo.ff_attr);
385
    unsigned short attr_off = FP_OFF(finfo.ff_attr);
386
    unsigned short finfo_seg = FP_SEG(&finfo);
387
    unsigned short finfo_off = FP_OFF(&finfo);
388
    unsigned short pathname_seg = FP_SEG(pathname);
389
    unsigned short pathname_off = FP_OFF(pathname);
390
 
2044 mateusz.vi 391
    _asm {
392
      push ax
393
      push bx
394
      push cx
395
      push dx
396
      push es
397
 
2045 mateusz.vi 398
      mov ah, 0x2F              //; Get Current DTA
399
      int 0x21                  //; Execute interrupt, returned in ES:BX
400
      push bx                   //; Store its Offset, then Segment
401
      push es
402
      mov ah, 0x1A              //; Set Current DTA to our buffer, DS:DX
403
      mov dx, finfo_off         //; Load our buffer for new DTA.
404
      push ds
405
      mov ds, finfo_seg
406
      int 0x21                  //; Execute interrupt
407
      pop ds
408
      mov ax, 0x4E00            //; Actual findfirst call
409
      mov cx, FILE_ATTRIBUTE_LABEL
410
      mov dx, pathname_off      //; Load DS:DX with pointer to modified RootPath for Findfirt
411
      push ds
412
      mov ds, pathname_seg
413
      int 0x21                  //; Execute interrupt, Carry set on error, unset on success
414
      pop ds
415
      jnc success               //; If carry is not set then succesful
416
      mov [cflag], ax           //; Set flag with error.
417
      jmp cleanup               //; Restore DTA
418
    success:                    //; True volume entry only has volume attribute set [MS' LFNspec]
419
      mov bx, attr_off
420
      push es
421
      mov es, attr_seg
422
      mov al, [es:bx]              //; Looking for a BYTE that is FILE_ATTRIBUTE_LABEL only
423
      pop es
424
      and al, 0xDF              //; Ignore Archive bit
425
      cmp al, FILE_ATTRIBUTE_LABEL
426
      je cleanup                //; They match, so should be true volume entry.
427
      mov ax, 0x4F00            //; Otherwise keep looking (findnext)
428
      int 0x21                  //; Execute interrupt
429
      jnc success               //; If carry is not set then succesful
430
      mov [cflag], ax           //; Set flag with error.
431
    cleanup:
432
      mov ah, 0x1A              //; Set Current DTA back to original, DS:DX
433
      mov dx, ds                //; Store DS, must be preserved
434
      pop ds                    //; Popping ES into DS since thats where we need it.
435
      pop bx                    //; Now DS:BX points to original DTA
436
      int 0x21                  //; Execute interrupt to restore.
437
      mov ds, dx                //; Restore DS
2019 mateusz.vi 438
 
2044 mateusz.vi 439
      pop es
440
      pop dx
441
      pop cx
442
      pop bx
443
      pop ax
2019 mateusz.vi 444
    }
445
 
2045 mateusz.vi 446
    /* copy over volume label, if buffer given */
447
    if (lpVolumeNameBuffer != NULL) {
448
      if (cflag != 0) {  /* error or no label */
449
        lpVolumeNameBuffer[0] = '\0';
450
      } else {                      /* copy up to buffer's size of label */
451
        strncpy(lpVolumeNameBuffer, finfo.ff_name, nVolumeNameSize);
452
        lpVolumeNameBuffer[nVolumeNameSize-1] = '\0';
453
        /* slide characters over if longer than 8 to remove . */
454
        if (lpVolumeNameBuffer[8] == '.') {
455
          lpVolumeNameBuffer[8] = lpVolumeNameBuffer[9];
456
          lpVolumeNameBuffer[9] = lpVolumeNameBuffer[10];
457
          lpVolumeNameBuffer[10] = lpVolumeNameBuffer[11];
458
          lpVolumeNameBuffer[11] = '\0';
2019 mateusz.vi 459
        }
460
      }
2045 mateusz.vi 461
    }
462
  }
2019 mateusz.vi 463
 
2045 mateusz.vi 464
  /* Test for no label found, which is not an error,
465
     Note: added the check for 0x02 as FreeDOS returns this instead
466
     at least for disks with LFN entries and no volume label.
467
  */
468
  if ((cflag == 0x12) || /* No more files or   */
469
      (cflag == 0x02)) {  /* File not found     */
470
    cflag = 0;       /* so assume valid drive  */
471
  }
2019 mateusz.vi 472
 
2045 mateusz.vi 473
  /* Get Serial Number, only supports drives mapped to letters */
474
  media.serial = 0;         /* set to 0, stays 0 on an error */
475
  {
476
    unsigned short media_off = FP_OFF(&media);
477
    unsigned short media_seg = FP_SEG(&media);
478
    unsigned char drv = (pathname[0] & 0xDF) - 'A' + 1;
479
    _asm {
480
      push ax
481
      push bx
482
      push cx
483
      push dx
2019 mateusz.vi 484
 
2045 mateusz.vi 485
      xor bh, bh
486
      mov bl, drv             //; Clear BH, drive in BL
487
      mov cx, 0x0866          //; CH=disk drive, CL=Get Serial #
488
      mov ax, 0x440D          //; Generic IOCTL
489
      mov dx, media_off       //; DS:DX pointer to media structure
490
      push ds
491
      mov ds, media_seg
492
      int 0x21
493
      pop ds
2044 mateusz.vi 494
 
2045 mateusz.vi 495
      pop dx
496
      pop cx
497
      pop bx
498
      pop ax
2019 mateusz.vi 499
    }
500
  }
2026 mateusz.vi 501
 
2045 mateusz.vi 502
  if (lpVolumeSerialNumber != NULL) *lpVolumeSerialNumber = media.serial;
503
 
2019 mateusz.vi 504
  /* If there was an error getting the validating drive return failure) */
2045 mateusz.vi 505
  if (cflag) {  /* cflag is nonzero on any errors )*/
2019 mateusz.vi 506
    return 0;   /* zero means error! */
2045 mateusz.vi 507
  } else {
2019 mateusz.vi 508
    return 1;   /* Success (drive exists we think anyway) */
2045 mateusz.vi 509
  }
2019 mateusz.vi 510
}
511
 
2041 mateusz.vi 512
 
513
/* retrieve attributes (ReadOnly/System/...) about file or directory
514
 * returns (DWORD)-1 on error
515
 */
516
DWORD GetFileAttributes(const char *pathname) {
517
  union REGS r;
518
  struct SREGS s;
519
  char buffer[260];
520
  int slen;
521
 
522
  /* we must remove any slashes from end */
523
  slen = strlen(pathname) - 1;  /* Warning, assuming pathname is not ""   */
524
  strcpy(buffer, pathname);
2045 mateusz.vi 525
  if ((buffer[slen] == '\\') || (buffer[slen] == '/')) { /* ends in a slash */
2041 mateusz.vi 526
    /* don't remove from root directory (slen == 0),
527
     * ignore UNC paths as SFN doesn't handle them anyway
528
     * if slen == 2, then check if drive given (e.g. C:\)
529
     */
530
    if (slen && !(slen == 2 &&  buffer[1] == ':'))
531
      buffer[slen] = '\0';
532
  }
533
  /* return standard attributes */
534
  r.x.ax = 0x4300;                  /* standard Get/Set File Attributes */
535
  r.x.dx = FP_OFF(buffer);          /* DS:DX points to ASCIIZ filename      */
536
  segread(&s);                      /* load with current segment values     */
537
  s.ds = FP_SEG(buffer);            /* get Segment of our filename pointer  */
538
  intdosx(&r, &r, &s);              /* invoke the DOS int21h call           */
539
 
540
  //if (r.x.cflag) printf("ERROR getting std attributes of %s, DOS err %i\n", buffer, r.x.ax);
541
  if (r.x.cflag) return (DWORD)-1;  /* error obtaining attributes           */
542
  return (DWORD)(0x3F & r.x.cx); /* mask off any DRDOS bits     */
543
}