source: branches/branch-1-0/src/helpers/eah.c@ 231

Last change on this file since 231 was 222, checked in by umoeller, 23 years ago

Minor adjustments for new static handling.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 46.9 KB
Line 
1
2/*
3 *@@sourcefile eah.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 * Usage: All OS/2 programs.
11 *
12 * This file is new with V0.81 and contains all the EA functions
13 * that were in helpers.c previously.
14 *
15 * Most of the functions in here come in pairs: one for working
16 * on EAs based on a path (eaPath*), one for open HFILEs (eaHFile*).
17 * Most functions return structures called EABINDING which should
18 * be freed again later.
19 *
20 * <B>Example:</B>
21 + PEABINDING peab = eaPathReadOneByName("C:\Desktop", ".LONGNAME");
22 + if (peab)
23 + PSZ pszLongName = peab->pszValue;
24 + eaFreeBinding(peab);
25 *
26 * Note: Version numbering in this file relates to XWorkplace version
27 * numbering.
28 *
29 *@@header "helpers\eah.h"
30 */
31
32/*
33 * Most of the code in this file dealing with Extended Attributes is based
34 * on code (w) by Chris Hanson (cph@zurich.ai.mit.edu).
35 * Copyright (c) 1995 Massachusetts Institute of Technology.
36 *
37 * The original code is available as EALIB.ZIP at Hobbes.
38 *
39 * This material was developed by the Scheme project at the Massachusetts
40 * Institute of Technology, Department of Electrical Engineering and
41 * Computer Science. Permission to copy this software, to redistribute
42 * it, and to use it for any purpose is granted, subject to the following
43 * restrictions and understandings.
44 *
45 * 1. Any copy made of this software must include this copyright notice
46 * in full.
47 *
48 * 2. Users of this software agree to make their best efforts (a) to
49 * return to the MIT Scheme project any improvements or extensions that
50 * they make, so that these may be included in future releases; and (b)
51 * to inform MIT of noteworthy uses of this software.
52 *
53 * 3. All materials developed as a consequence of the use of this
54 * software shall duly acknowledge such use, in accordance with the usual
55 * standards of acknowledging credit in academic research.
56 *
57 * 4. MIT has made no warrantee or representation that the operation of
58 * this software will be error-free, and MIT is under no obligation to
59 * provide any services, by way of maintenance, update, or otherwise.
60 *
61 * 5. In conjunction with products arising from the use of this material,
62 * there shall be no use of the name of the Massachusetts Institute of
63 * Technology nor of any adaptation thereof in any advertising,
64 * promotional, or sales literature without prior written consent from
65 * MIT in each case.
66 *
67 * Copyright (C) 1995 Massachusetts Institute of Technology.
68 * Copyright (C) 1997-2002 Ulrich M”ller.
69 * This file is part of the "XWorkplace helpers" source package.
70 * This is free software; you can redistribute it and/or modify
71 * it under the terms of the GNU General Public License as published
72 * by the Free Software Foundation, in version 2 as it comes in the
73 * "COPYING" file of the XWorkplace main distribution.
74 * This program is distributed in the hope that it will be useful,
75 * but WITHOUT ANY WARRANTY; without even the implied warranty of
76 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
77 * GNU General Public License for more details.
78 */
79
80#define OS2EMX_PLAIN_CHAR
81 // this is needed for "os2emx.h"; if this is defined,
82 // emx will define PSZ as _signed_ char, otherwise
83 // as unsigned char
84
85#define INCL_DOSFILEMGR
86#define INCL_DOSERRORS
87#include <os2.h>
88
89#include <stdlib.h>
90#include <string.h>
91
92#include "setup.h" // code generation and debugging options
93
94#include "helpers\eah.h"
95
96#pragma hdrstop
97
98/*
99 *@@category: Helpers\Control program helpers\Extended attributes
100 * See eah.c.
101 */
102
103/********************************************************************
104 *
105 * Extended Attribute handling
106 *
107 ********************************************************************/
108
109#define EA_BINDING_FLAGS(binding) ((binding)->bFlags)
110#define EA_BINDING_NAME_LENGTH(binding) ((binding)->bNameLength)
111#define EA_BINDING_VALUE_LENGTH(binding) ((binding)->usValueLength)
112#define EA_BINDING_NAME(binding) ((binding)->pszName)
113#define EA_BINDING_VALUE(binding) ((binding)->pszValue)
114
115#define EA_LIST_BINDING(list) ((list)->peab)
116#define EA_LIST_NEXT(list) ((list)->next)
117
118// forward declarations to helper funcs at bottom
119STATIC PEALIST ReadEAList(ULONG, PVOID);
120STATIC EABINDING * ReadEAByIndex(ULONG, PVOID, ULONG);
121STATIC EABINDING * ReadEAByName(ULONG, PVOID, PSZ);
122STATIC PDENA2 ReadDenaByIndex(ULONG, PVOID, ULONG);
123STATIC PEABINDING GetEAValue(ULONG, PVOID, PDENA2);
124STATIC void SetupQueryEAInfo(PDENA2, PEAOP2);
125STATIC PEABINDING ConvertFeal2Binding(PFEA2LIST);
126STATIC APIRET WriteEAList(ULONG, PVOID, PEALIST);
127STATIC APIRET WriteEA(ULONG, PVOID, PEABINDING);
128STATIC PFEA2LIST ConvertBinding2Feal(PEABINDING);
129
130/*
131 *@@ eaFreeBinding:
132 * deallocate EA binding memory that was generated
133 * by the ea...Read... procedures below. These procs
134 * assume that "malloc" was used for allocation and
135 * that the "pszName" and "pszValue" fields of each binding
136 * were also allocated using "malloc". "pszValue" may also
137 * be NULL.
138 *
139 *@@changed V0.9.0 [umoeller]: added check for (binding != NULL)
140 */
141
142void eaFreeBinding(PEABINDING peab)
143{
144 if (peab)
145 {
146 free(EA_BINDING_NAME(peab));
147 if ((EA_BINDING_VALUE(peab)) != 0)
148 free(EA_BINDING_VALUE(peab));
149 free(peab);
150 }
151}
152
153/*
154 *@@ eaFreeList:
155 * like eaFreeBinding, but for an EA binding list.
156 * This calls eaFreeBinding for each list item.
157 *
158 *@@changed V0.9.0 [umoeller]: added check for (list != NULL)
159 */
160
161void eaFreeList(PEALIST list)
162{
163 if (list)
164 {
165 while (list != 0)
166 {
167 PEALIST next = (EA_LIST_NEXT (list));
168 eaFreeBinding(EA_LIST_BINDING (list));
169 free(list);
170 list = next;
171 }
172 }
173}
174
175/* ******************************************************************
176 *
177 * Read-EA functions
178 *
179 ********************************************************************/
180
181/*
182 * All of the following functions come in two flavors:
183 *
184 * eaHFile* operate on an open file handle.
185 *
186 * eaPath* operate on any file specified by its
187 * filename, which may be fully qualified.
188 */
189
190/*
191 *@@ eaPathQueryTotalSize:
192 * returns the total size of all EAs for a given file.
193 * This does not use the other EA functions, but
194 * accesses the EAs directly, so this is a lot quicker
195 * if you only want the total EA size without accessing
196 * the EA data.
197 */
198
199ULONG eaPathQueryTotalSize(const char *pcszPath)
200{
201 APIRET arc;
202 ULONG ulTotalEASize = 0;
203 FILEFINDBUF4 ffb4;
204
205 if (!(arc = DosQueryPathInfo((PSZ)pcszPath,
206 FIL_QUERYEASIZE,
207 &ffb4,
208 sizeof(FILEFINDBUF4))))
209 {
210 BYTE abBuf[2000];
211 LONG lCount = 0;
212 PDENA2 pdena2;
213
214 lCount = -1;
215
216 if (!(arc = DosEnumAttribute(ENUMEA_REFTYPE_PATH,
217 (PSZ)pcszPath,
218 1,
219 abBuf,
220 sizeof(abBuf),
221 (PULONG)&lCount,
222 ENUMEA_LEVEL_NO_VALUE)))
223 {
224 // ulCount now contains the EA count
225
226 pdena2 = (PDENA2)abBuf;
227
228 if (lCount > 0)
229 {
230 ulTotalEASize = pdena2->cbName + 8;
231
232 while (lCount > 0)
233 {
234 ulTotalEASize += (pdena2->cbValue + sizeof(DENA2));
235 lCount--;
236 pdena2 = (PDENA2) (((PBYTE) pdena2) +
237 pdena2->oNextEntryOffset);
238
239 }
240 }
241 }
242 }
243
244 return (ulTotalEASize);
245}
246
247/*
248 *@@ eaPathReadAll:
249 * reads all of the extended attributes into an EALIST.
250 * Returns NULL if no EAs were found.
251 * The returned list should be freed using eaFreeList.
252 */
253
254PEALIST eaPathReadAll(const char *pcszPath)
255{
256 return (ReadEAList(ENUMEA_REFTYPE_PATH, (PSZ)pcszPath));
257}
258
259/*
260 *@@ eaHFileReadAll:
261 * like eaPathReadAll, but for an open file handle.
262 */
263
264PEALIST eaHFileReadAll(HFILE hfile)
265{
266 return (ReadEAList(ENUMEA_REFTYPE_FHANDLE, (&hfile)));
267}
268
269/*
270 *@@ eaPathReadOneByIndex:
271 * returns one EA specified by a given index, counting
272 * from 1. Returns NULL if the specified index was not
273 * found, either because the file has no EAs at all or
274 * the index is too large.
275 * The returned binding should be freed using eaFreeBinding.
276 */
277
278PEABINDING eaPathReadOneByIndex(const char *pcszPath, ULONG index)
279{
280 return (ReadEAByIndex(ENUMEA_REFTYPE_PATH, (PSZ)pcszPath, index));
281}
282
283/*
284 *@@ eaHFileReadOneByIndex:
285 * like eaPathReadOneByIndex, but for an open file handle.
286 */
287
288PEABINDING eaHFileReadOneByIndex(HFILE hfile, ULONG index)
289{
290 return (ReadEAByIndex(ENUMEA_REFTYPE_FHANDLE, (&hfile), index));
291}
292
293/*
294 *@@ eaPathReadOneByName:
295 * returns one EA specified by the given EA name (e.g.
296 * ".LONGNAME"). Returns NULL if not found.
297 * The returned binding should be freed using eaFreeBinding.
298 */
299
300PEABINDING eaPathReadOneByName(const char *pcszPath, const char *pcszEAName)
301{
302 return (ReadEAByName(ENUMEA_REFTYPE_PATH, (PSZ)pcszPath, (PSZ)pcszEAName));
303}
304
305/*
306 *@@ eaHFileReadOneByName:
307 * like eaPathReadOneByName, but for an open file handle.
308 */
309
310PEABINDING eaHFileReadOneByName(HFILE hfile, const char *pcszEAName)
311{
312 return (ReadEAByName(ENUMEA_REFTYPE_FHANDLE, (&hfile), (PSZ)pcszEAName));
313}
314
315/* ******************************************************************
316 *
317 * Write-EA functions
318 *
319 ********************************************************************/
320
321/*
322 *@@ eaPathWriteAll:
323 * writes a list of EAs to a given file. These EAs
324 * are added to possibly existing EAs on the file;
325 * existing EAs will be overwritten.
326 *
327 * A given EA is deleted if its EABINDING.usValueLength
328 * field is 0; only in that case, the EABINDING.value
329 * field may also be NULL.
330 *
331 *@@changed V0.9.7 (2000-11-30) [umoeller]: now returning APIRET
332 */
333
334APIRET eaPathWriteAll(const char *pcszPath, PEALIST list)
335{
336 return (WriteEAList(ENUMEA_REFTYPE_PATH, (PSZ)pcszPath, list));
337}
338
339/*
340 *@@ eaHFileWriteAll:
341 * like eaPathWriteAll, but for an open file handle.
342 *
343 *@@changed V0.9.7 (2000-11-30) [umoeller]: now returning APIRET
344 */
345
346APIRET eaHFileWriteAll(HFILE hfile, PEALIST list)
347{
348 return (WriteEAList(ENUMEA_REFTYPE_FHANDLE, (&hfile), list));
349}
350
351/*
352 *@@ eaPathWriteOne:
353 * adds one EA to a given file. If the EA exists
354 * alredy, it is overwritten.
355 *
356 * A given EA is deleted if its EABINDING.usValueLength
357 * field is 0; only in that case, the EABINDING.pszValue
358 * field may also be NULL.
359 *
360 * To delete an EA, you may also use eaPathDeleteOne.
361 *
362 *@@changed V0.9.7 (2000-11-30) [umoeller]: now returning APIRET
363 */
364
365APIRET eaPathWriteOne(const char *pcszPath, PEABINDING peab)
366{
367 return (WriteEA(ENUMEA_REFTYPE_PATH, (PSZ)pcszPath, peab));
368}
369
370/*
371 *@@ eaHFileWriteOne:
372 * like eaPathWriteOne, but for an open file handle.
373 *
374 *@@changed V0.9.7 (2000-11-30) [umoeller]: now returning APIRET
375 */
376
377APIRET eaHFileWriteOne(HFILE hfile, PEABINDING peab)
378{
379 return (WriteEA(ENUMEA_REFTYPE_FHANDLE, (&hfile), peab));
380}
381
382/*
383 *@@ eaPathDeleteOne:
384 * this deletes one EA by constructing a temporary
385 * empty EABINDING for pszEAName and calling
386 * eaPathWriteOne.
387 *
388 *@@added V0.9.0 [umoeller]
389 *@@changed V0.9.7 (2000-11-30) [umoeller]: now returning APIRET
390 */
391
392APIRET eaPathDeleteOne(const char *pcszPath, const char *pcszEAName)
393{
394 EABINDING eab;
395 eab.bFlags = 0;
396 eab.bNameLength = strlen(pcszEAName);
397 eab.pszName = (PSZ)pcszEAName;
398 eab.usValueLength = 0;
399 eab.pszValue = 0;
400 return (eaPathWriteOne(pcszPath, &eab));
401}
402
403/*
404 *@@category: Helpers\Control program helpers\Extended attributes\Translation helpers
405 * these functions are built on top of the regular EA helpers
406 * (see eah.c) to convert standard types to EAs.
407 */
408
409/********************************************************************
410 *
411 * Translation funcs
412 *
413 ********************************************************************/
414
415/*
416 *@@ eaQueryEAType:
417 * this returns the type of the EA stored
418 * in the given EA binding.
419 * See CPREF for the EAT_* codes which are
420 * returned here.
421 * Returns 0 upon errors.
422 *
423 *@@added V0.9.0 [umoeller]
424 */
425
426USHORT eaQueryEAType(PEABINDING peab)
427{
428 USHORT usReturn = 0;
429 if (peab)
430 if (peab->pszValue)
431 // first USHORT always has EAT_* flag
432 usReturn = *((PUSHORT)(peab->pszValue));
433 return (usReturn);
434}
435
436/*
437 *@@ eaCreatePSZFromBinding:
438 * this returns a new PSZ for the given EABINDING,
439 * if this is a string EA (EAT_ASCII).
440 * This PSZ should be free()'d after use.
441 * Otherwise, NULL is returned.
442 *
443 *@@added V0.9.0 [umoeller]
444 *@@changed V0.9.2 (2000-03-12) [umoeller]: added checks for NULl strings
445 */
446
447PSZ eaCreatePSZFromBinding(PEABINDING peab)
448{
449 PSZ pszReturn = NULL;
450
451 if (peab)
452 {
453 if (eaQueryEAType(peab) == EAT_ASCII)
454 {
455 // OK: next USHORT has length of string
456 PUSHORT pusLength = (PUSHORT)(peab->pszValue + 2);
457 if (*pusLength)
458 {
459 pszReturn = (PSZ)malloc(*pusLength + 1);
460 memcpy(pszReturn, peab->pszValue + 4, *pusLength);
461 // add null terminator
462 *(pszReturn + (*pusLength)) = 0;
463 }
464 }
465 }
466
467 return (pszReturn);
468}
469
470/*
471 *@@ eaCreateBindingFromPSZ:
472 * reverse to eaCreatePSZFromBinding, this creates
473 * a new EABINDING from the given PSZ, which
474 * can be used with the write-EA functions.
475 * This EA is of type EAT_ASCII and will be
476 * made non-critical (peab->bFlags = 0).
477 *
478 * If the given string is NULL or empty,
479 * a binding is created anyway; however, usValueLength
480 * and pszValue will be set to NULL so that the string
481 * can be deleted.
482 *
483 * Returns NULL only upon malloc() errors.
484 *
485 *@@added V0.9.0 [umoeller]
486 *@@changed V0.9.1 (2000-01-22) [umoeller]: fixed null-string behavior
487 *@@changed V0.9.2 (2000-02-26) [umoeller]: fixed null-string behaviour AGAIN
488 */
489
490PEABINDING eaCreateBindingFromPSZ(const char *pcszEAName, // in: EA name (e.g. ".LONGNAME")
491 const char *pcszInput) // in: string for EAT_ASCII EA
492{
493 PEABINDING peab = (PEABINDING)malloc(sizeof(EABINDING));
494 if (peab)
495 {
496 SHORT cbString = 0;
497 if (pcszInput)
498 cbString = strlen(pcszInput);
499
500 peab->bFlags = 0;
501 peab->bNameLength = strlen(pcszEAName);
502 peab->pszName = strdup(pcszEAName);
503
504 if (cbString)
505 {
506 // non-null string:
507 peab->usValueLength = cbString + 4;
508 peab->pszValue = (PSZ)malloc(peab->usValueLength);
509 if (peab->pszValue)
510 {
511 // set first USHORT to EAT_ASCII
512 *((PUSHORT)(peab->pszValue)) = EAT_ASCII;
513 // set second USHORT to length of string
514 *((PUSHORT)(peab->pszValue + 2)) = cbString;
515 // copy string to byte 4 (no null-terminator)
516 memcpy(peab->pszValue + 4, pcszInput, cbString);
517 }
518 else
519 {
520 // malloc error:
521 if (peab->pszName)
522 free(peab->pszName);
523 free(peab);
524 peab = NULL;
525 }
526 }
527 else
528 {
529 // null string:
530 peab->usValueLength = 0;
531 peab->pszValue = NULL;
532 }
533 }
534
535 return (peab);
536}
537
538/*
539 *@@ eaQueryMVCount:
540 * this returns the number of subitems in a
541 * multi-value EA. This works for both EAT_MVMT
542 * and EAT_MVST (multi-type and single-type) EAs.
543 * Returns 0 upon errors.
544 *
545 *@@added V0.9.0 [umoeller]
546 *@@changed V0.9.2 (2000-03-12) [umoeller]: added more error checks
547 */
548
549USHORT eaQueryMVCount(PEABINDING peab, // in: EA binding to examine (must be EAT_MVMT or EAT_MVST)
550 PUSHORT pusCodepage, // out: codepage found in binding (ptr can be NULL)
551 PUSHORT pusEAType) // out: either EAT_MVST or EAT_MVMT (ptr can be NULL)
552{
553 USHORT usReturn = 0;
554
555 USHORT usEAType = eaQueryEAType(peab);
556
557 if (pusEAType)
558 *pusEAType = usEAType;
559
560 if (usEAType == EAT_MVST)
561 {
562 // multi-value single-type:
563 // pszValue is as follows (all USHORTs)
564 // EAT_MVST usCodepage usCount usDataType data ....
565
566 // store codepage
567 if (pusCodepage)
568 *pusCodepage = *((PUSHORT)(peab->pszValue + 2));
569 // find count of entries
570 usReturn = *((PUSHORT)(peab->pszValue + 4));
571 } // end if (*((PUSHORT)(peab->pszValue)) == EAT_MVST)
572 else if (usEAType == EAT_MVMT)
573 {
574 // multi-value multi-type:
575 // pszValue is as follows (all USHORTs)
576 // EAT_MVMT usCodepage usCount (usDataType data... )...
577
578 // store codepage
579 if (pusCodepage)
580 *pusCodepage = *((PUSHORT)(peab->pszValue + 2));
581 // find count of entries
582 usReturn = *((PUSHORT)(peab->pszValue + 4));
583 }
584
585 return (usReturn);
586}
587
588/*
589 *@@ eaQueryMVItem:
590 * this returns a pointer to the beginning
591 * of data of a subitem in a multi-value
592 * (EAT_MVST or EAT_MVMT) EA.
593 *
594 * Note that this _only_ works if the data
595 * stored in the multi-value fields has
596 * length-data right after the EAT_* fields.
597 * This is true for EAT_ASCII, for example.
598 *
599 * <B>Example:</B> If the EA value in the
600 * binding is like this:
601 + EAT_MVMT codp count [DataType Data] ...
602 + EAT_MVMT 0000 0002 EAT_ASCII 000A Hello John
603 + EAT_BINARY 0003 0x12 0x21 0x34
604 * calling this function with usindex==1 would return
605 * a pointer to the 0x12 byte in the EA data, set *pusCodepage
606 * to 0, and set *pusDataLength to 3.
607 *
608 *@@added V0.9.0 [umoeller]
609 *@@changed V0.9.2 (2000-03-12) [umoeller]: added more error checks
610 */
611
612PSZ eaQueryMVItem(PEABINDING peab, // in: binding to examing
613 USHORT usIndex, // in: item to search (starting at 0)
614 PUSHORT pusCodepage, // out: codepage found in binding (ptr can be NULL)
615 PUSHORT pusEAType, // out: EAT_* data type of data that the return value points to (ptr can be NULL)
616 PUSHORT pusDataLength) // out: length of data that the return value points to (ptr can be NULL)
617{
618 PSZ pszReturn = NULL;
619
620 USHORT usEAType = eaQueryEAType(peab);
621
622 if (usEAType == EAT_MVST)
623 {
624 // multi-value single-type:
625 // pszValue is as follows (all USHORTs)
626 // EAT_MVST usCodepage usCount usDataType data ....
627 USHORT usCount,
628 usDataType;
629 PUSHORT pusLengthThis;
630 PSZ pData;
631 // store codepage
632 if (pusCodepage)
633 *pusCodepage = *((PUSHORT)(peab->pszValue + 2));
634 // find count of entries
635 usCount = *((PUSHORT)(peab->pszValue + 4));
636
637 if (usIndex < usCount)
638 {
639 // find data type
640 usDataType = *((PUSHORT)(peab->pszValue + 6));
641 if ( (usDataType == EAT_ASCII)
642 || (usDataType == EAT_BINARY)
643 )
644 {
645 USHORT us = 0;
646 // find beginning of data (after length word)
647 pData = peab->pszValue + 10;
648
649 while (us < usIndex)
650 {
651 pusLengthThis = (PUSHORT)(pData - 2);
652 pData += *pusLengthThis + 2;
653 us++;
654 }
655
656 // pData now points to the actual data;
657 // pData - 2 has the length of the subvalue
658
659 // return values
660 if (pusEAType)
661 *pusEAType = usDataType; // same for all MVST subvalues
662 if (pusDataLength)
663 *pusDataLength = *((PUSHORT)(pData - 2));
664 pszReturn = pData;
665 }
666 }
667 } // end if (usEAType == EAT_MVST)
668 else if (usEAType == EAT_MVMT)
669 {
670 // multi-value multi-type:
671 // pszValue is as follows (all USHORTs)
672 // EAT_MVMT usCodepage usCount (usDataType data... )...
673 USHORT usCount;
674 // usDataType;
675 PUSHORT pusLengthThis;
676 PSZ pData;
677 // store codepage
678 if (pusCodepage)
679 *pusCodepage = *((PUSHORT)(peab->pszValue + 2));
680 // find count of entries
681 usCount = *((PUSHORT)(peab->pszValue + 4));
682
683 if (usIndex < usCount)
684 {
685 USHORT us = 0;
686 pData = peab->pszValue + 6;
687
688 while (us < usIndex)
689 {
690 PUSHORT pusDataType = (PUSHORT)(pData);
691
692 if ( (*pusDataType == EAT_ASCII)
693 || (*pusDataType == EAT_BINARY)
694 )
695 {
696 pusLengthThis = (PUSHORT)(pData + 2);
697 pData += *pusLengthThis + 4;
698 us++;
699 }
700 else
701 {
702 pData = 0;
703 break;
704 }
705 }
706
707 // pData now points to the usDataType field
708 // of the subvalue;
709 // pData + 2 is the length of the subvalue;
710 // pData + 4 is the actual data
711
712 // return values
713 if (pData)
714 {
715 if (pusEAType)
716 *pusEAType = *((PUSHORT)(pData)); // different for each MVMT item
717 if (pusDataLength)
718 *pusDataLength = *((PUSHORT)(pData + 2));
719 pszReturn = pData + 4;
720 }
721 }
722 } // end if (usEAType == EAT_MVMT)
723
724 return (pszReturn);
725}
726
727/*
728 *@@ eaCreatePSZFromMVBinding:
729 * this returns a new PSZ for the given EABINDING,
730 * if this is a multi-value, multi-type EA (EAT_MVMT),
731 * all of whose subitems are of EAT_ASCII though.
732 * Note that this does _not_ work for EAT_MVST EAs.
733 *
734 * This format is used by the .COMMENTS and .KEYPHRASES
735 * system EAs, for example.
736 *
737 * The different subitems will be separated by what
738 * you specify in pszSeparator. You can, for example,
739 * specify \n\r\0 to have CR-LF separators.
740 *
741 * This PSZ should be free()'d after use.
742 * On errors, NULL is returned.
743 *
744 *@@added V0.9.0 [umoeller]
745 *@@changed V0.9.2 (2000-03-12) [umoeller]: added more error checks
746 */
747
748PSZ eaCreatePSZFromMVBinding(PEABINDING peab, // in: EAT_MVMT binding
749 const char *pcszSeparator, // in: null-terminated string used as separator
750 PUSHORT pusCodepage) // out: codepage found in binding (ptr can be NULL)
751{
752 PSZ pszTotal = NULL; // this will hold the whole string
753
754 if (peab)
755 {
756 USHORT usEAType = 0;
757
758 USHORT usMVCount = eaQueryMVCount(peab,
759 pusCodepage,
760 &usEAType);
761 if ( (usMVCount)
762 // items found?
763 && (usEAType == EAT_MVMT)
764 // rule out EAT_MVST, which we cannot handle here
765 )
766 {
767 // EAT_MVMT items found:
768 // go thru all of them
769 USHORT us = 0;
770 USHORT cbComment = 0;
771 USHORT cbSeparator = strlen(pcszSeparator);
772 while (us < usMVCount)
773 {
774 USHORT usEATypeThis = 0;
775 USHORT usEALenThis = 0;
776 PSZ pszSubItem = eaQueryMVItem(peab,
777 us, // index
778 NULL, // codepage
779 &usEATypeThis,
780 &usEALenThis);
781 if (!pszSubItem)
782 break;
783
784 if (usEATypeThis == EAT_ASCII)
785 {
786 if (usEALenThis)
787 {
788 PSZ pszTemp = pszTotal;
789 PSZ pTarget;
790 cbComment += usEALenThis + cbSeparator;
791 pszTotal = (PSZ)malloc(cbComment);
792 if (pszTemp)
793 {
794 // not first loop: append EA value
795 USHORT cbCommentOld = strlen(pszTemp);
796 // copy previous compiled string
797 strcpy(pszTotal, pszTemp);
798 // append separator
799 memcpy(pszTotal + cbCommentOld,
800 pcszSeparator,
801 cbSeparator);
802 // copy the rest after the separator (below)
803 pTarget = pszTotal + cbCommentOld + cbSeparator;
804 free(pszTemp);
805 }
806 else
807 // first loop: copy to beginning
808 pTarget = pszTotal;
809
810 // copy EA value
811 memcpy(pTarget, pszSubItem, usEALenThis);
812 // append null terminator
813 *(pTarget + usEALenThis) = 0;
814 }
815 } // if (usEATypeThis == EAT_ASCII)
816 us++;
817 } // end while (us < usMVCount)
818 } // end if (usMVCount)
819 }
820
821 return (pszTotal);
822}
823
824/*
825 *@@ eaCreateMVBindingFromPSZ:
826 * reverse to eaCreatePSZFromMVBinding, this
827 * parses pszInput and creates an EAT_MVMT
828 * EABINDING, all of whose subvalues are of
829 * EAT_ASCII. The EABINDING is non-critical
830 * (peab->bFlags = 0).
831 *
832 * pszSeparator is used in the analysis of pszInput
833 * as the separator string (e.g. "\r\n").
834 *
835 * Returns NULL if the given string is NULL.
836 *
837 * <B>Example:</B>
838 + PSZ pszInput = "Line 1\r\nLine2\r\nLine3\r\n";
839 + PEABINDING peab = eaCreateMVBindingFromPSZ(".KEYPHRASES",
840 + pszInput,
841 + "\r\n",
842 + 0); // codepage
843 * will create an EABINDING with the following pszValue:
844 + EAT_MVMT codp usCount (usDataType usLen data...)
845 + EAT_MVMT 0 3 EAT_ASCII 6 Line 1
846 + EAT_ASCII 5 Line2
847 + EAT_ASCII 5 Line3
848 *
849 *@@added V0.9.0 [umoeller]
850 */
851
852PEABINDING eaCreateMVBindingFromPSZ(const char *pcszEAName, // in: EA name (e.g. ".KEYPHRASES")
853 const char *pcszInput, // in: string to parse
854 const char *pcszSeparator, // in: separator used in pszInput
855 USHORT usCodepage) // in: codepage to set in EAT_MVMT
856{
857 PEABINDING peab = NULL;
858 if (pcszInput)
859 {
860 if ((peab = (PEABINDING)malloc(sizeof(EABINDING))))
861 {
862 const char *p = pcszInput,
863 *pSource;
864 PSZ pTarget;
865 USHORT cbInput = strlen(pcszInput),
866 cbSep = strlen(pcszSeparator),
867 usSepCount = 0,
868 cbToAlloc = 0,
869 cbThis,
870 us;
871
872 peab->bFlags = 0;
873 peab->bNameLength = strlen(pcszEAName);
874 peab->pszName = strdup(pcszEAName);
875
876 // now count the number of pszSeparators in pszInput
877 while ((p = strstr(p, pcszSeparator)))
878 {
879 usSepCount++;
880 p += cbSep;
881 }
882 // usSepCount now has the separator count; that means
883 // we have (usSepCount + 1) data fields
884
885 // allocate the memory we need for the total EA:
886 // EAT_MVMT usCodepage usCount (usDataType data... )...
887
888 cbToAlloc = 6 // six fixed bytes for (EAT_MVMT usCodepage usCount)
889 + cbInput - (usSepCount * cbSep)
890 // length of input string minus length of all separators
891 + ((usSepCount + 1) * 4);
892 // for each data field (of which we'll have (usSepCount + 1)),
893 // we need an extra four bytes for EAT_ASCII and the length
894 peab->usValueLength = cbToAlloc;
895 peab->pszValue = (PSZ)malloc(cbToAlloc + 1);
896
897 // now initialize the first three fields:
898 *((PUSHORT)(peab->pszValue)) = EAT_MVMT;
899 *((PUSHORT)(peab->pszValue + 2)) = usCodepage;
900 *((PUSHORT)(peab->pszValue + 4)) = (usSepCount + 1);
901
902 // set pointer to first field
903 pSource = pcszInput;
904 pTarget = peab->pszValue + 6;
905
906 // now go thru all fields except the last
907 for (us = 0;
908 us < usSepCount; // exclude the last field
909 us++)
910 {
911 // find the next separator
912 PSZ pNextSep = strstr(pSource, pcszSeparator);
913 // calculate the length of the substring
914 cbThis = pNextSep - pSource;
915 // set data type in field
916 *((PUSHORT)(pTarget)) = EAT_ASCII;
917 // set length of this field
918 *((PUSHORT)(pTarget + 2)) = cbThis;
919 // copy data
920 memcpy(pTarget + 4, pSource, cbThis);
921 // advance source to the next (after substring and separator)
922 pSource += cbThis + cbSep;
923 // advance target to the next (after substring and (EAT_ASCII usLen)
924 pTarget += cbThis + 4;
925 }
926
927 // now handle the last field
928 cbThis = strlen(pSource);
929 *((PUSHORT)(pTarget)) = EAT_ASCII;
930 *((PUSHORT)(pTarget + 2)) = cbThis;
931 memcpy(pTarget + 4, pSource, cbThis);
932 } // end if (peab)
933 } // end if (pszInput)
934
935 return (peab);
936}
937
938/********************************************************************
939 *
940 * EA helper funcs
941 *
942 ********************************************************************/
943
944/*
945 * These get called by the functions above.
946 *
947 */
948
949/*
950 *@@ ReadEAList:
951 *
952 */
953
954STATIC PEALIST ReadEAList(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
955 PVOID pfile)
956{
957 ULONG index = 1;
958 PEALIST head = 0;
959 PEALIST tail = 0;
960
961 while (1)
962 {
963 PEABINDING binding = (ReadEAByIndex(type, pfile, index));
964 if (binding == 0)
965 break;
966 {
967 PEALIST list = (PEALIST)malloc(sizeof(EALIST));
968 (EA_LIST_BINDING (list)) = binding;
969 (EA_LIST_NEXT (list)) = 0;
970 if (head == 0)
971 head = list;
972 else
973 (EA_LIST_NEXT (tail)) = list;
974 tail = list;
975 }
976 index += 1;
977 }
978 return (head);
979}
980
981/*
982 *@@ ReadEAByIndex:
983 *
984 */
985
986STATIC PEABINDING ReadEAByIndex(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
987 PVOID pfile,
988 ULONG index)
989{
990 PDENA2 dena = (ReadDenaByIndex(type, pfile, index));
991 return ((dena == 0)
992 ? 0
993 : (GetEAValue(type, pfile, dena)));
994}
995
996/*
997 *@@ ReadEAByName:
998 *
999 */
1000
1001STATIC PEABINDING ReadEAByName(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1002 PVOID pfile,
1003 PSZ name)
1004{
1005 ULONG index = 1;
1006 while (1)
1007 {
1008 PDENA2 dena = ReadDenaByIndex(type, pfile, index);
1009 if (dena == 0)
1010 return NULL;
1011 if ((strcmp(name, (dena->szName))) == 0)
1012 return (GetEAValue(type, pfile, dena));
1013 free(dena);
1014 index += 1;
1015 }
1016}
1017
1018/*
1019 *@@ ReadDenaByIndex:
1020 * fills a DENA2 structure by calling DosEnumAttribute.
1021 *
1022 * DENA2 is typedef'd to FEA2 in the OS/2 headers.
1023 * FEA2 defines the format for setting the full extended
1024 * attributes in the file.
1025 *
1026 + typedef struct _FEA2 {
1027 + ULONG oNextEntryOffset; // Offset to next entry.
1028 + BYTE fEA; // Extended attributes flag.
1029 + BYTE cbName; // Length of szName, not including NULL.
1030 + USHORT cbValue; // Value length.
1031 + CHAR szName[1]; // Extended attribute name.
1032 + } FEA2;
1033 + typedef FEA2 *PFEA2;
1034 *
1035 * Returns 0 on errors.
1036 *
1037 *@@changed V0.9.2 (2000-03-12) [umoeller]: added more error checking
1038 *@@changed V0.9.4 (2000-08-03) [umoeller]: added even more error checking; this fixed problems with swapper.dat and such
1039 */
1040
1041STATIC PDENA2 ReadDenaByIndex(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1042 PVOID pfile, // in: file handle or name
1043 ULONG index) // in: EA index (>= 1)
1044{
1045 ULONG count = 1;
1046 PDENA2 dena = (PDENA2)malloc(500); // 500 is magic -- IBM doesn't explain.
1047 APIRET arc = DosEnumAttribute(type,
1048 pfile,
1049 index,
1050 dena,
1051 500,
1052 (&count),
1053 ENUMEA_LEVEL_NO_VALUE);
1054 if ( (arc != NO_ERROR)
1055 || (count == 0) // check error code?
1056 )
1057 {
1058 free(dena);
1059 return (0);
1060 }
1061 else
1062 return (dena);
1063}
1064
1065/*
1066 *@@ GetEAValue:
1067 *
1068 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning NULL upon errors
1069 */
1070
1071STATIC PEABINDING GetEAValue(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1072 PVOID pfile, // in: file handle or path
1073 PDENA2 dena) // in: buffer allocated by ReadDenaByIndex
1074{
1075 ULONG level = FIL_QUERYEASFROMLIST;
1076 EAOP2 eaop;
1077 ULONG size = (sizeof(eaop));
1078 APIRET arc = NO_ERROR;
1079 SetupQueryEAInfo(dena, (&eaop));
1080 // this freeds dena
1081 if (type == ENUMEA_REFTYPE_FHANDLE)
1082 arc = DosQueryFileInfo((* ((PHFILE) pfile)), level, (&eaop), size);
1083 else
1084 arc = DosQueryPathInfo((PSZ)pfile, level, (&eaop), size);
1085 // changed V0.9.0 (99-11-28) [umoeller]; this now works with C
1086 free(eaop.fpGEA2List);
1087 if (arc == NO_ERROR)
1088 return (ConvertFeal2Binding(eaop.fpFEA2List));
1089 else
1090 return NULL;
1091}
1092
1093/*
1094 *@@ SetupQueryEAInfo:
1095 * prepares a EAOP2 structure for querying EAs.
1096 * This also frees dena, since it's no longer used.
1097 */
1098
1099STATIC void SetupQueryEAInfo(PDENA2 dena, // in: buffer allocated by ReadDenaByIndex
1100 PEAOP2 eaop) // out: EAOP2 to fill
1101{
1102 unsigned int geal_size = ((sizeof (GEA2LIST)) + (dena->cbName));
1103 unsigned int feal_size
1104 = ((sizeof (FEA2LIST)) + (dena->cbName) + (dena->cbValue));
1105 (eaop->fpGEA2List) = (GEA2LIST*)(malloc(geal_size));
1106 ((eaop->fpGEA2List)->cbList) = geal_size;
1107 (eaop->fpFEA2List) = (FEA2LIST*)(malloc(feal_size));
1108 ((eaop->fpFEA2List)->cbList) = feal_size;
1109 (eaop->oError) = 0;
1110 {
1111 PGEA2 gea = (&(((eaop->fpGEA2List)->list) [0]));
1112 (gea->oNextEntryOffset) = 0;
1113 (gea->cbName) = (dena->cbName);
1114 strcpy ((gea->szName), (dena->szName));
1115 }
1116 free(dena);
1117}
1118
1119/*
1120 *@@ ConvertFeal2Binding:
1121 * creates a new EABINDING from the given FEA2LIST
1122 * and frees feal. Returns NULL upon errors.
1123 *
1124 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning NULL upon errors
1125 */
1126
1127STATIC PEABINDING ConvertFeal2Binding(PFEA2LIST feal)
1128{
1129 PFEA2 fea = (&((feal->list) [0]));
1130 PEABINDING binding = (PEABINDING)(malloc(sizeof (EABINDING)));
1131 if (binding)
1132 {
1133 (EA_BINDING_FLAGS (binding)) = (fea->fEA);
1134 (EA_BINDING_NAME_LENGTH (binding)) = (fea->cbName);
1135 (EA_BINDING_VALUE_LENGTH (binding)) = (fea->cbValue);
1136 (EA_BINDING_NAME (binding)) = (PSZ)(malloc((fea->cbName) + 1));
1137 strcpy ((EA_BINDING_NAME (binding)), (fea->szName));
1138 (EA_BINDING_VALUE (binding)) = (PSZ)(malloc(fea->cbValue));
1139 memcpy ((EA_BINDING_VALUE (binding)),
1140 (&((fea->szName) [(fea->cbName) + 1])),
1141 (fea->cbValue));
1142 free(feal);
1143 }
1144 return (binding);
1145}
1146
1147/*
1148 *@@ WriteEAList:
1149 *
1150 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning APIRET
1151 */
1152
1153STATIC APIRET WriteEAList(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1154 PVOID pfile,
1155 PEALIST list)
1156{
1157 APIRET arc = NO_ERROR;
1158 while ( (list != 0)
1159 && (arc == NO_ERROR)
1160 )
1161 {
1162 arc = WriteEA(type, pfile, (EA_LIST_BINDING (list)));
1163 list = (EA_LIST_NEXT (list));
1164 }
1165
1166 return arc;
1167}
1168
1169/*
1170 *@@ WriteEA:
1171 *
1172 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning APIRET
1173 */
1174
1175STATIC APIRET WriteEA(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1176 PVOID pfile,
1177 PEABINDING binding)
1178{
1179 ULONG level = FIL_QUERYEASIZE;
1180 EAOP2 eaop;
1181 ULONG size = (sizeof (eaop));
1182 APIRET arc = NO_ERROR;
1183
1184 (eaop.fpGEA2List) = 0;
1185 (eaop.fpFEA2List) = (ConvertBinding2Feal(binding));
1186 (eaop.oError) = 0;
1187 if (type == ENUMEA_REFTYPE_FHANDLE)
1188 arc = DosSetFileInfo((* ((PHFILE) pfile)), level, (&eaop), size);
1189 else
1190 arc = DosSetPathInfo((PSZ)pfile, level, (&eaop), size, DSPI_WRTTHRU);
1191 free(eaop.fpFEA2List);
1192 return arc;
1193}
1194
1195/*
1196 *@@ ConvertBinding2Feal:
1197 *
1198 */
1199
1200STATIC PFEA2LIST ConvertBinding2Feal(PEABINDING binding)
1201{
1202 unsigned int feal_size
1203 = ((sizeof (FEA2LIST))
1204 + (EA_BINDING_NAME_LENGTH (binding))
1205 + (EA_BINDING_VALUE_LENGTH (binding)));
1206 PFEA2LIST feal = (PFEA2LIST)(malloc(feal_size));
1207 PFEA2 fea = (&((feal->list) [0]));
1208 (feal->cbList) = feal_size;
1209 (fea->oNextEntryOffset) = 0;
1210 (fea->fEA) = (EA_BINDING_FLAGS (binding));
1211 (fea->cbName) = (EA_BINDING_NAME_LENGTH (binding));
1212 (fea->cbValue) = (EA_BINDING_VALUE_LENGTH (binding));
1213 strcpy ((fea->szName), (EA_BINDING_NAME (binding)));
1214 if ((EA_BINDING_VALUE (binding)) != 0)
1215 memcpy ((&((fea->szName) [(fea->cbName) + 1])),
1216 (EA_BINDING_VALUE (binding)),
1217 (fea->cbValue));
1218 return (feal);
1219}
1220
1221/* ******************************************************************
1222 *
1223 * Direct plain-string EA handling
1224 *
1225 ********************************************************************/
1226
1227#define USE_EAMVMT 1
1228
1229/*
1230 * eahWriteStringEA:
1231 *
1232 * (C) Christian Langanke. Moved this here from tmsgfile.c.
1233 *
1234 *@@added V0.9.3 (2000-05-21) [umoeller]
1235 */
1236
1237APIRET eahWriteStringEA(HFILE hfile,
1238 PSZ pszEaName,
1239 PSZ pszEaValue)
1240{
1241
1242 APIRET rc = NO_ERROR;
1243 PFEA2LIST pfea2l = NULL;
1244
1245#ifdef USE_EAMVMT
1246 PEAMVMT peamvmt;
1247#else
1248 PEASVST peasvst;
1249#endif
1250 ULONG ulEAListLen;
1251 ULONG ulValueLen;
1252 EAOP2 eaop2;
1253
1254 // PSZ pszValue;
1255
1256 do
1257 {
1258 // check parameters
1259 if ( (hfile == NULLHANDLE)
1260 || (pszEaName == NULL)
1261 || (*pszEaName == 0)
1262 || (pszEaValue == NULL)
1263 )
1264 {
1265 rc = ERROR_INVALID_PARAMETER;
1266 break;
1267 }
1268
1269 // write EAs
1270 ulValueLen = strlen(pszEaValue) +
1271#ifdef USE_EAMVMT
1272 sizeof(EAMVMT);
1273#else
1274 sizeof(EASVST);
1275#endif
1276
1277 ulEAListLen = strlen(pszEaName) +
1278 sizeof(FEA2LIST) +
1279 ulValueLen;
1280
1281 // get memory for FEA2LIST
1282 pfea2l = (FEA2LIST*)malloc(ulEAListLen);
1283 if (pfea2l == 0)
1284 {
1285 rc = ERROR_NOT_ENOUGH_MEMORY;
1286 break;
1287 }
1288
1289 // init FEA2LIST
1290 eaop2.fpGEA2List = NULL;
1291 eaop2.fpFEA2List = pfea2l;
1292 memset(pfea2l, 0, ulEAListLen);
1293
1294 // write timeframe EA
1295 pfea2l->cbList = ulEAListLen;
1296 pfea2l->list[0].cbName = strlen(pszEaName);
1297 strcpy(pfea2l->list[0].szName, pszEaName);
1298
1299 // delete attribute if value empty
1300 if (strlen(pszEaValue) == 0)
1301 pfea2l->list[0].cbValue = 0;
1302 else
1303 {
1304 pfea2l->list[0].cbValue = ulValueLen;
1305
1306#ifdef USE_EAMVMT
1307 // multi value multi type
1308 peamvmt = (PEAMVMT) NEXTSTR(pfea2l->list[0].szName);
1309 peamvmt->usType = EAT_MVMT;
1310 peamvmt->usCodepage = 0;
1311 peamvmt->usEntries = 1;
1312 peamvmt->usEntryType = EAT_ASCII;
1313 peamvmt->usEntryLen = strlen(pszEaValue);
1314 memcpy(&peamvmt->chEntry[0], pszEaValue, peamvmt->usEntryLen);
1315#else
1316 // single value single type
1317 peasvst = NEXTSTR(pfea2l->list[0].szName);
1318 peasvst->usType = EAT_ASCII;
1319 peasvst->usEntryLen = strlen(pszEaValue);
1320 memcpy(&peasvst->chEntry[0], pszEaValue, peasvst->usEntryLen);
1321#endif
1322 }
1323
1324 // set the new EA value
1325 rc = DosSetFileInfo(hfile,
1326 FIL_QUERYEASIZE,
1327 &eaop2,
1328 sizeof(eaop2));
1329
1330 }
1331 while (FALSE);
1332
1333// cleanup
1334 if (pfea2l)
1335 free(pfea2l);
1336 return rc;
1337}
1338
1339/*
1340 * eahReadStringEA:
1341 *
1342 * (C) Christian Langanke. Moved this here from tmsgfile.c.
1343 *
1344 *@@added V0.9.3 (2000-05-21) [umoeller]
1345 */
1346
1347APIRET eahReadStringEA(PSZ pszFileName,
1348 PSZ pszEaName,
1349 PSZ pszBuffer,
1350 PULONG pulBuflen)
1351{
1352
1353 APIRET rc = NO_ERROR;
1354 FILESTATUS4 fs4;
1355
1356 EAOP2 eaop2;
1357 PGEA2LIST pgea2l = NULL;
1358 PFEA2LIST pfea2l = NULL;
1359
1360 PGEA2 pgea2;
1361 PFEA2 pfea2;
1362
1363 ULONG ulGea2Len = 0;
1364 ULONG ulFea2Len = 0;
1365
1366 PEASVST peasvst;
1367 PEAMVMT peamvmt;
1368
1369 ULONG ulRequiredLen;
1370
1371 do
1372 {
1373 // check parameters
1374 if ((pszFileName == NULL) ||
1375 (pszEaName == NULL) ||
1376 (*pszEaName == 0) ||
1377 (pulBuflen == NULL))
1378 {
1379 rc = ERROR_INVALID_PARAMETER;
1380 break;
1381 }
1382
1383 // initialize target buffer
1384 if (pszBuffer)
1385 memset(pszBuffer, 0, *pulBuflen);
1386
1387 // get EA size
1388 rc = DosQueryPathInfo(pszFileName,
1389 FIL_QUERYEASIZE,
1390 &fs4,
1391 sizeof(fs4));
1392 if (rc != NO_ERROR)
1393 break;
1394
1395 // no eas here ?
1396 if (fs4.cbList == 0)
1397 {
1398 pulBuflen = 0;
1399 break;
1400 }
1401
1402 // determine required space
1403 // - for ulFea2Len use at least 2 * Gea2Len because
1404 // buffer needs at least to be Geal2Len even for an empty
1405 // attribute, otherwise rc == ERROR_BUFFER_OVERFLOW !
1406 ulGea2Len = sizeof(GEA2LIST) + strlen(pszEaName);
1407 ulFea2Len = 2 * MAX(fs4.cbList, ulGea2Len);
1408
1409 // get memory for GEA2LIST
1410 if ((pgea2l = (GEA2LIST*)malloc(ulGea2Len)) == 0)
1411 {
1412 rc = ERROR_NOT_ENOUGH_MEMORY;
1413 break;
1414 }
1415 memset(pgea2l, 0, ulGea2Len);
1416
1417 // get memory for FEA2LIST
1418 if ((pfea2l = (FEA2LIST*)malloc(ulFea2Len)) == 0)
1419 {
1420 rc = ERROR_NOT_ENOUGH_MEMORY;
1421 break;
1422 }
1423 memset(pfea2l, 0, ulFea2Len);
1424
1425 // init ptrs and do the query
1426 memset(&eaop2, 0, sizeof(EAOP2));
1427 eaop2.fpGEA2List = pgea2l;
1428 eaop2.fpFEA2List = pfea2l;
1429 pfea2l->cbList = ulFea2Len;
1430 pgea2l->cbList = ulGea2Len;
1431
1432 pgea2 = &pgea2l->list[0];
1433 pfea2 = &pfea2l->list[0];
1434
1435
1436 pgea2->oNextEntryOffset = 0;
1437 pgea2->cbName = strlen(pszEaName);
1438 strcpy(pgea2->szName, pszEaName);
1439
1440 rc = DosQueryPathInfo(pszFileName,
1441 FIL_QUERYEASFROMLIST,
1442 &eaop2,
1443 sizeof(eaop2));
1444 if (rc != NO_ERROR)
1445 break;
1446
1447 // check first entry only
1448 peamvmt = (PEAMVMT) ((PBYTE) pfea2->szName + pfea2->cbName + 1);
1449
1450 // is it MVMT ? then adress single EA !
1451 if (peamvmt->usType == EAT_MVMT)
1452 {
1453 peasvst = (PEASVST) & peamvmt->usEntryType;
1454 }
1455 else
1456 peasvst = (PEASVST) peamvmt;
1457
1458
1459 // is entry empty ?
1460 if (peasvst->usEntryLen == 0)
1461 {
1462 rc = ERROR_INVALID_EA_NAME;
1463 break;
1464 }
1465
1466 // is it ASCII ?
1467 if (peasvst->usType != EAT_ASCII)
1468 {
1469 rc = ERROR_INVALID_DATA;
1470 break;
1471 }
1472
1473 // check buffer and hand over value
1474 ulRequiredLen = peasvst->usEntryLen + 1;
1475 if (*pulBuflen < ulRequiredLen)
1476 {
1477 *pulBuflen = ulRequiredLen;
1478 rc = ERROR_BUFFER_OVERFLOW;
1479 break;
1480 }
1481
1482 // hand over len
1483 *pulBuflen = ulRequiredLen;
1484
1485 // hand over value
1486 if (pszBuffer)
1487 memcpy(pszBuffer, peasvst->chEntry, peasvst->usEntryLen);
1488
1489 }
1490 while (FALSE);
1491
1492// cleanup
1493 if (pgea2l)
1494 free(pgea2l);
1495 if (pfea2l)
1496 free(pfea2l);
1497 return rc;
1498}
1499
1500
Note: See TracBrowser for help on using the repository browser.