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

Last change on this file since 17 was 17, checked in by umoeller, 25 years ago

Miscellanous updates.

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