| /** @file | |
| Implementation of the Posix access() function. | |
| Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials are licensed and made available under | |
| the terms and conditions of the BSD License that accompanies this distribution. | |
| The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license. | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <LibConfig.h> | |
| #include <sys/EfiCdefs.h> | |
| #include <ctype.h> | |
| #include <errno.h> | |
| #include <sys/stat.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <sys/syslimits.h> | |
| /** Save some typing later on. */ | |
| #define GOOD_MODE (F_OK | X_OK | W_OK | R_OK) | |
| /** Determine accessibility of a file. | |
| The access() function checks the file, named by the pathname pointed to by | |
| the Path argument, for accessibility according to the bit pattern contained | |
| in Mode. | |
| The value of Mode is either the bitwise-inclusive OR of the access | |
| permissions to be checked (R_OK, W_OK, X_OK) or the existence test (F_OK). | |
| If Path ends in '/' or '\\', the target must be a directory, otherwise it doesn't matter. | |
| A file is executable if it is NOT a directory and it ends in ".efi". | |
| @param[in] Path Path or name of the file to be checked. | |
| @param[in] Mode Access permissions to check for. | |
| @retval 0 Successful completion. | |
| @retval -1 File is not accessible with the given Mode. The error condition | |
| is indicated by errno. Values of errno specific to the access | |
| function include: EACCES, ENOENT, ENOTDIR, ENAMETOOLONG | |
| **/ | |
| int | |
| access( | |
| const char *Path, | |
| int Mode | |
| ) | |
| { | |
| struct stat FileStat; | |
| int retval = -1; | |
| size_t PLength; | |
| uint32_t WantDir; | |
| uint32_t DirMatch; | |
| if((Path == NULL) || ((Mode & ~GOOD_MODE) != 0)) { | |
| errno = EINVAL; | |
| } | |
| else { | |
| PLength = strlen(Path); | |
| if(PLength > PATH_MAX) { | |
| errno = ENAMETOOLONG; | |
| } | |
| else { | |
| retval = stat(Path, &FileStat); | |
| if(retval == 0) { | |
| /* Path exists. FileStat now holds valid information. */ | |
| WantDir = isDirSep(Path[PLength - 1]); // Does Path end in '/' or '\\' ? | |
| DirMatch = (! WantDir && (! S_ISDIR(FileStat.st_mode))); | |
| /* Test each permission individually. */ | |
| do { | |
| if(Mode == F_OK) { /* Existence test. */ | |
| if(DirMatch) { /* This is a directory or file as desired. */ | |
| retval = 0; | |
| } | |
| else { | |
| /* Indicate why we failed the test. */ | |
| errno = (WantDir) ? ENOTDIR : EISDIR; | |
| } | |
| break; /* F_OK does not combine with any other tests. */ | |
| } | |
| if(Mode & R_OK) { | |
| if((FileStat.st_mode & READ_PERMS) == 0) { | |
| /* No read permissions. | |
| For UEFI, everything should have READ permissions. | |
| */ | |
| errno = EDOOFUS; /* Programming Error. */ | |
| break; | |
| } | |
| } | |
| if(Mode & W_OK) { | |
| if((FileStat.st_mode & WRITE_PERMS) == 0) { | |
| /* No write permissions. */ | |
| errno = EACCES; /* Writing is not OK. */ | |
| break; | |
| } | |
| } | |
| if(Mode & X_OK) { | |
| /* In EDK II, executable files end in ".efi" */ | |
| if(strcmp(&Path[PLength-4], ".efi") != 0) { | |
| /* File is not an executable. */ | |
| errno = EACCES; | |
| break; | |
| } | |
| } | |
| retval = 0; | |
| } while(FALSE); | |
| } | |
| else { | |
| /* File or path does not exist. */ | |
| errno = ENOENT; | |
| } | |
| } | |
| } | |
| return retval; | |
| } |