Prev: interactive repl during background execution (in sbcl)
Next: Can someone give me an example of the SNAME type ?
From: Teemu Likonen on 1 Jul 2010 07:15 I'm wondering what would be the best way to detect the cause of some file errors. I mean opening a file may fail because the file doesn't exist or user has no access to the file (for example). I'm looking for ideas to detect the difference. The condition type doesn't tell much: (handler-case (with-open-file (s "/etc/shadow")) ;No permissions to read (t (c) (princ-to-string (type-of c)))) => "SIMPLE-FILE-ERROR" (handler-case (with-open-file (s "/does-not-exist")) (t (c) (princ-to-string (type-of c)))) => "SIMPLE-FILE-ERROR" CL implementation may provide error messages through a PRINT-OBJECT method. This is how SBCL would say with (princ-to-string c): error opening #P"/etc/shadow": Permission denied error opening #P"/does-not-exist": No such file or directory But what if I want to handle these errors differently and perhaps print a different error messages for user? Does the condition object contain a slot with standardized error code or something like that to see what's the actual cause of the file error? Or do I just have to detect the difference myself with something like this: (define-condition file-does-not-exist (file-error) nil) (define-condition file-is-not-readable (file-error) nil) [...] (unless (file-exists-p file) (error 'file-does-not-exist :pathname file)) (handler-case (with-open-file (s file :direction :input) ...) (file-error (c) ;; Probably no read access (error 'file-is-not-readable :pathname (file-error-pathname c)))) So now the different types of file errors would be signalled as FILE-DOES-NOT-EXIST and FILE-IS-NOT-READABLE which some other handler code can handle. What are your suggestions?
From: Zach Beane on 1 Jul 2010 08:08 Teemu Likonen <tlikonen(a)iki.fi> writes: > I'm wondering what would be the best way to detect the cause of some > file errors. I mean opening a file may fail because the file doesn't > exist or user has no access to the file (for example). I'm looking for > ideas to detect the difference. One way is via :if-does-not-exist, e.g. (open "/etc/shadow-blah-blah" :if-does-not-exist nil) => nil (open "/etc/shadow" :if-does-not-exist nil) => signals error Zach
From: Pascal J. Bourguignon on 1 Jul 2010 10:38 Teemu Likonen <tlikonen(a)iki.fi> writes: > I'm wondering what would be the best way to detect the cause of some > file errors. I mean opening a file may fail because the file doesn't > exist or user has no access to the file (for example). I'm looking for > ideas to detect the difference. The condition type doesn't tell much: > > (handler-case > (with-open-file (s "/etc/shadow")) ;No permissions to read > (t (c) (princ-to-string (type-of c)))) > => "SIMPLE-FILE-ERROR" > > (handler-case > (with-open-file (s "/does-not-exist")) > (t (c) (princ-to-string (type-of c)))) > => "SIMPLE-FILE-ERROR" > > CL implementation may provide error messages through a PRINT-OBJECT > method. This is how SBCL would say with (princ-to-string c): > > error opening #P"/etc/shadow": Permission denied > error opening #P"/does-not-exist": No such file or directory > > But what if I want to handle these errors differently and perhaps print > a different error messages for user? Does the condition object contain a > slot with standardized error code or something like that to see what's > the actual cause of the file error? Unfortunately, conditions are somewhat underspecified in Common Lisp. To the point they're almost useless, for automatic processing or recovery. When you're writing your own code, of course, you can specify a rich condition hiearchy, which would allow you to handle all exceptionnal cases without any difficulty. But then, in an OO program you could very well have 3 to 10 times more condition subclasses than program classes! > Or do I just have to detect the difference myself with something like > this: > > (define-condition file-does-not-exist (file-error) nil) > (define-condition file-is-not-readable (file-error) nil) See, already for one class (STREAM), and one operation (OPEN) you defined two conditions. To really use conditions, the Common Lisp standard would have to define thousands of conditions. Of course, an implementation would not signal a given condition if it never occured, but if the situation defined for a given condition occured, the standard would mandate the implementations to signal the corresponding condition. In any case, my point here is that you have the sources of the implementations. Define the thousands of condition subclasses needed (the "Exceptionnal Situations Ontology"), and implement them in each free implementation. > What are your suggestions? You could try indeed to PRINC the condition, and use regexps to try to identify the specific situation, and from this, signal the refined conditions you defined. (I did that once). Obviously, implementation specific (you can write it as a portability layer). The pain here is that it's very version specific, sometimes even user environment specific (in clisp, the error messages are localized). Since you're already doing something implementation dependent, why not further inspect the actual conditions signaled by the implementation. For example, in the case of clisp, most bare Common Lisp conditions are subclassed with a SIMPLE- version, which has a format control string and arguments. Using (unexported) readers from the SYSTEM package, you can get the list of arguments and usually find there, useful processable details about the condition. But not all implementations are so "helpful". -- __Pascal Bourguignon__ http://www.informatimago.com/
From: Teemu Likonen on 1 Jul 2010 13:02 * 2010-07-01 16:38 (+0200), Pascal J. Bourguignon wrote: > Unfortunately, conditions are somewhat underspecified in Common Lisp. OK. Fortunately, for me it's usually enough to detect the difference between non-existing file and other file errors. Still, for possible future needs I'll probably write some helper functions for checking file's type (regular file, directory, socket etc.), owner, group and permissions through POSIX stat. > You could try indeed to PRINC the condition, and use regexps to try to > identify the specific situation, and from this, signal the refined > conditions you defined. I think nobody wants to go with this kind of kludges. :-)
From: Teemu Likonen on 1 Jul 2010 18:02 * 2010-07-01 14:15 (+0300), Teemu Likonen wrote: > (define-condition file-is-not-readable (file-error) nil) > (handler-case > (with-open-file (s file :direction :input) > ...) > (file-error (c) > ;; Probably no read access > (error 'file-is-not-readable :pathname (file-error-pathname c)))) I just found out that SBCL has SB-POSIX:ACCESS function which makes it easy to check if user has permissions to some file or directory. Errors are signalled as condition SB-POSIX:SYSCALL-ERROR which has slot ERRNO containing a standard POSIX error code. So: (handler-case (sb-posix:access "/etc/shadow" #b100) ;read access (sb-posix:syscall-error (c) (case (sb-posix:syscall-errno c) (2 "File not found") (13 "No permissions") (36 "Filename too long")))) => "No permissions" There are predefined variables for error codes: SB-POSIX:ENOENT (2), SB-POSIX:EACCES (13), SB-POSIX:ENAMETOOLONG (36) etc.
|
Next
|
Last
Pages: 1 2 3 Prev: interactive repl during background execution (in sbcl) Next: Can someone give me an example of the SNAME type ? |