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

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

misc. changes.

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