home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: WPS_PM / WPS_PM.zip / xfld085s.zip / helpers / eas.c < prev    next >
C/C++ Source or Header  |  1999-02-23  |  16KB  |  502 lines

  1.  
  2. /*
  3.  *@@sourcefile eas.c:
  4.  *      contains helper functions for handling Extended Attributes.
  5.  *      See explanations below.
  6.  *
  7.  *      Function prefixes (new with V0.81):
  8.  *      --  ea*         EA helper functions
  9.  *
  10.  *      This file is new with V0.81 and contains all the EA functions
  11.  *      that were in helpers.c previously.
  12.  *
  13.  *@@include #include <os2.h>
  14.  *@@include #include "eas.h"
  15.  */
  16.  
  17. /*
  18.  *      Most of the code in this file dealing with Extended Attributes is based
  19.  *      on code (w) by Chris Hanson (cph@zurich.ai.mit.edu).
  20.  *      Copyright (c) 1995 Massachusetts Institute of Technology.
  21.  *
  22.  *      The original code is available as EALIB.ZIP at Hobbes.
  23.  *
  24.  *      This material was developed by the Scheme project at the Massachusetts
  25.  *      Institute of Technology, Department of Electrical Engineering and
  26.  *      Computer Science.  Permission to copy this software, to redistribute
  27.  *      it, and to use it for any purpose is granted, subject to the following
  28.  *      restrictions and understandings.
  29.  *
  30.  *      1. Any copy made of this software must include this copyright notice
  31.  *      in full.
  32.  *
  33.  *      2. Users of this software agree to make their best efforts (a) to
  34.  *      return to the MIT Scheme project any improvements or extensions that
  35.  *      they make, so that these may be included in future releases; and (b)
  36.  *      to inform MIT of noteworthy uses of this software.
  37.  *
  38.  *      3. All materials developed as a consequence of the use of this
  39.  *      software shall duly acknowledge such use, in accordance with the usual
  40.  *      standards of acknowledging credit in academic research.
  41.  *
  42.  *      4. MIT has made no warrantee or representation that the operation of
  43.  *      this software will be error-free, and MIT is under no obligation to
  44.  *      provide any services, by way of maintenance, update, or otherwise.
  45.  *
  46.  *      5. In conjunction with products arising from the use of this material,
  47.  *      there shall be no use of the name of the Massachusetts Institute of
  48.  *      Technology nor of any adaptation thereof in any advertising,
  49.  *      promotional, or sales literature without prior written consent from
  50.  *      MIT in each case.
  51.  *
  52.  *      This file Copyright (C) 1997-99 Ulrich Möller,
  53.  *                                      Massachusetts Institute of Technology.
  54.  *      This file is part of the XFolder source package.
  55.  *      XFolder is free software; you can redistribute it and/or modify
  56.  *      it under the terms of the GNU General Public License as published
  57.  *      by the Free Software Foundation, in version 2 as it comes in the
  58.  *      "COPYING" file of the XFolder main distribution.
  59.  *      This program is distributed in the hope that it will be useful,
  60.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  61.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  62.  *      GNU General Public License for more details.
  63.  */
  64.  
  65. #define INCL_DOS
  66. #define INCL_DOSERRORS
  67. #include <os2.h>
  68.  
  69. #include <stdlib.h>
  70. #include <string.h>
  71.  
  72. #include "eas.h"
  73.  
  74. // #define _PMPRINTF_
  75. #include "pmprintf.h"
  76.  
  77. /********************************************************************
  78.  *                                                                  *
  79.  *   Extended Attribute handling                                    *
  80.  *                                                                  *
  81.  ********************************************************************/
  82.  
  83. #define EA_BINDING_FLAGS(binding) ((binding)->bFlags)
  84. #define EA_BINDING_NAME_LENGTH(binding) ((binding)->bNameLength)
  85. #define EA_BINDING_VALUE_LENGTH(binding) ((binding)->usValueLength)
  86. #define EA_BINDING_NAME(binding) ((binding)->pszName)
  87. #define EA_BINDING_VALUE(binding) ((binding)->pszValue)
  88.  
  89. #define EA_LIST_BINDING(list) ((list)->binding)
  90. #define EA_LIST_NEXT(list) ((list)->next)
  91.  
  92. // forward declarations to helper funcs at bottom
  93. static PEALIST      ReadEAList(ULONG, PVOID);
  94. static EABINDING *  ReadEAByIndex(ULONG, PVOID, ULONG);
  95. static EABINDING *  ReadEAByName(ULONG, PVOID, PSZ);
  96. static PDENA2       ReadDenaByIndex(ULONG, PVOID, ULONG);
  97. static PEABINDING   GetEAValue(ULONG, PVOID, PDENA2);
  98. static void         SetupQueryEAInfo(PDENA2, PEAOP2);
  99. static PEABINDING   ConvertFeal2Binding(PFEA2LIST);
  100. static void         WriteEAList(ULONG, PVOID, PEALIST);
  101. static void         WriteEA(ULONG, PVOID, PEABINDING);
  102. static PFEA2LIST    ConvertBinding2Feal(PEABINDING);
  103.  
  104. /*
  105.  *@@ eaFreeBinding:
  106.  *      deallocate EA binding memory that was generated
  107.  *      by the ea...Read... procedures below. These procs
  108.  *      assume that "malloc" was used for allocation and
  109.  *      that the "name" and "value" fields of each binding
  110.  *      were also allocated using "malloc". "value" may also
  111.  *      be NULL.
  112.  */
  113.  
  114. void eaFreeBinding(PEABINDING binding)
  115. {
  116.     free(EA_BINDING_NAME(binding));
  117.     if ((EA_BINDING_VALUE(binding)) != 0)
  118.         free(EA_BINDING_VALUE(binding));
  119.     free(binding);
  120. }
  121.  
  122. /*
  123.  *@@ eaFreeList:
  124.  *      like eaFreeBinding, but for an EA binding list.
  125.  */
  126.  
  127. void eaFreeList(PEALIST list)
  128. {
  129.     while (list != 0)
  130.     {
  131.         PEALIST next = (EA_LIST_NEXT (list));
  132.         eaFreeBinding(EA_LIST_BINDING (list));
  133.         free(list);
  134.         list = next;
  135.     }
  136. }
  137.  
  138. /*
  139.  * All of the following functions come in two flavors:
  140.  *
  141.  *      eaHFile*    operate on an open file handle.
  142.  *
  143.  *      eaPath*     operate on any file specified by its
  144.  *                  filename, which may be fully qualified.
  145.  */
  146.  
  147. /*
  148.  * ------ READ EXTENDED ATTRIBUTES
  149.  */
  150.  
  151. /*
  152.  *@@ eaPathQueryTotalSize::
  153.  *      returns the total size of all EAs for a given file.
  154.  *      (W) Ulrich Möller.
  155.  */
  156.  
  157. ULONG eaPathQueryTotalSize(PSZ pszPath)
  158. {
  159.     APIRET  arc;
  160.     ULONG   ulTotalEASize = 0;
  161.     CHAR    pchPath;
  162.     // HDIR    hdir;
  163.     // ULONG ulCount = 1;
  164.     FILEFINDBUF4   ffb4;
  165.  
  166.     _Pmpf(("eaPathQueryTotalSize %s", pszPath));
  167.  
  168.     arc = DosQueryPathInfo(pszPath,
  169.                        // &hdir,
  170.                        // FILE_ARCHIVED | FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY | FILE_DIRECTORY,
  171.                        FIL_QUERYEASIZE,
  172.                        &ffb4,
  173.                        sizeof(FILEFINDBUF4));
  174.  
  175.     if (arc == NO_ERROR)
  176.     {
  177.         // CHAR szFile[CCHMAXPATH];
  178.         // PBYTE pbBuffer = malloc(ffb4.cbList);
  179.         BYTE abBuf[2000];
  180.         LONG lCount = 0;
  181.         PDENA2 pdena2;
  182.  
  183.         lCount = -1;
  184.  
  185.         arc = DosEnumAttribute(ENUMEA_REFTYPE_PATH,
  186.                                       pszPath,
  187.                                       1,
  188.                                       abBuf,
  189.                                       sizeof(abBuf),
  190.                                       (PULONG)&lCount,
  191.                                       ENUMEA_LEVEL_NO_VALUE);
  192.             // ulCount now contains the EA count
  193.  
  194.         pdena2 = (PDENA2)abBuf;
  195.  
  196.         _Pmpf(("  %s: arc = %d, count = %d", pszPath, arc, lCount));
  197.  
  198.         if (lCount > 0) {
  199.             ulTotalEASize = pdena2->cbName + 8;
  200.  
  201.             while (lCount > 0) {
  202.                 ulTotalEASize += (pdena2->cbValue + sizeof(DENA2));
  203.                 lCount--;
  204.                 pdena2 = (PDENA2) (((PBYTE) pdena2) +
  205.                               pdena2->oNextEntryOffset);
  206.  
  207.             }
  208.         }
  209.     }
  210.  
  211.     _Pmpf(("    %s: total %d", pszPath, ulTotalEASize));
  212.  
  213.     return (ulTotalEASize);
  214. }
  215.  
  216. /*
  217.  *@@ eaPathReadAll:
  218.  *      reads all of the extended attributes into an EALIST.
  219.  *      Returns NULL if no EAs were found.
  220.  *      The returned list should be freed using eaFreeList.
  221.  */
  222.  
  223. PEALIST eaPathReadAll(PSZ path)
  224. {
  225.     return (ReadEAList(ENUMEA_REFTYPE_PATH, path));
  226. }
  227.  
  228. /*
  229.  *@@ eaHFileReadAll:
  230.  *      like eaPathReadAll, but for an open file handle.
  231.  */
  232.  
  233. PEALIST eaHFileReadAll(HFILE hfile)
  234. {
  235.     return (ReadEAList(ENUMEA_REFTYPE_FHANDLE, (&hfile)));
  236. }
  237.  
  238. /*
  239.  *@@ eaPathReadOneByIndex:
  240.  *      returns one EA specified by a given index, counting
  241.  *      from 1. Returns NULL if the specified index was not
  242.  *      found, either because the file has no EAs at all or
  243.  *      the index is too large.
  244.  *      The returned binding should be freed using eaFreeBinding.
  245.  */
  246.  
  247. PEABINDING eaPathReadOneByIndex(PSZ path, ULONG index)
  248. {
  249.     return (ReadEAByIndex(ENUMEA_REFTYPE_PATH, path, index));
  250. }
  251.  
  252. /*
  253.  *@@ eaHFileReadOneByIndex:
  254.  *      like eaPathReadOneByIndex, but for an open file handle.
  255.  */
  256.  
  257. PEABINDING eaHFileReadOneByIndex(HFILE hfile, ULONG index)
  258. {
  259.     return (ReadEAByIndex(ENUMEA_REFTYPE_FHANDLE, (&hfile), index));
  260. }
  261.  
  262. /*
  263.  *@@ eaPathReadOneByName:
  264.  *      returns one EA specified by the given EA name (e.g.
  265.  *      ".LONGNAME"). Returns NULL if not found.
  266.  *      The returned binding should be freed using eaFreeBinding.
  267.  */
  268.  
  269. PEABINDING eaPathReadOneByName(PSZ path, PSZ name)
  270. {
  271.     return (ReadEAByName(ENUMEA_REFTYPE_PATH, path, name));
  272. }
  273.  
  274. /*
  275.  *@@ eaHFileReadOneByName:
  276.  *      like eaPathReadOneByName, but for an open file handle.
  277.  */
  278.  
  279. PEABINDING eaHFileReadOneByName(HFILE hfile, PSZ name)
  280. {
  281.     return (ReadEAByName(ENUMEA_REFTYPE_FHANDLE, (&hfile), name));
  282. }
  283.  
  284. /*
  285.  * ------ WRITE EXTENDED ATTRIBUTES
  286.  */
  287.  
  288. /*
  289.  *@@ eaPathWriteAll:
  290.  *      writes a list of EAs to a given file. These EAs
  291.  *      are added to possibly existing EAs on the file.
  292.  *      A given EA is deleted if its usValueLength field
  293.  *      is 0; in that case, the value field may also be NULL.
  294.  */
  295.  
  296. void eaPathWriteAll(PSZ path, PEALIST list)
  297. {
  298.     WriteEAList(ENUMEA_REFTYPE_PATH, path, list);
  299. }
  300.  
  301. /*
  302.  *@@ eaHFileWriteAll:
  303.  *      like eaPathWriteAll, but for an open file handle.
  304.  */
  305.  
  306. void eaHFileWriteAll(HFILE hfile, PEALIST list)
  307. {
  308.     WriteEAList(ENUMEA_REFTYPE_FHANDLE, (&hfile), list);
  309. }
  310.  
  311. /*
  312.  *@@ eaPathWriteOne:
  313.  *      adds one EA to a given file.
  314.  *      A given EA is deleted if its usValueLength field
  315.  *      is 0; in that case, the value field may also be NULL.
  316.  */
  317.  
  318. void eaPathWriteOne(PSZ path, PEABINDING binding)
  319. {
  320.     WriteEA(ENUMEA_REFTYPE_PATH, path, binding);
  321. }
  322.  
  323. /*
  324.  *@@ eaHFileWriteOne:
  325.  *      like eaPathWriteOne, but for an open file handle.
  326.  */
  327.  
  328. void eaHFileWriteOne(HFILE hfile, PEABINDING binding)
  329. {
  330.     WriteEA(ENUMEA_REFTYPE_FHANDLE, (&hfile), binding);
  331. }
  332.  
  333. /********************************************************************
  334.  *                                                                  *
  335.  *   EA helper funcs                                                *
  336.  *                                                                  *
  337.  ********************************************************************/
  338.  
  339. static PEALIST ReadEAList(ULONG type, PVOID pfile)
  340. {
  341.     ULONG index = 1;
  342.     PEALIST head = 0;
  343.     PEALIST tail = 0;
  344.  
  345.     while (1)
  346.     {
  347.         PEABINDING binding = (ReadEAByIndex(type, pfile, index));
  348.         if (binding == 0)
  349.             break;
  350.         {
  351.             PEALIST list = (malloc(sizeof (EALIST)));
  352.             (EA_LIST_BINDING (list)) = binding;
  353.             (EA_LIST_NEXT (list)) = 0;
  354.             if (head == 0)
  355.                 head = list;
  356.             else
  357.                 (EA_LIST_NEXT (tail)) = list;
  358.             tail = list;
  359.         }
  360.         index += 1;
  361.     }
  362.     return (head);
  363. }
  364.  
  365. static PEABINDING ReadEAByIndex(ULONG type, PVOID pfile, ULONG index)
  366. {
  367.     PDENA2 dena = (ReadDenaByIndex(type, pfile, index));
  368.     return ((dena == 0)
  369.                     ? 0
  370.                     : (GetEAValue(type, pfile, dena)));
  371. }
  372.  
  373. static PEABINDING ReadEAByName(ULONG type, PVOID pfile, PSZ name)
  374. {
  375.     ULONG index = 1;
  376.     while (1)
  377.     {
  378.         PDENA2 dena = ReadDenaByIndex(type, pfile, index);
  379.         if (dena == 0)
  380.             return (NULL);
  381.         if ((strcmp(name, (dena->szName))) == 0)
  382.             return (GetEAValue(type, pfile, dena));
  383.         free(dena);
  384.         index += 1;
  385.     }
  386. }
  387.  
  388. static PDENA2 ReadDenaByIndex(ULONG type, PVOID pfile, ULONG index)
  389. {
  390.     ULONG count = 1;
  391.     PDENA2 dena = (malloc(500)); // 500 is magic -- IBM doesn't explain.
  392.     APIRET arc = DosEnumAttribute(type, pfile, index, dena, 500, (&count),
  393.                      ENUMEA_LEVEL_NO_VALUE);
  394.     if (count == 0)
  395.     {
  396.         free(dena);
  397.         return (0);
  398.     }
  399.     else
  400.         return (dena);
  401. }
  402.  
  403. static PEABINDING GetEAValue(ULONG type, PVOID pfile, PDENA2 dena)
  404. {
  405.     ULONG level = FIL_QUERYEASFROMLIST;
  406.     EAOP2 eaop;
  407.     ULONG size = (sizeof(eaop));
  408.     APIRET arc = NO_ERROR;
  409.     SetupQueryEAInfo(dena, (&eaop));
  410.     if (type == ENUMEA_REFTYPE_FHANDLE)
  411.         arc = DosQueryFileInfo((* ((PHFILE) pfile)), level, (&eaop), size);
  412.     else
  413.         arc = DosQueryPathInfo(pfile, level, (&eaop), size);
  414.     free(eaop.fpGEA2List);
  415.     return (ConvertFeal2Binding(eaop.fpFEA2List));
  416. }
  417.  
  418. static void SetupQueryEAInfo(PDENA2 dena, PEAOP2 eaop)
  419. {
  420.     unsigned int geal_size = ((sizeof (GEA2LIST)) + (dena->cbName));
  421.     unsigned int feal_size
  422.                  = ((sizeof (FEA2LIST)) + (dena->cbName) + (dena->cbValue));
  423.     (eaop->fpGEA2List) = (malloc(geal_size));
  424.     ((eaop->fpGEA2List)->cbList) = geal_size;
  425.     (eaop->fpFEA2List) = (malloc(feal_size));
  426.     ((eaop->fpFEA2List)->cbList) = feal_size;
  427.     (eaop->oError) = 0;
  428.     {
  429.         PGEA2 gea = (&(((eaop->fpGEA2List)->list) [0]));
  430.         (gea->oNextEntryOffset) = 0;
  431.         (gea->cbName) = (dena->cbName);
  432.         strcpy ((gea->szName), (dena->szName));
  433.     }
  434.     free(dena);
  435. }
  436.  
  437. static PEABINDING ConvertFeal2Binding(PFEA2LIST feal)
  438. {
  439.     PFEA2 fea = (&((feal->list) [0]));
  440.     PEABINDING binding = (malloc(sizeof (EABINDING)));
  441.     (EA_BINDING_FLAGS (binding)) = (fea->fEA);
  442.     (EA_BINDING_NAME_LENGTH (binding)) = (fea->cbName);
  443.     (EA_BINDING_VALUE_LENGTH (binding)) = (fea->cbValue);
  444.     (EA_BINDING_NAME (binding)) = (malloc((fea->cbName) + 1));
  445.     strcpy ((EA_BINDING_NAME (binding)), (fea->szName));
  446.     (EA_BINDING_VALUE (binding)) = (malloc(fea->cbValue));
  447.     memcpy ((EA_BINDING_VALUE (binding)),
  448.         (&((fea->szName) [(fea->cbName) + 1])),
  449.         (fea->cbValue));
  450.     free(feal);
  451.     return (binding);
  452. }
  453.  
  454. static void WriteEAList(ULONG type, PVOID pfile, PEALIST list)
  455. {
  456.     while (list != 0)
  457.     {
  458.         WriteEA(type, pfile, (EA_LIST_BINDING (list)));
  459.         list = (EA_LIST_NEXT (list));
  460.     }
  461. }
  462.  
  463. static void WriteEA(ULONG type, PVOID pfile, PEABINDING binding)
  464. {
  465.     ULONG level = FIL_QUERYEASIZE;
  466.     EAOP2 eaop;
  467.     ULONG size = (sizeof (eaop));
  468.     APIRET arc = NO_ERROR;
  469.  
  470.     (eaop.fpGEA2List) = 0;
  471.     (eaop.fpFEA2List) = (ConvertBinding2Feal(binding));
  472.     (eaop.oError) = 0;
  473.     if (type == ENUMEA_REFTYPE_FHANDLE)
  474.         arc = DosSetFileInfo((* ((PHFILE) pfile)), level, (&eaop), size);
  475.     else
  476.         arc = DosSetPathInfo(pfile, level, (&eaop), size, DSPI_WRTTHRU);
  477.     free(eaop.fpFEA2List);
  478. }
  479.  
  480. static PFEA2LIST ConvertBinding2Feal(PEABINDING binding)
  481. {
  482.     unsigned int feal_size
  483.               = ((sizeof (FEA2LIST))
  484.                  + (EA_BINDING_NAME_LENGTH (binding))
  485.                  + (EA_BINDING_VALUE_LENGTH (binding)));
  486.     PFEA2LIST feal = (malloc(feal_size));
  487.     PFEA2 fea = (&((feal->list) [0]));
  488.     (feal->cbList) = feal_size;
  489.     (fea->oNextEntryOffset) = 0;
  490.     (fea->fEA) = (EA_BINDING_FLAGS (binding));
  491.     (fea->cbName) = (EA_BINDING_NAME_LENGTH (binding));
  492.     (fea->cbValue) = (EA_BINDING_VALUE_LENGTH (binding));
  493.     strcpy ((fea->szName), (EA_BINDING_NAME (binding)));
  494.     if ((EA_BINDING_VALUE (binding)) != 0)
  495.         memcpy ((&((fea->szName) [(fea->cbName) + 1])),
  496.             (EA_BINDING_VALUE (binding)),
  497.             (fea->cbValue));
  498.     return (feal);
  499. }
  500.  
  501.  
  502.