home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sysmgmt / setup / win9xmig / pview / miginf.c next >
Encoding:
C/C++ Source or Header  |  1997-08-13  |  17.7 KB  |  756 lines

  1. #include "poolmem.h"
  2. #include "miginf.h"
  3. #include <setupapi.h>
  4.  
  5. #define MIGRATEINF              ".\\migrate.inf"
  6. #define INITIALBUFFERSIZE       1024
  7. #define MIGINF_NOCREATE         FALSE
  8. #define MIGINF_CREATE           TRUE
  9.  
  10.  
  11. typedef struct tagMIGOBJECT MIGOBJECT, *PMIGOBJECT;
  12. struct tagMIGOBJECT {
  13.  
  14.     PSTR        Key;
  15.     PSTR        Value;
  16.     
  17.     PMIGOBJECT  Next;
  18. };
  19.  
  20. typedef struct tagMIGSECTION MIGSECTION, * PMIGSECTION;
  21. struct tagMIGSECTION {
  22.  
  23.     PSTR        Name;
  24.     PMIGOBJECT  Items;
  25.  
  26.     PMIGSECTION Next;
  27. };
  28.  
  29. PMIGSECTION g_MigrationInf;
  30. POOLHANDLE  g_Pool = NULL;
  31.  
  32.  
  33. static
  34. PCSTR
  35. pGetTypeAsString (
  36.     IN MIGTYPE Type
  37.     )
  38. {
  39.     //
  40.     // Note: Strings must be in the same order as the 
  41.     // corresponding types in the MIGTYPE enumeration above.
  42.     //
  43.     static PCHAR typeStrings[] = {
  44.             "FIRST - Invalid",
  45.             "File",
  46.             "Path",
  47.             "Registry",
  48.             "Message - Invalid",
  49.             "LAST - Invalid"
  50.         };
  51.  
  52.     assert(Type > MIG_FIRSTTYPE && Type < MIG_LASTTYPE);
  53.  
  54.     return typeStrings[Type];
  55. }
  56.  
  57. static
  58. PMIGSECTION 
  59. pFindSection (
  60.     IN PCSTR SectionString,
  61.     IN BOOL  CreateIfNotExist
  62.     )
  63. {
  64.     PMIGSECTION rSection;
  65.  
  66.     //
  67.     // We assume that SectionString is not null.
  68.     //
  69.     assert(SectionString);
  70.  
  71.     rSection = g_MigrationInf;
  72.  
  73.     while (rSection && (_mbsicmp(rSection -> Name,SectionString) != 0)) {
  74.  
  75.         //
  76.         // Continue looking.
  77.         //
  78.         rSection = rSection -> Next;
  79.     }
  80.         
  81.     if (!rSection && CreateIfNotExist) {
  82.         //
  83.         // No section was found matching this name. Make a new section and add it 
  84.         // to the list.
  85.         //
  86.         rSection = PoolMemGetMemory(g_Pool,sizeof(MIGSECTION));
  87.         if (rSection) {
  88.  
  89.             ZeroMemory(rSection,sizeof(MIGSECTION));
  90.             rSection -> Name  = PoolMemDuplicateStringA(g_Pool,SectionString);
  91.             rSection -> Next  = g_MigrationInf;
  92.             g_MigrationInf    = rSection;
  93.  
  94.             if (!rSection -> Name) {
  95.                 //
  96.                 // Something went wrong when we tried to duplicate the SectionString.
  97.                 // NULL out the rSection so that the caller doesn't get back a 
  98.                 // malformed section object.
  99.                 //
  100.                 rSection = NULL;
  101.             }
  102.         }
  103.     }
  104.  
  105.     return rSection;
  106. }
  107.  
  108. static
  109. BOOL
  110. pPathIsInPath(
  111.     IN PCSTR    SubPath,
  112.     IN PCSTR    ParentPath
  113.     )
  114. {
  115.     DWORD parentLength;
  116.     BOOL  rInPath;
  117.  
  118.     //
  119.     // This function assumes both parameters are non-NULL.
  120.     //
  121.     assert(SubPath);
  122.     assert(ParentPath);
  123.     
  124.     parentLength = _mbslen(ParentPath);
  125.  
  126.     //
  127.     // A path is considered "in" another path if the path is in the ParentPath
  128.     // or a subdirectory of it.
  129.     //
  130.     rInPath = !_mbsnicmp(SubPath,ParentPath,parentLength);
  131.  
  132.     if (rInPath) {
  133.         rInPath = SubPath[parentLength] == 0 || SubPath[parentLength] == '\\';
  134.     }
  135.  
  136.     return rInPath;
  137.  
  138. }
  139.  
  140. static
  141. DWORD
  142. pGetMbsSize (
  143.     IN  LPCSTR  String
  144.     )
  145. {
  146.     DWORD rLength;
  147.     
  148.     rLength = (DWORD) _mbschr(String,0) - (DWORD) String + 1;
  149.  
  150.     return rLength;
  151.  
  152. }
  153.  
  154.  
  155. static
  156. LPSTR 
  157. pEscapeString (
  158.     IN  MIGTYPE Type,
  159.     OUT LPSTR   EscapedString, 
  160.     IN  LPCSTR  String
  161.     )
  162.  
  163. {
  164.     LPSTR   stringStart;
  165.     static  CHAR exclusions[] = "[]~,;%\"";
  166.     INT     currentChar;
  167.  
  168.     //
  169.     // We assume that all parameters are valid.
  170.     //
  171.     assert(EscapedString && String);
  172.  
  173.     stringStart = EscapedString;
  174.  
  175.     while (*String)  {
  176.         currentChar = _mbsnextc (String);
  177.         
  178.         if (Type == MIG_REGKEY) {
  179.             
  180.             //
  181.             // Registry keys require more complex escaping than do normal INF strings.
  182.             //
  183.             if (!_ismbcprint (currentChar) || _mbschr (exclusions, currentChar)) {
  184.                 
  185.                 //
  186.                 // Escape unprintable or excluded character
  187.                 //
  188.                 wsprintfA (EscapedString, "~%X~", currentChar);
  189.                 EscapedString = _mbschr (EscapedString, 0);
  190.                 String = _mbsinc (String);
  191.             }
  192.             else {
  193.                 //
  194.                 // Copy multibyte character
  195.                 //
  196.                 if (isleadbyte (*String)) {
  197.                     *EscapedString = *String;
  198.                     EscapedString++;
  199.                     String++;
  200.                 }
  201.                 
  202.                 *EscapedString = *String;
  203.                 EscapedString++;
  204.                 String++;
  205.             }
  206.         }
  207.         else {
  208.  
  209.             //
  210.             // Escaping is pretty simple for non-registry keys. All we do is double up
  211.             // quotes and percents.
  212.             //
  213.             if (*String == '\"' || *String == '%') {
  214.  
  215.                 *EscapedString = *String;
  216.                 EscapedString++;
  217.             }
  218.             
  219.             //
  220.             // Copy multibyte character
  221.             //
  222.             if (isleadbyte (*String)) {
  223.                 *EscapedString = *String;
  224.                 EscapedString++;
  225.                 String++;
  226.             }
  227.             
  228.             *EscapedString = *String;
  229.             EscapedString++;
  230.             String++;
  231.         }
  232.     }
  233.  
  234.     //
  235.     // Ensure that returned string is NULL terminated.
  236.     //
  237.     *EscapedString = 0;
  238.  
  239.     return stringStart;
  240. }
  241.  
  242.  
  243. static
  244. PSTR
  245. pGetValueString (
  246.     IN MIGTYPE    ObjectType,
  247.     IN LPCSTR     StringOne,
  248.     IN LPCSTR     StringTwo
  249.     )
  250. {
  251.     static PSTR     buffer;
  252.     static DWORD    bufferSize;
  253.     DWORD           maxLength;
  254.     PSTR            bufferEnd;
  255.     
  256.     //
  257.     // This function assumes that StringOne exists.
  258.     //
  259.     assert(StringOne);
  260.  
  261.     if (ObjectType == MIG_REGKEY) {
  262.         //
  263.         // Size: size of both strings, plus the size of the quotes, plus the size of the brackets 
  264.         // for the value, * 6. This is the maximum size one of these could grow to, if every 
  265.         // character had to be escaped out.
  266.         //
  267.         maxLength = (pGetMbsSize(StringOne) + (StringTwo ? pGetMbsSize(StringTwo) + 2 : 0)) * 6 + 2;
  268.     }
  269.     else {
  270.         //
  271.         // Size: size of the string * 2 (The max size if every char was a '%' or '"' plus the quotes.
  272.         //
  273.         maxLength = pGetMbsSize(StringOne) * 2 + 2;
  274.     }
  275.  
  276.     if (maxLength > bufferSize) {
  277.  
  278.         //
  279.         // Initialize our buffer, or create a larger one.
  280.         //
  281.         bufferSize = (maxLength > INITIALBUFFERSIZE) ? maxLength : INITIALBUFFERSIZE;
  282.         buffer = PoolMemCreateStringA(g_Pool,bufferSize);
  283.     }
  284.  
  285.     if (buffer != NULL) {
  286.         
  287.         //
  288.         // Insert initial quote.
  289.         //
  290.         *buffer = '"';
  291.  
  292.         //
  293.         // Massage the string to ensure it is a valid INF file string.
  294.         //
  295.         pEscapeString(ObjectType,_mbsinc(buffer),StringOne);
  296.  
  297.         //
  298.         // If this is a REGISTRY entry, then we also need to add the value part of the string, 
  299.         // if one was specified (In StringTwo)
  300.         //
  301.  
  302.         if (ObjectType == MIG_REGKEY && StringTwo) {
  303.  
  304.             //
  305.             // Add the opening bracket.
  306.             //
  307.             bufferEnd = _mbschr(buffer,0);
  308.             *bufferEnd = '[';
  309.             
  310.             //
  311.             // Add the value string in, again making sure the string is valid for an INF file.
  312.             //
  313.             pEscapeString(ObjectType,_mbsinc(bufferEnd),StringTwo);
  314.  
  315.             //
  316.             // Now, add the closing braket.
  317.             //
  318.             bufferEnd = _mbschr(buffer,0);
  319.             *bufferEnd = ']';
  320.  
  321.             //
  322.             // Terminate the string.
  323.             //
  324.             bufferEnd = _mbsinc(bufferEnd);
  325.             *bufferEnd = 0;
  326.         }
  327.  
  328.         //
  329.         // Add the final quote.
  330.         //
  331.         bufferEnd = _mbschr(buffer,0);
  332.         *bufferEnd = '"';
  333.         bufferEnd = _mbsinc(bufferEnd);
  334.         *bufferEnd = 0;
  335.     }
  336.     
  337.     return buffer;
  338. }
  339.  
  340. static
  341. BOOL
  342. pCreateMigObject (
  343.     IN MIGTYPE          ObjectType,
  344.     IN PCSTR            ParamOne,
  345.     IN PCSTR            ParamTwo,
  346.     IN PMIGSECTION      Section
  347.     )
  348. {
  349.     BOOL            rSuccess;
  350.     PMIGOBJECT      newObject = NULL;
  351.  
  352.     //
  353.     // pCreateMigObject uses a set of hueristics to correctly assemble an object. 
  354.     // These hueristics are based on the ObjectType and the contents of ParamTwo.
  355.     // 
  356.     // ObjectType       ParamTwo      Key                   Value
  357.     // -------------------------------------------------------------------------
  358.     // MIG_REGKEY       <any>         ParamOne[ParamTwo]    Registry
  359.     // <other>          NULL          ParamOne              <ObjectType As String>
  360.     // <other>          non-NULL      ParamOne              ParamTwo
  361.     //
  362.     //
  363.  
  364.  
  365.     if (Section) {
  366.  
  367.         //
  368.         // First, create an object...
  369.         //
  370.         newObject = PoolMemGetMemory(g_Pool,sizeof(MIGOBJECT));
  371.  
  372.         if (newObject) {
  373.  
  374.             if (ObjectType == MIG_REGKEY) {
  375.  
  376.                 newObject -> Key = 
  377.                     PoolMemDuplicateStringA(g_Pool,pGetValueString(ObjectType,ParamOne,ParamTwo));
  378.  
  379.                 newObject -> Value = PoolMemDuplicateStringA(g_Pool,pGetTypeAsString(ObjectType));
  380.             }
  381.             else {
  382.                 
  383.                 newObject -> Key = 
  384.                     PoolMemDuplicateStringA(g_Pool,pGetValueString(ObjectType,ParamOne,NULL));
  385.  
  386.                 if (ParamTwo) {
  387.                     newObject -> Value =
  388.                         PoolMemDuplicateStringA(g_Pool,pGetValueString(ObjectType,ParamTwo,NULL));
  389.                 }
  390.                 else {
  391.  
  392.                     newObject -> Value = 
  393.                         PoolMemDuplicateStringA(g_Pool,pGetTypeAsString(ObjectType));
  394.                 }
  395.             }
  396.         }
  397.     }
  398.  
  399.  
  400.     if (newObject && newObject -> Key && newObject -> Value) {
  401.  
  402.         //
  403.         // The object has been successfully created. Link it into the section.
  404.         //
  405.         newObject -> Next = Section -> Items;
  406.         Section -> Items = newObject;
  407.         rSuccess = TRUE;
  408.     }
  409.     else {
  410.         rSuccess = FALSE;
  411.     }
  412.  
  413.     return newObject && newObject -> Key && newObject -> Value;
  414. }
  415.  
  416.  
  417. static
  418. BOOL
  419. pWriteInfSectionToDisk (
  420.     IN PMIGSECTION Section
  421.     )
  422. {
  423.     PMIGOBJECT curObject;
  424.     BOOL       rSuccess = TRUE;
  425.  
  426.     if (Section) {
  427.  
  428.         curObject = Section -> Items;
  429.  
  430.         while (curObject && rSuccess) {
  431.  
  432.             if (Section -> Name && curObject -> Key && curObject -> Value) {
  433.             
  434.                 rSuccess = WritePrivateProfileString(
  435.                     Section   -> Name,
  436.                     curObject -> Key, 
  437.                     curObject -> Value,
  438.                     MIGRATEINF
  439.                     );
  440.             }
  441.  
  442.             curObject = curObject -> Next;
  443.         }
  444.     }
  445.     else {
  446.         rSuccess = FALSE;
  447.     }
  448.  
  449.     return rSuccess;
  450. }
  451.  
  452.  
  453. static
  454. BOOL
  455. pBuildListFromSection (
  456.     IN PCSTR    SectionString
  457.     )
  458. {
  459.     HINF            infHandle;
  460.     PMIGSECTION     section;
  461.     PMIGOBJECT      currentObject;
  462.     INFCONTEXT      ic;
  463.     DWORD           size;
  464.     BOOL            rSuccess = TRUE;
  465.  
  466.     //
  467.     // This function assumes that Section is non-NULL.
  468.     //
  469.     assert(SectionString);
  470.  
  471.     currentObject = NULL;
  472.     
  473.     //
  474.     // First find the section specified.
  475.     //
  476.     section = pFindSection(SectionString,MIGINF_CREATE);
  477.  
  478.     if (section) {
  479.         
  480.         infHandle = SetupOpenInfFileA(MIGRATEINF,NULL,INF_STYLE_WIN4,NULL);
  481.         
  482.         if (infHandle != INVALID_HANDLE_VALUE) {
  483.             
  484.             if (SetupFindFirstLine(infHandle,SectionString,NULL,&ic)) {
  485.                 
  486.                 do {
  487.  
  488.                     //
  489.                     // Create the object.
  490.                     //
  491.                     currentObject = (PMIGOBJECT) PoolMemGetMemory(g_Pool,sizeof(MIGOBJECT));
  492.                     
  493.                     if (!currentObject) {
  494.                         rSuccess = FALSE;
  495.                         break;
  496.                     }
  497.                     
  498.                     //
  499.                     // Get the size of the string.
  500.                     //
  501.                     if (!SetupGetLineTextA(&ic,NULL,NULL,NULL,NULL,0,&size)) {
  502.                         rSuccess = FALSE;
  503.                         break;
  504.                     }
  505.                     
  506.                     //
  507.                     // Create a string large enough.
  508.                     //
  509.                     currentObject -> Key = PoolMemCreateStringA(g_Pool,size);
  510.                     
  511.                     if (!currentObject -> Key) {
  512.                         rSuccess = FALSE;
  513.                         break;
  514.                     }
  515.                     
  516.                     //
  517.                     // Get the string.
  518.                     //
  519.                     if (!SetupGetLineTextA(&ic,NULL,NULL,NULL,currentObject -> Key,size,NULL)) {
  520.                         rSuccess = FALSE;
  521.                         break;
  522.                     }
  523.                     
  524.                     //
  525.                     // Successfully retrieved the line.
  526.                     //
  527.                     currentObject -> Value  = (PSTR) pGetTypeAsString(MIG_FILE);
  528.                     currentObject -> Next   = section -> Items;
  529.                     section -> Items        = currentObject;
  530.                     
  531.                 } while(SetupFindNextLine(&ic,&ic));
  532.                 
  533.             }
  534.             
  535.             SetupCloseInfFile(infHandle);
  536.         }
  537.     }
  538.     else {
  539.         rSuccess = FALSE;
  540.     }
  541.  
  542.     return rSuccess;
  543. }
  544.  
  545.  
  546. BOOL
  547. MigInf_Initialize(
  548.     VOID
  549.     )
  550. {
  551.  
  552.     //
  553.     // First, initialize our pool and Zero out the structure.
  554.     //
  555.     g_Pool = PoolMemInitPool();
  556.  
  557.  
  558.     if (g_Pool) {
  559.         
  560.         //
  561.         // Now, read in the migration paths and excluded paths sections.
  562.         //
  563.         if (!pBuildListFromSection(SECTION_MIGRATIONPATHS) ||
  564.             !pBuildListFromSection(SECTION_EXCLUDEDPATHS)) {
  565.             //
  566.             // Something went wrong (i.e. out of memory. Destroy and NULL our pool.
  567.             //
  568.             PoolMemDestroyPool(g_Pool);
  569.             g_Pool = NULL;
  570.         }
  571.     }
  572.  
  573.     //
  574.     // If our memory pool initialized successfully, return TRUE.
  575.     //
  576.     return (g_Pool != NULL);
  577.  
  578. }
  579.  
  580.  
  581. VOID
  582. MigInf_CleanUp (
  583.     VOID
  584.     )
  585. {
  586.     //
  587.     // Only thing we need to do is clean out pool mem. We'll NULL out the list header to make
  588.     // sure it isn't usable.
  589.     //
  590.     if (g_Pool) {
  591.         PoolMemDestroyPool(g_Pool);
  592.         g_Pool = NULL;
  593.     }
  594.     
  595.     g_MigrationInf = NULL;
  596.  
  597. }
  598.  
  599.  
  600. BOOL
  601. MigInf_AddObject (
  602.     IN MIGTYPE  ObjectType,
  603.     IN PCSTR    SectionString,
  604.     IN PCSTR    ParamOne,
  605.     IN PCSTR    ParamTwo
  606.     )
  607. {
  608.  
  609.     return pCreateMigObject(
  610.         ObjectType,
  611.         ParamOne,
  612.         ParamTwo,
  613.         pFindSection(SectionString,MIGINF_CREATE)
  614.         );
  615. }
  616.  
  617. BOOL 
  618.  
  619. MigInf_FirstInSection(
  620.     IN PCSTR SectionName, 
  621.     OUT PMIGINFSECTIONENUM Enum
  622.     )
  623. {
  624.     PMIGSECTION section;
  625.  
  626.     //
  627.     // We assume that Enum is valid.
  628.     //
  629.     assert(Enum);
  630.  
  631.     section = pFindSection(SectionName,MIGINF_NOCREATE);
  632.  
  633.     if (section) {
  634.         Enum -> EnumKey = (PVOID) section -> Items;
  635.     }
  636.  
  637.     return MigInf_NextInSection(Enum);
  638. }
  639.  
  640. BOOL 
  641. MigInf_NextInSection(
  642.     IN OUT PMIGINFSECTIONENUM Enum
  643.     )
  644. {
  645.  
  646.  
  647.     BOOL            rSuccess = FALSE;
  648.  
  649.     //
  650.     // We assume that the Enum is valid.
  651.     //
  652.     assert(Enum);
  653.  
  654.     if (Enum -> EnumKey) {
  655.  
  656.         Enum -> Key     = ((PMIGOBJECT) (Enum -> EnumKey)) -> Key;
  657.         Enum -> Value   = ((PMIGOBJECT) (Enum -> EnumKey)) -> Value;
  658.         Enum -> EnumKey = ((PVOID) ((PMIGOBJECT) (Enum -> EnumKey)) -> Next);
  659.         rSuccess = TRUE;
  660.     }
  661.  
  662.     return rSuccess;
  663. }
  664.  
  665.  
  666. BOOL
  667. MigInf_WriteInfToDisk (
  668.     VOID
  669.     )
  670. {
  671.  
  672.     BOOL        rSuccess = TRUE;
  673.     PMIGSECTION curSection;
  674.     
  675.     //
  676.     // Simply loop through all of the sections, writing each of them to disk.
  677.     // As long as WriteSectionToDisk works, we work.
  678.     //
  679.     curSection = g_MigrationInf;
  680.  
  681.     while (curSection && rSuccess) {
  682.  
  683.         //
  684.         // We skip the [Excluded Paths] and [Migration Paths] sections.
  685.         //
  686.         if (_mbsicmp(curSection -> Name,SECTION_EXCLUDEDPATHS) &&
  687.             _mbsicmp(curSection -> Name,SECTION_MIGRATIONPATHS)) {
  688.             
  689.             rSuccess = pWriteInfSectionToDisk(curSection);
  690.         } 
  691.  
  692.         curSection = curSection -> Next;
  693.         
  694.     }
  695.  
  696.     return rSuccess;
  697. }
  698.  
  699. BOOL
  700. MigInf_PathIsExcluded (
  701.     IN PCSTR    Path
  702.     )
  703. {
  704.     PMIGOBJECT  curExcluded;
  705.     PMIGSECTION section;
  706.     BOOL        rIsExcluded = FALSE;
  707.  
  708.     //
  709.     // We assume Path is valid.
  710.     //
  711.     assert(Path);
  712.     
  713.     section = pFindSection(SECTION_EXCLUDEDPATHS,MIGINF_NOCREATE);
  714.  
  715.     if (section) {
  716.  
  717.         curExcluded = section -> Items;
  718.         
  719.         while (curExcluded && !rIsExcluded) {
  720.             
  721.             rIsExcluded = pPathIsInPath(Path,curExcluded -> Key);
  722.             curExcluded = curExcluded -> Next;
  723.         }
  724.     }
  725.     
  726.     return rIsExcluded;
  727. }
  728.  
  729.  
  730.  
  731.  
  732. BOOL 
  733. MigInf_UseSpace (
  734.     IN PCSTR DriveRoot,
  735.     IN LONGLONG Space
  736.     ) 
  737. {
  738.  
  739.     BOOL rSuccess;
  740.     PMIGSECTION section;
  741.     static CHAR spaceString[MAX_PATH];
  742.  
  743.     section = pFindSection(SECTION_DISKSPACEUSED,MIGINF_CREATE);
  744.  
  745.     if (section) {
  746.  
  747.         sprintf(spaceString,"%I64u",Space);
  748.         rSuccess = pCreateMigObject (MIG_FILE,DriveRoot,spaceString,section);
  749.     }
  750.     else {
  751.         rSuccess = FALSE;
  752.     }
  753.  
  754.     return rSuccess;
  755. }
  756.