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

Last change on this file since 17 was 14, checked in by umoeller, 25 years ago

Major updates; timers, LVM, miscellaneous.

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