GEOS SDK TechDocs
|
|
3.1 Accessing Drives
|
4 Directories and Paths
Applications will work with disks more than they will work with drives. Once a geode knows a disk's handle, it can ignore such questions as whether the disk is in a drive; it need merely provide the disk's handle. If necessary, the system will prompt the user to insert the disk in the appropriate drive.
DiskRegisterDisk(), DiskRegisterDiskSilently()
GEOS automatically keeps track of all disks used. The first time a disk is accessed in a session, it is registered . This means that it is assigned a disk handle .
The disk handle records certain information, such as the disk's volume name and whether the disk is writable. It also notes in which drive the disk was last inserted; if the system prompts the user to reinsert the disk, it will insist on that drive. A disk is automatically reregistered when certain actions are performed which might invalidate a disk's handle-table entry; for example, it is reregistered if it is formatted. It is also reregistered if someone tries to write a file to a disk which is marked read-only; the user may have ejected the disk and removed its write-protect tab. Note that reregistering a disk does not change its handle; it just brings GEOS's information about the disk up-to-date.
Note that the disk handle is not a reference to the global handle table; thus, Swat commands like
phandle
will not work with disk handles. Disk handles should always be treated as opaque 16-bit tokens.
You can specifically instruct the system to register a disk by calling the routine
DiskRegisterDisk()
. The routine is passed a single argument, namely the drive number. If the disk has an entry in the disk table, the routine will not reregister the disk; it will just return the disk's handle. If the disk has no entry in the table, the system will create an entry and register the disk. In this case, also, the routine will return the (new) disk handle. If the routine fails (for example, because there is no valid disk in the specified drive, or the drive itself does not exist), it returns a null handle.
When a disk is registered, the system notes the volume label. This label is used when the system has to prompt the user to insert a disk. If an unlabeled disk is inserted, the system will choose an arbitrary label for the volume (e.g. "UNNAMED1"). The system does not actually write this label to the disk; the label is used by the system and discarded when the session ends. Ordinarily, the system will present an alert box to inform the user about the temporary label.
You can suppress this notification by calling the system routine
DiskRegisterDiskSilently()
. This routine has the same arguments and return values as
DiskRegisterDisk()
.
DiskGetVolumeInfo(), DiskGetVolumeFreeSpace(), DiskGetDrive(), DiskGetVolumeName(), DiskFind(), DiskCheckWritable(), DiskCheckInUse(), DiskCheckUnnamed(), DiskForEach(), DiskInfoStruct, DiskFindResult
GEOS provides many routines to get information about disks. If geodes call disk routines at all, they are most likely to call these. Most of these routines are passed the handle of the disk. If you know the disk's volume label and need to find out its handle, call the routine
DiskFind()
(described below). If you know the disk is currently in a drive and you need to find out its handle, register the disk (see Registering Disks
). Note that any routine which is passed a disk handle can be passed a standard path constant; in this case, the routine will give you information about the disk containing the
geos.ini
file.
The basic disk-information routine is
DiskGetVolumeInfo()
. This returns information about the size of the disk and the amount of free space available. The routine is passed two arguments: the disk handle and a pointer to a
DiskInfoStruct
structure (shown below). The routine fills in the fields of the
DiskInfoStruct
structure and returns zero if it was successful. If it fails for any reason, it returns an error value and sets the thread's error value (which can be recovered with
ThreadGetError()
). The usual error value returned is the constant ERROR_INVALID_VOLUME.
Code Display 17-1 The DiskInfoStruct Structure
typedef struct {
word DIS_blockSize; /* # of bytes in a block; smallest size
* file system can allocate at once */
sdword DIS_freeSpace; /* # of bytes free on disk */
sdword DIS_totalSpace; /* Total size of the disk in bytes */
char DIS_name[VOLUME_BUFFER_SIZE];
/* Volume name; if disk is unnamed, this
* is the temporary name. String is
* null-terminated. */
} DiskInfoStruct;
If you just want to know a disk's name, call
DiskGetVolumeName()
. This routine takes two arguments: the disk handle and the address of a character buffer. (The buffer must be at least VOLUME_NAME_LENGTH_ZT characters long.) It writes the volume name to the buffer as a null-terminated string, and it returns the buffer's address. If the volume is unnamed,
DiskGetVolumeName()
writes the temporary volume name.
Note that all the routines which return a volume's name will return the temporary name if the volume is unnamed. For this reason, if you want to find out if a volume is unnamed, you must use a special purpose routine, namely
DiskCheckUnnamed()
. This Boolean routine is passed the disk's handle. If the volume does not have a permanent label, the routine returns
true
; otherwise, it returns
false
.
If you want to know how much free space is available on a disk, call the routine
DiskGetVolumeFreeSpace()
. The routine is passed the disk handle; it returns (as a dword) the number of free bytes available. If the volume is currently read-only (e.g. a floppy disk with the write-protect tab set), it returns the amount of space that would be available if the volume were made read/write. If the volume is, by its nature, not writable (e.g. a CD-ROM disk), the routine will return zero. It will also return zero if an error condition occurs; in this case, it will also set the thread's error value.
If you want to know what drive a volume is associated with, call
DiskGetDrive()
. This routine takes one argument, namely the volume's disk handle. It returns the number of the drive which had that disk. Note that it will return this value even if that drive is no longer usable.
If you know the label of a volume which has been registered and you need to find out its handle, call the routine
DiskFind()
.
The routine takes two arguments: the address of a null-terminated string containing the volume name and a pointer to a variable of the
DiskFindResult
enumerated type. It will return the disk's handle; if no disk with the specified name has been registered, it will return a null handle.
DiskFindResult
has the following possible values:
DiskForEach()
, described below.
To check if a volume is writable, call the Boolean routine
DiskCheckWritable()
. The routine takes one argument, the disk's handle. If the disk is writable, the routine returns
true
(i.e. non-zero). If the disk is non-writable, the routine returns
false
(i.e. zero).
To see if a disk is being used by any threads, call
DiskCheckInUse()
. The routine takes one argument: the disk's handle. It returns
true
(i.e. non-zero) if a file on the disk is open or if any thread has a directory on that disk in its directory stack (see Current Path and Directory Stack
). If neither condition applies, the routine returns
false
(i.e. zero).
If you want to perform an action on every disk, call
DiskForEach()
. This routine takes one argument, a pointer to a Boolean callback routine. The callback routine should take a single argument, the handle of a disk.
DiskForEach()
calls the callback routine once for every registered disk. It passes the disk handle to the callback routine, which can take any action it wants; for example, it could call one of the other disk-information routines. The callback routine can make
DiskForEach()
halt prematurely by returning a non-zero value. If the callback routine forced an early halt,
DiskForEach()
returns the last disk handle which had been passed to the callback routine; otherwise it returns a null handle. This routine is commonly called to look for a specific disk. To do this, simply have the callback routine check each disk to see if it is the one sought; if it is, simply return
true
, and
DiskForEach()
will return that disk's handle.
DiskForEach()
does not need to examine the actual disks; it works from the information the file-system stores about all registered disks. This means that
DiskForEach()
will not have to prompt the user to insert any disks. Of course, the callback routine may need to examine the disks, in which case the user will be prompted when necessary.
DiskSave(), DiskRestore(), DiskRestoreError
A disk does not necessarily have the same handle from one execution of GEOS to another. This can pose a problem for an application which is restarting from a state file. In order to reopen a file, it has to know the file's location. If it knows the file's location relative to a standard path, there is no problem, since the application can use the standard path constant in the place of a disk handle. If the file is not in a standard path, the application will need some way of figuring out the disk's handle on restart.
For this reason, GEOS provides
DiskSave()
and
DiskRestore()
.
DiskSave()
saves information about a disk in an opaque data structure.
DiskRestore()
reads such a data buffer and returns the handle of the disk described; it even arranges to prompt the user if the disk has not been registered yet.
To save a disk handle, call
DiskSave()
. This routine takes three arguments:
DiskSave()
will write opaque data to that buffer; you will need to pass that data to
DiskRestore()
to restore the handle.
DiskSave()
, that integer should contain the size of the buffer (in bytes). When
DiskSave()
exits, the integer will contain the size of the buffer needed or used (as described below).
If
DiskSave()
was successful, it will return
true
. The integer parameter will contain the size of the buffer actually needed; for example, if the buffer had been 100 bytes long and
DiskSave()
returns 60, you can safely free the last 40 bytes in the buffer. If
DiskSave()
failed, it will return
false
. If it failed because the buffer was too small, it will write the size needed into the integer passed; simply call
DiskSave()
again with a large enough buffer. If
DiskSave()
failed for some other reason (e.g. the disk belongs to a drive which no longer exists), it will write a zero value to the integer.
To restore a disk, call
DiskRestore()
. This routine takes two arguments:
DiskSave()
.
DiskRestore()
will fail in this situation.
If the disk in question has already been registered or is currently in its drive,
DiskRestore()
will return its handle. If the disk is not registered and is not in any drive,
DiskRestore()
will call the callback routine. The callback routine should accept the following four arguments:
DiskRestoreError
(see below) which would be returned if the callback routine hadn't been called.
If the callback routine believes the user inserted the correct disk, it should return DRE_DISK_IN_DRIVE. Otherwise, it should return a
DiskRestoreError
constant. In this case,
DiskRestore()
will fail and set the thread's error value to the constant specified. If the callback routine returns an error, that error will generally be DRE_USER_CANCELLED_RESTORE.
If
DiskRestore()
is successful, it will return the disk handle; this may be different from the disk's handle in the previous execution. You may now free the data buffer, if you like. If
DiskRestore()
fails, it will return a null handle and set the thread's error value.
There are several different
DiskRestoreError
values; they are listed below.
DiskRestore()
.
DiskRestore()
found the disk in the drive but was for some reason unable to create the disk handle.DiskSetVolumeName(), DiskFormat(), DiskCopy(), FormatError, DiskCopyCallback, DiskCopyError
GEOS provides several utilities for working with disks. These utilities allow geodes to copy disks, format them, and change their volume names. Most applications will never need to use these utilities; they can rely on the users to take care of disk formatting with an application like GeoManager. However, some applications will want to make use of them. For example, an archiving program might automatically format storage disks and give them appropriate labels.
If you want to set or change a volume's name, you should call
DiskSetVolumeName()
. This routine takes two arguments: the volume's handle and the address of a null-terminated string (containing the new volume name). If it is able to change the volume's name, it returns zero; otherwise, it returns an error code. It sets or clears the thread's error value appropriately. The following error codes may be returned:
If a geode needs to format a disk, it can call the routine
DiskFormat()
. This routine can do either low-level or high-level ("soft") formats. The routine does not interact with the user interface; instead, it calls a callback routine, which can arrange any such interaction.
DiskFormat()
takes seven arguments:
MediaType
enumerated type (see MEDIA_160K, MEDIA_180K, MEDIA_320K, MEDIA_360K These are all sizes used by 5.25-inch disks.
).
DiskFormat()
will do a "soft format" if possible; it will check the sectors and write a blank file allocation table, but it will not necessarily erase the data from the disk.
DiskFormat()
. It should return
true
to abort the format, or
false
(i.e. zero) to continue with the format. If neither DFF_CALLBACK_PERCENT_DONE nor DFF_CALLBACK_CYL_HEAD is passed, the callback routine will never be called, so this argument may be a null pointer.
DiskFormat()
returns a member of the
FormatError
enumerated type. If the format was successful, it will return the constant FMT_DONE (which is guaranteed to equal zero). Otherwise, it will return one of the following constants:
FMT_DRIVE_NOT_READY FMT_ERROR_WRITING_BOOT FMT_ERROR_WRITING_ROOT_DIR FMT_ERROR_WRITING_FAT FMT_ABORTED FMT_SET_VOLUME_NAME_ERROR FMT_CANNOT_FORMAT_FIXED_DISKS_IN_CUR_RELEASE FMT_BAD_PARTITION_TABLE, FMT_ERR_READING_PARTITION_TABLE, FMT_ERR_NO_PARTITION_FOUND, FMT_ERR_MULTIPLE_PRIMARY_PARTITIONS, FMT_ERR_NO_EXTENDED_PARTITION_FOUND FMT_ERR_CANNOT_ALLOC_SECTOR_BUFFER FMT_ERR_DISK_IS_IN_USE FMT_ERR_WRITE_PROTECTED FMT_ERR_DRIVE_CANNOT_SUPPORT_GIVEN_FORMAT FMT_ERR_INVALID_DRIVE_SPECIFIED FMT_ERR_DRIVE_CANNOT_BE_FORMATTED FMT_ERR_DISK_UNAVAILABLE
GEOS
provides a routine for copying disks. This routine,
DiskCopy()
, maintains a balance between the two goals of limiting memory usage and minimizing disk swapping. It will reformat the destination disk if necessary. The routine does a sector-for-sector copy; therefore, the destination disk must either be of exactly the same type as the source disk (i.e., same medium and size), or it must be reformatable to be the same size. For this reason, neither the source nor the destination may be a fixed disk.
DiskCopy()
does not interact with the user directly, even though the user may have to swap disks. Instead, it calls a callback routine whenever interaction with the user may be necessary. The routine takes the following arguments:
DiskCopyCallback
enumerated type (described below), a disk handle, and a word-sized parameter holding any other appropriate information. The routine should return non-zero to abort the copy; otherwise, it should return zero.
The callback routine is called under a variety of circumstances. When it is called, the first argument passed is a member of the
DiskCopyCallback
enumerated type, which specifies both why the callback routine was called and what the other arguments signify.
DiskCopyCallback
contains the following types:
DiskCopy()
will periodically call the callback routine with this parameter. In this case, the second argument will be meaningless; the third parameter will be the percentage of the destination disk which has been formatted.
DiskCopy()
will periodically call the callback routine with this parameter. In this case, the second parameter will be meaningless; the third parameter will be the percentage of the copy which has been completed.
If the copy was successful,
DiskCopy()
returns zero. Otherwise, it returns a member of the
DiskCopyError
enumerated type, which has the following members:
GEOS SDK TechDocs
|
|
3.1 Accessing Drives
|
4 Directories and Paths