[ Next ] [ Previous ] | Chapter 4 - I | [ Contents ] [ Chapter 3: Multitasking ] [ Chapter 4-II ] [ Chapter 5: Interprocess Communication ]

### File I/O and Extended Attributes

File I/O is one of the most important aspects of any operating system. OS/2 makes the file system programming very easy to understand and master, yet it still provides the programmer with many flexible and powerful features. OS/2 has introduced to DOS developers the new concept of Installable File Systems. which allows various file systems to be installed like device drivers. OS/2 introduces the new High Performance File System (HPFS), which allows greater throughput and security features for servers, workstations. and local area network (LAN) administrators. The File Allocation Table (FAT) compatibility is preserved, so DOS users can manipulate their flies without any constraints.

#### Extended Attributes

The following examples demonstrate some straightforward file manipulation, yet provide the user with some useful concepts. It is also necessary to introduce the concept of Extended Attributes (EAs), which is the lesser-known 0S/2 file system feature. One of the examples shows a way to gain access to the various types of EAs. EAs appeased in 0S/2 1.2 and have remained there through the 16- to 32-bit migration; they are nothing more than additional data that is associated with the file, The user does not see this extra data. It is there only for the use of the application and operating system. The designers had to be creative it order to implement EA support under FAT due to the fact that DOS, which is the grandfather of FAT never had support for EAs. The HPFS does not require the same creativity in implementation, thus the FAT implementation, is the one that deserves a short explanation.

Table 4.1 FAT Directory Entries
Entry | Location
Filename: | 00-07
Extension: | 08-0A
Attribute: | 0B
Reserved: | 0C-15
Time: | 16-17
Date: | 18-19
FAT cluster: | 1A-1B
Size: | 1C - 1F
| The FAT directory entries take up 32 bytes (20 hex) and are represented by Table 4.1. Most DOS files will have the reserved bits 0C to 15 set to zero. This is the area that is utilized to attach the Extended Attributes to the files in OS/2. The EA allocation clusters use the 14h and 15h bytes, and thus may appear illegal to some DOS applications. In order to avoid DOS compatibility problems, another file entry is maintained called EA DATA. SF; this file "pretends" to own all of the loose EA clusters on the hard disk, thus eliminating "lost clusters" messages from chkdsk.exe and similar messages from other disk managing utilities. Two references to all EA clusters exist: one that is maintained with the 14h- and 15h-byte directory entries, and one that is "assigned" to the EA DATA.SF. This implementation creates a source of confusion for users who are not familiar with EAs. For example, when using EA unaware backup utilities or when copying files from an OS/2 partition under DOS. most users do not know what to do wish the EA DATA.SF file. Users must realize that the EA clusters referenced by that file belong to several different applications. In order to maintain the EAs properly, it is best to use the OS/2 EAUTIL. program to separate EAs from their owners, then copy them as separate files and later reunite them for a happy ending. Generally the EAs take up a substantial amount of disk space; if space is at a premium, EAs not associated with a critical attribute can usually be deleted. In such cases, the presence of the EA is not critical to the application's correct execution and thus it can be removed. Users must take care in determining which EAs can be removed, as some applications will not work correctly afterward.

A more thorough discussion of EA API and a detailed discussion of the API structures for the FAT and HPFS can be found in the OS/2 Programming Guide and various other IBM technical publications. The short description offered here is merely for the benefit of the programming examples and to help the programmer understand the API syntax used to attain the EA information. Extended attributes will appear foreign to DOS users and programmers, and their usefulness generally is questioned almost immediately. Only upon closer inspection does it become evident that EAs are quite important and really constitute a must-have feature , especially in high-end operating systems such as OS/2. Basically the Extended Attributes are nothing more than a storage area of information no more than 64K in sire that are available for applications to use as they please. OS/2 defines several standard types of EAs that are available for general use. Also, the programmer can define application-specific extended attributes. The only restriction is that the total EA size s cannot exceed 64K. Standard EAs are called SEAs, and by convention starts with a period [.]. They include:

> `.ASSOCTABLE`
> `.CODEPAGE`
> `.COMMENTS`
> `.HISTORY`
> `.ICON`
> `.KEYPHRASES`
> `.LONGNAME`
> `.SUBJECT`
> `.TYPE`
> `.VERSION`

