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

Last change on this file since 105 was 91, checked in by umoeller, 24 years ago

Misc changes

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 138.0 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\standards.h"
68#include "helpers\stringh.h"
69
70#pragma hdrstop
71
72/*
73 *@@category: Helpers\Control program helpers\Miscellaneous
74 */
75
76/* ******************************************************************
77 *
78 * Miscellaneous
79 *
80 ********************************************************************/
81
82/*
83 *@@ doshIsValidFileName:
84 * this returns NO_ERROR only if pszFile is a valid file name.
85 * This may include a full path.
86 *
87 * If a drive letter is specified, this checks for whether
88 * that drive is a FAT drive and adjust the checks accordingly,
89 * i.e. 8+3 syntax (per path component).
90 *
91 * If no drive letter is specified, this check is performed
92 * for the current drive.
93 *
94 * This also checks if pszFileNames contains characters which
95 * are invalid for the current drive.
96 *
97 * Note: this performs syntactic checks only. This does not
98 * check for whether the specified path components exist.
99 * However, it _is_ checked for whether the given drive
100 * exists.
101 *
102 * This func is especially useful to check filenames that
103 * have been entered by the user in a "Save as" dialog.
104 *
105 * If an error is found, the corresponding DOS error code
106 * is returned:
107 * -- ERROR_INVALID_DRIVE
108 * -- ERROR_FILENAME_EXCED_RANGE (on FAT: no 8+3 filename)
109 * -- ERROR_INVALID_NAME (invalid character)
110 * -- ERROR_CURRENT_DIRECTORY (if fFullyQualified: no full path specified)
111 *
112 *@@changed V0.9.2 (2000-03-11) [umoeller]: added fFullyQualified
113 */
114
115APIRET doshIsValidFileName(const char* pcszFile,
116 BOOL fFullyQualified) // in: if TRUE, pcszFile must be fully q'fied
117{
118 APIRET arc = NO_ERROR;
119 CHAR szPath[CCHMAXPATH+4] = " :";
120 CHAR szComponent[CCHMAXPATH];
121 PSZ p1, p2;
122 BOOL fIsFAT = FALSE;
123 PSZ pszInvalid;
124
125 if (fFullyQualified) // V0.9.2 (2000-03-11) [umoeller]
126 {
127 if ( (*(pcszFile + 1) != ':')
128 || (*(pcszFile + 2) != '\\')
129 )
130 arc = ERROR_CURRENT_DIRECTORY;
131 }
132
133 // check drive first
134 if (*(pcszFile + 1) == ':')
135 {
136 CHAR cDrive = toupper(*pcszFile);
137 double d;
138 // drive specified:
139 strcpy(szPath, pcszFile);
140 szPath[0] = toupper(*pcszFile);
141 arc = doshQueryDiskFree(cDrive - 'A' + 1, &d);
142 }
143 else
144 {
145 // no drive specified: take current
146 ULONG ulDriveNum = 0,
147 ulDriveMap = 0;
148 arc = DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
149 szPath[0] = ((UCHAR)ulDriveNum) + 'A' - 1;
150 szPath[1] = ':';
151 strcpy(&szPath[2], pcszFile);
152 }
153
154 if (arc == NO_ERROR)
155 {
156 fIsFAT = doshIsFileOnFAT(szPath);
157
158 pszInvalid = (fIsFAT)
159 ? "<>|+=:;,\"/[] " // invalid characters in FAT
160 : "<>|:\"/"; // invalid characters in IFS's
161
162 // now separate path components
163 p1 = &szPath[2]; // advance past ':'
164
165 do {
166
167 if (*p1 == '\\')
168 p1++;
169
170 p2 = strchr(p1, '\\');
171 if (p2 == NULL)
172 p2 = p1 + strlen(p1);
173
174 if (p1 != p2)
175 {
176 LONG lDotOfs = -1,
177 lAfterDot = -1;
178 ULONG cbFile,
179 ul;
180 PSZ pSource = szComponent;
181
182 strncpy(szComponent, p1, p2-p1);
183 szComponent[p2-p1] = 0;
184 cbFile = strlen(szComponent);
185
186 // now check each path component
187 for (ul = 0; ul < cbFile; ul++)
188 {
189 if (fIsFAT)
190 {
191 // on FAT: only 8 characters allowed before dot
192 if (*pSource == '.')
193 {
194 lDotOfs = ul;
195 lAfterDot = 0;
196 if (ul > 7)
197 return (ERROR_FILENAME_EXCED_RANGE);
198 }
199 }
200 // and check for invalid characters
201 if (strchr(pszInvalid, *pSource) != NULL)
202 return (ERROR_INVALID_NAME);
203
204 pSource++;
205
206 // on FAT, allow only three chars after dot
207 if (fIsFAT)
208 if (lAfterDot != -1)
209 {
210 lAfterDot++;
211 if (lAfterDot > 3)
212 return (ERROR_FILENAME_EXCED_RANGE);
213 }
214 }
215
216 // we are still missing the case of a FAT file
217 // name without extension; if so, check whether
218 // the file stem is <= 8 chars
219 if (fIsFAT)
220 if (lDotOfs == -1) // dot not found:
221 if (cbFile > 8)
222 return (ERROR_FILENAME_EXCED_RANGE);
223 }
224
225 // go for next component
226 p1 = p2+1;
227 } while (*p2);
228 }
229
230 return (arc);
231}
232
233/*
234 *@@ doshMakeRealName:
235 * this copies pszSource to pszTarget, replacing
236 * all characters which are not supported by file
237 * systems with cReplace.
238 *
239 * pszTarget must be at least the same size as pszSource.
240 * If (fIsFAT), the file name will be made FAT-compliant (8+3).
241 *
242 * Returns TRUE if characters were replaced.
243 *
244 *@@changed V0.9.0 (99-11-06) [umoeller]: now replacing "*" too
245 */
246
247BOOL doshMakeRealName(PSZ pszTarget, // out: new real name
248 PSZ pszSource, // in: filename to translate
249 CHAR cReplace, // in: replacement char for invalid
250 // characters (e.g. '!')
251 BOOL fIsFAT) // in: make-FAT-compatible flag
252{
253 ULONG ul,
254 cbSource = strlen(pszSource);
255 LONG lDotOfs = -1,
256 lAfterDot = -1;
257 BOOL brc = FALSE;
258 PSZ pSource = pszSource,
259 pTarget = pszTarget;
260
261 const char *pcszInvalid = (fIsFAT)
262 ? "*<>|+=:;,\"/\\[] " // invalid characters in FAT
263 : "*<>|:\"/\\"; // invalid characters in IFS's
264
265 for (ul = 0; ul < cbSource; ul++)
266 {
267 if (fIsFAT)
268 {
269 // on FAT: truncate filename if neccessary
270 if (*pSource == '.')
271 {
272 lDotOfs = ul;
273 lAfterDot = 0;
274 if (ul > 7) {
275 // only 8 characters allowed before dot,
276 // so set target ptr to dot pos
277 pTarget = pszTarget+8;
278 }
279 }
280 }
281 // and replace invalid characters
282 if (strchr(pcszInvalid, *pSource) == NULL)
283 *pTarget = *pSource;
284 else
285 {
286 *pTarget = cReplace;
287 brc = TRUE;
288 }
289 pTarget++;
290 pSource++;
291
292 // on FAT, allow only three chars after dot
293 if (fIsFAT)
294 if (lAfterDot != -1)
295 {
296 lAfterDot++;
297 if (lAfterDot > 3)
298 break;
299 }
300 }
301 *pTarget = '\0';
302
303 if (fIsFAT)
304 {
305 // we are still missing the case of a FAT file
306 // name without extension; if so, check whether
307 // the file stem is <= 8 chars
308 if (lDotOfs == -1) // dot not found:
309 if (cbSource > 8)
310 *(pszTarget+8) = 0; // truncate
311
312 // convert to upper case
313 strupr(pszTarget);
314 }
315
316 return (brc);
317}
318
319/*
320 *@@ doshSetCurrentDir:
321 * sets the current working directory
322 * to the given path.
323 *
324 * As opposed to DosSetCurrentDir, this
325 * one will change the current drive
326 * also, if one is specified.
327 *
328 *@@changed V0.9.9 (2001-04-04) [umoeller]: this returned an error even if none occured, fixed
329 */
330
331APIRET doshSetCurrentDir(const char *pcszDir)
332{
333 APIRET arc = NO_ERROR;
334 if (!pcszDir)
335 return (ERROR_INVALID_PARAMETER);
336 {
337 if (*pcszDir != 0)
338 if (*(pcszDir+1) == ':')
339 {
340 // drive given:
341 CHAR cDrive = toupper(*(pcszDir));
342 // change drive
343 arc = DosSetDefaultDisk( (ULONG)(cDrive - 'A' + 1) );
344 // 1 = A:, 2 = B:, ...
345 }
346
347 arc = DosSetCurrentDir((PSZ)pcszDir);
348 }
349
350 return (arc); // V0.9.9 (2001-04-04) [umoeller]
351}
352
353/*
354 *@@category: Helpers\Control program helpers\Executable info
355 * these functions can retrieve BLDLEVEL information,
356 * imported modules information, exported functions information,
357 * and resources information from any executable module. See
358 * doshExecOpen.
359 */
360
361/********************************************************************
362 *
363 * Executable functions
364 *
365 ********************************************************************/
366
367/*
368 *@@ doshExecOpen:
369 * this opens the specified executable file
370 * (which can be an .EXE, .COM, .DLL, or
371 * driver file) for use with the other
372 * doshExec* functions.
373 *
374 * If no error occurs, NO_ERROR is returned
375 * and a pointer to a new EXECUTABLE structure
376 * is stored in *ppExec. Consider this pointer a
377 * handle and pass it to doshExecClose to clean
378 * up.
379 *
380 * If NO_ERROR is returned, all the fields through
381 * ulOS are set in EXECUTABLE. The psz* fields
382 * which follow afterwards require an additional
383 * call to doshExecQueryBldLevel.
384 *
385 * NOTE: If NO_ERROR is returned, the executable
386 * file has been opened by this function. It will
387 * only be closed when you call doshExecClose.
388 *
389 * If errors occur, this function returns the
390 * following error codes:
391 *
392 * -- ERROR_NOT_ENOUGH_MEMORY: malloc() failed.
393 *
394 * -- ERROR_INVALID_EXE_SIGNATURE: unknown
395 * executable type... the given file probably
396 * isn't even an executable.
397 *
398 * -- ERROR_INVALID_PARAMETER: ppExec is NULL.
399 *
400 * plus those of DosOpen, DosSetFilePtr, and
401 * DosRead.
402 *
403 * The following executable types are supported
404 * (see EXECUTABLE for details):
405 *
406 * -- Plain DOS 3.x executable without new header.
407 *
408 * -- New Executable (NE), used by Win16 and
409 * 16-bit OS/2 and still many of today's drivers.
410 *
411 * -- Linear Executable (LX), OS/2 2.x and above.
412 *
413 * -- Portable Executable (PE), used by Win32.
414 *
415 * V0.9.12 adds support for NOSTUB executables,
416 * which are new-style executables (NE or LX)
417 * without a leading DOS header. The executable
418 * then starts directly with the NE or LX header.
419 * I am not sure whether PE supports such things
420 * as well... if so, it should be supported too.
421 *
422 *@@added V0.9.0 [umoeller]
423 *@@changed V0.9.1 (2000-02-13) [umoeller]: fixed 32-bits flag
424 *@@changed V0.9.7 (2000-12-20) [lafaix]: fixed ulNewHeaderOfs
425 *@@changed V0.9.10 (2001-04-08) [lafaix]: added PE support
426 *@@changed V0.9.10 (2001-04-08) [umoeller]: now setting ppExec only if NO_ERROR is returned
427 *@@changed V0.9.12 (2001-05-03) [umoeller]: added support for NOSTUB newstyle executables
428 */
429
430APIRET doshExecOpen(const char* pcszExecutable,
431 PEXECUTABLE* ppExec)
432{
433 APIRET arc = NO_ERROR;
434
435 ULONG ulAction = 0;
436 HFILE hFile;
437 PEXECUTABLE pExec = NULL;
438
439 if (!ppExec)
440 return (ERROR_INVALID_PARAMETER);
441
442 pExec = (PEXECUTABLE)malloc(sizeof(EXECUTABLE));
443 if (!(pExec))
444 return (ERROR_NOT_ENOUGH_MEMORY);
445
446 memset(pExec, 0, sizeof(EXECUTABLE));
447
448 if (!(arc = DosOpen((PSZ)pcszExecutable,
449 &hFile,
450 &ulAction, // out: action taken
451 0, // in: new file (ignored for read-mode)
452 0, // in: new file attribs (ignored)
453 // open-flags
454 OPEN_ACTION_FAIL_IF_NEW
455 | OPEN_ACTION_OPEN_IF_EXISTS,
456 // open-mode
457 OPEN_FLAGS_FAIL_ON_ERROR // report errors to caller
458 | OPEN_FLAGS_SEQUENTIAL
459 | OPEN_FLAGS_NOINHERIT
460 | OPEN_SHARE_DENYNONE
461 | OPEN_ACCESS_READONLY, // read-only mode
462 NULL))) // no EAs
463 {
464 // file opened successfully:
465
466 ULONG ulLocal = 0;
467
468 // read old DOS EXE header
469 pExec->pDosExeHeader = (PDOSEXEHEADER)malloc(sizeof(DOSEXEHEADER));
470 if (!(pExec->pDosExeHeader))
471 arc = ERROR_NOT_ENOUGH_MEMORY;
472 else
473 {
474 ULONG ulBytesRead = 0;
475
476 if ( (!(arc = DosSetFilePtr(hFile,
477 0L,
478 FILE_BEGIN,
479 &ulLocal))) // out: new offset
480 && (!(arc = DosRead(hFile,
481 pExec->pDosExeHeader,
482 sizeof(DOSEXEHEADER),
483 &(pExec->cbDosExeHeader))))
484 )
485 {
486 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]
487 BOOL fLoadNewHeader = FALSE;
488
489 // now check if we really have a DOS header
490 if (pExec->pDosExeHeader->usDosExeID != 0x5a4d)
491 {
492 // arc = ERROR_INVALID_EXE_SIGNATURE;
493
494 // V0.9.12 (2001-05-03) [umoeller]
495 // try loading new header directly; there are
496 // drivers which were built with NOSTUB, and
497 // the exe image starts out with the NE or LX
498 // image directly
499 fLoadNewHeader = TRUE;
500 // ulNewHeaderOfs is 0 now
501
502 // remove the DOS header info, since we have none
503 // V0.9.12 (2001-05-03) [umoeller]
504 free (pExec->pDosExeHeader);
505 pExec->pDosExeHeader = 0;
506 }
507 else
508 {
509 // we have a DOS header:
510 if (pExec->pDosExeHeader->usRelocTableOfs < 0x40)
511 {
512 // neither LX nor PE nor NE:
513 pExec->ulOS = EXEOS_DOS3;
514 pExec->ulExeFormat = EXEFORMAT_OLDDOS;
515 }
516 else
517 {
518 // we have a new header offset:
519 fLoadNewHeader = TRUE;
520 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
521 }
522 }
523
524 if (fLoadNewHeader)
525 {
526 // either LX or PE or NE:
527 // read in new header...
528 // ulNewHeaderOfs is now either 0 (if no DOS header
529 // was found) or pDosExeHeader->ulNewHeaderOfs
530 // V0.9.12 (2001-05-03) [umoeller]
531 CHAR achNewHeaderType[2] = "";
532
533 if ( (!(arc = DosSetFilePtr(hFile,
534 ulNewHeaderOfs,
535 FILE_BEGIN,
536 &ulLocal)))
537 // read two chars to find out header type
538 && (!(arc = DosRead(hFile,
539 &achNewHeaderType,
540 sizeof(achNewHeaderType),
541 &ulBytesRead)))
542 )
543 {
544 PBYTE pbCheckOS = NULL;
545
546 // reset file ptr
547 DosSetFilePtr(hFile,
548 ulNewHeaderOfs,
549 FILE_BEGIN,
550 &ulLocal);
551
552 if (memcmp(achNewHeaderType, "NE", 2) == 0)
553 {
554 // New Executable:
555 pExec->ulExeFormat = EXEFORMAT_NE;
556 // allocate NE header
557 pExec->pNEHeader = (PNEHEADER)malloc(sizeof(NEHEADER));
558 if (!(pExec->pNEHeader))
559 arc = ERROR_NOT_ENOUGH_MEMORY;
560 else
561 // read in NE header
562 if (!(arc = DosRead(hFile,
563 pExec->pNEHeader,
564 sizeof(NEHEADER),
565 &(pExec->cbNEHeader))))
566 if (pExec->cbNEHeader == sizeof(NEHEADER))
567 pbCheckOS = &(pExec->pNEHeader->bTargetOS);
568 }
569 else if ( (memcmp(achNewHeaderType, "LX", 2) == 0)
570 || (memcmp(achNewHeaderType, "LE", 2) == 0)
571 // this is used by SMARTDRV.EXE
572 )
573 {
574 // OS/2 Linear Executable:
575 pExec->ulExeFormat = EXEFORMAT_LX;
576 // allocate LX header
577 pExec->pLXHeader = (PLXHEADER)malloc(sizeof(LXHEADER));
578 if (!(pExec->pLXHeader))
579 arc = ERROR_NOT_ENOUGH_MEMORY;
580 else
581 // read in LX header
582 if (!(arc = DosRead(hFile,
583 pExec->pLXHeader,
584 sizeof(LXHEADER),
585 &(pExec->cbLXHeader))))
586 if (pExec->cbLXHeader == sizeof(LXHEADER))
587 pbCheckOS = (PBYTE)(&(pExec->pLXHeader->usTargetOS));
588 }
589 else if (memcmp(achNewHeaderType, "PE", 2) == 0)
590 {
591 PEHEADER PEHeader = {0};
592
593 pExec->ulExeFormat = EXEFORMAT_PE;
594 pExec->ulOS = EXEOS_WIN32;
595 pExec->f32Bits = TRUE;
596
597 // V0.9.10 (2001-04-08) [lafaix]
598 // read in standard PE header
599 if (!(arc = DosRead(hFile,
600 &PEHeader,
601 24,
602 &ulBytesRead)))
603 {
604 // allocate PE header
605 pExec->pPEHeader = (PPEHEADER)malloc(24 + PEHeader.usHeaderSize);
606 if (!(pExec->pPEHeader))
607 arc = ERROR_NOT_ENOUGH_MEMORY;
608 else
609 {
610 // copy standard PE header
611 memcpy(pExec->pPEHeader,
612 &PEHeader,
613 24);
614
615 // read in optional PE header
616 if (!(arc = DosRead(hFile,
617 &(pExec->pPEHeader->usReserved3),
618 PEHeader.usHeaderSize,
619 &(pExec->cbPEHeader))))
620 pExec->cbPEHeader += 24;
621 }
622 }
623 }
624 else
625 // strange type:
626 arc = ERROR_INVALID_EXE_SIGNATURE;
627
628 if (pbCheckOS)
629 // BYTE to check for operating system
630 // (NE and LX):
631 switch (*pbCheckOS)
632 {
633 case NEOS_OS2:
634 pExec->ulOS = EXEOS_OS2;
635 if (pExec->ulExeFormat == EXEFORMAT_LX)
636 pExec->f32Bits = TRUE;
637 break;
638
639 case NEOS_WIN16:
640 pExec->ulOS = EXEOS_WIN16;
641 break;
642
643 case NEOS_DOS4:
644 pExec->ulOS = EXEOS_DOS4;
645 break;
646
647 case NEOS_WIN386:
648 pExec->ulOS = EXEOS_WIN386;
649 pExec->f32Bits = TRUE;
650 break;
651 }
652 } // end if (!(arc = DosSetFilePtr(hFile,
653 }
654 } // end if (!(arc = DosSetFilePtr(hFile,
655 } // end if pExec->pDosExeHeader = (PDOSEXEHEADER)malloc(sizeof(DOSEXEHEADER));
656
657 // store exec's HFILE
658 pExec->hfExe = hFile;
659 } // end if (!(arc = DosOpen((PSZ)pcszExecutable,
660
661 if (arc != NO_ERROR)
662 // error: clean up
663 doshExecClose(pExec);
664 else
665 *ppExec = pExec;
666
667 return (arc);
668}
669
670/*
671 *@@ doshExecClose:
672 * this closes an executable opened with doshExecOpen.
673 * Always call this function if NO_ERROR was returned by
674 * doshExecOpen.
675 *
676 *@@added V0.9.0 [umoeller]
677 */
678
679APIRET doshExecClose(PEXECUTABLE pExec)
680{
681 APIRET arc = NO_ERROR;
682 if (pExec)
683 {
684 if (pExec->pDosExeHeader)
685 free(pExec->pDosExeHeader);
686 if (pExec->pNEHeader)
687 free(pExec->pNEHeader);
688 if (pExec->pLXHeader)
689 free(pExec->pLXHeader);
690
691 if (pExec->pszDescription)
692 free(pExec->pszDescription);
693 if (pExec->pszVendor)
694 free(pExec->pszVendor);
695 if (pExec->pszVersion)
696 free(pExec->pszVersion);
697 if (pExec->pszInfo)
698 free(pExec->pszInfo);
699
700 if (pExec->hfExe)
701 arc = DosClose(pExec->hfExe);
702
703 free(pExec);
704 }
705 else
706 arc = ERROR_INVALID_PARAMETER;
707
708 return (arc);
709}
710
711/*
712 *@@ ParseBldLevel:
713 * called from doshExecQueryBldLevel to parse
714 * the BLDLEVEL string.
715 *
716 * On entry, caller has copied the string into
717 * pExec->pszDescription. The string is
718 * null-terminated.
719 *
720 * The BLDLEVEL string comes in two flavors.
721 *
722 * -- The standard format is:
723 *
724 + @#VENDOR:VERSION#@DESCRIPTION
725 *
726 * DESCRIPTION can have leading spaces, but
727 * need to have them.
728 *
729 * -- However, there is an extended version
730 * in that the DESCRIPTION field is split
731 * up even more. The marker for this seems
732 * to be that the description starts out
733 * with "##1##".
734 *
735 + ##1## DATETIME BUILDMACHINE:ASD:LANG:CTRY:REVISION:UNKNOWN:FIXPAK@@DESCRIPTION
736 *
737 * The problem is that the DATETIME field comes
738 * in several flavors. IBM uses things like
739 *
740 + "Thu Nov 30 15:30:37 2000 BWBLD228"
741 *
742 * while DANIS506.ADD has
743 *
744 + "15.12.2000 18:22:57 Nachtigall"
745 *
746 * Looks like the date/time string is standardized
747 * to have 24 characters then.
748 *
749 *@@added V0.9.12 (2001-05-18) [umoeller]
750 *@@changed V0.9.12 (2001-05-19) [umoeller]: added extended BLDLEVEL support
751 */
752
753VOID ParseBldLevel(PEXECUTABLE pExec)
754{
755 const char // *pStartOfAuthor = 0,
756 *pStartOfVendor = 0;
757
758 // @#VENDOR:VERSION#@ DESCRIPTION
759 // but skip the first byte, which has the string length
760 pStartOfVendor = strstr(pExec->pszDescription,
761 "@#");
762 if (pStartOfVendor)
763 {
764 const char *pStartOfInfo = strstr(pStartOfVendor + 2,
765 "#@");
766 if (pStartOfInfo)
767 {
768 const char *pEndOfVendor = strchr(pStartOfVendor + 2,
769 ':');
770 if (pEndOfVendor)
771 {
772 pExec->pszVendor = strhSubstr(pStartOfVendor + 2,
773 pEndOfVendor);
774 pExec->pszVersion = strhSubstr(pEndOfVendor + 1,
775 pStartOfInfo);
776 // skip "@#" in DESCRIPTION string
777 pStartOfInfo += 2;
778
779 // now check if we have extended DESCRIPTION V0.9.12 (2001-05-19) [umoeller]
780 if ( (strlen(pStartOfInfo) > 6)
781 && (!memcmp(pStartOfInfo, "##1##", 5))
782 )
783 {
784 // yes: parse that beast
785 const char *p = pStartOfInfo + 5;
786
787 // get build date/time
788 if (strlen(p) > 24)
789 {
790 // date/time seems to be fixed 24 chars in length
791 pExec->pszBuildDateTime = (PSZ)malloc(25);
792 if (pExec->pszBuildDateTime)
793 {
794 memcpy(pExec->pszBuildDateTime,
795 p,
796 24);
797 pExec->pszBuildDateTime[24] = '\0';
798
799 p += 24;
800
801 // now we're at the colon-separated
802 // strings, first of which is the
803 // build machine;
804 // skip leading spaces
805 while (*p == ' ')
806 p++;
807
808 if (*p)
809 {
810 char **papsz[] =
811 {
812 &pExec->pszBuildMachine,
813 &pExec->pszASD,
814 &pExec->pszLanguage,
815 &pExec->pszCountry,
816 &pExec->pszRevision,
817 &pExec->pszUnknown,
818 &pExec->pszFixpak
819 };
820 ULONG ul;
821
822 for (ul = 0;
823 ul < sizeof(papsz) / sizeof(papsz[0]);
824 ul++)
825 {
826 BOOL fStop = FALSE;
827 const char *pNextColon = strchr(p, ':'),
828 *pDoubleAt = strstr(p, "@@");
829 if (!pNextColon)
830 {
831 // last item:
832 if (pDoubleAt)
833 pNextColon = pDoubleAt;
834 else
835 pNextColon = p + strlen(p);
836
837 fStop = TRUE;
838 }
839
840 if ( (fStop)
841 || ( (pNextColon)
842 && ( (!pDoubleAt)
843 || (pNextColon < pDoubleAt)
844 )
845 )
846 )
847 {
848 if (pNextColon > p + 1)
849 *(papsz[ul]) = strhSubstr(p, pNextColon);
850 }
851 else
852 break;
853
854 if (fStop)
855 break;
856
857 p = pNextColon + 1;
858 }
859 }
860 }
861 }
862
863 pStartOfInfo = strstr(p,
864 "@@");
865 if (pStartOfInfo)
866 pStartOfInfo += 2;
867 }
868
869 // -- if we had no extended DESCRIPTION,
870 // pStartOfInfo points to regular description now
871 // -- if we parse the extended DESCRIPTION above,
872 // pStartOfInfo points to after @@ now
873 // -- if we had an error, pStartOfInfo is NULL
874 if (pStartOfInfo)
875 {
876 // add the regular DESCRIPTION then
877 // skip leading spaces in info string
878 while (*pStartOfInfo == ' ')
879 pStartOfInfo++;
880 if (*pStartOfInfo) // V0.9.9 (2001-04-04) [umoeller]
881 // and copy until end of string
882 pExec->pszInfo = strdup(pStartOfInfo);
883 }
884 }
885 }
886 }
887}
888
889/*
890 *@@ doshExecQueryBldLevel:
891 * this retrieves buildlevel information for an
892 * LX or NE executable previously opened with
893 * doshExecOpen.
894 *
895 * BuildLevel information must be contained in the
896 * DESCRIPTION field of an executable's module
897 * definition (.DEF) file. In order to be readable
898 * by BLDLEVEL.EXE (which ships with OS/2), this
899 * string must have the following format:
900 *
901 + Description '@#AUTHOR:VERSION#@ DESCRIPTION'
902 *
903 * Example:
904 *
905 + Description '@#Ulrich M”ller:0.9.0#@ XWorkplace Sound Support Module'
906 *
907 * The "Description" entry always ends up as the
908 * very first entry in the non-resident name table
909 * in LX and NE executables. So this is what we retrieve
910 * here.
911 *
912 * If the first entry in that table exists, NO_ERROR is
913 * returned and at least the pszDescription field in
914 * EXECUTABLE is set to that information.
915 *
916 * If that string is in IBM BLDLEVEL format, the string
917 * is automatically parsed, and the pszVendor, pszVersion,
918 * and pszInfo fields are also set. In the above examples,
919 * this would return the following information:
920 + pszVendor = "Ulrich M”ller"
921 + pszVersion = "0.9.0"
922 + pszInfo = "XWorkplace Sound Support Module"
923 *
924 * If that string is not in BLDLEVEL format, only pszDescription
925 * will be set. The other fields remain NULL.
926 *
927 * This returns the following errors:
928 *
929 * -- ERROR_INVALID_PARAMETER: pExec invalid
930 *
931 * -- ERROR_INVALID_EXE_SIGNATURE (191): pExec is not in LX or NE format
932 *
933 * -- ERROR_INVALID_DATA (13): non-resident name table not found.
934 *
935 * -- ERROR_NOT_ENOUGH_MEMORY: malloc() failed.
936 *
937 * plus the error codes of DosSetFilePtr and DosRead.
938 *
939 *@@added V0.9.0 [umoeller]
940 *@@changed V0.9.0 (99-10-22) [umoeller]: NE format now supported
941 *@@changed V0.9.1 (99-12-06): fixed memory leak
942 *@@changed V0.9.9 (2001-04-04) [umoeller]: added more error checking
943 *@@changed V0.9.12 (2001-05-18) [umoeller]: extracted ParseBldLevel
944 */
945
946APIRET doshExecQueryBldLevel(PEXECUTABLE pExec)
947{
948 APIRET arc = NO_ERROR;
949
950 if (!pExec)
951 arc = ERROR_INVALID_PARAMETER;
952 else
953 {
954 ULONG ulNRNTOfs = 0;
955
956 if (pExec->ulExeFormat == EXEFORMAT_LX)
957 {
958 // OK, LX format:
959 // check if we have a non-resident name table
960 if (pExec->pLXHeader == NULL)
961 arc = ERROR_INVALID_DATA;
962 else if (pExec->pLXHeader->ulNonResdNameTblOfs == 0)
963 arc = ERROR_INVALID_DATA;
964 else
965 ulNRNTOfs = pExec->pLXHeader->ulNonResdNameTblOfs;
966 }
967 else if (pExec->ulExeFormat == EXEFORMAT_NE)
968 {
969 // OK, NE format:
970 // check if we have a non-resident name table
971 if (pExec->pNEHeader == NULL)
972 arc = ERROR_INVALID_DATA;
973 else if (pExec->pNEHeader->ulNonResdTblOfs == 0)
974 arc = ERROR_INVALID_DATA;
975 else
976 ulNRNTOfs = pExec->pNEHeader->ulNonResdTblOfs;
977 }
978 else
979 // neither LX nor NE: stop
980 arc = ERROR_INVALID_EXE_SIGNATURE;
981
982 if ( (!arc)
983 && (ulNRNTOfs)
984 )
985 {
986 ULONG ulLocal = 0,
987 ulBytesRead = 0;
988
989 // move EXE file pointer to offset of non-resident name table
990 // (from LX header)
991 if (!(arc = DosSetFilePtr(pExec->hfExe, // file is still open
992 ulNRNTOfs, // ofs determined above
993 FILE_BEGIN,
994 &ulLocal)))
995 {
996 // allocate memory as necessary
997 PSZ pszNameTable = (PSZ)malloc(2001); // should suffice, because each entry
998 // may only be 255 bytes in length
999 if (!pszNameTable)
1000 arc = ERROR_NOT_ENOUGH_MEMORY;
1001 else
1002 {
1003 if (!(arc = DosRead(pExec->hfExe,
1004 pszNameTable,
1005 2000,
1006 &ulBytesRead)))
1007 {
1008 if (*pszNameTable == 0)
1009 // first byte (length byte) is null:
1010 arc = ERROR_INVALID_DATA;
1011 else
1012 {
1013 // now copy the string, which is in Pascal format
1014 pExec->pszDescription = (PSZ)malloc((*pszNameTable) + 1); // addt'l null byte
1015 if (!pExec->pszDescription)
1016 arc = ERROR_NOT_ENOUGH_MEMORY;
1017 else
1018 {
1019 memcpy(pExec->pszDescription,
1020 pszNameTable + 1, // skip length byte
1021 *pszNameTable); // length byte
1022 // terminate string
1023 *(pExec->pszDescription + (*pszNameTable)) = 0;
1024
1025 ParseBldLevel(pExec);
1026 }
1027 }
1028 }
1029
1030 free(pszNameTable);
1031 } // end if PSZ pszNameTable = (PSZ)malloc(2001);
1032 }
1033 }
1034 } // end if (!pExec)
1035
1036 return (arc);
1037}
1038
1039/*
1040 *@@ doshExecQueryImportedModules:
1041 * returns an array of FSYSMODULE structure describing all
1042 * imported modules.
1043 *
1044 * *pcModules receives the # of items in the array (not the
1045 * array size!). Use doshFreeImportedModules to clean up.
1046 *
1047 * This returns a standard OS/2 error code, which might be
1048 * any of the codes returned by DosSetFilePtr and DosRead.
1049 * In addition, this may return:
1050 *
1051 * -- ERROR_NOT_ENOUGH_MEMORY
1052 *
1053 * -- ERROR_INVALID_EXE_SIGNATURE: exe is in a format other
1054 * than LX or NE, which is not understood by this function.
1055 *
1056 * Even if NO_ERROR is returned, the array pointer might still
1057 * be NULL if the module contains no such data.
1058 *
1059 *@@added V0.9.9 (2001-03-11) [lafaix]
1060 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
1061 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
1062 *@@changed V0.9.10 (2001-04-10) [lafaix]: added Win16 and Win386 support
1063 *@@changed V0.9.10 (2001-04-13) [lafaix]: removed 127 characters limit
1064 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
1065 */
1066
1067APIRET doshExecQueryImportedModules(PEXECUTABLE pExec,
1068 PFSYSMODULE *ppaModules, // out: modules array
1069 PULONG pcModules) // out: array item count
1070{
1071 if ( (pExec)
1072 && ( (pExec->ulOS == EXEOS_OS2)
1073 || (pExec->ulOS == EXEOS_WIN16)
1074 || (pExec->ulOS == EXEOS_WIN386)
1075 )
1076 )
1077 {
1078 ENSURE_BEGIN;
1079 ULONG cModules = 0;
1080 PFSYSMODULE paModules = NULL;
1081 int i;
1082
1083 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]
1084
1085 if (pExec->pDosExeHeader)
1086 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
1087 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
1088
1089 if (pExec->ulExeFormat == EXEFORMAT_LX)
1090 {
1091 // 32-bit OS/2 executable:
1092 cModules = pExec->pLXHeader->ulImportModTblCnt;
1093
1094 if (cModules)
1095 {
1096 ULONG cb = sizeof(FSYSMODULE) * cModules; // V0.9.9 (2001-04-03) [umoeller]
1097 ULONG ulDummy;
1098
1099 paModules = (PFSYSMODULE)malloc(cb);
1100 if (!paModules)
1101 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY); // V0.9.9 (2001-04-03) [umoeller]
1102
1103 memset(paModules, 0, cb); // V0.9.9 (2001-04-03) [umoeller]
1104
1105 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1106 pExec->pLXHeader->ulImportModTblOfs
1107 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
1108 FILE_BEGIN,
1109 &ulDummy));
1110
1111 for (i = 0; i < cModules; i++)
1112 {
1113 BYTE bLen = 0;
1114
1115 // reading the length of the module name
1116 ENSURE_SAFE(DosRead(pExec->hfExe, &bLen, 1, &ulDummy));
1117
1118 // reading the module name
1119 ENSURE_SAFE(DosRead(pExec->hfExe,
1120 paModules[i].achModuleName,
1121 bLen,
1122 &ulDummy));
1123
1124 // module names are not null terminated, so we must
1125 // do it now
1126 paModules[i].achModuleName[bLen] = 0;
1127 } // end for
1128 }
1129 } // end LX
1130 else if (pExec->ulExeFormat == EXEFORMAT_NE)
1131 {
1132 // 16-bit executable:
1133 cModules = pExec->pNEHeader->usModuleTblEntries;
1134
1135 if (cModules)
1136 {
1137 ULONG cb = sizeof(FSYSMODULE) * cModules;
1138
1139 paModules = (PFSYSMODULE)malloc(cb);
1140 if (!paModules)
1141 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY); // V0.9.9 (2001-04-03) [umoeller]
1142
1143 memset(paModules, 0, cb); // V0.9.9 (2001-04-03) [umoeller]
1144
1145 for (i = 0; i < cModules; i ++)
1146 {
1147 BYTE bLen;
1148 USHORT usOfs;
1149 ULONG ulDummy;
1150
1151 // the module reference table contains offsets
1152 // relative to the import table; we hence read
1153 // the offset in the module reference table, and
1154 // then we read the name in the import table
1155
1156 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1157 pExec->pNEHeader->usModRefTblOfs
1158 + ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]
1159 + sizeof(usOfs) * i,
1160 FILE_BEGIN,
1161 &ulDummy));
1162
1163 ENSURE_SAFE(DosRead(pExec->hfExe, &usOfs, 2, &ulDummy));
1164
1165 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1166 pExec->pNEHeader->usImportTblOfs
1167 + ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]
1168 + usOfs,
1169 FILE_BEGIN,
1170 &ulDummy));
1171
1172 ENSURE_SAFE(DosRead(pExec->hfExe, &bLen, 1, &ulDummy));
1173
1174 ENSURE_SAFE(DosRead(pExec->hfExe,
1175 paModules[i].achModuleName,
1176 bLen,
1177 &ulDummy));
1178
1179 paModules[i].achModuleName[bLen] = 0;
1180 } // end for
1181 }
1182 } // end NE
1183 else
1184 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
1185
1186 // no error: output data
1187 *ppaModules = paModules;
1188 *pcModules = cModules;
1189
1190 ENSURE_FINALLY;
1191 // if we had an error above, clean up
1192 free(paModules);
1193 ENSURE_END;
1194 }
1195 else
1196 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
1197
1198 ENSURE_OK;
1199}
1200
1201/*
1202 *@@ doshExecFreeImportedModules:
1203 * frees resources allocated by doshExecQueryImportedModules.
1204 *
1205 *@@added V0.9.9 (2001-03-11)
1206 */
1207
1208APIRET doshExecFreeImportedModules(PFSYSMODULE paModules)
1209{
1210 free(paModules);
1211 return (NO_ERROR);
1212}
1213
1214/*
1215 *@@ ScanLXEntryTable:
1216 * returns the number of exported entries in the entry table.
1217 *
1218 * If paFunctions is not NULL, then successive entries are
1219 * filled with the found type and ordinal values.
1220 *
1221 *@@added V0.9.9 (2001-03-30) [lafaix]
1222 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
1223 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
1224 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
1225 */
1226
1227APIRET ScanLXEntryTable(PEXECUTABLE pExec,
1228 PFSYSFUNCTION paFunctions,
1229 PULONG pcEntries) // out: entry table entry count; ptr can be NULL
1230{
1231 ULONG ulDummy;
1232 USHORT usOrdinal = 1,
1233 usCurrent = 0;
1234 int i;
1235
1236 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]
1237
1238 if (pExec->pDosExeHeader)
1239 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
1240 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
1241
1242 ENSURE(DosSetFilePtr(pExec->hfExe,
1243 pExec->pLXHeader->ulEntryTblOfs
1244 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
1245 FILE_BEGIN,
1246 &ulDummy));
1247
1248 while (TRUE)
1249 {
1250 BYTE bCnt,
1251 bType,
1252 bFlag;
1253
1254 ENSURE(DosRead(pExec->hfExe, &bCnt, 1, &ulDummy));
1255
1256 if (bCnt == 0)
1257 // end of the entry table
1258 break;
1259
1260 ENSURE(DosRead(pExec->hfExe, &bType, 1, &ulDummy));
1261
1262 switch (bType & 0x7F)
1263 {
1264 /*
1265 * unused entries
1266 *
1267 */
1268
1269 case 0:
1270 usOrdinal += bCnt;
1271 break;
1272
1273 /*
1274 * 16-bit entries
1275 *
1276 * the bundle type is followed by the object number
1277 * and by bCnt bFlag+usOffset entries
1278 *
1279 */
1280
1281 case 1:
1282 ENSURE(DosSetFilePtr(pExec->hfExe,
1283 sizeof(USHORT),
1284 FILE_CURRENT,
1285 &ulDummy));
1286
1287 for (i = 0; i < bCnt; i ++)
1288 {
1289 ENSURE(DosRead(pExec->hfExe, &bFlag, 1, &ulDummy));
1290
1291 if (bFlag & 0x01)
1292 {
1293 if (paFunctions)
1294 {
1295 paFunctions[usCurrent].ulOrdinal = usOrdinal;
1296 paFunctions[usCurrent].ulType = 1;
1297 paFunctions[usCurrent].achFunctionName[0] = 0;
1298 }
1299 usCurrent++;
1300 }
1301
1302 usOrdinal++;
1303
1304 ENSURE(DosSetFilePtr(pExec->hfExe,
1305 sizeof(USHORT),
1306 FILE_CURRENT,
1307 &ulDummy));
1308
1309 } // end for
1310 break;
1311
1312 /*
1313 * 286 call gate entries
1314 *
1315 * the bundle type is followed by the object number
1316 * and by bCnt bFlag+usOffset+usCallGate entries
1317 *
1318 */
1319
1320 case 2:
1321 ENSURE(DosSetFilePtr(pExec->hfExe,
1322 sizeof(USHORT),
1323 FILE_CURRENT,
1324 &ulDummy));
1325
1326 for (i = 0; i < bCnt; i ++)
1327 {
1328 ENSURE(DosRead(pExec->hfExe, &bFlag, 1, &ulDummy));
1329
1330 if (bFlag & 0x01)
1331 {
1332 if (paFunctions)
1333 {
1334 paFunctions[usCurrent].ulOrdinal = usOrdinal;
1335 paFunctions[usCurrent].ulType = 2;
1336 paFunctions[usCurrent].achFunctionName[0] = 0;
1337 }
1338 usCurrent++;
1339 }
1340
1341 usOrdinal++;
1342
1343 ENSURE(DosSetFilePtr(pExec->hfExe,
1344 sizeof(USHORT) + sizeof(USHORT),
1345 FILE_CURRENT,
1346 &ulDummy));
1347
1348 } // end for
1349 break;
1350
1351 /*
1352 * 32-bit entries
1353 *
1354 * the bundle type is followed by the object number
1355 * and by bCnt bFlag+ulOffset entries
1356 *
1357 */
1358
1359 case 3:
1360 ENSURE(DosSetFilePtr(pExec->hfExe,
1361 sizeof(USHORT),
1362 FILE_CURRENT,
1363 &ulDummy));
1364
1365 for (i = 0; i < bCnt; i ++)
1366 {
1367 ENSURE(DosRead(pExec->hfExe, &bFlag, 1, &ulDummy));
1368
1369 if (bFlag & 0x01)
1370 {
1371 if (paFunctions)
1372 {
1373 paFunctions[usCurrent].ulOrdinal = usOrdinal;
1374 paFunctions[usCurrent].ulType = 3;
1375 paFunctions[usCurrent].achFunctionName[0] = 0;
1376 }
1377 usCurrent++;
1378 }
1379
1380 usOrdinal++;
1381
1382 ENSURE(DosSetFilePtr(pExec->hfExe,
1383 sizeof(ULONG),
1384 FILE_CURRENT,
1385 &ulDummy));
1386 } // end for
1387 break;
1388
1389 /*
1390 * forwarder entries
1391 *
1392 * the bundle type is followed by a reserved word
1393 * and by bCnt bFlag+usModOrd+ulOffsOrdNum entries
1394 *
1395 */
1396
1397 case 4:
1398 ENSURE(DosSetFilePtr(pExec->hfExe,
1399 sizeof(USHORT),
1400 FILE_CURRENT,
1401 &ulDummy));
1402
1403 for (i = 0; i < bCnt; i ++)
1404 {
1405 ENSURE(DosSetFilePtr(pExec->hfExe,
1406 sizeof(BYTE) + sizeof(USHORT) + sizeof(ULONG),
1407 FILE_CURRENT,
1408 &ulDummy));
1409
1410 if (paFunctions)
1411 {
1412 paFunctions[usCurrent].ulOrdinal = usOrdinal;
1413 paFunctions[usCurrent].ulType = 4;
1414 paFunctions[usCurrent].achFunctionName[0] = 0;
1415 }
1416 usCurrent++;
1417
1418 usOrdinal++;
1419 } // end for
1420 break;
1421
1422 /*
1423 * unknown bundle type
1424 *
1425 * we don't know how to handle this bundle, so we must
1426 * stop parsing the entry table here (as we don't know the
1427 * bundle size); if paFunctions is not null, we fill it with
1428 * informative data
1429 */
1430
1431 default:
1432 if (paFunctions)
1433 {
1434 paFunctions[usCurrent].ulOrdinal = usOrdinal;
1435 paFunctions[usCurrent].ulType = bType;
1436 sprintf(paFunctions[usCurrent].achFunctionName,
1437 "Unknown bundle type encountered (%d). Aborting entry table scan.",
1438 bType);
1439
1440 usCurrent++;
1441 }
1442 ENSURE_FAIL(ERROR_INVALID_LIST_FORMAT);
1443 // whatever
1444 // V0.9.9 (2001-04-03) [umoeller]
1445 } // end switch (bType & 0x7F)
1446 } // end while (TRUE)
1447
1448 if (pcEntries)
1449 *pcEntries = usCurrent;
1450
1451 ENSURE_OK;
1452}
1453
1454/*
1455 *@@ ScanNEEntryTable:
1456 * returns the number of exported entries in the entry table.
1457 *
1458 * if paFunctions is not NULL, then successive entries are
1459 * filled with the found type and ordinal values.
1460 *
1461 *@@added V0.9.9 (2001-03-30) [lafaix]
1462 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
1463 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
1464 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
1465 */
1466
1467APIRET ScanNEEntryTable(PEXECUTABLE pExec,
1468 PFSYSFUNCTION paFunctions,
1469 PULONG pcEntries) // out: entry table entry count; ptr can be NULL
1470{
1471 ULONG ulDummy;
1472 USHORT usOrdinal = 1,
1473 usCurrent = 0;
1474 int i;
1475
1476 ULONG ulNewHeaderOfs = 0;
1477
1478 if (pExec->pDosExeHeader)
1479 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
1480 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
1481
1482 ENSURE(DosSetFilePtr(pExec->hfExe,
1483 pExec->pNEHeader->usEntryTblOfs
1484 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
1485 FILE_BEGIN,
1486 &ulDummy));
1487
1488 while (TRUE)
1489 {
1490 BYTE bCnt,
1491 bType,
1492 bFlag;
1493
1494 ENSURE(DosRead(pExec->hfExe, &bCnt, 1, &ulDummy));
1495
1496 if (bCnt == 0)
1497 // end of the entry table
1498 break;
1499
1500 ENSURE(DosRead(pExec->hfExe, &bType, 1, &ulDummy));
1501
1502 if (bType)
1503 {
1504 for (i = 0; i < bCnt; i++)
1505 {
1506 ENSURE(DosRead(pExec->hfExe,
1507 &bFlag,
1508 1,
1509 &ulDummy));
1510
1511 if (bFlag & 0x01)
1512 {
1513 if (paFunctions)
1514 {
1515 paFunctions[usCurrent].ulOrdinal = usOrdinal;
1516 paFunctions[usCurrent].ulType = 1; // 16-bit entry
1517 paFunctions[usCurrent].achFunctionName[0] = 0;
1518 }
1519 usCurrent++;
1520 }
1521
1522 usOrdinal++;
1523
1524 if (bType == 0xFF)
1525 {
1526 // moveable segment
1527 ENSURE(DosSetFilePtr(pExec->hfExe,
1528 5,
1529 FILE_CURRENT,
1530 &ulDummy));
1531 }
1532 else
1533 {
1534 // fixed segment or constant (0xFE)
1535 ENSURE(DosSetFilePtr(pExec->hfExe,
1536 2,
1537 FILE_CURRENT,
1538 &ulDummy));
1539 }
1540
1541 } // end for
1542 }
1543 else
1544 usOrdinal += bCnt;
1545 } // end while (TRUE)
1546
1547 if (pcEntries)
1548 *pcEntries = usCurrent;
1549
1550 ENSURE_OK;
1551}
1552
1553/*
1554 *@@ Compare:
1555 * binary search helper
1556 *
1557 *@@added V0.9.9 (2001-04-01) [lafaix]
1558 *@@changed V0.9.9 (2001-04-07) [umoeller]: added _Optlink, or this won't compile as C++
1559 */
1560
1561int _Optlink Compare(const void *key,
1562 const void *element)
1563{
1564 USHORT usOrdinal = *((PUSHORT) key);
1565 PFSYSFUNCTION pFunction = (PFSYSFUNCTION)element;
1566
1567 if (usOrdinal > pFunction->ulOrdinal)
1568 return (1);
1569 else if (usOrdinal < pFunction->ulOrdinal)
1570 return (-1);
1571 else
1572 return (0);
1573}
1574
1575/*
1576 *@@ ScanNameTable:
1577 * scans a resident or non-resident name table, and fills the
1578 * appropriate paFunctions entries when it encounters exported
1579 * entries names.
1580 *
1581 * This functions works for both NE and LX executables.
1582 *
1583 *@@added V0.9.9 (2001-03-30) [lafaix]
1584 *@@changed V0.9.9 (2001-04-02) [lafaix]: the first entry is special
1585 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
1586 *@@changed V0.9.9 (2001-04-05) [lafaix]: removed the 127 char limit
1587 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
1588 */
1589
1590APIRET ScanNameTable(PEXECUTABLE pExec,
1591 ULONG cFunctions,
1592 PFSYSFUNCTION paFunctions)
1593{
1594 ULONG ulDummy;
1595
1596 USHORT usOrdinal;
1597 PFSYSFUNCTION pFunction;
1598
1599 while (TRUE)
1600 {
1601 BYTE bLen;
1602 CHAR achName[256];
1603 // int i;
1604
1605 ENSURE(DosRead(pExec->hfExe, &bLen, 1, &ulDummy));
1606
1607 if (bLen == 0)
1608 // end of the name table
1609 break;
1610
1611 ENSURE(DosRead(pExec->hfExe, &achName, bLen, &ulDummy));
1612 achName[bLen] = 0;
1613
1614 ENSURE(DosRead(pExec->hfExe, &usOrdinal, sizeof(USHORT), &ulDummy));
1615
1616 if ((pFunction = (PFSYSFUNCTION)bsearch(&usOrdinal,
1617 paFunctions,
1618 cFunctions,
1619 sizeof(FSYSFUNCTION),
1620 Compare)))
1621 {
1622 memcpy(pFunction->achFunctionName,
1623 achName,
1624 bLen+1);
1625 }
1626 }
1627
1628 ENSURE_OK;
1629}
1630
1631/*
1632 *@@ doshExecQueryExportedFunctions:
1633 * returns an array of FSYSFUNCTION structure describing all
1634 * exported functions.
1635 *
1636 * *pcFunctions receives the # of items in the array (not the
1637 * array size!). Use doshFreeExportedFunctions to clean up.
1638 *
1639 * Note that the returned array only contains entry for exported
1640 * functions. Empty export entries are _not_ included.
1641 *
1642 * This returns a standard OS/2 error code, which might be
1643 * any of the codes returned by DosSetFilePtr and DosRead.
1644 * In addition, this may return:
1645 *
1646 * -- ERROR_NOT_ENOUGH_MEMORY
1647 *
1648 * -- ERROR_INVALID_EXE_SIGNATURE: exe is in a format other
1649 * than LX or NE, which is not understood by this function.
1650 *
1651 * -- If ERROR_INVALID_LIST_FORMAT is returned, the format of an
1652 * export entry wasn't understood here.
1653 *
1654 * Even if NO_ERROR is returned, the array pointer might still
1655 * be NULL if the module contains no such data.
1656 *
1657 *@@added V0.9.9 (2001-03-11) [lafaix]
1658 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
1659 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
1660 *@@changed V0.9.10 (2001-04-10) [lafaix]: added Win16 and Win386 support
1661 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
1662 */
1663
1664APIRET doshExecQueryExportedFunctions(PEXECUTABLE pExec,
1665 PFSYSFUNCTION *ppaFunctions, // out: functions array
1666 PULONG pcFunctions) // out: array item count
1667{
1668 if ( (pExec)
1669 && ( (pExec->ulOS == EXEOS_OS2)
1670 || (pExec->ulOS == EXEOS_WIN16)
1671 || (pExec->ulOS == EXEOS_WIN386)
1672 )
1673 )
1674 {
1675 ENSURE_BEGIN;
1676 ULONG cFunctions = 0;
1677 PFSYSFUNCTION paFunctions = NULL;
1678
1679 ULONG ulDummy;
1680
1681 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]
1682
1683 if (pExec->pDosExeHeader)
1684 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
1685 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
1686
1687 if (pExec->ulExeFormat == EXEFORMAT_LX)
1688 {
1689 // It's a 32bit OS/2 executable
1690
1691 // the number of exported entry points is not stored
1692 // in the executable header; we have to count them in
1693 // the entry table
1694
1695 ENSURE(ScanLXEntryTable(pExec, NULL, &cFunctions));
1696
1697 // we now have the number of exported entries; let us
1698 // build them
1699
1700 if (cFunctions)
1701 {
1702 ULONG cb = sizeof(FSYSFUNCTION) * cFunctions;
1703
1704 paFunctions = (PFSYSFUNCTION)malloc(cb);
1705 if (!paFunctions)
1706 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
1707
1708 // we rescan the entry table (the cost is not as bad
1709 // as it may seem, due to disk caching)
1710
1711 ENSURE_SAFE(ScanLXEntryTable(pExec, paFunctions, NULL));
1712
1713 // we now scan the resident name table entries
1714
1715 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1716 pExec->pLXHeader->ulResdNameTblOfs
1717 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
1718 FILE_BEGIN,
1719 &ulDummy));
1720
1721 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
1722
1723 // we now scan the non-resident name table entries,
1724 // whose offset is _from the begining of the file_
1725
1726 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1727 pExec->pLXHeader->ulNonResdNameTblOfs,
1728 FILE_BEGIN,
1729 &ulDummy));
1730
1731 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
1732 } // end if (cFunctions)
1733 }
1734 else if (pExec->ulExeFormat == EXEFORMAT_NE)
1735 {
1736 // it's a "new" segmented 16bit executable
1737
1738 // here too the number of exported entry points
1739 // is not stored in the executable header; we
1740 // have to count them in the entry table
1741
1742 ENSURE(ScanNEEntryTable(pExec, NULL, &cFunctions));
1743
1744 // we now have the number of exported entries; let us
1745 // build them
1746
1747 if (cFunctions)
1748 {
1749 // USHORT usOrdinal = 1;
1750 // usCurrent = 0;
1751
1752 paFunctions = (PFSYSFUNCTION)malloc(sizeof(FSYSFUNCTION) * cFunctions);
1753 if (!paFunctions)
1754 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
1755
1756 // we rescan the entry table (the cost is not as bad
1757 // as it may seem, due to disk caching)
1758
1759 ENSURE_SAFE(ScanNEEntryTable(pExec, paFunctions, NULL));
1760
1761 // we now scan the resident name table entries
1762
1763 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1764 pExec->pNEHeader->usResdNameTblOfs
1765 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
1766 FILE_BEGIN,
1767 &ulDummy));
1768
1769 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
1770
1771 // we now scan the non-resident name table entries,
1772 // whose offset is _from the begining of the file_
1773
1774 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1775 pExec->pNEHeader->ulNonResdTblOfs,
1776 FILE_BEGIN,
1777 &ulDummy));
1778
1779 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
1780 }
1781 }
1782 else
1783 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
1784
1785 // no error: output data
1786 *ppaFunctions = paFunctions;
1787 *pcFunctions = cFunctions;
1788
1789 ENSURE_FINALLY;
1790 // if we had an error above, clean up
1791 free(paFunctions);
1792 ENSURE_END;
1793 }
1794 else
1795 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
1796
1797 ENSURE_OK;
1798}
1799
1800/*
1801 *@@ doshExecFreeExportedFunctions:
1802 * frees resources allocated by doshExecQueryExportedFunctions.
1803 *
1804 *@@added V0.9.9 (2001-03-11)
1805 */
1806
1807APIRET doshExecFreeExportedFunctions(PFSYSFUNCTION paFunctions)
1808{
1809 free(paFunctions);
1810
1811 return (NO_ERROR);
1812}
1813
1814/*
1815 *@@ doshExecQueryResources:
1816 * returns an array of FSYSRESOURCE structures describing all
1817 * available resources in the module.
1818 *
1819 * *pcResources receives the no. of items in the array
1820 * (not the array size!). Use doshExecFreeResources to clean up.
1821 *
1822 * This returns a standard OS/2 error code, which might be
1823 * any of the codes returned by DosSetFilePtr and DosRead.
1824 * In addition, this may return:
1825 *
1826 * -- ERROR_NOT_ENOUGH_MEMORY
1827 *
1828 * -- ERROR_INVALID_EXE_SIGNATURE: exe is in a format other
1829 * than LX or NE, which is not understood by this function.
1830 *
1831 * Even if NO_ERROR is returned, the array pointer might still
1832 * be NULL if the module contains no such data.
1833 *
1834 *@@added V0.9.7 (2000-12-18) [lafaix]
1835 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
1836 *@@changed V0.9.10 (2001-04-10) [lafaix]: added Win16 and Win386 support
1837 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
1838 */
1839
1840APIRET doshExecQueryResources(PEXECUTABLE pExec, // in: executable from doshExecOpen
1841 PFSYSRESOURCE *ppaResources, // out: res's array
1842 PULONG pcResources) // out: array item count
1843{
1844 if ( (pExec)
1845 && ( (pExec->ulOS == EXEOS_OS2)
1846 || (pExec->ulOS == EXEOS_WIN16)
1847 || (pExec->ulOS == EXEOS_WIN386)
1848 )
1849 )
1850 {
1851 ENSURE_BEGIN;
1852 ULONG cResources = 0;
1853 PFSYSRESOURCE paResources = NULL;
1854
1855 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]
1856
1857 if (pExec->pDosExeHeader)
1858 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
1859 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
1860
1861 if (pExec->ulExeFormat == EXEFORMAT_LX)
1862 {
1863 // 32-bit OS/2 executable:
1864 cResources = pExec->pLXHeader->ulResTblCnt;
1865
1866 if (cResources)
1867 {
1868 #pragma pack(1) // V0.9.9 (2001-04-02) [umoeller]
1869 struct rsrc32 /* Resource Table Entry */
1870 {
1871 unsigned short type; /* Resource type */
1872 unsigned short name; /* Resource name */
1873 unsigned long cb; /* Resource size */
1874 unsigned short obj; /* Object number */
1875 unsigned long offset; /* Offset within object */
1876 } rs;
1877
1878 struct o32_obj /* Flat .EXE object table entry */
1879 {
1880 unsigned long o32_size; /* Object virtual size */
1881 unsigned long o32_base; /* Object base virtual address */
1882 unsigned long o32_flags; /* Attribute flags */
1883 unsigned long o32_pagemap; /* Object page map index */
1884 unsigned long o32_mapsize; /* Number of entries in object page map */
1885 unsigned long o32_reserved; /* Reserved */
1886 } ot;
1887 #pragma pack() // V0.9.9 (2001-04-03) [umoeller]
1888
1889 ULONG cb = sizeof(FSYSRESOURCE) * cResources;
1890 ULONG ulDummy;
1891 int i;
1892
1893 paResources = (PFSYSRESOURCE)malloc(cb);
1894 if (!paResources)
1895 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
1896
1897 memset(paResources, 0, cb); // V0.9.9 (2001-04-03) [umoeller]
1898
1899 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1900 pExec->pLXHeader->ulResTblOfs
1901 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
1902 FILE_BEGIN,
1903 &ulDummy));
1904
1905 for (i = 0; i < cResources; i++)
1906 {
1907 ENSURE_SAFE(DosRead(pExec->hfExe, &rs, 14, &ulDummy));
1908
1909 paResources[i].ulID = rs.name;
1910 paResources[i].ulType = rs.type;
1911 paResources[i].ulSize = rs.cb;
1912 paResources[i].ulFlag = rs.obj; // Temp storage for Object
1913 // number. Will be filled
1914 // with resource flag
1915 // later.
1916 }
1917
1918 for (i = 0; i < cResources; i++)
1919 {
1920 ULONG ulOfsThis = pExec->pLXHeader->ulObjTblOfs
1921 + ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]
1922 + ( sizeof(ot)
1923 * (paResources[i].ulFlag - 1));
1924
1925 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1926 ulOfsThis,
1927 FILE_BEGIN,
1928 &ulDummy));
1929
1930 ENSURE_SAFE(DosRead(pExec->hfExe, &ot, sizeof(ot), &ulDummy));
1931
1932 paResources[i].ulFlag = ((ot.o32_flags & OBJWRITE)
1933 ? 0
1934 : RNPURE);
1935 paResources[i].ulFlag |= ((ot.o32_flags & OBJDISCARD)
1936 ? 4096
1937 : 0);
1938 paResources[i].ulFlag |= ((ot.o32_flags & OBJSHARED)
1939 ? RNMOVE
1940 : 0);
1941 paResources[i].ulFlag |= ((ot.o32_flags & OBJPRELOAD)
1942 ? RNPRELOAD
1943 : 0);
1944 } // end for
1945 } // end if (cResources)
1946 } // end if (pExec->ulExeFormat == EXEFORMAT_LX)
1947 else if (pExec->ulExeFormat == EXEFORMAT_NE)
1948 {
1949 if (pExec->ulOS == EXEOS_OS2)
1950 {
1951 // 16-bit OS/2 executable:
1952 cResources = pExec->pNEHeader->usResSegmCount;
1953
1954 if (cResources)
1955 {
1956 #pragma pack(1) // V0.9.9 (2001-04-02) [umoeller]
1957 struct {unsigned short type; unsigned short name;} rti;
1958 struct new_seg /* New .EXE segment table entry */
1959 {
1960 unsigned short ns_sector; /* File sector of start of segment */
1961 unsigned short ns_cbseg; /* Number of bytes in file */
1962 unsigned short ns_flags; /* Attribute flags */
1963 unsigned short ns_minalloc; /* Minimum allocation in bytes */
1964 } ns;
1965 #pragma pack()
1966
1967 ULONG cb = sizeof(FSYSRESOURCE) * cResources;
1968 ULONG ulDummy;
1969 int i;
1970
1971 paResources = (PFSYSRESOURCE)malloc(cb);
1972 if (!paResources)
1973 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
1974
1975 memset(paResources, 0, cb); // V0.9.9 (2001-04-03) [umoeller]
1976
1977 // we first read the resources IDs and types
1978
1979 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1980 pExec->pNEHeader->usResTblOfs
1981 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
1982 FILE_BEGIN,
1983 &ulDummy));
1984
1985 for (i = 0; i < cResources; i++)
1986 {
1987 ENSURE_SAFE(DosRead(pExec->hfExe, &rti, sizeof(rti), &ulDummy));
1988
1989 paResources[i].ulID = rti.name;
1990 paResources[i].ulType = rti.type;
1991 }
1992
1993 // we then read their sizes and flags
1994
1995 for (i = 0; i < cResources; i++)
1996 {
1997 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
1998 ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]
1999 + pExec->pNEHeader->usSegTblOfs
2000 + (sizeof(ns)
2001 * ( pExec->pNEHeader->usSegTblEntries
2002 - pExec->pNEHeader->usResSegmCount
2003 + i)),
2004 FILE_BEGIN,
2005 &ulDummy));
2006
2007 ENSURE_SAFE(DosRead(pExec->hfExe, &ns, sizeof(ns), &ulDummy));
2008
2009 paResources[i].ulSize = ns.ns_cbseg;
2010
2011 paResources[i].ulFlag = (ns.ns_flags & OBJPRELOAD) ? RNPRELOAD : 0;
2012 paResources[i].ulFlag |= (ns.ns_flags & OBJSHARED) ? RNPURE : 0;
2013 paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? RNMOVE : 0;
2014 paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? 4096 : 0;
2015 }
2016 } // end if (cResources)
2017 }
2018 else
2019 {
2020 // 16-bit Windows executable
2021 USHORT usAlignShift;
2022 ULONG ulDummy;
2023
2024 ENSURE(DosSetFilePtr(pExec->hfExe,
2025 pExec->pNEHeader->usResTblOfs
2026 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
2027 FILE_BEGIN,
2028 &ulDummy));
2029
2030 ENSURE(DosRead(pExec->hfExe,
2031 &usAlignShift,
2032 sizeof(usAlignShift),
2033 &ulDummy));
2034
2035 while (TRUE)
2036 {
2037 USHORT usTypeID;
2038 USHORT usCount;
2039
2040 ENSURE(DosRead(pExec->hfExe,
2041 &usTypeID,
2042 sizeof(usTypeID),
2043 &ulDummy));
2044
2045 if (usTypeID == 0)
2046 break;
2047
2048 ENSURE(DosRead(pExec->hfExe,
2049 &usCount,
2050 sizeof(usCount),
2051 &ulDummy));
2052
2053 ENSURE(DosSetFilePtr(pExec->hfExe,
2054 sizeof(ULONG),
2055 FILE_CURRENT,
2056 &ulDummy));
2057
2058 cResources += usCount;
2059
2060 // first pass, skip NAMEINFO table
2061 ENSURE(DosSetFilePtr(pExec->hfExe,
2062 usCount*6*sizeof(USHORT),
2063 FILE_CURRENT,
2064 &ulDummy));
2065 }
2066
2067 if (cResources)
2068 {
2069 USHORT usCurrent = 0;
2070 ULONG cb = sizeof(FSYSRESOURCE) * cResources;
2071
2072 paResources = (PFSYSRESOURCE)malloc(cb);
2073 if (!paResources)
2074 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
2075
2076 memset(paResources, 0, cb);
2077
2078 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
2079 pExec->pNEHeader->usResTblOfs
2080 + ulNewHeaderOfs,
2081 FILE_BEGIN,
2082 &ulDummy));
2083
2084 ENSURE_SAFE(DosRead(pExec->hfExe,
2085 &usAlignShift,
2086 sizeof(usAlignShift),
2087 &ulDummy));
2088
2089 while (TRUE)
2090 {
2091 USHORT usTypeID;
2092 USHORT usCount;
2093 int i;
2094
2095 ENSURE_SAFE(DosRead(pExec->hfExe,
2096 &usTypeID,
2097 sizeof(usTypeID),
2098 &ulDummy));
2099
2100 if (usTypeID == 0)
2101 break;
2102
2103 ENSURE_SAFE(DosRead(pExec->hfExe,
2104 &usCount,
2105 sizeof(usCount),
2106 &ulDummy));
2107
2108 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
2109 sizeof(ULONG),
2110 FILE_CURRENT,
2111 &ulDummy));
2112
2113 // second pass, read NAMEINFO table
2114 for (i = 0; i < usCount; i++)
2115 {
2116 USHORT usLength,
2117 usFlags,
2118 usID;
2119
2120 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
2121 sizeof(USHORT),
2122 FILE_CURRENT,
2123 &ulDummy));
2124
2125 ENSURE_SAFE(DosRead(pExec->hfExe,
2126 &usLength,
2127 sizeof(USHORT),
2128 &ulDummy));
2129 ENSURE_SAFE(DosRead(pExec->hfExe,
2130 &usFlags,
2131 sizeof(USHORT),
2132 &ulDummy));
2133 ENSURE_SAFE(DosRead(pExec->hfExe,
2134 &usID,
2135 sizeof(USHORT),
2136 &ulDummy));
2137
2138 ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
2139 2*sizeof(USHORT),
2140 FILE_CURRENT,
2141 &ulDummy));
2142
2143 // !!! strings ids and types not handled yet
2144 // !!! 15th bit is used to denotes strings
2145 // !!! offsets [lafaix]
2146 paResources[usCurrent].ulType = usTypeID ^ 0x8000;
2147 paResources[usCurrent].ulID = usID ^ 0x8000;
2148 paResources[usCurrent].ulSize = usLength << usAlignShift;
2149 paResources[usCurrent].ulFlag = usFlags & 0x70;
2150
2151 usCurrent++;
2152 }
2153 }
2154 }
2155 }
2156 } // end else if (pExec->ulExeFormat == EXEFORMAT_NE)
2157 else
2158 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
2159
2160 *ppaResources = paResources;
2161 *pcResources = cResources;
2162
2163 ENSURE_FINALLY;
2164 // if we had an error above, clean up
2165 free(paResources);
2166 ENSURE_END;
2167 }
2168 else
2169 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
2170
2171 ENSURE_OK;
2172}
2173
2174/*
2175 *@@ doshExecFreeResources:
2176 * frees resources allocated by doshExecQueryResources.
2177 *
2178 *@@added V0.9.7 (2000-12-18) [lafaix]
2179 */
2180
2181APIRET doshExecFreeResources(PFSYSRESOURCE paResources)
2182{
2183 free(paResources);
2184 return (NO_ERROR);
2185}
2186
2187/*
2188 * FindFile:
2189 * helper for doshFindExecutable.
2190 *
2191 *added V0.9.11 (2001-04-25) [umoeller]
2192 */
2193
2194APIRET FindFile(const char *pcszCommand, // in: command (e.g. "lvm")
2195 PSZ pszExecutable, // out: full path (e.g. "F:\os2\lvm.exe")
2196 ULONG cbExecutable) // in: sizeof (*pszExecutable)
2197{
2198 APIRET arc = NO_ERROR;
2199 FILESTATUS3 fs3;
2200
2201 if ( (strchr(pcszCommand, '\\'))
2202 || (strchr(pcszCommand, ':'))
2203 )
2204 {
2205 // looks like this is qualified:
2206 arc = DosQueryPathInfo((PSZ)pcszCommand,
2207 FIL_STANDARD,
2208 &fs3,
2209 sizeof(fs3));
2210 if (!arc)
2211 if (!(fs3.attrFile & FILE_DIRECTORY))
2212 strhncpy0(pszExecutable,
2213 pcszCommand,
2214 cbExecutable);
2215 else
2216 // directory:
2217 arc = ERROR_INVALID_EXE_SIGNATURE;
2218 }
2219 else
2220 // non-qualified:
2221 arc = DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY,
2222 "PATH",
2223 (PSZ)pcszCommand,
2224 pszExecutable,
2225 cbExecutable);
2226
2227 return (arc);
2228}
2229
2230/*
2231 *@@ doshFindExecutable:
2232 * this attempts to find an executable by doing the
2233 * following:
2234 *
2235 * 1) If pcszCommand appears to be qualified (i.e. contains
2236 * a backslash), this checks for whether the file exists.
2237 *
2238 * 2) If pcszCommand contains no backslash, this calls
2239 * DosSearchPath in order to find the full path of the
2240 * executable.
2241 *
2242 * papcszExtensions determines if additional searches are to be
2243 * performed if the file doesn't exist (case 1) or DosSearchPath
2244 * returned ERROR_FILE_NOT_FOUND (case 2).
2245 * This must point to an array of strings specifying the extra
2246 * extensions to search for.
2247 *
2248 * If both papcszExtensions and cExtensions are null, no
2249 * extra searches are performed.
2250 *
2251 * If this returns NO_ERROR, pszExecutable receives
2252 * the full path of the executable found by DosSearchPath.
2253 * Otherwise ERROR_FILE_NOT_FOUND is returned.
2254 *
2255 * Example:
2256 *
2257 + const char *aExtensions[] = { "EXE",
2258 + "COM",
2259 + "CMD"
2260 + };
2261 + CHAR szExecutable[CCHMAXPATH];
2262 + APIRET arc = doshFindExecutable("lvm",
2263 + szExecutable,
2264 + sizeof(szExecutable),
2265 + aExtensions,
2266 + 3);
2267 *
2268 *@@added V0.9.9 (2001-03-07) [umoeller]
2269 *@@changed V0.9.11 (2001-04-25) [umoeller]: this never worked for qualified pcszCommand's, fixed
2270 */
2271
2272APIRET doshFindExecutable(const char *pcszCommand, // in: command (e.g. "lvm")
2273 PSZ pszExecutable, // out: full path (e.g. "F:\os2\lvm.exe")
2274 ULONG cbExecutable, // in: sizeof (*pszExecutable)
2275 const char **papcszExtensions, // in: array of extensions (without dots)
2276 ULONG cExtensions) // in: array item count
2277{
2278 APIRET arc = FindFile(pcszCommand,
2279 pszExecutable,
2280 cbExecutable);
2281
2282 if ( (arc == ERROR_FILE_NOT_FOUND) // not found?
2283 && (cExtensions) // any extra searches wanted?
2284 )
2285 {
2286 // try additional things then
2287 PSZ psz2 = (PSZ)malloc(strlen(pcszCommand) + 20);
2288 if (psz2)
2289 {
2290 ULONG ul;
2291 for (ul = 0;
2292 ul < cExtensions;
2293 ul++)
2294 {
2295 const char *pcszExtThis = papcszExtensions[ul];
2296 sprintf(psz2, "%s.%s", pcszCommand, pcszExtThis);
2297 arc = FindFile(psz2,
2298 pszExecutable,
2299 cbExecutable);
2300 if (arc != ERROR_FILE_NOT_FOUND)
2301 break;
2302 }
2303
2304 free(psz2);
2305 }
2306 else
2307 arc = ERROR_NOT_ENOUGH_MEMORY;
2308 }
2309
2310 return (arc);
2311}
2312
2313/*
2314 *@@category: Helpers\Control program helpers\Partitions info
2315 * functions for retrieving partition information directly
2316 * from the partition tables on the disk. See doshGetPartitionsList.
2317 */
2318
2319/********************************************************************
2320 *
2321 * Partition functions
2322 *
2323 ********************************************************************/
2324
2325/*
2326 *@@ doshQueryDiskCount:
2327 * returns the no. of physical disks installed
2328 * on the system.
2329 *
2330 * Based on code (C) Dmitry A. Steklenev.
2331 *
2332 *@@added V0.9.0 [umoeller]
2333 */
2334
2335UINT doshQueryDiskCount(VOID)
2336{
2337 USHORT count = 0;
2338
2339 DosPhysicalDisk(INFO_COUNT_PARTITIONABLE_DISKS, &count, 2, 0, 0);
2340 return (count);
2341}
2342
2343/*
2344 *@@ doshReadSector:
2345 * reads a physical disk sector.
2346 *
2347 * If NO_ERROR is returned, the sector contents
2348 * have been stored in *buff.
2349 *
2350 * Based on code (C) Dmitry A. Steklenev.
2351 *
2352 *@@added V0.9.0 [umoeller]
2353 *@@changed V0.9.9 (2001-04-04) [umoeller]: added more error checking
2354 */
2355
2356APIRET doshReadSector(USHORT disk, // in: physical disk no. (1, 2, 3, ...)
2357 void *buff,
2358 USHORT head,
2359 USHORT cylinder,
2360 USHORT sector)
2361{
2362 APIRET arc;
2363 HFILE dh = 0;
2364 char dn[256];
2365
2366 sprintf(dn, "%u:", disk);
2367 if (!(arc = DosPhysicalDisk(INFO_GETIOCTLHANDLE, &dh, 2, dn, 3)))
2368 {
2369 TRACKLAYOUT DiskIOParm;
2370 ULONG IOCtlDataLength = sizeof(DiskIOParm);
2371 ULONG IOCtlParmLength = 512;
2372
2373 DiskIOParm.bCommand = 0;
2374 DiskIOParm.usHead = head;
2375 DiskIOParm.usCylinder = cylinder;
2376 DiskIOParm.usFirstSector = 0;
2377 DiskIOParm.cSectors = 1;
2378 DiskIOParm.TrackTable[0].usSectorNumber = sector;
2379 DiskIOParm.TrackTable[0].usSectorSize = 512;
2380
2381 arc = DosDevIOCtl(dh,
2382 IOCTL_PHYSICALDISK, PDSK_READPHYSTRACK,
2383 &DiskIOParm, IOCtlParmLength, &IOCtlParmLength,
2384 buff , IOCtlDataLength, &IOCtlDataLength);
2385
2386 DosPhysicalDisk(INFO_FREEIOCTLHANDLE, 0, 0, &dh, 2);
2387 }
2388
2389 return (arc);
2390}
2391
2392/*
2393 *@@ doshType2FSName:
2394 * this returns a static, zero-terminated string
2395 * for the given FS type. This is always 7 bytes
2396 * in length.
2397 *
2398 * Values for operating system indicator:
2399 * -- 00h empty
2400 * -- 01h DOS 12-bit FAT
2401 * -- 02h XENIX root file system
2402 * -- 03h XENIX /usr file system (obsolete)
2403 * -- 04h DOS 16-bit FAT (up to 32M)
2404 * -- 05h DOS 3.3+ extended partition
2405 * -- 06h DOS 3.31+ Large File System (16-bit FAT, over 32M)
2406 * -- 07h QNX
2407 * -- 07h OS/2 HPFS
2408 * -- 07h Windows NT NTFS
2409 * -- 07h Advanced Unix
2410 * -- 08h OS/2 (v1.0-1.3 only)
2411 * -- 08h AIX bootable partition, SplitDrive
2412 * -- 08h Commodore DOS
2413 * -- 08h DELL partition spanning multiple drives
2414 * -- 09h AIX data partition
2415 * -- 09h Coherent filesystem
2416 * -- 0Ah OS/2 Boot Manager
2417 * -- 0Ah OPUS
2418 * -- 0Ah Coherent swap partition
2419 * -- 0Bh Windows95 with 32-bit FAT
2420 * -- 0Ch Windows95 with 32-bit FAT (using LBA-mode INT 13 extensions)
2421 * -- 0Eh logical-block-addressable VFAT (same as 06h but using LBA-mode INT 13)
2422 * -- 0Fh logical-block-addressable VFAT (same as 05h but using LBA-mode INT 13)
2423 * -- 10h OPUS
2424 * -- 11h OS/2 Boot Manager hidden 12-bit FAT partition
2425 * -- 12h Compaq Diagnostics partition
2426 * -- 14h (resulted from using Novell DOS 7.0 FDISK to delete Linux Native part)
2427 * -- 14h OS/2 Boot Manager hidden sub-32M 16-bit FAT partition
2428 * -- 16h OS/2 Boot Manager hidden over-32M 16-bit FAT partition
2429 * -- 17h OS/2 Boot Manager hidden HPFS partition
2430 * -- 18h AST special Windows swap file ("Zero-Volt Suspend" partition)
2431 * -- 21h officially listed as reserved
2432 * -- 23h officially listed as reserved
2433 * -- 24h NEC MS-DOS 3.x
2434 * -- 26h officially listed as reserved
2435 * -- 31h officially listed as reserved
2436 * -- 33h officially listed as reserved
2437 * -- 34h officially listed as reserved
2438 * -- 36h officially listed as reserved
2439 * -- 38h Theos
2440 * -- 3Ch PowerQuest PartitionMagic recovery partition
2441 * -- 40h VENIX 80286
2442 * -- 41h Personal RISC Boot
2443 * -- 42h SFS (Secure File System) by Peter Gutmann
2444 * -- 50h OnTrack Disk Manager, read-only partition
2445 * -- 51h OnTrack Disk Manager, read/write partition
2446 * -- 51h NOVEL
2447 * -- 52h CP/M
2448 * -- 52h Microport System V/386
2449 * -- 53h OnTrack Disk Manager, write-only partition???
2450 * -- 54h OnTrack Disk Manager (DDO)
2451 * -- 56h GoldenBow VFeature
2452 * -- 61h SpeedStor
2453 * -- 63h Unix SysV/386, 386/ix
2454 * -- 63h Mach, MtXinu BSD 4.3 on Mach
2455 * -- 63h GNU HURD
2456 * -- 64h Novell NetWare 286
2457 * -- 65h Novell NetWare (3.11)
2458 * -- 67h Novell
2459 * -- 68h Novell
2460 * -- 69h Novell
2461 * -- 70h DiskSecure Multi-Boot
2462 * -- 71h officially listed as reserved
2463 * -- 73h officially listed as reserved
2464 * -- 74h officially listed as reserved
2465 * -- 75h PC/IX
2466 * -- 76h officially listed as reserved
2467 * -- 80h Minix v1.1 - 1.4a
2468 * -- 81h Minix v1.4b+
2469 * -- 81h Linux
2470 * -- 81h Mitac Advanced Disk Manager
2471 * -- 82h Linux Swap partition
2472 * -- 82h Prime
2473 * -- 83h Linux native file system (ext2fs/xiafs)
2474 * -- 84h OS/2-renumbered type 04h partition (related to hiding DOS C: drive)
2475 * -- 86h FAT16 volume/stripe set (Windows NT)
2476 * -- 87h HPFS Fault-Tolerant mirrored partition
2477 * -- 87h NTFS volume/stripe set
2478 * -- 93h Amoeba file system
2479 * -- 94h Amoeba bad block table
2480 * -- A0h Phoenix NoteBIOS Power Management "Save-to-Disk" partition
2481 * -- A1h officially listed as reserved
2482 * -- A3h officially listed as reserved
2483 * -- A4h officially listed as reserved
2484 * -- A5h FreeBSD, BSD/386
2485 * -- A6h officially listed as reserved
2486 * -- B1h officially listed as reserved
2487 * -- B3h officially listed as reserved
2488 * -- B4h officially listed as reserved
2489 * -- B6h officially listed as reserved
2490 * -- B7h BSDI file system (secondarily swap)
2491 * -- B8h BSDI swap partition (secondarily file system)
2492 * -- C1h DR DOS 6.0 LOGIN.EXE-secured 12-bit FAT partition
2493 * -- C4h DR DOS 6.0 LOGIN.EXE-secured 16-bit FAT partition
2494 * -- C6h DR DOS 6.0 LOGIN.EXE-secured Huge partition
2495 * -- C6h corrupted FAT16 volume/stripe set (Windows NT)
2496 * -- C7h Syrinx Boot
2497 * -- C7h corrupted NTFS volume/stripe set
2498 * -- D8h CP/M-86
2499 * -- DBh CP/M, Concurrent CP/M, Concurrent DOS
2500 * -- DBh CTOS (Convergent Technologies OS)
2501 * -- E1h SpeedStor 12-bit FAT extended partition
2502 * -- E3h DOS read-only
2503 * -- E3h Storage Dimensions
2504 * -- E4h SpeedStor 16-bit FAT extended partition
2505 * -- E5h officially listed as reserved
2506 * -- E6h officially listed as reserved
2507 * -- F1h Storage Dimensions
2508 * -- F2h DOS 3.3+ secondary partition
2509 * -- F3h officially listed as reserved
2510 * -- F4h SpeedStor
2511 * -- F4h Storage Dimensions
2512 * -- F6h officially listed as reserved
2513 * -- FEh LANstep
2514 * -- FEh IBM PS/2 IML
2515 * -- FFh Xenix bad block table
2516 *
2517 * Note: for partition type 07h, one should inspect the partition boot record
2518 * for the actual file system type
2519 *
2520 * Based on code (C) Dmitry A. Steklenev.
2521 *
2522 *@@added V0.9.0 [umoeller]
2523 */
2524
2525const char* doshType2FSName(unsigned char bFSType) // in: FS type
2526{
2527 PSZ zFSName = NULL;
2528
2529 switch (bFSType)
2530 {
2531 case PAR_UNUSED:
2532 zFSName = "UNUSED ";
2533 break;
2534 case PAR_FAT12SMALL:
2535 zFSName = "FAT-12 ";
2536 break;
2537 case PAR_XENIXROOT:
2538 zFSName = "XENIX ";
2539 break;
2540 case PAR_XENIXUSER:
2541 zFSName = "XENIX ";
2542 break;
2543 case PAR_FAT16SMALL:
2544 zFSName = "FAT-16 ";
2545 break;
2546 case PAR_EXTENDED:
2547 zFSName = "EXTEND ";
2548 break;
2549 case PAR_FAT16BIG:
2550 zFSName = "BIGDOS ";
2551 break;
2552 case PAR_HPFS:
2553 zFSName = "HPFS ";
2554 break;
2555 case PAR_AIXBOOT:
2556 zFSName = "AIX ";
2557 break;
2558 case PAR_AIXDATA:
2559 zFSName = "AIX ";
2560 break;
2561 case PAR_BOOTMANAGER:
2562 zFSName = "BOOTMNG";
2563 break;
2564 case PAR_WINDOWS95:
2565 zFSName = "WIN95 ";
2566 break;
2567 case PAR_WINDOWS95LB:
2568 zFSName = "WIN95 ";
2569 break;
2570 case PAR_VFAT16BIG:
2571 zFSName = "VFAT ";
2572 break;
2573 case PAR_VFAT16EXT:
2574 zFSName = "VFAT ";
2575 break;
2576 case PAR_OPUS:
2577 zFSName = "OPUS ";
2578 break;
2579 case PAR_HID12SMALL:
2580 zFSName = "FAT-12*";
2581 break;
2582 case PAR_COMPAQDIAG:
2583 zFSName = "COMPAQ ";
2584 break;
2585 case PAR_HID16SMALL:
2586 zFSName = "FAT-16*";
2587 break;
2588 case PAR_HID16BIG:
2589 zFSName = "BIGDOS*";
2590 break;
2591 case PAR_HIDHPFS:
2592 zFSName = "HPFS* ";
2593 break;
2594 case PAR_WINDOWSSWP:
2595 zFSName = "WINSWAP";
2596 break;
2597 case PAR_NECDOS:
2598 zFSName = "NECDOS ";
2599 break;
2600 case PAR_THEOS:
2601 zFSName = "THEOS ";
2602 break;
2603 case PAR_VENIX:
2604 zFSName = "VENIX ";
2605 break;
2606 case PAR_RISCBOOT:
2607 zFSName = "RISC ";
2608 break;
2609 case PAR_SFS:
2610 zFSName = "SFS ";
2611 break;
2612 case PAR_ONTRACK:
2613 zFSName = "ONTRACK";
2614 break;
2615 case PAR_ONTRACKEXT:
2616 zFSName = "ONTRACK";
2617 break;
2618 case PAR_CPM:
2619 zFSName = "CP/M ";
2620 break;
2621 case PAR_UNIXSYSV:
2622 zFSName = "UNIX ";
2623 break;
2624 case PAR_NOVELL_64:
2625 zFSName = "NOVELL ";
2626 break;
2627 case PAR_NOVELL_65:
2628 zFSName = "NOVELL ";
2629 break;
2630 case PAR_NOVELL_67:
2631 zFSName = "NOVELL ";
2632 break;
2633 case PAR_NOVELL_68:
2634 zFSName = "NOVELL ";
2635 break;
2636 case PAR_NOVELL_69:
2637 zFSName = "NOVELL ";
2638 break;
2639 case PAR_PCIX:
2640 zFSName = "PCIX ";
2641 break;
2642 case PAR_MINIX:
2643 zFSName = "MINIX ";
2644 break;
2645 case PAR_LINUX:
2646 zFSName = "LINUX ";
2647 break;
2648 case PAR_LINUXSWAP:
2649 zFSName = "LNXSWP ";
2650 break;
2651 case PAR_LINUXFILE:
2652 zFSName = "LINUX ";
2653 break;
2654 case PAR_FREEBSD:
2655 zFSName = "FREEBSD";
2656 break;
2657 case PAR_BBT:
2658 zFSName = "BBT ";
2659 break;
2660
2661 default:
2662 zFSName = " ";
2663 break;
2664 }
2665 return zFSName;
2666}
2667
2668/*
2669 * AppendPartition:
2670 * this appends the given partition information to
2671 * the given partition list. To do this, a new
2672 * PARTITIONINFO structure is created and appended
2673 * in a list (managed thru the PARTITIONINFO.pNext
2674 * items).
2675 *
2676 * pppiThis must be a pointer to a pointer to a PARTITIONINFO.
2677 * With each call of this function, this pointer is advanced
2678 * to point to the newly created PARTITIONINFO, so before
2679 * calling this function for the first time,
2680 *
2681 * Based on code (C) Dmitry A. Steklenev.
2682 *
2683 *@@added V0.9.0 [umoeller]
2684 */
2685
2686APIRET AppendPartition(PARTITIONINFO **pppiFirst,
2687 PARTITIONINFO **pppiThis, // in/out: partition info; pointer will be advanced
2688 PUSHORT posCount, // in/out: partition count
2689 BYTE bDisk, // in: disk of partition
2690 const char *pszBootName, // in: boot partition name
2691 CHAR cLetter, // in/out: drive letter
2692 BYTE bFsType, // in: file system type
2693 BOOL fPrimary, // in: primary?
2694 BOOL fBootable,
2695 ULONG ulSectors) // in: no. of sectors
2696{
2697 APIRET arc = NO_ERROR;
2698 PPARTITIONINFO ppiNew = NEW(PARTITIONINFO);
2699 if (ppiNew)
2700 {
2701 ZERO(ppiNew);
2702
2703 // store data
2704 ppiNew->bDisk = bDisk;
2705 if ((fBootable) && (pszBootName) )
2706 {
2707 memcpy(ppiNew->szBootName, pszBootName, 8);
2708 ppiNew->szBootName[8] = 0;
2709 }
2710 else
2711 ppiNew->szBootName[0] = 0;
2712 ppiNew->cLetter = cLetter;
2713 ppiNew->bFSType = bFsType;
2714 strcpy(ppiNew->szFSType,
2715 doshType2FSName(bFsType));
2716 ppiNew->fPrimary = fPrimary;
2717 ppiNew->fBootable = fBootable;
2718 ppiNew->ulSize = ulSectors / 2048;
2719
2720 ppiNew->pNext = NULL;
2721
2722 (*posCount)++;
2723
2724 if (*pppiFirst == (PPARTITIONINFO)NULL)
2725 {
2726 // first call:
2727 *pppiFirst = ppiNew;
2728 *pppiThis = ppiNew;
2729 }
2730 else
2731 {
2732 // append to list
2733 (**pppiThis).pNext = ppiNew;
2734 *pppiThis = ppiNew;
2735 }
2736 }
2737 else
2738 arc = ERROR_NOT_ENOUGH_MEMORY;
2739
2740 return (arc);
2741}
2742
2743// Sector and Cylinder values are actually 6 bits and 10 bits:
2744//
2745// 1 1 1 1 1 1
2746// Ú5Â4Â3Â2Â1Â0Â9Â8Â7Â6Â5Â4Â3Â2Â1ÂÄ¿
2747// ³c c c c c c c c C c S s s s s s³
2748// ÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙ
2749//
2750// The high two bits of the second byte are used as the high bits
2751// of a 10-bit value. This allows for as many as 1024 cylinders
2752// and 64 sectors per cylinder.
2753
2754/*
2755 * GetCyl:
2756 * get cylinder number.
2757 *
2758 * Based on code (C) Dmitry A. Steklenev.
2759 *
2760 *@@added V0.9.0 [umoeller]
2761 */
2762
2763static USHORT GetCyl(USHORT rBeginSecCyl)
2764{
2765 return ( (rBeginSecCyl & 0x00C0) << 2)
2766 + ((rBeginSecCyl & 0xFF00) >> 8);
2767}
2768
2769/*
2770 * GetSec:
2771 * get sector number.
2772 *
2773 * Based on code (C) Dmitry A. Steklenev.
2774 *
2775 *@@added V0.9.0 [umoeller]
2776 */
2777
2778static USHORT GetSec(USHORT rBeginSecCyl)
2779{
2780 return rBeginSecCyl & 0x003F;
2781}
2782
2783/*
2784 *@@ doshGetBootManager:
2785 * this goes thru the master boot records on all
2786 * disks to find the boot manager partition.
2787 *
2788 * Returns:
2789 *
2790 * -- NO_ERROR: boot manager found; in that case,
2791 * information about the boot manager
2792 * is written into *pusDisk, *pusPart,
2793 * *BmInfo. Any of these pointers can
2794 * be NULL if you're not interested.
2795 *
2796 * -- ERROR_NOT_SUPPORTED (50): boot manager not installed.
2797 *
2798 * Based on code (C) Dmitry A. Steklenev.
2799 *
2800 *@@added V0.9.0 [umoeller]
2801 */
2802
2803APIRET doshGetBootManager(USHORT *pusDisk, // out: if != NULL, boot manager disk (1, 2, ...)
2804 USHORT *pusPart, // out: if != NULL, index of bmgr primary partition (0-3)
2805 PAR_INFO *pBmInfo) // out: if != NULL, boot manager partition info
2806{
2807 APIRET arc = NO_ERROR;
2808 USHORT count = doshQueryDiskCount(); // Physical disk number
2809 MBR_INFO MBoot; // Master Boot
2810 USHORT usDisk;
2811
2812 if (count > 8) // Not above 8 disks
2813 count = 8;
2814
2815 for (usDisk = 1; usDisk <= count; usDisk++)
2816 {
2817 USHORT usPrim = 0;
2818
2819 // for each disk, read the MBR, which has the
2820 // primary partitions
2821 if ((arc = doshReadSector(usDisk,
2822 &MBoot,
2823 0, // head
2824 0, // cylinder
2825 1))) // sector
2826 return (arc);
2827
2828 // scan primary partitions for whether
2829 // BootManager partition exists
2830 for (usPrim = 0; usPrim < 4; usPrim++)
2831 {
2832 if (MBoot.sPrtnInfo[usPrim].bFileSysCode == 0x0A)
2833 {
2834 // this is boot manager:
2835 if (pBmInfo)
2836 *pBmInfo = MBoot.sPrtnInfo[usPrim];
2837 if (pusPart)
2838 *pusPart = usPrim;
2839 if (pusDisk)
2840 *pusDisk = usDisk;
2841 // stop scanning
2842 return (NO_ERROR);
2843 }
2844 }
2845 }
2846
2847 return (ERROR_NOT_SUPPORTED);
2848}
2849
2850/*
2851 * GetPrimaryPartitions:
2852 * this returns the primary partitions.
2853 *
2854 * This gets called from doshGetPartitionsList.
2855 *
2856 * Returns:
2857 *
2858 * -- ERROR_INVALID_PARAMETER: BMInfo is NULL.
2859 *
2860 * Based on code (C) Dmitry A. Steklenev.
2861 *
2862 *@@added V0.9.0 [umoeller]
2863 */
2864
2865APIRET GetPrimaryPartitions(PARTITIONINFO **pppiFirst,
2866 PARTITIONINFO **pppiThis,
2867 PUSHORT posCount, // in/out: partition count
2868 PCHAR pcLetter, // in/out: drive letter counter
2869 UINT BmDisk, // in: physical disk (1, 2, 3, ...) of boot manager or null
2870 PAR_INFO* pBmInfo, // in: info returned by doshGetBootManager or NULL
2871 UINT iDisk) // in: system's physical disk count
2872{
2873 APIRET arc = NO_ERROR;
2874
2875 if (!pBmInfo)
2876 arc = ERROR_INVALID_PARAMETER;
2877 else
2878 {
2879 SYS_INFO MName[32]; // Name Space from Boot Manager
2880 memset(&MName, 0, sizeof(MName));
2881
2882 // read boot manager name table;
2883 // this is in the boot manager primary partition
2884 // at sector offset 3 (?!?)
2885 if (!(arc = doshReadSector(BmDisk,
2886 &MName,
2887 // head, cylinder, sector of bmgr primary partition:
2888 pBmInfo->bBeginHead,
2889 GetCyl(pBmInfo->rBeginSecCyl),
2890 GetSec(pBmInfo->rBeginSecCyl) + 3)))
2891 {
2892 // got bmgr name table:
2893 MBR_INFO MBoot; // Master Boot
2894 USHORT i;
2895
2896 // read master boot record of this disk
2897 if (!(arc = doshReadSector(iDisk,
2898 &MBoot,
2899 0, // head
2900 0, // cylinder
2901 1))) // sector
2902 {
2903 for (i = 0;
2904 i < 4; // there can be only four primary partitions
2905 i++)
2906 {
2907 // skip unused partition, BootManager or Extended partition
2908 if ( (MBoot.sPrtnInfo[i].bFileSysCode) // skip unused
2909 && (MBoot.sPrtnInfo[i].bFileSysCode != PAR_BOOTMANAGER) // skip boot manager
2910 && (MBoot.sPrtnInfo[i].bFileSysCode != PAR_EXTENDED) // skip extended
2911 )
2912 {
2913 BOOL fBootable = ( (pBmInfo)
2914 && (MName[(iDisk-1) * 4 + i].bootable & 0x01)
2915 );
2916 // store this partition
2917 if ((arc = AppendPartition(pppiFirst,
2918 pppiThis,
2919 posCount,
2920 iDisk,
2921 (fBootable)
2922 ? (char*)&MName[(iDisk - 1) * 4 + i].name
2923 : "",
2924 *pcLetter,
2925 MBoot.sPrtnInfo[i].bFileSysCode,
2926 TRUE, // primary
2927 fBootable,
2928 MBoot.sPrtnInfo[i].lTotalSects)))
2929 return (arc);
2930 }
2931 }
2932 }
2933 }
2934 }
2935
2936 return (arc);
2937}
2938
2939/*
2940 * GetLogicalDrives:
2941 * this returns info for the logical drives
2942 * in the extended partition. This gets called
2943 * from GetExtendedPartition.
2944 *
2945 * This gets called from GetExtendedPartition.
2946 *
2947 * Based on code (C) Dmitry A. Steklenev.
2948 *
2949 *@@added V0.9.0 [umoeller]
2950 */
2951
2952APIRET GetLogicalDrives(PARTITIONINFO **pppiFirst,
2953 PARTITIONINFO **pppiThis,
2954 PUSHORT posCount,
2955 PCHAR pcLetter,
2956 PAR_INFO* PrInfo, // in: MBR entry of extended partition
2957 UINT PrDisk,
2958 PAR_INFO* BmInfo)
2959{
2960 APIRET arc = NO_ERROR;
2961 EXT_INFO MBoot; // Master Boot
2962 USHORT i;
2963
2964 if ((arc = doshReadSector(PrDisk,
2965 &MBoot,
2966 PrInfo->bBeginHead,
2967 GetCyl(PrInfo->rBeginSecCyl),
2968 GetSec(PrInfo->rBeginSecCyl))))
2969 return (arc);
2970
2971 for (i = 0; i < 4; i++)
2972 {
2973 // skip unused partition or BootManager partition
2974 if ( (MBoot.sPrtnInfo[i].bFileSysCode)
2975 && (MBoot.sPrtnInfo[i].bFileSysCode != PAR_BOOTMANAGER)
2976 )
2977 {
2978 BOOL fBootable = FALSE;
2979 BOOL fAssignLetter = FALSE;
2980
2981 // special work around extended partition
2982 if (MBoot.sPrtnInfo[i].bFileSysCode == PAR_EXTENDED)
2983 {
2984 if ((arc = GetLogicalDrives(pppiFirst,
2985 pppiThis,
2986 posCount,
2987 pcLetter,
2988 &MBoot.sPrtnInfo[i],
2989 PrDisk,
2990 BmInfo)))
2991 return (arc);
2992
2993 continue;
2994 }
2995
2996 // raise driver letter if OS/2 would recognize this drive
2997 if ( (MBoot.sPrtnInfo[i].bFileSysCode < PAR_PCIX)
2998 )
2999 fAssignLetter = TRUE;
3000
3001 if (fAssignLetter)
3002 (*pcLetter)++;
3003
3004 fBootable = ( (BmInfo)
3005 && ((MBoot.sBmNames[i].bootable & 0x01) != 0)
3006 );
3007
3008 if ((arc = AppendPartition(pppiFirst,
3009 pppiThis,
3010 posCount,
3011 PrDisk,
3012 (fBootable)
3013 ? (char*)&MBoot.sBmNames[i].name
3014 : "",
3015 (fAssignLetter)
3016 ? *pcLetter
3017 : ' ',
3018 MBoot.sPrtnInfo[i].bFileSysCode,
3019 FALSE, // primary
3020 fBootable, // bootable
3021 MBoot.sPrtnInfo[i].lTotalSects)))
3022 return (arc);
3023 }
3024 }
3025
3026 return (NO_ERROR);
3027}
3028
3029/*
3030 * GetExtendedPartition:
3031 * this finds the extended partition on the given
3032 * drive and calls GetLogicalDrives in turn.
3033 *
3034 * This gets called from doshGetPartitionsList.
3035 *
3036 * Based on code (C) Dmitry A. Steklenev.
3037 *
3038 *@@added V0.9.0 [umoeller]
3039 */
3040
3041APIRET GetExtendedPartition(PARTITIONINFO **pppiFirst,
3042 PARTITIONINFO **pppiThis,
3043 PUSHORT posCount,
3044 PCHAR pcLetter,
3045 PAR_INFO* BmInfo,
3046 UINT iDisk) // in: disk to query
3047{
3048 APIRET arc = NO_ERROR;
3049 MBR_INFO MBoot; // Master Boot
3050 USHORT i;
3051
3052 if ((arc = doshReadSector(iDisk, &MBoot, 0, 0, 1)))
3053 return (arc);
3054
3055 // go thru MBR entries to find extended partition
3056 for (i = 0;
3057 i < 4;
3058 i++)
3059 {
3060 if (MBoot.sPrtnInfo[i].bFileSysCode == PAR_EXTENDED)
3061 {
3062 if ((arc = GetLogicalDrives(pppiFirst,
3063 pppiThis,
3064 posCount,
3065 pcLetter,
3066 &MBoot.sPrtnInfo[i],
3067 iDisk,
3068 BmInfo)))
3069 return (arc);
3070 }
3071 }
3072
3073 return (NO_ERROR);
3074}
3075
3076/*
3077 *@@ CleanPartitionInfos:
3078 *
3079 *@@added V0.9.9 (2001-04-07) [umoeller]
3080 */
3081
3082VOID CleanPartitionInfos(PPARTITIONINFO ppiThis)
3083{
3084 while (ppiThis)
3085 {
3086 PPARTITIONINFO ppiNext = ppiThis->pNext;
3087 free(ppiThis);
3088 ppiThis = ppiNext;
3089 }
3090}
3091
3092/*
3093 *@@ doshGetPartitionsList:
3094 * this returns lots of information about the
3095 * partitions on all physical disks, which is
3096 * read directly from the MBRs and partition
3097 * tables.
3098 *
3099 * If NO_ERROR is returned by this function,
3100 * *ppPartitionInfo points to a linked list of
3101 * PARTITIONINFO structures, which has
3102 * *pusPartitionCount items.
3103 *
3104 * In that case, use doshFreePartitionsList to
3105 * free the resources allocated by this function.
3106 *
3107 * What this function returns depends on whether
3108 * LVM is installed.
3109 *
3110 * -- If LVM.DLL is found on the LIBPATH, this opens
3111 * the LVM engine and returns the info from the
3112 * LVM engine in the PARTITIONINFO structures.
3113 * The partitions are then sorted by disk in
3114 * ascending order.
3115 *
3116 * -- Otherwise, we parse the partition tables
3117 * manually. The linked list then starts out with
3118 * all the primary partitions, followed by the
3119 * logical drives in the extended partitions.
3120 * This function attempts to guess the correct drive
3121 * letters and stores these with the PARTITIONINFO
3122 * items, but there's no guarantee that this is
3123 * correct. We correctly ignore Linux partitions here
3124 * and give all primary partitions the C: letter, but
3125 * I have no idea what happens with NTFS partitions,
3126 * since I have none.
3127 *
3128 * If an error != NO_ERROR is returned, *pusContext
3129 * will be set to one of the following:
3130 *
3131 * -- 1: boot manager not found
3132 *
3133 * -- 2: primary partitions error
3134 *
3135 * -- 3: secondary partitions error
3136 *
3137 * -- 0: something else.
3138 *
3139 * Based on code (C) Dmitry A. Steklenev.
3140 *
3141 *@@added V0.9.0 [umoeller]
3142 *@@changed V0.9.9 (2001-04-07) [umoeller]: added transparent LVM support; changed prototype
3143 *@@changed V0.9.9 (2001-04-07) [umoeller]: fixed memory leaks on errors
3144 */
3145
3146APIRET doshGetPartitionsList(PPARTITIONSLIST *ppList,
3147 PUSHORT pusContext) // out: error context
3148{
3149 APIRET arc = NO_ERROR;
3150
3151 PLVMINFO pLVMInfo = NULL;
3152
3153 PARTITIONINFO *pPartitionInfos = NULL, // linked list of all partitions
3154 *ppiTemp = NULL;
3155 USHORT cPartitions = 0; // bootable partition count
3156
3157 if (!ppList)
3158 return (ERROR_INVALID_PARAMETER);
3159
3160 if (!(arc = doshQueryLVMInfo(&pLVMInfo)))
3161 {
3162 // LVM installed:
3163 arc = doshReadLVMPartitions(pLVMInfo, // in: LVM info
3164 &pPartitionInfos, // out: partitions array
3165 &cPartitions); // out: partitions count
3166 // copied to output below
3167
3168 if (arc)
3169 {
3170 // error: start over
3171 doshFreeLVMInfo(pLVMInfo);
3172 CleanPartitionInfos(pPartitionInfos);
3173 pPartitionInfos = NULL;
3174 cPartitions = 0;
3175 }
3176 }
3177
3178 if (arc)
3179 {
3180 // LVM not installed, or failed:
3181 // parse partitions manually
3182 PAR_INFO BmInfo; // BootManager partition
3183 USHORT usBmDisk; // BootManager disk
3184 USHORT cDisks = doshQueryDiskCount(); // physical disks count
3185 USHORT i;
3186
3187 CHAR cLetter = 'C'; // first drive letter
3188
3189 // start over
3190 arc = NO_ERROR;
3191
3192 if (cDisks > 8) // Not above 8 disks
3193 cDisks = 8;
3194
3195 // get boot manager disk and info
3196 if ((arc = doshGetBootManager(&usBmDisk,
3197 NULL,
3198 &BmInfo)) != NO_ERROR)
3199 {
3200 *pusContext = 1;
3201 }
3202 else
3203 {
3204 // on each disk, read primary partitions
3205 for (i = 1; i <= cDisks; i++)
3206 {
3207 if ((arc = GetPrimaryPartitions(&pPartitionInfos,
3208 &ppiTemp,
3209 &cPartitions,
3210 &cLetter,
3211 usBmDisk,
3212 usBmDisk ? &BmInfo : 0,
3213 i)))
3214 {
3215 *pusContext = 2;
3216 }
3217 }
3218
3219 if (!arc && usBmDisk)
3220 {
3221 // boot manager found:
3222 // on each disk, read extended partition
3223 // with logical drives
3224 for (i = 1; i <= cDisks; i++)
3225 {
3226 if ((arc = GetExtendedPartition(&pPartitionInfos,
3227 &ppiTemp,
3228 &cPartitions,
3229 &cLetter,
3230 &BmInfo,
3231 i)))
3232 {
3233 *pusContext = 3;
3234 }
3235 }
3236 }
3237 } // end else if ((arc = doshGetBootManager(&usBmDisk,
3238 } // end else if (!doshQueryLVMInfo(&pLVMInfo))
3239
3240 if (!arc)
3241 {
3242 // no error so far:
3243 *pusContext = 0;
3244
3245 *ppList = NEW(PARTITIONSLIST);
3246 if (!(*ppList))
3247 arc = ERROR_NOT_ENOUGH_MEMORY;
3248 else
3249 {
3250 ZERO(*ppList);
3251
3252 (*ppList)->pPartitionInfo = pPartitionInfos;
3253 (*ppList)->cPartitions = cPartitions;
3254
3255 _Pmpf((__FUNCTION__ ": returning %d partitions", cPartitions));
3256 }
3257 }
3258
3259 if (arc)
3260 CleanPartitionInfos(pPartitionInfos);
3261
3262 _Pmpf((__FUNCTION__ ": exiting, arc = %d", arc));
3263
3264 return (arc);
3265}
3266
3267/*
3268 *@@ doshFreePartitionsList:
3269 * this frees the resources allocated by
3270 * doshGetPartitionsList.
3271 *
3272 *@@added V0.9.0 [umoeller]
3273 */
3274
3275APIRET doshFreePartitionsList(PPARTITIONSLIST ppList)
3276{
3277 if (!ppList)
3278 return (ERROR_INVALID_PARAMETER);
3279 else
3280 {
3281 CleanPartitionInfos(ppList->pPartitionInfo);
3282 doshFreeLVMInfo(ppList->pLVMInfo);
3283 free(ppList);
3284 }
3285
3286 return (NO_ERROR);
3287}
3288
3289/********************************************************************
3290 *
3291 * LVM declarations
3292 *
3293 ********************************************************************/
3294
3295/*
3296 *@@category: Helpers\Control program helpers\Partitions info\Quick LVM Interface
3297 * functions for transparently interfacing LVM.DLL.
3298 */
3299
3300typedef unsigned char BOOLEAN;
3301typedef unsigned short int CARDINAL16;
3302typedef unsigned long CARDINAL32;
3303typedef unsigned int CARDINAL;
3304typedef unsigned long DoubleWord;
3305
3306#ifdef ADDRESS
3307#undef ADDRESS
3308#endif
3309
3310typedef void* ADDRESS;
3311
3312#pragma pack(1)
3313
3314#define DISK_NAME_SIZE 20
3315#define FILESYSTEM_NAME_SIZE 20
3316#define PARTITION_NAME_SIZE 20
3317#define VOLUME_NAME_SIZE 20
3318
3319/*
3320 *@@ Drive_Control_Record:
3321 * invariant for a disk drive.
3322 *
3323 *@@added V0.9.9 (2001-04-07) [umoeller]
3324 */
3325
3326typedef struct _Drive_Control_Record
3327{
3328 CARDINAL32 Drive_Number; // OS/2 Drive Number for this drive.
3329 CARDINAL32 Drive_Size; // The total number of sectors on the drive.
3330 DoubleWord Drive_Serial_Number; // The serial number assigned to this drive. For info. purposes only.
3331 ADDRESS Drive_Handle; // Handle used for operations on the disk that this record corresponds to.
3332 CARDINAL32 Cylinder_Count; // The number of cylinders on the drive.
3333 CARDINAL32 Heads_Per_Cylinder; // The number of heads per cylinder for this drive.
3334 CARDINAL32 Sectors_Per_Track; // The number of sectors per track for this drive.
3335 BOOLEAN Drive_Is_PRM; // Set to TRUE if this drive is a PRM.
3336 BYTE Reserved[3]; // Alignment.
3337} Drive_Control_Record;
3338
3339/*
3340 *@@ Drive_Control_Array:
3341 * returned by the Get_Drive_Control_Data function
3342 *
3343 *@@added V0.9.9 (2001-04-07) [umoeller]
3344 */
3345
3346typedef struct _Drive_Control_Array
3347{
3348 Drive_Control_Record * Drive_Control_Data; // An array of drive control records.
3349 CARDINAL32 Count; // The number of entries in the array of drive control records.
3350} Drive_Control_Array;
3351
3352/*
3353 *@@ Drive_Information_Record:
3354 * defines the information that can be changed for a specific disk drive.
3355 *
3356 *@@added V0.9.9 (2001-04-07) [umoeller]
3357 */
3358
3359typedef struct _Drive_Information_Record
3360{
3361 CARDINAL32 Total_Available_Sectors; // The number of sectors on the disk which are not currently assigned to a partition.
3362 CARDINAL32 Largest_Free_Block_Of_Sectors; // The number of sectors in the largest contiguous block of available sectors.
3363 BOOLEAN Corrupt_Partition_Table; // If TRUE, then the partitioning information found on the drive is incorrect!
3364 BOOLEAN Unusable; // If TRUE, the drive's MBR is not accessible and the drive can not be partitioned.
3365 BOOLEAN IO_Error; // If TRUE, then the last I/O operation on this drive failed!
3366 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).
3367 char Drive_Name[DISK_NAME_SIZE]; // User assigned name for this disk drive.
3368} Drive_Information_Record;
3369
3370/*
3371 *@@ Partition_Information_Record:
3372 *
3373 *@@added V0.9.9 (2001-04-07) [umoeller]
3374 */
3375
3376typedef struct _Partition_Information_Record
3377{
3378 ADDRESS Partition_Handle;
3379 // The handle used to perform operations on this partition.
3380 ADDRESS Volume_Handle;
3381 // If this partition is part of a volume, this will be the handle of
3382 // the volume. If this partition is NOT part of a volume, then this
3383 // handle will be 0.
3384 ADDRESS Drive_Handle;
3385 // The handle for the drive this partition resides on.
3386 DoubleWord Partition_Serial_Number;
3387 // The serial number assigned to this partition.
3388 CARDINAL32 Partition_Start;
3389 // The LBA of the first sector of the partition.
3390 CARDINAL32 True_Partition_Size;
3391 // The total number of sectors comprising the partition.
3392 CARDINAL32 Usable_Partition_Size;
3393 // The size of the partition as reported to the IFSM. This is the
3394 // size of the partition less any LVM overhead.
3395 CARDINAL32 Boot_Limit;
3396 // The maximum number of sectors from this block of free space that
3397 // can be used to create a bootable partition if you allocate from the
3398 // beginning of the block of free space.
3399 BOOLEAN Spanned_Volume;
3400 // TRUE if this partition is part of a multi-partition volume.
3401 BOOLEAN Primary_Partition;
3402 // True or False. Any non-zero value here indicates that this partition
3403 // is a primary partition. Zero here indicates that this partition is
3404 // a "logical drive" - i.e. it resides inside of an extended partition.
3405 BYTE Active_Flag;
3406 // 80 = Partition is marked as being active.
3407 // 0 = Partition is not active.
3408 BYTE OS_Flag;
3409 // This field is from the partition table. It is known as the OS flag,
3410 // the Partition Type Field, Filesystem Type, and various other names.
3411 // Values of interest
3412 // If this field is: (values are in hex)
3413 // 07 = The partition is a compatibility partition formatted for use
3414 // with an installable filesystem, such as HPFS or JFS.
3415 // 00 = Unformatted partition
3416 // 01 = FAT12 filesystem is in use on this partition.
3417 // 04 = FAT16 filesystem is in use on this partition.
3418 // 0A = OS/2 Boot Manager Partition
3419 // 35 = LVM partition
3420 // 84 = OS/2 FAT16 partition which has been relabeled by Boot Manager to "Hide" it.
3421 BYTE Partition_Type;
3422 // 0 = Free Space
3423 // 1 = LVM Partition (Part of an LVM Volume.)
3424 // 2 = Compatibility Partition
3425 // All other values are reserved for future use.
3426 BYTE Partition_Status;
3427 // 0 = Free Space
3428 // 1 = In Use - i.e. already assigned to a volume.
3429 // 2 = Available - i.e. not currently assigned to a volume.
3430 BOOLEAN On_Boot_Manager_Menu;
3431 // Set to TRUE if this partition is not part of a Volume yet is on the
3432 // Boot Manager Menu.
3433 BYTE Reserved;
3434 // Alignment.
3435 char Volume_Drive_Letter;
3436 // The drive letter assigned to the volume that this partition is a part of.
3437 char Drive_Name[DISK_NAME_SIZE];
3438 // User assigned name for this disk drive.
3439 char File_System_Name[FILESYSTEM_NAME_SIZE];
3440 // The name of the filesystem in use on this partition, if it is known.
3441 char Partition_Name[PARTITION_NAME_SIZE];
3442 // The user assigned name for this partition.
3443 char Volume_Name[VOLUME_NAME_SIZE];
3444 // If this partition is part of a volume, then this will be the
3445 // name of the volume that this partition is a part of. If this
3446 // record represents free space, then the Volume_Name will be
3447 // "FREE SPACE xx", where xx is a unique numeric ID generated by
3448 // LVM.DLL. Otherwise it will be an empty string.
3449} Partition_Information_Record;
3450
3451// The following defines are for use with the Partition_Type field in the
3452// Partition_Information_Record.
3453#define FREE_SPACE_PARTITION 0
3454#define LVM_PARTITION 1
3455#define COMPATIBILITY_PARTITION 2
3456
3457// The following defines are for use with the Partition_Status field in the
3458// Partition_Information_Record.
3459#define PARTITION_IS_IN_USE 1
3460#define PARTITION_IS_AVAILABLE 2
3461#define PARTITION_IS_FREE_SPACE 0
3462
3463/*
3464 *@@ Partition_Information_Array:
3465 * returned by various functions in the LVM Engine.
3466 *
3467 *@@added V0.9.9 (2001-04-07) [umoeller]
3468 */
3469
3470typedef struct _Partition_Information_Array
3471{
3472 Partition_Information_Record * Partition_Array; // An array of Partition_Information_Records.
3473 CARDINAL32 Count; // The number of entries in the Partition_Array.
3474} Partition_Information_Array;
3475
3476/*
3477 *@@ Volume_Information_Record:
3478 * variable information for a volume.
3479 *
3480 *@@added V0.9.9 (2001-04-07) [umoeller]
3481 */
3482
3483typedef struct _Volume_Information_Record
3484{
3485 CARDINAL32 Volume_Size;
3486 // The number of sectors comprising the volume.
3487 CARDINAL32 Partition_Count;
3488 // The number of partitions which comprise this volume.
3489 CARDINAL32 Drive_Letter_Conflict;
3490 // 0 indicates that the drive letter preference for this volume is unique.
3491 // 1 indicates that the drive letter preference for this volume
3492 // is not unique, but this volume got its preferred drive letter anyway.
3493 // 2 indicates that the drive letter preference for this volume
3494 // is not unique, and this volume did NOT get its preferred drive letter.
3495 // 4 indicates that this volume is currently "hidden" - i.e. it has
3496 // no drive letter preference at the current time.
3497 BOOLEAN Compatibility_Volume;
3498 // TRUE if this is for a compatibility volume, FALSE otherwise.
3499 BOOLEAN Bootable;
3500 // Set to TRUE if this volume appears on the Boot Manager menu, or if it is
3501 // a compatibility volume and its corresponding partition is the first active
3502 // primary partition on the first drive.
3503 char Drive_Letter_Preference;
3504 // The drive letter that this volume desires to be.
3505 char Current_Drive_Letter;
3506 // The drive letter currently used to access this volume.
3507 // May be different than Drive_Letter_Preference if there was a conflict ( i.e. Drive_Letter_Preference
3508 // is already in use by another volume ).
3509 char Initial_Drive_Letter;
3510 // The drive letter assigned to this volume by the operating system
3511 // when LVM was started. This may be different from the
3512 // Drive_Letter_Preference if there were conflicts, and
3513 // may be different from the Current_Drive_Letter. This
3514 // will be 0x0 if the Volume did not exist when the LVM Engine
3515 // was opened (i.e. it was created during this LVM session).
3516 BOOLEAN New_Volume;
3517 // Set to FALSE if this volume existed before the LVM Engine was
3518 // opened. Set to TRUE if this volume was created after the LVM
3519 // Engine was opened.
3520 BYTE Status;
3521 // 0 = None.
3522 // 1 = Bootable
3523 // 2 = Startable
3524 // 3 = Installable.
3525 BYTE Reserved_1;
3526 char Volume_Name[VOLUME_NAME_SIZE];
3527 // The user assigned name for this volume.
3528 char File_System_Name[FILESYSTEM_NAME_SIZE];
3529 // The name of the filesystem in use on this partition, if it
3530 // is known.
3531} Volume_Information_Record;
3532
3533#pragma pack()
3534
3535/********************************************************************
3536 *
3537 * Quick LVM Interface API
3538 *
3539 ********************************************************************/
3540
3541/*
3542 *@@ LVMINFOPRIVATE:
3543 * private structure used by doshQueryLVMInfo.
3544 * This is what the LVMINFO pointer really
3545 * points to.
3546 *
3547 *@@added V0.9.9 (2001-04-07) [umoeller]
3548 */
3549
3550typedef struct _LVMINFOPRIVATE
3551{
3552 LVMINFO LVMInfo; // public structure (dosh.h)
3553
3554 // function pointers resolved from LVM.DLL
3555
3556 void (* _System Open_LVM_Engine)(BOOLEAN Ignore_CHS,
3557 CARDINAL32 *Error_Code);
3558
3559 void (* _System Free_Engine_Memory)(ADDRESS Object);
3560
3561 void (* _System Close_LVM_Engine)(void);
3562
3563 Drive_Control_Array (* _System
3564 Get_Drive_Control_Data)(CARDINAL32 *Error_Code);
3565
3566 Drive_Information_Record (* _System
3567 Get_Drive_Status)(ADDRESS Drive_Handle,
3568 CARDINAL32 *Error_Code);
3569
3570 Partition_Information_Array (* _System
3571 Get_Partitions)(ADDRESS Handle,
3572 CARDINAL32 *Error_Code);
3573
3574 Volume_Information_Record (*_System
3575 Get_Volume_Information)(ADDRESS Volume_Handle,
3576 CARDINAL32 *Error_Code);
3577
3578} LVMINFOPRIVATE, *PLVMINFOPRIVATE;
3579
3580#define LVM_ERROR_FIRST 20000
3581
3582/*
3583 *@@ doshQueryLVMInfo:
3584 * creates an LVMINFO structure if LVM is installed.
3585 * Returns that structure (which the caller must free
3586 * using doshFreeLVMInfo) or NULL if LVM.DLL was not
3587 * found along the LIBPATH.
3588 *
3589 *@@added V0.9.9 (2001-04-07) [umoeller]
3590 */
3591
3592APIRET doshQueryLVMInfo(PLVMINFO *ppLVMInfo)
3593{
3594 APIRET arc = NO_ERROR;
3595 CHAR szError[100];
3596 PLVMINFOPRIVATE pLVMInfo = NULL;
3597 HMODULE hmodLVM = NULLHANDLE;
3598
3599 if (!(arc = DosLoadModule(szError,
3600 sizeof(szError),
3601 "LVM",
3602 &hmodLVM)))
3603 {
3604 // got LVM.DLL:
3605 pLVMInfo = NEW(LVMINFOPRIVATE);
3606 if (!pLVMInfo)
3607 arc = ERROR_NOT_ENOUGH_MEMORY;
3608 else
3609 {
3610 // array of function pointers to be resolved from LVM.DLL
3611 RESOLVEFUNCTION aFunctions[] =
3612 {
3613 "Open_LVM_Engine", (PFN*)&pLVMInfo->Open_LVM_Engine,
3614 "Free_Engine_Memory", (PFN*)&pLVMInfo->Free_Engine_Memory,
3615 "Close_LVM_Engine", (PFN*)&pLVMInfo->Close_LVM_Engine,
3616 "Get_Drive_Control_Data", (PFN*)&pLVMInfo->Get_Drive_Control_Data,
3617 "Get_Drive_Status", (PFN*)&pLVMInfo->Get_Drive_Status,
3618 "Get_Partitions", (PFN*)&pLVMInfo->Get_Partitions,
3619 "Get_Volume_Information", (PFN*)&pLVMInfo->Get_Volume_Information
3620 };
3621 ULONG ul;
3622
3623 ZERO(pLVMInfo);
3624
3625 pLVMInfo->LVMInfo.hmodLVM = hmodLVM;
3626
3627 // now resolve function pointers
3628 for (ul = 0;
3629 ul < ARRAYITEMCOUNT(aFunctions);
3630 ul++)
3631 {
3632 PRESOLVEFUNCTION pFuncThis = &aFunctions[ul];
3633 arc = DosQueryProcAddr(hmodLVM,
3634 0, // ordinal, ignored
3635 (PSZ)pFuncThis->pcszFunctionName,
3636 pFuncThis->ppFuncAddress);
3637 if (!pFuncThis->ppFuncAddress)
3638 arc = ERROR_INVALID_NAME;
3639
3640 if (arc)
3641 break;
3642 }
3643 }
3644 }
3645
3646 if (arc)
3647 doshFreeLVMInfo((PLVMINFO)pLVMInfo);
3648 else
3649 *ppLVMInfo = (PLVMINFO)pLVMInfo;
3650
3651 return (arc);
3652}
3653
3654/*
3655 *@@ doshReadLVMPartitions:
3656 * using the LVMINFO parameter from doshQueryLVMInfo,
3657 * builds an array of PARTITIONINFO structures with
3658 * the data returned from LVM.DLL.
3659 *
3660 *@@added V0.9.9 (2001-04-07) [umoeller]
3661 */
3662
3663APIRET doshReadLVMPartitions(PLVMINFO pInfo, // in: LVM info
3664 PPARTITIONINFO *ppPartitionInfo, // out: partitions array
3665 PUSHORT pcPartitions) // out: partitions count
3666{
3667 APIRET arc = NO_ERROR;
3668 CARDINAL32 Error = 0;
3669
3670 PARTITIONINFO *pPartitionInfos = NULL, // linked list of all partitions
3671 *ppiTemp = NULL;
3672 USHORT cPartitions = 0; // bootable partition count
3673 PLVMINFOPRIVATE pLVMInfo = (PLVMINFOPRIVATE)pInfo;
3674
3675 _Pmpf((__FUNCTION__ ": entering"));
3676
3677 if (!pLVMInfo)
3678 return (ERROR_INVALID_PARAMETER);
3679
3680 // initialize LVM engine
3681 pLVMInfo->Open_LVM_Engine(TRUE,
3682 &Error);
3683
3684 _Pmpf((" Open_LVM_Engine Error: %d"));
3685
3686 if (!Error)
3687 {
3688 Drive_Control_Array DCA = pLVMInfo->Get_Drive_Control_Data(&Error);
3689 // member records to be freed
3690
3691 _Pmpf((" Get_Drive_Control_Data Error: %d, drive count: %d", Error, DCA.Count));
3692
3693 if ( (!Error)
3694 && (DCA.Count)
3695 )
3696 {
3697 // DCA.Drive_Control_Data now contains drive information records;
3698 // this must be freed
3699 ULONG ulDisk;
3700
3701 for (ulDisk = 0;
3702 ulDisk < DCA.Count;
3703 ulDisk++)
3704 {
3705 Drive_Control_Record *pDriveControlRecord
3706 = &DCA.Drive_Control_Data[ulDisk];
3707 ADDRESS hDrive = pDriveControlRecord->Drive_Handle;
3708
3709 /* Drive_Information_Record pDriveInfoRecord
3710 = pLVMInfo->Get_Drive_Status(hDrive,
3711 &Error);
3712
3713 _Pmpf((" drive %d Get_Drive_Status Error: %d", ulDisk, Error));
3714
3715 if (!Error) */
3716 {
3717 Partition_Information_Array PIA
3718 = pLVMInfo->Get_Partitions(hDrive,
3719 &Error);
3720
3721 _Pmpf((" Get_Partitions Error: %d", Error));
3722
3723 if (!Error)
3724 {
3725 // PIA.Partition_Array now contains
3726 // Partition_Information_Record; must be freed
3727
3728 // now go thru partitions of this drive
3729 ULONG ulPart;
3730 for (ulPart = 0;
3731 ulPart < PIA.Count;
3732 ulPart++)
3733 {
3734 Partition_Information_Record *pPartition
3735 = &PIA.Partition_Array[ulPart];
3736 Volume_Information_Record VolumeInfo;
3737
3738 const char *pcszBootName = NULL; // for now
3739 BOOL fBootable = FALSE;
3740
3741 if (pPartition->Volume_Handle)
3742 {
3743 // this partition is part of a volume:
3744 // only then can it be bootable...
3745 // get the volume info
3746 VolumeInfo
3747 = pLVMInfo->Get_Volume_Information(pPartition->Volume_Handle,
3748 &Error);
3749 pcszBootName = VolumeInfo.Volume_Name;
3750
3751 fBootable = (VolumeInfo.Status == 1);
3752 }
3753
3754
3755 if (arc = AppendPartition(&pPartitionInfos,
3756 &ppiTemp,
3757 &cPartitions,
3758 ulDisk + 1,
3759 pcszBootName,
3760 pPartition->Volume_Drive_Letter,
3761 pPartition->OS_Flag, // FS type
3762 pPartition->Primary_Partition,
3763 fBootable,
3764 pPartition->True_Partition_Size))
3765 break;
3766 }
3767
3768 // clean up partitions
3769 pLVMInfo->Free_Engine_Memory(PIA.Partition_Array);
3770 }
3771 }
3772 /* else
3773 // error:
3774 break; */
3775 }
3776
3777 // clean up drive data
3778 pLVMInfo->Free_Engine_Memory(DCA.Drive_Control_Data);
3779 }
3780 }
3781
3782 // close LVM
3783 pLVMInfo->Close_LVM_Engine();
3784
3785 if (Error)
3786 {
3787 // if we got an error, return it with the
3788 // LVM error offset
3789 arc = LVM_ERROR_FIRST + Error;
3790
3791 CleanPartitionInfos(pPartitionInfos);
3792 }
3793
3794 if (!arc)
3795 {
3796 *ppPartitionInfo = pPartitionInfos;
3797 *pcPartitions = cPartitions;
3798 }
3799
3800 _Pmpf((__FUNCTION__ ": exiting, arg = %d", arc));
3801
3802 return (arc);
3803}
3804
3805/*
3806 *@@ doshFreeLVMInfo:
3807 *
3808 *@@added V0.9.9 (2001-04-07) [umoeller]
3809 */
3810
3811VOID doshFreeLVMInfo(PLVMINFO pInfo)
3812{
3813 if (pInfo)
3814 {
3815 if (pInfo->hmodLVM)
3816 DosFreeModule(pInfo->hmodLVM);
3817
3818 free(pInfo);
3819 }
3820}
Note: See TracBrowser for help on using the repository browser.