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

Last change on this file since 47 was 46, checked in by umoeller, 24 years ago

Mistc. updates for WarpIN, new features.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 77.7 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\stringh.h"
67
68#pragma hdrstop
69
70/*
71 *@@category: Helpers\Control program helpers\Miscellaneous
72 */
73
74/* ******************************************************************
75 *
76 * Miscellaneous
77 *
78 ********************************************************************/
79
80/*
81 *@@ doshIsValidFileName:
82 * this returns NO_ERROR only if pszFile is a valid file name.
83 * This may include a full path.
84 *
85 * If a drive letter is specified, this checks for whether
86 * that drive is a FAT drive and adjust the checks accordingly,
87 * i.e. 8+3 syntax (per path component).
88 *
89 * If no drive letter is specified, this check is performed
90 * for the current drive.
91 *
92 * This also checks if pszFileNames contains characters which
93 * are invalid for the current drive.
94 *
95 * Note: this performs syntactic checks only. This does not
96 * check for whether the specified path components exist.
97 * However, it _is_ checked for whether the given drive
98 * exists.
99 *
100 * This func is especially useful to check filenames that
101 * have been entered by the user in a "Save as" dialog.
102 *
103 * If an error is found, the corresponding DOS error code
104 * is returned:
105 * -- ERROR_INVALID_DRIVE
106 * -- ERROR_FILENAME_EXCED_RANGE (on FAT: no 8+3 filename)
107 * -- ERROR_INVALID_NAME (invalid character)
108 * -- ERROR_CURRENT_DIRECTORY (if fFullyQualified: no full path specified)
109 *
110 *@@changed V0.9.2 (2000-03-11) [umoeller]: added fFullyQualified
111 */
112
113APIRET doshIsValidFileName(const char* pcszFile,
114 BOOL fFullyQualified) // in: if TRUE, pcszFile must be fully q'fied
115{
116 APIRET arc = NO_ERROR;
117 CHAR szPath[CCHMAXPATH+4] = " :";
118 CHAR szComponent[CCHMAXPATH];
119 PSZ p1, p2;
120 BOOL fIsFAT = FALSE;
121 PSZ pszInvalid;
122
123 if (fFullyQualified) // V0.9.2 (2000-03-11) [umoeller]
124 {
125 if ( (*(pcszFile + 1) != ':')
126 || (*(pcszFile + 2) != '\\')
127 )
128 arc = ERROR_CURRENT_DIRECTORY;
129 }
130
131 // check drive first
132 if (*(pcszFile + 1) == ':')
133 {
134 CHAR cDrive = toupper(*pcszFile);
135 double d;
136 // drive specified:
137 strcpy(szPath, pcszFile);
138 szPath[0] = toupper(*pcszFile);
139 arc = doshQueryDiskFree(cDrive - 'A' + 1, &d);
140 }
141 else
142 {
143 // no drive specified: take current
144 ULONG ulDriveNum = 0,
145 ulDriveMap = 0;
146 arc = DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
147 szPath[0] = ((UCHAR)ulDriveNum) + 'A' - 1;
148 szPath[1] = ':';
149 strcpy(&szPath[2], pcszFile);
150 }
151
152 if (arc == NO_ERROR)
153 {
154 fIsFAT = doshIsFileOnFAT(szPath);
155
156 pszInvalid = (fIsFAT)
157 ? "<>|+=:;,\"/[] " // invalid characters in FAT
158 : "<>|:\"/"; // invalid characters in IFS's
159
160 // now separate path components
161 p1 = &szPath[2]; // advance past ':'
162
163 do {
164
165 if (*p1 == '\\')
166 p1++;
167
168 p2 = strchr(p1, '\\');
169 if (p2 == NULL)
170 p2 = p1 + strlen(p1);
171
172 if (p1 != p2)
173 {
174 LONG lDotOfs = -1,
175 lAfterDot = -1;
176 ULONG cbFile,
177 ul;
178 PSZ pSource = szComponent;
179
180 strncpy(szComponent, p1, p2-p1);
181 szComponent[p2-p1] = 0;
182 cbFile = strlen(szComponent);
183
184 // now check each path component
185 for (ul = 0; ul < cbFile; ul++)
186 {
187 if (fIsFAT)
188 {
189 // on FAT: only 8 characters allowed before dot
190 if (*pSource == '.')
191 {
192 lDotOfs = ul;
193 lAfterDot = 0;
194 if (ul > 7)
195 return (ERROR_FILENAME_EXCED_RANGE);
196 }
197 }
198 // and check for invalid characters
199 if (strchr(pszInvalid, *pSource) != NULL)
200 return (ERROR_INVALID_NAME);
201
202 pSource++;
203
204 // on FAT, allow only three chars after dot
205 if (fIsFAT)
206 if (lAfterDot != -1)
207 {
208 lAfterDot++;
209 if (lAfterDot > 3)
210 return (ERROR_FILENAME_EXCED_RANGE);
211 }
212 }
213
214 // we are still missing the case of a FAT file
215 // name without extension; if so, check whether
216 // the file stem is <= 8 chars
217 if (fIsFAT)
218 if (lDotOfs == -1) // dot not found:
219 if (cbFile > 8)
220 return (ERROR_FILENAME_EXCED_RANGE);
221 }
222
223 // go for next component
224 p1 = p2+1;
225 } while (*p2);
226 }
227
228 return (arc);
229}
230
231/*
232 *@@ doshMakeRealName:
233 * this copies pszSource to pszTarget, replacing
234 * all characters which are not supported by file
235 * systems with cReplace.
236 * pszTarget must be at least the same size as pszSource.
237 * If (fIsFAT), the file name will be made FAT-compliant (8+3).
238 * Returns TRUE if characters were replaced.
239 *
240 *@@changed V0.9.0 (99-11-06) [umoeller]: now replacing "*" too
241 */
242
243BOOL doshMakeRealName(PSZ pszTarget, // out: new real name
244 PSZ pszSource, // in: filename to translate
245 CHAR cReplace, // in: replacement char for invalid
246 // characters (e.g. '!')
247 BOOL fIsFAT) // in: make-FAT-compatible flag
248{
249 ULONG ul,
250 cbSource = strlen(pszSource);
251 LONG lDotOfs = -1,
252 lAfterDot = -1;
253 BOOL brc = FALSE;
254 PSZ pSource = pszSource,
255 pTarget = pszTarget,
256 pszInvalid = (fIsFAT)
257 ? "*<>|+=:;,\"/\\[] " // invalid characters in FAT
258 : "*<>|:\"/\\"; // invalid characters in IFS's
259
260 for (ul = 0; ul < cbSource; ul++)
261 {
262 if (fIsFAT)
263 {
264 // on FAT: truncate filename if neccessary
265 if (*pSource == '.')
266 {
267 lDotOfs = ul;
268 lAfterDot = 0;
269 if (ul > 7) {
270 // only 8 characters allowed before dot,
271 // so set target ptr to dot pos
272 pTarget = pszTarget+8;
273 }
274 }
275 }
276 // and replace invalid characters
277 if (strchr(pszInvalid, *pSource) == NULL)
278 *pTarget = *pSource;
279 else
280 {
281 *pTarget = cReplace;
282 brc = TRUE;
283 }
284 pTarget++;
285 pSource++;
286
287 // on FAT, allow only three chars after dot
288 if (fIsFAT)
289 if (lAfterDot != -1)
290 {
291 lAfterDot++;
292 if (lAfterDot > 3)
293 break;
294 }
295 }
296 *pTarget = '\0';
297
298 if (fIsFAT)
299 {
300 // we are still missing the case of a FAT file
301 // name without extension; if so, check whether
302 // the file stem is <= 8 chars
303 if (lDotOfs == -1) // dot not found:
304 if (cbSource > 8)
305 *(pszTarget+8) = 0; // truncate
306
307 // convert to upper case
308 strupr(pszTarget);
309 }
310
311 return (brc);
312}
313
314/*
315 *@@ doshSetCurrentDir:
316 * sets the current working directory
317 * to the given path.
318 *
319 * As opposed to DosSetCurrentDir, this
320 * one will change the current drive
321 * also, if one is specified.
322 */
323
324APIRET doshSetCurrentDir(const char *pcszDir)
325{
326 if (pcszDir)
327 {
328 if (*pcszDir != 0)
329 if (*(pcszDir+1) == ':')
330 {
331 // drive given:
332 CHAR cDrive = toupper(*(pcszDir));
333 APIRET arc;
334 // change drive
335 arc = DosSetDefaultDisk( (ULONG)(cDrive - 'A' + 1) );
336 // 1 = A:, 2 = B:, ...
337 if (arc != NO_ERROR)
338 return (arc);
339 }
340
341 return (DosSetCurrentDir((PSZ)pcszDir));
342 }
343 return (ERROR_INVALID_PARAMETER);
344}
345
346/*
347 *@@category: Helpers\Control program helpers\Environment management
348 * helpers for managing those ugly environment string arrays
349 * that are used with DosStartSession and WinStartApp.
350 */
351
352/* ******************************************************************
353 *
354 * Environment helpers
355 *
356 ********************************************************************/
357
358/*
359 *@@ doshParseEnvironment:
360 * this takes one of those ugly environment strings
361 * as used by DosStartSession and WinStartApp (with
362 * lots of zero-terminated strings one after another
363 * and a duplicate zero byte as a terminator) as
364 * input and splits it into an array of separate
365 * strings in pEnv.
366 *
367 * The newly allocated strings are stored in in
368 * pEnv->papszVars. The array count is stored in
369 * pEnv->cVars.
370 *
371 * Each environment variable will be copied into
372 * one newly allocated string in the array. Use
373 * doshFreeEnvironment to free the memory allocated
374 * by this function.
375 *
376 * Use the following code to browse thru the array:
377 +
378 + DOSENVIRONMENT Env = {0};
379 + if (doshParseEnvironment(pszEnv,
380 + &Env)
381 + == NO_ERROR)
382 + {
383 + if (Env.papszVars)
384 + {
385 + PSZ *ppszThis = Env.papszVars;
386 + for (ul = 0;
387 + ul < Env.cVars;
388 + ul++)
389 + {
390 + PSZ pszThis = *ppszThis;
391 + // pszThis now has something like PATH=C:\TEMP
392 + // ...
393 + // next environment string
394 + ppszThis++;
395 + }
396 + }
397 + doshFreeEnvironment(&Env);
398 + }
399 *
400 *@@added V0.9.4 (2000-08-02) [umoeller]
401 */
402
403APIRET doshParseEnvironment(const char *pcszEnv,
404 PDOSENVIRONMENT pEnv)
405{
406 APIRET arc = NO_ERROR;
407 if (!pcszEnv)
408 arc = ERROR_INVALID_PARAMETER;
409 else
410 {
411 PSZ pszVarThis = (PSZ)pcszEnv;
412 ULONG cVars = 0;
413 // count strings
414 while (*pszVarThis)
415 {
416 cVars++;
417 pszVarThis += strlen(pszVarThis) + 1;
418 }
419
420 pEnv->cVars = cVars;
421 pEnv->papszVars = 0;
422
423 if (cVars)
424 {
425 PSZ *papsz = (PSZ*)malloc(sizeof(PSZ) * cVars);
426 if (!papsz)
427 arc = ERROR_NOT_ENOUGH_MEMORY;
428 else
429 {
430 PSZ *ppszTarget = papsz;
431 memset(papsz, 0, sizeof(PSZ) * cVars);
432 pszVarThis = (PSZ)pcszEnv;
433 while (*pszVarThis)
434 {
435 *ppszTarget = strdup(pszVarThis);
436 ppszTarget++;
437 pszVarThis += strlen(pszVarThis) + 1;
438 }
439
440 pEnv->papszVars = papsz;
441 }
442 }
443 }
444
445 return (arc);
446}
447
448/*
449 *@@ doshGetEnvironment:
450 * calls doshParseEnvironment for the current
451 * process environment, which is retrieved from
452 * the info blocks.
453 *
454 *@@added V0.9.4 (2000-07-19) [umoeller]
455 */
456
457APIRET doshGetEnvironment(PDOSENVIRONMENT pEnv)
458{
459 APIRET arc = NO_ERROR;
460 if (!pEnv)
461 arc = ERROR_INVALID_PARAMETER;
462 else
463 {
464 PTIB ptib = 0;
465 PPIB ppib = 0;
466 arc = DosGetInfoBlocks(&ptib, &ppib);
467 if (arc == NO_ERROR)
468 {
469 PSZ pszEnv = ppib->pib_pchenv;
470 if (pszEnv)
471 arc = doshParseEnvironment(pszEnv, pEnv);
472 else
473 arc = ERROR_BAD_ENVIRONMENT;
474 }
475 }
476
477 return (arc);
478}
479
480/*
481 *@@ doshFindEnvironmentVar:
482 * returns the PSZ* in the pEnv->papszVars array
483 * which specifies the environment variable in pszVarName.
484 *
485 * With pszVarName, you can either specify the variable
486 * name only ("VARNAME") or a full environment string
487 * ("VARNAME=BLAH"). In any case, only the variable name
488 * is compared.
489 *
490 * Returns NULL if no such variable name was found in
491 * the array.
492 *
493 *@@added V0.9.4 (2000-07-19) [umoeller]
494 */
495
496PSZ* doshFindEnvironmentVar(PDOSENVIRONMENT pEnv,
497 PSZ pszVarName)
498{
499 PSZ *ppszRet = 0;
500 if (pEnv)
501 {
502 if ((pEnv->papszVars) && (pszVarName))
503 {
504 PSZ *ppszThis = pEnv->papszVars;
505 PSZ pszThis;
506 ULONG ul = 0;
507 ULONG ulVarNameLen = 0;
508
509 PSZ pszSearch = NULL; // receives "VARNAME="
510 PSZ pFirstEqual = strchr(pszVarName, '=');
511 if (pFirstEqual)
512 pszSearch = strhSubstr(pszVarName, pFirstEqual + 1);
513 else
514 {
515 ulVarNameLen = strlen(pszVarName);
516 pszSearch = (PSZ)malloc(ulVarNameLen + 2);
517 memcpy(pszSearch, pszVarName, ulVarNameLen);
518 *(pszSearch + ulVarNameLen) = '=';
519 *(pszSearch + ulVarNameLen + 1) = 0;
520 }
521
522 ulVarNameLen = strlen(pszSearch);
523
524 for (ul = 0;
525 ul < pEnv->cVars;
526 ul++)
527 {
528 pszThis = *ppszThis;
529
530 if (strnicmp(*ppszThis, pszSearch, ulVarNameLen) == 0)
531 {
532 ppszRet = ppszThis;
533 break;
534 }
535
536 // next environment string
537 ppszThis++;
538 }
539 }
540 }
541
542 return (ppszRet);
543}
544
545/*
546 *@@ doshSetEnvironmentVar:
547 * sets an environment variable in the specified
548 * environment, which must have been initialized
549 * using doshGetEnvironment first.
550 *
551 * pszNewEnv must be a full environment string
552 * in the form "VARNAME=VALUE".
553 *
554 * If "VARNAME" has already been set to something
555 * in the string array in pEnv, that array item
556 * is replaced.
557 *
558 * OTOH, if "VARNAME" has not been set yet, a new
559 * item is added to the array, and pEnv->cVars is
560 * raised by one. In that case, fAddFirst determines
561 * whether the new array item is added to the front
562 * or the tail of the environment list.
563 *
564 *@@added V0.9.4 (2000-07-19) [umoeller]
565 *@@changed V0.9.7 (2000-12-17) [umoeller]: added fAddFirst
566 */
567
568APIRET doshSetEnvironmentVar(PDOSENVIRONMENT pEnv,
569 PSZ pszNewEnv,
570 BOOL fAddFirst)
571{
572 APIRET arc = NO_ERROR;
573 if (!pEnv)
574 arc = ERROR_INVALID_PARAMETER;
575 else
576 {
577 if ((!pEnv->papszVars) || (!pszNewEnv))
578 arc = ERROR_INVALID_PARAMETER;
579 else
580 {
581 PSZ *ppszEnvLine = doshFindEnvironmentVar(pEnv, pszNewEnv);
582 if (ppszEnvLine)
583 {
584 // was set already: replace
585 free(*ppszEnvLine);
586 *ppszEnvLine = strdup(pszNewEnv);
587 if (!(*ppszEnvLine))
588 arc = ERROR_NOT_ENOUGH_MEMORY;
589 }
590 else
591 {
592 PSZ *ppszNew = NULL;
593 PSZ *papszNew = NULL;
594 // not set already:
595 if (fAddFirst)
596 {
597 // add as first entry:
598 papszNew = (PSZ*)malloc(sizeof(PSZ) * (pEnv->cVars + 1));
599 // overwrite first entry
600 ppszNew = papszNew;
601 // copy old entries
602 memcpy(papszNew + 1, // second new entry
603 pEnv->papszVars, // first old entry
604 sizeof(PSZ) * pEnv->cVars);
605 }
606 else
607 {
608 // append at the tail:
609 // reallocate array and add new string
610 papszNew = (PSZ*)realloc(pEnv->papszVars,
611 sizeof(PSZ) * (pEnv->cVars + 1));
612 // overwrite last entry
613 ppszNew = papszNew + pEnv->cVars;
614 }
615
616 if (!papszNew)
617 arc = ERROR_NOT_ENOUGH_MEMORY;
618 else
619 {
620 pEnv->papszVars = papszNew;
621 pEnv->cVars++;
622 *ppszNew = strdup(pszNewEnv);
623 }
624 }
625 }
626 }
627
628 return (arc);
629}
630
631/*
632 *@@ doshConvertEnvironment:
633 * converts an environment initialized by doshGetEnvironment
634 * to the string format required by WinStartApp and DosExecPgm,
635 * that is, one memory block is allocated in *ppszEnv and all
636 * strings in pEnv->papszVars are copied to that block. Each
637 * string is terminated with a null character; the last string
638 * is terminated with two null characters.
639 *
640 * Use free() to free the memory block allocated by this
641 * function in *ppszEnv.
642 *
643 *@@added V0.9.4 (2000-07-19) [umoeller]
644 */
645
646APIRET doshConvertEnvironment(PDOSENVIRONMENT pEnv,
647 PSZ *ppszEnv, // out: environment string
648 PULONG pulSize) // out: size of block allocated in *ppszEnv; ptr can be NULL
649{
650 APIRET arc = NO_ERROR;
651 if (!pEnv)
652 arc = ERROR_INVALID_PARAMETER;
653 else
654 {
655 if (!pEnv->papszVars)
656 arc = ERROR_INVALID_PARAMETER;
657 else
658 {
659 // count memory needed for all strings
660 ULONG cbNeeded = 0,
661 ul = 0;
662 PSZ *ppszThis = pEnv->papszVars;
663
664 for (ul = 0;
665 ul < pEnv->cVars;
666 ul++)
667 {
668 cbNeeded += strlen(*ppszThis) + 1; // length of string plus null terminator
669
670 // next environment string
671 ppszThis++;
672 }
673
674 cbNeeded++; // for another null terminator
675
676 *ppszEnv = (PSZ)malloc(cbNeeded);
677 if (!(*ppszEnv))
678 arc = ERROR_NOT_ENOUGH_MEMORY;
679 else
680 {
681 PSZ pTarget = *ppszEnv;
682 if (pulSize)
683 *pulSize = cbNeeded;
684 ppszThis = pEnv->papszVars;
685
686 // now copy each string
687 for (ul = 0;
688 ul < pEnv->cVars;
689 ul++)
690 {
691 PSZ pSource = *ppszThis;
692
693 while ((*pTarget++ = *pSource++))
694 ;
695
696 // *pTarget++ = 0; // append null terminator per string
697
698 // next environment string
699 ppszThis++;
700 }
701
702 *pTarget++ = 0; // append second null terminator
703 }
704 }
705 }
706
707 return (arc);
708}
709
710/*
711 *@@ doshFreeEnvironment:
712 * frees memory allocated by doshGetEnvironment.
713 *
714 *@@added V0.9.4 (2000-07-19) [umoeller]
715 */
716
717APIRET doshFreeEnvironment(PDOSENVIRONMENT pEnv)
718{
719 APIRET arc = NO_ERROR;
720 if (!pEnv)
721 arc = ERROR_INVALID_PARAMETER;
722 else
723 {
724 if (!pEnv->papszVars)
725 arc = ERROR_INVALID_PARAMETER;
726 else
727 {
728 PSZ *ppszThis = pEnv->papszVars;
729 PSZ pszThis;
730 ULONG ul = 0;
731
732 for (ul = 0;
733 ul < pEnv->cVars;
734 ul++)
735 {
736 pszThis = *ppszThis;
737 free(pszThis);
738 // *ppszThis = NULL;
739 // next environment string
740 ppszThis++;
741 }
742
743 free(pEnv->papszVars);
744 pEnv->cVars = 0;
745 }
746 }
747
748 return (arc);
749}
750
751/*
752 *@@category: Helpers\Control program helpers\Executable info
753 * these functions can retrieve BLDLEVEL information from
754 * any executable module. See doshExecOpen.
755 */
756
757/********************************************************************
758 *
759 * Executable functions
760 *
761 ********************************************************************/
762
763/*
764 *@@ doshExecOpen:
765 * this opens the specified executable file
766 * (which can be an .EXE, .COM, .DLL, or
767 * driver file) for use with the other
768 * doshExec* functions.
769 *
770 * If no error occurs, NO_ERROR is returned
771 * and a pointer to a new EXECUTABLE structure
772 * is stored in *ppExec. Consider this pointer a
773 * handle and pass it to doshExecClose when the
774 * executable is no longer needed to free
775 * resources.
776 *
777 * If NO_ERROR is returned, all the fields through
778 * ulOS are set in EXECUTABLE. The psz* fields
779 * which follow afterwards require an additional
780 * call to doshExecQueryBldLevel.
781 *
782 * If errors occur, this function returns the
783 * following error codes:
784 * -- ERROR_NOT_ENOUGH_MEMORY: malloc() failed.
785 * -- ERROR_INVALID_EXE_SIGNATURE: specified file
786 * has no DOS EXE header.
787 * -- ERROR_INVALID_PARAMETER: ppExec is NULL.
788 *
789 * plus those of DosOpen, DosSetFilePtr, and
790 * DosRead.
791 *
792 *@@added V0.9.0 [umoeller]
793 *@@changed V0.9.1 (2000-02-13) [umoeller]: fixed 32-bits flag
794 *@@changed V0.9.7 (2000-12-20) [lafaix]: fixed ulNewHeaderOfs
795 */
796
797APIRET doshExecOpen(const char* pcszExecutable,
798 PEXECUTABLE* ppExec)
799{
800 ULONG ulAction = 0;
801 HFILE hFile;
802 APIRET arc = DosOpen((PSZ)pcszExecutable,
803 &hFile,
804 &ulAction, // out: action taken
805 0, // in: new file (ignored for read-mode)
806 0, // in: new file attribs (ignored)
807 // open-flags
808 OPEN_ACTION_FAIL_IF_NEW
809 | OPEN_ACTION_OPEN_IF_EXISTS,
810 // open-mode
811 OPEN_FLAGS_FAIL_ON_ERROR // report errors to caller
812 | OPEN_FLAGS_SEQUENTIAL
813 | OPEN_FLAGS_NOINHERIT
814 | OPEN_SHARE_DENYNONE
815 | OPEN_ACCESS_READONLY, // read-only mode
816 NULL); // no EAs
817
818 if (arc == NO_ERROR)
819 {
820 // file opened successfully:
821 // create EXECUTABLE structure
822
823 if (ppExec)
824 {
825 *ppExec = (PEXECUTABLE)malloc(sizeof(EXECUTABLE));
826 if (*ppExec)
827 {
828 ULONG ulLocal = 0;
829
830 memset((*ppExec), 0, sizeof(EXECUTABLE));
831
832 // read old DOS EXE header
833 (*ppExec)->pDosExeHeader = (PDOSEXEHEADER)malloc(sizeof(DOSEXEHEADER));
834 if ((*ppExec)->pDosExeHeader == NULL)
835 arc = ERROR_NOT_ENOUGH_MEMORY;
836 else
837 {
838 ULONG ulBytesRead = 0;
839 arc = DosSetFilePtr(hFile,
840 0L,
841 FILE_BEGIN,
842 &ulLocal); // out: new offset
843 arc = DosRead(hFile,
844 (*ppExec)->pDosExeHeader,
845 sizeof(DOSEXEHEADER),
846 &((*ppExec)->cbDosExeHeader));
847 // now check if we really have a DOS header
848 if ((*ppExec)->pDosExeHeader->usDosExeID != 0x5a4d)
849 arc = ERROR_INVALID_EXE_SIGNATURE;
850 else
851 {
852 // we have a DOS header:
853 if ((*ppExec)->pDosExeHeader->usRelocTableOfs < 0x40)
854 {
855 // not LX or PE or NE:
856 (*ppExec)->ulOS = EXEOS_DOS3;
857 (*ppExec)->ulExeFormat = EXEFORMAT_OLDDOS;
858 }
859 else
860 {
861 // either LX or PE or NE:
862 // read more bytes from position
863 // specified in header
864 arc = DosSetFilePtr(hFile,
865 (*ppExec)->pDosExeHeader->ulNewHeaderOfs,
866 FILE_BEGIN,
867 &ulLocal);
868
869 if (arc == NO_ERROR)
870 {
871 PBYTE pbCheckOS = NULL;
872
873 // read two chars to find out header type
874 CHAR achNewHeaderType[2] = "";
875 arc = DosRead(hFile,
876 &achNewHeaderType,
877 sizeof(achNewHeaderType),
878 &ulBytesRead);
879 // reset file ptr
880 DosSetFilePtr(hFile,
881 (*ppExec)->pDosExeHeader->ulNewHeaderOfs,
882 FILE_BEGIN,
883 &ulLocal);
884
885 if (memcmp(achNewHeaderType, "NE", 2) == 0)
886 {
887 // New Executable:
888 (*ppExec)->ulExeFormat = EXEFORMAT_NE;
889 // read NE header
890 (*ppExec)->pNEHeader = (PNEHEADER)malloc(sizeof(NEHEADER));
891 DosRead(hFile,
892 (*ppExec)->pNEHeader,
893 sizeof(NEHEADER),
894 &((*ppExec)->cbNEHeader));
895 if ((*ppExec)->cbNEHeader == sizeof(NEHEADER))
896 pbCheckOS = &((*ppExec)->pNEHeader->bTargetOS);
897 }
898 else if ( (memcmp(achNewHeaderType, "LX", 2) == 0)
899 || (memcmp(achNewHeaderType, "LE", 2) == 0)
900 // this is used by SMARTDRV.EXE
901 )
902 {
903 // OS/2 Linear Executable:
904 (*ppExec)->ulExeFormat = EXEFORMAT_LX;
905 // read LX header
906 (*ppExec)->pLXHeader = (PLXHEADER)malloc(sizeof(LXHEADER));
907 DosRead(hFile,
908 (*ppExec)->pLXHeader,
909 sizeof(LXHEADER),
910 &((*ppExec)->cbLXHeader));
911 if ((*ppExec)->cbLXHeader == sizeof(LXHEADER))
912 pbCheckOS = (PBYTE)(&((*ppExec)->pLXHeader->usTargetOS));
913 }
914 else if (memcmp(achNewHeaderType, "PE", 2) == 0)
915 {
916 (*ppExec)->ulExeFormat = EXEFORMAT_PE;
917 (*ppExec)->ulOS = EXEOS_WIN32;
918 (*ppExec)->f32Bits = TRUE;
919 }
920 else
921 arc = ERROR_INVALID_EXE_SIGNATURE;
922
923 if (pbCheckOS)
924 // BYTE to check for operating system
925 // (NE and LX):
926 switch (*pbCheckOS)
927 {
928 case NEOS_OS2:
929 (*ppExec)->ulOS = EXEOS_OS2;
930 if ((*ppExec)->ulExeFormat == EXEFORMAT_LX)
931 (*ppExec)->f32Bits = TRUE;
932 break;
933 case NEOS_WIN16:
934 (*ppExec)->ulOS = EXEOS_WIN16;
935 break;
936 case NEOS_DOS4:
937 (*ppExec)->ulOS = EXEOS_DOS4;
938 break;
939 case NEOS_WIN386:
940 (*ppExec)->ulOS = EXEOS_WIN386;
941 (*ppExec)->f32Bits = TRUE;
942 break;
943 }
944 }
945 }
946 }
947
948 // store exec's HFILE
949 (*ppExec)->hfExe = hFile;
950 }
951
952 if (arc != NO_ERROR)
953 // error: clean up
954 doshExecClose(*ppExec);
955
956 } // end if (*ppExec)
957 else
958 arc = ERROR_NOT_ENOUGH_MEMORY;
959 } // end if (ppExec)
960 else
961 arc = ERROR_INVALID_PARAMETER;
962 } // end if (arc == NO_ERROR)
963
964 return (arc);
965}
966
967/*
968 *@@ doshExecClose:
969 * this closes an executable opened with doshExecOpen.
970 * Always call this function if NO_ERROR was returned by
971 * doshExecOpen.
972 *
973 *@@added V0.9.0 [umoeller]
974 */
975
976APIRET doshExecClose(PEXECUTABLE pExec)
977{
978 APIRET arc = NO_ERROR;
979 if (pExec)
980 {
981 if (pExec->pDosExeHeader)
982 free(pExec->pDosExeHeader);
983 if (pExec->pNEHeader)
984 free(pExec->pNEHeader);
985 if (pExec->pLXHeader)
986 free(pExec->pLXHeader);
987
988 if (pExec->pszDescription)
989 free(pExec->pszDescription);
990 if (pExec->pszVendor)
991 free(pExec->pszVendor);
992 if (pExec->pszVersion)
993 free(pExec->pszVersion);
994 if (pExec->pszInfo)
995 free(pExec->pszInfo);
996
997 DosClose(pExec->hfExe);
998
999 free(pExec);
1000 }
1001 else
1002 arc = ERROR_INVALID_PARAMETER;
1003
1004 return (arc);
1005}
1006
1007/*
1008 *@@ doshExecQueryBldLevel:
1009 * this retrieves buildlevel information for an
1010 * LX or NE executable previously opened with
1011 * doshExecOpen.
1012 *
1013 * BuildLevel information must be contained in the
1014 * DESCRIPTION field of an executable's module
1015 * definition (.DEF) file. In order to be readable
1016 * by BLDLEVEL.EXE (which ships with OS/2), this
1017 * string must have the following format:
1018 *
1019 + Description '@#AUTHOR:VERSION#@ DESCRIPTION'
1020 *
1021 * Example:
1022 *
1023 + Description '@#Ulrich M”ller:0.9.0#@ XWorkplace Sound Support Module'
1024 *
1025 * The "Description" entry always ends up as the
1026 * very first entry in the non-resident name table
1027 * in LX and NE executables. So this is what we retrieve
1028 * here.
1029 *
1030 * If the first entry in that table exists, NO_ERROR is
1031 * returned and at least the pszDescription field in
1032 * EXECUTABLE is set to that information.
1033 *
1034 * If that string is in IBM BLDLEVEL format, the string
1035 * is automatically parsed, and the pszVendor, pszVersion,
1036 * and pszInfo fields are also set. In the above examples,
1037 * this would return the following information:
1038 + pszVendor = "Ulrich M”ller"
1039 + pszVersion = "0.9.0"
1040 + pszInfo = "XWorkplace Sound Support Module"
1041 *
1042 * If that string is not in BLDLEVEL format, only pszDescription
1043 * will be set. The other fields remain NULL.
1044 *
1045 * This returns the following errors:
1046 * -- ERROR_INVALID_PARAMETER: pExec invalid
1047 * -- ERROR_INVALID_EXE_SIGNATURE (191): pExec is not in LX or NE format
1048 * -- ERROR_INVALID_DATA (13): non-resident name table not found.
1049 * -- ERROR_NOT_ENOUGH_MEMORY: malloc() failed.
1050 *
1051 * plus the error codes of DosSetFilePtr and DosRead.
1052 *
1053 *@@added V0.9.0 [umoeller]
1054 *@@changed V0.9.0 (99-10-22) [umoeller]: NE format now supported
1055 *@@changed V0.9.1 (99-12-06): fixed memory leak
1056 */
1057
1058APIRET doshExecQueryBldLevel(PEXECUTABLE pExec)
1059{
1060 APIRET arc = NO_ERROR;
1061 PSZ pszNameTable = NULL;
1062 ULONG ulNRNTOfs = 0;
1063
1064 do
1065 {
1066 ULONG ulLocal = 0,
1067 ulBytesRead = 0;
1068 PSZ pStartOfAuthor = NULL;
1069
1070 if (pExec == NULL)
1071 {
1072 arc = ERROR_INVALID_PARAMETER;
1073 break;
1074 }
1075
1076 if (pExec->ulExeFormat == EXEFORMAT_LX)
1077 {
1078 // OK, LX format:
1079 // check if we have a non-resident name table
1080 if (pExec->pLXHeader == NULL)
1081 {
1082 arc = ERROR_INVALID_DATA;
1083 break;
1084 }
1085 if (pExec->pLXHeader->ulNonResdNameTblOfs == 0)
1086 {
1087 arc = ERROR_INVALID_DATA;
1088 break;
1089 }
1090
1091 ulNRNTOfs = pExec->pLXHeader->ulNonResdNameTblOfs;
1092 }
1093 else if (pExec->ulExeFormat == EXEFORMAT_NE)
1094 {
1095 // OK, NE format:
1096 // check if we have a non-resident name table
1097 if (pExec->pNEHeader == NULL)
1098 {
1099 arc = ERROR_INVALID_DATA;
1100 break;
1101 }
1102 if (pExec->pNEHeader->ulNonResdTblOfs == 0)
1103 {
1104 arc = ERROR_INVALID_DATA;
1105 break;
1106 }
1107
1108 ulNRNTOfs = pExec->pNEHeader->ulNonResdTblOfs;
1109 }
1110 else
1111 {
1112 // neither LX nor NE: stop
1113 arc = ERROR_INVALID_EXE_SIGNATURE;
1114 break;
1115 }
1116
1117 if (ulNRNTOfs == 0)
1118 {
1119 // shouldn't happen
1120 arc = ERROR_INVALID_DATA;
1121 break;
1122 }
1123
1124 // move EXE file pointer to offset of non-resident name table
1125 // (from LX header)
1126 arc = DosSetFilePtr(pExec->hfExe, // file is still open
1127 ulNRNTOfs, // ofs determined above
1128 FILE_BEGIN,
1129 &ulLocal);
1130 if (arc != NO_ERROR)
1131 break;
1132
1133 // allocate memory as necessary
1134 pszNameTable = (PSZ)malloc(2001); // should suffice, because each entry
1135 // may only be 255 bytes in length
1136 if (pszNameTable)
1137 {
1138 arc = DosRead(pExec->hfExe,
1139 pszNameTable,
1140 2000,
1141 &ulBytesRead);
1142 if (arc != NO_ERROR)
1143 break;
1144 if (*pszNameTable == 0)
1145 {
1146 // first byte (length byte) is null:
1147 arc = ERROR_INVALID_DATA;
1148 free (pszNameTable); // fixed V0.9.1 (99-12-06)
1149 break;
1150 }
1151
1152 // now copy the string, which is in Pascal format
1153 pExec->pszDescription = (PSZ)malloc((*pszNameTable) + 1); // addt'l null byte
1154 memcpy(pExec->pszDescription,
1155 pszNameTable + 1, // skip length byte
1156 *pszNameTable); // length byte
1157 // terminate string
1158 *(pExec->pszDescription + (*pszNameTable)) = 0;
1159
1160 // _Pmpf(("pszDescription: %s", pExec->pszDescription));
1161
1162 // now parse the damn thing:
1163 // @#AUTHOR:VERSION#@ DESCRIPTION
1164 // but skip the first byte, which has the string length
1165 pStartOfAuthor = strstr(pExec->pszDescription, "@#");
1166 if (pStartOfAuthor)
1167 {
1168 PSZ pStartOfInfo = strstr(pStartOfAuthor + 2, "#@");
1169 // _Pmpf(("Testing"));
1170 if (pStartOfInfo)
1171 {
1172 PSZ pEndOfAuthor = strchr(pStartOfAuthor + 2, ':');
1173 // _Pmpf(("pStartOfinfo: %s", pStartOfInfo));
1174 if (pEndOfAuthor)
1175 {
1176 // _Pmpf(("pEndOfAuthor: %s", pEndOfAuthor));
1177 pExec->pszVendor = strhSubstr(pStartOfAuthor + 2, pEndOfAuthor);
1178 pExec->pszVersion = strhSubstr(pEndOfAuthor + 1, pStartOfInfo);
1179 // skip "@#" in info string
1180 pStartOfInfo += 2;
1181 // skip leading spaces in info string
1182 while (*pStartOfInfo == ' ')
1183 pStartOfInfo++;
1184 // and copy until end of string
1185 pExec->pszInfo = strdup(pStartOfInfo);
1186 }
1187 }
1188 }
1189
1190 free(pszNameTable);
1191 }
1192 else
1193 arc = ERROR_NOT_ENOUGH_MEMORY;
1194 } while (FALSE);
1195
1196
1197 return (arc);
1198}
1199
1200/*
1201 *@@ doshExecQueryImportedModules:
1202 * returns an array of FSYSMODULE structure describing all
1203 * imported modules.
1204 *
1205 * *pcModules receives the # of items in the array (not the
1206 * array size!). Use doshFreeImportedModules to clean up.
1207 *
1208 *@@added V0.9.9 (2001-03-11) [lafaix]
1209 */
1210
1211PFSYSMODULE doshExecQueryImportedModules(PEXECUTABLE pExec,
1212 PULONG pcModules)
1213{
1214 return (NULL);
1215}
1216
1217/*
1218 *@@ doshExecFreeImportedModules:
1219 * frees resources allocated by doshExecQueryImportedModules.
1220 *
1221 *@@added V0.9.9 (2001-03-11)
1222 */
1223
1224APIRET doshExecFreeImportedModules(PFSYSMODULE paModules)
1225{
1226 free(paModules);
1227 return (NO_ERROR);
1228}
1229
1230/*
1231 *@@ doshExecQueryExportedFunctions:
1232 * returns an array of FSYSFUNCTION structure describing all
1233 * exported functions.
1234 *
1235 * *pcFunctions receives the # of items in the array (not the
1236 * array size!). Use doshFreeExportedFunctions to clean up.
1237 *
1238 * Note that the returned array only contains entry for exported
1239 * functions. Empty export entries are _not_ included.
1240 *
1241 *@@added V0.9.9 (2001-03-11) [lafaix]
1242 */
1243
1244PFSYSFUNCTION doshExecQueryExportedFunctions(PEXECUTABLE pExec,
1245 PULONG pcFunctions)
1246{
1247 return (NULL);
1248}
1249
1250/*
1251 *@@ doshExecFreeExportedFunctions:
1252 * frees resources allocated by doshExecQueryExportedFunctions.
1253 *
1254 *@@added V0.9.9 (2001-03-11)
1255 */
1256
1257APIRET doshExecFreeExportedFunctions(PFSYSFUNCTION paFunctions)
1258{
1259 free(paFunctions);
1260 return (NO_ERROR);
1261}
1262
1263/*
1264 *@@ doshExecQueryResources:
1265 * returns an array of FSYSRESOURCE structures describing all
1266 * available resources in the module.
1267 *
1268 * *pcResources receives the no. of items in the array
1269 * (not the array size!). Use doshExecFreeResources to clean up.
1270 *
1271 *@@added V0.9.7 (2000-12-18) [lafaix]
1272 */
1273
1274PFSYSRESOURCE doshExecQueryResources(PEXECUTABLE pExec, PULONG pcResources)
1275{
1276 ULONG cResources = 0;
1277 PFSYSRESOURCE paResources = NULL;
1278 int i;
1279
1280 if (pExec)
1281 {
1282 if (pExec->ulOS == EXEOS_OS2)
1283 {
1284 ULONG ulDummy;
1285
1286 if (pExec->ulExeFormat == EXEFORMAT_LX)
1287 {
1288 // It's a 32bit OS/2 executable
1289 cResources = pExec->pLXHeader->ulResTblCnt;
1290
1291 if (cResources)
1292 {
1293 struct rsrc32 /* Resource Table Entry */
1294 {
1295 unsigned short type; /* Resource type */
1296 unsigned short name; /* Resource name */
1297 unsigned long cb; /* Resource size */
1298 unsigned short obj; /* Object number */
1299 unsigned long offset; /* Offset within object */
1300 } rs;
1301
1302 struct o32_obj /* Flat .EXE object table entry */
1303 {
1304 unsigned long o32_size; /* Object virtual size */
1305 unsigned long o32_base; /* Object base virtual address */
1306 unsigned long o32_flags; /* Attribute flags */
1307 unsigned long o32_pagemap; /* Object page map index */
1308 unsigned long o32_mapsize; /* Number of entries in object page map */
1309 unsigned long o32_reserved; /* Reserved */
1310 } ot;
1311
1312 paResources = (PFSYSRESOURCE)malloc(sizeof(FSYSRESOURCE) * cResources);
1313
1314 DosSetFilePtr(pExec->hfExe,
1315 pExec->pLXHeader->ulResTblOfs
1316 + pExec->pDosExeHeader->ulNewHeaderOfs,
1317 FILE_BEGIN,
1318 &ulDummy);
1319
1320 for (i = 0; i < cResources; i++)
1321 {
1322 DosRead(pExec->hfExe, &rs, 14, &ulDummy);
1323 paResources[i].ulID = rs.name;
1324 paResources[i].ulType = rs.type;
1325 paResources[i].ulSize = rs.cb;
1326 paResources[i].ulFlag = rs.obj; // Temp storage for Object
1327 // number. Will be filled
1328 // with resource flag
1329 // later.
1330 }
1331
1332 for (i = 0; i < cResources; i++)
1333 {
1334 DosSetFilePtr(pExec->hfExe,
1335 pExec->pLXHeader->ulObjTblOfs
1336 + pExec->pDosExeHeader->ulNewHeaderOfs
1337 + ( sizeof(ot)
1338 * (paResources[i].ulFlag - 1)),
1339 FILE_BEGIN,
1340 &ulDummy);
1341 DosRead(pExec->hfExe, &ot, sizeof(ot), &ulDummy);
1342
1343 paResources[i].ulFlag = (ot.o32_flags & OBJWRITE) ? 0 : RNPURE;
1344 paResources[i].ulFlag |= (ot.o32_flags & OBJDISCARD) ? 4096 : 0;
1345 paResources[i].ulFlag |= (ot.o32_flags & OBJSHARED) ? RNMOVE : 0;
1346 paResources[i].ulFlag |= (ot.o32_flags & OBJPRELOAD) ? RNPRELOAD : 0;
1347 }
1348 }
1349 }
1350 else
1351 if (pExec->ulExeFormat == EXEFORMAT_NE)
1352 {
1353 // It's a 16bit OS/2 executable
1354 cResources = pExec->pNEHeader->usResSegmCount;
1355
1356 if (cResources)
1357 {
1358 struct {unsigned short type; unsigned short name;} rti;
1359 struct new_seg /* New .EXE segment table entry */
1360 {
1361 unsigned short ns_sector; /* File sector of start of segment */
1362 unsigned short ns_cbseg; /* Number of bytes in file */
1363 unsigned short ns_flags; /* Attribute flags */
1364 unsigned short ns_minalloc; /* Minimum allocation in bytes */
1365 } ns;
1366
1367 paResources = (PFSYSRESOURCE)malloc(sizeof(FSYSRESOURCE) * cResources);
1368
1369 // We first read the resources IDs and types
1370 DosSetFilePtr(pExec->hfExe,
1371 pExec->pNEHeader->usResTblOfs
1372 + pExec->pDosExeHeader->ulNewHeaderOfs,
1373 FILE_BEGIN,
1374 &ulDummy);
1375
1376 for (i = 0; i < cResources; i++)
1377 {
1378 DosRead(pExec->hfExe, &rti, sizeof(rti), &ulDummy);
1379 paResources[i].ulID = rti.name;
1380 paResources[i].ulType = rti.type;
1381 }
1382
1383 // And we then read their sizes and flags
1384 for (i = 0; i < cResources; i++)
1385 {
1386 DosSetFilePtr(pExec->hfExe,
1387 pExec->pDosExeHeader->ulNewHeaderOfs
1388 + pExec->pNEHeader->usSegTblOfs
1389 + (sizeof(ns)
1390 * ( pExec->pNEHeader->usSegTblEntries
1391 - pExec->pNEHeader->usResSegmCount
1392 + i)),
1393 FILE_BEGIN,
1394 &ulDummy);
1395 DosRead(pExec->hfExe, &ns, sizeof(ns), &ulDummy);
1396
1397 paResources[i].ulSize = ns.ns_cbseg;
1398
1399 paResources[i].ulFlag = (ns.ns_flags & OBJPRELOAD) ? RNPRELOAD : 0;
1400 paResources[i].ulFlag |= (ns.ns_flags & OBJSHARED) ? RNPURE : 0;
1401 paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? RNMOVE : 0;
1402 paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? 4096 : 0;
1403 }
1404 }
1405 }
1406
1407 *pcResources = cResources;
1408 }
1409 }
1410
1411 return (paResources);
1412}
1413
1414/*
1415 *@@ doshExecFreeResources:
1416 * frees resources allocated by doshExecQueryResources.
1417 *
1418 *@@added V0.9.7 (2000-12-18) [lafaix]
1419 */
1420
1421APIRET doshExecFreeResources(PFSYSRESOURCE paResources)
1422{
1423 free(paResources);
1424 return (NO_ERROR);
1425}
1426
1427/*
1428 *@@category: Helpers\Control program helpers\Partitions info
1429 * functions for retrieving partition information directly
1430 * from the partition tables on the disk. See doshGetPartitionsList.
1431 */
1432
1433/********************************************************************
1434 *
1435 * Partition functions
1436 *
1437 ********************************************************************/
1438
1439/*
1440 *@@ doshQueryDiskCount:
1441 * returns the no. of physical disks installed
1442 * on the system.
1443 *
1444 * Based on code (C) Dmitry A. Steklenev.
1445 *
1446 *@@added V0.9.0 [umoeller]
1447 */
1448
1449UINT doshQueryDiskCount(VOID)
1450{
1451 USHORT count = 0;
1452
1453 DosPhysicalDisk(INFO_COUNT_PARTITIONABLE_DISKS, &count, 2, 0, 0);
1454 return (count);
1455}
1456
1457/*
1458 *@@ doshReadSector:
1459 * reads a physical disk sector.
1460 *
1461 * If NO_ERROR is returned, the sector contents
1462 * have been stored in *buff.
1463 *
1464 * Based on code (C) Dmitry A. Steklenev.
1465 *
1466 *@@added V0.9.0 [umoeller]
1467 */
1468
1469APIRET doshReadSector(USHORT disk, // in: physical disk no. (1, 2, 3, ...)
1470 void *buff,
1471 USHORT head,
1472 USHORT cylinder,
1473 USHORT sector)
1474{
1475 UINT arc;
1476 HFILE dh = 0;
1477 char dn[256];
1478 // char ms[256];
1479
1480 sprintf( dn, "%u:", disk );
1481 arc = DosPhysicalDisk(INFO_GETIOCTLHANDLE, &dh, 2, dn, 3);
1482
1483 if (arc)
1484 // error:
1485 return (arc);
1486 else
1487 {
1488 TRACKLAYOUT DiskIOParm;
1489 ULONG IOCtlDataLength = sizeof(DiskIOParm);
1490 ULONG IOCtlParmLength = 512;
1491
1492 DiskIOParm.bCommand = 0;
1493 DiskIOParm.usHead = head;
1494 DiskIOParm.usCylinder = cylinder;
1495 DiskIOParm.usFirstSector = 0;
1496 DiskIOParm.cSectors = 1;
1497 DiskIOParm.TrackTable[0].usSectorNumber = sector;
1498 DiskIOParm.TrackTable[0].usSectorSize = 512;
1499
1500 arc = DosDevIOCtl(dh,
1501 IOCTL_PHYSICALDISK, PDSK_READPHYSTRACK,
1502 &DiskIOParm, IOCtlParmLength, &IOCtlParmLength,
1503 buff , IOCtlDataLength, &IOCtlDataLength);
1504
1505 if(arc)
1506 {
1507 // error:
1508 DosPhysicalDisk(INFO_FREEIOCTLHANDLE, 0, 0, &dh, 2);
1509 return (arc);
1510 }
1511
1512 DosPhysicalDisk(INFO_FREEIOCTLHANDLE, 0, 0, &dh, 2);
1513 }
1514 return (NO_ERROR);
1515}
1516
1517/*
1518 *@@ doshType2FSName:
1519 * this returns a static, zero-terminated string
1520 * for the given FS type. This is always 7 bytes
1521 * in length.
1522 *
1523 * Values for operating system indicator:
1524 * -- 00h empty
1525 * -- 01h DOS 12-bit FAT
1526 * -- 02h XENIX root file system
1527 * -- 03h XENIX /usr file system (obsolete)
1528 * -- 04h DOS 16-bit FAT (up to 32M)
1529 * -- 05h DOS 3.3+ extended partition
1530 * -- 06h DOS 3.31+ Large File System (16-bit FAT, over 32M)
1531 * -- 07h QNX
1532 * -- 07h OS/2 HPFS
1533 * -- 07h Windows NT NTFS
1534 * -- 07h Advanced Unix
1535 * -- 08h OS/2 (v1.0-1.3 only)
1536 * -- 08h AIX bootable partition, SplitDrive
1537 * -- 08h Commodore DOS
1538 * -- 08h DELL partition spanning multiple drives
1539 * -- 09h AIX data partition
1540 * -- 09h Coherent filesystem
1541 * -- 0Ah OS/2 Boot Manager
1542 * -- 0Ah OPUS
1543 * -- 0Ah Coherent swap partition
1544 * -- 0Bh Windows95 with 32-bit FAT
1545 * -- 0Ch Windows95 with 32-bit FAT (using LBA-mode INT 13 extensions)
1546 * -- 0Eh logical-block-addressable VFAT (same as 06h but using LBA-mode INT 13)
1547 * -- 0Fh logical-block-addressable VFAT (same as 05h but using LBA-mode INT 13)
1548 * -- 10h OPUS
1549 * -- 11h OS/2 Boot Manager hidden 12-bit FAT partition
1550 * -- 12h Compaq Diagnostics partition
1551 * -- 14h (resulted from using Novell DOS 7.0 FDISK to delete Linux Native part)
1552 * -- 14h OS/2 Boot Manager hidden sub-32M 16-bit FAT partition
1553 * -- 16h OS/2 Boot Manager hidden over-32M 16-bit FAT partition
1554 * -- 17h OS/2 Boot Manager hidden HPFS partition
1555 * -- 18h AST special Windows swap file ("Zero-Volt Suspend" partition)
1556 * -- 21h officially listed as reserved
1557 * -- 23h officially listed as reserved
1558 * -- 24h NEC MS-DOS 3.x
1559 * -- 26h officially listed as reserved
1560 * -- 31h officially listed as reserved
1561 * -- 33h officially listed as reserved
1562 * -- 34h officially listed as reserved
1563 * -- 36h officially listed as reserved
1564 * -- 38h Theos
1565 * -- 3Ch PowerQuest PartitionMagic recovery partition
1566 * -- 40h VENIX 80286
1567 * -- 41h Personal RISC Boot
1568 * -- 42h SFS (Secure File System) by Peter Gutmann
1569 * -- 50h OnTrack Disk Manager, read-only partition
1570 * -- 51h OnTrack Disk Manager, read/write partition
1571 * -- 51h NOVEL
1572 * -- 52h CP/M
1573 * -- 52h Microport System V/386
1574 * -- 53h OnTrack Disk Manager, write-only partition???
1575 * -- 54h OnTrack Disk Manager (DDO)
1576 * -- 56h GoldenBow VFeature
1577 * -- 61h SpeedStor
1578 * -- 63h Unix SysV/386, 386/ix
1579 * -- 63h Mach, MtXinu BSD 4.3 on Mach
1580 * -- 63h GNU HURD
1581 * -- 64h Novell NetWare 286
1582 * -- 65h Novell NetWare (3.11)
1583 * -- 67h Novell
1584 * -- 68h Novell
1585 * -- 69h Novell
1586 * -- 70h DiskSecure Multi-Boot
1587 * -- 71h officially listed as reserved
1588 * -- 73h officially listed as reserved
1589 * -- 74h officially listed as reserved
1590 * -- 75h PC/IX
1591 * -- 76h officially listed as reserved
1592 * -- 80h Minix v1.1 - 1.4a
1593 * -- 81h Minix v1.4b+
1594 * -- 81h Linux
1595 * -- 81h Mitac Advanced Disk Manager
1596 * -- 82h Linux Swap partition
1597 * -- 82h Prime
1598 * -- 83h Linux native file system (ext2fs/xiafs)
1599 * -- 84h OS/2-renumbered type 04h partition (related to hiding DOS C: drive)
1600 * -- 86h FAT16 volume/stripe set (Windows NT)
1601 * -- 87h HPFS Fault-Tolerant mirrored partition
1602 * -- 87h NTFS volume/stripe set
1603 * -- 93h Amoeba file system
1604 * -- 94h Amoeba bad block table
1605 * -- A0h Phoenix NoteBIOS Power Management "Save-to-Disk" partition
1606 * -- A1h officially listed as reserved
1607 * -- A3h officially listed as reserved
1608 * -- A4h officially listed as reserved
1609 * -- A5h FreeBSD, BSD/386
1610 * -- A6h officially listed as reserved
1611 * -- B1h officially listed as reserved
1612 * -- B3h officially listed as reserved
1613 * -- B4h officially listed as reserved
1614 * -- B6h officially listed as reserved
1615 * -- B7h BSDI file system (secondarily swap)
1616 * -- B8h BSDI swap partition (secondarily file system)
1617 * -- C1h DR DOS 6.0 LOGIN.EXE-secured 12-bit FAT partition
1618 * -- C4h DR DOS 6.0 LOGIN.EXE-secured 16-bit FAT partition
1619 * -- C6h DR DOS 6.0 LOGIN.EXE-secured Huge partition
1620 * -- C6h corrupted FAT16 volume/stripe set (Windows NT)
1621 * -- C7h Syrinx Boot
1622 * -- C7h corrupted NTFS volume/stripe set
1623 * -- D8h CP/M-86
1624 * -- DBh CP/M, Concurrent CP/M, Concurrent DOS
1625 * -- DBh CTOS (Convergent Technologies OS)
1626 * -- E1h SpeedStor 12-bit FAT extended partition
1627 * -- E3h DOS read-only
1628 * -- E3h Storage Dimensions
1629 * -- E4h SpeedStor 16-bit FAT extended partition
1630 * -- E5h officially listed as reserved
1631 * -- E6h officially listed as reserved
1632 * -- F1h Storage Dimensions
1633 * -- F2h DOS 3.3+ secondary partition
1634 * -- F3h officially listed as reserved
1635 * -- F4h SpeedStor
1636 * -- F4h Storage Dimensions
1637 * -- F6h officially listed as reserved
1638 * -- FEh LANstep
1639 * -- FEh IBM PS/2 IML
1640 * -- FFh Xenix bad block table
1641 *
1642 * Note: for partition type 07h, one should inspect the partition boot record
1643 * for the actual file system type
1644 *
1645 * Based on code (C) Dmitry A. Steklenev.
1646 *
1647 *@@added V0.9.0 [umoeller]
1648 */
1649
1650char* doshType2FSName(unsigned char bFSType) // in: FS type
1651{
1652 PSZ zFSName = NULL;
1653
1654 switch (bFSType)
1655 {
1656 case PAR_UNUSED:
1657 zFSName = "UNUSED ";
1658 break;
1659 case PAR_FAT12SMALL:
1660 zFSName = "FAT-12 ";
1661 break;
1662 case PAR_XENIXROOT:
1663 zFSName = "XENIX ";
1664 break;
1665 case PAR_XENIXUSER:
1666 zFSName = "XENIX ";
1667 break;
1668 case PAR_FAT16SMALL:
1669 zFSName = "FAT-16 ";
1670 break;
1671 case PAR_EXTENDED:
1672 zFSName = "EXTEND ";
1673 break;
1674 case PAR_FAT16BIG:
1675 zFSName = "BIGDOS ";
1676 break;
1677 case PAR_HPFS:
1678 zFSName = "HPFS ";
1679 break;
1680 case PAR_AIXBOOT:
1681 zFSName = "AIX ";
1682 break;
1683 case PAR_AIXDATA:
1684 zFSName = "AIX ";
1685 break;
1686 case PAR_BOOTMANAGER:
1687 zFSName = "BOOTMNG";
1688 break;
1689 case PAR_WINDOWS95:
1690 zFSName = "WIN95 ";
1691 break;
1692 case PAR_WINDOWS95LB:
1693 zFSName = "WIN95 ";
1694 break;
1695 case PAR_VFAT16BIG:
1696 zFSName = "VFAT ";
1697 break;
1698 case PAR_VFAT16EXT:
1699 zFSName = "VFAT ";
1700 break;
1701 case PAR_OPUS:
1702 zFSName = "OPUS ";
1703 break;
1704 case PAR_HID12SMALL:
1705 zFSName = "FAT-12*";
1706 break;
1707 case PAR_COMPAQDIAG:
1708 zFSName = "COMPAQ ";
1709 break;
1710 case PAR_HID16SMALL:
1711 zFSName = "FAT-16*";
1712 break;
1713 case PAR_HID16BIG:
1714 zFSName = "BIGDOS*";
1715 break;
1716 case PAR_HIDHPFS:
1717 zFSName = "HPFS* ";
1718 break;
1719 case PAR_WINDOWSSWP:
1720 zFSName = "WINSWAP";
1721 break;
1722 case PAR_NECDOS:
1723 zFSName = "NECDOS ";
1724 break;
1725 case PAR_THEOS:
1726 zFSName = "THEOS ";
1727 break;
1728 case PAR_VENIX:
1729 zFSName = "VENIX ";
1730 break;
1731 case PAR_RISCBOOT:
1732 zFSName = "RISC ";
1733 break;
1734 case PAR_SFS:
1735 zFSName = "SFS ";
1736 break;
1737 case PAR_ONTRACK:
1738 zFSName = "ONTRACK";
1739 break;
1740 case PAR_ONTRACKEXT:
1741 zFSName = "ONTRACK";
1742 break;
1743 case PAR_CPM:
1744 zFSName = "CP/M ";
1745 break;
1746 case PAR_UNIXSYSV:
1747 zFSName = "UNIX ";
1748 break;
1749 case PAR_NOVELL_64:
1750 zFSName = "NOVELL ";
1751 break;
1752 case PAR_NOVELL_65:
1753 zFSName = "NOVELL ";
1754 break;
1755 case PAR_NOVELL_67:
1756 zFSName = "NOVELL ";
1757 break;
1758 case PAR_NOVELL_68:
1759 zFSName = "NOVELL ";
1760 break;
1761 case PAR_NOVELL_69:
1762 zFSName = "NOVELL ";
1763 break;
1764 case PAR_PCIX:
1765 zFSName = "PCIX ";
1766 break;
1767 case PAR_MINIX:
1768 zFSName = "MINIX ";
1769 break;
1770 case PAR_LINUX:
1771 zFSName = "LINUX ";
1772 break;
1773 case PAR_LINUXSWAP:
1774 zFSName = "LNXSWP ";
1775 break;
1776 case PAR_LINUXFILE:
1777 zFSName = "LINUX ";
1778 break;
1779 case PAR_FREEBSD:
1780 zFSName = "FREEBSD";
1781 break;
1782 case PAR_BBT:
1783 zFSName = "BBT ";
1784 break;
1785
1786 default:
1787 zFSName = " ";
1788 break;
1789 }
1790 return zFSName;
1791}
1792
1793/*
1794 * AppendPartition:
1795 * this appends the given partition information to
1796 * the given partition list. To do this, a new
1797 * PARTITIONINFO structure is created and appended
1798 * in a list (managed thru the PARTITIONINFO.pNext
1799 * items).
1800 *
1801 * pppiThis must be a pointer to a pointer to a PARTITIONINFO.
1802 * With each call of this function, this pointer is advanced
1803 * to point to the newly created PARTITIONINFO, so before
1804 * calling this function for the first time,
1805 *
1806 * Based on code (C) Dmitry A. Steklenev.
1807 *
1808 *@@added V0.9.0 [umoeller]
1809 */
1810
1811APIRET AppendPartition(PARTITIONINFO **pppiFirst,
1812 PARTITIONINFO **pppiThis, // in/out: partition info; pointer will be advanced
1813 PUSHORT posCount, // in/out: partition count
1814 BYTE bDisk, // in: disk of partition
1815 char *pszBootName, // in: boot partition name
1816 CHAR cLetter, // in/out: drive letter
1817 BYTE bFsType, // in: file system type
1818 BOOL fPrimary, // in: primary?
1819 BOOL fBootable,
1820 ULONG ulSectors) // in: no. of sectors
1821{
1822 APIRET arc = NO_ERROR;
1823 PPARTITIONINFO ppiNew = (PPARTITIONINFO)malloc(sizeof(PARTITIONINFO));
1824 if (ppiNew)
1825 {
1826 // store data
1827 ppiNew->bDisk = bDisk;
1828 if (fBootable)
1829 {
1830 memcpy(ppiNew->szBootName, pszBootName, 8);
1831 ppiNew->szBootName[8] = 0;
1832 }
1833 else
1834 ppiNew->szBootName[0] = 0;
1835 ppiNew->cLetter = cLetter;
1836 ppiNew->bFSType = bFsType;
1837 strcpy(ppiNew->szFSType,
1838 doshType2FSName(bFsType));
1839 ppiNew->fPrimary = fPrimary;
1840 ppiNew->fBootable = fBootable;
1841 ppiNew->ulSize = ulSectors / 2048;
1842
1843 ppiNew->pNext = NULL;
1844
1845 (*posCount)++;
1846
1847 if (*pppiFirst == (PPARTITIONINFO)NULL)
1848 {
1849 // first call:
1850 *pppiFirst = ppiNew;
1851 *pppiThis = ppiNew;
1852 }
1853 else
1854 {
1855 // append to list
1856 (**pppiThis).pNext = ppiNew;
1857 *pppiThis = ppiNew;
1858 }
1859 }
1860 else
1861 arc = ERROR_NOT_ENOUGH_MEMORY;
1862
1863 return (arc);
1864}
1865
1866// Sector and Cylinder values are actually 6 bits and 10 bits:
1867//
1868// 1 1 1 1 1 1
1869// Ú5Â4Â3Â2Â1Â0Â9Â8Â7Â6Â5Â4Â3Â2Â1ÂÄ¿
1870// ³c c c c c c c c C c S s s s s s³
1871// ÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙ
1872//
1873// The high two bits of the second byte are used as the high bits
1874// of a 10-bit value. This allows for as many as 1024 cylinders
1875// and 64 sectors per cylinder.
1876
1877/*
1878 * GetCyl:
1879 * get cylinder number.
1880 *
1881 * Based on code (C) Dmitry A. Steklenev.
1882 *
1883 *@@added V0.9.0 [umoeller]
1884 */
1885
1886static USHORT GetCyl(USHORT rBeginSecCyl)
1887{
1888 return ((rBeginSecCyl & 0x00C0) << 2) +
1889 ((rBeginSecCyl & 0xFF00) >> 8);
1890}
1891
1892/*
1893 * GetSec:
1894 * get sector number.
1895 *
1896 * Based on code (C) Dmitry A. Steklenev.
1897 *
1898 *@@added V0.9.0 [umoeller]
1899 */
1900
1901static USHORT GetSec(USHORT rBeginSecCyl)
1902{
1903 return rBeginSecCyl & 0x003F;
1904}
1905
1906/*
1907 *@@ doshGetBootManager:
1908 * this goes thru the master boot records on all
1909 * disks to find the boot manager partitions.
1910 *
1911 * Returns:
1912 * -- NO_ERROR: boot manager found; in that case,
1913 * information about the boot manager
1914 * is written into *pusDisk, *pusPart,
1915 * *BmInfo. Any of these pointers can
1916 * be NULL if you're not interested.
1917 * -- ERROR_NOT_SUPPORTED (50): boot manager not installed.
1918 *
1919 * Based on code (C) Dmitry A. Steklenev.
1920 *
1921 *@@added V0.9.0 [umoeller]
1922 */
1923
1924APIRET doshGetBootManager(USHORT *pusDisk, // out: if != NULL, boot manager disk (1, 2, ...)
1925 USHORT *pusPart, // out: if != NULL, index of bmgr primary partition (0-3)
1926 PAR_INFO *BmInfo) // out: if != NULL, boot manager partition info
1927{
1928 APIRET arc = NO_ERROR;
1929 USHORT count = doshQueryDiskCount(); // Physical disk number
1930 MBR_INFO MBoot; // Master Boot
1931 USHORT usDisk;
1932
1933 if (count > 8) // Not above 8 disks
1934 count = 8;
1935
1936 for (usDisk = 1; usDisk <= count; usDisk++)
1937 {
1938 USHORT usPrim = 0;
1939
1940 // for each disk, read the MBR, which has the
1941 // primary partitions
1942 if ((arc = doshReadSector(usDisk, &MBoot,
1943 0, 0, 1)))
1944 return (arc);
1945
1946 // Lookup BootManager partition
1947 for (usPrim = 0; usPrim < 4; usPrim++)
1948 {
1949 if (MBoot.sPrtnInfo[usPrim].bFileSysCode == 0x0A)
1950 {
1951 if (BmInfo)
1952 *BmInfo = MBoot.sPrtnInfo[usPrim];
1953 if (pusPart)
1954 *pusPart = usPrim;
1955 if (pusDisk)
1956 *pusDisk = usDisk;
1957 return (NO_ERROR);
1958 }
1959 }
1960 }
1961
1962 return (ERROR_NOT_SUPPORTED);
1963}
1964
1965/*
1966 * GetPrimaryPartitions:
1967 * this returns the primary partitions.
1968 *
1969 * This gets called from doshGetPartitionsList.
1970 *
1971 * Returns 0 upon errors.
1972 *
1973 * Based on code (C) Dmitry A. Steklenev.
1974 *
1975 *@@added V0.9.0 [umoeller]
1976 */
1977
1978APIRET GetPrimaryPartitions(PARTITIONINFO **pppiFirst,
1979 PARTITIONINFO **pppiThis,
1980 PUSHORT posCount, // in/out: partition count
1981 PCHAR pcLetter, // in/out: drive letter counter
1982 UINT BmDisk, // in: physical disk (1, 2, 3, ...) of boot manager or null
1983 PAR_INFO* BmInfo, // in: info returned by doshGetBootManager or NULL
1984 UINT iDisk) // in: system's physical disk count
1985{
1986 APIRET arc = NO_ERROR;
1987 MBR_INFO MBoot; // Master Boot
1988 SYS_INFO MName[32]; // Name Space from Boot Manager
1989 USHORT i;
1990
1991 memset(&MName, 0, sizeof(MName));
1992
1993 if (BmInfo)
1994 {
1995 // read boot manager name table
1996 if ((arc = doshReadSector(BmDisk, &MName, BmInfo->bBeginHead,
1997 GetCyl(BmInfo->rBeginSecCyl),
1998 GetSec(BmInfo->rBeginSecCyl) + 3)))
1999 return (arc);
2000 }
2001
2002 // read master boot record
2003 if ((arc = doshReadSector(iDisk, &MBoot, 0, 0, 1)))
2004 return (arc);
2005
2006 for (i = 0;
2007 i < 4; // there can be only four primary partitions
2008 i++)
2009 {
2010 // skip unused partition, BootManager or Extended partition
2011 if ( (MBoot.sPrtnInfo[i].bFileSysCode) // skip unused
2012 && (MBoot.sPrtnInfo[i].bFileSysCode != PAR_BOOTMANAGER) // skip boot manager
2013 && (MBoot.sPrtnInfo[i].bFileSysCode != PAR_EXTENDED) // skip extended
2014 )
2015 {
2016 BOOL fBootable = ( (BmInfo)
2017 && (MName[(iDisk-1) * 4 + i].bootable & 0x01)
2018 );
2019 // store this partition
2020 if ((arc = AppendPartition(pppiFirst,
2021 pppiThis,
2022 posCount,
2023 iDisk,
2024 (fBootable)
2025 ? (char*)&MName[(iDisk - 1) * 4 + i].name
2026 : "",
2027 *pcLetter,
2028 MBoot.sPrtnInfo[i].bFileSysCode,
2029 TRUE, // primary
2030 fBootable,
2031 MBoot.sPrtnInfo[i].lTotalSects)))
2032 return (arc);
2033 }
2034 }
2035 return (NO_ERROR);
2036}
2037
2038/*
2039 * GetLogicalDrives:
2040 * this returns info for the logical drives
2041 * in the extended partition. This gets called
2042 * from GetExtendedPartition.
2043 *
2044 * This gets called from GetExtendedPartition.
2045 *
2046 * Based on code (C) Dmitry A. Steklenev.
2047 *
2048 *@@added V0.9.0 [umoeller]
2049 */
2050
2051APIRET GetLogicalDrives(PARTITIONINFO **pppiFirst,
2052 PARTITIONINFO **pppiThis,
2053 PUSHORT posCount,
2054 PCHAR pcLetter,
2055 PAR_INFO* PrInfo, // in: MBR entry of extended partition
2056 UINT PrDisk,
2057 PAR_INFO* BmInfo)
2058{
2059 APIRET arc = NO_ERROR;
2060 EXT_INFO MBoot; // Master Boot
2061 USHORT i;
2062
2063 if ((arc = doshReadSector(PrDisk, &MBoot, PrInfo->bBeginHead,
2064 GetCyl(PrInfo->rBeginSecCyl),
2065 GetSec(PrInfo->rBeginSecCyl))))
2066 return (arc);
2067
2068 for (i = 0; i < 4; i++)
2069 {
2070 // skip unused partition or BootManager partition
2071 if ( (MBoot.sPrtnInfo[i].bFileSysCode)
2072 && (MBoot.sPrtnInfo[i].bFileSysCode != PAR_BOOTMANAGER)
2073 )
2074 {
2075 BOOL fBootable = FALSE;
2076 BOOL fAssignLetter = FALSE;
2077
2078 // special work around extended partition
2079 if (MBoot.sPrtnInfo[i].bFileSysCode == PAR_EXTENDED)
2080 {
2081 if ((arc = GetLogicalDrives(pppiFirst,
2082 pppiThis,
2083 posCount,
2084 pcLetter,
2085 &MBoot.sPrtnInfo[i],
2086 PrDisk,
2087 BmInfo)))
2088 return (arc);
2089
2090 continue;
2091 }
2092
2093 // raise driver letter if OS/2 would recognize this drive
2094 if ( (MBoot.sPrtnInfo[i].bFileSysCode < PAR_PCIX)
2095 )
2096 fAssignLetter = TRUE;
2097
2098 if (fAssignLetter)
2099 (*pcLetter)++;
2100
2101 fBootable = ( (BmInfo)
2102 && ((MBoot.sBmNames[i].bootable & 0x01) != 0)
2103 );
2104
2105 if ((arc = AppendPartition(pppiFirst,
2106 pppiThis,
2107 posCount,
2108 PrDisk,
2109 (fBootable)
2110 ? (char*)&MBoot.sBmNames[i].name
2111 : "",
2112 (fAssignLetter)
2113 ? *pcLetter
2114 : ' ',
2115 MBoot.sPrtnInfo[i].bFileSysCode,
2116 FALSE, // primary
2117 fBootable, // bootable
2118 MBoot.sPrtnInfo[i].lTotalSects)))
2119 return (arc);
2120 }
2121
2122 /* // if BootManager installed and partition is bootable
2123 if (BmInfo)
2124 {
2125 if (MBoot.sBmNames[i].bootable & 0x01)
2126 {
2127 }
2128 }
2129
2130 // if BootManager not installed
2131 else
2132 {
2133 if (arc = AppendPartition(pppiFirst,
2134 pppiThis,
2135 posCount,
2136 PrDisk,
2137 "",
2138 *pcLetter,
2139 MBoot.sPrtnInfo[i].bFileSysCode,
2140 FALSE,
2141 MBoot.sPrtnInfo[i].lTotalSects))
2142 return (arc);
2143 } */
2144 }
2145
2146 return (NO_ERROR);
2147}
2148
2149/*
2150 * GetExtendedPartition:
2151 * this finds the extended partition on the given
2152 * drive and calls GetLogicalDrives in turn.
2153 *
2154 * This gets called from doshGetPartitionsList.
2155 *
2156 * Based on code (C) Dmitry A. Steklenev.
2157 *
2158 *@@added V0.9.0 [umoeller]
2159 */
2160
2161APIRET GetExtendedPartition(PARTITIONINFO **pppiFirst,
2162 PARTITIONINFO **pppiThis,
2163 PUSHORT posCount,
2164 PCHAR pcLetter,
2165 PAR_INFO* BmInfo,
2166 UINT iDisk) // in: disk to query
2167{
2168 APIRET arc = NO_ERROR;
2169 MBR_INFO MBoot; // Master Boot
2170 USHORT i;
2171
2172 if ((arc = doshReadSector(iDisk, &MBoot, 0, 0, 1)))
2173 return (arc);
2174
2175 // go thru MBR entries to find extended partition
2176 for (i = 0;
2177 i < 4;
2178 i++)
2179 {
2180 if (MBoot.sPrtnInfo[i].bFileSysCode == PAR_EXTENDED)
2181 {
2182 if ((arc = GetLogicalDrives(pppiFirst,
2183 pppiThis,
2184 posCount,
2185 pcLetter,
2186 &MBoot.sPrtnInfo[i],
2187 iDisk,
2188 BmInfo)))
2189 return (arc);
2190 }
2191 }
2192
2193 return (NO_ERROR);
2194}
2195
2196/*
2197 *@@ doshGetPartitionsList:
2198 * this returns lots of information about the
2199 * partitions on all physical disks, which is
2200 * read directly from the MBRs and partition
2201 * tables.
2202 *
2203 * If NO_ERROR is returned by this function,
2204 * *ppPartitionInfo points to a linked list of
2205 * PARTITIONINFO structures, which has
2206 * *pusPartitionCount items.
2207 *
2208 * In that case, use doshFreePartitionsList to
2209 * free the resources allocated by this function.
2210 *
2211 * The linked list starts out with all the primary
2212 * partitions, followed by the logical drives in
2213 * the extended partitions. This function attempts
2214 * to guess the correct drive letters and stores
2215 * these with the PARTITIONINFO items, but there's
2216 * no guarantee that this is correct. We correctly
2217 * ignore Linux partitions here and give all primary
2218 * partitions the C: letter, but I have no idea
2219 * what happens with NTFS partitions, since I have
2220 * none.
2221 *
2222 * If an error != NO_ERROR is returned, *pusContext
2223 * will be set to one of the following:
2224 * -- 1: boot manager not found
2225 * -- 2: primary partitions error
2226 * -- 3: secondary partitions error
2227 *
2228 * Based on code (C) Dmitry A. Steklenev.
2229 *
2230 *@@added V0.9.0 [umoeller]
2231 */
2232
2233APIRET doshGetPartitionsList(PPARTITIONINFO *ppPartitionInfo, // out: partition info array
2234 PUSHORT pusPartitionCount, // out: count of items in **ppPartitionInfo
2235 PUSHORT pusContext) // out: error context
2236{
2237 APIRET arc = NO_ERROR;
2238 PAR_INFO BmInfo; // BootManager partition
2239 USHORT usBmDisk; // BootManager disk
2240 USHORT cDisks = doshQueryDiskCount(); // physical disks count
2241 USHORT i;
2242
2243 PARTITIONINFO *pPartitionInfos = NULL, // linked list of all partitions
2244 *ppiTemp = NULL;
2245 USHORT osCount; // bootable partition count
2246 CHAR cLetter = 'C'; // first drive letter
2247
2248 if (cDisks > 8) // Not above 8 disks
2249 cDisks = 8;
2250
2251 // get boot manager disk and info
2252 if ((arc = doshGetBootManager(&usBmDisk,
2253 NULL,
2254 &BmInfo)) != NO_ERROR)
2255 {
2256 *pusContext = 1;
2257 return (arc);
2258 }
2259 // on each disk, read primary partitions
2260 for (i = 1; i <= cDisks; i++)
2261 if ((arc = GetPrimaryPartitions(&pPartitionInfos,
2262 &ppiTemp,
2263 &osCount,
2264 &cLetter,
2265 usBmDisk,
2266 usBmDisk ? &BmInfo : 0,
2267 i)))
2268 {
2269 *pusContext = 2;
2270 return (arc);
2271 }
2272
2273 if (usBmDisk)
2274 {
2275 // boot manager found:
2276 // on each disk, read extended partition
2277 // with logical drives
2278 for (i = 1; i <= cDisks; i++)
2279 if ((arc = GetExtendedPartition(&pPartitionInfos,
2280 &ppiTemp,
2281 &osCount,
2282 &cLetter,
2283 &BmInfo,
2284 i)))
2285 {
2286 *pusContext = 3;
2287 return (arc);
2288 }
2289 }
2290
2291 *ppPartitionInfo = pPartitionInfos;
2292 *pusPartitionCount = osCount;
2293
2294 return (NO_ERROR); // 0
2295}
2296
2297/*
2298 *@@ doshFreePartitionsList:
2299 * this frees the resources allocated by
2300 * doshGetPartitionsList.
2301 *
2302 *@@added V0.9.0 [umoeller]
2303 */
2304
2305APIRET doshFreePartitionsList(PPARTITIONINFO pPartitionInfo)
2306{
2307 PPARTITIONINFO ppiThis = NULL;
2308 ppiThis = pPartitionInfo;
2309 while (ppiThis)
2310 {
2311 PPARTITIONINFO ppiNext = ppiThis->pNext;
2312 free(ppiThis);
2313 ppiThis = ppiNext;
2314 }
2315 return (NO_ERROR);
2316}
2317
2318
Note: See TracBrowser for help on using the repository browser.