andre@3: #ifdef OS2 andre@3: andre@3: #include andre@3: #include andre@3: #include andre@3: #include andre@3: andre@3: #include andre@3: #include andre@3: andre@3: /*#ifndef __EMX__ andre@3: #include andre@3: #endif */ andre@3: andre@3: #define INCL_DOSFILEMGR andre@3: #define INCL_DOSERRORS andre@3: #include andre@3: andre@3: #if OS2 >= 2 andre@3: # define FFBUF FILEFINDBUF3 andre@3: # define Word ULONG andre@3: /* andre@3: * LS20 recommends a request count of 100, but according to the andre@3: * APAR text it does not lead to missing files, just to funny andre@3: * numbers of returned entries. andre@3: * andre@3: * LS30 HPFS386 requires a count greater than 2, or some files andre@3: * are missing (those starting with a character less that '.'). andre@3: * andre@3: * Novell loses entries which overflow the buffer. In previous andre@3: * versions of dirent2, this could have lead to missing files andre@3: * when the average length of 100 directory entries was 40 bytes andre@3: * or more (quite unlikely for files on a Novell server). andre@3: * andre@3: * Conclusion: Make sure that the entries all fit into the buffer andre@3: * and that the buffer is large enough for more than 2 entries andre@3: * (each entry is at most 300 bytes long). And ignore the LS20 andre@3: * effect. andre@3: */ andre@3: # define Count 25 andre@3: # define BufSz (25 * (sizeof(FILEFINDBUF3)+1)) andre@3: #else andre@3: # define FFBUF FILEFINDBUF andre@3: # define Word USHORT andre@3: # define BufSz 1024 andre@3: # define Count 3 andre@3: #endif andre@3: andre@3: #if defined(__IBMC__) || defined(__IBMCPP__) andre@3: #define error(rc) _doserrno = rc, errno = EOS2ERR andre@3: #elif defined(MICROSOFT) andre@3: #define error(rc) _doserrno = rc, errno = 255 andre@3: #else andre@3: #define error(rc) errno = 255 andre@3: #endif andre@3: andre@3: struct _dirdescr { andre@3: HDIR handle; /* DosFindFirst handle */ andre@3: char fstype; /* filesystem type */ andre@3: Word count; /* valid entries in */ andre@3: long number; /* absolute number of next entry */ andre@3: int index; /* relative number of next entry */ andre@3: FFBUF * next; /* pointer to next entry */ andre@3: char name[MAXPATHLEN+3]; /* directory name */ andre@3: unsigned attrmask; /* attribute mask for seekdir */ andre@3: struct dirent entry; /* buffer for directory entry */ andre@3: BYTE ffbuf[BufSz]; andre@3: }; andre@3: andre@3: /* andre@3: * Return first char of filesystem type, or 0 if unknown. andre@3: */ andre@3: static char andre@3: getFSType(const char *path) andre@3: { andre@3: static char cache[1+26]; andre@3: char drive[3], info[512]; andre@3: Word unit, infolen; andre@3: char r; andre@3: andre@3: if (isalpha(path[0]) && path[1] == ':') { andre@3: unit = toupper(path[0]) - '@'; andre@3: path += 2; andre@3: } else { andre@3: ULONG driveMap; andre@3: #if OS2 >= 2 andre@3: if (DosQueryCurrentDisk(&unit, &driveMap)) andre@3: #else andre@3: if (DosQCurDisk(&unit, &driveMap)) andre@3: #endif andre@3: return 0; andre@3: } andre@3: andre@3: if ((path[0] == '\\' || path[0] == '/') andre@3: && (path[1] == '\\' || path[1] == '/')) andre@3: return 0; andre@3: andre@3: if (cache [unit]) andre@3: return cache [unit]; andre@3: andre@3: drive[0] = '@' + unit; andre@3: drive[1] = ':'; andre@3: drive[2] = '\0'; andre@3: infolen = sizeof info; andre@3: #if OS2 >= 2 andre@3: if (DosQueryFSAttach(drive, 0, FSAIL_QUERYNAME, (PVOID)info, &infolen)) andre@3: return 0; andre@3: if (infolen >= sizeof(FSQBUFFER2)) { andre@3: FSQBUFFER2 *p = (FSQBUFFER2 *)info; andre@3: r = p->szFSDName[p->cbName]; andre@3: } else andre@3: #else andre@3: if (DosQFSAttach((PSZ)drive, 0, FSAIL_QUERYNAME, (PVOID)info, &infolen, 0)) andre@3: return 0; andre@3: if (infolen >= 9) { andre@3: char *p = info + sizeof(USHORT); andre@3: p += sizeof(USHORT) + *(USHORT *)p + 1 + sizeof(USHORT); andre@3: r = *p; andre@3: } else andre@3: #endif andre@3: r = 0; andre@3: return cache [unit] = r; andre@3: } andre@3: andre@3: char * andre@3: abs_path(const char *name, char *buffer, int len) andre@3: { andre@3: char buf[4]; andre@3: if (isalpha(name[0]) && name[1] == ':' && name[2] == '\0') { andre@3: buf[0] = name[0]; andre@3: buf[1] = name[1]; andre@3: buf[2] = '.'; andre@3: buf[3] = '\0'; andre@3: name = buf; andre@3: } andre@3: #if OS2 >= 2 andre@3: if (DosQueryPathInfo((PSZ)name, FIL_QUERYFULLNAME, buffer, len)) andre@3: #else andre@3: if (DosQPathInfo((PSZ)name, FIL_QUERYFULLNAME, (PBYTE)buffer, len, 0L)) andre@3: #endif andre@3: return NULL; andre@3: return buffer; andre@3: } andre@3: andre@3: DIR * andre@3: openxdir(const char *path, unsigned att_mask) andre@3: { andre@3: DIR *dir; andre@3: char name[MAXPATHLEN+3]; andre@3: Word rc; andre@3: andre@3: dir = malloc(sizeof(DIR)); andre@3: if (dir == NULL) { andre@3: errno = ENOMEM; andre@3: return NULL; andre@3: } andre@3: andre@3: strncpy(name, path, MAXPATHLEN); andre@3: name[MAXPATHLEN] = '\0'; andre@3: switch (name[strlen(name)-1]) { andre@3: default: andre@3: strcat(name, "\\"); andre@3: case '\\': andre@3: case '/': andre@3: case ':': andre@3: ; andre@3: } andre@3: strcat(name, "."); andre@3: if (!abs_path(name, dir->name, MAXPATHLEN+1)) andre@3: strcpy(dir->name, name); andre@3: if (dir->name[strlen(dir->name)-1] == '\\') andre@3: strcat(dir->name, "*"); andre@3: else andre@3: strcat(dir->name, "\\*"); andre@3: andre@3: dir->fstype = getFSType(dir->name); andre@3: dir->attrmask = att_mask | A_DIR; andre@3: andre@3: dir->handle = HDIR_CREATE; andre@3: dir->count = 100; andre@3: #if OS2 >= 2 andre@3: rc = DosFindFirst(dir->name, &dir->handle, dir->attrmask, andre@3: dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD); andre@3: #else andre@3: rc = DosFindFirst((PSZ)dir->name, &dir->handle, dir->attrmask, andre@3: (PFILEFINDBUF)dir->ffbuf, sizeof dir->ffbuf, &dir->count, 0); andre@3: #endif andre@3: switch (rc) { andre@3: default: andre@3: free(dir); andre@3: error(rc); andre@3: return NULL; andre@3: case NO_ERROR: andre@3: case ERROR_NO_MORE_FILES: andre@3: ; andre@3: } andre@3: andre@3: dir->number = 0; andre@3: dir->index = 0; andre@3: dir->next = (FFBUF *)dir->ffbuf; andre@3: andre@3: return (DIR *)dir; andre@3: } andre@3: andre@3: DIR * andre@3: opendir(const char *pathname) andre@3: { andre@3: return openxdir(pathname, 0); andre@3: } andre@3: andre@3: struct dirent * andre@3: readdir(DIR *dir) andre@3: { andre@3: static int dummy_ino = 2; andre@3: andre@3: if (dir->index == dir->count) { andre@3: Word rc; andre@3: dir->count = 100; andre@3: #if OS2 >= 2 andre@3: rc = DosFindNext(dir->handle, dir->ffbuf, andre@3: sizeof dir->ffbuf, &dir->count); andre@3: #else andre@3: rc = DosFindNext(dir->handle, (PFILEFINDBUF)dir->ffbuf, andre@3: sizeof dir->ffbuf, &dir->count); andre@3: #endif andre@3: if (rc) { andre@3: error(rc); andre@3: return NULL; andre@3: } andre@3: andre@3: dir->index = 0; andre@3: dir->next = (FFBUF *)dir->ffbuf; andre@3: } andre@3: andre@3: if (dir->index == dir->count) andre@3: return NULL; andre@3: andre@3: memcpy(dir->entry.d_name, dir->next->achName, dir->next->cchName); andre@3: dir->entry.d_name[dir->next->cchName] = '\0'; andre@3: dir->entry.d_ino = dummy_ino++; andre@3: dir->entry.d_reclen = dir->next->cchName; andre@3: dir->entry.d_namlen = dir->next->cchName; andre@3: dir->entry.d_size = dir->next->cbFile; andre@3: dir->entry.d_attribute = dir->next->attrFile; andre@3: dir->entry.d_time = *(USHORT *)&dir->next->ftimeLastWrite; andre@3: dir->entry.d_date = *(USHORT *)&dir->next->fdateLastWrite; andre@3: andre@3: switch (dir->fstype) { andre@3: case 'F': /* FAT */ andre@3: case 'C': /* CDFS */ andre@3: if (dir->next->attrFile & FILE_DIRECTORY) andre@3: strupr(dir->entry.d_name); andre@3: else andre@3: strlwr(dir->entry.d_name); andre@3: } andre@3: andre@3: #if OS2 >= 2 andre@3: dir->next = (FFBUF *)((BYTE *)dir->next + dir->next->oNextEntryOffset); andre@3: #else andre@3: dir->next = (FFBUF *)((BYTE *)dir->next->achName + dir->next->cchName + 1); andre@3: #endif andre@3: ++dir->number; andre@3: ++dir->index; andre@3: andre@3: return &dir->entry; andre@3: } andre@3: andre@3: long andre@3: telldir(DIR *dir) andre@3: { andre@3: return dir->number; andre@3: } andre@3: andre@3: void andre@3: seekdir(DIR *dir, long off) andre@3: { andre@3: if (dir->number > off) { andre@3: char name[MAXPATHLEN+2]; andre@3: Word rc; andre@3: andre@3: DosFindClose(dir->handle); andre@3: andre@3: strcpy(name, dir->name); andre@3: strcat(name, "*"); andre@3: andre@3: dir->handle = HDIR_CREATE; andre@3: dir->count = 32767; andre@3: #if OS2 >= 2 andre@3: rc = DosFindFirst(name, &dir->handle, dir->attrmask, andre@3: dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD); andre@3: #else andre@3: rc = DosFindFirst((PSZ)name, &dir->handle, dir->attrmask, andre@3: (PFILEFINDBUF)dir->ffbuf, sizeof dir->ffbuf, &dir->count, 0); andre@3: #endif andre@3: switch (rc) { andre@3: default: andre@3: error(rc); andre@3: return; andre@3: case NO_ERROR: andre@3: case ERROR_NO_MORE_FILES: andre@3: ; andre@3: } andre@3: andre@3: dir->number = 0; andre@3: dir->index = 0; andre@3: dir->next = (FFBUF *)dir->ffbuf; andre@3: } andre@3: andre@3: while (dir->number < off && readdir(dir)) andre@3: ; andre@3: } andre@3: andre@3: void andre@3: closedir(DIR *dir) andre@3: { andre@3: DosFindClose(dir->handle); andre@3: free(dir); andre@3: } andre@3: andre@3: /*****************************************************************************/ andre@3: andre@3: #ifdef TEST andre@3: andre@3: main(int argc, char **argv) andre@3: { andre@3: int i; andre@3: DIR *dir; andre@3: struct dirent *ep; andre@3: andre@3: for (i = 1; i < argc; ++i) { andre@3: dir = opendir(argv[i]); andre@3: if (!dir) andre@3: continue; andre@3: while (ep = readdir(dir)) andre@3: if (strchr("\\/:", argv[i] [strlen(argv[i]) - 1])) andre@3: printf("%s%s\n", argv[i], ep->d_name); andre@3: else andre@3: printf("%s/%s\n", argv[i], ep->d_name); andre@3: closedir(dir); andre@3: } andre@3: andre@3: return 0; andre@3: } andre@3: andre@3: #endif andre@3: andre@3: #endif /* OS2 */ andre@3: