another update from CVS HEAD, for QA
[alioth/jupp.git] / path.c
1 /*
2  *      Directory and path functions
3  *      Copyright
4  *              (C) 1992 Joseph H. Allen
5  *
6  *      This file is part of JOE (Joe's Own Editor)
7  */
8 #include "config.h"
9 #include "types.h"
10
11 __RCSID("$MirOS: contrib/code/jupp/path.c,v 1.18 2017/12/08 02:28:05 tg Exp $");
12
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #include <unistd.h>
17 #ifdef HAVE_PATHS_H
18 #  include <paths.h>    /* for _PATH_TMP */
19 #endif
20 #include <limits.h>
21 #include <stdlib.h>
22
23 #ifdef HAVE_BSD_STRING_H
24 #include <bsd/string.h>
25 #endif
26
27 #include "path.h"
28 #include "vs.h"
29 #include "va.h"
30
31 #ifdef TIME_WITH_SYS_TIME
32 # include <sys/time.h>
33 # include <time.h>
34 #else
35 # ifdef HAVE_SYS_TIME_H
36 #  include <sys/time.h>
37 # else
38 #  include <time.h>
39 # endif
40 #endif
41
42 #ifdef HAVE_DIRENT_H
43 #  include <dirent.h>
44 #  define NAMLEN(dirent) strlen((dirent)->d_name)
45 #else
46 #  ifdef HAVE_SYS_DIRENT_H
47 #    include <sys/dirent.h>
48 #    define NAMLEN(dirent) strlen((dirent)->d_name)
49 #  else
50 #    define direct dirent
51 #    define NAMLEN(dirent) (dirent)->d_namlen
52 #    ifdef HAVE_SYS_NDIR_H
53 #      include <sys/ndir.h>
54 #    else
55 #      ifdef HAVE_SYS_DIR_H
56 #        include <sys/dir.h>
57 #      else
58 #        ifdef HAVE_NDIR_H
59 #          include <ndir.h>
60 #        else
61 #          ifndef __MSDOS__
62 #            include "dir.c"
63 #          endif
64 #        endif
65 #      endif
66 #    endif
67 #  endif
68 #endif
69
70 #if HAVE_DRIVE_LETTERS
71 #define do_if_drive_letter(path, command) do {          \
72         if ((path)[1] == ':' && (                       \
73             ((path)[0] >= 'a' && (path)[0] <= 'z') ||   \
74             ((path)[0] >= 'A' && (path)[0] <= 'Z'))) {  \
75                 command;                                \
76         }                                               \
77 } while (/* CONSTCOND */ 0)
78 #else
79 #define do_if_drive_letter(path, command) do { } while (/* CONSTCOND */ 0)
80 #endif
81 #define skip_drive_letter(path) do_if_drive_letter((path), (path) += 2)
82
83 #ifndef _PATH_TMP
84 #define _PATH_TMP       "/tmp/"
85 #endif
86
87 #if !defined(PATH_MAX) && !defined(HAVE_GET_CURRENT_DIR_NAME)
88 #warning What should we include to have PATH_MAX defined?
89 #define PATH_MAX        4096
90 #endif
91
92 /********************************************************************/
93 #if HAVE_BACKSLASH_PATHS
94 unsigned char *joesep(unsigned char *path)
95 {
96         int x;
97
98         for (x = 0; path[x]; ++x)
99                 if (path[x] == '\\')
100                         path[x] = '/';
101         return path;
102 }
103 #endif
104 /********************************************************************/
105 unsigned char *namprt(unsigned char *path)
106 {
107         unsigned char *z;
108
109         skip_drive_letter(path);
110         z = path + slen(path);
111         while ((z != path) && (z[-1] != '/'))
112                 --z;
113         return vsncpy(NULL, 0, sz(z));
114 }
115 /********************************************************************/
116 unsigned char *namepart(unsigned char *tmp, unsigned char *path)
117 {
118         unsigned char *z;
119
120         skip_drive_letter(path);
121         z = path + strlen((char *)path);
122         while ((z != path) && (z[-1] != '/'))
123                 --z;
124         strlcpy((char *)tmp, (char *)z, 1024);
125         return (tmp);
126 }
127 /********************************************************************/
128 unsigned char *dirprt_ptr(unsigned char *path)
129 {
130         unsigned char *b = path;
131         unsigned char *z = path + slen(path);
132
133         skip_drive_letter(b);
134         while ((z != b) && (z[-1] != '/'))
135                 --z;
136         return (z);
137 }
138 unsigned char *dirprt(unsigned char *path)
139 {
140         return vsncpy(NULL, 0, path, dirprt_ptr(path) - path);
141 }
142 /********************************************************************/
143 unsigned char *begprt(unsigned char *path)
144 {
145         unsigned char *z = path + slen(path);
146         int drv = 0;
147
148         do_if_drive_letter(path, drv = 2);
149         while ((z != path + drv) && (z[-1] == '/'))
150                 --z;
151         if (z == path + drv)
152                 return vsncpy(NULL, 0, sz(path));
153         else {
154                 while ((z != path + drv) && (z[-1] != '/'))
155                         --z;
156                 return vsncpy(NULL, 0, path, z - path);
157         }
158 }
159 /********************************************************************/
160 unsigned char *endprt(unsigned char *path)
161 {
162         unsigned char *z = path + slen(path);
163         int drv = 0;
164
165         do_if_drive_letter(path, drv = 2);
166         while ((z != path + drv) && (z[-1] == '/'))
167                 --z;
168         if (z == path + drv)
169                 return vsncpy(NULL, 0, sc(""));
170         else {
171                 while (z != path + drv && z[-1] != '/')
172                         --z;
173                 return vsncpy(NULL, 0, sz(z));
174         }
175 }
176 /********************************************************************/
177 int mkpath(unsigned char *path)
178 {
179         unsigned char *s;
180
181         if (path[0] == '/') {
182                 if (chddir("/"))
183                         return 1;
184                 s = path;
185                 goto in;
186         }
187
188         while (path[0]) {
189                 int c;
190
191                 for (s = path; (*s) && (*s != '/'); s++) ;
192                 c = *s;
193                 *s = 0;
194                 if (chddir((char *)path)) {
195                         if (mkdir((char *)path, 0777))
196                                 return 1;
197                         if (chddir((char *)path))
198                                 return 1;
199                 }
200                 *s = c;
201  in:
202                 while (*s == '/')
203                         ++s;
204                 path = s;
205         }
206         return 0;
207 }
208 /********************************************************************/
209 /* Create a temporary file */
210 /********************************************************************/
211 unsigned char *mktmp(unsigned char *where, int *fdp)
212 {
213 #ifndef HAVE_MKSTEMP
214         static unsigned seq = 0;
215 #endif
216         unsigned char *name;
217         int fd;
218         unsigned namesize;
219
220         if (!where)
221                 where = (unsigned char *)getenv("TMPDIR");
222         if (!where)
223                 where = (unsigned char *)getenv("TEMP");
224         if (!where)
225                 where = US _PATH_TMP;
226
227         namesize = strlen((char *)where) + 20;
228         name = vsmk(namesize);  /* [G.Ghibo'] we need to use vsmk() and not malloc() as
229                                    area returned by mktmp() is destroyed later with
230                                    vsrm(); */
231 #ifdef HAVE_MKSTEMP
232         joe_snprintf_1((char *)name, namesize, "%s/joe.tmp.XXXXXXXXXX", where);
233         if ((fd = mkstemp((char *)name)) == -1)
234                 return (NULL);  /* FIXME: vflsh() and vflshf() */
235                                 /* expect mktmp() always succeed!!! */
236         fchmod(fd, 0600);       /* Linux glibc 2.0 mkstemp() creates it with */
237                                 /* 0666 mode --> change it to 0600, so nobody */
238                                 /* else sees content of temporary file */
239 #else
240 #warning "Waah, this is insane! Consider getting mkstemp!"
241  loop:
242         seq = (seq + 1) % 10000;
243         joe_snprintf_3(name, namesize, "%s/joe.tmp.%04u%05u", where, seq,
244             (unsigned)(time(NULL) % 100000));
245         if ((fd = open(name, O_RDONLY)) != -1) {
246                 close(fd);
247                 goto loop;      /* FIXME: possible endless loop --> DoS attack */
248         }
249         if ((fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600)) == -1)
250                 return (NULL);  /* FIXME: see above */
251 #endif
252         if (fdp)
253                 *fdp = fd;
254         else
255                 close(fd);
256         return (name);
257 }
258 /********************************************************************/
259 int rmatch(unsigned char *a, unsigned char *b)
260 {
261         int flag, inv, c;
262
263         for (;;)
264                 switch (*a) {
265                 case '*':
266                         ++a;
267                         do {
268                                 if (rmatch(a, b))
269                                         return 1;
270                         } while (*b++);
271                         return 0;
272                 case '[':
273                         ++a;
274                         flag = 0;
275                         if (*a == '^') {
276                                 ++a;
277                                 inv = 1;
278                         } else
279                                 inv = 0;
280                         if (*a == ']')
281                                 if (*b == *a++)
282                                         flag = 1;
283                         while (*a && (c = *a++) != ']')
284                                 if ((c == '-') && (a[-2] != '[') && (*a)) {
285                                         if ((*b >= a[-2]) && (*b <= *a))
286                                                 flag = 1;
287                                 } else if (*b == c)
288                                         flag = 1;
289                         if ((!flag && !inv) || (flag && inv) || (!*b))
290                                 return 0;
291                         ++b;
292                         break;
293                 case '?':
294                         ++a;
295                         if (!*b)
296                                 return 0;
297                         ++b;
298                         break;
299                 case 0:
300                         if (!*b)
301                                 return 1;
302                         else
303                                 return 0;
304                 default:
305                         if (*a++ != *b++)
306                                 return 0;
307                 }
308 }
309 /********************************************************************/
310 int isreg(unsigned char *s)
311 {
312         int x;
313
314         for (x = 0; s[x]; ++x)
315                 if ((s[x] == '*') || (s[x] == '?') || (s[x] == '['))
316                         return 1;
317         return 0;
318 }
319 /********************************************************************/
320 unsigned char **rexpnd(unsigned char *word)
321 {
322         void *dir;
323         unsigned char **lst = NULL;
324
325         struct dirent *de;
326         dir = opendir(".");
327         if (dir) {
328                 while ((de = readdir(dir)) != NULL)
329                         if (strcmp(".", de->d_name))
330                                 if (rmatch(word, (unsigned char *)de->d_name))
331                                         lst = vaadd(lst, vsncpy(NULL, 0, sz((unsigned char *)de->d_name)));
332                 closedir(dir);
333         }
334         return lst;
335 }
336 /********************************************************************/
337 int chJpwd(const unsigned char *path)
338 {
339         unsigned char *fullpath;
340         int rv;
341
342         if (!has_JOERC)
343                 return (-1);
344         fullpath = vsncpy(NULL, 0, sz(get_JOERC));
345         fullpath = vsncpy(sv(fullpath), sz(path));
346         rv = chpwd(fullpath);
347         vsrm(fullpath);
348         return (rv);
349 }
350
351 int chpwd(const unsigned char *path)
352 {
353         if ((!path) || (!path[0]))
354                 return 0;
355         return chdir((char *)path);
356 }
357
358 /* The pwd function */
359 unsigned char *pwd(void)
360 {
361 #if defined(PATH_MAX) || !defined(HAVE_GET_CURRENT_DIR_NAME)
362         static unsigned char buf[PATH_MAX];
363         unsigned char   *ret;
364
365 #ifdef HAVE_GETCWD
366         ret = (unsigned char *)getcwd((char *)buf, PATH_MAX - 1);
367 #else
368         ret = (unsigned char *)getwd((char *)buf);
369 #endif
370         buf[PATH_MAX - 1] = '\0';
371
372         return ret;
373 #else
374         /* Hurd */
375         static char *wd = NULL;
376
377         free(wd);
378         wd = get_current_dir_name();
379         return ((void *)wd);
380 #endif
381 }
382
383 #if JUPP_WIN32RELOC
384 unsigned char has_JOERC = 0;
385 unsigned char *get_JOERC = NULL;
386
387 extern char *cygwin32_argv0(void);
388
389 void init_JOERC(void)
390 {
391         struct stat sb;
392         char *sep;
393
394         if ((get_JOERC = (unsigned char *)cygwin32_argv0()) == NULL)
395                 return;
396         joesep(get_JOERC);
397         if ((sep = strrchr((char *)get_JOERC, '/')) == NULL)
398                 return;
399         if (stat(get_JOERC, &sb))
400                 return;
401         sep[1] = '\0';
402         has_JOERC = 1;
403 }
404 #endif