Improved FILE-NOT-ACCESSIBLE, which still has problems, and added discussion
of its problems to the manual.
This commit is contained in:
		
							parent
							
								
									cdfa775de7
								
							
						
					
					
						commit
						61cdf20586
					
				|  | @ -1294,8 +1294,33 @@ For example, | |||
|     Since symlink permission bits are ignored by the filesystem, these | ||||
|     calls do not take a \var{chase?} flag. | ||||
| 
 | ||||
|     \oops{\ex{file-not-writeable?} does not currently do the directory | ||||
|             check.} | ||||
|     Note that these procedures use the process' \emph{effective} user | ||||
|     and group ids for permission checking. {\Posix} defines an \ex{access()} | ||||
|     function that uses the process' real uid and gids. This is handy | ||||
|     for setuid programs that would like to find out if the actual user | ||||
|     has specific rights; scsh ought to provide this functionality (but doesn't | ||||
|     at the current time).  | ||||
| 
 | ||||
|     There are several problems with these procedures. First, there's an | ||||
|     atomicity issue. In between checking permissions for a file and then trying | ||||
|     an operation on the file, another process could change the permissions, | ||||
|     so a return value from these functions guarantees nothing. Second,  | ||||
|     the code special-cases permission checking when the uid is root---if | ||||
|     the file exists, root is assumed to have the requested permission. | ||||
|     However, not even root can write a file that is on a read-only file system, | ||||
|     such as a CD ROM. In this case, \ex{file-not-writable?} will lie, saying | ||||
|     that root has write access, when in fact the opening the file for write | ||||
|     access will fail. | ||||
|     Finally, write permission confounds write access and create access. | ||||
|     These should be disentangled. | ||||
| 
 | ||||
|     Some of these problems could be avoided if {\Posix} had a real-uid | ||||
|     variant of the \ex{access()} call we could use, but the atomicity | ||||
|     issue is still a problem. In the final analysis, the only way to | ||||
|     find out if you have the right to perform an operation on a file | ||||
|     is to try and open it for the desired operation. These permission-checking | ||||
|     functions are mostly intended for script-writing, where loose guarantees | ||||
|     are tolerated. | ||||
| \end{desc} | ||||
| 
 | ||||
| \defun  {file-readable?}   {fname} \boolean | ||||
|  | @ -1304,6 +1329,7 @@ For example, | |||
| \begin{desc} | ||||
|     These procedures are the logical negation of the  | ||||
|     preceding \ex{file-not-\ldots?} procedures. | ||||
|     Refer to them for a discussion of their problems and limitations. | ||||
| \end{desc} | ||||
| 
 | ||||
| \begin{defundesc}{file-not-exists?} {fname [chase?]} \object | ||||
|  |  | |||
|  | @ -3,11 +3,31 @@ | |||
| ;;; chase? true (the default) means if the file is a symlink, chase the link | ||||
| ;;; and report on the file it references. chase? = #f means check the actual | ||||
| ;;; file itself, even if it's a symlink. | ||||
| ;;; writeable means (1) file exists & is writeable OR (2) file doesn't exist | ||||
| ;;;     but directory is writeable. | ||||
| 
 | ||||
| ;;; (file-not-accessible? perms fd/port/fname) | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;; PERMS is 3 bits, not 9. | ||||
| ;;; writeable means (1) file exists & is writeable OR (2) file doesn't exist | ||||
| ;;;     and directory is writeable. That is, writeable means writeable or | ||||
| ;;;     creatable. | ||||
| ;;; | ||||
| ;;; There's a Posix call, access(), that checks using the *real* uid, not | ||||
| ;;; the effective uid, so that setuid programs can figure out if the luser | ||||
| ;;; has perms. file-not-accessible? is defined in terms of the effective uid,  | ||||
| ;;; so we can't use access(). | ||||
| ;;;  | ||||
| ;;; This is a kind of bogus function. The only way to do a real check is to | ||||
| ;;; try an open() and see if it flies. Otherwise, there's an obvious atomicity | ||||
| ;;; problem. Also, we special case root, saying root always has all perms. But | ||||
| ;;; not even root can write on a read-only filesystem, such as a CD ROM. In | ||||
| ;;; this case, we'd blithely say the file was writeable -- there's no way to | ||||
| ;;; check for a ROFS without doing an open(). We need a euid analog to | ||||
| ;;; access(). Ah, well. | ||||
| ;;;  | ||||
| ;;; I also should define a family of real uid perm-checking calls. | ||||
| ;;; | ||||
| ;;; Return values: | ||||
| ;;; #f			Accessible | ||||
| ;;; #f			Accessible in at least one of the requested ways. | ||||
| ;;; search-denied	Can't stat | ||||
| ;;; permission		File exists but is protected | ||||
| ;;; 			(also for errno/rofs) | ||||
|  | @ -16,27 +36,43 @@ | |||
| ;;; | ||||
| ;;; Otherwise, signals an error. | ||||
| 
 | ||||
