/* * Directory and path functions * Copyright * (C) 1992 Joseph H. Allen * * This file is part of JOE (Joe's Own Editor) */ #include "types.h" #ifdef HAVE_PWD_H #include #endif #ifdef HAVE_PATHS_H # include /* for _PATH_TMP */ #endif #ifdef HAVE_LIMITS_H #include #endif #ifdef HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else # ifdef HAVE_SYS_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) # else # define direct dirent # define NAMLEN(dirent) (dirent)->d_namlen # ifdef HAVE_SYS_NDIR_H # include # else # ifdef HAVE_SYS_DIR_H # include # else # ifdef HAVE_NDIR_H # include # else # ifndef __MSDOS__ # include "dir.c" # endif # endif # endif # endif # endif #endif #ifdef __MSDOS__ /* paths in MS-DOS can include a drive letter followed by semicolon */ #define do_if_drive_letter(path, command) do { \ if ((path)[0] && (path)[1] == ':') { \ command; \ } \ } while(0) #else #define do_if_drive_letter(path, command) do { } while(0) #endif #define skip_drive_letter(path) do_if_drive_letter((path), (path) += 2) #ifndef _PATH_TMP # ifdef __MSDOS__ # define _PATH_TMP "" # else # define _PATH_TMP "/tmp/" # endif #endif #ifndef PATH_MAX /* #warning is gcc extension #warning What should we include to have PATH_MAX defined? */ #define PATH_MAX 4096 #endif /********************************************************************/ unsigned char *joesep(unsigned char *path) { #ifdef __MSDOS__ int x; for (x = 0; path[x]; ++x) if (path[x] == '\\') path[x] = '/'; #endif return path; } /********************************************************************/ unsigned char *namprt(unsigned char *path) { unsigned char *z; skip_drive_letter(path); z = path + slen(path); while ((z != path) && (z[-1] != '/')) --z; return vsncpy(NULL, 0, sz(z)); } /********************************************************************/ unsigned char *namepart(unsigned char *tmp, unsigned char *path) { unsigned char *z; skip_drive_letter(path); z = path + zlen(path); while ((z != path) && (z[-1] != '/')) --z; return zcpy(tmp, z); } /********************************************************************/ unsigned char *dirprt(unsigned char *path) { unsigned char *b = path; unsigned char *z = path + slen(path); skip_drive_letter(b); while ((z != b) && (z[-1] != '/')) --z; return vsncpy(NULL, 0, path, z - path); } /********************************************************************/ unsigned char *begprt(unsigned char *path) { unsigned char *z = path + slen(path); int drv = 0; do_if_drive_letter(path, drv = 2); while ((z != path + drv) && (z[-1] == '/')) --z; if (z == path + drv) return vsncpy(NULL, 0, sz(path)); else { while ((z != path + drv) && (z[-1] != '/')) --z; return vsncpy(NULL, 0, path, z - path); } } /********************************************************************/ unsigned char *endprt(unsigned char *path) { unsigned char *z = path + slen(path); int drv = 0; do_if_drive_letter(path, drv = 2); while ((z != path + drv) && (z[-1] == '/')) --z; if (z == path + drv) return vsncpy(NULL, 0, sc("")); else { while (z != path + drv && z[-1] != '/') --z; return vsncpy(NULL, 0, sz(z)); } } /********************************************************************/ int mkpath(unsigned char *path) { unsigned char *s; if (path[0] == '/') { if (chddir("/")) return 1; s = path; goto in; } while (path[0]) { int c; for (s = path; (*s) && (*s != '/'); s++) ; c = *s; *s = 0; if (chddir((char *)path)) { if (mkdir((char *)path, 0777)) return 1; if (chddir((char *)path)) return 1; } *s = c; in: while (*s == '/') ++s; path = s; } return 0; } /********************************************************************/ /* Create a temporary file */ /********************************************************************/ unsigned char *mktmp(unsigned char *where) { #ifndef HAVE_MKSTEMP static unsigned seq = 0; #endif unsigned char *name; int fd; unsigned namesize; if (!where) where = (unsigned char *)getenv("TEMP"); if (!where) where = USTR _PATH_TMP; namesize = zlen(where) + 16; name = vsmk(namesize); /* [G.Ghibo'] we need to use vsmk() and not malloc() as area returned by mktmp() is destroyed later with vsrm(); */ #ifdef HAVE_MKSTEMP joe_snprintf_1(name, namesize, "%s/joe.tmp.XXXXXX", where); if((fd = mkstemp((char *)name)) == -1) return NULL; /* FIXME: vflsh() and vflshf() */ /* expect mktmp() always succeed!!! */ fchmod(fd, 0600); /* Linux glibc 2.0 mkstemp() creates it with */ /* 0666 mode --> change it to 0600, so nobody */ /* else sees content of temporary file */ close(fd); #else loop: seq = (seq + 1) % 1000; joe_snprintf_3(name, namesize, "%s/joe.tmp.%03u%03u", where, seq, (unsigned) time(NULL) % 1000); if ((fd = open(name, O_RDONLY)) != -1) { close(fd); goto loop; /* FIXME: possible endless loop --> DoS attack */ } if ((fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600)) == -1) return NULL; /* FIXME: see above */ else close(fd); #endif return name; } /********************************************************************/ int rmatch(unsigned char *a, unsigned char *b) { int flag, inv, c; for (;;) switch (*a) { case '*': ++a; do { if (rmatch(a, b)) return 1; } while (*b++); return 0; case '[': ++a; flag = 0; if (*a == '^') { ++a; inv = 1; } else inv = 0; if (*a == ']') if (*b == *a++) flag = 1; while (*a && (c = *a++) != ']') if ((c == '-') && (a[-2] != '[') && (*a)) { if ((*b >= a[-2]) && (*b <= *a)) flag = 1; } else if (*b == c) flag = 1; if ((!flag && !inv) || (flag && inv) || (!*b)) return 0; ++b; break; case '?': ++a; if (!*b) return 0; ++b; break; case 0: if (!*b) return 1; else return 0; default: if (*a++ != *b++) return 0; } } /********************************************************************/ int isreg(unsigned char *s) { int x; for (x = 0; s[x]; ++x) if ((s[x] == '*') || (s[x] == '?') || (s[x] == '[')) return 1; return 0; } /********************************************************************/ #ifdef __MSDOS__ #include #include struct direct { unsigned char d_name[16]; } direc; int dirstate = 0; struct ffblk ffblk; unsigned char *dirpath = NULL; void *opendir(unsigned char *path) { dirstate = 0; return &direc; } void closedir() { } struct direct *readdir() { int x; if (dirstate) { if (findnext(&ffblk)) return NULL; } else { if (findfirst("*.*", &ffblk, FA_DIREC)) return NULL; dirstate = 1; } zcpy(direc.d_name, ffblk.ff_name); for (x = 0; direc.d_name[x]; ++x) direc.d_name[x] = tolower(direc.d_name[x]); return &direc; } #endif /********************************************************************/ unsigned char **rexpnd(unsigned char *word) { void *dir; unsigned char **lst = NULL; struct dirent *de; dir = opendir("."); if (dir) { while ((de = readdir(dir)) != NULL) if (strcmp(".", de->d_name)) if (rmatch(word, (unsigned char *)de->d_name)) lst = vaadd(lst, vsncpy(NULL, 0, sz((unsigned char *)de->d_name))); closedir(dir); } return lst; } /********************************************************************/ unsigned char **rexpnd_users(unsigned char *word) { unsigned char **lst = NULL; struct passwd *pw; while((pw=getpwent())) if (rmatch(word+1, (unsigned char *)pw->pw_name)) { unsigned char *t = vsncpy(NULL,0,sc("~")); lst = vaadd(lst, vsncpy(sv(t),sz((unsigned char *)pw->pw_name))); } endpwent(); return lst; } /********************************************************************/ int chpwd(unsigned char *path) { #ifdef __MSDOS__ unsigned char buf[256]; int x; if (!path) return 0; if ((path[0]) && (path[1] == ':')) { if (_chdrive(path[0] & 0x1F)) return -1; path += 2; } if (!path[0]) return 0; zcpy(buf, path); x = zlen(buf); while (x > 1) { --x; if ((buf[x] == '/') || (buf[x] == '\\')) buf[x] = 0; else break; } return chdir(buf); #else if ((!path) || (!path[0])) return 0; return chdir((char *)path); #endif } /* The pwd function */ unsigned char *pwd(void) { static unsigned char buf[PATH_MAX]; unsigned char *ret; #ifdef HAVE_GETCWD ret = (unsigned char *)getcwd((char *)buf, PATH_MAX - 1); #else ret = (unsigned char *)getwd((char *)buf); #endif buf[PATH_MAX - 1] = '\0'; return ret; } /* Simplify prefix by using ~ */ /* Expects s to have trailing / */ unsigned char *simplify_prefix(unsigned char *s) { unsigned char *t = (unsigned char *)getenv("HOME"); unsigned char *n; #ifdef junk unsigned char *org = pwd(); /* Normalize home */ if (t && !chpwd(t)) { t = pwd(); } else { t = 0; } chpwd(org); #endif /* If current directory is prefixed with home directory, use ~... */ if (t && !strncmp((char *)s,(char *)t,zlen(t)) && (!s[zlen(t)] || s[zlen(t)]=='/')) { n = vsncpy(NULL,0,sc("~/")); /* If anything more than just the home directory, add it */ if (s[zlen(t)]) { n = vsncpy(sv(n),s+zlen(t)+1,zlen(s+zlen(t)+1)); } } else { n = vsncpy(NULL,0,sz(s)); } return n; }