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