It is a good idea to not use the preceding [.] character in your own applications. The operating system reserves the right to use [.] as the first character of the EA name types. Nothing prevents users from implementing the same convention, but if OS/2 designers decide to add another standard type that happens to use your EA name, some unpredictable behavior may result. The type of data that is stored within an SEA is representative of the SEA name. For example, the .ICON SEA will contain the icon data, while the .TYPE SEA will contain the file object's type. This type can represent an executable, data, metafile, C code, bitmap, icon, resource file, object code, DOS binary, and so on. As you might have guessed, the .TYPE SEA is one of the more frequently used attributes of a file object. Note that extended attributes are associated not only with files but also with subdirectories. In fact, the subdirectory containing the Workplace Shell desktop information contains subdirectories that have many, many EAs.

#### EAs - Fragile: Handle with Care

A programmer must take certain steps while using EAs. First, if the file objects are being moved or copied to a system that does not support EAs (such as a DOS-FAT combination), the programmer must take care not to lose the EAs that may be associated with the particular file object. Consider the case of uploading a file with EAs to a UNIX machine and then downloading the same file back. Doing so may result in EAs being lost or misplaced because most UNIX machines do not support EAs. Another good example is trying to copy a file that has a long name from an HPFS partition to a FAT partition. Since FAT supports the 8.3 naming convention only, the file name may be truncated, but that is not a problem since the correct HPFS name may be stored in the .LONGNAME EA. An application that manipulates files must be EA- and HPFS-aware in order to perform proper file management in an OS/2 environment.

#### The LIBPATH.C Example

The first example we discuss attempts to find out the value of the LIBPATH environment variable. In OS/2 Warp, an extended LIBPATH variable was created. This special variable can be set or queried from the command line or from an API, DosSetExtLIBPATH and DosQueryExtLIBPATH. This variable can be changed dynamically and either pretended or appended to the system LIBPATH variable. The system LIBPATH itself cannot be returned from the regular environment SET command or a DosQuery... API. Occasionally the system LIBPATH variable is a handy thing to know. So, a not-so-clean solution is to find the value of the boot drive, find the CONFIG.SYS file, and attempt to extract the LIBPATH string from that file. This will work only when there have been no previous changes to the CONFIG.SYS file since the system has been booted and specifically no direct manipulations of the system LIBPATH value. Although this example is a crude kluge, the method actually can be useful on a number of occasions.

> LIBPATH.C
> LIBPATH.MAK
> LIBPATH.DEF

The first step is to find the system boot drive. In order to do this, use DosQuerySysInfo and specify the arguments corresponding to the boot drive information. DosQuerySysInfo takes three input parameters and one output parameter, and returns the values of the system's static variables:

`APIRET DosQuerySysInfo (`
`ULONG uStartIndex; /* Ordinal of the first system variable to return. */`
`ULONG uLastIndex; /* Ordinal of the last system variable to return. */`
`PVOID pDataBuf; /* Address of the data buffer where the system returns the variable values. */`
`ULONG ulDataBufLen);/* Length, in bytes, of the data buffer. */`
`/* APIRET Return Code. */`

This call can return a single value or a range of values, depending on the ulSrartIndex, ulLastIndex. As is evident by the example, in order to obtain a single value, the ulStartIndex and ulLastIndex are set to the same input value:

> `arReturn = DosQuerySysInfo(`
> `QSV_BOOT_DRIVE,`
> `QSV_BOOT_DRIVE,`
> `&ulDrive,`
> `sizeof( ulDrive) );`

The QSV_BOOT_DRIVE constant is defined by the BSEDOS.H header file, which is part of the set standard header files provided by she Programmer's Toolkit. Table 4.1 defines the additional values. The third parameter is the data buffer that DosQuerySysInfo uses to place the returned values into. The parameter is the size of the data buffer.

