CPGuide - File Management: Difference between revisions
mNo edit summary |
|||
(3 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{IBM-Reprint}} | {{IBM-Reprint}} | ||
{{CPGuide}} | {{CPGuide}} | ||
OS/2 provides a standard set of file system functions. This means that applications can create, open, read, write, copy, and delete files and directories by using the same functions, regardless of which file system is used. When an application calls a file system function, OS/2 passes the request to the dynamic link library that supports the file system. The dynamic link library carries out most file system processing, such as validating file names. If an error occurs, the file system returns the error to OS/2, which then passes it back to the calling application. | OS/2 provides a standard set of file system functions. This means that applications can create, open, read, write, copy, and delete files and directories by using the same functions, regardless of which file system is used. When an application calls a file system function, OS/2 passes the request to the dynamic link library that supports the file system. The dynamic link library carries out most file system processing, such as validating file names. If an error occurs, the file system returns the error to OS/2, which then passes it back to the calling application. | ||
The OS/2 file system functions identify files and directories by their names. These functions store or search for the file or directory in the current directory on the current drive unless the name explicitly specifies a different directory and drive. Occasionally, a file system has control functions in addition to the standard file system functions. The control functions are specific to the given file system. An application can call a control function by using DosFSCtl, which directs OS/2 to pass the control-function information to the corresponding Installable File System (IFS). | The OS/2 file system functions identify files and directories by their names. These functions store or search for the file or directory in the current directory on the current drive unless the name explicitly specifies a different directory and drive. Occasionally, a file system has control functions in addition to the standard file system functions. The control functions are specific to the given file system. An application can call a control function by using DosFSCtl, which directs OS/2 to pass the control-function information to the corresponding Installable File System (IFS). | ||
The following topics are related to the information in this chapter: | The following topics are related to the information in this chapter: | ||
*Files systems | *Files systems | ||
*Files names | *Files names | ||
*Extended attributes | *Extended attributes | ||
*Pipes | *Pipes | ||
*Device I/O | *Device I/O | ||
==About Volumes and Drives== | ==About Volumes and Drives== | ||
OS/2 allows more than one file system on a single storage device. If the device can have more than one partition (or volume), each partition can be initialized as an OS/2 partition and given a valid OS/2 file system. For each volume, OS/2 determines the type of file system the first time the volume is accessed by a function or when the medium in the drive changes. After that, OS/2 manages all input and output to that volume by using the corresponding dynamic link library. | OS/2 allows more than one file system on a single storage device. If the device can have more than one partition (or volume), each partition can be initialized as an OS/2 partition and given a valid OS/2 file system. For each volume, OS/2 determines the type of file system the first time the volume is accessed by a function or when the medium in the drive changes. After that, OS/2 manages all input and output to that volume by using the corresponding dynamic link library. | ||
OS/2 uses the volume label and serial number to ensure that the medium in the drive does not change while there are outstanding requests for input and output. Each volume has a volume label and a 32-bit volume serial number, stored in a reserved location in logical sector 0 at the time of formatting. If the volume label and serial number do not match, OS/2 signals the critical error handler to prompt the user to insert the volume that has the specified serial number and label. OS/2 maintains the connection between the medium and the volume label and serial number until all open files on the volume are closed and all search references and cache buffer references are removed. The system redetermines the type of file system and the volume label and serial number only when the medium changes. | OS/2 uses the volume label and serial number to ensure that the medium in the drive does not change while there are outstanding requests for input and output. Each volume has a volume label and a 32-bit volume serial number, stored in a reserved location in logical sector 0 at the time of formatting. If the volume label and serial number do not match, OS/2 signals the critical error handler to prompt the user to insert the volume that has the specified serial number and label. OS/2 maintains the connection between the medium and the volume label and serial number until all open files on the volume are closed and all search references and cache buffer references are removed. The system redetermines the type of file system and the volume label and serial number only when the medium changes. | ||
OS/2 enables applications to: | OS/2 enables applications to: | ||
*Determine and set the default drive using [[DosQueryCurrentDisk]] and [[DosSetDefaultDisk]], respectively. | *Determine and set the default drive using [[DosQueryCurrentDisk]] and [[DosSetDefaultDisk]], respectively. | ||
*Determine and set drive information using [[DosQueryFSInfo]] and [[DosSetFSInfo]]. | *Determine and set drive information using [[DosQueryFSInfo]] and [[DosSetFSInfo]]. | ||
*Determine and set the write verification switch using [[DosQueryVerify]] and [[DosSetVerify]]. If the write verification switch is on, each time data is written to the disk, the data is verified to ensure it has been recorded correctly. These functions are provided for recording critical data. | *Determine and set the write verification switch using [[DosQueryVerify]] and [[DosSetVerify]]. If the write verification switch is on, each time data is written to the disk, the data is verified to ensure it has been recorded correctly. These functions are provided for recording critical data. | ||
==About Directories== | ==About Directories== | ||
When an application starts, it inherits the current directory and drive from the application that starts it. An application can determine which directory and drive are current by using DosQueryCurrentDir and DosQueryCurrentDisk. An application can change the current directory and drive of the file system by using DosSetCurrentDir and DosSetDefaultDisk. | When an application starts, it inherits the current directory and drive from the application that starts it. An application can determine which directory and drive are current by using DosQueryCurrentDir and DosQueryCurrentDisk. An application can change the current directory and drive of the file system by using DosSetCurrentDir and DosSetDefaultDisk. | ||
When an application creates a new file, the system adds a file entry to the specified directory. Each directory can have any number of entries, up to the physical limit of the disk. An application can create new directories and delete existing directories by using DosCreateDir and DosDeleteDir. Before a directory can be deleted, it must be empty; if there are files or directories in that directory, they must be deleted or moved. An application can delete a file by using DosDelete or move a file to another directory by using DosMove. | |||
===Creating a Subdirectory=== | ===Creating a Subdirectory=== | ||
To create a new subdirectory, an application calls DosCreateDir and specifies a directory path name. If the call is successful, a new subdirectory is created at the end of the path on the specified disk. If no path name is specified, a new subdirectory is created at the end of the current directory for the process. If any subdirectories in the path do not exist, the subdirectory is not created. | To create a new subdirectory, an application calls DosCreateDir and specifies a directory path name. If the call is successful, a new subdirectory is created at the end of the path on the specified disk. If no path name is specified, a new subdirectory is created at the end of the current directory for the process. If any subdirectories in the path do not exist, the subdirectory is not created. | ||
Because a subdirectory is a file object, an application also can define an extended attribute for the directory when it is created during this call. See Extended Attributes for more information on extended attributes. | |||
===Determining and Changing the Current Directory=== | ===Determining and Changing the Current Directory=== | ||
Calling DosQueryCurrentDir returns the full path name of the current directory for the specified drive. The string does not begin with a back slash (\) and it ends with a byte containing 00H, the NULL character. | Calling DosQueryCurrentDir returns the full path name of the current directory for the specified drive. The string does not begin with a back slash (\) and it ends with a byte containing 00H, the NULL character. | ||
To change the current directory, call DosQueryCurrentDir with the path name of the directory you want to make the current directory. | |||
===Deleting a Directory === | ===Deleting a Directory === | ||
A subdirectory cannot be removed if it is the current subdirectory or if it contains hidden files or subdirectory entries other than the "." and ".." entries. When these requirements for removal are met, DosDeleteDir can be called with a path name to remove the subdirectory from the disk. | A subdirectory cannot be removed if it is the current subdirectory or if it contains hidden files or subdirectory entries other than the "." and ".." entries. When these requirements for removal are met, DosDeleteDir can be called with a path name to remove the subdirectory from the disk. | ||
==About Files== | ==About Files== | ||
A file is one or more bytes of data, usually stored on a disk. While the application that creates the file determines the format of the file, the file system determines how the file is stored on the disk and what actions can be performed on it. The file system also stores information about the file in file attributes and extended attributes. | A file is one or more bytes of data, usually stored on a disk. While the application that creates the file determines the format of the file, the file system determines how the file is stored on the disk and what actions can be performed on it. The file system also stores information about the file in file attributes and extended attributes. | ||
Files are accessed through the file system using file handles. File handles are returned by DosOpen when the file is opened and are used for all subsequent accesses to the file. Files can be be opened, read from, written to, closed, copied, moved, deleted, renamed, and locked. Files can be searched for based on a metacharacter template. | |||
Each open file has a file pointer that indicates the current reading or writing location within the file. The file pointer moves automatically with each read or write operation on the file and can be moved manually by the application. | |||
===File Attributes=== | ===File Attributes=== | ||
Each directory entry includes a set of file attributes. File attributes specify whether the directory entry is for a file, a directory, or a volume identifier. The attributes also specify if the file is read-only, hidden, archived, or a system file. | Each directory entry includes a set of file attributes. File attributes specify whether the directory entry is for a file, a directory, or a volume identifier. The attributes also specify if the file is read-only, hidden, archived, or a system file. | ||
A read-only file cannot be opened for writing, nor can it be deleted. A hidden file (or directory) cannot be displayed by using an ordinary directory listing. A system file is excluded from normal directory searches. The archived attribute is for use by special purpose applications to mark a file that has been changed since the last time the file was examined. | |||
An application can retrieve and set the file attributes by using DosQueryFileInfo and DosSetFileInfo. | |||
===File Handles=== | ===File Handles=== | ||
OS/2 identifies each open file by assigning it a file handle when the application opens or creates the file. The file handle is a unique 32-bit integer. The application can use the handle in functions that read from and write to the file, depending on how the file was opened. The application can continue to use the handle until the file is closed. | OS/2 identifies each open file by assigning it a file handle when the application opens or creates the file. The file handle is a unique 32-bit integer. The application can use the handle in functions that read from and write to the file, depending on how the file was opened. The application can continue to use the handle until the file is closed. | ||
The default maximum number of file handles for a process is 50. An application can change this maximum by using DosSetMaxFH. When this call is made, all currently open file handles are preserved. | The default maximum number of file handles for a process is 50. An application can change this maximum by using DosSetMaxFH. When this call is made, all currently open file handles are preserved. | ||
In the past, the maximum number of file handles was 20. If you previously had code that increased the maximum file handles from 20 to less than 50, you can now remove this code. | In the past, the maximum number of file handles was 20. If you previously had code that increased the maximum file handles from 20 to less than 50, you can now remove this code. | ||
When an application starts, it inherits all open file handles from the process that starts it. If the system's command processor starts an application, file handles 0, 1, and 2 represent the standard input, standard output, and standard error files. The standard input file is the keyboard; the standard output and standard error files are the screen. An application can read from the standard input file and write to the standard output and standard error files immediately; it does not have to open the files first. | When an application starts, it inherits all open file handles from the process that starts it. If the system's command processor starts an application, file handles 0, 1, and 2 represent the standard input, standard output, and standard error files. The standard input file is the keyboard; the standard output and standard error files are the screen. An application can read from the standard input file and write to the standard output and standard error files immediately; it does not have to open the files first. | ||
An application can create a duplicate file handle for an open file by using DosDupHandle. A duplicate handle is identical to the original handle. Typically, duplicate handles are used to redirect the standard input and standard output files. For example, an application can open a disk file and duplicate the disk-file handle as handle 0. Thereafter, an application reading from the standard input file (handle 0) takes data from the disk file, not from the keyboard. | An application can create a duplicate file handle for an open file by using DosDupHandle. A duplicate handle is identical to the original handle. Typically, duplicate handles are used to redirect the standard input and standard output files. For example, an application can open a disk file and duplicate the disk-file handle as handle 0. Thereafter, an application reading from the standard input file (handle 0) takes data from the disk file, not from the keyboard. | ||
When devices and pipes are accessed through the file system functions (using DosOpen, DosRead, and so on), the devices and pipes are treated as files and are identified using file handles. The standard file handles can be redirected to a device or pipe. | |||
===File Pointer=== | ===File Pointer=== | ||
Every open file has a file pointer that specifies the next byte to be read or the location to receive the next byte that is written. When a file is first opened, the system places the file pointer at the beginning of the file. As each byte is read or written, OS/2 advances the pointer. | Every open file has a file pointer that specifies the next byte to be read or the location to receive the next byte that is written. When a file is first opened, the system places the file pointer at the beginning of the file. As each byte is read or written, OS/2 advances the pointer. | ||
An application can also move the pointer by using DosSetFilePtr. When the pointer reaches the end of the file and the application attempts to read from the file, no bytes are read and no error occurs. Thus, reading 0 bytes without an error means the program has reached the end of the file. | An application can also move the pointer by using DosSetFilePtr. When the pointer reaches the end of the file and the application attempts to read from the file, no bytes are read and no error occurs. Thus, reading 0 bytes without an error means the program has reached the end of the file. | ||
When an application writes to a disk file, the data being written is usually collected in an internal buffer. OS/2 writes to the disk only when the amount of data equals (or is a multiple of) the sector size of the disk. If there is data in the internal buffer when the file is closed, the system automatically writes the data to the disk before closing the file. An application can also flush the buffer (that is, write the contents of the buffer to the disk) by using DosResetBuffer. | |||
===Copying Files=== | ===Copying Files=== | ||
DosCopy is used to copy files and subdirectories. Metacharacters (global file name characters) are not allowed, so only individual files or entire subdirectories can be copied with this function. The source and target can be on different drives. | DosCopy is used to copy files and subdirectories. Metacharacters (global file name characters) are not allowed, so only individual files or entire subdirectories can be copied with this function. The source and target can be on different drives. | ||
When the source specified is a subdirectory and an I/O error occurs, the file being copied from the source directory to the target directory at the time of the error will be deleted from the target directory and DosCopy will be terminated. | When the source specified is a subdirectory and an I/O error occurs, the file being copied from the source directory to the target directory at the time of the error will be deleted from the target directory and DosCopy will be terminated. | ||
When a file is being copied and an I/O error occurs, | When a file is being copied and an I/O error occurs, | ||
*if the source file name is that of a file to be replaced, the file is deleted from the target path. | |||
*if the source file name is that of a file to be appended, the target file is resized to its original size. | |||
DosCopy will copy the attributes of the source file, such as date of creation, and time of creation to the target file. Additionally, DosCopy will copy the extended attributes of the source file when creating a new subdirectory or a new file, or when replacing an existing file. | |||
===Moving Files=== | |||
DosMove is used to move a file from one subdirectory to another on the same drive. In the process of moving the file, its name can be changed. Metacharacters (global file name characters) are not permitted. | |||
===Deleting Files=== | ===Deleting Files=== | ||
Calling DosDelete removes the directory entry associated with a file name. Metacharacters (global file name characters) are not permitted. | Calling DosDelete removes the directory entry associated with a file name. Metacharacters (global file name characters) are not permitted. | ||
Files whose read-only attribute is set cannot be deleted. | |||
===Changing File Sizes=== | ===Changing File Sizes=== | ||
DosSetFileSize is used to extend or truncate the size of a file that is open for Read/Write or Write-Only access. | DosSetFileSize is used to extend or truncate the size of a file that is open for Read/Write or Write-Only access. | ||
When a file is extended, for example to reserve disk space, the value of the additional bytes allocated by the system is undefined. | |||
===Locking and Unlocking File Regions=== | ===Locking and Unlocking File Regions=== | ||
Because OS/2 permits more than one application to open a file and write to it, it is important that the applications not write over each other's work. An application can protect against this problem by temporarily locking a region in a file. | Because OS/2 permits more than one application to open a file and write to it, it is important that the applications not write over each other's work. An application can protect against this problem by temporarily locking a region in a file. | ||
DosSetFileLocks provides a simple mechanism that temporarily prevents access by other processes to regions within a file. DosSetFileLocks specifies a range of bytes in the file that is locked by an application and that can be accessed only by the application locking the region. The application uses the same function to free the locked region. | DosSetFileLocks provides a simple mechanism that temporarily prevents access by other processes to regions within a file. DosSetFileLocks specifies a range of bytes in the file that is locked by an application and that can be accessed only by the application locking the region. The application uses the same function to free the locked region. | ||
Locking and unlocking regions in a file enables sharing processes to coordinate their efforts. A process can lock a region in a file so the process can read and update the file region. A sharing process that attempts to lock the region before the other process finishes its update and unlocks the region receives an error code. When a lock is unsuccessful because a lock is already in place, ERROR_LOCK_VIOLATION is returned. | Locking and unlocking regions in a file enables sharing processes to coordinate their efforts. A process can lock a region in a file so the process can read and update the file region. A sharing process that attempts to lock the region before the other process finishes its update and unlocks the region receives an error code. When a lock is unsuccessful because a lock is already in place, ERROR_LOCK_VIOLATION is returned. | ||
A lock that extends beyond end-of-file is not considered an error. However, a locked region cannot overlap another locked region, nor can it encompass a locked region. Any such conflicting locks must be cleared before a region can be locked. | A lock that extends beyond end-of-file is not considered an error. However, a locked region cannot overlap another locked region, nor can it encompass a locked region. Any such conflicting locks must be cleared before a region can be locked. | ||
When a file handle is duplicated, the duplicate handle has access to any locked regions currently being accessed by the original handle. Although a child process created with DosExecPgm can inherit the file handles of its parent process, it does not inherit access to locked regions in effect for a file handle unless the file handle is duplicated and passed to it. | When a file handle is duplicated, the duplicate handle has access to any locked regions currently being accessed by the original handle. Although a child process created with DosExecPgm can inherit the file handles of its parent process, it does not inherit access to locked regions in effect for a file handle unless the file handle is duplicated and passed to it. | ||
;Note: File locks are intended to be in effect for only short periods of time. | ;Note: File locks are intended to be in effect for only short periods of time. | ||
:When a file with locks is closed, the locks are released in no defined order. | |||
===Searching for Files=== | |||
An application can use DosFindFirst, DosFindNext, and DosFindClose to search the current directory for all file names that match a given pattern. | |||
The pattern must be an OS/2 file name and can include metacharacters (global file name characters). The wildcard characters are the question mark (?) and the asterisk (*). The question mark matches any single character; the asterisk matches any combination of characters. For example, the pattern "A*" matches the names "ABC", "A23", and "ABCD", but the pattern "A?C" matches only the name "ABC". | |||
=== | ===Determining the Maximum Path Length=== | ||
An application can | An application that recognizes long file names might be run on systems with or without installable file systems. Additionally, the maximum length of a file name might vary from one installable file system to another. So that an application can properly handle this variable condition (and, for example, allocate large enough buffers to hold file names), the application should call DosQuerySysInfo to determine the maximum path length supported by the file system. | ||
Make this call before calling file system functions that require full path names. | |||
===Specifying an Extended LIBPATH=== | ===Specifying an Extended LIBPATH=== | ||
The LIBPATH, which is set in CONFIG.SYS, specifies a search path which OS/2 uses when searching for dynamic link libraries (DLLs). The LIBPATH is set during system startup and cannot be changed dynamically. | The LIBPATH, which is set in CONFIG.SYS, specifies a search path which OS/2 uses when searching for dynamic link libraries (DLLs). The LIBPATH is set during system startup and cannot be changed dynamically. | ||
OS/2 provides the capability of specifying extensions to the LIBPATH. An Extended LIBPATH is a path which is searched in conjunction with the system LIBPATH, but which can be changed dynamically, either by the user from the command line, or by an application. | |||
There are two Extended LIBPATHs: BeginLIBPATH, which is searched before the system LIBPATH, and EndLIBPATH, which is searched after the system LIBPATH. | |||
Extended LIBPATHs are ASCIIZ strings which are formatted in the same manner as the system LIBPATH, that is, they contains a list of subdirectory paths separated by semicolons. The maximum size for each Extended LIBPATH is 1024 characters. | |||
Extended LIBPATHs | Applications can use DosSetExtLIBPATH to set the Extended LIBPATHs. Likewise, they can use DosQueryExtLIBPATH to query the value of either of the Extended LIBPATHs. A flag parameter for the function specifies whether the BeginLIBPATH or the EndLIBPATH is being set or queried. The flag allows two values: BEGIN_LIBPATH (1) which will set or query BeginLIBPATH, or END_LIBPATH (2) which will set or query EndLIBPATH. | ||
You can call DosSetExtLIBPATH as often as you want. The new Extended LIBPATH that you pass in will replace the current Extended LIBPATH. | |||
You can | You can specify the current Extended LIBPATH as part of the argument by using the % symbol before and after the Extended LIBPATH variable name, that is, as %BeginLIBPATH% or %EndLIBPATH%. For example, suppose you set BeginLIBPATH to "D:\MYDLLS", then later you want to add "D:\TOMSDLLS" before the existing BeginLIBPATH, and "D:\JOESDLLS" after the existing BeginLIBPATH (that is, you want to change BeginLIBPATH to "D:\TOMSDLLS;D:\MYDLLS;D:\JOESDLLS"). You could accomplish this by using "D:\TOMSDLLS;%BeginLIBPATH%;D:\JOESDLLS" as the argument for DosSetExtLIBPATH. | ||
The string argument can be up to 1024 characters long. However, if the resulting Extended LIBPATH is longer than 1024 characters, the function will return an error. | |||
===Devices=== | ===Devices=== | ||
OS/2 enables you to access peripheral devices using file system commands, and treat those devices as file streams of data. These devices include: | OS/2 enables you to access peripheral devices using file system commands, and treat those devices as file streams of data. These devices include: | ||
;Character devices:COM, clock, console (keyboard and screen), screen, keyboard, printer, null, pointer, and mouse devices. | |||
;Character devices | ;Standard I/O devices:Character devices automatically installed by OS/2 and recognized by the file system as the standard input, standard output, and standard error devices. | ||
:COM, clock, console (keyboard and screen), screen, keyboard, printer, null, pointer, and mouse devices. | ;Pseudocharacter devices:An application can attach a device name to a file system and use the file system as a pseudocharacter device (also called a single-file device). Attaching a device name to a file system allows an application to open the device associated with the file system as if it were a character device (for example, a serial port) and read from and write to the device by using DosRead and DosWrite. | ||
:In addition, an application can use DosSetFilePtr and DosSetFileLocks with a pseudocharacter device. Also, pseudocharacter devices can be redirected. | |||
;Standard I/O devices | :A file system that can be attached to a pseudocharacter device is typically associated with a single disk file or with a special storage device, such as a tape drive. The file system establishes a connection with the device and transfers requests and data between OS/2 and the device. The user perceives this file as a device name for a nonexistent device. | ||
:Character devices automatically installed by OS/2 and recognized by the file system as the standard input, standard output, and standard error devices. | :This file is seen as a character device because the current drive and directory have no effect on the name. A pseudocharacter device name is an ASCII string with the name of an OS/2 file in the form: | ||
;Pseudocharacter devices | |||
:An application can attach a device name to a file system and use the file system as a pseudocharacter device (also called a single-file device). Attaching a device name to a file system allows an application to open the device associated with the file system as if it were a character device (for example, a serial port) and read from and write to the device by using DosRead and DosWrite. | |||
:In addition, an application can use DosSetFilePtr and DosSetFileLocks with a pseudocharacter device. Also, pseudocharacter devices can be redirected. | |||
:A file system that can be attached to a pseudocharacter device is typically associated with a single disk file or with a special storage device, such as a tape drive. The file system establishes a connection with the device and transfers requests and data between OS/2 and the device. The user perceives this file as a device name for a nonexistent device. | |||
:This file is seen as a character device because the current drive and directory have no effect on the name. A pseudocharacter device name is an ASCII string with the name of an OS/2 file in the form: | |||
\DEV\DEV_NAME | \DEV\DEV_NAME | ||
:The "\dev\" is a required part of the name, but there is no actual subdirectory named "\dev\". This just lets OS/2 know that it is a pseudocharacter device name. | |||
:The "\dev\" is a required part of the name, but there is no actual subdirectory named "\dev\". This just lets OS/2 know that it is a pseudocharacter device name. | ;Logical file:devices The hard disk or floppy disk drives, or the partitions on the hard disk or floppy disk drives. | ||
;Logical file | |||
:devices The hard disk or floppy disk drives, or the partitions on the hard disk or floppy disk drives. | |||
==Using File Commands== | ==Using File Commands== | ||
Files are accessed through the file system using file handles. File handles are returned by DosOpen when the file is opened and are used for all subsequent accesses to the file. Files can be be created, opened, read from, written to, closed, copied, moved, deleted, renamed, and locked. Files can be searched for based on a metacharacter pattern template. | Files are accessed through the file system using file handles. File handles are returned by DosOpen when the file is opened and are used for all subsequent accesses to the file. Files can be be created, opened, read from, written to, closed, copied, moved, deleted, renamed, and locked. Files can be searched for based on a metacharacter pattern template. | ||
Each open file has a file pointer that indicates the current reading or writing location within the file. The file pointer moves automatically with each read or write operation on the file and can be moved manually by the application. | Each open file has a file pointer that indicates the current reading or writing location within the file. The file pointer moves automatically with each read or write operation on the file and can be moved manually by the application. | ||
The standard file handles-standard input, standard output, and standard error-provide redirectable input and output to applications. The standard file handles can be used to read input from the keyboard and write output to the display. Alternatively, they can be redirected to read input from and write output to a file. To an application reading and writing the standard file handles, there is no difference between the two. | The standard file handles-standard input, standard output, and standard error-provide redirectable input and output to applications. The standard file handles can be used to read input from the keyboard and write output to the display. Alternatively, they can be redirected to read input from and write output to a file. To an application reading and writing the standard file handles, there is no difference between the two. | ||
;Note: In the example code fragments that follow, error checking was left out to conserve space. Applications should always check the return code that the functions return. Control Program functions return an APIRET value. A return code of 0 indicates success. If a non-zero value is returned, an error occurred. | ;Note: In the example code fragments that follow, error checking was left out to conserve space. Applications should always check the return code that the functions return. Control Program functions return an APIRET value. A return code of 0 indicates success. If a non-zero value is returned, an error occurred. | ||
===Creating Files=== | ===Creating Files=== | ||
DosOpen is used to create files, which are then read from or written to. To create a file, specify FILE_CREATE as the sixth argument in the call to the function. DosOpen then creates the file, if it does not already exist. If the file already exists, the function returns the error value FILE_EXISTED. | DosOpen is used to create files, which are then read from or written to. To create a file, specify FILE_CREATE as the sixth argument in the call to the function. DosOpen then creates the file, if it does not already exist. If the file already exists, the function returns the error value FILE_EXISTED. | ||
The following code fragment shows how to use DosOpen to create the file NEWFILE.TXT: | |||
<pre> | <pre> | ||
#define INCL_DOSFILEMGR /* File System values */ | |||
#include <os2.h> | |||
HFILE hf; | |||
ULONG ulAction; | |||
APIRET ulrc; | |||
ulrc = DosOpen("NEWFILE.TXT", /* Name of file to create and open */ | |||
&hf, /* Address of file handle */ | |||
&ulAction, /* Action taken */ | |||
0, /* Size of new file */ | |||
FILE_NORMAL, /* File attributes */ | |||
FILE_CREATE, /* Creates the file */ | |||
OPEN_ACCESS_WRITEONLY | | |||
OPEN_SHARE_DENYNONE, | |||
(PEAOP2) NULL); /* No extended attributes */ | |||
</pre> | </pre> | ||
In this example, DosOpen creates the file and opens it for writing only. Note that the sharing method chosen permits other processes to open the file for any access. The new file is empty (contains no data). | |||
When you use DosOpen to create (or replace) a file, you must specify the attributes the new file is to have. In the preceding example, this value is FILE_NORMAL, so the file is created as a normal file. Other possible file attributes include read-only and hidden, which correspond to FILE_READONLY and FILE_HIDDEN, respectively. The possible file attributes are: | |||
File Attribute Defined Constant | |||
When you use DosOpen to create (or replace) a file, you must specify the attributes the new file is to have. In the preceding example, this value is FILE_NORMAL, so the file is created as a normal file. Other possible file attributes include read-only and hidden, which correspond to FILE_READONLY and FILE_HIDDEN, respectively. The possible file attributes are: | Normal file FILE_NORMAL | ||
Read-only file FILE_READONLY | |||
File Attribute Defined Constant | Hidden file FILE_HIDDEN | ||
Normal file FILE_NORMAL | System file FILE_SYSTEM | ||
Read-only file FILE_READONLY | Subdirectory FILE_DIRECTORY | ||
Hidden file FILE_HIDDEN | Archived file FILE_ARCHIVED. | ||
System file FILE_SYSTEM | The file attribute affects how other processes access the file. For example, if the file is read-only, no process can open the file for writing. There is one exception-the process that creates the read-only file can write to it immediately after creating it. After closing the file, however, the process cannot reopen it for writing. | ||
Subdirectory FILE_DIRECTORY | |||
Archived file FILE_ARCHIVED. | |||
If you are creating a new file object (a new file or a replacement for an existing one), you must specify the size of the new file in bytes. For example, if you specify 256, the file size is 256 bytes. However, these 256 bytes are undefined. If the file being opened already exists, the file size parameter is ignored. It is up to the application to write valid data to the file. No matter what size you specify, the file pointer is set to point to the beginning of the file so a subsequent call to DosWrite starts writing data at the beginning of the file. | |||
Extended attributes can be defined by an application when a file object is created. An application can define an extended attribute for a file when the file is created during a DosOpen call. | |||
Applications can also control access to specific regions within a file by calling DosSetFileLocks. | |||
===Opening Files=== | ===Opening Files=== | ||
Before performing input or output operations on a file, you must open the file and obtain a file handle. You obtain a file handle by using DosOpen. This function opens the specified file and returns a file handle for it. DosOpen can also be used to create new files. | Before performing input or output operations on a file, you must open the file and obtain a file handle. You obtain a file handle by using DosOpen. This function opens the specified file and returns a file handle for it. DosOpen can also be used to create new files. | ||
DosOpen establishes a connection betwee n a file object and an application. This connection is in the form of a 32-bit identifier called a file handle, which is used to refer to the file object and any information associated with it. DosOpen returns a handle that is used in other file system calls to gain access to the object. The file object can be a new file, an existing file, or a replacement for an existing file. It can also be a character device, a block device, or the client end of a named pipe. The type of object is determined by the file name you pass to DosOpen. | DosOpen establishes a connection betwee n a file object and an application. This connection is in the form of a 32-bit identifier called a file handle, which is used to refer to the file object and any information associated with it. DosOpen returns a handle that is used in other file system calls to gain access to the object. The file object can be a new file, an existing file, or a replacement for an existing file. It can also be a character device, a block device, or the client end of a named pipe. The type of object is determined by the file name you pass to DosOpen. | ||
;Note: If the object is a named pipe, it must be in a listening state for DosOpen to be successful. | ;Note: If the object is a named pipe, it must be in a listening state for DosOpen to be successful. | ||
The following code fragment shows the use of DosOpen to: | |||
*Open the existing file SAMPLE.TXT for reading | |||
*Put the file handle into the hf variable | |||
<pre> | <pre> | ||
#define INCL_DOSFILEMGR /* File System values */ | |||
#include <os2.h> | |||
HFILE hf; | |||
ULONG ulAction; | |||
APIRET ulrc; | |||
ulrc = DosOpen("SAMPLE.TXT", /* Name of file to open */ | |||
&hf, /* Address of file handle */ | |||
&ulAction, /* Action taken */ | |||
0, /* Size of file */ | |||
FILE_NORMAL, /* File attribute */ | |||
FILE_OPEN, /* Open the file */ | |||
OPEN_ACCESS_READONLY | | |||
OPEN_SHARE_DENYNONE, | |||
(PEAOP2) NULL); /* Extended attribute buffer */ | |||
</pre> | </pre> | ||
If DosOpen successfully opens the file, it copies the file handle to the hf variable and copies a value to the ulAction variable indicating what action was taken (for example, FILE_EXISTED for "existing file opened"). A file size is not needed to open an existing file, so the fourth argument is 0. The fifth argument, FILE_NORMAL, specifies the normal file attribute. The sixth argument, FILE_OPEN, directs DosOpen to open the file if it exists or return an error if it does not exist. The seventh argument directs DosOpen to open the file for reading only and enables other applications to open the file even while the current application has it open. The final argument is a pointer to a structure containing information on extended attributes. If the file has no extended attributes, this argument must be NULL. | If DosOpen successfully opens the file, it copies the file handle to the hf variable and copies a value to the ulAction variable indicating what action was taken (for example, FILE_EXISTED for "existing file opened"). A file size is not needed to open an existing file, so the fourth argument is 0. The fifth argument, FILE_NORMAL, specifies the normal file attribute. The sixth argument, FILE_OPEN, directs DosOpen to open the file if it exists or return an error if it does not exist. The seventh argument directs DosOpen to open the file for reading only and enables other applications to open the file even while the current application has it open. The final argument is a pointer to a structure containing information on extended attributes. If the file has no extended attributes, this argument must be NULL. | ||
DosOpen returns 0 if it successfully op ens the file. Applications use the file handle in subsequent functions to read data from the file or to check the status and other file characteristics. If DosOpen fails to open the file, it returns an error value. | DosOpen returns 0 if it successfully op ens the file. Applications use the file handle in subsequent functions to read data from the file or to check the status and other file characteristics. If DosOpen fails to open the file, it returns an error value. | ||
When you open a file you must specify whether you want to read from the file, write to it, or both read and write. Also, since more than one application might attempt to open the same file, you must also specify whether you want to allow other processes to have access to the file while you have it open. A file that is shared can be shared for reading only, writing only, or reading and writing. A file that is not shared cannot be opened by another application (or more than once by the first application) until it has been closed by the first application. | When you open a file you must specify whether you want to read from the file, write to it, or both read and write. Also, since more than one application might attempt to open the same file, you must also specify whether you want to allow other processes to have access to the file while you have it open. A file that is shared can be shared for reading only, writing only, or reading and writing. A file that is not shared cannot be opened by another application (or more than once by the first application) until it has been closed by the first application. | ||
An application defines its file access rights (that is, I/O it needs to perform on a file) by setting the appropriate file access mode field in the file open-mode parameter. An application accesses a file as: | An application defines its file access rights (that is, I/O it needs to perform on a file) by setting the appropriate file access mode field in the file open-mode parameter. An application accesses a file as: | ||
*Read-only | |||
*Write-only | |||
*Read/write | |||
An application defines what I/O operations other processes can perform on a file by setting the appropriate sharing mode field in the OpenMode parameter. Other processes are granted: | |||
*Deny read/write access | |||
*Deny write access | |||
*Deny read access | |||
*Deny neither read or write access (deny none) | |||
File sharing requires cooperation between the sharing processes. For example, if process A calls DosOpen to open a file with Deny Write sharing and process B calls DosOpen to open the same file with Read/Write access, the DosOpen call made by process B fails. | |||
You indicate whether or not you want to permit another application to access your file by combining an OPEN_ACCESS_ value and an OPEN_SHARE_ value from the following list: | |||
{|class="wikitable" | |||
|+File Access and Sharing Rights | |||
!Value||Meaning | |||
|- | |||
|OPEN_ACCESS_READONLY||Open a file for reading. | |||
|- | |||
|OPEN_ACCESS_WRITEONLY||Open a file for writing. | |||
|- | |||
|OPEN_ACCESS_READWRITE||Open a file for reading and writing. | |||
|- | |||
|OPEN_SHARE_DENYREADWRITE||Open a file for exclusive use, denying other processes read and write access. | |||
|- | |||
|OPEN_SHARE_DENYWRITE||Deny other processes write access to a file. | |||
|- | |||
|OPEN_SHARE_DENYREAD||Deny other processes read access to a file. | |||
|- | |||
|OPEN_SHARE_DENYNONE||Open a file with no sharing restrictions, granting read and write access to all processes. | |||
|} | |||
In general, you can combine any access method (read, write, or read and write) with any sharing method (deny reading, deny writing, deny reading and writing, or grant any access). Some combinations have to be handled carefully, however, such as opening a file for writing without denying other processes access to it. | |||
;Note: For named pipes, the access and sharing modes must be consistent with those specified by DosCreateNPipe. | |||
Other characteristics of the file handle that can be set: | |||
{|class="wikitable" | |||
|+File Handle Characteristics | |||
!Flag||Purpose | |||
|- | |||
|Inheritance||Handle is inherited by a child process created with DosExecPgm, or is private to the calling process. | |||
|- | |||
|Write-Through||Actual I/O for synchronous writes is not guaranteed as complete or is guaranteed as complete before the write returns. | |||
|- | |||
|Fail-Errors||Media errors are reported by the system critical error handler, or by the application. | |||
|- | |||
|DASD||The file name parameter is the name of a file or device opened in the normal way, or a drive specification for a fixed disk or diskette drive. The DASD flag can be set for direct access to an entire disk or diskette volume, independent of the file system. When the DASD flag is set, the handle returned by DosOpen represents the logical volume as a single file. To block other processes from accessing the logical volume, a DosDevIOCtl Category 8, Function 0 call should be made using the handle returned by DosOpen. The DASD flag should be set only by systems programs, not by applications. | |||
|- | |||
|Cache||The file system caches or does not cache data for I/O operations on the file. This flag is advisory only. | |||
|} | |||
See the [[DosOpen]] material in the Control Program Programming Reference for details of these characteristics. | |||
After an object has been opened, its file handle state flags can be queried by calling [[DosQueryFHState]] and reset by calling [[DosSetFHState]]. See Determining and Setting the State of a File or Device Handle for information on determining the state of a file handle. | |||
When a child process inherits a file handle, it also inherits the sharing and access rights of the file. | |||
; | You cannot use metacharacters (global file name characters; * and ?) in file names you supply to DosOpen. | ||
===Reading from Files=== | ===Reading from Files=== | ||
Once you open a file or have a file handle, you can read from and write to the file by using DosRead and DosWrite. | Once you open a file or have a file handle, you can read from and write to the file by using DosRead and DosWrite. | ||
DosRead is called with a handle (obtained with DosOpen) for a file, pipe, or device. DosRead copies a specified number of bytes (up to the end of the file) from the file object to the buffer you specify. OS/2 returns, in a parameter, the number of bytes actually read (which might not be the same as the number of bytes requested because the end of the file might have been reached). | DosRead is called with a handle (obtained with DosOpen) for a file, pipe, or device. DosRead copies a specified number of bytes (up to the end of the file) from the file object to the buffer you specify. OS/2 returns, in a parameter, the number of bytes actually read (which might not be the same as the number of bytes requested because the end of the file might have been reached). | ||
To read from a file, you must open it for reading or for reading and writing. | To read from a file, you must open it for reading or for reading and writing. | ||
The following code fragment shows how to open the file named SAMPLE.TXT and read the first 512 bytes from it: | |||
The following code fragment shows how to open the file named SAMPLE.TXT and read the first 512 bytes from it: | |||
<pre> | <pre> | ||
#define INCL_DOSFILEMGR /* File System values */ | #define INCL_DOSFILEMGR /* File System values */ | ||
Line 391: | Line 329: | ||
} | } | ||
</pre> | </pre> | ||
If the file does not have 512 bytes, DosRead reads to the end of the file and puts the number of bytes read in the cbRead variable. If the file pointer is already positioned at the end of the file when DosRead is called, the function puts a 0 in the cbRead variable. | |||
===Writing to Files=== | ===Writing to Files=== | ||
Once you open a file or have a file handle, you can read from and write to the file by using DosRead and DosWrite. | Once you open a file or have a file handle, you can read from and write to the file by using DosRead and DosWrite. | ||
DosWrite copies bytes from a buffer you specify to a file, device, or pipe. | DosWrite copies bytes from a buffer you specify to a file, device, or pipe. | ||
Calling DosWrite with a handle for a file, pipe, or device transfers the number of bytes specified from a buffer location to the object. The system returns, in a parameter, the number of bytes actually written (which in the case of a disk file might not be the same as the number requested because of insufficient disk space). | Calling DosWrite with a handle for a file, pipe, or device transfers the number of bytes specified from a buffer location to the object. The system returns, in a parameter, the number of bytes actually written (which in the case of a disk file might not be the same as the number requested because of insufficient disk space). | ||
To write to a file, you must first open it for writing or for reading and writing. | To write to a file, you must first open it for writing or for reading and writing. | ||
The following code fragment shows how to open the file SAMPLE.TXT again and write 512 bytes to it: | |||
The following code fragment shows how to open the file SAMPLE.TXT again and write 512 bytes to it: | |||
<pre> | <pre> | ||
#define INCL_DOSFILEMGR /* File System values */ | #define INCL_DOSFILEMGR /* File System values */ | ||
Line 484: | Line 421: | ||
&ulWritten); | &ulWritten); | ||
</pre> | </pre> | ||
In this example, DosSetFilePtr moves the file pointer to the 200th byte from the end of the file. If the file is not that long, the function moves the pointer to the first byte in the file and returns the actual position (relative to the end of the file) in the ulNewPtr variable. | |||
You can move the file pointer for disk files only. You cannot use DosSetFilePtr on devices, despite using other file functions (DosOpen, DosRead) to access a device. | |||
If a file is read-only, write operations to the file will not be performed. | |||
Moving the pointer from the end of the file can be used to determine the size of the file. | |||
===Closing Files=== | ===Closing Files=== | ||
You can close a file by using DosClose. Since each application has a limited number of file handles that can be open at one time, it is a good practice to close a file after using it. | You can close a file by using DosClose. Since each application has a limited number of file handles that can be open at one time, it is a good practice to close a file after using it. | ||
To do so, supply the file handle in DosClose, as shown in the following code fragment: | To do so, supply the file handle in DosClose, as shown in the following code fragment: | ||
<pre> | <pre> | ||
#define INCL_DOSFILEMGR /* File system values */ | #define INCL_DOSFILEMGR /* File system values */ | ||
Line 527: | Line 464: | ||
} | } | ||
</pre> | </pre> | ||
If you open a file for writing, DosClose directs the system to flush the file buffer-that is, to write any existing data in OS/2's intermediate file buffer to the disk or device. The system keeps these intermediate file buffers to make file input and output more efficient. For example, it saves data from previous calls to DosWrite until a certain number of bytes are in the buffer then writes the contents of the buffer to the disk. | If you open a file for writing, DosClose directs the system to flush the file buffer-that is, to write any existing data in OS/2's intermediate file buffer to the disk or device. The system keeps these intermediate file buffers to make file input and output more efficient. For example, it saves data from previous calls to DosWrite until a certain number of bytes are in the buffer then writes the contents of the buffer to the disk. | ||
DosClose also closes the handle to the file (or pipe, or device). If one or more additional handles to a file have been created with DosDupHandle , the internal buffers for the file are not written to disk, and its directory entry is not updated, until DosClose has been called for all the handles. | DosClose also closes the handle to the file (or pipe, or device). If one or more additional handles to a file have been created with DosDupHandle, the internal buffers for the file are not written to disk, and its directory entry is not updated, until DosClose has been called for all the handles. | ||
===Creating Duplicate File or Device Handles=== | ===Creating Duplicate File or Device Handles=== | ||
DosDupHandle enables a process to create a duplicate handle for an open file, pipe, or device. | DosDupHandle enables a process to create a duplicate handle for an open file, pipe, or device. | ||
The value for the old-file-handle parameter is the handle of an open file, a pipe, or a device. The valid values for the new-file-handle parameter include FFFFH, 0000H (standard input), 0001H (standard output), and 0002H (standard error). Any value other than FFFFH is assumed to be the value of the new file handle. | The value for the old-file-handle parameter is the handle of an open file, a pipe, or a device. The valid values for the new-file-handle parameter include FFFFH, 0000H (standard input), 0001H (standard output), and 0002H (standard error). Any value other than FFFFH is assumed to be the value of the new file handle. | ||
A value of FFFFH causes the system to allocate a new file handle and send it to this location. If the value specified for the new-file-handle parameter is that of a currently open file, the file handle is closed before it is redefined. | A value of FFFFH causes the system to allocate a new file handle and send it to this location. If the value specified for the new-file-handle parameter is that of a currently open file, the file handle is closed before it is redefined. | ||
An agreed upon value for a duplicate file handle can be established between a parent process and a child process. Avoid choosing arbitrary values for the new file handle. | An agreed upon value for a duplicate file handle can be established between a parent process and a child process. Avoid choosing arbitrary values for the new file handle. | ||
The duplicate handle acquires the characteristics of the original. If you move the read/write pointer of the original file handle, for example by calling DosRead, DosWrite, or DosSetFilePtr , the pointer of the duplicate handle is also moved. If the original handle has access to regions in a file that have been locked by DosSetFileLocks , the duplicate also has access. | The duplicate handle acquires the characteristics of the original. If you move the read/write pointer of the original file handle, for example by calling DosRead, DosWrite, or DosSetFilePtr , the pointer of the duplicate handle is also moved. If the original handle has access to regions in a file that have been locked by DosSetFileLocks , the duplicate also has access. | ||
If inheritance was indicated when a file was opened with DosOpen, a parent process can create a duplicate handle for the file and pass it to a child process by means of shared memory. This permits the child to close the duplicate handle without affecting the file handle of the parent. | If inheritance was indicated when a file was opened with DosOpen, a parent process can create a duplicate handle for the file and pass it to a child process by means of shared memory. This permits the child to close the duplicate handle without affecting the file handle of the parent. | ||
Because a parent process controls the meanings for standard I/O done by any child process it creates, the parent can use DosDupHandle to redefine unnamed pipe handles as standard I/O handles to communicate with a child. The steps involved are: | Because a parent process controls the meanings for standard I/O done by any child process it creates, the parent can use DosDupHandle to redefine unnamed pipe handles as standard I/O handles to communicate with a child. The steps involved are: | ||
*The parent process creates two pipes and duplicates the read handle of one pipe as 0000 and the write handle of the other pipe as 0001. | |||
*The parent process creates two pipes and duplicates the read handle of one pipe as 0000 and the write handle of the other pipe as 0001. | *When the child process performs standard I/O, instead of reading from the keyboard and writing to the display, it reads from and writes to the pipes created by its parent. | ||
*When the child process performs standard I/O, instead of reading from the keyboard and writing to the display, it reads from and writes to the pipes created by its parent. | *As the owner of the pipe, the parent process uses its read and write handles to write to the pipe defined to the child as standard input and read from the pipe defined to the child as standard output. | ||
*As the owner of the pipe, the parent process uses its read and write handles to write to the pipe defined to the child as standard input and read from the pipe defined to the child as standard output. | |||
===Determining and Setting the State of a File or Device Handle=== | ===Determining and Setting the State of a File or Device Handle=== | ||
After a file has been opened, the file handle state flags set with a DosOpen can be queried and reset by calling DosQueryFHState and DosSetFHState . The handle returned by DosSetFHState is used for subsequent input and output to the file | After a file has been opened, the file handle state flags set with a DosOpen can be queried and reset by calling DosQueryFHState and DosSetFHState . The handle returned by DosSetFHState is used for subsequent input and output to the file. | ||
The following code fragment calls DosSetFHState to set the File Write-Through flag for an opened file. Writes to the file may go through the file system buffer, but the sectors are to be written before any synchronous write call returns. DosQueryFHState is called first to obtain the file handle state bits. Assume that the appropriate file handle has been placed into FileHandle already. | |||
<pre> | <pre> | ||
#define INCL_DOSFILEMGR /* File system values */ | #define INCL_DOSFILEMGR /* File system values */ | ||
Line 583: | Line 518: | ||
return; | return; | ||
} | } | ||
</pre> | </pre> | ||
Here are two scenarios involving the use of this function. | |||
Here are two scenarios involving the use of this function. | *An application requires that data be written in a specific order. To guarantee the order of the data written, it must perform separate synchronous write operations. The application can call DosSetFHState to set the Write-Through flag for the file. This action does not affect any previous asynchronous writes, whose data can remain in the buffers. | ||
*An application cannot handle a certain critical error situation. DosSetFHState can be called to reset critica l error handling as OS/2's responsibility. The I/O function that caused the critical error must be called again so the error can recur, causing control to be passed to OS/2. In the case where asynchronous I/O is being done, the precise time the results of this function will be available to the application is unpredictable. | |||
*An application requires that data be written in a specific order. To guarantee the order of the data written, it must perform separate synchronous write operations. The application can call DosSetFHState to set the Write-Through flag for the file. This action does not affect any previous asynchronous writes, whose data can remain in the buffers. | |||
*An application cannot handle a certain critical error situation. DosSetFHState can be called to reset critica l error handling as OS/2's responsibility. The I/O function that caused the critical error must be called again so the error can recur, causing control to be passed to OS/2. In the case where asynchronous I/O is being done, the precise time the results of this function will be available to the application is unpredictable. | |||
===Determining the Handle Type=== | ===Determining the Handle Type=== | ||
DosQueryHType enables an application to determine whether a handle is to a file, a pipe, or a device. This function can be used when a file-oriented application needs to modify its behavior, depending on the source of its input. For example, CMD.EXE suppresses writing prompts when its input is from a disk file. | DosQueryHType enables an application to determine whether a handle is to a file, a pipe, or a device. This function can be used when a file-oriented application needs to modify its behavior, depending on the source of its input. For example, CMD.EXE suppresses writing prompts when its input is from a disk file. | ||
The following code fragment determines whether a given file handle refers to a file or a device. Assume that the desired file handle has been placed into FileHandle already. | The following code fragment determines whether a given file handle refers to a file or a device. Assume that the desired file handle has been placed into FileHandle already. | ||
<pre> | <pre> | ||
#define INCL_DOSFILEMGR /* File system values | #define INCL_DOSFILEMGR /* File system values */ | ||
#include <os2.h> | #include <os2.h> | ||
#include <stdio.h> | #include <stdio.h> | ||
Line 616: | Line 547: | ||
} | } | ||
</pre> | </pre> | ||
In the preceding example, DosQueryHType returns a value that characterizes the type of file handle, and the associated device driver attribute word, if the handle type indicates that the file handle is associated with a local character device. | In the preceding example, DosQueryHType returns a value that characterizes the type of file handle, and the associated device driver attribute word, if the handle type indicates that the file handle is associated with a local character device. | ||
===Searching for Files=== | ===Searching for Files=== | ||
You can locate files with names that match a given pattern by using metacharacters in DosFindFirst and DosFindNext . | You can locate files with names that match a given pattern by using metacharacters in DosFindFirst and DosFindNext. | ||
DosFindFirst searches the current directory and locates the first file name that matches the given pattern. DosFindNext locates the next matching file name and continues to find additional matches on each subsequent call until all matching names are found. The functions copy the file statistics on each file located to a data structure that you supply. The file information returned by a search includes file dates and times, length of data in the file, file size, file attributes, and file name. | DosFindFirst searches the current directory and locates the first file name that matches the given pattern. DosFindNext locates the next matching file name and continues to find additional matches on each subsequent call until all matching names are found. The functions copy the file statistics on each file located to a data structure that you supply. The file information returned by a search includes file dates and times, length of data in the file, file size, file attributes, and file name. | ||
To find all files that match the file specification, call DosFindNext repeatedly until the message ERROR_NO_MORE_FILES is returned. Then call DosFindClose to close the directory handle. | To find all files that match the file specification, call DosFindNext repeatedly until the message ERROR_NO_MORE_FILES is returned. Then call DosFindClose to close the directory handle. | ||
The following code fragment shows how to find all file names that have the extension ".C": | |||
<pre> | <pre> | ||
#define INCL_DOSFILEMGR /* File system values */ | #define INCL_DOSFILEMGR /* File system values */ | ||
Line 660: | Line 591: | ||
DosFindClose(hdHdir); | DosFindClose(hdHdir); | ||
</pre> | </pre> | ||
In this example, DosFindNext continues to retrieve matching file names until it returns an error value (it returns ERROR_NO_MORE_FILES when it cannot find any more matching files). | |||
To keep track of which files have already been found, both functions use the directory handle, hdir. | |||
This directory handle must be set to HDIR_SYSTEM or HDIR_CREATE before the call to DosFindFirst. HDIR_SYSTEM (00000001H) tells OS/2 to use the system handle for standard output, which is always available to the requesting process. HDIR_CREATE (FFFFFFFFH) tells OS/2 to allocate a new, unused handle. | |||
The directory handle returned by DosFindFirst must be used in subsequent calls to DosFindNext; it identifies for DosFindNext the name of the file being sought and the current position in the directory. | |||
An attribute parameter for DosFindFirst allows hidden and system files, as well as normal files, to be included in searches. | |||
After locating the files you need, use DosFindClose to close the directory handle. This ensures that when you search for the same files again, you will start at the beginning of the directory. After DosFindClose is called, a subsequent DosFindNext fails. | |||
===Searching Paths for Files=== | ===Searching Paths for Files=== | ||
DosSearchPath searches directory paths for t he name of a file object. The file specification can include metacharacters (global file name characters). | DosSearchPath searches directory paths for t he name of a file object. The file specification can include metacharacters (global file name characters). | ||
The path string used in the search consists of directory paths separated by semicolons. The caller can supply the path string, or it can supply the name of an environment variable whose value is the path string to be searched. The caller can request that the current working directory be searched before the path string is searched. | The path string used in the search consists of directory paths separated by semicolons. The caller can supply the path string, or it can supply the name of an environment variable whose value is the path string to be searched. The caller can request that the current working directory be searched before the path string is searched. | ||
If the caller specifies an environment variable, DosSearchPath uses DosScanEnv to find the path string. DosScanEnv searches the environment segme nt for an environment variable name; for example, DPATH. The result pointer points to the string that is the value of the environment variable. The call to DosScanEnv can be made direct ly by the application, or it can be invoked by DosSearchPath. | If the caller specifies an environment variable, DosSearchPath uses DosScanEnv to find the path string. DosScanEnv searches the environment segme nt for an environment variable name; for example, DPATH. The result pointer points to the string that is the value of the environment variable. The call to DosScanEnv can be made direct ly by the application, or it can be invoked by DosSearchPath. | ||
If the file is found, its full path name is returned, with metacharacters left in place. The results might not be meaningful if a buffer overflow occurs. | If the file is found, its full path name is returned, with metacharacters left in place. The results might not be meaningful if a buffer overflow occurs. | ||
As an example, assume that a string such as the following exists in the environment: | |||
DPATH=C:\SYSDIR;C:\INIT | DPATH=C:\SYSDIR;C:\INIT | ||
The following code fragment illustrates a method for searching directory paths to find a file. | |||
The following code fragment illustrates a method for searching directory paths to find a file. | |||
<pre> | <pre> | ||
#define INCL_DOSFILEMGR /* File system values */ | #define INCL_DOSFILEMGR /* File system values */ | ||
Line 722: | Line 651: | ||
return; | return; | ||
} | } | ||
</pre> | </pre> | ||
[ | ==Specifying Extended LIBPATHs== | ||
An Extended LIBPATH is a path which is searched in conjunction with the system LIBPATH, but which can be changed dynamically, either by the user from the command line, or by an application. There are two Extended LIBPATHs: BeginLIBPATH, which is searched before the system LIBPATH, and EndLIBPATH, which is searched after the system LIBPATH. | |||
Applications can use DosSetExtLIBPATH to set the Extended LIBPATHs. Likewise, they can use DosQueryExtLIBPATH to query the value of either of the Extended LIBPATHs. A flag parameter for the function specifies whether the BeginLIBPATH or the EndLIBPATH is being set or queried. The flag allows two values: BEGIN_LIBPATH (1) which will set or query BeginLIBPATH, or END_LIBPATH (2) which will set or query EndLIBPATH. | |||
Extended LIBPATHs are ASCIIZ strings which are formatted in the same manner as the system LIBPATH, that is, they contains a list of subdirectory paths separated by semicolons. The string argument can be up to 1024 characters and will return an error if longer. | |||
The following example updates the path to be searched before the system LIBPATH, then queries and displays the value. | |||
<pre> | |||
#define INCL_DOSMISC | |||
#define INCL_DOSERRORS | |||
#include <os2.h> | |||
#include <stdio.h> | |||
UCHAR uchBeginLIBPATH[1024] = ""; /* Begin LIBPATH value returned */ | |||
APIRET ulrc = NO_ERROR; /* Return code */ | |||
ulrc = DosSetExtLIBPATH("C:\\TOOL_X\\VERS_20\\DLL", | |||
BEGIN_LIBPATH); /* Add to beginning LIBPATH */ | |||
if (ulrc != NO_ERROR) { | |||
printf("DosSetExtLIBPATH error: return code = %u\n", | |||
ulrc); | |||
return 1; | |||
} | |||
ulrc = DosQueryExtLIBPATH(uchBeginLIBPATH, | |||
BEGIN_LIBPATH); /* Query the BeginLIBPATH */ | |||
if (ulrc != NO_ERROR) { | |||
printf("DosQueryExtLIBPATH error: return code = %u\n", | |||
ulrc); | |||
return 1; | |||
} | |||
printf(" BeginLIBPATH = %s\n", | |||
uchBeginLIBPATH); | |||
</pre> | |||
==Standard File Handles== | ==Standard File Handles== | ||
Every application, when it first starts, has three input and output file handles available to use. These file handles, called the standard input, standard output, and standard error files, enable the application to read input from the keyboard and display output on the screen without opening or preparing the keyboard or screen. | |||
===Standard Input, Output, and Error File Handles=== | ===Standard Input, Output, and Error File Handles=== | ||
As OS/2 starts an application, it automatically opens the three standard files and makes the file handles-numbered 0, 1, and 2-available to the application. Applications can read from and write to the standard files as soon as they start. | |||
;Standard Input | |||
File handle 0 is the standard input file. This handle can be used to read characters from the keyboard with DosRead. The function reads the specified number of characters unless the user types a turnaround character-that is, a character that marks the end of a line (the default turnaround character is a carriage-return/linefeed character pair). | |||
As DosRead reads the characters, it copies them to the buffer you have supplied, as shown in the code fragment below. | |||
In this example, DosRead copies the number of characters read from standard input to to variable cbRead. DosRead also copies the turnaround character, or characters, to the buffer If the function reads fewer than 80 characters, the turnaround character is the last one in the buffer. | |||
;Standard Output | |||
File handle 1 is the standard output file. This handle can be used to write characters on the screen with DosWrite. The function writes the characters in the given buffer to the current line. If you want to start a new line, you must place the current turnaround character in the buffer. | |||
The code fragment below: | |||
*Displays a prompt | |||
*Reads a string | |||
*Displays the string | |||
<pre> | |||
#define INCL_DOSFILEMGR /* File system values */ | |||
#include <os2.h> | |||
#define HF_STDIN 0 /* Standard input handle */ | |||
#define HF_STDOUT 1 /* Standard output handle */ | |||
#define BUF_SIZE 80 | |||
ULONG ulWritten, | |||
ulRead; | |||
BYTE abBuffer[BUF_SIZE]; | |||
static UCHAR ucEnterName[] = "Enter a name: "; | |||
DosWrite(HF_STDOUT, | |||
ucEnterName, | |||
sizeof(ucEnterName), | |||
&ulWritten); | |||
DosRead(HF_STDIN, | |||
abBuffer, | |||
sizeof(abBuffer), | |||
&ulRead); | |||
DosWrite(HF_STDOUT, | |||
abBuffer, | |||
ulRead, | |||
&ulWritten); | |||
</pre> | |||
;Standard Error | |||
File handle 2 is the standard error file. This handle, like the standard output handle, enables applications to write characters on the screen. Most applications use the standard error file to display error messages, enabling the application to redirect standard output to a file without also redirecting error messages to the file. | |||
===Redirecting Standard File Handles=== | ===Redirecting Standard File Handles=== | ||
The standard input, standard output, and standard error files are usually the keyboard and screen, but not always. For example, if you redirect standard output by using the greater-than (>) redirection symbol on the application's command line, all data written to the standard output file goes to the given file. | |||
The following command line redirects standard output to the file SAMPLE.TXT and redirects error messages to the file SAMPLE.ERR: | |||
type startup.cmd >sample.txt 2>sample.err | |||
When a standard file is redirected, its handle is still available but corresponds to the given disk file instead of to the keyboard or screen. You can still use DosRead and DosWrite to read from and write to the files. | |||
You can use [[DosDupHandle]] to redirect a standard file from inside your application. If you duplicate the standard input file handle, your application reads from the specified file rather than from the keyboard. Duplicating the standard output file handle causes output to be directed to a file or device instead of to the standard output device. | |||
The following code fragment shows how to use the standard input handle to read from a file: | |||
<pre> | |||
#define INCL_DOSFILEMGR /* File system values */ | |||
#include <os2.h> | |||
#define HF_STDIN 0 /* Standard input handle */ | |||
#define HF_STDOUT 1 /* Standard output handle */ | |||
#define BUF_SIZE 80 | |||
BYTE abBuffer[BUF_SIZE]; | |||
HFILE hf, | |||
hfNew; | |||
ULONG ulRead, | |||
ulWritten, | |||
ulAction; | |||
APIRET ulrc; | |||
ulrc = DosOpen("SAMPLE.C", | |||
&hf, | |||
&ulAction, | |||
0, | |||
FILE_NORMAL, | |||
FILE_OPEN, | |||
OPEN_ACCESS_READONLY | | |||
OPEN_SHARE_DENYNONE, | |||
(PEAOP2) NULL); | |||
if (!ulrc) { | |||
hfNew = 0; /* Duplicates standard input */ | |||
DosDupHandle(hf, | |||
&hfNew); | |||
DosRead(HF_STDIN, | |||
abBuffer, | |||
sizeof(abBuffer), | |||
&ulRead); | |||
DosWrite(HF_STDOUT, | |||
abBuffer, | |||
ulRead, | |||
&ulWritten); | |||
} | |||
</pre> | |||
[[Category:CPGuide]] |
Latest revision as of 22:47, 30 May 2023
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
OS/2 provides a standard set of file system functions. This means that applications can create, open, read, write, copy, and delete files and directories by using the same functions, regardless of which file system is used. When an application calls a file system function, OS/2 passes the request to the dynamic link library that supports the file system. The dynamic link library carries out most file system processing, such as validating file names. If an error occurs, the file system returns the error to OS/2, which then passes it back to the calling application.
The OS/2 file system functions identify files and directories by their names. These functions store or search for the file or directory in the current directory on the current drive unless the name explicitly specifies a different directory and drive. Occasionally, a file system has control functions in addition to the standard file system functions. The control functions are specific to the given file system. An application can call a control function by using DosFSCtl, which directs OS/2 to pass the control-function information to the corresponding Installable File System (IFS).
The following topics are related to the information in this chapter:
- Files systems
- Files names
- Extended attributes
- Pipes
- Device I/O
About Volumes and Drives
OS/2 allows more than one file system on a single storage device. If the device can have more than one partition (or volume), each partition can be initialized as an OS/2 partition and given a valid OS/2 file system. For each volume, OS/2 determines the type of file system the first time the volume is accessed by a function or when the medium in the drive changes. After that, OS/2 manages all input and output to that volume by using the corresponding dynamic link library.
OS/2 uses the volume label and serial number to ensure that the medium in the drive does not change while there are outstanding requests for input and output. Each volume has a volume label and a 32-bit volume serial number, stored in a reserved location in logical sector 0 at the time of formatting. If the volume label and serial number do not match, OS/2 signals the critical error handler to prompt the user to insert the volume that has the specified serial number and label. OS/2 maintains the connection between the medium and the volume label and serial number until all open files on the volume are closed and all search references and cache buffer references are removed. The system redetermines the type of file system and the volume label and serial number only when the medium changes.
OS/2 enables applications to:
- Determine and set the default drive using DosQueryCurrentDisk and DosSetDefaultDisk, respectively.
- Determine and set drive information using DosQueryFSInfo and DosSetFSInfo.
- Determine and set the write verification switch using DosQueryVerify and DosSetVerify. If the write verification switch is on, each time data is written to the disk, the data is verified to ensure it has been recorded correctly. These functions are provided for recording critical data.
About Directories
When an application starts, it inherits the current directory and drive from the application that starts it. An application can determine which directory and drive are current by using DosQueryCurrentDir and DosQueryCurrentDisk. An application can change the current directory and drive of the file system by using DosSetCurrentDir and DosSetDefaultDisk.
When an application creates a new file, the system adds a file entry to the specified directory. Each directory can have any number of entries, up to the physical limit of the disk. An application can create new directories and delete existing directories by using DosCreateDir and DosDeleteDir. Before a directory can be deleted, it must be empty; if there are files or directories in that directory, they must be deleted or moved. An application can delete a file by using DosDelete or move a file to another directory by using DosMove.
Creating a Subdirectory
To create a new subdirectory, an application calls DosCreateDir and specifies a directory path name. If the call is successful, a new subdirectory is created at the end of the path on the specified disk. If no path name is specified, a new subdirectory is created at the end of the current directory for the process. If any subdirectories in the path do not exist, the subdirectory is not created.
Because a subdirectory is a file object, an application also can define an extended attribute for the directory when it is created during this call. See Extended Attributes for more information on extended attributes.
Determining and Changing the Current Directory
Calling DosQueryCurrentDir returns the full path name of the current directory for the specified drive. The string does not begin with a back slash (\) and it ends with a byte containing 00H, the NULL character.
To change the current directory, call DosQueryCurrentDir with the path name of the directory you want to make the current directory.
Deleting a Directory
A subdirectory cannot be removed if it is the current subdirectory or if it contains hidden files or subdirectory entries other than the "." and ".." entries. When these requirements for removal are met, DosDeleteDir can be called with a path name to remove the subdirectory from the disk.
About Files
A file is one or more bytes of data, usually stored on a disk. While the application that creates the file determines the format of the file, the file system determines how the file is stored on the disk and what actions can be performed on it. The file system also stores information about the file in file attributes and extended attributes.
Files are accessed through the file system using file handles. File handles are returned by DosOpen when the file is opened and are used for all subsequent accesses to the file. Files can be be opened, read from, written to, closed, copied, moved, deleted, renamed, and locked. Files can be searched for based on a metacharacter template.
Each open file has a file pointer that indicates the current reading or writing location within the file. The file pointer moves automatically with each read or write operation on the file and can be moved manually by the application.
File Attributes
Each directory entry includes a set of file attributes. File attributes specify whether the directory entry is for a file, a directory, or a volume identifier. The attributes also specify if the file is read-only, hidden, archived, or a system file.
A read-only file cannot be opened for writing, nor can it be deleted. A hidden file (or directory) cannot be displayed by using an ordinary directory listing. A system file is excluded from normal directory searches. The archived attribute is for use by special purpose applications to mark a file that has been changed since the last time the file was examined.
An application can retrieve and set the file attributes by using DosQueryFileInfo and DosSetFileInfo.
File Handles
OS/2 identifies each open file by assigning it a file handle when the application opens or creates the file. The file handle is a unique 32-bit integer. The application can use the handle in functions that read from and write to the file, depending on how the file was opened. The application can continue to use the handle until the file is closed.
The default maximum number of file handles for a process is 50. An application can change this maximum by using DosSetMaxFH. When this call is made, all currently open file handles are preserved.
In the past, the maximum number of file handles was 20. If you previously had code that increased the maximum file handles from 20 to less than 50, you can now remove this code.
When an application starts, it inherits all open file handles from the process that starts it. If the system's command processor starts an application, file handles 0, 1, and 2 represent the standard input, standard output, and standard error files. The standard input file is the keyboard; the standard output and standard error files are the screen. An application can read from the standard input file and write to the standard output and standard error files immediately; it does not have to open the files first.
An application can create a duplicate file handle for an open file by using DosDupHandle. A duplicate handle is identical to the original handle. Typically, duplicate handles are used to redirect the standard input and standard output files. For example, an application can open a disk file and duplicate the disk-file handle as handle 0. Thereafter, an application reading from the standard input file (handle 0) takes data from the disk file, not from the keyboard.
When devices and pipes are accessed through the file system functions (using DosOpen, DosRead, and so on), the devices and pipes are treated as files and are identified using file handles. The standard file handles can be redirected to a device or pipe.
File Pointer
Every open file has a file pointer that specifies the next byte to be read or the location to receive the next byte that is written. When a file is first opened, the system places the file pointer at the beginning of the file. As each byte is read or written, OS/2 advances the pointer.
An application can also move the pointer by using DosSetFilePtr. When the pointer reaches the end of the file and the application attempts to read from the file, no bytes are read and no error occurs. Thus, reading 0 bytes without an error means the program has reached the end of the file.
When an application writes to a disk file, the data being written is usually collected in an internal buffer. OS/2 writes to the disk only when the amount of data equals (or is a multiple of) the sector size of the disk. If there is data in the internal buffer when the file is closed, the system automatically writes the data to the disk before closing the file. An application can also flush the buffer (that is, write the contents of the buffer to the disk) by using DosResetBuffer.
Copying Files
DosCopy is used to copy files and subdirectories. Metacharacters (global file name characters) are not allowed, so only individual files or entire subdirectories can be copied with this function. The source and target can be on different drives.
When the source specified is a subdirectory and an I/O error occurs, the file being copied from the source directory to the target directory at the time of the error will be deleted from the target directory and DosCopy will be terminated.
When a file is being copied and an I/O error occurs,
- if the source file name is that of a file to be replaced, the file is deleted from the target path.
- if the source file name is that of a file to be appended, the target file is resized to its original size.
DosCopy will copy the attributes of the source file, such as date of creation, and time of creation to the target file. Additionally, DosCopy will copy the extended attributes of the source file when creating a new subdirectory or a new file, or when replacing an existing file.
Moving Files
DosMove is used to move a file from one subdirectory to another on the same drive. In the process of moving the file, its name can be changed. Metacharacters (global file name characters) are not permitted.
Deleting Files
Calling DosDelete removes the directory entry associated with a file name. Metacharacters (global file name characters) are not permitted.
Files whose read-only attribute is set cannot be deleted.
Changing File Sizes
DosSetFileSize is used to extend or truncate the size of a file that is open for Read/Write or Write-Only access.
When a file is extended, for example to reserve disk space, the value of the additional bytes allocated by the system is undefined.
Locking and Unlocking File Regions
Because OS/2 permits more than one application to open a file and write to it, it is important that the applications not write over each other's work. An application can protect against this problem by temporarily locking a region in a file.
DosSetFileLocks provides a simple mechanism that temporarily prevents access by other processes to regions within a file. DosSetFileLocks specifies a range of bytes in the file that is locked by an application and that can be accessed only by the application locking the region. The application uses the same function to free the locked region.
Locking and unlocking regions in a file enables sharing processes to coordinate their efforts. A process can lock a region in a file so the process can read and update the file region. A sharing process that attempts to lock the region before the other process finishes its update and unlocks the region receives an error code. When a lock is unsuccessful because a lock is already in place, ERROR_LOCK_VIOLATION is returned.
A lock that extends beyond end-of-file is not considered an error. However, a locked region cannot overlap another locked region, nor can it encompass a locked region. Any such conflicting locks must be cleared before a region can be locked.
When a file handle is duplicated, the duplicate handle has access to any locked regions currently being accessed by the original handle. Although a child process created with DosExecPgm can inherit the file handles of its parent process, it does not inherit access to locked regions in effect for a file handle unless the file handle is duplicated and passed to it.
- Note
- File locks are intended to be in effect for only short periods of time.
- When a file with locks is closed, the locks are released in no defined order.
Searching for Files
An application can use DosFindFirst, DosFindNext, and DosFindClose to search the current directory for all file names that match a given pattern.
The pattern must be an OS/2 file name and can include metacharacters (global file name characters). The wildcard characters are the question mark (?) and the asterisk (*). The question mark matches any single character; the asterisk matches any combination of characters. For example, the pattern "A*" matches the names "ABC", "A23", and "ABCD", but the pattern "A?C" matches only the name "ABC".
Determining the Maximum Path Length
An application that recognizes long file names might be run on systems with or without installable file systems. Additionally, the maximum length of a file name might vary from one installable file system to another. So that an application can properly handle this variable condition (and, for example, allocate large enough buffers to hold file names), the application should call DosQuerySysInfo to determine the maximum path length supported by the file system.
Make this call before calling file system functions that require full path names.
Specifying an Extended LIBPATH
The LIBPATH, which is set in CONFIG.SYS, specifies a search path which OS/2 uses when searching for dynamic link libraries (DLLs). The LIBPATH is set during system startup and cannot be changed dynamically.
OS/2 provides the capability of specifying extensions to the LIBPATH. An Extended LIBPATH is a path which is searched in conjunction with the system LIBPATH, but which can be changed dynamically, either by the user from the command line, or by an application.
There are two Extended LIBPATHs: BeginLIBPATH, which is searched before the system LIBPATH, and EndLIBPATH, which is searched after the system LIBPATH.
Extended LIBPATHs are ASCIIZ strings which are formatted in the same manner as the system LIBPATH, that is, they contains a list of subdirectory paths separated by semicolons. The maximum size for each Extended LIBPATH is 1024 characters.
Applications can use DosSetExtLIBPATH to set the Extended LIBPATHs. Likewise, they can use DosQueryExtLIBPATH to query the value of either of the Extended LIBPATHs. A flag parameter for the function specifies whether the BeginLIBPATH or the EndLIBPATH is being set or queried. The flag allows two values: BEGIN_LIBPATH (1) which will set or query BeginLIBPATH, or END_LIBPATH (2) which will set or query EndLIBPATH.
You can call DosSetExtLIBPATH as often as you want. The new Extended LIBPATH that you pass in will replace the current Extended LIBPATH.
You can specify the current Extended LIBPATH as part of the argument by using the % symbol before and after the Extended LIBPATH variable name, that is, as %BeginLIBPATH% or %EndLIBPATH%. For example, suppose you set BeginLIBPATH to "D:\MYDLLS", then later you want to add "D:\TOMSDLLS" before the existing BeginLIBPATH, and "D:\JOESDLLS" after the existing BeginLIBPATH (that is, you want to change BeginLIBPATH to "D:\TOMSDLLS;D:\MYDLLS;D:\JOESDLLS"). You could accomplish this by using "D:\TOMSDLLS;%BeginLIBPATH%;D:\JOESDLLS" as the argument for DosSetExtLIBPATH.
The string argument can be up to 1024 characters long. However, if the resulting Extended LIBPATH is longer than 1024 characters, the function will return an error.
Devices
OS/2 enables you to access peripheral devices using file system commands, and treat those devices as file streams of data. These devices include:
- Character devices
- COM, clock, console (keyboard and screen), screen, keyboard, printer, null, pointer, and mouse devices.
- Standard I/O devices
- Character devices automatically installed by OS/2 and recognized by the file system as the standard input, standard output, and standard error devices.
- Pseudocharacter devices
- An application can attach a device name to a file system and use the file system as a pseudocharacter device (also called a single-file device). Attaching a device name to a file system allows an application to open the device associated with the file system as if it were a character device (for example, a serial port) and read from and write to the device by using DosRead and DosWrite.
- In addition, an application can use DosSetFilePtr and DosSetFileLocks with a pseudocharacter device. Also, pseudocharacter devices can be redirected.
- A file system that can be attached to a pseudocharacter device is typically associated with a single disk file or with a special storage device, such as a tape drive. The file system establishes a connection with the device and transfers requests and data between OS/2 and the device. The user perceives this file as a device name for a nonexistent device.
- This file is seen as a character device because the current drive and directory have no effect on the name. A pseudocharacter device name is an ASCII string with the name of an OS/2 file in the form:
\DEV\DEV_NAME
- The "\dev\" is a required part of the name, but there is no actual subdirectory named "\dev\". This just lets OS/2 know that it is a pseudocharacter device name.
- Logical file
- devices The hard disk or floppy disk drives, or the partitions on the hard disk or floppy disk drives.
Using File Commands
Files are accessed through the file system using file handles. File handles are returned by DosOpen when the file is opened and are used for all subsequent accesses to the file. Files can be be created, opened, read from, written to, closed, copied, moved, deleted, renamed, and locked. Files can be searched for based on a metacharacter pattern template.
Each open file has a file pointer that indicates the current reading or writing location within the file. The file pointer moves automatically with each read or write operation on the file and can be moved manually by the application.
The standard file handles-standard input, standard output, and standard error-provide redirectable input and output to applications. The standard file handles can be used to read input from the keyboard and write output to the display. Alternatively, they can be redirected to read input from and write output to a file. To an application reading and writing the standard file handles, there is no difference between the two.
- Note
- In the example code fragments that follow, error checking was left out to conserve space. Applications should always check the return code that the functions return. Control Program functions return an APIRET value. A return code of 0 indicates success. If a non-zero value is returned, an error occurred.
Creating Files
DosOpen is used to create files, which are then read from or written to. To create a file, specify FILE_CREATE as the sixth argument in the call to the function. DosOpen then creates the file, if it does not already exist. If the file already exists, the function returns the error value FILE_EXISTED.
The following code fragment shows how to use DosOpen to create the file NEWFILE.TXT:
#define INCL_DOSFILEMGR /* File System values */ #include <os2.h> HFILE hf; ULONG ulAction; APIRET ulrc; ulrc = DosOpen("NEWFILE.TXT", /* Name of file to create and open */ &hf, /* Address of file handle */ &ulAction, /* Action taken */ 0, /* Size of new file */ FILE_NORMAL, /* File attributes */ FILE_CREATE, /* Creates the file */ OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE, (PEAOP2) NULL); /* No extended attributes */
In this example, DosOpen creates the file and opens it for writing only. Note that the sharing method chosen permits other processes to open the file for any access. The new file is empty (contains no data).
When you use DosOpen to create (or replace) a file, you must specify the attributes the new file is to have. In the preceding example, this value is FILE_NORMAL, so the file is created as a normal file. Other possible file attributes include read-only and hidden, which correspond to FILE_READONLY and FILE_HIDDEN, respectively. The possible file attributes are:
File Attribute Defined Constant Normal file FILE_NORMAL Read-only file FILE_READONLY Hidden file FILE_HIDDEN System file FILE_SYSTEM Subdirectory FILE_DIRECTORY Archived file FILE_ARCHIVED.
The file attribute affects how other processes access the file. For example, if the file is read-only, no process can open the file for writing. There is one exception-the process that creates the read-only file can write to it immediately after creating it. After closing the file, however, the process cannot reopen it for writing.
If you are creating a new file object (a new file or a replacement for an existing one), you must specify the size of the new file in bytes. For example, if you specify 256, the file size is 256 bytes. However, these 256 bytes are undefined. If the file being opened already exists, the file size parameter is ignored. It is up to the application to write valid data to the file. No matter what size you specify, the file pointer is set to point to the beginning of the file so a subsequent call to DosWrite starts writing data at the beginning of the file.
Extended attributes can be defined by an application when a file object is created. An application can define an extended attribute for a file when the file is created during a DosOpen call.
Applications can also control access to specific regions within a file by calling DosSetFileLocks.
Opening Files
Before performing input or output operations on a file, you must open the file and obtain a file handle. You obtain a file handle by using DosOpen. This function opens the specified file and returns a file handle for it. DosOpen can also be used to create new files.
DosOpen establishes a connection betwee n a file object and an application. This connection is in the form of a 32-bit identifier called a file handle, which is used to refer to the file object and any information associated with it. DosOpen returns a handle that is used in other file system calls to gain access to the object. The file object can be a new file, an existing file, or a replacement for an existing file. It can also be a character device, a block device, or the client end of a named pipe. The type of object is determined by the file name you pass to DosOpen.
- Note
- If the object is a named pipe, it must be in a listening state for DosOpen to be successful.
The following code fragment shows the use of DosOpen to:
- Open the existing file SAMPLE.TXT for reading
- Put the file handle into the hf variable
#define INCL_DOSFILEMGR /* File System values */ #include <os2.h> HFILE hf; ULONG ulAction; APIRET ulrc; ulrc = DosOpen("SAMPLE.TXT", /* Name of file to open */ &hf, /* Address of file handle */ &ulAction, /* Action taken */ 0, /* Size of file */ FILE_NORMAL, /* File attribute */ FILE_OPEN, /* Open the file */ OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, (PEAOP2) NULL); /* Extended attribute buffer */
If DosOpen successfully opens the file, it copies the file handle to the hf variable and copies a value to the ulAction variable indicating what action was taken (for example, FILE_EXISTED for "existing file opened"). A file size is not needed to open an existing file, so the fourth argument is 0. The fifth argument, FILE_NORMAL, specifies the normal file attribute. The sixth argument, FILE_OPEN, directs DosOpen to open the file if it exists or return an error if it does not exist. The seventh argument directs DosOpen to open the file for reading only and enables other applications to open the file even while the current application has it open. The final argument is a pointer to a structure containing information on extended attributes. If the file has no extended attributes, this argument must be NULL.
DosOpen returns 0 if it successfully op ens the file. Applications use the file handle in subsequent functions to read data from the file or to check the status and other file characteristics. If DosOpen fails to open the file, it returns an error value.
When you open a file you must specify whether you want to read from the file, write to it, or both read and write. Also, since more than one application might attempt to open the same file, you must also specify whether you want to allow other processes to have access to the file while you have it open. A file that is shared can be shared for reading only, writing only, or reading and writing. A file that is not shared cannot be opened by another application (or more than once by the first application) until it has been closed by the first application.
An application defines its file access rights (that is, I/O it needs to perform on a file) by setting the appropriate file access mode field in the file open-mode parameter. An application accesses a file as:
- Read-only
- Write-only
- Read/write
An application defines what I/O operations other processes can perform on a file by setting the appropriate sharing mode field in the OpenMode parameter. Other processes are granted:
- Deny read/write access
- Deny write access
- Deny read access
- Deny neither read or write access (deny none)
File sharing requires cooperation between the sharing processes. For example, if process A calls DosOpen to open a file with Deny Write sharing and process B calls DosOpen to open the same file with Read/Write access, the DosOpen call made by process B fails.
You indicate whether or not you want to permit another application to access your file by combining an OPEN_ACCESS_ value and an OPEN_SHARE_ value from the following list:
Value | Meaning |
---|---|
OPEN_ACCESS_READONLY | Open a file for reading. |
OPEN_ACCESS_WRITEONLY | Open a file for writing. |
OPEN_ACCESS_READWRITE | Open a file for reading and writing. |
OPEN_SHARE_DENYREADWRITE | Open a file for exclusive use, denying other processes read and write access. |
OPEN_SHARE_DENYWRITE | Deny other processes write access to a file. |
OPEN_SHARE_DENYREAD | Deny other processes read access to a file. |
OPEN_SHARE_DENYNONE | Open a file with no sharing restrictions, granting read and write access to all processes. |
In general, you can combine any access method (read, write, or read and write) with any sharing method (deny reading, deny writing, deny reading and writing, or grant any access). Some combinations have to be handled carefully, however, such as opening a file for writing without denying other processes access to it.
- Note
- For named pipes, the access and sharing modes must be consistent with those specified by DosCreateNPipe.
Other characteristics of the file handle that can be set:
Flag | Purpose |
---|---|
Inheritance | Handle is inherited by a child process created with DosExecPgm, or is private to the calling process. |
Write-Through | Actual I/O for synchronous writes is not guaranteed as complete or is guaranteed as complete before the write returns. |
Fail-Errors | Media errors are reported by the system critical error handler, or by the application. |
DASD | The file name parameter is the name of a file or device opened in the normal way, or a drive specification for a fixed disk or diskette drive. The DASD flag can be set for direct access to an entire disk or diskette volume, independent of the file system. When the DASD flag is set, the handle returned by DosOpen represents the logical volume as a single file. To block other processes from accessing the logical volume, a DosDevIOCtl Category 8, Function 0 call should be made using the handle returned by DosOpen. The DASD flag should be set only by systems programs, not by applications. |
Cache | The file system caches or does not cache data for I/O operations on the file. This flag is advisory only. |
See the DosOpen material in the Control Program Programming Reference for details of these characteristics.
After an object has been opened, its file handle state flags can be queried by calling DosQueryFHState and reset by calling DosSetFHState. See Determining and Setting the State of a File or Device Handle for information on determining the state of a file handle.
When a child process inherits a file handle, it also inherits the sharing and access rights of the file.
You cannot use metacharacters (global file name characters; * and ?) in file names you supply to DosOpen.
Reading from Files
Once you open a file or have a file handle, you can read from and write to the file by using DosRead and DosWrite.
DosRead is called with a handle (obtained with DosOpen) for a file, pipe, or device. DosRead copies a specified number of bytes (up to the end of the file) from the file object to the buffer you specify. OS/2 returns, in a parameter, the number of bytes actually read (which might not be the same as the number of bytes requested because the end of the file might have been reached).
To read from a file, you must open it for reading or for reading and writing.
The following code fragment shows how to open the file named SAMPLE.TXT and read the first 512 bytes from it:
#define INCL_DOSFILEMGR /* File System values */ #include <os2.h> #define BUF_SIZE 512 HFILE hf; ULONG ulAction; BYTE abBuffer[BUF_SIZE]; ULONG cbRead; APIRET ulrc; ulrc = DosOpen("SAMPLE.TXT", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, (PEAOP2) NULL); if (!ulrc) { DosRead(hf, abBuffer, sizeof(abBuffer), &cbRead); DosClose(hf); }
If the file does not have 512 bytes, DosRead reads to the end of the file and puts the number of bytes read in the cbRead variable. If the file pointer is already positioned at the end of the file when DosRead is called, the function puts a 0 in the cbRead variable.
Writing to Files
Once you open a file or have a file handle, you can read from and write to the file by using DosRead and DosWrite.
DosWrite copies bytes from a buffer you specify to a file, device, or pipe.
Calling DosWrite with a handle for a file, pipe, or device transfers the number of bytes specified from a buffer location to the object. The system returns, in a parameter, the number of bytes actually written (which in the case of a disk file might not be the same as the number requested because of insufficient disk space).
To write to a file, you must first open it for writing or for reading and writing.
The following code fragment shows how to open the file SAMPLE.TXT again and write 512 bytes to it:
#define INCL_DOSFILEMGR /* File System values */ #include <os2.h> #define BUF_SIZE 512 HFILE hf; ULONG ulAction; BYTE abBuffer[BUF_SIZE]; ULONG cbWritten; APIRET ulrc; ulrc = DosOpen("SAMPLE.TXT", &hf, &ulAction, 0, FILE_NORMAL, FILE_CREATE, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE, (PEAOP2) NULL); if (!ulrc) { DosWrite(hf, abBuffer, sizeof(abBuffer), &cbWritten); DosClose(hf); }
DosWrite writes the contents of the buffer to the file. If it fails to write 512 bytes (for example, if the disk is full), the function puts the number of bytes written in the cbWritten variable. The data is read and written exactly as given; the function does not format the data-that is, they do not convert binary data to decimal strings, or vice versa.
The Write-Through Flag If an application requires data to be written in a specific order, setting the Write-Through flag to 1 guarantees that actual I/O for a synchronous write is completed before the DosWrite returns. If this flag has been set with DosOpen for buffered I/O, and multiple synchronous writes are performed, the system cannot guarantee the actual order in which the data is written. For details on changing the state of the Write-Through flag, see Determining and Setting the State of a File or Device Handle.
Moving the File Pointer
Every disk file has a corresponding file pointer that marks the current location in the file. The current location is the byte in the file that will be read from or written to on the next call to DosRead or DosWrite. Usually, the file pointer is at the beginning of the file when you first open or create the file, and it advances as you read or write to the file. You can, however, change the position of the file pointer at any time by using DosSetFilePtr.
DosSetFilePtr moves the file pointer a specified offset from a given position. You can move the pointer from the beginning of the file, from the end, or from the current position.
The following code fragment shows how to move the pointer 200 bytes from the end of the file:
#define INCL_DOSFILEMGR /* File system values */ #include <os2.h> #define HF_STDOUT 1 /* Standard output handle */ #define BUF_SIZE 255 BYTE abBuf[BUF_SIZE]; HFILE hf; ULONG ulRead, ulWritten, ulAction, ulNewPtr; DosOpen("SAMPLE.TXT", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, (PEAOP2) NULL); DosSetFilePtr(hf, -200, FILE_END, &ulNewPtr); DosRead(hf, &abBuf, sizeof(abBuf), &ulRead); DosWrite(HF_STDOUT, abBuf, ulRead, &ulWritten);
In this example, DosSetFilePtr moves the file pointer to the 200th byte from the end of the file. If the file is not that long, the function moves the pointer to the first byte in the file and returns the actual position (relative to the end of the file) in the ulNewPtr variable.
You can move the file pointer for disk files only. You cannot use DosSetFilePtr on devices, despite using other file functions (DosOpen, DosRead) to access a device.
If a file is read-only, write operations to the file will not be performed.
Moving the pointer from the end of the file can be used to determine the size of the file.
Closing Files
You can close a file by using DosClose. Since each application has a limited number of file handles that can be open at one time, it is a good practice to close a file after using it.
To do so, supply the file handle in DosClose, as shown in the following code fragment:
#define INCL_DOSFILEMGR /* File system values */ #include <os2.h> #define BUF_SIZE 80 HFILE hf; ULONG ulAction; BYTE abBuffer[BUF_SIZE]; ULONG ulRead; APIRET ulrc; ulrc = DosOpen("SAMPLE.TXT", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, (PEAOP2) NULL); if (!ulrc) { DosRead(hf, abBuffer, sizeof(abBuffer), &ulRead); DosClose(hf); }
If you open a file for writing, DosClose directs the system to flush the file buffer-that is, to write any existing data in OS/2's intermediate file buffer to the disk or device. The system keeps these intermediate file buffers to make file input and output more efficient. For example, it saves data from previous calls to DosWrite until a certain number of bytes are in the buffer then writes the contents of the buffer to the disk.
DosClose also closes the handle to the file (or pipe, or device). If one or more additional handles to a file have been created with DosDupHandle, the internal buffers for the file are not written to disk, and its directory entry is not updated, until DosClose has been called for all the handles.
Creating Duplicate File or Device Handles
DosDupHandle enables a process to create a duplicate handle for an open file, pipe, or device.
The value for the old-file-handle parameter is the handle of an open file, a pipe, or a device. The valid values for the new-file-handle parameter include FFFFH, 0000H (standard input), 0001H (standard output), and 0002H (standard error). Any value other than FFFFH is assumed to be the value of the new file handle.
A value of FFFFH causes the system to allocate a new file handle and send it to this location. If the value specified for the new-file-handle parameter is that of a currently open file, the file handle is closed before it is redefined.
An agreed upon value for a duplicate file handle can be established between a parent process and a child process. Avoid choosing arbitrary values for the new file handle.
The duplicate handle acquires the characteristics of the original. If you move the read/write pointer of the original file handle, for example by calling DosRead, DosWrite, or DosSetFilePtr , the pointer of the duplicate handle is also moved. If the original handle has access to regions in a file that have been locked by DosSetFileLocks , the duplicate also has access.
If inheritance was indicated when a file was opened with DosOpen, a parent process can create a duplicate handle for the file and pass it to a child process by means of shared memory. This permits the child to close the duplicate handle without affecting the file handle of the parent.
Because a parent process controls the meanings for standard I/O done by any child process it creates, the parent can use DosDupHandle to redefine unnamed pipe handles as standard I/O handles to communicate with a child. The steps involved are:
- The parent process creates two pipes and duplicates the read handle of one pipe as 0000 and the write handle of the other pipe as 0001.
- When the child process performs standard I/O, instead of reading from the keyboard and writing to the display, it reads from and writes to the pipes created by its parent.
- As the owner of the pipe, the parent process uses its read and write handles to write to the pipe defined to the child as standard input and read from the pipe defined to the child as standard output.
Determining and Setting the State of a File or Device Handle
After a file has been opened, the file handle state flags set with a DosOpen can be queried and reset by calling DosQueryFHState and DosSetFHState . The handle returned by DosSetFHState is used for subsequent input and output to the file.
The following code fragment calls DosSetFHState to set the File Write-Through flag for an opened file. Writes to the file may go through the file system buffer, but the sectors are to be written before any synchronous write call returns. DosQueryFHState is called first to obtain the file handle state bits. Assume that the appropriate file handle has been placed into FileHandle already.
#define INCL_DOSFILEMGR /* File system values */ #include <os2.h> #include <stdio.h> HFILE hfFileHandle; /* File handle */ ULONG ulFileHandleState; /* File handle state */ APIRET ulrc; /* Return code */ ulrc = DosQueryFHState(hfFileHandle, &FileHandleState); if (ulrc != 0) { printf("DosQueryFHState error: return code = %ld", ulrc); return; } ulFileHandleState |= OPEN_FLAGS_WRITE_THROUGH; ulrc = DosSetFHState(hfFileHandle, ulFileHandleState); if (ulrc != 0) { printf("DosSetFHState error: return code = %ld", ulrc); return; }
Here are two scenarios involving the use of this function.
- An application requires that data be written in a specific order. To guarantee the order of the data written, it must perform separate synchronous write operations. The application can call DosSetFHState to set the Write-Through flag for the file. This action does not affect any previous asynchronous writes, whose data can remain in the buffers.
- An application cannot handle a certain critical error situation. DosSetFHState can be called to reset critica l error handling as OS/2's responsibility. The I/O function that caused the critical error must be called again so the error can recur, causing control to be passed to OS/2. In the case where asynchronous I/O is being done, the precise time the results of this function will be available to the application is unpredictable.
Determining the Handle Type
DosQueryHType enables an application to determine whether a handle is to a file, a pipe, or a device. This function can be used when a file-oriented application needs to modify its behavior, depending on the source of its input. For example, CMD.EXE suppresses writing prompts when its input is from a disk file.
The following code fragment determines whether a given file handle refers to a file or a device. Assume that the desired file handle has been placed into FileHandle already.
#define INCL_DOSFILEMGR /* File system values */ #include <os2.h> #include <stdio.h> HFILE hfFileHandle; /* File handle */ ULONG ulHandType; /* Handle type (returned) */ ULONG ulFlagWord; /* Device driver attribute (returned) */ APIRET ulrc; /* Return code */ ulrc = DosQueryHType(hfFileHandle, &ulHandType, &ulFlagWord); if (ulrc != 0) { printf("DosQueryHType error: return code = %ld", ulrc); return; }
In the preceding example, DosQueryHType returns a value that characterizes the type of file handle, and the associated device driver attribute word, if the handle type indicates that the file handle is associated with a local character device.
Searching for Files
You can locate files with names that match a given pattern by using metacharacters in DosFindFirst and DosFindNext.
DosFindFirst searches the current directory and locates the first file name that matches the given pattern. DosFindNext locates the next matching file name and continues to find additional matches on each subsequent call until all matching names are found. The functions copy the file statistics on each file located to a data structure that you supply. The file information returned by a search includes file dates and times, length of data in the file, file size, file attributes, and file name.
To find all files that match the file specification, call DosFindNext repeatedly until the message ERROR_NO_MORE_FILES is returned. Then call DosFindClose to close the directory handle.
The following code fragment shows how to find all file names that have the extension ".C":
#define INCL_DOSFILEMGR /* File system values */ #include <os2.h> HDIR hdHdir; ULONG ulFilenames; FILEFINDBUF3 ffbFindBuf; APIRET ulrc; ulFilenames = 1; hdHdir = HDIR_SYSTEM; ulrc = DosFindFirst("*.C", &hdHdir, /* Directory handle */ FILE_NORMAL, /* File attribute to look for */ &ffbFindBuf, /* Result buffer */ sizeof(ffbFindBuf), /* Size of result buffer */ &ulFilenames, /* Number of matching names to look for */ FIL_STANDARD); /* Standard level of information */ if (!ulrc) { do { . . /* Use file name in findbuf.achName */ . ulrc = DosFindNext(hdHdir, &ffbFindBuf, sizeof(ffbFindBuf), &ulFilenames); } while (!ulrc); } DosFindClose(hdHdir);
In this example, DosFindNext continues to retrieve matching file names until it returns an error value (it returns ERROR_NO_MORE_FILES when it cannot find any more matching files).
To keep track of which files have already been found, both functions use the directory handle, hdir.
This directory handle must be set to HDIR_SYSTEM or HDIR_CREATE before the call to DosFindFirst. HDIR_SYSTEM (00000001H) tells OS/2 to use the system handle for standard output, which is always available to the requesting process. HDIR_CREATE (FFFFFFFFH) tells OS/2 to allocate a new, unused handle.
The directory handle returned by DosFindFirst must be used in subsequent calls to DosFindNext; it identifies for DosFindNext the name of the file being sought and the current position in the directory.
An attribute parameter for DosFindFirst allows hidden and system files, as well as normal files, to be included in searches.
After locating the files you need, use DosFindClose to close the directory handle. This ensures that when you search for the same files again, you will start at the beginning of the directory. After DosFindClose is called, a subsequent DosFindNext fails.
Searching Paths for Files
DosSearchPath searches directory paths for t he name of a file object. The file specification can include metacharacters (global file name characters).
The path string used in the search consists of directory paths separated by semicolons. The caller can supply the path string, or it can supply the name of an environment variable whose value is the path string to be searched. The caller can request that the current working directory be searched before the path string is searched.
If the caller specifies an environment variable, DosSearchPath uses DosScanEnv to find the path string. DosScanEnv searches the environment segme nt for an environment variable name; for example, DPATH. The result pointer points to the string that is the value of the environment variable. The call to DosScanEnv can be made direct ly by the application, or it can be invoked by DosSearchPath.
If the file is found, its full path name is returned, with metacharacters left in place. The results might not be meaningful if a buffer overflow occurs.
As an example, assume that a string such as the following exists in the environment:
DPATH=C:\SYSDIR;C:\INIT
The following code fragment illustrates a method for searching directory paths to find a file.
#define INCL_DOSFILEMGR /* File system values */ #define INCL_DOSMISC #include <os2.h> #include <stdio.h> #define ResultBufLen 255 INT main(VOID) { PSZ pszPathRef=""; UCHAR achResultBuffer[ResultBufLen}; PSZ pszFile="OS2.INI"; DosScanEnv("DPATH", &pszPathRef); DosSearchPath(0, /* Path source bit=0 */ pszPathRef, pszFile, achResultBuffer, ResultBufLen); printf("Result 1: %s\n", achResultBuffer); DosSearchPath(2, /* Path source bit=1 */ (PSZ)"DPATH", pszFile, achResultBuffer, ResultBufLen); printf("Result 2: %s\n", achResultBuffer); return; }
Specifying Extended LIBPATHs
An Extended LIBPATH is a path which is searched in conjunction with the system LIBPATH, but which can be changed dynamically, either by the user from the command line, or by an application. There are two Extended LIBPATHs: BeginLIBPATH, which is searched before the system LIBPATH, and EndLIBPATH, which is searched after the system LIBPATH.
Applications can use DosSetExtLIBPATH to set the Extended LIBPATHs. Likewise, they can use DosQueryExtLIBPATH to query the value of either of the Extended LIBPATHs. A flag parameter for the function specifies whether the BeginLIBPATH or the EndLIBPATH is being set or queried. The flag allows two values: BEGIN_LIBPATH (1) which will set or query BeginLIBPATH, or END_LIBPATH (2) which will set or query EndLIBPATH.
Extended LIBPATHs are ASCIIZ strings which are formatted in the same manner as the system LIBPATH, that is, they contains a list of subdirectory paths separated by semicolons. The string argument can be up to 1024 characters and will return an error if longer.
The following example updates the path to be searched before the system LIBPATH, then queries and displays the value.
#define INCL_DOSMISC #define INCL_DOSERRORS #include <os2.h> #include <stdio.h> UCHAR uchBeginLIBPATH[1024] = ""; /* Begin LIBPATH value returned */ APIRET ulrc = NO_ERROR; /* Return code */ ulrc = DosSetExtLIBPATH("C:\\TOOL_X\\VERS_20\\DLL", BEGIN_LIBPATH); /* Add to beginning LIBPATH */ if (ulrc != NO_ERROR) { printf("DosSetExtLIBPATH error: return code = %u\n", ulrc); return 1; } ulrc = DosQueryExtLIBPATH(uchBeginLIBPATH, BEGIN_LIBPATH); /* Query the BeginLIBPATH */ if (ulrc != NO_ERROR) { printf("DosQueryExtLIBPATH error: return code = %u\n", ulrc); return 1; } printf(" BeginLIBPATH = %s\n", uchBeginLIBPATH);
Standard File Handles
Every application, when it first starts, has three input and output file handles available to use. These file handles, called the standard input, standard output, and standard error files, enable the application to read input from the keyboard and display output on the screen without opening or preparing the keyboard or screen.
Standard Input, Output, and Error File Handles
As OS/2 starts an application, it automatically opens the three standard files and makes the file handles-numbered 0, 1, and 2-available to the application. Applications can read from and write to the standard files as soon as they start.
- Standard Input
File handle 0 is the standard input file. This handle can be used to read characters from the keyboard with DosRead. The function reads the specified number of characters unless the user types a turnaround character-that is, a character that marks the end of a line (the default turnaround character is a carriage-return/linefeed character pair).
As DosRead reads the characters, it copies them to the buffer you have supplied, as shown in the code fragment below.
In this example, DosRead copies the number of characters read from standard input to to variable cbRead. DosRead also copies the turnaround character, or characters, to the buffer If the function reads fewer than 80 characters, the turnaround character is the last one in the buffer.
- Standard Output
File handle 1 is the standard output file. This handle can be used to write characters on the screen with DosWrite. The function writes the characters in the given buffer to the current line. If you want to start a new line, you must place the current turnaround character in the buffer.
The code fragment below:
- Displays a prompt
- Reads a string
- Displays the string
#define INCL_DOSFILEMGR /* File system values */ #include <os2.h> #define HF_STDIN 0 /* Standard input handle */ #define HF_STDOUT 1 /* Standard output handle */ #define BUF_SIZE 80 ULONG ulWritten, ulRead; BYTE abBuffer[BUF_SIZE]; static UCHAR ucEnterName[] = "Enter a name: "; DosWrite(HF_STDOUT, ucEnterName, sizeof(ucEnterName), &ulWritten); DosRead(HF_STDIN, abBuffer, sizeof(abBuffer), &ulRead); DosWrite(HF_STDOUT, abBuffer, ulRead, &ulWritten);
- Standard Error
File handle 2 is the standard error file. This handle, like the standard output handle, enables applications to write characters on the screen. Most applications use the standard error file to display error messages, enabling the application to redirect standard output to a file without also redirecting error messages to the file.
Redirecting Standard File Handles
The standard input, standard output, and standard error files are usually the keyboard and screen, but not always. For example, if you redirect standard output by using the greater-than (>) redirection symbol on the application's command line, all data written to the standard output file goes to the given file.
The following command line redirects standard output to the file SAMPLE.TXT and redirects error messages to the file SAMPLE.ERR:
type startup.cmd >sample.txt 2>sample.err
When a standard file is redirected, its handle is still available but corresponds to the given disk file instead of to the keyboard or screen. You can still use DosRead and DosWrite to read from and write to the files.
You can use DosDupHandle to redirect a standard file from inside your application. If you duplicate the standard input file handle, your application reads from the specified file rather than from the keyboard. Duplicating the standard output file handle causes output to be directed to a file or device instead of to the standard output device.
The following code fragment shows how to use the standard input handle to read from a file:
#define INCL_DOSFILEMGR /* File system values */ #include <os2.h> #define HF_STDIN 0 /* Standard input handle */ #define HF_STDOUT 1 /* Standard output handle */ #define BUF_SIZE 80 BYTE abBuffer[BUF_SIZE]; HFILE hf, hfNew; ULONG ulRead, ulWritten, ulAction; APIRET ulrc; ulrc = DosOpen("SAMPLE.C", &hf, &ulAction, 0, FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, (PEAOP2) NULL); if (!ulrc) { hfNew = 0; /* Duplicates standard input */ DosDupHandle(hf, &hfNew); DosRead(HF_STDIN, abBuffer, sizeof(abBuffer), &ulRead); DosWrite(HF_STDOUT, abBuffer, ulRead, &ulWritten); }