/* POSIX compatible directory access routines for TOS */ /* written by Eric R. Smith and placed in the public domain */ #include #include #include #include #include #include #include #include #include #include #include #include "lib.h" #include "symdir.h" #ifndef _COMPILER_H #include #endif static char *shadowed __PROTO((const char *name, SYMDIR *dir)); ino_t __inode; /* in stat.c */ DIR *__opendir_chain; /* ditto */ static char *shadowed(name, dir) const char *name; SYMDIR *dir; { SYMENTRY *ent; if (!dir) return (char *)0; ent = dir->s_dir; while (ent) { if (!strcmp(name, ent->linkto) && (ent->flags & SD_AUTO)) return ent->linkname; ent = ent->next; } return (char *)0; } DIR *opendir(_dirname) const char *_dirname; { char dirname[FILENAME_MAX]; char tmpnam[_LIB_NAME_MAX]; char *t; DIR *dd; struct dirent *d, *x, **last; SYMENTRY *lent; SYMDIR *ldir; long r; short i = 0; struct _dta mydta, *olddta; _unx2dos(_dirname, dirname); #if 0 /* we should maybe check to see if we're opening a directory */ /* this code doesn't work, though -- Fattrib is dumb */ if (dirname[0] && (dirname[1] == ':') && !dirname[2]) { /* nothing to do */ } else { r = Fattrib(dirname, 0, FA_DIR|FA_HIDDEN|FA_SYSTEM); if (r < 0) { errno = -r; return NULL; } else if (!(r & FA_DIR)) { errno = EPATH; return NULL; } } #endif if (!(dd = malloc((size_t)sizeof(DIR)))) { errno = ENOMEM; return NULL; } olddta = (struct _dta *)Fgetdta(); Fsetdta(&mydta); d = x = NULL; last = &d; dd->D_path = strdup(dirname); /* check for symbolic links in the directory */ ldir = _read_symdir(dirname); if (!ldir) goto skip_symlinks; lent = ldir->s_dir; while (lent) { x = malloc((size_t)(DIRENTSIZ(strlen(lent->linkname)))); if (!x) { errno = ENOMEM; free(dd->D_path); free(dd); while(d) { x = d->d_next; free(d); d = x; } _free_symdir(ldir); Fsetdta(olddta); /* reset dta ++jrb */ return NULL; } strcpy(x->d_name, lent->linkname); x->d_reclen = x->d_size = strlen(x->d_name); x->d_ino = ++__inode; x->d_off = i++; x->d_next = NULL; x->d_date = x->d_time = 0; x->d_attribute = 0xff; /* mark symbolic link */ *last = x; last = &x->d_next; lent = lent->next; } /* OK, so much for the symbolic links. Now for the real directories */ skip_symlinks: strcat(dirname, "\\*.*"); if ((r = Fsfirst(dirname, FA_SYSTEM|FA_HIDDEN|FA_DIR)) != 0) { /* report an error unless dirname is a root directory */ /* (all other valid directories have '.' and '..' in them */ if (!*dirname || strcmp(dirname+1, "\\*.*")) { errno = -r; while (d) { x = d->d_next; free(d); d = x; } free(dd->D_path); free(dd); dd = NULL; } } else { /* Fsfirst worked OK */ do { _dos2unx(mydta.dta_name, tmpnam); /* skip the symbolic directory itself if we're supposed to */ if (_lHIDE && _lOK && !strcmp(_lDIR, tmpnam)) continue; /* check for files being hidden by auto symlinks */ if (_lAUTO && (t = shadowed(tmpnam, ldir))) { for (x = d; x; x = x->d_next) if (!strcmp(x->d_name, t)) break; assert(x != 0); /* put the real file's info in the structure */ goto tos_fill; } x = malloc((size_t)(DIRENTSIZ(strlen(tmpnam)))); if (!x) { errno = ENOMEM; while (d) { x = d->d_next; free(d); d = x; } free(dd->D_path); free(dd); dd = NULL; break; } strcpy(x->d_name, tmpnam); x->d_ino = ++__inode; /* make sure no two are equal */ x->d_off = i++; /* I don't know what d_reclen means on Unix, but for TOS we might as well stuff the string length in here (so sys/dir.h can be more like BSD) */ x->d_reclen = strlen(x->d_name); x->d_next = NULL; *last = x; last = &x->d_next; tos_fill: /* fill in TOS specific stuff so stat can find it later */ x->d_time = mydta.dta_time; x->d_date = mydta.dta_date; x->d_attribute = mydta.dta_attribute; x->d_size = mydta.dta_size; } while (!Fsnext()); } Fsetdta(olddta); if (dd) { dd->D_list = dd->D_curpos = d; dd->D_nxtdir = __opendir_chain; __opendir_chain = dd; } _free_symdir(ldir); return dd; } struct dirent *readdir(dirp) DIR *dirp; { struct dirent *x; if (!dirp) return NULL; x = dirp->D_curpos; if (x) dirp->D_curpos = x->d_next; return x; } off_t telldir(dirp) DIR *dirp; { struct dirent *x = dirp->D_curpos; if (x) return x->d_off; else return -1; } void seekdir(dirp, loc) DIR *dirp; off_t loc; { struct dirent *x; x = dirp->D_list; while (x && x->d_off != loc) x = x->d_next; dirp->D_curpos = x; } void rewinddir(dirp) DIR *dirp; { dirp->D_curpos = dirp->D_list; } int closedir(dirp) DIR *dirp; { struct dirent *x, *oldx; DIR **old, *nxt; if (!dirp) return -1; if (dirp->D_path) free(dirp->D_path); for (x = dirp->D_list; x; ) { oldx = x; x = x->d_next; free(oldx); } /* unlink from __opendir_chain */ old = &__opendir_chain; nxt = *old; while (nxt) { if (nxt == dirp) { *old = nxt->D_nxtdir; nxt->D_nxtdir = 0; break; } old = &nxt->D_nxtdir; nxt = *old; } free(dirp); return 0; }