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

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

Misc fixes.

  • 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
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
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
1145 return binding;
1146}
1147
1148/*
1149 *@@ WriteEAList:
1150 *
1151 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning APIRET
1152 */
1153
1154STATIC APIRET WriteEAList(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1155 PVOID pfile,
1156 PEALIST list)
1157{
1158 APIRET arc = NO_ERROR;
1159 while ( (list != 0)
1160 && (arc == NO_ERROR)
1161 )
1162 {
1163 arc = WriteEA(type, pfile, (EA_LIST_BINDING (list)));
1164 list = (EA_LIST_NEXT (list));
1165 }
1166
1167 return arc;
1168}
1169
1170/*
1171 *@@ WriteEA:
1172 *
1173 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning APIRET
1174 */
1175
1176STATIC APIRET WriteEA(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1177 PVOID pfile,
1178 PEABINDING binding)
1179{
1180 ULONG level = FIL_QUERYEASIZE;
1181 EAOP2 eaop;
1182 ULONG size = (sizeof (eaop));
1183 APIRET arc = NO_ERROR;
1184
1185 (eaop.fpGEA2List) = 0;
1186 (eaop.fpFEA2List) = (ConvertBinding2Feal(binding));
1187 (eaop.oError) = 0;
1188 if (type == ENUMEA_REFTYPE_FHANDLE)
1189 arc = DosSetFileInfo((* ((PHFILE) pfile)), level, (&eaop), size);
1190 else
1191 arc = DosSetPathInfo((PSZ)pfile, level, (&eaop), size, DSPI_WRTTHRU);
1192 free(eaop.fpFEA2List);
1193 return arc;
1194}
1195
1196/*
1197 *@@ ConvertBinding2Feal:
1198 *
1199 */
1200
1201STATIC PFEA2LIST ConvertBinding2Feal(PEABINDING binding)
1202{
1203 unsigned int feal_size
1204 = ((sizeof (FEA2LIST))
1205 + (EA_BINDING_NAME_LENGTH (binding))
1206 + (EA_BINDING_VALUE_LENGTH (binding)));
1207 PFEA2LIST feal = (PFEA2LIST)(malloc(feal_size));
1208 PFEA2 fea = (&((feal->list) [0]));
1209 (feal->cbList) = feal_size;
1210 (fea->oNextEntryOffset) = 0;
1211 (fea->fEA) = (EA_BINDING_FLAGS (binding));
1212 (fea->cbName) = (EA_BINDING_NAME_LENGTH (binding));
1213 (fea->cbValue) = (EA_BINDING_VALUE_LENGTH (binding));
1214 strcpy ((fea->szName), (EA_BINDING_NAME (binding)));
1215 if ((EA_BINDING_VALUE (binding)) != 0)
1216 memcpy ((&((fea->szName) [(fea->cbName) + 1])),
1217 (EA_BINDING_VALUE (binding)),
1218 (fea->cbValue));
1219 return feal;
1220}
1221
1222/* ******************************************************************
1223 *
1224 * Direct plain-string EA handling
1225 *
1226 ********************************************************************/
1227
1228#define USE_EAMVMT 1
1229
1230/*
1231 * eahWriteStringEA:
1232 *
1233 * (C) Christian Langanke. Moved this here from tmsgfile.c.
1234 *
1235 *@@added V0.9.3 (2000-05-21) [umoeller]
1236 */
1237
1238APIRET eahWriteStringEA(HFILE hfile,
1239 PSZ pszEaName,
1240 PSZ pszEaValue)
1241{
1242
1243 APIRET rc = NO_ERROR;
1244 PFEA2LIST pfea2l = NULL;
1245
1246#ifdef USE_EAMVMT
1247 PEAMVMT peamvmt;
1248#else
1249 PEASVST peasvst;
1250#endif
1251 ULONG ulEAListLen;
1252 ULONG ulValueLen;
1253 EAOP2 eaop2;
1254
1255 // PSZ pszValue;
1256
1257 do
1258 {
1259 // check parameters
1260 if ( (hfile == NULLHANDLE)
1261 || (pszEaName == NULL)
1262 || (*pszEaName == 0)
1263 || (pszEaValue == NULL)
1264 )
1265 {
1266 rc = ERROR_INVALID_PARAMETER;
1267 break;
1268 }
1269
1270 // write EAs
1271 ulValueLen = strlen(pszEaValue) +
1272#ifdef USE_EAMVMT
1273 sizeof(EAMVMT);
1274#else
1275 sizeof(EASVST);
1276#endif
1277
1278 ulEAListLen = strlen(pszEaName) +
1279 sizeof(FEA2LIST) +
1280 ulValueLen;
1281
1282 // get memory for FEA2LIST
1283 pfea2l = (FEA2LIST*)malloc(ulEAListLen);
1284 if (pfea2l == 0)
1285 {
1286 rc = ERROR_NOT_ENOUGH_MEMORY;
1287 break;
1288 }
1289
1290 // init FEA2LIST
1291 eaop2.fpGEA2List = NULL;
1292 eaop2.fpFEA2List = pfea2l;
1293 memset(pfea2l, 0, ulEAListLen);
1294
1295 // write timeframe EA
1296 pfea2l->cbList = ulEAListLen;
1297 pfea2l->list[0].cbName = strlen(pszEaName);
1298 strcpy(pfea2l->list[0].szName, pszEaName);
1299
1300 // delete attribute if value empty
1301 if (strlen(pszEaValue) == 0)
1302 pfea2l->list[0].cbValue = 0;
1303 else
1304 {
1305 pfea2l->list[0].cbValue = ulValueLen;
1306
1307#ifdef USE_EAMVMT
1308 // multi value multi type
1309 peamvmt = (PEAMVMT) NEXTSTR(pfea2l->list[0].szName);
1310 peamvmt->usType = EAT_MVMT;
1311 peamvmt->usCodepage = 0;
1312 peamvmt->usEntries = 1;
1313 peamvmt->usEntryType = EAT_ASCII;
1314 peamvmt->usEntryLen = strlen(pszEaValue);
1315 memcpy(&peamvmt->chEntry[0], pszEaValue, peamvmt->usEntryLen);
1316#else
1317 // single value single type
1318 peasvst = NEXTSTR(pfea2l->list[0].szName);
1319 peasvst->usType = EAT_ASCII;
1320 peasvst->usEntryLen = strlen(pszEaValue);
1321 memcpy(&peasvst->chEntry[0], pszEaValue, peasvst->usEntryLen);
1322#endif
1323 }
1324
1325 // set the new EA value
1326 rc = DosSetFileInfo(hfile,
1327 FIL_QUERYEASIZE,
1328 &eaop2,
1329 sizeof(eaop2));
1330
1331 }
1332 while (FALSE);
1333
1334// cleanup
1335 if (pfea2l)
1336 free(pfea2l);
1337 return rc;
1338}
1339
1340/*
1341 * eahReadStringEA:
1342 *
1343 * (C) Christian Langanke. Moved this here from tmsgfile.c.
1344 *
1345 *@@added V0.9.3 (2000-05-21) [umoeller]
1346 */
1347
1348APIRET eahReadStringEA(PSZ pszFileName,
1349 PSZ pszEaName,
1350 PSZ pszBuffer,
1351 PULONG pulBuflen)
1352{
1353
1354 APIRET rc = NO_ERROR;
1355 FILESTATUS4 fs4;
1356
1357 EAOP2 eaop2;
1358 PGEA2LIST pgea2l = NULL;
1359 PFEA2LIST pfea2l = NULL;
1360
1361 PGEA2 pgea2;
1362 PFEA2 pfea2;
1363
1364 ULONG ulGea2Len = 0;
1365 ULONG ulFea2Len = 0;
1366
1367 PEASVST peasvst;
1368 PEAMVMT peamvmt;
1369
1370 ULONG ulRequiredLen;
1371
1372 do
1373 {
1374 // check parameters
1375 if ((pszFileName == NULL) ||
1376 (pszEaName == NULL) ||
1377 (*pszEaName == 0) ||
1378 (pulBuflen == NULL))
1379 {
1380 rc = ERROR_INVALID_PARAMETER;
1381 break;
1382 }
1383
1384 // initialize target buffer
1385 if (pszBuffer)
1386 memset(pszBuffer, 0, *pulBuflen);
1387
1388 // get EA size
1389 rc = DosQueryPathInfo(pszFileName,
1390 FIL_QUERYEASIZE,
1391 &fs4,
1392 sizeof(fs4));
1393 if (rc != NO_ERROR)
1394 break;
1395
1396 // no eas here ?
1397 if (fs4.cbList == 0)
1398 {
1399 pulBuflen = 0;
1400 break;
1401 }
1402
1403 // determine required space
1404 // - for ulFea2Len use at least 2 * Gea2Len because
1405 // buffer needs at least to be Geal2Len even for an empty
1406 // attribute, otherwise rc == ERROR_BUFFER_OVERFLOW !
1407 ulGea2Len = sizeof(GEA2LIST) + strlen(pszEaName);
1408 ulFea2Len = 2 * MAX(fs4.cbList, ulGea2Len);
1409
1410 // get memory for GEA2LIST
1411 if ((pgea2l = (GEA2LIST*)malloc(ulGea2Len)) == 0)
1412 {
1413 rc = ERROR_NOT_ENOUGH_MEMORY;
1414 break;
1415 }
1416 memset(pgea2l, 0, ulGea2Len);
1417
1418 // get memory for FEA2LIST
1419 if ((pfea2l = (FEA2LIST*)malloc(ulFea2Len)) == 0)
1420 {
1421 rc = ERROR_NOT_ENOUGH_MEMORY;
1422 break;
1423 }
1424 memset(pfea2l, 0, ulFea2Len);
1425
1426 // init ptrs and do the query
1427 memset(&eaop2, 0, sizeof(EAOP2));
1428 eaop2.fpGEA2List = pgea2l;
1429 eaop2.fpFEA2List = pfea2l;
1430 pfea2l->cbList = ulFea2Len;
1431 pgea2l->cbList = ulGea2Len;
1432
1433 pgea2 = &pgea2l->list[0];
1434 pfea2 = &pfea2l->list[0];
1435
1436
1437 pgea2->oNextEntryOffset = 0;
1438 pgea2->cbName = strlen(pszEaName);
1439 strcpy(pgea2->szName, pszEaName);
1440
1441 rc = DosQueryPathInfo(pszFileName,
1442 FIL_QUERYEASFROMLIST,
1443 &eaop2,
1444 sizeof(eaop2));
1445 if (rc != NO_ERROR)
1446 break;
1447
1448 // check first entry only
1449 peamvmt = (PEAMVMT) ((PBYTE) pfea2->szName + pfea2->cbName + 1);
1450
1451 // is it MVMT ? then adress single EA !
1452 if (peamvmt->usType == EAT_MVMT)
1453 {
1454 peasvst = (PEASVST) & peamvmt->usEntryType;
1455 }
1456 else
1457 peasvst = (PEASVST) peamvmt;
1458
1459
1460 // is entry empty ?
1461 if (peasvst->usEntryLen == 0)
1462 {
1463 rc = ERROR_INVALID_EA_NAME;
1464 break;
1465 }
1466
1467 // is it ASCII ?
1468 if (peasvst->usType != EAT_ASCII)
1469 {
1470 rc = ERROR_INVALID_DATA;
1471 break;
1472 }
1473
1474 // check buffer and hand over value
1475 ulRequiredLen = peasvst->usEntryLen + 1;
1476 if (*pulBuflen < ulRequiredLen)
1477 {
1478 *pulBuflen = ulRequiredLen;
1479 rc = ERROR_BUFFER_OVERFLOW;
1480 break;
1481 }
1482
1483 // hand over len
1484 *pulBuflen = ulRequiredLen;
1485
1486 // hand over value
1487 if (pszBuffer)
1488 memcpy(pszBuffer, peasvst->chEntry, peasvst->usEntryLen);
1489
1490 }
1491 while (FALSE);
1492
1493// cleanup
1494 if (pgea2l)
1495 free(pgea2l);
1496 if (pfea2l)
1497 free(pfea2l);
1498 return rc;
1499}
1500
1501
Note: See TracBrowser for help on using the repository browser.