| (define (file-not-accessible? perms fd/port/fname . maybe-chase?) | ||||
| (define (file-not-accessible? perms fd/port/fname) | ||||
|   (let ((uid (user-effective-uid))) | ||||
|     (and (not (zero? uid)) ; Root can do what he likes. | ||||
| 	 (with-errno-handler ((err data) | ||||
| 			      ((errno/acces) 'search-denied) | ||||
| 			      ((errno/noent) 'nonexistent) | ||||
| 			      ((errno/notdir) 'not-directory)) | ||||
|     (with-errno-handler ((err data) | ||||
| 			 ((errno/acces) 'search-denied) | ||||
| 			 ((errno/notdir) 'not-directory) | ||||
| 
 | ||||
| 	   (and (let* ((info (apply file-info fd/port/fname maybe-chase?)) | ||||
| 		       (acc (file-info:mode info))) | ||||
| 		  (cond ((= (file-info:uid info) (user-effective-uid)) ; User | ||||
| 			 (zero? (bitwise-and acc (arithmetic-shift perms 6)))) | ||||
| 			 ;; If the file doesn't exist, we usually return | ||||
| 			 ;; 'nonexistent, but we special-case writability | ||||
| 			 ;; for the directory check. | ||||
| 			 ((errno/noent) | ||||
| 			  (and (or (zero? (bitwise-and perms 2)) | ||||
| 				   ;; This string? test *has* to return #t. | ||||
| 				   ;; If fd/port/fname is an fd or a port, | ||||
| 				   ;; we wouldn't get an errno/noent error! | ||||
| 				   ;; Just being paranoid... | ||||
| 				   (not (string? fd/port/fname)) | ||||
| 				   ;; OK, check to see if we can create | ||||
| 				   ;; files in the directory. | ||||
| 				   (file-not-accessible? 2 | ||||
| 				     (directory-as-file-name | ||||
| 				       (file-name-directory fd/port/fname)))) | ||||
| 			       'nonexistent))) | ||||
| 
 | ||||
|       (and (let* ((info (file-info fd/port/fname)) | ||||
| 		  (acc (file-info:mode info))) | ||||
| 	     (cond ((zero? uid) #f)	; Root can do as he wishes. | ||||
| 
 | ||||
| 		   ((= (file-info:uid info) (user-effective-uid)) ; User | ||||
| 		    (zero? (bitwise-and acc (arithmetic-shift perms 6)))) | ||||
| 		       | ||||
| 			((= (file-info:gid info) (user-effective-gid)) ; Group | ||||
| 			 (zero? (bitwise-and acc (arithmetic-shift perms 3)))) | ||||
| 			((memv (file-info:gid info) (user-supplementary-gids)) | ||||
| 			 (zero? (bitwise-and acc (arithmetic-shift perms 3)))) | ||||
| 		   ((or (= (file-info:gid info) (user-effective-gid)) ; Group | ||||
| 			(memv (file-info:gid info) (user-supplementary-gids))) | ||||
| 		    (zero? (bitwise-and acc (arithmetic-shift perms 3)))) | ||||
| 		       | ||||
| 			(else				    ; Other | ||||
| 			 (zero? (bitwise-and acc perms))))) | ||||
| 		'permission))))) | ||||
| 		   (else		; Other | ||||
| 		    (zero? (bitwise-and acc perms))))) | ||||
| 	   'permission)))) | ||||
| 
 | ||||
| ;;;;;; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 shivers
						shivers