📄 os2zip.c
字号:
/* * @(#)dir.c 1.4 87/11/06 Public Domain. * * A public domain implementation of BSD directory routines for * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield), * August 1987 * * Ported to OS/2 by Kai Uwe Rommel * Addition of other OS/2 file system specific code * Placed into the public domain *//* does also contain EA access code for use in ZIP */#ifdef OS2#if defined(__EMX__) && !defined(__32BIT__)# define __32BIT__#endif#include "zip.h"#include <stdlib.h>#include <time.h>#include <ctype.h>#ifndef __BORLANDC__#include <malloc.h>#endif#define INCL_NOPM#define INCL_DOSNLS#define INCL_DOSERRORS#include <os2.h>#include "os2zip.h"#include "os2acl.h"#ifndef max#define max(a, b) ((a) < (b) ? (b) : (a))#endif#ifdef __32BIT__#define DosFindFirst(p1, p2, p3, p4, p5, p6) \ DosFindFirst(p1, p2, p3, p4, p5, p6, 1)#else#define DosQueryCurrentDisk DosQCurDisk#define DosQueryFSAttach(p1, p2, p3, p4, p5) \ DosQFSAttach(p1, p2, p3, p4, p5, 0)#define DosQueryFSInfo(d, l, b, s) \ DosQFSInfo(d, l, b, s)#define DosQueryPathInfo(p1, p2, p3, p4) \ DosQPathInfo(p1, p2, p3, p4, 0)#define DosSetPathInfo(p1, p2, p3, p4, p5) \ DosSetPathInfo(p1, p2, p3, p4, p5, 0)#define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \ DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0)#define DosFindFirst(p1, p2, p3, p4, p5, p6) \ DosFindFirst(p1, p2, p3, p4, p5, p6, 0)#define DosMapCase DosCaseMap#endif#ifndef UTILextern int noisy;#ifndef S_IFMT#define S_IFMT 0xF000#endifstatic int attributes = _A_DIR | _A_HIDDEN | _A_SYSTEM;static char *getdirent(char *);static void free_dircontents(struct _dircontents *);#ifdef __32BIT__static HDIR hdir;static ULONG count;static FILEFINDBUF3 find;#elsestatic HDIR hdir;static USHORT count;static FILEFINDBUF find;#endifDIR *opendir(const char *name){ struct stat statb; DIR *dirp; char c; char *s; struct _dircontents *dp; char nbuf[MAXPATHLEN + 1]; int len; attributes = hidden_files ? (_A_DIR | _A_HIDDEN | _A_SYSTEM) : _A_DIR; strcpy(nbuf, name); if ((len = strlen(nbuf)) == 0) return NULL; if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1)) { nbuf[len - 1] = 0; --len; if (nbuf[len - 1] == ':') { strcpy(nbuf+len, "\\."); len += 2; } } else if (nbuf[len - 1] == ':') { strcpy(nbuf+len, "."); ++len; }#ifndef __BORLANDC__ /* when will we ever see a Borland compiler that can properly stat !!! */ if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR) return NULL;#endif if ((dirp = malloc(sizeof(DIR))) == NULL) return NULL; if (nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.')) strcpy(nbuf+len-1, "*.*"); else if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1)) strcpy(nbuf+len, "*"); else strcpy(nbuf+len, "\\*"); /* len is no longer correct (but no longer needed) */ dirp -> dd_loc = 0; dirp -> dd_contents = dirp -> dd_cp = NULL; if ((s = getdirent(nbuf)) == NULL) return dirp; do { if (((dp = malloc(sizeof(struct _dircontents))) == NULL) || ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL) ) { if (dp) free(dp); free_dircontents(dirp -> dd_contents); return NULL; } if (dirp -> dd_contents) { dirp -> dd_cp -> _d_next = dp; dirp -> dd_cp = dirp -> dd_cp -> _d_next; } else dirp -> dd_contents = dirp -> dd_cp = dp; strcpy(dp -> _d_entry, s); dp -> _d_next = NULL; dp -> _d_size = find.cbFile; dp -> _d_mode = find.attrFile; dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite); dp -> _d_date = *(unsigned *) &(find.fdateLastWrite); } while ((s = getdirent(NULL)) != NULL); dirp -> dd_cp = dirp -> dd_contents; return dirp;}void closedir(DIR * dirp){ free_dircontents(dirp -> dd_contents); free(dirp);}struct dirent *readdir(DIR * dirp){ static struct dirent dp; if (dirp -> dd_cp == NULL) return NULL; dp.d_namlen = dp.d_reclen = strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry)); dp.d_ino = 0; dp.d_size = dirp -> dd_cp -> _d_size; dp.d_mode = dirp -> dd_cp -> _d_mode; dp.d_time = dirp -> dd_cp -> _d_time; dp.d_date = dirp -> dd_cp -> _d_date; dirp -> dd_cp = dirp -> dd_cp -> _d_next; dirp -> dd_loc++; return &dp;}void seekdir(DIR * dirp, long off){ long i = off; struct _dircontents *dp; if (off >= 0) { for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next); dirp -> dd_loc = off - (i + 1); dirp -> dd_cp = dp; }}long telldir(DIR * dirp){ return dirp -> dd_loc;}static void free_dircontents(struct _dircontents * dp){ struct _dircontents *odp; while (dp) { if (dp -> _d_entry) free(dp -> _d_entry); dp = (odp = dp) -> _d_next; free(odp); }}static char *getdirent(char *dir){ int done; static int lower; if (dir != NULL) { /* get first entry */ hdir = HDIR_SYSTEM; count = 1; done = DosFindFirst(dir, &hdir, attributes, &find, sizeof(find), &count); lower = IsFileSystemFAT(dir); } else /* get next entry */ done = DosFindNext(hdir, &find, sizeof(find), &count); if (done == 0) { if (lower) StringLower(find.achName); return find.achName; } else { DosFindClose(hdir); return NULL; }}/* FAT / HPFS detection */int IsFileSystemFAT(char *dir){ static USHORT nLastDrive = -1, nResult; ULONG lMap; BYTE bData[64]; char bName[3];#ifdef __32BIT__ ULONG nDrive, cbData; PFSQBUFFER2 pData = (PFSQBUFFER2) bData;#else USHORT nDrive, cbData; PFSQBUFFER pData = (PFSQBUFFER) bData;#endif /* We separate FAT and HPFS+other file systems here. at the moment I consider other systems to be similar to HPFS, i.e. support long file names and being case sensitive */ if (isalpha(dir[0]) && (dir[1] == ':')) nDrive = to_up(dir[0]) - '@'; else DosQueryCurrentDisk(&nDrive, &lMap); if (nDrive == nLastDrive) return nResult; bName[0] = (char) (nDrive + '@'); bName[1] = ':'; bName[2] = 0; nLastDrive = nDrive; cbData = sizeof(bData); if (!DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData)) nResult = !strcmp((char *) pData -> szFSDName + pData -> cbName, "FAT"); else nResult = FALSE; /* End of this ugly code */ return nResult;}/* access mode bits and time stamp */int GetFileMode(char *name){#ifdef __32BIT__ FILESTATUS3 fs; return DosQueryPathInfo(name, 1, &fs, sizeof(fs)) ? -1 : fs.attrFile;#else USHORT mode; return DosQFileMode(name, &mode, 0L) ? -1 : mode;#endif}ulg GetFileTime(char *name){#ifdef __32BIT__ FILESTATUS3 fs;#else FILESTATUS fs;#endif USHORT nDate, nTime; DATETIME dtCurrent; if (strcmp(name, "-") == 0) { DosGetDateTime(&dtCurrent); fs.fdateLastWrite.day = dtCurrent.day; fs.fdateLastWrite.month = dtCurrent.month; fs.fdateLastWrite.year = dtCurrent.year - 1980; fs.ftimeLastWrite.hours = dtCurrent.hours; fs.ftimeLastWrite.minutes = dtCurrent.minutes; fs.ftimeLastWrite.twosecs = dtCurrent.seconds / 2; } else if (DosQueryPathInfo(name, 1, (PBYTE) &fs, sizeof(fs))) return -1; nDate = * (USHORT *) &fs.fdateLastWrite; nTime = * (USHORT *) &fs.ftimeLastWrite; return ((ULONG) nDate) << 16 | nTime;}void SetFileTime(char *path, ulg stamp){ FILESTATUS fs; USHORT fd, ft; if (DosQueryPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs))) return; fd = (USHORT) (stamp >> 16); ft = (USHORT) stamp; fs.fdateLastWrite = fs.fdateCreation = * (FDATE *) &fd; fs.ftimeLastWrite = fs.ftimeCreation = * (FTIME *) &ft; DosSetPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0);}/* read volume label */char *getVolumeLabel(int drive, unsigned long *vtime, unsigned long *vmode, time_t *utim){ static FSINFO fi; if (DosQueryFSInfo(drive ? drive - 'A' + 1 : 0, FSIL_VOLSER, (PBYTE) &fi, sizeof(fi))) return NULL; time(utim); *vtime = unix2dostime(utim); *vmode = _A_VOLID | _A_ARCHIVE; return (fi.vol.cch > 0) ? fi.vol.szVolLabel : NULL;}/* FAT / HPFS name conversion stuff */int IsFileNameValid(char *name){ HFILE hf;#ifdef __32BIT__ ULONG uAction;#else USHORT uAction;#endif switch(DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0)) { case ERROR_INVALID_NAME: case ERROR_FILENAME_EXCED_RANGE: return FALSE; case NO_ERROR: DosClose(hf); default: return TRUE; }}void ChangeNameForFAT(char *name){ char *src, *dst, *next, *ptr, *dot, *start; static char invalid[] = ":;,=+\"[]<>| \t"; if (isalpha(name[0]) && (name[1] == ':')) start = name + 2; else start = name; src = dst = start; if ((*src == '/') || (*src == '\\')) src++, dst++; while (*src) { for (next = src; *next && (*next != '/') && (*next != '\\'); next++); for (ptr = src, dot = NULL; ptr < next; ptr++) if (*ptr == '.') { dot = ptr; /* remember last dot */ *ptr = '_'; } if (dot == NULL) for (ptr = src; ptr < next; ptr++) if (*ptr == '_') dot = ptr; /* remember last _ as if it were a dot */ if (dot && (dot > src) && ((next - dot <= 4) || ((next - src > 8) && (dot - src > 3)))) { if (dot) *dot = '.'; for (ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++) *dst++ = *ptr; for (ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++) *dst++ = *ptr; } else { if (dot && (next - src == 1)) *dot = '.'; /* special case: "." as a path component */ for (ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++) *dst++ = *ptr; } *dst++ = *next; /* either '/' or 0 */ if (*next) { src = next + 1; if (*src == 0) /* handle trailing '/' on dirs ! */ *dst = 0; } else break; } for (src = start; *src != 0; ++src) if ((strchr(invalid, *src) != NULL) || (*src == ' ')) *src = '_';}/* .LONGNAME EA code */typedef struct{ ULONG cbList; /* length of value + 22 */#ifdef __32BIT__ ULONG oNext;#endif BYTE fEA; /* 0 */ BYTE cbName; /* length of ".LONGNAME" = 9 */ USHORT cbValue; /* length of value + 4 */ BYTE szName[10]; /* ".LONGNAME" */ USHORT eaType; /* 0xFFFD for length-preceded ASCII */ USHORT eaSize; /* length of value */ BYTE szValue[CCHMAXPATH];}FEALST;typedef struct{ ULONG cbList;#ifdef __32BIT__ ULONG oNext;#endif BYTE cbName; BYTE szName[10]; /* ".LONGNAME" */}GEALST;char *GetLongNameEA(const char *name){ EAOP eaop; GEALST gealst; static FEALST fealst; char *ptr; eaop.fpGEAList = (PGEALIST) &gealst; eaop.fpFEAList = (PFEALIST) &fealst; eaop.oError = 0; strcpy((char *) gealst.szName, ".LONGNAME"); gealst.cbName = (BYTE) strlen((char *) gealst.szName);#ifdef __32BIT__ gealst.oNext = 0;#endif gealst.cbList = sizeof(gealst); fealst.cbList = sizeof(fealst); if (DosQueryPathInfo(name, FIL_QUERYEASFROMLIST, (PBYTE) &eaop, sizeof(eaop))) return NULL; if (fealst.cbValue > 4 && fealst.eaType == 0xFFFD) { fealst.szValue[fealst.eaSize] = 0; for (ptr = fealst.szValue; *ptr; ptr++) if (*ptr == '/' || *ptr == '\\') *ptr = '!'; return (char *) fealst.szValue; } return NULL;}char *GetLongPathEA(const char *name){ static char nbuf[CCHMAXPATH + 1]; char tempbuf[CCHMAXPATH + 1]; char *comp, *next, *ea, sep; BOOL bFound = FALSE; nbuf[0] = 0; strncpy(tempbuf, name, CCHMAXPATH); tempbuf[CCHMAXPATH] = '\0'; next = tempbuf; while (*next) { comp = next; while (*next != '\\' && *next != '/' && *next != 0) next++; sep = *next; *next = 0; ea = GetLongNameEA(tempbuf); strcat(nbuf, ea ? ea : comp); bFound = bFound || (ea != NULL); if (sep) { strcat(nbuf, "\\"); *next++ = sep; } } return (nbuf[0] != 0) && bFound ? nbuf : NULL;}/* general EA code */typedef struct{ USHORT nID; USHORT nSize; ULONG lSize;}EFHEADER, *PEFHEADER;#ifdef __32BIT__/* Perhaps due to bugs in the current OS/2 2.0 kernel, the success or failure of the DosEnumAttribute() and DosQueryPathInfo() system calls depends on the area where the return buffers are allocated. This differs for the various compilers, for some alloca() works, for some
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -