[Next] [Previous] | Chapter 4 - part III |
CHKEA.C
CHKEA.MAK
CHKEA.DEF
CHKEA.EXE expects a command-line input argument that is the name of the file of interest. Wildcard characters are accepted. First, a determination is made if the file object can be located on the hard disk; if successful, the full name of the object is constructed.
DosQueryPathInfo ( apchArgs[1],
FIL_QUERYFULLNAME,
achPath,
CCHMAXPATHCOMP );
pchPath = strrchr ( achPath, '\\') ;
if ( pchPath != NULL )
{ pchPath++;
*pchPath =
0;
} /* endif */
ulCount = 1;
hdFile = HDIR_SYSTEM
arReturn = DosFindFirst(apchArqs[1],
&hdFile,
FILE_DIRECTORY,
&ffbFile,
sizeof ( FILEFINDBUF4 ) ,
&ulCount,
FIL_QUERYEASIZE ) ;
The DosFindFirst API is the most useful function call available to a programmer when attempting to locate the objects.
/* Finds the first file object
or group of file objects whose names match the specification.
*/
/* The specification
can include extended attributes (EA) associated with a file or directory.
*/
APIRET APIENTRY DosFindFirst(
PSZ pszFileSpec,/*
Address of the ASCIIZ path name of the file or subdirectory to be found.
*/
PHDIR phdir,
/* Address of the handle associated with this DosFindFirst
request. */
ULONG flAttribute,/*
Attribute value that determines the file objects to be searched for. */
PVOID pfindbuf, /*
Result buffer. */
ULONG cbBuf,
/* The length, in bytes, of pfindbuf. */
PULONG pcFileNames,/* Pointer
to the number of entries: */
ULONG ulInfoLevel /*
The level of file information required. */
);
The definition for this API can be found in the BSEDOS.H header file,
which is part of the OS/2 Developers Toolkit. Table 4.7 presents the arguments
of interest.
Arguments | Value(s) | Meaning |
phdir | HDIR_SYSTEM | Use STDOUT for handle |
phdir | HDIR_CREATE | Handle is created |
flAttribute | bit encoded | Type of object to search for |
pfindbuf | depends on ulInfoLevel | Result of the request |
ulInfoLevel | FIL_STANDARD | Standard file information is returned |
ulInfoLevel | FIL_QUERYEASIZE | File EA size is returned |
ulInfoLevel | FIL_QUERYEASFROMLIST | Actual EA data is returned |
Table 4.8 lists the acceptable values for the flAuribute argument.
Value | Description |
MUST_HAVE_ARCHIVED | Files returned must have the archive bit set |
MUST_HAVE_DIRECTORY | Files returned must have the directory bit set |
MUST_HAVE_SYSTEM | Files returned must have the system bit set |
MUST_HAVE_HIDDEN | Files returned must have the hidden bit set |
MUST_HAVE_READONLY | Files returned must have the read-only bit set |
FILE_ARCHIVED | Files with archive bit set are not returned unless this value is specified |
FILE_DIRECTORY | Files with directory bit set are not returned unless this value is specified |
FILE_SYSTEM | Files with system bit set are not returned unless this value is specified |
FILE_HIDDEN | Files with hidden bit set are not returned unless this value is specified |
FILE_READONLY | Files with read-only bit set are not returned unless this value is specified |
phdir is an input/output parameter. On input it specifies the type of file handle required by the application. HDIR_SYSTEM tells the operating system to assign a handle that will always be available to the process. This is a handle for standard output. HDIR_CREATE will cause the system to allocate a handle and return it to the application in phdir. Since pszFileSpec can accept wildcard characters, the handle returned can be used in conjunction with the DosFindNext to find the next file object that matches the pszFileSpec.
flAttribute is an input bit-encoded flag that tells DosFindFirst what types of file objects to look for. These bits represent conditions that may be true or must be true. For example, a programmer may want to locate a directory with a particular name that may be hidden; although there are files that can correspond to the pszFileSpec specified, only the directories are of interest. The following bit combination could be used.
flAttribute = MUST_HAVE_DIRECTORY | FILE_HIDDEN;
The pfindbuf is a pointer to the buffer that must be allocated prior to making the DosFindFirst call, and must be passed to the API as a pointer. On output the buffer will contain the information specified by the next parameter ulInfoLevel, which can have three valid values associated with it (FIL_STANDARD, FIL_QUERYEASIZIE, FILE_QUEARYEASFROMLIST).
The first value requests DosFindFirst to return FIL_STANDARD information about the file. FIL_STANDARD information contains the data associated with the FILEFINDBUF3 structure.
FIL_QUERYEASIZE information is requested by specifying FIL_QUERYEASIZE for ulInfoLcvcl, and it returns the data associated with the FILEFINDBUF4 structure. Finally, FIL_QUERYEASFROMLIST information is obtained by specifying the value FIL_QUERYEASFROMLIST for the ulInfoLevel. It returns an EAOP2 data structure.
The FIL_QUERYEASFROMLIST request is slightly different from the previous two levels. On input pfindbuf must contain the EAOP2 data structure with the correct names of the EAs to be queried. Since EA data structures are variable in length. the fpGEA2List must contain a pointer to the GEA2 list, which in turn must have the correct value specified for the oNextEntryOffset and szName. The szName specifies the EA to be returned, and the oNextEntryOffset contains the number of bytes from the beginning of the first entry to the end of the next entry. On output the EAOP2 contains a pointer to the fpFEA2List. The fpFEA2List points to the list of FEA2 structures that have the actual EA information. All of the input records must be aligned on a two-word boundary, and the last in the list of GEA2 structures oNextEntryOffset value must be set to zero. The following are the various data buffers that are returned depending on the level of information requested.
The oNextEntryOffset field indicates the number of bytes from the beginning of the current structure to the beginning of the next structure. When this field is 0, the last structure has been reached.
typedef FILEFINDBUF4 *PFILEFINDBUF4;
The cbList field contains the size of the entire EA set for this file object, in bytes.
On output, pfindbuf contains a structure with a set of records, each aligned on a doubleword boundary. These records represent the directory entry and associated EAs for the matched file object. pfindbuf has the following format:
![]() |
Gotcha!
The result buffer from DosFindFirst should be less than 64KB.
|
/* Level 3 (32-bit) (FIL_QUERYEASFROMLIST) file information - get extended attributes. */
typedef struct _GEA2 {
ULONG
oNextEntryOffset; /* Offset to next entry. */
BYTE
cbName;
/* Name length not including NULL. */
CHAR
szName[1]; /* Attribute
name. */
} GEA2;
typedef GEA2 *PGEA2;
/* Get extended attributes list. */
typedef struct _GEA2LIST {
ULONG
cbList; /* Total bytes of structure including full list.
*/
GEA2
list[1]; /* Variable-length GEA2 structures. */
} GEA2LIST;
typedef GEA2LIST *PGEA2LIST;
/* FEA2 defines the format for setting the full extended attributes in the file. */
typedef struct _FEA2 {
ULONG
oNextEntryOffset; /* Offset to next entry. */
BYTE
fEA;
/* Extended attributes flag. */
BYTE
cbName;
/* Length of szName, not including NULL. */
USHORT
cbValue; /*
Value length. */
CHAR
szName[1]; /* Extended
attribute name. */
} FEA2;
typedef FEA2 *PFEA2;
/* FEA2 data structure. */
typedef struct _FEA2LIST {
ULONG
cbList; /* Total bytes of structure including full list.
*/
FEA2
list[1]; /* Variable-length FEA2 structures. */
} FEA2LIST;
typedef FEA2LIST *PFEA2LIST;
/* EAOP2 data structure. */
typedef struct _EAOP2 {
PGEA2LIST
fpGEA2List; /* GEA set. */
PFEA2LIST
fpFEA2List; /* FEA set. */
ULONG
oError; /* Offset of FEA error. */
} EAOP2;
typedef EAOP2 *PEAOP2;
Figure 4.4 Illustrates the EAOP2 structure in memory.
EAOP2 | fpGEA2List | cbList
(4 bytes) |
|
list | cbNextEntryOffest (4 bytes)
cbName (1byte) szName (cbName bytes) |
||
fpFEA2List | cbList
(4 bytes) |
||
list | cbNextEntryOffset ( 4 bytes)
fEA (1 byte) cbName (1 byte) cbValue (2 bytes) szName (cbName bytes) EA Data (cbValue) |
DosFindFirst also accomplishes one other thing.
It provides us with the size of the EAs associated with the file. A buffer
of this size, pbBuffer, is allocated.
DosEnumAttribute is used to identify the names
of the EAs associated with a particular file object.
/* Identifies names and lengths of extended attributes for a specific file or subdirectory. */
APIRET APIENTRY DosEnumAttribute(
ULONG ulRefType,
/* A value that indicates whether pvFile points to
a handle or to an ASCIIZ name. */
PVOID pvFile,
/* Address of the handle of a file returned by DosOpen;
or the ASCIIZ name of a file or subdirectory. */
ULONG ulEntry,
/* Ordinal of an entry in the file object's EA list,
which indicates where in the list to begin the return of EA information.
*/
PVOID pvBuf,
/* Address of the buffer where EA information is returned.
*/
ULONG cbBuf,
/* The length, in bytes, of the buffer pointed to
by pvBuf. */
PULONG pulCount,
/* Pointer to number of EAs. */
ULONG ulInfoLevel);
/* Level of information required. */
The ulRefType tells the DosEnumAttribute about the next input parameter. When the value is 0. the pvFile argument contains a file handle; when the value is 1, the pvFile argument contains a pointer to null-terminated string representing the name of the file object.
If the pvFile contains a handle, then this handle must be obtained
by an earlier call to a DosOpen or similar API.
ulEntry describes the ordinal of the file object's EA entry.
This value must be non-zero and positive. The value of 1 is indicative
of the first EA entry in the list, 2 of the second one, and so on.
pvBuf is the pointer to the output buffer. Only FIL_STANDARD
information can be returned; thus the ulInfoLevel is always 1 (ENUMEA_LEVEL_NO_VALUE).
cbBuf is the length of the buffer referenced by the pvBuf.
pulCount is an input/output type argument. On input, the value
contains the number of EAs for which the information is requested. If the
value of -1L is specified, all of the EAs are queried, and the information
is returned in the pvBuf provided the buffer is of adequate size.
On output this argument contains the actual number of EAs for which the
information was returned. If the buffer is big enough, all of the requested
EAs for the file will be returned. On output the buffer contains the list
of those FEA2 structures that are aligned on a two-word boundary. The last
structure in the list will have the oNextEntryOffset value of zero.
arReturn = DosEnumAttribute (
ENUMEA_REFTYPE_PATH,
achFile,
1,
pbBuffer,
ffbFile.cbList,
ulCount,
ENUMEA_LEVEL_NO_VALUE);
printf("\nThis object contains %ld Eas.\n",
ulCount);
In this example, DosEnumAttribute uses a '1" as
the EA ordinal, indicating the function is to start enumerating at the
first EA. Since pbBuffer is big enough to hold all the EA, it should all
be placed in the buffer after just one function call to DosEnumAttribute.
pdAttribute = (PFEA2)pbBuffer;
while ( ulCount
!= 0 )
{ printf("\nFound
EA with name (Name length=%i)\"%s\"",
(int)(pdAttribute->cbName),pdAttribute->szName);
DumpEA(achFile,
pdAttribute);
ulCount--;
pdAttribute = (PFEA2)(((PBYTE)pdAttribute)+
pdAttribute->oNextEntryOffset);
}
/* endwhile */
Once the EM are enumerated, a while loop is used to loop through
and list each EA. The user function DumpEA is covered in more detail
later. The next EA is found by adding the oNextEntryOffes
to the pbBuffer pointer. Notice the casting involved here. Remember,
additions should be made in PBYTE-increments, not in PFEA2-increments.
arReturn =
DosFindNext(hdFile,
&ffbFile,
sizeof(ffbFile),
&ulCount);
Once all the EAs are listed for one file object, DosFindNext is used to find the next file object this matches the wildcard criteria.
In order so obtain the values of the EAs, Level FIL_QUERYEASFROMLIST information should be specified and DosQueryFileInfo or DosQueryPathInfo should be used. Also, it is important to remember that while one process is reading the EA information, another one can be changing it. To prevent this from becoming a problem. the application must open a file wish the sharing flag set to the deny-write state. This will prevent another user from changing the information in the EAs while in use. Note that the DosEnumAttribute may return a different EA for the same specified ordinal number, because ordinals are assigned only to the existing EAs. An application can delete an EA, then turn around and write another one in its place. The ordinal numbers are not preserved, and thus are not unique. The following formula (from the OS/2 2.1 Control Program Programming Reference manual) shows the information needed to calculate the required buffer size.
The buffer size is calculated as follows:
4 bytes (for oNextEntryOffset) | + |
1 byte (for fEA) | +wild card |
1 byte (for cbName) | + |
2 bytes (for cbVabse) | + |
Value of cbName (for the name of EA) | + |
1 byte (for NULL in cbName) | + |
Value of cbValue (for the value of EA) |
![]() |
Gotcha!
Each EA list entry must start on a double-word boundary. The DumpEA function checks the FEA2 structure to see if the EA matches
the types, .LONGNAME, .ICONPOS, or .TYPE. These types were selected as
examples, simply because each is an ASCII string.
|
ulFBufLen = sizeof(FEA2LIST) + pdAttribute->cbName + 1 + /* actual name
*/
pdAttribute->cbValue; /* actual value */
pFEA2 = (PFEA2)calloc(1,
ulFBufLen);
if (!pFEA2)
return FALSE;
/***************************/
/* only one pFEA2 attribute in this list
*/
/***************************/
eaopGet.fpFEA2List = (FEA2LIST *)pFEA2;
eaopGet.fpFEA2List->cbList = ulFBufLen;
The first step is building the fpFEA2List structure for input. The size of the buffer is calculated by adding the structure size, plus the size of the EA name, cbName, plus the sire of the EA data cbValue, plus one byte for a '\0' appended to the name. The fpFEA2List structure in the eaopGet structure is set equal to the memory that has been allocated. The only other initialization involved is setting cbList equal to the size of the output buffer.
ulGBufLen = sizeof(GEA2LIST) + pdAttribute->cbName +1;
pGEA2List = (GEA2LIST *) calloc(1,
ulGBufLen);
if (!pGEA2List)
{ free(pFEA2);
return FALSE;
}
/**************************/
/* initialize fpGEA2List */
/**************************/
pGEA2List->cbList = ulGBufLen;
pGEA2List->list[0].oNextEntryOffset = 0;
pGEA2List->list[0].cbName = pdAttribute->cbName;
strcpy(pGEA2List->list[0].szName,
pdAttribute->szName);
eaopGet.fpGEA2List = (GEA2LIST *) pGEA2List;
The fpGEA2List structure is used to tell the DosQuery
functions which EAs the programmer is interested in. The buffer size is
calculated like the fpFEA2List buffer. The offset to the next list
entry is set to 0, because this example is looking for only one EA at a
time. The cbList variable is the buffer size. The cbNanse variable is the
EA name string size. The actual name is copied into the szName buffer.
The last assignment is setting fpGEA2List in the eaopGet
structure equal to the pGEA2List structure that has just been created.
DosQueryPathInfo is used to retrieve the actual
EA data. The prototype for the function is:
/* Gets file information for a file or subdirectory.*/
APIRET DosQueryPathInfo(
PSZ
pszPathName, /* Address of the ASCIIZ file specification
of the file or subdirectory. */
ULONG
ulInfoLevel,
/* The level of path information required. */
PVOID
pInfoBuf,
/* Address of the storage area containing
the requested level of path information. */
ULONG
cbInfoBuf);
/* The length, in bytes, of pInfoBuf. */
The first parameter is the filename to use to query the information. The second parameter is the level of information to retrieve. The value FIL_QUERYEASFROMLIST will retrieve the EA information. The third parameter is a pointer to the EAOP2 structure. The last parameter is the size of the EAOP2. This value is equal to the size of the fpFEA2List structure plus the size of the fpGEA2List structure.
rc = DosQueryPathInfo(pszFile,
FIL_QUERYEASFROMLIST,
(PVOID)&eaopGet,
ulEBufLen);
ulSize = sizeof(FEA2LIST);
pFEA2 = (PFEA2)eaopGet.fpFEA2List->list;
ulDataStart = ulSize+pFEA2->cbName;
ptrEAData = (PEAINFO)((PBYTE)eaopGet.fpFEA2List + ulDataStart);
ptrEADataHolder = calloc(1,
sizeof(EAINFO) +
ptrEAData->usEALength+1);
printf("Type = 0x%x ",
ptrEAData->usEAType);
printf("Length = 0x%x",
ptrEAData->usEALength);
memcpy(ptrEADataHolder,
ptrEAData->bEAData,
ptrEAData->usEALength);
printf("\nData = %s", ptrEADataHolder);
The last step in the DumpEA function is actually to print out the EA data. The data is returned in the fpFEA2List structure that was set up on input. First, the offset into the fpFEA2List where the EA data is located is found by adding the size of the FEA2 structure plus the size of the attribute name. If this sounds confusing, take a look at Figure 4.4 to help illustrate this. The EA data is formatted in the following manner. The first USHORT contains the type of EA data. The second USHORT contains size of the EAdata. All the bytes that follow contain the actual data located in that EA. This data is copied into a memory buffer that contains enough space for a '\0' character at the end. The EA data does not contain the '\0' character at the end of the data, because not all EA data is in the form of an ASCII null-terminated string.
[Next] [Previous] | Chapter 4 - part III |