2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2007 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
18 #include "../charconv/utf8.h"
19 #include "../charconv/filesys.h"
20 #include "canaccess.h"
28 #define ACCESS_IN_CWD(F,M) (can_access((F), (M)))
34 #define ACCESS_IN_CWD(F,M) (-1)
43 * Check if we can access a file in a given way
45 * Args: file -- The file to check
46 * mode -- The mode ala the access() system call, see ACCESS_EXISTS
47 * and friends in alpine.h.
49 * Result: returns 0 if the user can access the file according to the mode,
50 * -1 if he can't (and errno is set).
55 can_access(char *file
, int mode
)
61 * NOTE: The WinNT access call returns that every directory is readable and
62 * writable. We actually want to know if the write is going to fail, so we
63 * try it. We don't read directories in Windows so we skip implementing that.
65 if(mode
& WRITE_ACCESS
&& file
&& !our_stat(file
, &buf
) && (buf
.st_mode
& S_IFMT
) == S_IFDIR
){
71 * We'd like to just call temp_nam here, since it creates a file
72 * and does what we want. However, temp_nam calls us!
74 if((testname
= malloc(MAXPATH
* sizeof(char)))){
75 strncpy(testname
, file
, MAXPATH
-1);
76 testname
[MAXPATH
-1] = '\0';
77 if(testname
[0] && testname
[(l
=strlen(testname
))-1] != '\\' &&
80 strncat(testname
, "\\", MAXPATH
-strlen(testname
)-1);
81 testname
[MAXPATH
-1] = '\0';
85 strncat(testname
, "caXXXXXX", MAXPATH
-strlen(testname
)-1) && mktemp(testname
)){
86 if((fd
= our_open(testname
, O_CREAT
|O_EXCL
|O_WRONLY
|O_BINARY
, 0600)) >= 0){
90 /* success, drop through to access call */
94 /* can't write in the directory */
104 if(mode
& EXECUTE_ACCESS
) /* Windows access has no execute mode */
105 mode
&= ~EXECUTE_ACCESS
; /* and crashes because of it */
108 return(our_access(file
, mode
));
112 /*----------------------------------------------------------------------
113 Check if we can access a file in a given way in the given path
115 Args: path -- The path to look for "file" in
116 file -- The file to check
117 mode -- The mode ala the access() system call, see ACCESS_EXISTS
118 and friends in alpine.h.
120 Result: returns 0 if the user can access the file according to the mode,
121 -1 if he can't (and errno is set).
124 can_access_in_path(char *path
, char *file
, int mode
)
129 if(!path
|| !*path
|| is_rooted_path(file
)){
130 rv
= can_access(file
, mode
);
132 else if(is_homedir_path(file
)){
133 strncpy(tmp
, file
, sizeof(tmp
));
134 tmp
[sizeof(tmp
)-1] = '\0';
135 rv
= fnexpand(tmp
, sizeof(tmp
)) ? can_access(tmp
, mode
) : -1;
137 else if((rv
= ACCESS_IN_CWD(file
,mode
)) < 0){
138 char path_copy
[MAXPATH
+ 1], *p
, *t
;
140 if(strlen(path
) < MAXPATH
){
141 strncpy(path_copy
, path
, sizeof(path_copy
));
142 path_copy
[sizeof(path_copy
)-1] = '\0';
144 for(p
= path_copy
; p
&& *p
; p
= t
){
145 if((t
= strchr(p
, PATH_SEP
)) != NULL
)
148 snprintf(tmp
, sizeof(tmp
), "%s%c%s", p
, FILE_SEP
, file
);
149 if((rv
= can_access(tmp
, mode
)) == 0)