Subversion Repositories SvarDOS

Rev

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