Table 4.1 System Constants for DosQuerySysInfo
Description | Value | Meaning
QSV_MAX_PATH_LENGTH | 1 | Maximum path name length in bytes
Q_MAX_PATH_LENGTH | 1 | = QSV_MAX_PATH_LENGTH
QSV_MAX_TEXT_SESSIONS | 2 | Maximum number or text sessions
QSV_MAX_PM_SESSIONS | 3 | Maximum number of PM sessions
QSV_MAX_VDM_SESSIONS | 4 | Maximum number of virtual DOS machine (VDM) sessions
QSV_BOOT_DRIVE | 5 | Boot drive value ( 1=A:, 2=B:, etc. )
QSV_DYN_PRI_VARIATION | 6 | Dynamic/Absolute priority (0=Absolute, 1=Dynamic )
QSV_MAX_WAIT | 7 | Maximum wait time in seconds
QSV_MIN_SLICE | 8 | Minimum time slice allowed in milliseconds
QSV_MAX_SLICE | 9 | Maximum time slice allowed in milliseconds
QSV_PAGE_SIZE | 10 | Default page size (4K)
QSV_VERSION_MAJOR | 11 | Major version number (20 for OS/2 2.0, 2.1, 2.11, 3.0, 4.0)
QSV_VERSION_MINOR | 12 | Minor version number (00, 10, 11, 30,40 for OS/2 2.0, 2.1, 2.11, 3.0, 4.0 respectively)
QSV_VERSION_REVISION | 13 | Revision version letter
QSV_MS_COUNT | 14 | Free running millisecond 32-bit counter (value=0 at boot time)
QSV_TIME_LOW | 15 | Lower 32 bits of time since 01-01-1970 in seconds
QSV_TIME_HIGH | 16 | Upper 32 bits of times since 01-01-1970 in seconds
QSV_TOTPHYSMEM | 17 | Total number of bytes of physical memory
QSV_TOTRESMEM | 18 | Total number of system-resident memory
QSV_TOTAVAILMEM | 19 | (Available memory for all processes) Maximum number of bytes of memory that can be allocated by all processes in the system. This number is advisory and is not guaranteed, since system conditions change constantly.
QSV_MAXPRMEM | 20 | (Avail private mem for calling proc) Maximum number of bytes of memory that this process can allocate in its private arena. This number is advisory and is not guaranteed, since system conditions change constantly.
QSV_MAXSHMEM | 21 | ( Avail shared mem for calling proc ) Maximum number of bytes of memory that a process can allocate in the shared arena. This number is advisory and is not guaranteed, since system conditions change constantly.
QSV_TIMER_INTERVAL | 22 | Timer interval in tenths of millisecond
QSV_MAX_COMP_LENGTH | 23 | Maximum length, in bytes, of one component in a path name.
QSV_FOREGROUND_FS_SESSION | 24 | Session ID of current fgnd FS session Session ID of the current foreground full-screen session. Note that this only applies to full-screen sessions. The Presentation Manager session (which displays Vio-windowed, PM, and windowed DOS Sessions) is full-screen session ID 1.
QSV_FOREGROUND_PROCESS | 25 | Process ID of the current foreground process.
QSV_NUMPROCESSORS | 26 | Number of processors in the machine
QSV_MAXHPRMEM | 27 | Maximum amount of free space in process's high private arena
QSV_MAXHSHMEM | 28 | Maximum amount of free space in process's high shared arena
QSV_MAXPROCESSES | 29 | Maximum number of concurrent processes supported
QSV_VIRTUALADDRESSLIMIT | 30 | Size of the user's address space in megabytes
QSV_INT10ENABLED | 31 | INT10ENABLED
QSV_MAX |  | = QSV_INT10ENABLED

| Gotcha! An application that is intended to be used in the HPFS/FAT environment should make the DosQuerySysInfo call and determine the maximum value of the legal file name length: QSV_MAX_COMP_LENGTH. For HPFS, this value is much greater than FAT (255). The application should issue this call in its initialization section and remember the pertinent values for future DosFindFirst, DosFindNext buffer sire allocation values.

Once the boot drive is located, the string containing the full path to CONFIG.SYS is created.

#### Getting the File Size

> `arReturn = DosQueryPathInfo(`
> `pchFile,`
> `FIL_STANDARD,`
> `&fsStatus,`
> `sizeof( fsStatus) );`
> `pchBuffer = malloc (fsStatus.cbFile +1);`

DosQueryPathInfo is used to determine the size of CONFIG.SYS. The function is designed to get file information for a file or subdirectory. The first parameter, pchFile, is the fully qualified path for the file. The second parameter is the level of information required. All we need for this example is standard file information, FIL_STANDARD. The information level determines the third parameter. If FIL_STANDARD is specified, a pointer to a FILESTATUS3 structure is used. The structure looks like this:

