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

Last change on this file since 53 was 21, checked in by umoeller, 25 years ago

Final changes for 0.9.7, i hope...

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