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

Last change on this file since 108 was 108, checked in by umoeller, 24 years ago

Lots of updates from the last week for conditional compiles and other stuff.

  • 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 = NULL;
860 if (pcszInput)
861 {
862 if ((peab = (PEABINDING)malloc(sizeof(EABINDING))))
863 {
864 const char *p = pcszInput,
865 *pSource;
866 PSZ pTarget;
867 USHORT cbInput = strlen(pcszInput),
868 cbSep = strlen(pcszSeparator),
869 usSepCount = 0,
870 cbToAlloc = 0,
871 cbThis,
872 us;
873
874 peab->bFlags = 0;
875 peab->bNameLength = strlen(pcszEAName);
876 peab->pszName = strdup(pcszEAName);
877
878 // now count the number of pszSeparators in pszInput
879 while ((p = strstr(p, pcszSeparator)))
880 {
881 usSepCount++;
882 p += cbSep;
883 }
884 // usSepCount now has the separator count; that means
885 // we have (usSepCount + 1) data fields
886
887 // allocate the memory we need for the total EA:
888 // EAT_MVMT usCodepage usCount (usDataType data... )...
889
890 cbToAlloc = 6 // six fixed bytes for (EAT_MVMT usCodepage usCount)
891 + cbInput - (usSepCount * cbSep)
892 // length of input string minus length of all separators
893 + ((usSepCount + 1) * 4);
894 // for each data field (of which we'll have (usSepCount + 1)),
895 // we need an extra four bytes for EAT_ASCII and the length
896 peab->usValueLength = cbToAlloc;
897 peab->pszValue = (PSZ)malloc(cbToAlloc + 1);
898
899 // now initialize the first three fields:
900 *((PUSHORT)(peab->pszValue)) = EAT_MVMT;
901 *((PUSHORT)(peab->pszValue + 2)) = usCodepage;
902 *((PUSHORT)(peab->pszValue + 4)) = (usSepCount + 1);
903
904 // set pointer to first field
905 pSource = pcszInput;
906 pTarget = peab->pszValue + 6;
907
908 // now go thru all fields except the last
909 for (us = 0;
910 us < usSepCount; // exclude the last field
911 us++)
912 {
913 // find the next separator
914 PSZ pNextSep = strstr(pSource, pcszSeparator);
915 // calculate the length of the substring
916 cbThis = pNextSep - pSource;
917 // set data type in field
918 *((PUSHORT)(pTarget)) = EAT_ASCII;
919 // set length of this field
920 *((PUSHORT)(pTarget + 2)) = cbThis;
921 // copy data
922 memcpy(pTarget + 4, pSource, cbThis);
923 // advance source to the next (after substring and separator)
924 pSource += cbThis + cbSep;
925 // advance target to the next (after substring and (EAT_ASCII usLen)
926 pTarget += cbThis + 4;
927 }
928
929 // now handle the last field
930 cbThis = strlen(pSource);
931 *((PUSHORT)(pTarget)) = EAT_ASCII;
932 *((PUSHORT)(pTarget + 2)) = cbThis;
933 memcpy(pTarget + 4, pSource, cbThis);
934 } // end if (peab)
935 } // end if (pszInput)
936
937 return (peab);
938}
939
940/********************************************************************
941 *
942 * EA helper funcs
943 *
944 ********************************************************************/
945
946/*
947 * These get called by the functions above.
948 *
949 */
950
951/*
952 *@@ ReadEAList:
953 *
954 */
955
956static PEALIST ReadEAList(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
957 PVOID pfile)
958{
959 ULONG index = 1;
960 PEALIST head = 0;
961 PEALIST tail = 0;
962
963 while (1)
964 {
965 PEABINDING binding = (ReadEAByIndex(type, pfile, index));
966 if (binding == 0)
967 break;
968 {
969 PEALIST list = (PEALIST)malloc(sizeof(EALIST));
970 (EA_LIST_BINDING (list)) = binding;
971 (EA_LIST_NEXT (list)) = 0;
972 if (head == 0)
973 head = list;
974 else
975 (EA_LIST_NEXT (tail)) = list;
976 tail = list;
977 }
978 index += 1;
979 }
980 return (head);
981}
982
983/*
984 *@@ ReadEAByIndex:
985 *
986 */
987
988static PEABINDING ReadEAByIndex(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
989 PVOID pfile,
990 ULONG index)
991{
992 PDENA2 dena = (ReadDenaByIndex(type, pfile, index));
993 return ((dena == 0)
994 ? 0
995 : (GetEAValue(type, pfile, dena)));
996}
997
998/*
999 *@@ ReadEAByName:
1000 *
1001 */
1002
1003static PEABINDING ReadEAByName(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1004 PVOID pfile,
1005 PSZ name)
1006{
1007 ULONG index = 1;
1008 while (1)
1009 {
1010 PDENA2 dena = ReadDenaByIndex(type, pfile, index);
1011 if (dena == 0)
1012 return (NULL);
1013 if ((strcmp(name, (dena->szName))) == 0)
1014 return (GetEAValue(type, pfile, dena));
1015 free(dena);
1016 index += 1;
1017 }
1018}
1019
1020/*
1021 *@@ ReadDenaByIndex:
1022 * fills a DENA2 structure by calling DosEnumAttribute.
1023 *
1024 * DENA2 is typedef'd to FEA2 in the OS/2 headers.
1025 * FEA2 defines the format for setting the full extended
1026 * attributes in the file.
1027 *
1028 + typedef struct _FEA2 {
1029 + ULONG oNextEntryOffset; // Offset to next entry.
1030 + BYTE fEA; // Extended attributes flag.
1031 + BYTE cbName; // Length of szName, not including NULL.
1032 + USHORT cbValue; // Value length.
1033 + CHAR szName[1]; // Extended attribute name.
1034 + } FEA2;
1035 + typedef FEA2 *PFEA2;
1036 *
1037 * Returns 0 on errors.
1038 *
1039 *@@changed V0.9.2 (2000-03-12) [umoeller]: added more error checking
1040 *@@changed V0.9.4 (2000-08-03) [umoeller]: added even more error checking; this fixed problems with swapper.dat and such
1041 */
1042
1043static PDENA2 ReadDenaByIndex(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1044 PVOID pfile, // in: file handle or name
1045 ULONG index) // in: EA index (>= 1)
1046{
1047 ULONG count = 1;
1048 PDENA2 dena = (PDENA2)malloc(500); // 500 is magic -- IBM doesn't explain.
1049 APIRET arc = DosEnumAttribute(type,
1050 pfile,
1051 index,
1052 dena,
1053 500,
1054 (&count),
1055 ENUMEA_LEVEL_NO_VALUE);
1056 if ( (arc != NO_ERROR)
1057 || (count == 0) // check error code?
1058 )
1059 {
1060 free(dena);
1061 return (0);
1062 }
1063 else
1064 return (dena);
1065}
1066
1067/*
1068 *@@ GetEAValue:
1069 *
1070 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning NULL upon errors
1071 */
1072
1073static PEABINDING GetEAValue(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1074 PVOID pfile, // in: file handle or path
1075 PDENA2 dena) // in: buffer allocated by ReadDenaByIndex
1076{
1077 ULONG level = FIL_QUERYEASFROMLIST;
1078 EAOP2 eaop;
1079 ULONG size = (sizeof(eaop));
1080 APIRET arc = NO_ERROR;
1081 SetupQueryEAInfo(dena, (&eaop));
1082 // this freeds dena
1083 if (type == ENUMEA_REFTYPE_FHANDLE)
1084 arc = DosQueryFileInfo((* ((PHFILE) pfile)), level, (&eaop), size);
1085 else
1086 arc = DosQueryPathInfo((PSZ)pfile, level, (&eaop), size);
1087 // changed V0.9.0 (99-11-28) [umoeller]; this now works with C
1088 free(eaop.fpGEA2List);
1089 if (arc == NO_ERROR)
1090 return (ConvertFeal2Binding(eaop.fpFEA2List));
1091 else
1092 return (NULL);
1093}
1094
1095/*
1096 *@@ SetupQueryEAInfo:
1097 * prepares a EAOP2 structure for querying EAs.
1098 * This also frees dena, since it's no longer used.
1099 */
1100
1101static void SetupQueryEAInfo(PDENA2 dena, // in: buffer allocated by ReadDenaByIndex
1102 PEAOP2 eaop) // out: EAOP2 to fill
1103{
1104 unsigned int geal_size = ((sizeof (GEA2LIST)) + (dena->cbName));
1105 unsigned int feal_size
1106 = ((sizeof (FEA2LIST)) + (dena->cbName) + (dena->cbValue));
1107 (eaop->fpGEA2List) = (GEA2LIST*)(malloc(geal_size));
1108 ((eaop->fpGEA2List)->cbList) = geal_size;
1109 (eaop->fpFEA2List) = (FEA2LIST*)(malloc(feal_size));
1110 ((eaop->fpFEA2List)->cbList) = feal_size;
1111 (eaop->oError) = 0;
1112 {
1113 PGEA2 gea = (&(((eaop->fpGEA2List)->list) [0]));
1114 (gea->oNextEntryOffset) = 0;
1115 (gea->cbName) = (dena->cbName);
1116 strcpy ((gea->szName), (dena->szName));
1117 }
1118 free(dena);
1119}
1120
1121/*
1122 *@@ ConvertFeal2Binding:
1123 * creates a new EABINDING from the given FEA2LIST
1124 * and frees feal. Returns NULL upon errors.
1125 *
1126 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning NULL upon errors
1127 */
1128
1129static PEABINDING ConvertFeal2Binding(PFEA2LIST feal)
1130{
1131 PFEA2 fea = (&((feal->list) [0]));
1132 PEABINDING binding = (PEABINDING)(malloc(sizeof (EABINDING)));
1133 if (binding)
1134 {
1135 (EA_BINDING_FLAGS (binding)) = (fea->fEA);
1136 (EA_BINDING_NAME_LENGTH (binding)) = (fea->cbName);
1137 (EA_BINDING_VALUE_LENGTH (binding)) = (fea->cbValue);
1138 (EA_BINDING_NAME (binding)) = (PSZ)(malloc((fea->cbName) + 1));
1139 strcpy ((EA_BINDING_NAME (binding)), (fea->szName));
1140 (EA_BINDING_VALUE (binding)) = (PSZ)(malloc(fea->cbValue));
1141 memcpy ((EA_BINDING_VALUE (binding)),
1142 (&((fea->szName) [(fea->cbName) + 1])),
1143 (fea->cbValue));
1144 free(feal);
1145 }
1146 return (binding);
1147}
1148
1149/*
1150 *@@ WriteEAList:
1151 *
1152 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning APIRET
1153 */
1154
1155static APIRET WriteEAList(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1156 PVOID pfile,
1157 PEALIST list)
1158{
1159 APIRET arc = NO_ERROR;
1160 while ( (list != 0)
1161 && (arc == NO_ERROR)
1162 )
1163 {
1164 arc = WriteEA(type, pfile, (EA_LIST_BINDING (list)));
1165 list = (EA_LIST_NEXT (list));
1166 }
1167
1168 return (arc);
1169}
1170
1171/*
1172 *@@ WriteEA:
1173 *
1174 *@@changed V0.9.1 (2000-01-30) [umoeller]: now returning APIRET
1175 */
1176
1177static APIRET WriteEA(ULONG type, // in: ENUMEA_REFTYPE_FHANDLE or ENUMEA_REFTYPE_PATH
1178 PVOID pfile,
1179 PEABINDING binding)
1180{
1181 ULONG level = FIL_QUERYEASIZE;
1182 EAOP2 eaop;
1183 ULONG size = (sizeof (eaop));
1184 APIRET arc = NO_ERROR;
1185
1186 (eaop.fpGEA2List) = 0;
1187 (eaop.fpFEA2List) = (ConvertBinding2Feal(binding));
1188 (eaop.oError) = 0;
1189 if (type == ENUMEA_REFTYPE_FHANDLE)
1190 arc = DosSetFileInfo((* ((PHFILE) pfile)), level, (&eaop), size);
1191 else
1192 arc = DosSetPathInfo((PSZ)pfile, level, (&eaop), size, DSPI_WRTTHRU);
1193 free(eaop.fpFEA2List);
1194 return (arc);
1195}
1196
1197/*
1198 *@@ ConvertBinding2Feal:
1199 *
1200 */
1201
1202static PFEA2LIST ConvertBinding2Feal(PEABINDING binding)
1203{
1204 unsigned int feal_size
1205 = ((sizeof (FEA2LIST))
1206 + (EA_BINDING_NAME_LENGTH (binding))
1207 + (EA_BINDING_VALUE_LENGTH (binding)));
1208 PFEA2LIST feal = (PFEA2LIST)(malloc(feal_size));
1209 PFEA2 fea = (&((feal->list) [0]));
1210 (feal->cbList) = feal_size;
1211 (fea->oNextEntryOffset) = 0;
1212 (fea->fEA) = (EA_BINDING_FLAGS (binding));
1213 (fea->cbName) = (EA_BINDING_NAME_LENGTH (binding));
1214 (fea->cbValue) = (EA_BINDING_VALUE_LENGTH (binding));
1215 strcpy ((fea->szName), (EA_BINDING_NAME (binding)));
1216 if ((EA_BINDING_VALUE (binding)) != 0)
1217 memcpy ((&((fea->szName) [(fea->cbName) + 1])),
1218 (EA_BINDING_VALUE (binding)),
1219 (fea->cbValue));
1220 return (feal);
1221}
1222
1223/* ******************************************************************
1224 *
1225 * Direct plain-string EA handling
1226 *
1227 ********************************************************************/
1228
1229#define USE_EAMVMT 1
1230
1231/*
1232 * eahWriteStringEA:
1233 *
1234 * (C) Christian Langanke. Moved this here from tmsgfile.c.
1235 *
1236 *@@added V0.9.3 (2000-05-21) [umoeller]
1237 */
1238
1239APIRET eahWriteStringEA(HFILE hfile,
1240 PSZ pszEaName,
1241 PSZ pszEaValue)
1242{
1243
1244 APIRET rc = NO_ERROR;
1245 PFEA2LIST pfea2l = NULL;
1246
1247#ifdef USE_EAMVMT
1248 PEAMVMT peamvmt;
1249#else
1250 PEASVST peasvst;
1251#endif
1252 ULONG ulEAListLen;
1253 ULONG ulValueLen;
1254 EAOP2 eaop2;
1255
1256 // PSZ pszValue;
1257
1258 do
1259 {
1260 // check parameters
1261 if ( (hfile == NULLHANDLE)
1262 || (pszEaName == NULL)
1263 || (*pszEaName == 0)
1264 || (pszEaValue == NULL)
1265 )
1266 {
1267 rc = ERROR_INVALID_PARAMETER;
1268 break;
1269 }
1270
1271 // write EAs
1272 ulValueLen = strlen(pszEaValue) +
1273#ifdef USE_EAMVMT
1274 sizeof(EAMVMT);
1275#else
1276 sizeof(EASVST);
1277#endif
1278
1279 ulEAListLen = strlen(pszEaName) +
1280 sizeof(FEA2LIST) +
1281 ulValueLen;
1282
1283 // get memory for FEA2LIST
1284 pfea2l = (FEA2LIST*)malloc(ulEAListLen);
1285 if (pfea2l == 0)
1286 {
1287 rc = ERROR_NOT_ENOUGH_MEMORY;
1288 break;
1289 }
1290
1291 // init FEA2LIST
1292 eaop2.fpGEA2List = NULL;
1293 eaop2.fpFEA2List = pfea2l;
1294 memset(pfea2l, 0, ulEAListLen);
1295
1296 // write timeframe EA
1297 pfea2l->cbList = ulEAListLen;
1298 pfea2l->list[0].cbName = strlen(pszEaName);
1299 strcpy(pfea2l->list[0].szName, pszEaName);
1300
1301 // delete attribute if value empty
1302 if (strlen(pszEaValue) == 0)
1303 pfea2l->list[0].cbValue = 0;
1304 else
1305 {
1306 pfea2l->list[0].cbValue = ulValueLen;
1307
1308#ifdef USE_EAMVMT
1309 // multi value multi type
1310 peamvmt = (PEAMVMT) NEXTSTR(pfea2l->list[0].szName);
1311 peamvmt->usType = EAT_MVMT;
1312 peamvmt->usCodepage = 0;
1313 peamvmt->usEntries = 1;
1314 peamvmt->usEntryType = EAT_ASCII;
1315 peamvmt->usEntryLen = strlen(pszEaValue);
1316 memcpy(&peamvmt->chEntry[0], pszEaValue, peamvmt->usEntryLen);
1317#else
1318 // single value single type
1319 peasvst = NEXTSTR(pfea2l->list[0].szName);
1320 peasvst->usType = EAT_ASCII;
1321 peasvst->usEntryLen = strlen(pszEaValue);
1322 memcpy(&peasvst->chEntry[0], pszEaValue, peasvst->usEntryLen);
1323#endif
1324 }
1325
1326 // set the new EA value
1327 rc = DosSetFileInfo(hfile,
1328 FIL_QUERYEASIZE,
1329 &eaop2,
1330 sizeof(eaop2));
1331
1332 }
1333 while (FALSE);
1334
1335// cleanup
1336 if (pfea2l)
1337 free(pfea2l);
1338 return rc;
1339}
1340
1341/*
1342 * eahReadStringEA:
1343 *
1344 * (C) Christian Langanke. Moved this here from tmsgfile.c.
1345 *
1346 *@@added V0.9.3 (2000-05-21) [umoeller]
1347 */
1348
1349APIRET eahReadStringEA(PSZ pszFileName,
1350 PSZ pszEaName,
1351 PSZ pszBuffer,
1352 PULONG pulBuflen)
1353{
1354
1355 APIRET rc = NO_ERROR;
1356 FILESTATUS4 fs4;
1357
1358 EAOP2 eaop2;
1359 PGEA2LIST pgea2l = NULL;
1360 PFEA2LIST pfea2l = NULL;
1361
1362 PGEA2 pgea2;
1363 PFEA2 pfea2;
1364
1365 ULONG ulGea2Len = 0;
1366 ULONG ulFea2Len = 0;
1367
1368 PEASVST peasvst;
1369 PEAMVMT peamvmt;
1370
1371 ULONG ulRequiredLen;
1372
1373 do
1374 {
1375 // check parameters
1376 if ((pszFileName == NULL) ||
1377 (pszEaName == NULL) ||
1378 (*pszEaName == 0) ||
1379 (pulBuflen == NULL))
1380 {
1381 rc = ERROR_INVALID_PARAMETER;
1382 break;
1383 }
1384
1385 // initialize target buffer
1386 if (pszBuffer)
1387 memset(pszBuffer, 0, *pulBuflen);
1388
1389 // get EA size
1390 rc = DosQueryPathInfo(pszFileName,
1391 FIL_QUERYEASIZE,
1392 &fs4,
1393 sizeof(fs4));
1394 if (rc != NO_ERROR)
1395 break;
1396
1397 // no eas here ?
1398 if (fs4.cbList == 0)
1399 {
1400 pulBuflen = 0;
1401 break;
1402 }
1403
1404 // determine required space
1405 // - for ulFea2Len use at least 2 * Gea2Len because
1406 // buffer needs at least to be Geal2Len even for an empty
1407 // attribute, otherwise rc == ERROR_BUFFER_OVERFLOW !
1408 ulGea2Len = sizeof(GEA2LIST) + strlen(pszEaName);
1409 ulFea2Len = 2 * MAX(fs4.cbList, ulGea2Len);
1410
1411 // get memory for GEA2LIST
1412 if ((pgea2l = (GEA2LIST*)malloc(ulGea2Len)) == 0)
1413 {
1414 rc = ERROR_NOT_ENOUGH_MEMORY;
1415 break;
1416 }
1417 memset(pgea2l, 0, ulGea2Len);
1418
1419 // get memory for FEA2LIST
1420 if ((pfea2l = (FEA2LIST*)malloc(ulFea2Len)) == 0)
1421 {
1422 rc = ERROR_NOT_ENOUGH_MEMORY;
1423 break;
1424 }
1425 memset(pfea2l, 0, ulFea2Len);
1426
1427 // init ptrs and do the query
1428 memset(&eaop2, 0, sizeof(EAOP2));
1429 eaop2.fpGEA2List = pgea2l;
1430 eaop2.fpFEA2List = pfea2l;
1431 pfea2l->cbList = ulFea2Len;
1432 pgea2l->cbList = ulGea2Len;
1433
1434 pgea2 = &pgea2l->list[0];
1435 pfea2 = &pfea2l->list[0];
1436
1437
1438 pgea2->oNextEntryOffset = 0;
1439 pgea2->cbName = strlen(pszEaName);
1440 strcpy(pgea2->szName, pszEaName);
1441
1442 rc = DosQueryPathInfo(pszFileName,
1443 FIL_QUERYEASFROMLIST,
1444 &eaop2,
1445 sizeof(eaop2));
1446 if (rc != NO_ERROR)
1447 break;
1448
1449 // check first entry only
1450 peamvmt = (PEAMVMT) ((PBYTE) pfea2->szName + pfea2->cbName + 1);
1451
1452 // is it MVMT ? then adress single EA !
1453 if (peamvmt->usType == EAT_MVMT)
1454 {
1455 peasvst = (PEASVST) & peamvmt->usEntryType;
1456 }
1457 else
1458 peasvst = (PEASVST) peamvmt;
1459
1460
1461 // is entry empty ?
1462 if (peasvst->usEntryLen == 0)
1463 {
1464 rc = ERROR_INVALID_EA_NAME;
1465 break;
1466 }
1467
1468 // is it ASCII ?
1469 if (peasvst->usType != EAT_ASCII)
1470 {
1471 rc = ERROR_INVALID_DATA;
1472 break;
1473 }
1474
1475 // check buffer and hand over value
1476 ulRequiredLen = peasvst->usEntryLen + 1;
1477 if (*pulBuflen < ulRequiredLen)
1478 {
1479 *pulBuflen = ulRequiredLen;
1480 rc = ERROR_BUFFER_OVERFLOW;
1481 break;
1482 }
1483
1484 // hand over len
1485 *pulBuflen = ulRequiredLen;
1486
1487 // hand over value
1488 if (pszBuffer)
1489 memcpy(pszBuffer, peasvst->chEntry, peasvst->usEntryLen);
1490
1491 }
1492 while (FALSE);
1493
1494// cleanup
1495 if (pgea2l)
1496 free(pgea2l);
1497 if (pfea2l)
1498 free(pfea2l);
1499 return rc;
1500}
1501
1502
Note: See TracBrowser for help on using the repository browser.