`typedef struct _FILESTATUS3 {`
`FDATE fdateCreation; /* Date of file creation. */`
`FTIME ftimeCreation; /* Time of file creation. */`
`FDATE fdateLastAccess; /* Date of last access. */`
`FTIME ftimeLastAccess; /* Time of last access. */`
`FDATE fdateLastWrite; /* Date of last write. */`
`FTIME ftimeLastWrite; /* Time of last write. */`
`ULONG cbFile; /* File size (end of data). */`
`ULONG cbFileAlloc; /* File allocated size. */`
`ULONG attrFile; /* Attributes of the file. */`
`} FILESTATUS3;`

The FILESTATUS3 structure contains two fields of interest: cbFile and cbFileAlloc. The cbFiIe element contains the actual size of the file, start to finish, in bytes. The cbFileAlloc, on the other hand, contains the file size, based on system allocation unit (AU) size, whose value can be a multiple of 512, 2K, 4K, 8K, l6K,32K. and so on, depending on the type of magnetic media used. HPFS and diskettes use 512-byte AUs, while the FAT AU size depends on the volume size. cbFileAlloc is of minimal value in applications, and the cbFile value should be used to allocate the required storage. Thus, cbFile size value is used in the next call to allocate the memory buffer needed to read the whole CONFIG.SYS at once, plus an extra byte for a NULL character.

This memory allocation does not have to be performed. It is possible to read one character at a time and parse the output using a 1-byte storage area. The method used in CHKEA was used for ease of implementation as well as performance reasons. Reading the whole file is much quicker. (Since the CONFIG.SYS is generally smaller than 4K in size, it should easily fit into a single page of memory, which is the smallest allocation allowed in 32-bit OS/2.) The parsing can be achieved more rapidly as well. Memory operations are much quicker than storage disk I/O.

#### Opening a File

Having found the file size, the next step is to attempt to open the CONFIG.SYS file. The DosOpen API call is a good example of the flexibility and power of the OS/2 file system interface. Several flags are available to the programmer, and almost any combination of them can be defined in order to provide for maximum systemwide cooperation. In this case, the file is opened in read-only mode and with full sharing enabled This means that if another application decided to open and read CONFIG.SYS at the same time, it would be able to do so. Allowing other applications full sharing rights also presents a problem of the file data being changed while we are attempting to read if. Although this is a remote possibility, the risk is still there; using the OPEN_SHARE_DENYWRITE flag instead of OPEN_SHARE_DENYNONE easily prevents it. The OPEN_FLAGS_SEQUENTIAL flag is used to define how we will be reading the file. Last. we examine the file in read-only mode by specifying the flag OPEN_ACCESS_READONLY. DosOpen is a fairly involved API. We'll go into some more details in just a moment.

> `arReturn = DosOpen (`
> `pchFile,`
> `&hfFile,`
> `&ulAction,`
> `0,`
> `FILE_NORMAL,`
> `FILE_OPEN,`
> `OPEN_FLAGS_FAIL_ON_ERROR |`
> `OPEN_FLAGS_SEQUENTIAL |`
> `OPEN_SHARE_DENYNONE |`
> `OPEN_ACCESS_READONLY,`
> `NULL);`

#### Reading a File

> `arReturn = DosRead(`
> `hfFile,`
> `pchBuffer,`
> `fsStatus.cbFile,`
> `&ulBytesRead);`

DosRead is the function to read not only flies but any devices. The first parameter, hfFile, is the file handle returned from DosOpen . The buffer, pchBuffer, is the second parameter. The third parameter is the number of bytes to read. In our case, the entire file size is used. The last parameter is a pointer to a ULONG. The number of bytes actually placed into the buffer is returned in a variable, ulBytesRead.

> Note: In DOS and OS/2 it is possible to get a good return code (arReturn = 0) and not have the DosRead/DosWrite API complete as expected. It is a good idea to check for the return code first, then check for the BytesRead value and compare it with the expected number.

Once in memory, the last character of the CONFIG.SYS file is set to NULL. This is done so that string operations can be performed more easily. The last step is parsing the file in order to find the LIBPATH information. Once the LIBPATH is found, it is displayed with a straightforward printf. The cleanup is accomplished by freeing the memory and using DosClose to close the file.

> `arReturn = DosClose( hfFile );`
> `printf( "\n%s\n", pchLibpath);`
> `free(pchBuffer);`

[ Next ] [ Previous ] | Chapter 4 - I | [ Contents ] [ Chapter 3: Multitasking ] [ Chapter 4-II ] [ Chapter 5: Interprocess Communication ]