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