Handling errors
The CfsError class provides a common mechanism for obtaining error information pertaining to file system operations. If an error prevents the successful completion of a Common File System operation, the affected method will answer an instance of CfsError, rather than its normal return value. The CfsError instance contains information pertaining to the cause of the error.
Errors are detected by sending the isCfsError message to the result returned by any low-level file system operation, CfsStat operation, or file stream class method such as open: or openEmpty:. Instances of CfsError are the only objects that answer true to this message, all other objects answer false.
File stream instance methods in Common File System handle errors in the same manner as the
Stream class in CLDT. If errors are expected when streaming over a file, set up an exception handler as described in the section on
"Handling of exceptions".
Two examples of handling errors follow. The
CwMessagePrompter class is described in
"Message prompter".
"Attempt to open a file stream on a file, fail if the file does not exist"
| fileName file text |
file := CfsReadFileStream open: (fileName := 'notthere.txt').
file isCfsError
"Test the file descriptor 'open' result for a CfsError"
ifTrue: [
"Open a dialog displaying the open error"
^CwMessagePrompter new
buttonType: XmOK;
iconType: XmICONERROR;
messageString: ('Unable to open file: %1.%2 Error: %3'
bindWith: fileName
with: LineDelimiter
with: file printString);
prompt].
"If the file does exist, answer the file's contents. Instances of
CfsError are not answered by the file stream instance methods
contents or close"
text := file contents.
file close.
^text
"Attempt to open a file descriptor for a file, fail if the file does not exist"
| fd fileName strings stringBuf result |
fd := CfsFileDescriptor
open: (fileName := 'strings.dat')
oflag: ORDONLY.
fd isCfsError
"Test the file descriptor 'open' result for a CfsError"
ifTrue: [
"Open a dialog displaying the error"
^CwMessagePrompter new
buttonType: XmOK;
iconType: XmICONERROR;
messageString: ('Unable to open file: %1.%2 Error: %3'
bindWith: fileName
with: LineDelimiter
with: fd printString);
prompt].
"If the file exists, read 1000 24-byte strings into an array of strings,
and answer the array. If a file error occurs at any time while reading,
answer the CfsError."
strings := Array new: 1000.
1 to: strings size do: :i |
stringBuf := String new: 24.
result := fd
read: stringBuf
startingAt: 1
nbyte: stringBuf size.
result isCfsError
"Test the file descriptor 'read' result for a CfsError"
ifTrue: [
fd close.
^result].
strings at: i put: stringBuf.].
fd close.
^strings
The information contained in a CfsError instance is accessed by way of the following methods:
errno
Answers the integer error number for comparison against the error constants in the CfsConstants pool dictionary.
identifier
Answers a string that is the abbreviated error name. This is the same as the string representing the key in the CfsConstants pool dictionary associated with the receiver's errno value.
message
Answers a short text description of the error.
Printing a CfsError instance using the printString or printOn: message will display all of the information described above.
The specific errors that can be returned by a method are listed in the method comment. No other errors are returned. Following is an example of testing for a specific error that prompts to overwrite existing file:
"Open a new file, prompt for overwrite if it exists"
| fd |
"Open the file, OEXCL causes failure if it exists"
fd := CfsFileDescriptor
open: 'new.fil'
oflag: ORDWR | OCREAT | OEXCL.
fd isCfsError
ifTrue:
"NOTE: Because an error occurred, fd is not a file descriptor,
it is a CfsError instance."
fd errno = EEXIST
ifTrue: [
"The file already exists"
(CwMessagePrompter new
buttonType: XmYESNO;
iconType: XmICONWARNING;
messageString: 'File exists. Overwrite?';
prompt)
ifTrue: [
"Overwrite the file obtaining a file descriptor"
fd := CfsFileDescriptor
open: 'new.fil'
oflag: ORDWR | OTRUNC.
fd isCfsError
ifTrue: ^self error: fd printString]]
ifFalse: ^self]]
ifFalse: [
"It's some other error - walkback"
^self error: fd printString]].
"Here, fd is guaranteed to be a file descriptor,
do something with the fd, and then close it"
fd close.
When testing for a specific error, compare the CfsError instance's errno against the error constants in the CfsConstants pool dictionary. All application code and documentation should refer to errors by identifier, for example, ENOENT, rather than by number, because error constant values can vary from platform to platform.