source: trunk/src/helpers/eah.c@ 13

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

Initial checkin of helpers code which used to be in WarpIN.

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