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

Last change on this file since 74 was 71, checked in by umoeller, 24 years ago

misc updates

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