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