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