Subversion Repositories SvarDOS

Rev

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