* Update to version 2.19.5
[alpine.git] / pith / osdep / canaccess.c
blob8dd97b262650134b12669245ea9e6e84b8238be9
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: canaccess.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2014 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include <system.h>
20 #include "bldpath.h"
21 #include "fnexpand.h"
22 #include "../charconv/utf8.h"
23 #include "../charconv/filesys.h"
24 #include "canaccess.h"
28 * Useful definitions
30 #ifdef _WINDOWS
32 #define ACCESS_IN_CWD(F,M) (can_access((F), (M)))
33 #define PATH_SEP ';'
34 #define FILE_SEP '\\'
36 #else /* UNIX */
38 #define ACCESS_IN_CWD(F,M) (-1)
39 #define PATH_SEP ':'
40 #define FILE_SEP '/'
42 #endif /* UNIX */
47 * Check if we can access a file in a given way
49 * Args: file -- The file to check
50 * mode -- The mode ala the access() system call, see ACCESS_EXISTS
51 * and friends in alpine.h.
53 * Result: returns 0 if the user can access the file according to the mode,
54 * -1 if he can't (and errno is set).
58 int
59 can_access(char *file, int mode)
61 #ifdef _WINDOWS
62 struct stat buf;
65 * NOTE: The WinNT access call returns that every directory is readable and
66 * writable. We actually want to know if the write is going to fail, so we
67 * try it. We don't read directories in Windows so we skip implementing that.
69 if(mode & WRITE_ACCESS && file && !our_stat(file, &buf) && (buf.st_mode & S_IFMT) == S_IFDIR){
70 char *testname;
71 int fd;
72 size_t l = 0;
75 * We'd like to just call temp_nam here, since it creates a file
76 * and does what we want. However, temp_nam calls us!
78 if((testname = malloc(MAXPATH * sizeof(char)))){
79 strncpy(testname, file, MAXPATH-1);
80 testname[MAXPATH-1] = '\0';
81 if(testname[0] && testname[(l=strlen(testname))-1] != '\\' &&
82 l+1 < MAXPATH){
83 l++;
84 strncat(testname, "\\", MAXPATH-strlen(testname)-1);
85 testname[MAXPATH-1] = '\0';
88 if(l+8 < MAXPATH &&
89 strncat(testname, "caXXXXXX", MAXPATH-strlen(testname)-1) && mktemp(testname)){
90 if((fd = our_open(testname, O_CREAT|O_EXCL|O_WRONLY|O_BINARY, 0600)) >= 0){
91 (void)close(fd);
92 our_unlink(testname);
93 free(testname);
94 /* success, drop through to access call */
96 else{
97 free(testname);
98 /* can't write in the directory */
99 return(-1);
102 else{
103 free(testname);
104 return(-1);
108 if(mode & EXECUTE_ACCESS) /* Windows access has no execute mode */
109 mode &= ~EXECUTE_ACCESS; /* and crashes because of it */
110 #endif /* WINDOWS */
112 return(our_access(file, mode));
116 /*----------------------------------------------------------------------
117 Check if we can access a file in a given way in the given path
119 Args: path -- The path to look for "file" in
120 file -- The file to check
121 mode -- The mode ala the access() system call, see ACCESS_EXISTS
122 and friends in alpine.h.
124 Result: returns 0 if the user can access the file according to the mode,
125 -1 if he can't (and errno is set).
126 ----*/
128 can_access_in_path(char *path, char *file, int mode)
130 char tmp[MAXPATH];
131 int rv = -1;
133 if(!path || !*path || is_rooted_path(file)){
134 rv = can_access(file, mode);
136 else if(is_homedir_path(file)){
137 strncpy(tmp, file, sizeof(tmp));
138 tmp[sizeof(tmp)-1] = '\0';
139 rv = fnexpand(tmp, sizeof(tmp)) ? can_access(tmp, mode) : -1;
141 else if((rv = ACCESS_IN_CWD(file,mode)) < 0){
142 char path_copy[MAXPATH + 1], *p, *t;
144 if(strlen(path) < MAXPATH){
145 strncpy(path_copy, path, sizeof(path_copy));
146 path_copy[sizeof(path_copy)-1] = '\0';
148 for(p = path_copy; p && *p; p = t){
149 if((t = strchr(p, PATH_SEP)) != NULL)
150 *t++ = '\0';
152 snprintf(tmp, sizeof(tmp), "%s%c%s", p, FILE_SEP, file);
153 if((rv = can_access(tmp, mode)) == 0)
154 break;
159 return(rv);