source: trunk/src/helpers/dosh2.c@ 147

Last change on this file since 147 was 142, checked in by umoeller, 23 years ago

misc. updates

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 75.8 KB
Line 
1
2/*
3 *@@sourcefile dosh2.c:
4 * dosh.c contains more Control Program helper functions.
5 *
6 * This file is new with V0.9.4 (2000-07-26) [umoeller].
7 *
8 * As opposed to the functions in dosh.c, these require
9 * linking against other helpers. As a result, these have
10 * been separated from dosh.c to allow linking against
11 * dosh.obj only.
12 *
13 * Function prefixes:
14 * -- dosh* Dos (Control Program) helper functions
15 *
16 * This has the same header as dosh.c, dosh.h.
17 *
18 * The partition functions in this file are based on
19 * code which has kindly been provided by Dmitry A. Steklenev.
20 * See doshGetPartitionsList for how to use these.
21 *
22 * Note: Version numbering in this file relates to XWorkplace version
23 * numbering.
24 *
25 *@@header "helpers\dosh.h"
26 *@@added V0.9.4 (2000-07-27) [umoeller]
27 */
28
29/*
30 * This file Copyright (C) 1997-2000 Ulrich M”ller,
31 * Dmitry A. Steklenev.
32 * This file is part of the "XWorkplace helpers" source package.
33 * This is free software; you can redistribute it and/or modify
34 * it under the terms of the GNU General Public License as published
35 * by the Free Software Foundation, in version 2 as it comes in the
36 * "COPYING" file of the XWorkplace main distribution.
37 * This program is distributed in the hope that it will be useful,
38 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 * GNU General Public License for more details.
41 */
42
43#define OS2EMX_PLAIN_CHAR
44 // this is needed for "os2emx.h"; if this is defined,
45 // emx will define PSZ as _signed_ char, otherwise
46 // as unsigned char
47
48#define INCL_DOSMODULEMGR
49#define INCL_DOSPROCESS
50#define INCL_DOSSESMGR
51#define INCL_DOSQUEUES
52#define INCL_DOSMISC
53#define INCL_DOSDEVICES
54#define INCL_DOSDEVIOCTL
55#define INCL_DOSERRORS
56#include <os2.h>
57
58#include <stdlib.h>
59#include <string.h>
60#include <stdio.h>
61#include <ctype.h>
62
63#include "setup.h" // code generation and debugging options
64
65#include "helpers\dosh.h"
66#include "helpers\ensure.h"
67#include "helpers\nls.h"
68#include "helpers\standards.h"
69#include "helpers\stringh.h"
70
71#pragma hdrstop
72
73/*
74 *@@category: Helpers\Control program helpers\Miscellaneous
75 */
76
77/* ******************************************************************
78 *
79 * Miscellaneous
80 *
81 ********************************************************************/
82
83/*
84 *@@ doshIsValidFileName:
85 * this returns NO_ERROR only if pszFile is a valid file name.
86 * This may include a full path.
87 *
88 * If a drive letter is specified, this checks for whether
89 * that drive is a FAT drive and adjust the checks accordingly,
90 * i.e. 8+3 syntax (per path component).
91 *
92 * If no drive letter is specified, this check is performed
93 * for the current drive.
94 *
95 * This also checks if pszFileNames contains characters which
96 * are invalid for the current drive.
97 *
98 * Note: this performs syntactic checks only. This does not
99 * check for whether the specified path components exist.
100 * However, it _is_ checked for whether the given drive
101 * exists.
102 *
103 * This func is especially useful to check filenames that
104 * have been entered by the user in a "Save as" dialog.
105 *
106 * If an error is found, the corresponding DOS error code
107 * is returned:
108 * -- ERROR_INVALID_DRIVE
109 * -- ERROR_FILENAME_EXCED_RANGE (on FAT: no 8+3 filename)
110 * -- ERROR_INVALID_NAME (invalid character)
111 * -- ERROR_CURRENT_DIRECTORY (if fFullyQualified: no full path specified)
112 *
113 *@@changed V0.9.2 (2000-03-11) [umoeller]: added fFullyQualified
114 */
115
116APIRET doshIsValidFileName(const char* pcszFile,
117 BOOL fFullyQualified) // in: if TRUE, pcszFile must be fully q'fied
118{
119 APIRET arc = NO_ERROR;
120 CHAR szPath[CCHMAXPATH+4] = " :";
121 CHAR szComponent[CCHMAXPATH];
122 PSZ p1, p2;
123 BOOL fIsFAT = FALSE;
124 PSZ pszInvalid;
125
126 if (fFullyQualified) // V0.9.2 (2000-03-11) [umoeller]
127 {
128 if ( (*(pcszFile + 1) != ':')
129 || (*(pcszFile + 2) != '\\')
130 )
131 arc = ERROR_CURRENT_DIRECTORY;
132 }
133
134 // check drive first
135 if (*(pcszFile + 1) == ':')
136 {
137 CHAR cDrive = toupper(*pcszFile);
138 double d;
139 // drive specified:
140 strcpy(szPath, pcszFile);
141 szPath[0] = toupper(*pcszFile);
142 arc = doshQueryDiskFree(cDrive - 'A' + 1, &d);
143 }
144 else
145 {
146 // no drive specified: take current
147 ULONG ulDriveNum = 0,
148 ulDriveMap = 0;
149 arc = DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
150 szPath[0] = ((UCHAR)ulDriveNum) + 'A' - 1;
151 szPath[1] = ':';
152 strcpy(&szPath[2], pcszFile);
153 }
154
155 if (arc == NO_ERROR)
156 {
157 fIsFAT = doshIsFileOnFAT(szPath);
158
159 pszInvalid = (fIsFAT)
160 ? "<>|+=:;,\"/[] " // invalid characters in FAT
161 : "<>|:\"/"; // invalid characters in IFS's
162
163 // now separate path components
164 p1 = &szPath[2]; // advance past ':'
165
166 do {
167
168 if (*p1 == '\\')
169 p1++;
170
171 p2 = strchr(p1, '\\');
172 if (p2 == NULL)
173 p2 = p1 + strlen(p1);
174
175 if (p1 != p2)
176 {
177 LONG lDotOfs = -1,
178 lAfterDot = -1;
179 ULONG cbFile,
180 ul;
181 PSZ pSource = szComponent;
182
183 strncpy(szComponent, p1, p2-p1);
184 szComponent[p2-p1] = 0;
185 cbFile = strlen(szComponent);
186
187 // now check each path component
188 for (ul = 0; ul < cbFile; ul++)
189 {
190 if (fIsFAT)
191 {
192 // on FAT: only 8 characters allowed before dot
193 if (*pSource == '.')
194 {
195 lDotOfs = ul;
196 lAfterDot = 0;
197 if (ul > 7)
198 return (ERROR_FILENAME_EXCED_RANGE);
199 }
200 }
201 // and check for invalid characters
202 if (strchr(pszInvalid, *pSource) != NULL)
203 return (ERROR_INVALID_NAME);
204
205 pSource++;
206
207 // on FAT, allow only three chars after dot
208 if (fIsFAT)
209 if (lAfterDot != -1)
210 {
211 lAfterDot++;
212 if (lAfterDot > 3)
213 return (ERROR_FILENAME_EXCED_RANGE);
214 }
215 }
216
217 // we are still missing the case of a FAT file
218 // name without extension; if so, check whether
219 // the file stem is <= 8 chars
220 if (fIsFAT)
221 if (lDotOfs == -1) // dot not found:
222 if (cbFile > 8)
223 return (ERROR_FILENAME_EXCED_RANGE);
224 }
225
226 // go for next component
227 p1 = p2+1;
228 } while (*p2);
229 }
230
231 return (arc);
232}
233
234/*
235 *@@ doshMakeRealName:
236 * this copies pszSource to pszTarget, replacing
237 * all characters which are not supported by file
238 * systems with cReplace.
239 *
240 * pszTarget must be at least the same size as pszSource.
241 * If (fIsFAT), the file name will be made FAT-compliant (8+3).
242 *
243 * Returns TRUE if characters were replaced.
244 *
245 *@@changed V0.9.0 (99-11-06) [umoeller]: now replacing "*" too
246 */
247
248BOOL doshMakeRealName(PSZ pszTarget, // out: new real name
249 PSZ pszSource, // in: filename to translate
250 CHAR cReplace, // in: replacement char for invalid
251 // characters (e.g. '!')
252 BOOL fIsFAT) // in: make-FAT-compatible flag
253{
254 ULONG ul,
255 cbSource = strlen(pszSource);
256 LONG lDotOfs = -1,
257 lAfterDot = -1;
258 BOOL brc = FALSE;
259 PSZ pSource = pszSource,
260 pTarget = pszTarget;
261
262 const char *pcszInvalid = (fIsFAT)
263 ? "*<>|+=:;,\"/\\[] " // invalid characters in FAT
264 : "*<>|:\"/\\"; // invalid characters in IFS's
265
266 for (ul = 0; ul < cbSource; ul++)
267 {
268 if (fIsFAT)
269 {
270 // on FAT: truncate filename if neccessary
271 if (*pSource == '.')
272 {
273 lDotOfs = ul;
274 lAfterDot = 0;
275 if (ul > 7) {
276 // only 8 characters allowed before dot,
277 // so set target ptr to dot pos
278 pTarget = pszTarget+8;
279 }
280 }
281 }
282 // and replace invalid characters
283 if (strchr(pcszInvalid, *pSource) == NULL)
284 *pTarget = *pSource;
285 else
286 {
287 *pTarget = cReplace;
288 brc = TRUE;
289 }
290 pTarget++;
291 pSource++;
292
293 // on FAT, allow only three chars after dot
294 if (fIsFAT)
295 if (lAfterDot != -1)
296 {
297 lAfterDot++;
298 if (lAfterDot > 3)
299 break;
300 }
301 }
302 *pTarget = '\0';
303
304 if (fIsFAT)
305 {
306 // we are still missing the case of a FAT file
307 // name without extension; if so, check whether
308 // the file stem is <= 8 chars
309 if (lDotOfs == -1) // dot not found:
310 if (cbSource > 8)
311 *(pszTarget+8) = 0; // truncate
312
313 // convert to upper case
314 strupr(pszTarget);
315 }
316
317 return (brc);
318}
319
320/*
321 *@@ doshSetCurrentDir:
322 * sets the current working directory
323 * to the given path.
324 *
325 * As opposed to DosSetCurrentDir, this
326 * one will change the current drive
327 * also, if one is specified.
328 *
329 *@@changed V0.9.9 (2001-04-04) [umoeller]: this returned an error even if none occured, fixed
330 */
331
332APIRET doshSetCurrentDir(const char *pcszDir)
333{
334 APIRET arc = NO_ERROR;
335 if (!pcszDir)
336 return (ERROR_INVALID_PARAMETER);
337 {
338 if (*pcszDir != 0)
339 if (*(pcszDir+1) == ':')
340 {
341 // drive given:
342 CHAR cDrive = toupper(*(pcszDir));
343 // change drive
344 arc = DosSetDefaultDisk( (ULONG)(cDrive - 'A' + 1) );
345 // 1 = A:, 2 = B:, ...
346 }
347
348 arc = DosSetCurrentDir((PSZ)pcszDir);
349 }
350
351 return (arc); // V0.9.9 (2001-04-04) [umoeller]
352}
353
354/*
355 *@@ CopyToBuffer:
356 * little helper for copying a string to
357 * a target buffer with length checking.
358 *
359 * Returns:
360 *
361 * -- NO_ERROR
362 *
363 * -- ERROR_BUFFER_OVERFLOW if pszTarget does
364 * not have enough room to hold pcszSource
365 * (including the null terminator).
366 *
367 *@@added V0.9.16 (2001-10-08) [umoeller]
368 */
369
370static APIRET CopyToBuffer(PSZ pszTarget, // out: target buffer
371 PCSZ pcszSource, // in: source string
372 ULONG cbTarget) // in: size of target buffer
373{
374 ULONG ulLength = strlen(pcszSource);
375 if (ulLength < cbTarget)
376 {
377 memcpy(pszTarget,
378 pcszSource,
379 ulLength + 1);
380 return (NO_ERROR);
381 }
382
383 return(ERROR_BUFFER_OVERFLOW);
384}
385
386/*
387 *@@ doshSearchPath:
388 * replacement for DosSearchPath.
389 *
390 * This looks along all directories which are
391 * specified in the value of the given environment
392 * variable if pcszFile is found.
393 *
394 * As opposed to the stupid DosSearchPath, this
395 * ignores subdirectories in the path particles.
396 * For example, DosSearchPath would usually not
397 * find an INSTALL file because \OS2 contains
398 * an INSTALL directory, or NETSCAPE because
399 * \OS2\INSTALL contains a NETSCAPE directory.
400 *
401 * Returns:
402 *
403 * -- NO_ERROR: pszExecutable has received the
404 * full path of pcszFile.
405 *
406 * -- ERROR_FILE_NOT_FOUND: pcszFile was not found
407 * in the specified path (or is a directory).
408 *
409 * -- ERROR_BUFFER_OVERFLOW: pcszFile was found, but
410 * the pszExecutable buffer is too small to hold
411 * the full path.
412 *
413 *@@added V0.9.16 (2001-10-08) [umoeller]
414 */
415
416APIRET doshSearchPath(const char *pcszPath, // in: path variable name (e.g. "PATH")
417 const char *pcszFile, // in: file to look for (e.g. "LVM.EXE")
418 PSZ pszExecutable, // out: full path (e.g. "F:\os2\lvm.exe")
419 ULONG cbExecutable) // in: sizeof (*pszExecutable)
420{
421 APIRET arc = NO_ERROR;
422
423 // get the PATH value
424 PCSZ pcszPathValue;
425 if (!(arc = DosScanEnv((PSZ)pcszPath,
426#if __cplusplus
427 &pcszPathValue)))
428#else
429 (PSZ*)&pcszPathValue)))
430#endif
431 {
432 // run thru the path components
433 PSZ pszPathCopy;
434 if (pszPathCopy = strdup(pcszPathValue))
435 {
436 PSZ pszToken = strtok(pszPathCopy, ";");
437 while (pszToken)
438 {
439 CHAR szFileMask[2*CCHMAXPATH];
440 FILESTATUS3 fs3;
441
442 sprintf(szFileMask,
443 "%s\\%s",
444 pszToken, // path particle
445 pcszFile); // e.g. "netscape"
446
447 if ( (!(arc = DosQueryPathInfo(szFileMask,
448 FIL_STANDARD,
449 &fs3,
450 sizeof(fs3))))
451 // make sure it's not a directory
452 // and that it's not hidden
453 && (!(fs3.attrFile & (FILE_DIRECTORY | FILE_HIDDEN)))
454 )
455 {
456 // copy
457 arc = CopyToBuffer(pszExecutable,
458 szFileMask,
459 cbExecutable);
460 // and stop
461 break;
462 }
463 else
464 arc = ERROR_FILE_NOT_FOUND;
465 // and search on
466
467 pszToken = strtok(NULL, ";");
468 };
469
470 free(pszPathCopy);
471 }
472 else
473 arc = ERROR_NOT_ENOUGH_MEMORY;
474 }
475
476 return (arc);
477}
478
479/*
480 * FindFile:
481 * helper for doshFindExecutable.
482 *
483 *added V0.9.11 (2001-04-25) [umoeller]
484 *@@changed V0.9.16 (2001-10-08) [umoeller]: rewrote second half for DosSearchPath replacement, which returns directories too
485 */
486
487static APIRET FindFile(const char *pcszCommand, // in: command (e.g. "lvm")
488 PSZ pszExecutable, // out: full path (e.g. "F:\os2\lvm.exe")
489 ULONG cbExecutable) // in: sizeof (*pszExecutable)
490{
491 APIRET arc = NO_ERROR;
492 FILESTATUS3 fs3;
493
494 if ( (strchr(pcszCommand, '\\'))
495 || (strchr(pcszCommand, ':'))
496 )
497 {
498 // looks like this is qualified:
499 arc = DosQueryPathInfo((PSZ)pcszCommand,
500 FIL_STANDARD,
501 &fs3,
502 sizeof(fs3));
503 if (!arc)
504 if (!(fs3.attrFile & FILE_DIRECTORY))
505 arc = CopyToBuffer(pszExecutable,
506 pcszCommand,
507 cbExecutable);
508 else
509 // directory:
510 arc = ERROR_INVALID_EXE_SIGNATURE;
511 }
512 else
513 {
514 // non-qualified:
515 /* arc = DosSearchPath(SEARCH_IGNORENETERRS
516 | SEARCH_ENVIRONMENT
517 | SEARCH_CUR_DIRECTORY,
518 "PATH",
519 (PSZ)pcszCommand,
520 pszExecutable,
521 cbExecutable); */
522 // The above is not useable. It returns directories
523 // on the path... for example, it returns \OS2\INSTALL\NETSCAPE
524 // if netscape is looked for. So we search manually... sigh.
525 // V0.9.16 (2001-10-08) [umoeller]
526 arc = doshSearchPath("PATH",
527 pcszCommand,
528 pszExecutable,
529 cbExecutable);
530 }
531
532 return (arc);
533}
534
535/*
536 *@@ doshFindExecutable:
537 * this attempts to find an executable by doing the
538 * following:
539 *
540 * 1) If pcszCommand appears to be qualified (i.e. contains
541 * a backslash), this checks for whether the file exists.
542 * If it is a directory, ERROR_INVALID_EXE_SIGNATURE is
543 * returned.
544 *
545 * 2) If pcszCommand contains no backslash, this searches
546 * all directories on the PATH in order to find the full
547 * path of the executable. Starting with V0.9.16, we
548 * use doshSearchPath for that.
549 *
550 * papcszExtensions determines if additional searches are to be
551 * performed if the file doesn't exist (case 1) or doshSearchPath
552 * returned ERROR_FILE_NOT_FOUND (case 2).
553 * This must point to an array of strings specifying the extra
554 * extensions to search for.
555 *
556 * If both papcszExtensions and cExtensions are null, no
557 * extra searches are performed.
558 *
559 * Returns:
560 *
561 * -- NO_ERROR: pszExecutable has received the full path of
562 * the executable found by DosSearchPath.
563 *
564 * -- ERROR_FILE_NOT_FOUND
565 *
566 * -- ERROR_BUFFER_OVERFLOW: pcszCommand was found, but
567 * the pszExecutable buffer is too small to hold
568 * the full path.
569 *
570 * Example:
571 *
572 + const char *aExtensions[] = { "EXE",
573 + "COM",
574 + "CMD"
575 + };
576 + CHAR szExecutable[CCHMAXPATH];
577 + APIRET arc = doshFindExecutable("lvm",
578 + szExecutable,
579 + sizeof(szExecutable),
580 + aExtensions,
581 + 3);
582 *
583 *@@added V0.9.9 (2001-03-07) [umoeller]
584 *@@changed V0.9.11 (2001-04-25) [umoeller]: this never worked for qualified pcszCommand's, fixed
585 */
586
587APIRET doshFindExecutable(const char *pcszCommand, // in: command (e.g. "lvm")
588 PSZ pszExecutable, // out: full path (e.g. "F:\os2\lvm.exe")
589 ULONG cbExecutable, // in: sizeof (*pszExecutable)
590 const char **papcszExtensions, // in: array of extensions (without dots)
591 ULONG cExtensions) // in: array item count
592{
593 APIRET arc = FindFile(pcszCommand,
594 pszExecutable,
595 cbExecutable);
596
597 if ( (arc == ERROR_FILE_NOT_FOUND) // not found?
598 && (cExtensions) // any extra searches wanted?
599 )
600 {
601 // try additional things then
602 PSZ psz2 = (PSZ)malloc(strlen(pcszCommand) + 20);
603 if (psz2)
604 {
605 ULONG ul;
606 for (ul = 0;
607 ul < cExtensions;
608 ul++)
609 {
610 const char *pcszExtThis = papcszExtensions[ul];
611 sprintf(psz2,
612 "%s.%s",
613 pcszCommand,
614 pcszExtThis);
615 arc = FindFile(psz2,
616 pszExecutable,
617 cbExecutable);
618 if (arc != ERROR_FILE_NOT_FOUND)
619 break;
620 }
621
622 free(psz2);
623 }
624 else
625 arc = ERROR_NOT_ENOUGH_MEMORY;
626 }
627
628 return (arc);
629}
630
631/*
632 *@@category: Helpers\Control program helpers\Partitions info
633 * functions for retrieving partition information directly
634 * from the partition tables on the disk. See doshGetPartitionsList.
635 */
636
637/********************************************************************
638 *
639 * Partition functions
640 *
641 ********************************************************************/
642
643/*
644 *@@ doshQueryDiskCount:
645 * returns the no. of physical disks installed
646 * on the system.
647 *
648 *@@added V0.9.0 [umoeller]
649 */
650
651UINT doshQueryDiskCount(VOID)
652{
653 USHORT usCount = 0;
654 DosPhysicalDisk(INFO_COUNT_PARTITIONABLE_DISKS, &usCount, 2, 0, 0);
655 return (usCount);
656}
657
658/*
659 *@@ doshType2FSName:
660 * this returns a static, zero-terminated string
661 * for the given FS type, or NULL if the type
662 * is unknown.
663 *
664 *@@added V0.9.0 [umoeller]
665 *@@changed V0.9.16 (2001-10-08) [umoeller]: rewritten
666 */
667
668const char* doshType2FSName(unsigned char bFSType) // in: FS type
669{
670 switch (bFSType)
671 {
672 case 0x00: return "empty";
673 case 0x01: return "DOS 12-bit FAT < 10 Mb";
674 case 0x02: return "XENIX root file system";
675 case 0x03: return "XENIX /usr file system (obsolete)";
676 case 0x04: return "DOS 16-bit FAT < 32 Mb";
677 case 0x05: return "DOS 3.3+ extended partition";
678 case 0x06: return "DOS 3.31+ 16-bit FAT > 32 Mb";
679 case 0x07: return "HPFS/NTFS/QNX/Advanced Unix";
680 case 0x08: return "OS/2 1.0-1.3/AIX/Commodore/DELL";
681 case 0x09: return "AIX data/Coherent";
682 case 0x0A: return "OS/2 Boot Manager/OPUS/Coherent Swap";
683 case 0x0B: return "Windows95 with 32-bit FAT";
684 case 0x0C: return "Windows95 with 32-bit FAT (LBA)";
685 case 0x0E: return "Windows 95 VFAT (06h plus LBA)";
686 case 0x0F: return "Windows 95 VFAT (05h plus LBA)";
687 case 0x10: return "OPUS";
688 case 0x11: return "OS/2 Boot Manager hidden 12-bit FAT";
689 case 0x12: return "Compaq Diagnostics";
690 case 0x14: return "OS/2 Boot Manager hidden sub-32M 16-bit FAT";
691 case 0x16: return "OS/2 Boot Manager hidden over-32M 16-bit FAT";
692 case 0x17: return "OS/2 Boot Manager hidden HPFS";
693 case 0x18: return "AST special Windows swap file (\"Zero-Volt Suspend\")";
694 // case 0x21: reserved
695 // case 0x23: reserved
696 case 0x24: return "NEC MS-DOS 3.x";
697 // case 0x26: reserved
698 // case 0x31: reserved
699 // case 0x33: reserved
700 // case 0x34: reserved
701 // case 0x36: reserved
702 case 0x38: return "Theos";
703 case 0x3C: return "PowerQuest PartitionMagic recovery partition";
704 case 0x40: return "VENIX 80286";
705 case 0x41: return "Personal RISC Boot";
706 case 0x42: return "SFS (Secure File System) by Peter Gutmann";
707 case 0x50: return "OnTrack Disk Manager, read-only";
708 case 0x51: return "OnTrack Disk Manager, read/write";
709 case 0x52: return "CP/M or Microport System V/386";
710 case 0x53: return "OnTrack Disk Manager, write-only???";
711 case 0x54: return "OnTrack Disk Manager (DDO)";
712 case 0x56: return "GoldenBow VFeature";
713 case 0x61: return "SpeedStor";
714 case 0x63: return "Unix SysV/386, 386/ix or Mach, MtXinu BSD 4.3 on Mach or GNU HURD";
715 case 0x64: return "Novell NetWare 286";
716 case 0x65: return "Novell NetWare (3.11)";
717 case 0x67:
718 case 0x68:
719 case 0x69: return "Novell";
720 case 0x70: return "DiskSecure Multi-Boot";
721 // case 0x71: reserved
722 // case 0x73: reserved
723 // case 0x74: reserved
724 case 0x75: return "PC/IX";
725 // case 0x76: reserved
726 case 0x80: return "Minix v1.1 - 1.4a";
727 case 0x81: return "Minix v1.4b+ or Linux or Mitac Advanced Disk Manager";
728 case 0x82: return "Linux Swap or Prime";
729 case 0x83: return "Linux native file system (ext2fs/xiafs)";
730 case 0x84: return "OS/2-renumbered type 04h (hidden DOS C: drive)";
731 case 0x86: return "FAT16 volume/stripe set (Windows NT)";
732 case 0x87: return "HPFS Fault-Tolerant mirrored partition or NTFS volume/stripe set";
733 case 0x93: return "Amoeba file system";
734 case 0x94: return "Amoeba bad block table";
735 case 0xA0: return "Phoenix NoteBIOS Power Management \"Save-to-Disk\" partition";
736 // case 0xA1: reserved
737 // case 0xA3: reserved
738 // case 0xA4: reserved
739 case 0xA5: return "FreeBSD, BSD/386";
740 // case 0xA6: reserved
741 // case 0xB1: reserved
742 // case 0xB3: reserved
743 // case 0xB4: reserved
744 // case 0xB6: reserved
745 case 0xB7: return "BSDI file system (secondarily swap)";
746 case 0xB8: return "BSDI swap (secondarily file system)";
747 case 0xC1: return "DR DOS 6.0 LOGIN.EXE-secured 12-bit FAT";
748 case 0xC4: return "DR DOS 6.0 LOGIN.EXE-secured 16-bit FAT";
749 case 0xC6: return "DR DOS 6.0 LOGIN.EXE-secured Huge partition or NT corrupted FAT16 volume/stripe set";
750 case 0xC7: return "Syrinx Boot or corrupted NTFS volume/stripe set";
751 case 0xD8: return "CP/M-86";
752 case 0xDB: return "CP/M, Concurrent CP/M, Concurrent DOS, Convergent Technologies OS";
753 case 0xE1: return "SpeedStor 12-bit FAT extended partition";
754 case 0xE3: return "DOS read-only or Storage Dimensions";
755 case 0xE4: return "SpeedStor 16-bit FAT extended partition";
756 // case 0xE5: reserved
757 // case 0xE6: reserved
758 case 0xF1: return "Storage Dimensions";
759 case 0xF2: return "DOS 3.3+ secondary partition";
760 // case 0xF3: reserved
761 case 0xF4: return "SpeedStor or Storage Dimensions";
762 // case 0xF6: reserved
763 case 0xFE: return "LANstep or IBM PS/2 IML";
764 case 0xFF: return "Xenix bad block table";
765 }
766
767 return NULL;
768}
769
770/*
771 * AppendPartition:
772 * this appends the given partition information to
773 * the given partition list. To do this, a new
774 * PARTITIONINFO structure is created and appended
775 * in a list (managed thru the PARTITIONINFO.pNext
776 * items).
777 *
778 * pppiThis must be a pointer to a pointer to a PARTITIONINFO.
779 * With each call of this function, this pointer is advanced
780 * to point to the newly created PARTITIONINFO, so before
781 * calling this function for the first time,
782 *
783 *@@added V0.9.0 [umoeller]
784 */
785
786static APIRET AppendPartition(PARTITIONINFO **pppiFirst,
787 PARTITIONINFO **pppiThis, // in/out: partition info; pointer will be advanced
788 PUSHORT posCount, // in/out: partition count
789 BYTE bDisk, // in: disk of partition
790 const char *pszBootName, // in: boot partition name
791 CHAR cLetter, // in/out: drive letter
792 BYTE bFsType, // in: file system type
793 BOOL fPrimary, // in: primary?
794 BOOL fBootable,
795 ULONG ulSectors) // in: no. of sectors
796{
797 APIRET arc = NO_ERROR;
798 PPARTITIONINFO ppiNew = NEW(PARTITIONINFO);
799 if (ppiNew)
800 {
801 ZERO(ppiNew);
802
803 // store data
804 ppiNew->bDisk = bDisk;
805 if ((fBootable) && (pszBootName) )
806 {
807 memcpy(ppiNew->szBootName, pszBootName, 8);
808 ppiNew->szBootName[8] = 0;
809 }
810 else
811 ppiNew->szBootName[0] = 0;
812 ppiNew->cLetter = cLetter;
813 ppiNew->bFSType = bFsType;
814 ppiNew->pcszFSType = doshType2FSName(bFsType);
815 ppiNew->fPrimary = fPrimary;
816 ppiNew->fBootable = fBootable;
817 ppiNew->ulSize = ulSectors / 2048;
818
819 ppiNew->pNext = NULL;
820
821 (*posCount)++;
822
823 if (*pppiFirst == (PPARTITIONINFO)NULL)
824 {
825 // first call:
826 *pppiFirst = ppiNew;
827 *pppiThis = ppiNew;
828 }
829 else
830 {
831 // append to list
832 (**pppiThis).pNext = ppiNew;
833 *pppiThis = ppiNew;
834 }
835 }
836 else
837 arc = ERROR_NOT_ENOUGH_MEMORY;
838
839 return (arc);
840}
841
842#ifndef __XWPLITE__
843
844/*
845 *@@ doshReadSector:
846 * reads a physical disk sector.
847 *
848 * If NO_ERROR is returned, the sector contents
849 * have been stored in *buff.
850 *
851 * Originally contributed by Dmitry A. Steklenev.
852 *
853 *@@added V0.9.0 [umoeller]
854 *@@changed V0.9.9 (2001-04-04) [umoeller]: added more error checking
855 */
856
857APIRET doshReadSector(USHORT disk, // in: physical disk no. (1, 2, 3, ...)
858 void *buff,
859 USHORT head,
860 USHORT cylinder,
861 USHORT sector)
862{
863 APIRET arc;
864 HFILE dh = 0;
865 char dn[256];
866
867 sprintf(dn, "%u:", disk);
868 if (!(arc = DosPhysicalDisk(INFO_GETIOCTLHANDLE, &dh, 2, dn, 3)))
869 {
870 TRACKLAYOUT DiskIOParm;
871 ULONG IOCtlDataLength = sizeof(DiskIOParm);
872 ULONG IOCtlParmLength = 512;
873
874 DiskIOParm.bCommand = 0;
875 DiskIOParm.usHead = head;
876 DiskIOParm.usCylinder = cylinder;
877 DiskIOParm.usFirstSector = 0;
878 DiskIOParm.cSectors = 1;
879 DiskIOParm.TrackTable[0].usSectorNumber = sector;
880 DiskIOParm.TrackTable[0].usSectorSize = 512;
881
882 arc = DosDevIOCtl(dh,
883 IOCTL_PHYSICALDISK, PDSK_READPHYSTRACK,
884 &DiskIOParm, IOCtlParmLength, &IOCtlParmLength,
885 buff , IOCtlDataLength, &IOCtlDataLength);
886
887 DosPhysicalDisk(INFO_FREEIOCTLHANDLE, 0, 0, &dh, 2);
888 }
889
890 return (arc);
891}
892
893// Sector and Cylinder values are actually 6 bits and 10 bits:
894//
895// 1 1 1 1 1 1
896// Ú5Â4Â3Â2Â1Â0Â9Â8Â7Â6Â5Â4Â3Â2Â1ÂÄ¿
897// ³c c c c c c c c C c S s s s s s³
898// ÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙ
899//
900// The high two bits of the second byte are used as the high bits
901// of a 10-bit value. This allows for as many as 1024 cylinders
902// and 64 sectors per cylinder.
903
904/*
905 * GetCyl:
906 * get cylinder number.
907 *
908 * Originally contributed by Dmitry A. Steklenev.
909 *
910 *@@added V0.9.0 [umoeller]
911 */
912
913static USHORT GetCyl(USHORT rBeginSecCyl)
914{
915 return ( (rBeginSecCyl & 0x00C0) << 2)
916 + ((rBeginSecCyl & 0xFF00) >> 8);
917}
918
919/*
920 * GetSec:
921 * get sector number.
922 *
923 * Originally contributed by Dmitry A. Steklenev.
924 *
925 *@@added V0.9.0 [umoeller]
926 */
927
928static USHORT GetSec(USHORT rBeginSecCyl)
929{
930 return rBeginSecCyl & 0x003F;
931}
932
933/*
934 *@@ doshGetBootManager:
935 * this goes thru the master boot records on all
936 * disks to find the boot manager partition.
937 *
938 * Returns:
939 *
940 * -- NO_ERROR: boot manager found; in that case,
941 * information about the boot manager
942 * is written into *pusDisk, *pusPart,
943 * *BmInfo. Any of these pointers can
944 * be NULL if you're not interested.
945 *
946 * -- ERROR_NOT_SUPPORTED (50): boot manager not installed.
947 *
948 * Originally contributed by Dmitry A. Steklenev.
949 *
950 *@@added V0.9.0 [umoeller]
951 */
952
953APIRET doshGetBootManager(USHORT *pusDisk, // out: if != NULL, boot manager disk (1, 2, ...)
954 USHORT *pusPart, // out: if != NULL, index of bmgr primary partition (0-3)
955 PAR_INFO *pBmInfo) // out: if != NULL, boot manager partition info
956{
957 APIRET arc = NO_ERROR;
958 USHORT count = doshQueryDiskCount(); // Physical disk number
959 MBR_INFO MBoot; // Master Boot
960 USHORT usDisk;
961
962 if (count > 8) // Not above 8 disks
963 count = 8;
964
965 for (usDisk = 1; usDisk <= count; usDisk++)
966 {
967 USHORT usPrim = 0;
968
969 // for each disk, read the MBR, which has the
970 // primary partitions
971 if ((arc = doshReadSector(usDisk,
972 &MBoot,
973 0, // head
974 0, // cylinder
975 1))) // sector
976 return (arc);
977
978 // scan primary partitions for whether
979 // BootManager partition exists
980 for (usPrim = 0; usPrim < 4; usPrim++)
981 {
982 if (MBoot.sPrtnInfo[usPrim].bFileSysCode == 0x0A)
983 {
984 // this is boot manager:
985 if (pBmInfo)
986 *pBmInfo = MBoot.sPrtnInfo[usPrim];
987 if (pusPart)
988 *pusPart = usPrim;
989 if (pusDisk)
990 *pusDisk = usDisk;
991 // stop scanning
992 return (NO_ERROR);
993 }
994 }
995 }
996
997 return (ERROR_NOT_SUPPORTED);
998}
999
1000/*
1001 * GetPrimaryPartitions:
1002 * this returns the primary partitions.
1003 *
1004 * This gets called from doshGetPartitionsList.
1005 *
1006 * Returns:
1007 *
1008 * -- ERROR_INVALID_PARAMETER: BMInfo is NULL.
1009 *
1010 * Originally contributed by Dmitry A. Steklenev.
1011 *
1012 *@@added V0.9.0 [umoeller]
1013 */
1014
1015static APIRET GetPrimaryPartitions(PARTITIONINFO **pppiFirst,
1016 PARTITIONINFO **pppiThis,
1017 PUSHORT posCount, // in/out: partition count
1018 PCHAR pcLetter, // in/out: drive letter counter
1019 UINT BmDisk, // in: physical disk (1, 2, 3, ...) of boot manager or null
1020 PAR_INFO* pBmInfo, // in: info returned by doshGetBootManager or NULL
1021 UINT iDisk) // in: system's physical disk count
1022{
1023 APIRET arc = NO_ERROR;
1024
1025 if (!pBmInfo)
1026 arc = ERROR_INVALID_PARAMETER;
1027 else
1028 {
1029 SYS_INFO MName[32]; // Name Space from Boot Manager
1030 memset(&MName, 0, sizeof(MName));
1031
1032 // read boot manager name table;
1033 // this is in the boot manager primary partition
1034 // at sector offset 3 (?!?)
1035 if (!(arc = doshReadSector(BmDisk,
1036 &MName,
1037 // head, cylinder, sector of bmgr primary partition:
1038 pBmInfo->bBeginHead,
1039 GetCyl(pBmInfo->rBeginSecCyl),
1040 GetSec(pBmInfo->rBeginSecCyl) + 3)))
1041 {
1042 // got bmgr name table:
1043 MBR_INFO MBoot; // Master Boot
1044 USHORT i;
1045
1046 // read master boot record of this disk
1047 if (!(arc = doshReadSector(iDisk,
1048 &MBoot,
1049 0, // head
1050 0, // cylinder
1051 1))) // sector
1052 {
1053 for (i = 0;
1054 i < 4; // there can be only four primary partitions
1055 i++)
1056 {
1057 // skip unused partition, BootManager or Extended partition
1058 if ( (MBoot.sPrtnInfo[i].bFileSysCode) // skip unused
1059 && (MBoot.sPrtnInfo[i].bFileSysCode != 0x0A) // skip boot manager
1060 && (MBoot.sPrtnInfo[i].bFileSysCode != 0x05) // skip extended partition
1061 )
1062 {
1063 BOOL fBootable = ( (pBmInfo)
1064 && (MName[(iDisk-1) * 4 + i].bootable & 0x01)
1065 );
1066 // store this partition
1067 if ((arc = AppendPartition(pppiFirst,
1068 pppiThis,
1069 posCount,
1070 iDisk,
1071 (fBootable)
1072 ? (char*)&MName[(iDisk - 1) * 4 + i].name
1073 : "",
1074 *pcLetter,
1075 MBoot.sPrtnInfo[i].bFileSysCode,
1076 TRUE, // primary
1077 fBootable,
1078 MBoot.sPrtnInfo[i].lTotalSects)))
1079 return (arc);
1080 }
1081 }
1082 }
1083 }
1084 }
1085
1086 return (arc);
1087}
1088
1089/*
1090 * GetLogicalDrives:
1091 * this returns info for the logical drives
1092 * in the extended partition. This gets called
1093 * from GetExtendedPartition.
1094 *
1095 * This gets called from GetExtendedPartition.
1096 *
1097 * Originally contributed by Dmitry A. Steklenev.
1098 *
1099 *@@added V0.9.0 [umoeller]
1100 */
1101
1102static APIRET GetLogicalDrives(PARTITIONINFO **pppiFirst,
1103 PARTITIONINFO **pppiThis,
1104 PUSHORT posCount,
1105 PCHAR pcLetter,
1106 PAR_INFO* PrInfo, // in: MBR entry of extended partition
1107 UINT PrDisk,
1108 PAR_INFO* BmInfo)
1109{
1110 APIRET arc = NO_ERROR;
1111 EXT_INFO MBoot; // Master Boot
1112 USHORT i;
1113
1114 if ((arc = doshReadSector(PrDisk,
1115 &MBoot,
1116 PrInfo->bBeginHead,
1117 GetCyl(PrInfo->rBeginSecCyl),
1118 GetSec(PrInfo->rBeginSecCyl))))
1119 return (arc);
1120
1121 for (i = 0; i < 4; i++)
1122 {
1123 // skip unused partition or BootManager partition
1124 if ( (MBoot.sPrtnInfo[i].bFileSysCode)
1125 && (MBoot.sPrtnInfo[i].bFileSysCode != 0x0A)
1126 )
1127 {
1128 BOOL fBootable = FALSE;
1129 BOOL fAssignLetter = FALSE;
1130
1131 // special work around extended partition
1132 if (MBoot.sPrtnInfo[i].bFileSysCode == 0x05)
1133 {
1134 if ((arc = GetLogicalDrives(pppiFirst,
1135 pppiThis,
1136 posCount,
1137 pcLetter,
1138 &MBoot.sPrtnInfo[i],
1139 PrDisk,
1140 BmInfo)))
1141 return (arc);
1142
1143 continue;
1144 }
1145
1146 // raise driver letter if OS/2 would recognize this drive
1147 if ( (MBoot.sPrtnInfo[i].bFileSysCode < 0x75)
1148 )
1149 fAssignLetter = TRUE;
1150
1151 if (fAssignLetter)
1152 (*pcLetter)++;
1153
1154 fBootable = ( (BmInfo)
1155 && ((MBoot.sBmNames[i].bootable & 0x01) != 0)
1156 );
1157
1158 if ((arc = AppendPartition(pppiFirst,
1159 pppiThis,
1160 posCount,
1161 PrDisk,
1162 (fBootable)
1163 ? (char*)&MBoot.sBmNames[i].name
1164 : "",
1165 (fAssignLetter)
1166 ? *pcLetter
1167 : ' ',
1168 MBoot.sPrtnInfo[i].bFileSysCode,
1169 FALSE, // primary
1170 fBootable, // bootable
1171 MBoot.sPrtnInfo[i].lTotalSects)))
1172 return (arc);
1173 }
1174 }
1175
1176 return (NO_ERROR);
1177}
1178
1179/*
1180 * GetExtendedPartition:
1181 * this finds the extended partition on the given
1182 * drive and calls GetLogicalDrives in turn.
1183 *
1184 * This gets called from doshGetPartitionsList.
1185 *
1186 * Originally contributed by Dmitry A. Steklenev.
1187 *
1188 *@@added V0.9.0 [umoeller]
1189 */
1190
1191static APIRET GetExtendedPartition(PARTITIONINFO **pppiFirst,
1192 PARTITIONINFO **pppiThis,
1193 PUSHORT posCount,
1194 PCHAR pcLetter,
1195 PAR_INFO* BmInfo,
1196 UINT iDisk) // in: disk to query
1197{
1198 APIRET arc = NO_ERROR;
1199 MBR_INFO MBoot; // Master Boot
1200 USHORT i;
1201
1202 if ((arc = doshReadSector(iDisk, &MBoot, 0, 0, 1)))
1203 return (arc);
1204
1205 // go thru MBR entries to find extended partition
1206 for (i = 0;
1207 i < 4;
1208 i++)
1209 {
1210 if (MBoot.sPrtnInfo[i].bFileSysCode == 0x05)
1211 {
1212 if ((arc = GetLogicalDrives(pppiFirst,
1213 pppiThis,
1214 posCount,
1215 pcLetter,
1216 &MBoot.sPrtnInfo[i],
1217 iDisk,
1218 BmInfo)))
1219 return (arc);
1220 }
1221 }
1222
1223 return (NO_ERROR);
1224}
1225
1226/*
1227 *@@ ReadFDiskPartitions:
1228 * helper for doshGetPartitionsList for non-LVM
1229 * systems.
1230 *
1231 * Originally contributed by Dmitry A. Steklenev.
1232 *
1233 *@@added V0.9.16 (2001-10-08) [umoeller]
1234 */
1235
1236static APIRET ReadFDiskPartitions(PARTITIONINFO **ppPartitionInfos,
1237 USHORT *pcPartitions,
1238 PUSHORT pusContext) // out: error context
1239{
1240 APIRET arc = NO_ERROR;
1241
1242 PAR_INFO BmInfo; // BootManager partition
1243 USHORT usBmDisk; // BootManager disk
1244 USHORT cDisks = doshQueryDiskCount(); // physical disks count
1245 USHORT i;
1246
1247 CHAR cLetter = 'C'; // first drive letter
1248
1249 PARTITIONINFO *ppiTemp = NULL;
1250
1251 if (cDisks > 8) // Not above 8 disks
1252 cDisks = 8;
1253
1254 // get boot manager disk and info
1255 if ((arc = doshGetBootManager(&usBmDisk,
1256 NULL,
1257 &BmInfo)) != NO_ERROR)
1258 {
1259 *pusContext = 1;
1260 }
1261 else
1262 {
1263 // on each disk, read primary partitions
1264 for (i = 1; i <= cDisks; i++)
1265 {
1266 if ((arc = GetPrimaryPartitions(ppPartitionInfos,
1267 &ppiTemp,
1268 pcPartitions,
1269 &cLetter,
1270 usBmDisk,
1271 usBmDisk ? &BmInfo : 0,
1272 i)))
1273 {
1274 *pusContext = 2;
1275 }
1276 }
1277
1278 if (!arc && usBmDisk)
1279 {
1280 // boot manager found:
1281 // on each disk, read extended partition
1282 // with logical drives
1283 for (i = 1; i <= cDisks; i++)
1284 {
1285 if ((arc = GetExtendedPartition(ppPartitionInfos,
1286 &ppiTemp,
1287 pcPartitions,
1288 &cLetter,
1289 &BmInfo,
1290 i)))
1291 {
1292 *pusContext = 3;
1293 }
1294 }
1295 }
1296 } // end else if ((arc = doshGetBootManager(&usBmDisk,
1297
1298 return (arc);
1299}
1300
1301#endif
1302
1303/*
1304 *@@ CleanPartitionInfos:
1305 *
1306 *@@added V0.9.9 (2001-04-07) [umoeller]
1307 */
1308
1309static VOID CleanPartitionInfos(PPARTITIONINFO ppiThis)
1310{
1311 while (ppiThis)
1312 {
1313 PPARTITIONINFO ppiNext = ppiThis->pNext;
1314 free(ppiThis);
1315 ppiThis = ppiNext;
1316 }
1317}
1318
1319/*
1320 *@@ doshGetPartitionsList:
1321 * this returns lots of information about the
1322 * partitions on all physical disks, which is
1323 * read directly from the MBRs and partition
1324 * tables.
1325 *
1326 * If NO_ERROR is returned by this function,
1327 * *ppPartitionInfo points to a linked list of
1328 * PARTITIONINFO structures, which has
1329 * *pusPartitionCount items.
1330 *
1331 * In that case, use doshFreePartitionsList to
1332 * free the resources allocated by this function.
1333 *
1334 * What this function returns depends on whether
1335 * LVM is installed.
1336 *
1337 * -- If LVM.DLL is found on the LIBPATH, this opens
1338 * the LVM engine and returns the info from the
1339 * LVM engine in the PARTITIONINFO structures.
1340 * The partitions are then sorted by disk in
1341 * ascending order.
1342 *
1343 * -- Otherwise, we parse the partition tables
1344 * manually. The linked list then starts out with
1345 * all the primary partitions, followed by the
1346 * logical drives in the extended partitions.
1347 * This function attempts to guess the correct drive
1348 * letters and stores these with the PARTITIONINFO
1349 * items, but there's no guarantee that this is
1350 * correct. We correctly ignore Linux partitions here
1351 * and give all primary partitions the C: letter, but
1352 * I have no idea what happens with NTFS partitions,
1353 * since I have none.
1354 *
1355 * If an error != NO_ERROR is returned, *pusContext
1356 * will be set to one of the following:
1357 *
1358 * -- 1: boot manager not found
1359 *
1360 * -- 2: primary partitions error
1361 *
1362 * -- 3: secondary partitions error
1363 *
1364 * -- 0: something else.
1365 *
1366 * Originally contributed by Dmitry A. Steklenev.
1367 *
1368 *@@added V0.9.0 [umoeller]
1369 *@@changed V0.9.9 (2001-04-07) [umoeller]: added transparent LVM support; changed prototype
1370 *@@changed V0.9.9 (2001-04-07) [umoeller]: fixed memory leaks on errors
1371 */
1372
1373APIRET doshGetPartitionsList(PPARTITIONSLIST *ppList,
1374 PUSHORT pusContext) // out: error context
1375{
1376 APIRET arc = NO_ERROR;
1377
1378 PLVMINFO pLVMInfo = NULL;
1379
1380 PARTITIONINFO *pPartitionInfos = NULL; // linked list of all partitions
1381 USHORT cPartitions = 0; // bootable partition count
1382
1383 if (!ppList)
1384 return (ERROR_INVALID_PARAMETER);
1385
1386 if (!(arc = doshQueryLVMInfo(&pLVMInfo)))
1387 {
1388 // LVM installed:
1389 arc = doshReadLVMPartitions(pLVMInfo, // in: LVM info
1390 &pPartitionInfos, // out: partitions array
1391 &cPartitions); // out: partitions count
1392 // copied to output below
1393
1394 if (arc)
1395 {
1396 // error: start over
1397 doshFreeLVMInfo(pLVMInfo);
1398 CleanPartitionInfos(pPartitionInfos);
1399 pPartitionInfos = NULL;
1400 cPartitions = 0;
1401 }
1402 }
1403
1404#ifndef __XWPLITE__
1405 if (arc)
1406 // LVM not installed, or failed:
1407 // parse partitions manually
1408 arc = ReadFDiskPartitions(&pPartitionInfos,
1409 &cPartitions,
1410 pusContext);
1411#endif
1412
1413 if (!arc)
1414 {
1415 // no error so far:
1416 *pusContext = 0;
1417
1418 *ppList = NEW(PARTITIONSLIST);
1419 if (!(*ppList))
1420 arc = ERROR_NOT_ENOUGH_MEMORY;
1421 else
1422 {
1423 ZERO(*ppList);
1424
1425 (*ppList)->pPartitionInfo = pPartitionInfos;
1426 (*ppList)->cPartitions = cPartitions;
1427
1428 _Pmpf((__FUNCTION__ ": returning %d partitions", cPartitions));
1429 }
1430 }
1431
1432 if (arc)
1433 CleanPartitionInfos(pPartitionInfos);
1434
1435 _Pmpf((__FUNCTION__ ": exiting, arc = %d", arc));
1436
1437 return (arc);
1438}
1439
1440/*
1441 *@@ doshFreePartitionsList:
1442 * this frees the resources allocated by
1443 * doshGetPartitionsList.
1444 *
1445 *@@added V0.9.0 [umoeller]
1446 */
1447
1448APIRET doshFreePartitionsList(PPARTITIONSLIST ppList)
1449{
1450 if (!ppList)
1451 return (ERROR_INVALID_PARAMETER);
1452 else
1453 {
1454 CleanPartitionInfos(ppList->pPartitionInfo);
1455 doshFreeLVMInfo(ppList->pLVMInfo);
1456 free(ppList);
1457 }
1458
1459 return (NO_ERROR);
1460}
1461
1462/********************************************************************
1463 *
1464 * LVM declarations
1465 *
1466 ********************************************************************/
1467
1468/*
1469 *@@category: Helpers\Control program helpers\Partitions info\Quick LVM Interface
1470 * functions for transparently interfacing LVM.DLL.
1471 */
1472
1473typedef unsigned char BOOLEAN;
1474typedef unsigned short int CARDINAL16;
1475typedef unsigned long CARDINAL32;
1476typedef unsigned int CARDINAL;
1477typedef unsigned long DoubleWord;
1478
1479#ifdef ADDRESS
1480#undef ADDRESS
1481#endif
1482
1483typedef void* ADDRESS;
1484
1485#pragma pack(1)
1486
1487#define DISK_NAME_SIZE 20
1488#define FILESYSTEM_NAME_SIZE 20
1489#define PARTITION_NAME_SIZE 20
1490#define VOLUME_NAME_SIZE 20
1491
1492/*
1493 *@@ Drive_Control_Record:
1494 * invariant for a disk drive.
1495 *
1496 *@@added V0.9.9 (2001-04-07) [umoeller]
1497 */
1498
1499typedef struct _Drive_Control_Record
1500{
1501 CARDINAL32 Drive_Number; // OS/2 Drive Number for this drive.
1502 CARDINAL32 Drive_Size; // The total number of sectors on the drive.
1503 DoubleWord Drive_Serial_Number; // The serial number assigned to this drive. For info. purposes only.
1504 ADDRESS Drive_Handle; // Handle used for operations on the disk that this record corresponds to.
1505 CARDINAL32 Cylinder_Count; // The number of cylinders on the drive.
1506 CARDINAL32 Heads_Per_Cylinder; // The number of heads per cylinder for this drive.
1507 CARDINAL32 Sectors_Per_Track; // The number of sectors per track for this drive.
1508 BOOLEAN Drive_Is_PRM; // Set to TRUE if this drive is a PRM.
1509 BYTE Reserved[3]; // Alignment.
1510} Drive_Control_Record;
1511
1512/*
1513 *@@ Drive_Control_Array:
1514 * returned by the Get_Drive_Control_Data function
1515 *
1516 *@@added V0.9.9 (2001-04-07) [umoeller]
1517 */
1518
1519typedef struct _Drive_Control_Array
1520{
1521 Drive_Control_Record * Drive_Control_Data; // An array of drive control records.
1522 CARDINAL32 Count; // The number of entries in the array of drive control records.
1523} Drive_Control_Array;
1524
1525/*
1526 *@@ Drive_Information_Record:
1527 * defines the information that can be changed for a specific disk drive.
1528 *
1529 *@@added V0.9.9 (2001-04-07) [umoeller]
1530 */
1531
1532typedef struct _Drive_Information_Record
1533{
1534 CARDINAL32 Total_Available_Sectors; // The number of sectors on the disk which are not currently assigned to a partition.
1535 CARDINAL32 Largest_Free_Block_Of_Sectors; // The number of sectors in the largest contiguous block of available sectors.
1536 BOOLEAN Corrupt_Partition_Table; // If TRUE, then the partitioning information found on the drive is incorrect!
1537 BOOLEAN Unusable; // If TRUE, the drive's MBR is not accessible and the drive can not be partitioned.
1538 BOOLEAN IO_Error; // If TRUE, then the last I/O operation on this drive failed!
1539 BOOLEAN Is_Big_Floppy; // If TRUE, then the drive is a PRM formatted as a big floppy (i.e. the old style removable media support).
1540 char Drive_Name[DISK_NAME_SIZE]; // User assigned name for this disk drive.
1541} Drive_Information_Record;
1542
1543/*
1544 *@@ Partition_Information_Record:
1545 *
1546 *@@added V0.9.9 (2001-04-07) [umoeller]
1547 */
1548
1549typedef struct _Partition_Information_Record
1550{
1551 ADDRESS Partition_Handle;
1552 // The handle used to perform operations on this partition.
1553 ADDRESS Volume_Handle;
1554 // If this partition is part of a volume, this will be the handle of
1555 // the volume. If this partition is NOT part of a volume, then this
1556 // handle will be 0.
1557 ADDRESS Drive_Handle;
1558 // The handle for the drive this partition resides on.
1559 DoubleWord Partition_Serial_Number;
1560 // The serial number assigned to this partition.
1561 CARDINAL32 Partition_Start;
1562 // The LBA of the first sector of the partition.
1563 CARDINAL32 True_Partition_Size;
1564 // The total number of sectors comprising the partition.
1565 CARDINAL32 Usable_Partition_Size;
1566 // The size of the partition as reported to the IFSM. This is the
1567 // size of the partition less any LVM overhead.
1568 CARDINAL32 Boot_Limit;
1569 // The maximum number of sectors from this block of free space that
1570 // can be used to create a bootable partition if you allocate from the
1571 // beginning of the block of free space.
1572 BOOLEAN Spanned_Volume;
1573 // TRUE if this partition is part of a multi-partition volume.
1574 BOOLEAN Primary_Partition;
1575 // True or False. Any non-zero value here indicates that this partition
1576 // is a primary partition. Zero here indicates that this partition is
1577 // a "logical drive" - i.e. it resides inside of an extended partition.
1578 BYTE Active_Flag;
1579 // 80 = Partition is marked as being active.
1580 // 0 = Partition is not active.
1581 BYTE OS_Flag;
1582 // This field is from the partition table. It is known as the OS flag,
1583 // the Partition Type Field, Filesystem Type, and various other names.
1584 // Values of interest
1585 // If this field is: (values are in hex)
1586 // 07 = The partition is a compatibility partition formatted for use
1587 // with an installable filesystem, such as HPFS or JFS.
1588 // 00 = Unformatted partition
1589 // 01 = FAT12 filesystem is in use on this partition.
1590 // 04 = FAT16 filesystem is in use on this partition.
1591 // 0A = OS/2 Boot Manager Partition
1592 // 35 = LVM partition
1593 // 84 = OS/2 FAT16 partition which has been relabeled by Boot Manager to "Hide" it.
1594 BYTE Partition_Type;
1595 // 0 = Free Space
1596 // 1 = LVM Partition (Part of an LVM Volume.)
1597 // 2 = Compatibility Partition
1598 // All other values are reserved for future use.
1599 BYTE Partition_Status;
1600 // 0 = Free Space
1601 // 1 = In Use - i.e. already assigned to a volume.
1602 // 2 = Available - i.e. not currently assigned to a volume.
1603 BOOLEAN On_Boot_Manager_Menu;
1604 // Set to TRUE if this partition is not part of a Volume yet is on the
1605 // Boot Manager Menu.
1606 BYTE Reserved;
1607 // Alignment.
1608 char Volume_Drive_Letter;
1609 // The drive letter assigned to the volume that this partition is a part of.
1610 char Drive_Name[DISK_NAME_SIZE];
1611 // User assigned name for this disk drive.
1612 char File_System_Name[FILESYSTEM_NAME_SIZE];
1613 // The name of the filesystem in use on this partition, if it is known.
1614 char Partition_Name[PARTITION_NAME_SIZE];
1615 // The user assigned name for this partition.
1616 char Volume_Name[VOLUME_NAME_SIZE];
1617 // If this partition is part of a volume, then this will be the
1618 // name of the volume that this partition is a part of. If this
1619 // record represents free space, then the Volume_Name will be
1620 // "FREE SPACE xx", where xx is a unique numeric ID generated by
1621 // LVM.DLL. Otherwise it will be an empty string.
1622} Partition_Information_Record;
1623
1624// The following defines are for use with the Partition_Type field in the
1625// Partition_Information_Record.
1626#define FREE_SPACE_PARTITION 0
1627#define LVM_PARTITION 1
1628#define COMPATIBILITY_PARTITION 2
1629
1630// The following defines are for use with the Partition_Status field in the
1631// Partition_Information_Record.
1632#define PARTITION_IS_IN_USE 1
1633#define PARTITION_IS_AVAILABLE 2
1634#define PARTITION_IS_FREE_SPACE 0
1635
1636/*
1637 *@@ Partition_Information_Array:
1638 * returned by various functions in the LVM Engine.
1639 *
1640 *@@added V0.9.9 (2001-04-07) [umoeller]
1641 */
1642
1643typedef struct _Partition_Information_Array
1644{
1645 Partition_Information_Record * Partition_Array; // An array of Partition_Information_Records.
1646 CARDINAL32 Count; // The number of entries in the Partition_Array.
1647} Partition_Information_Array;
1648
1649/*
1650 *@@ Volume_Information_Record:
1651 * variable information for a volume.
1652 *
1653 *@@added V0.9.9 (2001-04-07) [umoeller]
1654 */
1655
1656typedef struct _Volume_Information_Record
1657{
1658 CARDINAL32 Volume_Size;
1659 // The number of sectors comprising the volume.
1660 CARDINAL32 Partition_Count;
1661 // The number of partitions which comprise this volume.
1662 CARDINAL32 Drive_Letter_Conflict;
1663 // 0 indicates that the drive letter preference for this volume is unique.
1664 // 1 indicates that the drive letter preference for this volume
1665 // is not unique, but this volume got its preferred drive letter anyway.
1666 // 2 indicates that the drive letter preference for this volume
1667 // is not unique, and this volume did NOT get its preferred drive letter.
1668 // 4 indicates that this volume is currently "hidden" - i.e. it has
1669 // no drive letter preference at the current time.
1670 BOOLEAN Compatibility_Volume;
1671 // TRUE if this is for a compatibility volume, FALSE otherwise.
1672 BOOLEAN Bootable;
1673 // Set to TRUE if this volume appears on the Boot Manager menu, or if it is
1674 // a compatibility volume and its corresponding partition is the first active
1675 // primary partition on the first drive.
1676 char Drive_Letter_Preference;
1677 // The drive letter that this volume desires to be.
1678 char Current_Drive_Letter;
1679 // The drive letter currently used to access this volume.
1680 // May be different than Drive_Letter_Preference if there was a conflict ( i.e. Drive_Letter_Preference
1681 // is already in use by another volume ).
1682 char Initial_Drive_Letter;
1683 // The drive letter assigned to this volume by the operating system
1684 // when LVM was started. This may be different from the
1685 // Drive_Letter_Preference if there were conflicts, and
1686 // may be different from the Current_Drive_Letter. This
1687 // will be 0x0 if the Volume did not exist when the LVM Engine
1688 // was opened (i.e. it was created during this LVM session).
1689 BOOLEAN New_Volume;
1690 // Set to FALSE if this volume existed before the LVM Engine was
1691 // opened. Set to TRUE if this volume was created after the LVM
1692 // Engine was opened.
1693 BYTE Status;
1694 // 0 = None.
1695 // 1 = Bootable
1696 // 2 = Startable
1697 // 3 = Installable.
1698 BYTE Reserved_1;
1699 char Volume_Name[VOLUME_NAME_SIZE];
1700 // The user assigned name for this volume.
1701 char File_System_Name[FILESYSTEM_NAME_SIZE];
1702 // The name of the filesystem in use on this partition, if it
1703 // is known.
1704} Volume_Information_Record;
1705
1706#pragma pack()
1707
1708/********************************************************************
1709 *
1710 * Quick LVM Interface API
1711 *
1712 ********************************************************************/
1713
1714/*
1715 *@@ LVMINFOPRIVATE:
1716 * private structure used by doshQueryLVMInfo.
1717 * This is what the LVMINFO pointer really
1718 * points to.
1719 *
1720 *@@added V0.9.9 (2001-04-07) [umoeller]
1721 */
1722
1723typedef struct _LVMINFOPRIVATE
1724{
1725 LVMINFO LVMInfo; // public structure (dosh.h)
1726
1727 // function pointers resolved from LVM.DLL
1728
1729 void (* _System Open_LVM_Engine)(BOOLEAN Ignore_CHS,
1730 CARDINAL32 *Error_Code);
1731
1732 void (* _System Free_Engine_Memory)(ADDRESS Object);
1733
1734 void (* _System Close_LVM_Engine)(void);
1735
1736 Drive_Control_Array (* _System
1737 Get_Drive_Control_Data)(CARDINAL32 *Error_Code);
1738
1739 Drive_Information_Record (* _System
1740 Get_Drive_Status)(ADDRESS Drive_Handle,
1741 CARDINAL32 *Error_Code);
1742
1743 Partition_Information_Array (* _System
1744 Get_Partitions)(ADDRESS Handle,
1745 CARDINAL32 *Error_Code);
1746
1747 Volume_Information_Record (*_System
1748 Get_Volume_Information)(ADDRESS Volume_Handle,
1749 CARDINAL32 *Error_Code);
1750
1751} LVMINFOPRIVATE, *PLVMINFOPRIVATE;
1752
1753#define LVM_ERROR_FIRST 20000
1754
1755/*
1756 *@@ doshQueryLVMInfo:
1757 * creates an LVMINFO structure if LVM is installed.
1758 * Returns that structure (which the caller must free
1759 * using doshFreeLVMInfo) or NULL if LVM.DLL was not
1760 * found along the LIBPATH.
1761 *
1762 *@@added V0.9.9 (2001-04-07) [umoeller]
1763 */
1764
1765APIRET doshQueryLVMInfo(PLVMINFO *ppLVMInfo)
1766{
1767 APIRET arc = NO_ERROR;
1768 CHAR szError[100];
1769 PLVMINFOPRIVATE pLVMInfo = NULL;
1770 HMODULE hmodLVM = NULLHANDLE;
1771
1772 if (!(arc = DosLoadModule(szError,
1773 sizeof(szError),
1774 "LVM",
1775 &hmodLVM)))
1776 {
1777 // got LVM.DLL:
1778 pLVMInfo = NEW(LVMINFOPRIVATE);
1779 if (!pLVMInfo)
1780 arc = ERROR_NOT_ENOUGH_MEMORY;
1781 else
1782 {
1783 // array of function pointers to be resolved from LVM.DLL
1784 RESOLVEFUNCTION aFunctions[] =
1785 {
1786 "Open_LVM_Engine", (PFN*)&pLVMInfo->Open_LVM_Engine,
1787 "Free_Engine_Memory", (PFN*)&pLVMInfo->Free_Engine_Memory,
1788 "Close_LVM_Engine", (PFN*)&pLVMInfo->Close_LVM_Engine,
1789 "Get_Drive_Control_Data", (PFN*)&pLVMInfo->Get_Drive_Control_Data,
1790 "Get_Drive_Status", (PFN*)&pLVMInfo->Get_Drive_Status,
1791 "Get_Partitions", (PFN*)&pLVMInfo->Get_Partitions,
1792 "Get_Volume_Information", (PFN*)&pLVMInfo->Get_Volume_Information
1793 };
1794 ULONG ul;
1795
1796 ZERO(pLVMInfo);
1797
1798 pLVMInfo->LVMInfo.hmodLVM = hmodLVM;
1799
1800 // now resolve function pointers
1801 for (ul = 0;
1802 ul < ARRAYITEMCOUNT(aFunctions);
1803 ul++)
1804 {
1805 PRESOLVEFUNCTION pFuncThis = &aFunctions[ul];
1806 arc = DosQueryProcAddr(hmodLVM,
1807 0, // ordinal, ignored
1808 (PSZ)pFuncThis->pcszFunctionName,
1809 pFuncThis->ppFuncAddress);
1810 if (!pFuncThis->ppFuncAddress)
1811 arc = ERROR_INVALID_NAME;
1812
1813 if (arc)
1814 break;
1815 }
1816 }
1817 }
1818
1819 if (arc)
1820 doshFreeLVMInfo((PLVMINFO)pLVMInfo);
1821 else
1822 *ppLVMInfo = (PLVMINFO)pLVMInfo;
1823
1824 return (arc);
1825}
1826
1827/*
1828 *@@ doshReadLVMPartitions:
1829 * using the LVMINFO parameter from doshQueryLVMInfo,
1830 * builds an array of PARTITIONINFO structures with
1831 * the data returned from LVM.DLL.
1832 *
1833 *@@added V0.9.9 (2001-04-07) [umoeller]
1834 */
1835
1836APIRET doshReadLVMPartitions(PLVMINFO pInfo, // in: LVM info
1837 PPARTITIONINFO *ppPartitionInfo, // out: partitions array
1838 PUSHORT pcPartitions) // out: partitions count
1839{
1840 APIRET arc = NO_ERROR;
1841 CARDINAL32 Error = 0;
1842
1843 PARTITIONINFO *pPartitionInfos = NULL, // linked list of all partitions
1844 *ppiTemp = NULL;
1845 USHORT cPartitions = 0; // bootable partition count
1846 PLVMINFOPRIVATE pLVMInfo = (PLVMINFOPRIVATE)pInfo;
1847
1848 _Pmpf((__FUNCTION__ ": entering"));
1849
1850 if (!pLVMInfo)
1851 return (ERROR_INVALID_PARAMETER);
1852
1853 // initialize LVM engine
1854 pLVMInfo->Open_LVM_Engine(TRUE,
1855 &Error);
1856
1857 _Pmpf((" Open_LVM_Engine Error: %d"));
1858
1859 if (!Error)
1860 {
1861 Drive_Control_Array DCA = pLVMInfo->Get_Drive_Control_Data(&Error);
1862 // member records to be freed
1863
1864 _Pmpf((" Get_Drive_Control_Data Error: %d, drive count: %d", Error, DCA.Count));
1865
1866 if ( (!Error)
1867 && (DCA.Count)
1868 )
1869 {
1870 // DCA.Drive_Control_Data now contains drive information records;
1871 // this must be freed
1872 ULONG ulDisk;
1873
1874 for (ulDisk = 0;
1875 ulDisk < DCA.Count;
1876 ulDisk++)
1877 {
1878 Drive_Control_Record *pDriveControlRecord
1879 = &DCA.Drive_Control_Data[ulDisk];
1880 ADDRESS hDrive = pDriveControlRecord->Drive_Handle;
1881
1882 /* Drive_Information_Record pDriveInfoRecord
1883 = pLVMInfo->Get_Drive_Status(hDrive,
1884 &Error);
1885
1886 _Pmpf((" drive %d Get_Drive_Status Error: %d", ulDisk, Error));
1887
1888 if (!Error) */
1889 {
1890 Partition_Information_Array PIA
1891 = pLVMInfo->Get_Partitions(hDrive,
1892 &Error);
1893
1894 _Pmpf((" Get_Partitions Error: %d", Error));
1895
1896 if (!Error)
1897 {
1898 // PIA.Partition_Array now contains
1899 // Partition_Information_Record; must be freed
1900
1901 // now go thru partitions of this drive
1902 ULONG ulPart;
1903 for (ulPart = 0;
1904 ulPart < PIA.Count;
1905 ulPart++)
1906 {
1907 Partition_Information_Record *pPartition
1908 = &PIA.Partition_Array[ulPart];
1909 Volume_Information_Record VolumeInfo;
1910
1911 const char *pcszBootName = NULL; // for now
1912 BOOL fBootable = FALSE;
1913
1914 if (pPartition->Volume_Handle)
1915 {
1916 // this partition is part of a volume:
1917 // only then can it be bootable...
1918 // get the volume info
1919 VolumeInfo
1920 = pLVMInfo->Get_Volume_Information(pPartition->Volume_Handle,
1921 &Error);
1922 pcszBootName = VolumeInfo.Volume_Name;
1923
1924 fBootable = (VolumeInfo.Status == 1);
1925 }
1926
1927
1928 if (arc = AppendPartition(&pPartitionInfos,
1929 &ppiTemp,
1930 &cPartitions,
1931 ulDisk + 1,
1932 pcszBootName,
1933 pPartition->Volume_Drive_Letter,
1934 pPartition->OS_Flag, // FS type
1935 pPartition->Primary_Partition,
1936 fBootable,
1937 pPartition->True_Partition_Size))
1938 break;
1939 }
1940
1941 // clean up partitions
1942 pLVMInfo->Free_Engine_Memory(PIA.Partition_Array);
1943 }
1944 }
1945 /* else
1946 // error:
1947 break; */
1948 }
1949
1950 // clean up drive data
1951 pLVMInfo->Free_Engine_Memory(DCA.Drive_Control_Data);
1952 }
1953 }
1954
1955 // close LVM
1956 pLVMInfo->Close_LVM_Engine();
1957
1958 if (Error)
1959 {
1960 // if we got an error, return it with the
1961 // LVM error offset
1962 arc = LVM_ERROR_FIRST + Error;
1963
1964 CleanPartitionInfos(pPartitionInfos);
1965 }
1966
1967 if (!arc)
1968 {
1969 *ppPartitionInfo = pPartitionInfos;
1970 *pcPartitions = cPartitions;
1971 }
1972
1973 _Pmpf((__FUNCTION__ ": exiting, arg = %d", arc));
1974
1975 return (arc);
1976}
1977
1978/*
1979 *@@ doshFreeLVMInfo:
1980 *
1981 *@@added V0.9.9 (2001-04-07) [umoeller]
1982 */
1983
1984VOID doshFreeLVMInfo(PLVMINFO pInfo)
1985{
1986 if (pInfo)
1987 {
1988 if (pInfo->hmodLVM)
1989 DosFreeModule(pInfo->hmodLVM);
1990
1991 free(pInfo);
1992 }
1993}
1994
1995/*
1996 *@@category: Helpers\Control program helpers\Wildcard matching
1997 * See doshMatch.
1998 */
1999
2000/* ******************************************************************
2001 *
2002 * Wildcard matching
2003 *
2004 ********************************************************************/
2005
2006/*
2007 * PerformMatch:
2008 * compares a single path component. The input strings must
2009 * not have slashes or backslashes in them.
2010 *
2011 * fHasDot must be true if pName contains at least one dot.
2012 *
2013 * Note that this function is recursive.
2014 */
2015
2016static BOOL PerformMatch(PCSZ pMask,
2017 PCSZ pName,
2018 int fHasDot)
2019{
2020 while (TRUE)
2021 {
2022 // go thru the pMask char by char
2023 switch (*pMask)
2024 {
2025 case 0:
2026 // if we've reached the end of the mask,
2027 // we better have the end of the name too
2028 if (*pName == 0)
2029 return TRUE;
2030 return FALSE;
2031
2032 case '?':
2033 // a question mark matches one single character;
2034 // it does _not_ match a dot;
2035 // at the end of the component, it also matches
2036 // no characters
2037 if ( (*pName != '.')
2038 && (*pName != 0)
2039 )
2040 ++pName;
2041 ++pMask;
2042 break;
2043
2044 case '*':
2045 // asterisk matches zero or more characters
2046
2047 // skip extra asterisks
2048 do
2049 {
2050 ++pMask;
2051 } while (*pMask == '*');
2052
2053 // pMask points to after '*';
2054 // pName is unchanged... so for each pName
2055 // that follows, check if it matches
2056 while (TRUE)
2057 {
2058 if (PerformMatch(pMask, pName, fHasDot))
2059 // the remainder matched:
2060 // then everything matches
2061 return TRUE;
2062
2063 if (*pName == 0)
2064 return FALSE;
2065
2066 // didn't match: try next pName
2067 ++pName;
2068 }
2069
2070 case '.':
2071 // a dot matches a dot only, even if the name doesn't
2072 // have one at the end
2073 ++pMask;
2074 if (*pName == '.')
2075 ++pName;
2076 else if ( (fHasDot)
2077 || (*pName != 0)
2078 )
2079 return FALSE;
2080 break;
2081
2082 default:
2083 if (*pMask++ != *pName++)
2084 return FALSE;
2085 break;
2086 }
2087 }
2088}
2089
2090/*
2091 *@@ doshMatch:
2092 * this matches '*' and '?' wildcards, similar to what
2093 * DosEditName does. It returns TRUE if the given name
2094 * matches the given mask.
2095 *
2096 * However, this does not require a file to be present, but
2097 * works on strings only.
2098 *
2099 * This accepts both short and fully qualified masks and
2100 * names, but the following rules apply:
2101 *
2102 * -- Either both the mask and the name must be fully
2103 * qualified, or both must not. Otherwise the match fails.
2104 *
2105 * -- If fully qualified, only the last component may contain
2106 * wildcards.
2107 *
2108 * -- This compares without respect to case always.
2109 *
2110 * -- As opposed to the WPS, this handles multiple dots in
2111 * filenames correctly. For example, the WPS will not
2112 * match "*.ZIP" against "whatever-0.9.3.zip", but this
2113 * one will.
2114 *
2115 * -- THIS COMPARES WITH RESPECT TO CASE.
2116 *
2117 * This replaces strhMatchOS2 which has been removed with
2118 * V0.9.16 and is a lot faster than the old code, which has
2119 * been completely rewritten.
2120 *
2121 *@@added V0.9.16 (2002-01-01) [umoeller]
2122 */
2123
2124BOOL doshMatchCase(const char *pcszMask, // in: mask (e.g. "*.TXT")
2125 const char *pcszName) // in: string to check (e.g. "TEST.TXT")
2126{
2127 BOOL brc = FALSE;
2128
2129 int iMaskDrive = -1,
2130 iNameDrive = -1;
2131
2132 // ULONG cbMask = strlen(pcszMask),
2133 // cbName = strlen(pcszName);
2134 // PSZ pszMask = (PSZ)_alloca(cbMask + 1),
2135 // pszName = (PSZ)_alloca(cbName + 1);
2136
2137 PCSZ pLastMaskComponent,
2138 pLastNameComponent;
2139
2140 ULONG cbMaskPath = 0,
2141 cbNamePath = 0;
2142
2143 CHAR c;
2144
2145 if (pLastMaskComponent = strrchr(pcszMask, '\\'))
2146 {
2147 // length of path component
2148 cbMaskPath = pLastMaskComponent - pcszMask;
2149 pLastMaskComponent++;
2150 }
2151 else
2152 pLastMaskComponent = pcszMask;
2153
2154 if (pLastNameComponent = strrchr(pcszName, '\\'))
2155 {
2156 // length of path component
2157 cbNamePath = pLastNameComponent - pcszName;
2158 pLastNameComponent++;
2159 }
2160 else
2161 pLastNameComponent = pcszName;
2162
2163 // compare paths; if the lengths are different
2164 // or memcmp fails, we can't match
2165 if ( (cbMaskPath == cbNamePath) // can both be null
2166 && ( (cbMaskPath == 0)
2167 || (!memcmp(pcszMask, pcszName, cbMaskPath))
2168 )
2169 )
2170 {
2171 // alright, paths match:
2172 brc = PerformMatch(pLastMaskComponent,
2173 pLastNameComponent,
2174 // has dot?
2175 (strchr(pLastNameComponent, '.') != NULL));
2176
2177 }
2178
2179 return brc;
2180}
2181
2182/*
2183 *@@ doshMatch:
2184 * like doshMatchCase, but compares without respect
2185 * to case.
2186 *
2187 *@@added V0.9.16 (2002-01-26) [umoeller]
2188 */
2189
2190BOOL doshMatch(const char *pcszMask, // in: mask (e.g. "*.TXT")
2191 const char *pcszName) // in: string to check (e.g. "TEST.TXT")
2192{
2193 ULONG cbMask = strlen(pcszMask),
2194 cbName = strlen(pcszName);
2195 PSZ pszMask = (PSZ)_alloca(cbMask + 1),
2196 pszName = (PSZ)_alloca(cbName + 1);
2197
2198 memcpy(pszMask, pcszMask, cbMask + 1);
2199 nlsUpper(pszMask, cbMask);
2200 memcpy(pszName, pcszName, cbName + 1);
2201 nlsUpper(pszName, cbName);
2202
2203 return (doshMatchCase(pszMask,
2204 pszName));
2205}
Note: See TracBrowser for help on using the repository browser.