Subversion Repositories SvarDOS

Rev

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