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