home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / wphandle.c < prev    next >
C/C++ Source or Header  |  2002-08-05  |  37KB  |  1,112 lines

  1.  
  2. /*
  3.  *@@sourcefile wphandle.c:
  4.  *      this file contains the logic for dealing with
  5.  *      those annoying WPS object handles in OS2SYS.INI.
  6.  *      This does not use WPS interfaces, but parses
  7.  *      the profiles directly.
  8.  *
  9.  *      Usage: All OS/2 programs.
  10.  *
  11.  *      Function prefixes (new with V0.81):
  12.  *      --  wph*   WPS object helper functions
  13.  *
  14.  *      Thanks go out to Henk Kelder for telling me the
  15.  *      format of the WPS INI data. With V0.9.16, this
  16.  *      file was completely rewritten and no longer uses
  17.  *      his code though.
  18.  *
  19.  *      Note: Version numbering in this file relates to XWorkplace version
  20.  *            numbering.
  21.  *
  22.  *@@header "helpers\wphandle.h"
  23.  */
  24.  
  25. /*
  26.  *      This file Copyright (C) 1997-2001 Ulrich Möller,
  27.  *      This file is part of the "XWorkplace helpers" source package.
  28.  *      This is free software; you can redistribute it and/or modify
  29.  *      it under the terms of the GNU General Public License as published
  30.  *      by the Free Software Foundation, in version 2 as it comes in the
  31.  *      "COPYING" file of the XWorkplace main distribution.
  32.  *      This program is distributed in the hope that it will be useful,
  33.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  34.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  35.  *      GNU General Public License for more details.
  36.  */
  37.  
  38. #define OS2EMX_PLAIN_CHAR
  39.     // this is needed for "os2emx.h"; if this is defined,
  40.     // emx will define PSZ as _signed_ char, otherwise
  41.     // as unsigned char
  42.  
  43. #define INCL_DOSEXCEPTIONS
  44. #define INCL_DOSPROCESS
  45. #define INCL_DOSERRORS
  46.  
  47. #define INCL_WINSHELLDATA
  48. #define INCL_WINNLS
  49. #include <os2.h>
  50.  
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include <stdlib.h>
  54. #include <io.h>
  55. #include <setjmp.h>
  56.  
  57. #include "setup.h"                      // code generation and debugging options
  58.  
  59. #include "helpers\except.h"
  60. #include "helpers\linklist.h"
  61. #include "helpers\prfh.h"
  62. #include "helpers\standards.h"
  63. #include "helpers\stringh.h"
  64. #include "helpers\tree.h"
  65. #include "helpers\xstring.h"
  66.  
  67. #define INCLUDE_WPHANDLE_PRIVATE
  68. #include "helpers\wphandle.h"
  69.  
  70. /*
  71.  *@@category: Helpers\PM helpers\Workplace Shell\Handles (OS2SYS.INI)
  72.  *      See wphandle.c.
  73.  */
  74.  
  75. /* ******************************************************************
  76.  *
  77.  *   Load handles functions
  78.  *
  79.  ********************************************************************/
  80.  
  81. /*
  82.  *@@ wphQueryActiveHandles:
  83.  *      returns the value of PM_Workplace:ActiveHandles
  84.  *      in OS2SYS.INI as a new buffer.
  85.  *
  86.  *      There are always two buffers in OS2SYS.INI for object
  87.  *      handles, called "PM_Workplace:HandlesX" with "X" either
  88.  *      being "0" or "1".
  89.  *
  90.  *      It seems that every time the WPS does something in the
  91.  *      handles section, it writes the data to the inactive
  92.  *      buffer first and then makes it the active buffer by
  93.  *      changing the "active handles" key. You can test this
  94.  *      by creating a shadow on your Desktop.
  95.  *
  96.  *      This returns a new PSZ which the caller must free()
  97.  *      after use.
  98.  *
  99.  *      This gets called by the one-shot function
  100.  *      wphQueryHandleFromPath.
  101.  *
  102.  *@@changed V0.9.16 (2001-10-02) [umoeller]: rewritten
  103.  */
  104.  
  105. APIRET wphQueryActiveHandles(HINI hiniSystem,
  106.                              PSZ *ppszActiveHandles)        // out: active handles string (new buffer)
  107. {
  108.     PSZ pszActiveHandles;
  109.     if (pszActiveHandles = prfhQueryProfileData(hiniSystem,
  110.                                                 WPINIAPP_ACTIVEHANDLES,
  111.                                                 WPINIAPP_HANDLESAPP,
  112.                                                 NULL))
  113.     {
  114.         *ppszActiveHandles = pszActiveHandles;
  115.         return NO_ERROR;
  116.     }
  117.  
  118.     return ERROR_WPH_NO_ACTIVEHANDLES_DATA;
  119. }
  120.  
  121. /*
  122.  *@@ wphQueryBaseClassesHiwords:
  123.  *      returns the hiwords for the WPS base
  124.  *      classes. Unless the user's system is
  125.  *      really badly configured, this should
  126.  *      set
  127.  *
  128.  *      --  pusHiwordAbstract to 2;
  129.  *      --  pusHiwordFileSystem to 3.
  130.  *
  131.  *      Returns:
  132.  *
  133.  *      --  NO_ERROR
  134.  *
  135.  *      --  ERROR_WPH_NO_BASECLASS_DATA
  136.  *
  137.  *      --  ERROR_WPH_INCOMPLETE_BASECLASS_DATA
  138.  *
  139.  *      This gets called automatically from wphLoadHandles.
  140.  *
  141.  *@@added V0.9.16 (2001-10-02) [umoeller]
  142.  */
  143.  
  144. APIRET wphQueryBaseClassesHiwords(HINI hiniUser,
  145.                                   PUSHORT pusHiwordAbstract,
  146.                                   PUSHORT pusHiwordFileSystem)
  147. {
  148.     APIRET arc = NO_ERROR;
  149.  
  150.     // get the index of WPFileSystem from the base classes list...
  151.     // we need this to determine the hiword for file-system handles
  152.     // properly. Normally, this should be 3.
  153.     ULONG cbBaseClasses = 0;
  154.     PSZ pszBaseClasses;
  155.     if (pszBaseClasses = prfhQueryProfileData(hiniUser,
  156.                                               "PM_Workplace:BaseClass",
  157.                                               "ClassList",
  158.                                               &cbBaseClasses))
  159.     {
  160.         // parse that buffer... these has the base class names,
  161.         // separated by 0. List is terminated by two zeroes.
  162.         PSZ     pszClassThis = pszBaseClasses;
  163.         ULONG   ulHiwordThis = 1;
  164.         while (    (*pszClassThis)
  165.                 && (pszClassThis - pszBaseClasses < cbBaseClasses)
  166.               )
  167.         {
  168.             if (!strcmp(pszClassThis, "WPFileSystem"))
  169.                 *pusHiwordFileSystem = ulHiwordThis;
  170.             else if (!strcmp(pszClassThis, "WPAbstract"))
  171.                 *pusHiwordAbstract = ulHiwordThis;
  172.  
  173.             ulHiwordThis++;
  174.             pszClassThis += strlen(pszClassThis) + 1;
  175.         }
  176.  
  177.         // now check if we found both
  178.         if (    (!(*pusHiwordFileSystem))
  179.              || (!(*pusHiwordAbstract))
  180.            )
  181.             arc = ERROR_WPH_INCOMPLETE_BASECLASS_DATA;
  182.  
  183.         free(pszBaseClasses);
  184.     }
  185.     else
  186.         arc = ERROR_WPH_NO_BASECLASS_DATA;
  187.  
  188.     return arc;
  189. }
  190.  
  191. /*
  192.  *@@ FreeChildrenTree:
  193.  *      called from NukeNameTrees for recursion.
  194.  *
  195.  *@@added V0.9.16 (2001-10-19) [umoeller]
  196.  */
  197.  
  198. static VOID FreeChildrenTree(TREE **ppChildrenTree,
  199.                              PLONG plCount)
  200. {
  201.     LONG    cItems = *plCount;
  202.     TREE**  papNodes = treeBuildArray(*ppChildrenTree,
  203.                                       &cItems);
  204.     if (papNodes)
  205.     {
  206.         ULONG ul;
  207.         for (ul = 0; ul < cItems; ul++)
  208.         {
  209.             PNODETREENODE pNodeThis = (PNODETREENODE)papNodes[ul];
  210.  
  211.             FreeChildrenTree(&pNodeThis->ChildrenTree,
  212.                              &pNodeThis->cChildren);
  213.  
  214.             free(pNodeThis);
  215.         }
  216.  
  217.         free(papNodes);
  218.         *plCount = 0;
  219.  
  220.         treeInit(ppChildrenTree, plCount);
  221.     }
  222. }
  223.  
  224. /*
  225.  *@@ NukeNameTrees:
  226.  *      frees all cache trees.
  227.  *
  228.  *@@added V0.9.16 (2001-10-19) [umoeller]
  229.  */
  230.  
  231. static APIRET NukeNameTrees(PHANDLESBUF pHandlesBuf)
  232. {
  233.     APIRET arc = NO_ERROR;
  234.  
  235.     LONG    cItems = pHandlesBuf->cDrives;
  236.     TREE**  papNodes = treeBuildArray(pHandlesBuf->DrivesTree,
  237.                                       &cItems);
  238.     if (papNodes)
  239.     {
  240.         ULONG ul;
  241.         for (ul = 0; ul < cItems; ul++)
  242.         {
  243.             PDRIVETREENODE pNodeThis = (PDRIVETREENODE)papNodes[ul];
  244.  
  245.             FreeChildrenTree(&pNodeThis->ChildrenTree,
  246.                              &pNodeThis->cChildren);
  247.  
  248.             free(pNodeThis);
  249.         }
  250.  
  251.         free(papNodes);
  252.  
  253.         treeInit(&pHandlesBuf->DrivesTree,
  254.                  &pHandlesBuf->cDrives);
  255.     }
  256.  
  257.     return arc;
  258. }
  259.  
  260. /*
  261.  *@@ wphRebuildNodeHashTable:
  262.  *      builds all the complex cache trees in the
  263.  *      given handles buffer.
  264.  *
  265.  *      If (fQuitOnErrors == TRUE), we'll fail as
  266.  *      soon as an invalid handle is found. Otherwise
  267.  *      we will try to continue if the error is not fatal.
  268.  *
  269.  *      Returns:
  270.  *
  271.  *      --  NO_ERROR
  272.  *
  273.  *      --  ERROR_INVALID_PARAMETER
  274.  *
  275.  *      --  ERROR_WPH_CORRUPT_HANDLES_DATA
  276.  *
  277.  *      --  ERROR_WPH_DRIV_TREEINSERT_FAILED: duplicate DRIV node
  278.  *          (non-fatal)
  279.  *
  280.  *@@added V0.9.16 (2001-10-02) [umoeller]
  281.  *@@changted V0.9.17 (2002-02-05) [umoeller]: added fQuitOnErrors
  282.  */
  283.  
  284. APIRET wphRebuildNodeHashTable(HHANDLES hHandles,
  285.                                BOOL fQuitOnErrors)
  286. {
  287.     APIRET arc = NO_ERROR;
  288.  
  289.     PHANDLESBUF pHandlesBuf;
  290.  
  291.     if (    (!(pHandlesBuf = (PHANDLESBUF)hHandles))
  292.          || (!pHandlesBuf->pbData)
  293.          || (!pHandlesBuf->cbData)
  294.        )
  295.         arc = ERROR_INVALID_PARAMETER;
  296.     else
  297.     {
  298.         // start at beginning of buffer
  299.         PBYTE pCur = pHandlesBuf->pbData + 4;
  300.         PBYTE pEnd = pHandlesBuf->pbData + pHandlesBuf->cbData;
  301.  
  302.         PDRIVETREENODE  pLastDriveTreeNode = NULL;
  303.  
  304.         memset(pHandlesBuf->NodeHashTable, 0, sizeof(pHandlesBuf->NodeHashTable));
  305.         NukeNameTrees(pHandlesBuf);
  306.  
  307.         // now set up hash table
  308.         while (    (pCur < pEnd)
  309.                 && (!arc)
  310.               )
  311.         {
  312.             if (!memicmp(pCur, "DRIV", 4))
  313.             {
  314.                 // pCur points to a DRIVE node:
  315.                 // these never have handles, so skip this
  316.                 PDRIVE pDriv = (PDRIVE)pCur;
  317.  
  318.                 // upper the node name for string comparisons
  319.                 strupr(pDriv->szName);
  320.  
  321.                 // create a drive tree node
  322.                 // (stored so we can append to this)
  323.                 if (!(pLastDriveTreeNode = NEW(DRIVETREENODE)))
  324.                     arc = ERROR_NOT_ENOUGH_MEMORY;
  325.                 else
  326.                 {
  327.                     pLastDriveTreeNode->Tree.ulKey = (ULONG)pDriv->szName;
  328.                     pLastDriveTreeNode->pDriv = pDriv;
  329.                     treeInit(&pLastDriveTreeNode->ChildrenTree,
  330.                              &pLastDriveTreeNode->cChildren);
  331.                     if (treeInsert(&pHandlesBuf->DrivesTree,
  332.                                    &pHandlesBuf->cDrives,
  333.                                    (TREE*)pLastDriveTreeNode,
  334.                                    treeCompareStrings))
  335.                         if (fQuitOnErrors)
  336.                             arc = ERROR_WPH_DRIV_TREEINSERT_FAILED;
  337.                 }
  338.  
  339.                 // next item
  340.                 pCur += sizeof(DRIVE) + strlen(pDriv->szName);
  341.             }
  342.             else if (!memicmp(pCur, "NODE", 4))
  343.             {
  344.                 // pCur points to a regular NODE: offset pointer first
  345.                 PNODE pNode = (PNODE)pCur;
  346.                 PNODETREENODE pNew;
  347.  
  348.                 // upper the node name for string comparisons
  349.                 strupr(pNode->szName);
  350.  
  351.                 // create a node tree node
  352.                 if (!(pNew = NEW(NODETREENODE)))
  353.                     arc = ERROR_NOT_ENOUGH_MEMORY;
  354.                 else
  355.                 {
  356.                     TREE **ppTree = NULL;
  357.                     PLONG pcChildren = NULL;
  358.  
  359.                     pNew->Tree.ulKey = (ULONG)pNode->szName;
  360.                     pNew->pNode = pNode;
  361.                     treeInit(&pNew->ChildrenTree,
  362.                              &pNew->cChildren);
  363.                     // now check where to insert this...
  364.                     // does it have a parent?
  365.                     if (pNode->usParentHandle)
  366.                     {
  367.                         PNODETREENODE pParent;
  368.                         if (!(pParent = pHandlesBuf->NodeHashTable[pNode->usParentHandle]))
  369.                         {
  370.                             // this parent handle is invalid:
  371.                             if (fQuitOnErrors)
  372.                                 arc = ERROR_WPH_INVALID_PARENT_HANDLE;
  373.                         }
  374.                         else
  375.                         {
  376.                             ppTree = &pParent->ChildrenTree;
  377.                             pcChildren = &pParent->cChildren;
  378.                         }
  379.                     }
  380.                     else
  381.                         // null parent handle: then the parent
  382.                         // must be a DRIVE node
  383.                         if (pLastDriveTreeNode)
  384.                         {
  385.                             ppTree = &pLastDriveTreeNode->ChildrenTree;
  386.                             pcChildren = &pLastDriveTreeNode->cChildren;
  387.                         }
  388.                         else
  389.                             if (fQuitOnErrors)
  390.                                 arc = ERROR_WPH_NODE_BEFORE_DRIV;
  391.  
  392.                     if (ppTree && pcChildren)
  393.                         if (!treeInsert(ppTree,
  394.                                         pcChildren,
  395.                                         (TREE*)pNew,
  396.                                         treeCompareStrings))
  397.                         {
  398.                             // store PNODE in hash table
  399.                             pHandlesBuf->NodeHashTable[pNode->usHandle] = pNew;
  400.                             // do not free
  401.                             pNew = NULL;
  402.                         }
  403.                         else
  404.                             ;
  405.                             // @@todo if this fails, there are
  406.                             // several handles for short name!!!
  407.                             // arc = ERROR_WPH_NODE_TREEINSERT_FAILED;
  408.  
  409.                     if (pNew)
  410.                         free(pNew);
  411.  
  412.                 }
  413.  
  414.                 pCur += sizeof(NODE) + pNode->usNameSize;
  415.             }
  416.             else
  417.             {
  418.                 arc = ERROR_WPH_CORRUPT_HANDLES_DATA;
  419.                 break;
  420.             }
  421.         }
  422.     }
  423.  
  424.     if (!arc)
  425.         pHandlesBuf->fCacheValid = TRUE;
  426.  
  427.     return arc;
  428. }
  429.  
  430. /*
  431.  *@@ wphLoadHandles:
  432.  *      returns a HANDLESBUF structure which will hold
  433.  *      all the handles from OS2SYS.INI. In addition,
  434.  *      this calls wphQueryBaseClassesHiwords and puts
  435.  *      the hiwords for WPAbstract and WPFileSystem into
  436.  *      the HANDLESBUF as well.
  437.  *
  438.  *      Prerequisite before using any of the other wph*
  439.  *      functions.
  440.  *
  441.  *      Call wphFreeHandles to free all data allocated
  442.  *      by this function.
  443.  *
  444.  *      Returns:
  445.  *
  446.  *      --  NO_ERROR
  447.  *
  448.  *      --  ERROR_NOT_ENOUGH_MEMORY
  449.  *
  450.  *      --  ERROR_INVALID_PARAMETER
  451.  *
  452.  *      --  ERROR_WPH_NO_HANDLES_DATA: cannot read handle blocks.
  453.  *
  454.  *      --  ERROR_WPH_CORRUPT_HANDLES_DATA: cannot read handle blocks.
  455.  *
  456.  *@@added V0.9.16 (2001-10-02) [umoeller]
  457.  */
  458.  
  459. APIRET wphLoadHandles(HINI hiniUser,      // in: HINI_USER or other INI handle
  460.                       HINI hiniSystem,    // in: HINI_SYSTEM or other INI handle
  461.                       const char *pcszActiveHandles,
  462.                       HHANDLES *phHandles)
  463. {
  464.     APIRET arc = NO_ERROR;
  465.  
  466.     if (!phHandles)
  467.         arc = ERROR_INVALID_PARAMETER;
  468.     else
  469.     {
  470.         PSZ pszKeysList;
  471.         if (!(arc = prfhQueryKeysForApp(hiniSystem,
  472.                                         pcszActiveHandles,
  473.                                         &pszKeysList)))
  474.         {
  475.             PHANDLESBUF pReturn = NULL;
  476.  
  477.             ULONG   ulHighestBlock = 0,
  478.                     ul,
  479.                     cbTotal;
  480.             PBYTE   pbData;
  481.  
  482.             const char *pKey2 = pszKeysList;
  483.             while (*pKey2)
  484.             {
  485.                 if (!memicmp((PVOID)pKey2, "BLOCK", 5))
  486.                 {
  487.                     ULONG ulBlockThis = atoi(pKey2 + 5);
  488.                     if (ulBlockThis > ulHighestBlock)
  489.                         ulHighestBlock = ulBlockThis;
  490.                 }
  491.  
  492.                 pKey2 += strlen(pKey2)+1; // next key
  493.             }
  494.  
  495.             free(pszKeysList);
  496.  
  497.             if (!ulHighestBlock)
  498.                 arc = ERROR_WPH_NO_HANDLES_DATA;
  499.             else
  500.             {
  501.                 // now go read the data
  502.                 // (BLOCK1, BLOCK2, ..., BLOCKn)
  503.                 cbTotal = 0;
  504.                 pbData = NULL;
  505.                 for (ul = 1;
  506.                      ul <= ulHighestBlock;
  507.                      ul++)
  508.                 {
  509.                     ULONG   cbBlockThis;
  510.                     CHAR    szBlockThis[10];
  511.                     sprintf(szBlockThis, "BLOCK%d", ul);
  512.                     if (!PrfQueryProfileSize(hiniSystem,
  513.                                              (PSZ)pcszActiveHandles,
  514.                                              szBlockThis,
  515.                                              &cbBlockThis))
  516.                     {
  517.                         arc = ERROR_WPH_PRFQUERYPROFILESIZE_BLOCK;
  518.                         break;
  519.                     }
  520.                     else
  521.                     {
  522.                         ULONG   cbTotalOld = cbTotal;
  523.                         cbTotal += cbBlockThis;
  524.                         if (!(pbData = (BYTE*)realloc(pbData, cbTotal)))
  525.                                 // on first call, pbData is NULL and this
  526.                                 // behaves like malloc()
  527.                         {
  528.                             arc = ERROR_NOT_ENOUGH_MEMORY;
  529.                             break;
  530.                         }
  531.  
  532.                         if (!PrfQueryProfileData(hiniSystem,
  533.                                                  (PSZ)pcszActiveHandles,
  534.                                                  szBlockThis,
  535.                                                  pbData + cbTotalOld,
  536.                                                  &cbBlockThis))
  537.                         {
  538.                             arc = ERROR_WPH_PRFQUERYPROFILEDATA_BLOCK;
  539.                             break;
  540.                         }
  541.                     }
  542.                 }
  543.             }
  544.  
  545.             if (!arc)
  546.             {
  547.                 // all went OK:
  548.                 if (pReturn = NEW(HANDLESBUF))
  549.                 {
  550.                     ZERO(pReturn);
  551.  
  552.                     treeInit(&pReturn->DrivesTree,
  553.                              &pReturn->cDrives);
  554.  
  555.                     pReturn->pbData = pbData;
  556.                     pReturn->cbData = cbTotal;
  557.  
  558.                     // and load the hiwords too
  559.                     if (!(arc = wphQueryBaseClassesHiwords(hiniUser,
  560.                                                            &pReturn->usHiwordAbstract,
  561.                                                            &pReturn->usHiwordFileSystem)))
  562.                         *phHandles = (HHANDLES)pReturn;
  563.                 }
  564.                 else
  565.                     arc = ERROR_NOT_ENOUGH_MEMORY;
  566.             }
  567.  
  568.             if (arc)
  569.                 // error:
  570.                 wphFreeHandles((HHANDLES*)&pReturn);
  571.         }
  572.     }
  573.  
  574.     return arc;
  575. }
  576.  
  577. /*
  578.  *@@ wphFreeHandles:
  579.  *      frees all data allocated by wphLoadHandles
  580.  *      and sets *ppHandlesBuf to NULL, for safety.
  581.  *
  582.  *@@added V0.9.16 (2001-10-02) [umoeller]
  583.  */
  584.  
  585. APIRET wphFreeHandles(HHANDLES *phHandles)
  586. {
  587.     APIRET arc = NO_ERROR;
  588.  
  589.     PHANDLESBUF pHandlesBuf;
  590.     if (    (phHandles)
  591.          && (pHandlesBuf = (PHANDLESBUF)*phHandles)
  592.        )
  593.     {
  594.         PBYTE pbData;
  595.  
  596.         NukeNameTrees(pHandlesBuf);
  597.  
  598.         if (pbData = pHandlesBuf->pbData)
  599.             free(pbData);
  600.  
  601.         free(pHandlesBuf);
  602.         *phHandles = NULLHANDLE;
  603.     }
  604.     else
  605.         arc = ERROR_INVALID_PARAMETER;
  606.  
  607.     return arc;
  608. }
  609.  
  610. /* ******************************************************************
  611.  *
  612.  *   Get HOBJECT from filename
  613.  *
  614.  ********************************************************************/
  615.  
  616. /*
  617.  *@@ wphSearchBufferForHandle:
  618.  *      returns the 16-bit file-system handle which corresponds
  619.  *      to pszFilename, searching pHandlesBuffer. Note that you
  620.  *      must OR the return value with the proper hiword to make
  621.  *      this a valid WPS file-system handle.
  622.  *
  623.  *      You must pass a handles buffer to this function which
  624.  *      has been filled using wphReadAllBlocks above.
  625.  *
  626.  *      This gets called by the one-shot function
  627.  *      wphQueryHandleFromPath.
  628.  *
  629.  *      Returns:
  630.  *
  631.  *      --  NO_ERROR
  632.  *
  633.  *      --  ERROR_INVALID_PARAMETER
  634.  *
  635.  *      --  ERROR_FILE_NOT_FOUND
  636.  *
  637.  *      --  ERROR_INVALID_NAME
  638.  *
  639.  *      --  ERROR_WPH_CORRUPT_HANDLES_DATA
  640.  *
  641.  *      --  ERROR_WPH_CANNOT_FIND_HANDLE: no handle exists for the
  642.  *          given filename.
  643.  *
  644.  *@@changed V0.9.16 (2001-10-19) [umoeller]: rewritten
  645.  */
  646.  
  647. APIRET wphSearchBufferForHandle(HHANDLES hHandles,
  648.                                 PCSZ pcszFile,  // in: fully qlf'd filename to search for
  649.                                 PUSHORT pusHandle)  // out: 16-bit handle
  650. {
  651.     APIRET arc = NO_ERROR;
  652.  
  653.     PHANDLESBUF pHandlesBuf;
  654.  
  655.     _Pmpf((__FUNCTION__ ": entering"));
  656.  
  657.     if (    (hHandles)
  658.          && (pHandlesBuf = (PHANDLESBUF)hHandles)
  659.        )
  660.     {
  661.         // rebuild cache
  662.         if (!pHandlesBuf->fCacheValid)
  663.             arc = wphRebuildNodeHashTable(hHandles,
  664.                                           TRUE);        // fail on errors
  665.  
  666.         if (!arc)
  667.         {
  668.             // We can thus work our way through the buffer by splitting the
  669.             // fully qualified filename that we're searching for into the
  670.             // different directory names and, each time, searching for the
  671.             // corresponding NODE. If we have found that, we go for the next.
  672.             // Example for C:\OS2\E.EXE:
  673.             //   1) first search for the "C:" NODE
  674.             //   2) then find the "OS2" node which has "C" as its parent NODE
  675.             //      (we do this by comparing the parent object handles)
  676.             //   3) then find the "E.EXE" NODE the same way
  677.             // The "E.EXE" NODE then has the object handle we're looking for.
  678.  
  679.             // make a copy of the filename so we can play
  680.             PSZ     pszFilename = strdup(pcszFile),
  681.                     pEnd = NULL;
  682.  
  683.             strupr(pszFilename);
  684.  
  685.             // 1) OK, find the drive.
  686.  
  687.             // If this is an UNC name, the DRIVE node has the form
  688.             // \\SERVER\RESOURCE.
  689.             if (    (*pszFilename == '\\')
  690.                  && (*(pszFilename + 1) == '\\')
  691.                )
  692.             {
  693.                 // UNC:
  694.                 // @@todo
  695.             }
  696.             else if (*(pszFilename + 1) == ':')
  697.                 // extract the drive then (without \)
  698.                 pEnd = pszFilename + 2;
  699.  
  700.             if (!pEnd)
  701.                 arc = ERROR_INVALID_NAME;
  702.             else
  703.             {
  704.                 PDRIVETREENODE pDrive = NULL;
  705.                 PNODETREENODE pNode;
  706.  
  707.                 // find the DRIVE node
  708.                 CHAR cOld = *pEnd;
  709.                 *pEnd = 0;
  710.  
  711.                 _Pmpf(("  searching for drive \"%s\"", pszFilename));
  712.  
  713.                 if (!(pDrive = (PDRIVETREENODE)treeFind(pHandlesBuf->DrivesTree,
  714.                                                         (ULONG)pszFilename,   // drive name
  715.                                                         treeCompareStrings)))
  716.                     arc = ERROR_WPH_NO_MATCHING_DRIVE_BLOCK;
  717.                 // find the root dir, which has the same name
  718.                 else if (!(pNode = (PNODETREENODE)treeFind(pDrive->ChildrenTree,
  719.                                                            (ULONG)pszFilename,
  720.                                                            treeCompareStrings)))
  721.                     arc = ERROR_WPH_NO_MATCHING_ROOT_DIR;
  722.                 else
  723.                 {
  724.                     // now we got the root dir... go for next path component
  725.                     while (    (pEnd)
  726.                             && (*pEnd = cOld)       // not null char
  727.                             && (!arc)
  728.                           )
  729.                     {
  730.                         // got another path component to search:
  731.                         PSZ pCurrent = pEnd + 1,
  732.                             pNext;
  733.  
  734.                         if (pNext = strchr(pCurrent, '\\'))
  735.                         {
  736.                             cOld = *pNext;
  737.                             *pNext = 0;
  738.                         }
  739.                         else
  740.                             // done:
  741.                             cOld = 0;
  742.  
  743.                         _Pmpf(("  searching for node \"%s\"", pCurrent));
  744.  
  745.                         // find the next node
  746.                         if (!(pNode = (PNODETREENODE)treeFind(pNode->ChildrenTree,
  747.                                                               (ULONG)pCurrent,
  748.                                                               treeCompareStrings)))
  749.                             arc = ERROR_WPH_CANNOT_FIND_HANDLE;
  750.  
  751.                         pEnd = pNext;
  752.                     }
  753.  
  754.                     if (!arc && pNode)
  755.                         // found everything:
  756.                         *pusHandle = pNode->pNode->usHandle;
  757.                 }
  758.             } // end while
  759.  
  760.             free(pszFilename);
  761.         }
  762.     }
  763.     else
  764.         arc = ERROR_INVALID_PARAMETER;
  765.  
  766.     _Pmpf((__FUNCTION__ ": returning %d", arc));
  767.  
  768.     // not found: end of buffer reached
  769.     return arc;
  770. }
  771.  
  772. /*
  773.  *@@ wphQueryHandleFromPath:
  774.  *      finds the object handle for the given fully qualified
  775.  *      filename.
  776.  *      This is a one-shot function, using wphQueryActiveHandles,
  777.  *      wphReadAllBlocks, and wphSearchBufferForHandle.
  778.  *
  779.  *      Returns:
  780.  *
  781.  *      --  NO_ERROR: *phobj has received the object handle.
  782.  *
  783.  *      --  ERROR_FILE_NOT_FOUND: file does not exist.
  784.  *
  785.  *      plus the error codes of the other wph* functions called.
  786.  *
  787.  *@@changed V0.9.16 (2001-10-02) [umoeller]: rewritten
  788.  */
  789.  
  790. APIRET wphQueryHandleFromPath(HINI hiniUser,      // in: HINI_USER or other INI handle
  791.                               HINI hiniSystem,    // in: HINI_SYSTEM or other INI handle
  792.                               const char *pcszName,    // in: fully qlf'd filename
  793.                               HOBJECT *phobj)      // out: object handle found if NO_ERROR
  794. {
  795.     APIRET      arc = NO_ERROR;
  796.  
  797.     PSZ         pszActiveHandles = NULL;
  798.     HHANDLES    hHandles = NULLHANDLE;
  799.  
  800.     TRY_LOUD(excpt1)
  801.     {
  802.         // not found there: check the handles then
  803.  
  804.         if (arc = wphQueryActiveHandles(hiniSystem, &pszActiveHandles))
  805.             _Pmpf((__FUNCTION__ ": wphQueryActiveHandles returned %d", arc));
  806.         else
  807.         {
  808.             if (arc = wphLoadHandles(hiniUser,
  809.                                      hiniSystem,
  810.                                      pszActiveHandles,
  811.                                      &hHandles))
  812.                 _Pmpf((__FUNCTION__ ": wphLoadHandles returned %d", arc));
  813.             else
  814.             {
  815.                 USHORT      usObjID;
  816.                 CHAR        szFullPath[2*CCHMAXPATH];
  817.                 _fullpath(szFullPath, (PSZ)pcszName, sizeof(szFullPath));
  818.  
  819.                 // search that buffer
  820.                 if (!(arc = wphSearchBufferForHandle(hHandles,
  821.                                                      szFullPath,
  822.                                                      &usObjID)))
  823.                     // found: OR 0x30000
  824.                     *phobj = usObjID | (((PHANDLESBUF)hHandles)->usHiwordFileSystem << 16);
  825.                 else
  826.                     arc = ERROR_FILE_NOT_FOUND;
  827.             }
  828.         }
  829.     }
  830.     CATCH(excpt1)
  831.     {
  832.         arc = ERROR_PROTECTION_VIOLATION; // V0.9.19 (2002-07-01) [umoeller]
  833.     } END_CATCH();
  834.  
  835.     if (pszActiveHandles)
  836.         free(pszActiveHandles);
  837.     if (hHandles)
  838.         wphFreeHandles(&hHandles);
  839.  
  840.     return arc;
  841. }
  842.  
  843. /* ******************************************************************
  844.  *
  845.  *   Get filename from HOBJECT
  846.  *
  847.  ********************************************************************/
  848.  
  849. /*
  850.  *@@ ComposeThis:
  851.  *      helper for wphComposePath recursion.
  852.  *
  853.  *@@added V0.9.16 (2001-10-02) [umoeller]
  854.  *@@changed V0.9.19 (2002-04-14) [umoeller]: fixed wrong error for parent handles
  855.  */
  856.  
  857. static APIRET ComposeThis(PHANDLESBUF pHandlesBuf,
  858.                           USHORT usHandle,         // in: handle to search for
  859.                           PXSTRING pstrFilename,   // in/out: filename
  860.                           ULONG ulLevel,           // in: recursion level (initially 0)
  861.                           PNODE *ppNode)           // out: node found (ptr can be NULL)
  862. {
  863.     APIRET          arc = NO_ERROR;
  864.     PNODETREENODE   pTreeNode;
  865.     PNODE           pNode;
  866.     if (    (pTreeNode = pHandlesBuf->NodeHashTable[usHandle])
  867.          && (pNode = pTreeNode->pNode)
  868.        )
  869.     {
  870.         // handle exists:
  871.         if (pNode->usParentHandle)
  872.         {
  873.             // node has parent:
  874.             // recurse first
  875.             if (!(arc = ComposeThis(pHandlesBuf,
  876.                                     pNode->usParentHandle,
  877.                                     pstrFilename,
  878.                                     ulLevel + 1,
  879.                                     ppNode)))
  880.             {
  881.                 // no error:
  882.                 xstrcatc(pstrFilename, '\\');
  883.                 xstrcat(pstrFilename, pNode->szName, pNode->usNameSize);
  884.             }
  885.         }
  886.         else
  887.             // no parent:
  888.             xstrcpy(pstrFilename, pNode->szName, pNode->usNameSize);
  889.     }
  890.     else
  891.         // handle not found:
  892.         if (ulLevel == 0)       // V0.9.19 (2002-04-14) [umoeller]
  893.             arc = ERROR_INVALID_HANDLE;
  894.         else
  895.             arc = ERROR_WPH_INVALID_PARENT_HANDLE;
  896.  
  897.     if (!arc)
  898.         if (ppNode)
  899.             *ppNode = pNode;
  900.  
  901.     return arc;
  902. }
  903.  
  904. /*
  905.  *@@ wphComposePath:
  906.  *      returns the fully qualified path name for the specified
  907.  *      file-system handle. This function is very fast because
  908.  *      it uses a hash table for all the handles internally.
  909.  *
  910.  *      Warning: This calls a helper, which recurses.
  911.  *
  912.  *      This returns:
  913.  *
  914.  *      --  NO_ERROR
  915.  *
  916.  *      --  ERROR_WPH_CORRUPT_HANDLES_DATA: buffer data cannot be parsed.
  917.  *
  918.  *      --  ERROR_WPH_INVALID_HANDLE: usHandle cannot be found.
  919.  *
  920.  *      --  ERROR_WPH_INVALID_PARENT_HANDLE: a handle was found
  921.  *          that has a broken parent handle.
  922.  *
  923.  *      --  ERROR_BUFFER_OVERFLOW: cbFilename is too small to
  924.  *          hold the full path that was composed.
  925.  *
  926.  *@@added V0.9.16 (2001-10-02) [umoeller]
  927.  */
  928.  
  929. APIRET wphComposePath(HHANDLES hHandles,
  930.                       USHORT usHandle,      // in: loword of handle to search for
  931.                       PSZ pszFilename,
  932.                       ULONG cbFilename,
  933.                       PNODE *ppNode)        // out: node found (ptr can be NULL)
  934. {
  935.     APIRET arc = NO_ERROR;
  936.  
  937.     PHANDLESBUF pHandlesBuf;
  938.     if (    (hHandles)
  939.          && (pHandlesBuf = (PHANDLESBUF)hHandles)
  940.        )
  941.     {
  942.         TRY_LOUD(excpt1)
  943.         {
  944.             if (!pHandlesBuf->fCacheValid)
  945.                 arc = wphRebuildNodeHashTable(hHandles,
  946.                                               TRUE);        // fail on errors
  947.  
  948.             if (!arc)
  949.             {
  950.                 XSTRING str;
  951.                 xstrInit(&str, CCHMAXPATH);
  952.                 if (!(arc = ComposeThis(pHandlesBuf,
  953.                                         usHandle,
  954.                                         &str,
  955.                                         0,      // initial recursion level
  956.                                         ppNode)))
  957.                     if (str.ulLength > cbFilename - 1)
  958.                         arc = ERROR_BUFFER_OVERFLOW;
  959.                     else
  960.                         memcpy(pszFilename,
  961.                                str.psz,
  962.                                str.ulLength + 1);
  963.                 xstrClear(&str);
  964.             }
  965.         }
  966.         CATCH(excpt1)
  967.         {
  968.             arc = ERROR_PROTECTION_VIOLATION; // V0.9.19 (2002-07-01) [umoeller]
  969.         } END_CATCH();
  970.     }
  971.  
  972.     return arc;
  973. }
  974.  
  975. /*
  976.  *@@ wphQueryPathFromHandle:
  977.  *      reverse to wphQueryHandleFromPath, this gets the
  978.  *      filename for hObject.
  979.  *      This is a one-shot function, using wphQueryActiveHandles,
  980.  *      wphLoadHandles, and wphComposePath.
  981.  *      As a result, this function is _very_ expensive.
  982.  *
  983.  *      Returns:
  984.  *
  985.  *      --  NO_ERROR
  986.  *
  987.  *      --  ERROR_INVALID_HANDLE: hObject is invalid.
  988.  *
  989.  *      --  ERROR_WPH_NOT_FILESYSTEM_HANDLE: hObject's hiword is wrong.
  990.  *
  991.  *@@changed V0.9.16 (2001-10-02) [umoeller]: rewritten
  992.  */
  993.  
  994. APIRET wphQueryPathFromHandle(HINI hiniUser,      // in: HINI_USER or other INI handle
  995.                               HINI hiniSystem,    // in: HINI_SYSTEM or other INI handle
  996.                               HOBJECT hObject,    // in: 32-bit object handle
  997.                               PSZ pszFilename,    // out: filename, if found
  998.                               ULONG cbFilename)   // in: sizeof(*pszFilename)
  999. {
  1000.     APIRET arc = NO_ERROR;
  1001.  
  1002.     TRY_LOUD(excpt1)
  1003.     {
  1004.         PSZ pszActiveHandles;
  1005.         if (arc = wphQueryActiveHandles(hiniSystem, &pszActiveHandles))
  1006.             _Pmpf((__FUNCTION__ ": wphQueryActiveHandles returned %d", arc));
  1007.         else
  1008.         {
  1009.             HHANDLES hHandles;
  1010.             if (arc = wphLoadHandles(hiniUser,
  1011.                                      hiniSystem,
  1012.                                      pszActiveHandles,
  1013.                                      &hHandles))
  1014.                 _Pmpf((__FUNCTION__ ": wphLoadHandles returned %d", arc));
  1015.             else
  1016.             {
  1017.                 USHORT usHiwordFileSystem = ((PHANDLESBUF)hHandles)->usHiwordFileSystem;
  1018.  
  1019.                 // is this really a file-system object?
  1020.                 if (HIUSHORT(hObject) == usHiwordFileSystem)
  1021.                 {
  1022.                     // use loword only
  1023.                     USHORT      usObjID = LOUSHORT(hObject);
  1024.  
  1025.                     memset(pszFilename, 0, cbFilename);
  1026.                     arc = wphComposePath(hHandles,
  1027.                                          usObjID,
  1028.                                          pszFilename,
  1029.                                          cbFilename,
  1030.                                          NULL);
  1031.  
  1032.                     // _Pmpf((__FUNCTION__ ": wphFindPartName returned %d", arc));
  1033.                 }
  1034.                 else
  1035.                     arc = ERROR_WPH_NOT_FILESYSTEM_HANDLE;
  1036.  
  1037.                 wphFreeHandles(&hHandles);
  1038.             }
  1039.  
  1040.             free(pszActiveHandles);
  1041.         }
  1042.     }
  1043.     CATCH(excpt1)
  1044.     {
  1045.         arc = ERROR_PROTECTION_VIOLATION; // V0.9.19 (2002-07-01) [umoeller]
  1046.     } END_CATCH();
  1047.  
  1048.     return arc;
  1049. }
  1050.  
  1051. /*
  1052.  *@@ wphDescribeError:
  1053.  *      returns an error description for one of the handles
  1054.  *      engine errors, or NULL if the error code is not
  1055.  *      recognized.
  1056.  *
  1057.  *@@added V0.9.19 (2002-07-01) [umoeller]
  1058.  */
  1059.  
  1060. PCSZ wphDescribeError(APIRET arc)
  1061. {
  1062.     switch (arc)
  1063.     {
  1064.         case ERROR_WPH_NO_BASECLASS_DATA:
  1065.             return "Cannot find PM_Workplace:BaseClass in OS2.INI";
  1066.  
  1067.         case ERROR_WPH_NO_ACTIVEHANDLES_DATA:
  1068.             return "Cannot find PM_Workplace:ActiveHandles in OS2SYS.INI";
  1069.  
  1070.         case ERROR_WPH_INCOMPLETE_BASECLASS_DATA:
  1071.             return "PM_Workplace:ActiveHandles in OS2SYS.INI is incomplete";
  1072.  
  1073.         case ERROR_WPH_NO_HANDLES_DATA:
  1074.             return "Active handles block in OS2SYS.INI is empty";
  1075.  
  1076.         case ERROR_WPH_CORRUPT_HANDLES_DATA:
  1077.             return "Cannot parse data in active handles block in OS2SYS.INI";
  1078.  
  1079.         case ERROR_WPH_INVALID_PARENT_HANDLE:
  1080.             return "Handle has invalid parent handle";
  1081.  
  1082.         case ERROR_WPH_CANNOT_FIND_HANDLE:
  1083.             return "No handle exists for the given filename";
  1084.  
  1085.         case ERROR_WPH_DRIV_TREEINSERT_FAILED:
  1086.             return "Duplicate DRIV node (treeInsert failed)";
  1087.  
  1088.         case ERROR_WPH_NODE_TREEINSERT_FAILED:
  1089.             return "Duplicate NODE node (treeInsert failed)";
  1090.  
  1091.         case ERROR_WPH_NODE_BEFORE_DRIV:
  1092.             return "NODE node before DRIV node";
  1093.  
  1094.         case ERROR_WPH_NO_MATCHING_DRIVE_BLOCK:
  1095.             return "No matching DRIV node";
  1096.  
  1097.         case ERROR_WPH_NO_MATCHING_ROOT_DIR:
  1098.             return "No matching root directory";
  1099.  
  1100.         case ERROR_WPH_NOT_FILESYSTEM_HANDLE:
  1101.             return "Handle is not a file-system handle";
  1102.  
  1103.         case ERROR_WPH_PRFQUERYPROFILESIZE_BLOCK:
  1104.             return "PrfQueryProfileSize failed on reading one BLOCK in OS2SYS.INI";
  1105.  
  1106.         case ERROR_WPH_PRFQUERYPROFILEDATA_BLOCK:
  1107.             return "PrfQueryProfileData failed on reading one BLOCK in OS2SYS.INI";
  1108.     }
  1109.  
  1110.     return NULL;
  1111. }
  1112.