1 /*
2 Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9     - Redistributions of source code must retain the above copyright
10       notice, this list of conditions and the following disclaimer.
11 
12     - Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in
14       the documentation and/or other materials provided with the
15       distribution.
16 
17     - Neither the name of The Numerical ALgorithms Group Ltd. nor the
18       names of its contributors may be used to endorse or promote products
19       derived from this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <limits.h>
41 #include "fricas_c_macros.h"
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 
45 #include "cfuns-c.H1"
46 
47 /* Most versions of Windows don't have the POSIX functions getuid(),
48    geteuid(), getgid(), and getegid().  The following definitions are
49    approximations, to patch for the deficiencies of Windows
50    POSIX interface.  */
51 
52 #if !HAVE_DECL_GETUID
53 #  define getuid() 0
54 #endif
55 
56 #if !HAVE_DECL_GETGID
57 #  define getgid() 0
58 #endif
59 
60 #if !HAVE_DECL_GETEUID
61 #  define geteuid() getuid()
62 #endif
63 
64 #if !HAVE_DECL_GETEGID
65 #  define getegid() getgid()
66 #endif
67 
68 int
addtopath(char * dir)69 addtopath(char *dir)
70 {
71     char *path, *newpath;
72 
73     path = getenv("PATH");
74     if (path == NULL)
75         return -1;
76 
77     newpath = (char *) malloc(1 + strlen(path) + strlen(dir) + strlen("PATH=:"));
78     if (newpath == NULL)
79         return -1;
80 
81     sprintf(newpath, "PATH=%s;%s", path, dir); /* MSYS/MinGW ??? */
82 
83     return putenv(newpath);
84 }
85 
86 /*
87  * Test whether the path is the name of a directory.  Returns 1 if so, 0 if
88  * not, -1 if it doesn't exist.
89  */
90 
91 
92 int
directoryp(char * path)93 directoryp(char *path)
94 {
95     struct stat buf;
96     int code;
97 
98     code = stat(path, &buf);
99     if (code == -1) {
100         return (-1);
101     }
102     else {
103         return ((buf.st_mode & S_IFDIR) != 0);
104     }
105 }
106 
107 
108 /* Make a directory returning 0 for success and -1 for failure */
109 
110 int
makedir(char * path)111 makedir(char *path)
112 {
113 #ifdef HAVE_TWO_ARG_MKDIR
114    return ( mkdir (path,(S_IRWXU | S_IRWXO | S_IRWXG)) );
115 #else
116    return ( mkdir (path) );
117 #endif
118 }
119 
120 int
make_path_from_file(char * s,char * t)121 make_path_from_file(char *s, char *t)
122 {
123     char *pos = NULL;
124     char *c;
125 
126     /** simply copies the path name from t into s **/
127     for (c = t + strlen(t); c != t; c--)
128         if ( ( *c == '/' ) || ( *c == '\\' ) ) {
129             pos = c;
130             break;
131         }
132     /** Check to see if the path was actually present **/
133     if (c == t) {               /** No Path, so return the pwd **/
134         return (-1);
135     }
136     /** now just do the copying **/
137     strncpy(s, t, pos - t);
138     return 1;
139 }
140 
141 /* The functions writeablep() and readablep() determine write and
142    read access of a file designated by its name.
143 
144    The access is determined based on the POSIX semantics; see
145    "Advanced Programming in the UNIX Environement", section 4.5.
146 
147    1. If the effective user ID of the process is 0 (the superuser),
148       access is allowed.  This gives the superuser free rein throughout
149       the entire file system.
150 
151    2. If the effective user ID of the process equals the owner ID of
152       the file (i.e., the process owns the file), access is allowed
153       if the appropriate user access permission bit is set. [...]
154 
155    3. If the effective group ID of the process or one of the
156       supplementary group IDs of the process equals the group ID
157       of the file, access is allowed if the appropriate
158       group access permission bit is set.  Otherwise, permission
159       is denied.
160 
161    4. If the appropriate other access permission bit is set, access is
162       allowed.  Otherwise, permission is defined.   */
163 
164 /* Return
165      -1 if the file designated by PATH is inexistent.
166       0 if the file exists but wirte access is denied.
167       1 if the file exists and process has write access.
168       2 if the file does not exists but process has write
169         has write access to the dirname of path.  */
170 
171 int
writeablep(char * path)172 writeablep(char *path)
173 {
174     struct stat buf;
175     char newpath[100];
176     int code;
177 
178     code = stat(path, &buf);
179     if (code == -1) {
180         /** The file does not exist, so check to see
181                  if the directory is writable                  *****/
182         if (make_path_from_file(newpath, path) == -1 ||
183             stat(newpath, &buf) == -1) {
184             return (-1);
185         }
186     }
187     else if (geteuid() == buf.st_uid) {
188         return ((buf.st_mode & S_IWUSR) != 0);
189 #ifdef S_IWGRP
190     }
191     else if (getegid() == buf.st_gid) {
192         return ((buf.st_mode & S_IWGRP) != 0);
193 #endif
194 #ifdef S_IWOTH
195     }
196     else {
197         return ((buf.st_mode & S_IWOTH) != 0);
198 #endif
199     };
200     return ( 1 ); /* MSYS/MinGW */
201 }
202 
203 
204 int
readablep(char * path)205 readablep(char *path)
206 {
207     struct stat buf;
208     int code;
209 
210     code = stat(path, &buf);
211     if (code == -1) {
212         return (-1);
213     }
214     else if (geteuid() == buf.st_uid) {
215         return ((buf.st_mode & S_IREAD) != 0);
216 #ifdef S_IRGRP
217     }
218     else if (getegid() == buf.st_gid) {
219         return ((buf.st_mode & S_IRGRP) != 0);
220 #endif
221 #ifdef S_IROTH
222     }
223     else {
224      return ((buf.st_mode & S_IROTH) != 0);
225 #endif
226     };
227     return ( 1 ); /* MSYS/MinGW */
228 }
229 
230 
231 long
findString(char * file,char * string)232 findString(char *file, char *string)
233 {
234     int nstring, charpos;
235     FILE *fn;
236     char buffer[1024];
237 
238     if ((fn = fopen(file, "r")) == NULL)
239         return -1;
240 
241     for (charpos = 0, nstring = strlen(string);
242          fgets(buffer, sizeof buffer, fn) != NULL;
243          charpos += strlen(buffer)
244         )
245         if (!strncmp(buffer, string, nstring))
246             return charpos;
247     return -1;
248 
249 }
250 
251 #ifdef HOST_HAS_DIRECTORY_OPERATIONS
252 
253 #include <dirent.h>
254 
fricas_copy_string(char * str)255 char * fricas_copy_string(char *str)
256 {
257     char * res = malloc(strlen(str) + 1);
258     if (res) {
259         strcpy(res, str);
260     } else {
261         fprintf(stderr, "Malloc failed (fricas_copy_string)\n");
262     }
263     return res;
264 }
265 
266 int
remove_directory(char * name)267 remove_directory(char * name)
268 {
269 #ifdef HOST_HAS_DIRFD_FCHDIR
270     DIR * cur_dir = opendir(".");
271     int cur_dir_fd;
272     int dir_fd;
273 #else
274     size_t name_len = strlen(name);
275 #endif
276     DIR * dir;
277     struct dirent * entry;
278     struct file_list {
279         struct file_list * next;
280         char * file;
281     };
282     struct file_list * flst = 0;
283 #ifdef HOST_HAS_DIRFD_FCHDIR
284     if (!cur_dir) {
285         fprintf(stderr, "Unable to open current directory\n");
286         return -1;
287     }
288 #else
289     if (name_len > INT_MAX/5) {
290         fprintf(stderr, "directory name too long\n");
291         return -1;
292     }
293 #endif
294     dir = opendir(name);
295     if (!dir) {
296         fprintf(stderr, "Unable to open directory to be removed\n");
297         goto err1;
298     }
299 #ifdef HOST_HAS_DIRFD_FCHDIR
300     cur_dir_fd = dirfd(cur_dir);
301     dir_fd = dirfd(dir);
302     if (cur_dir_fd == -1 || dir_fd == -1) {
303         fprintf(stderr, "dirfd failed\n");
304         goto err2;
305     }
306 #endif
307     while ((entry = readdir(dir))) {
308         char * fname = &(entry->d_name[0]);
309         if (strlen(fname) > INT_MAX/5) {
310             break;
311         }
312         if (!strcmp(fname, ".")) {
313             continue;
314         } else if (!strcmp(fname, "..")) {
315             continue;
316         } else {
317             struct file_list * npos = malloc(sizeof(*npos));
318             if (!npos) {
319                 fprintf(stderr, "Malloc failed (npos)\n");
320                 break;
321             }
322             npos->file = fricas_copy_string(fname);
323             if (!(npos->file)) {
324                 free(npos);
325                 break;
326             }
327             npos->next = flst;
328             flst = npos;
329         }
330     }
331 #ifdef HOST_HAS_DIRFD_FCHDIR
332     if (fchdir(dir_fd)) {
333         perror("Failed to change directory to directory to be removed");
334         while (flst) {
335             struct file_list * npos = flst->next;
336             free(flst->file);
337             free(flst);
338             flst = npos;
339         }
340         goto err2;
341     }
342 #endif
343     while (flst) {
344         struct file_list * npos = flst->next;
345 #ifdef HOST_HAS_DIRFD_FCHDIR
346        if (unlink(flst->file)) {
347             perror("Unlink failed");
348         }
349 #else
350         char pathbuf[PATH_MAX];
351         if (strlen(flst->file) + name_len + 1 < PATH_MAX) {
352             strcpy(pathbuf, name);
353             strcat(pathbuf, "/");
354             strcat(pathbuf, flst->file);
355             if (unlink(pathbuf)) {
356                 perror("Unlink failed");
357             }
358         } else {
359             fprintf(stderr, "panthname too long\n");
360         }
361 #endif
362         free(flst->file);
363         free(flst);
364         flst = npos;
365     }
366 #ifdef HOST_HAS_DIRFD_FCHDIR
367     if (fchdir(cur_dir_fd)) {
368         closedir(dir);
369         closedir(cur_dir);
370         return -1;
371     }
372   err2:
373 #endif
374     closedir(dir);
375   err1:
376 #ifdef HOST_HAS_DIRFD_FCHDIR
377     closedir(cur_dir);
378 #endif
379     {
380         int res = rmdir(name);
381         if (res) {
382             perror("rmdir failed");
383         }
384         return res;
385     }
386 }
387 
388 #endif
389