os2zip.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. /*
  2. * @(#)dir.c 1.4 87/11/06 Public Domain.
  3. *
  4. * A public domain implementation of BSD directory routines for
  5. * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
  6. * August 1987
  7. *
  8. * Ported to OS/2 by Kai Uwe Rommel
  9. * Addition of other OS/2 file system specific code
  10. * Placed into the public domain
  11. */
  12. /* does also contain EA access code for use in ZIP */
  13. #ifdef OS2
  14. #if defined(__EMX__) && !defined(__32BIT__)
  15. # define __32BIT__
  16. #endif
  17. #include "zip.h"
  18. #include <stdlib.h>
  19. #include <time.h>
  20. #include <ctype.h>
  21. #ifndef __BORLANDC__
  22. #include <malloc.h>
  23. #endif
  24. #define INCL_NOPM
  25. #define INCL_DOSNLS
  26. #define INCL_DOSERRORS
  27. #include <os2.h>
  28. #include "os2zip.h"
  29. #include "os2acl.h"
  30. #ifndef max
  31. #define max(a, b) ((a) < (b) ? (b) : (a))
  32. #endif
  33. #ifdef __32BIT__
  34. #define DosFindFirst(p1, p2, p3, p4, p5, p6) \
  35. DosFindFirst(p1, p2, p3, p4, p5, p6, 1)
  36. #else
  37. #define DosQueryCurrentDisk DosQCurDisk
  38. #define DosQueryFSAttach(p1, p2, p3, p4, p5) \
  39. DosQFSAttach(p1, p2, p3, p4, p5, 0)
  40. #define DosQueryFSInfo(d, l, b, s) \
  41. DosQFSInfo(d, l, b, s)
  42. #define DosQueryPathInfo(p1, p2, p3, p4) \
  43. DosQPathInfo(p1, p2, p3, p4, 0)
  44. #define DosSetPathInfo(p1, p2, p3, p4, p5) \
  45. DosSetPathInfo(p1, p2, p3, p4, p5, 0)
  46. #define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \
  47. DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0)
  48. #define DosFindFirst(p1, p2, p3, p4, p5, p6) \
  49. DosFindFirst(p1, p2, p3, p4, p5, p6, 0)
  50. #define DosMapCase DosCaseMap
  51. #endif
  52. #ifndef UTIL
  53. extern int noisy;
  54. #ifndef S_IFMT
  55. #define S_IFMT 0xF000
  56. #endif
  57. static int attributes = _A_DIR | _A_HIDDEN | _A_SYSTEM;
  58. static char *getdirent(char *);
  59. static void free_dircontents(struct _dircontents *);
  60. #ifdef __32BIT__
  61. static HDIR hdir;
  62. static ULONG count;
  63. static FILEFINDBUF3 find;
  64. #else
  65. static HDIR hdir;
  66. static USHORT count;
  67. static FILEFINDBUF find;
  68. #endif
  69. DIR *opendir(const char *name)
  70. {
  71. struct stat statb;
  72. DIR *dirp;
  73. char c;
  74. char *s;
  75. struct _dircontents *dp;
  76. char nbuf[MAXPATHLEN + 1];
  77. int len;
  78. attributes = hidden_files ? (_A_DIR | _A_HIDDEN | _A_SYSTEM) : _A_DIR;
  79. strcpy(nbuf, name);
  80. if ((len = strlen(nbuf)) == 0)
  81. return NULL;
  82. if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1))
  83. {
  84. nbuf[len - 1] = 0;
  85. --len;
  86. if (nbuf[len - 1] == ':')
  87. {
  88. strcpy(nbuf+len, "\\.");
  89. len += 2;
  90. }
  91. }
  92. else
  93. if (nbuf[len - 1] == ':')
  94. {
  95. strcpy(nbuf+len, ".");
  96. ++len;
  97. }
  98. #ifndef __BORLANDC__
  99. /* when will we ever see a Borland compiler that can properly stat !!! */
  100. if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
  101. return NULL;
  102. #endif
  103. if ((dirp = malloc(sizeof(DIR))) == NULL)
  104. return NULL;
  105. if (nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.'))
  106. strcpy(nbuf+len-1, "*.*");
  107. else
  108. if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1))
  109. strcpy(nbuf+len, "*");
  110. else
  111. strcpy(nbuf+len, "\\*");
  112. /* len is no longer correct (but no longer needed) */
  113. dirp -> dd_loc = 0;
  114. dirp -> dd_contents = dirp -> dd_cp = NULL;
  115. if ((s = getdirent(nbuf)) == NULL)
  116. return dirp;
  117. do
  118. {
  119. if (((dp = malloc(sizeof(struct _dircontents))) == NULL) ||
  120. ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL) )
  121. {
  122. if (dp)
  123. free(dp);
  124. free_dircontents(dirp -> dd_contents);
  125. return NULL;
  126. }
  127. if (dirp -> dd_contents)
  128. {
  129. dirp -> dd_cp -> _d_next = dp;
  130. dirp -> dd_cp = dirp -> dd_cp -> _d_next;
  131. }
  132. else
  133. dirp -> dd_contents = dirp -> dd_cp = dp;
  134. strcpy(dp -> _d_entry, s);
  135. dp -> _d_next = NULL;
  136. dp -> _d_size = find.cbFile;
  137. dp -> _d_mode = find.attrFile;
  138. dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite);
  139. dp -> _d_date = *(unsigned *) &(find.fdateLastWrite);
  140. }
  141. while ((s = getdirent(NULL)) != NULL);
  142. dirp -> dd_cp = dirp -> dd_contents;
  143. return dirp;
  144. }
  145. void closedir(DIR * dirp)
  146. {
  147. free_dircontents(dirp -> dd_contents);
  148. free(dirp);
  149. }
  150. struct dirent *readdir(DIR * dirp)
  151. {
  152. static struct dirent dp;
  153. if (dirp -> dd_cp == NULL)
  154. return NULL;
  155. dp.d_namlen = dp.d_reclen =
  156. strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry));
  157. dp.d_ino = 0;
  158. dp.d_size = dirp -> dd_cp -> _d_size;
  159. dp.d_mode = dirp -> dd_cp -> _d_mode;
  160. dp.d_time = dirp -> dd_cp -> _d_time;
  161. dp.d_date = dirp -> dd_cp -> _d_date;
  162. dirp -> dd_cp = dirp -> dd_cp -> _d_next;
  163. dirp -> dd_loc++;
  164. return &dp;
  165. }
  166. void seekdir(DIR * dirp, long off)
  167. {
  168. long i = off;
  169. struct _dircontents *dp;
  170. if (off >= 0)
  171. {
  172. for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next);
  173. dirp -> dd_loc = off - (i + 1);
  174. dirp -> dd_cp = dp;
  175. }
  176. }
  177. long telldir(DIR * dirp)
  178. {
  179. return dirp -> dd_loc;
  180. }
  181. static void free_dircontents(struct _dircontents * dp)
  182. {
  183. struct _dircontents *odp;
  184. while (dp)
  185. {
  186. if (dp -> _d_entry)
  187. free(dp -> _d_entry);
  188. dp = (odp = dp) -> _d_next;
  189. free(odp);
  190. }
  191. }
  192. static char *getdirent(char *dir)
  193. {
  194. int done;
  195. static int lower;
  196. if (dir != NULL)
  197. { /* get first entry */
  198. hdir = HDIR_SYSTEM;
  199. count = 1;
  200. done = DosFindFirst(dir, &hdir, attributes, &find, sizeof(find), &count);
  201. lower = IsFileSystemFAT(dir);
  202. }
  203. else /* get next entry */
  204. done = DosFindNext(hdir, &find, sizeof(find), &count);
  205. if (done == 0)
  206. {
  207. if (lower)
  208. StringLower(find.achName);
  209. return find.achName;
  210. }
  211. else
  212. {
  213. DosFindClose(hdir);
  214. return NULL;
  215. }
  216. }
  217. /* FAT / HPFS detection */
  218. int IsFileSystemFAT(char *dir)
  219. {
  220. static USHORT nLastDrive = -1, nResult;
  221. ULONG lMap;
  222. BYTE bData[64];
  223. char bName[3];
  224. #ifdef __32BIT__
  225. ULONG nDrive, cbData;
  226. PFSQBUFFER2 pData = (PFSQBUFFER2) bData;
  227. #else
  228. USHORT nDrive, cbData;
  229. PFSQBUFFER pData = (PFSQBUFFER) bData;
  230. #endif
  231. /* We separate FAT and HPFS+other file systems here.
  232. at the moment I consider other systems to be similar to HPFS,
  233. i.e. support long file names and being case sensitive */
  234. if (isalpha(dir[0]) && (dir[1] == ':'))
  235. nDrive = to_up(dir[0]) - '@';
  236. else
  237. DosQueryCurrentDisk(&nDrive, &lMap);
  238. if (nDrive == nLastDrive)
  239. return nResult;
  240. bName[0] = (char) (nDrive + '@');
  241. bName[1] = ':';
  242. bName[2] = 0;
  243. nLastDrive = nDrive;
  244. cbData = sizeof(bData);
  245. if (!DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData))
  246. nResult = !strcmp((char *) pData -> szFSDName + pData -> cbName, "FAT");
  247. else
  248. nResult = FALSE;
  249. /* End of this ugly code */
  250. return nResult;
  251. }
  252. /* access mode bits and time stamp */
  253. int GetFileMode(char *name)
  254. {
  255. #ifdef __32BIT__
  256. FILESTATUS3 fs;
  257. return DosQueryPathInfo(name, 1, &fs, sizeof(fs)) ? -1 : fs.attrFile;
  258. #else
  259. USHORT mode;
  260. return DosQFileMode(name, &mode, 0L) ? -1 : mode;
  261. #endif
  262. }
  263. ulg GetFileTime(char *name)
  264. {
  265. #ifdef __32BIT__
  266. FILESTATUS3 fs;
  267. #else
  268. FILESTATUS fs;
  269. #endif
  270. USHORT nDate, nTime;
  271. DATETIME dtCurrent;
  272. if (strcmp(name, "-") == 0)
  273. {
  274. DosGetDateTime(&dtCurrent);
  275. fs.fdateLastWrite.day = dtCurrent.day;
  276. fs.fdateLastWrite.month = dtCurrent.month;
  277. fs.fdateLastWrite.year = dtCurrent.year - 1980;
  278. fs.ftimeLastWrite.hours = dtCurrent.hours;
  279. fs.ftimeLastWrite.minutes = dtCurrent.minutes;
  280. fs.ftimeLastWrite.twosecs = dtCurrent.seconds / 2;
  281. }
  282. else
  283. if (DosQueryPathInfo(name, 1, (PBYTE) &fs, sizeof(fs)))
  284. return -1;
  285. nDate = * (USHORT *) &fs.fdateLastWrite;
  286. nTime = * (USHORT *) &fs.ftimeLastWrite;
  287. return ((ULONG) nDate) << 16 | nTime;
  288. }
  289. void SetFileTime(char *path, ulg stamp)
  290. {
  291. FILESTATUS fs;
  292. USHORT fd, ft;
  293. if (DosQueryPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)))
  294. return;
  295. fd = (USHORT) (stamp >> 16);
  296. ft = (USHORT) stamp;
  297. fs.fdateLastWrite = fs.fdateCreation = * (FDATE *) &fd;
  298. fs.ftimeLastWrite = fs.ftimeCreation = * (FTIME *) &ft;
  299. DosSetPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0);
  300. }
  301. /* read volume label */
  302. char *getVolumeLabel(int drive, unsigned long *vtime, unsigned long *vmode,
  303. time_t *utim)
  304. {
  305. static FSINFO fi;
  306. if (DosQueryFSInfo(drive ? drive - 'A' + 1 : 0,
  307. FSIL_VOLSER, (PBYTE) &fi, sizeof(fi)))
  308. return NULL;
  309. time(utim);
  310. *vtime = unix2dostime(utim);
  311. *vmode = _A_VOLID | _A_ARCHIVE;
  312. return (fi.vol.cch > 0) ? fi.vol.szVolLabel : NULL;
  313. }
  314. /* FAT / HPFS name conversion stuff */
  315. int IsFileNameValid(char *name)
  316. {
  317. HFILE hf;
  318. #ifdef __32BIT__
  319. ULONG uAction;
  320. #else
  321. USHORT uAction;
  322. #endif
  323. switch(DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN,
  324. OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0))
  325. {
  326. case ERROR_INVALID_NAME:
  327. case ERROR_FILENAME_EXCED_RANGE:
  328. return FALSE;
  329. case NO_ERROR:
  330. DosClose(hf);
  331. default:
  332. return TRUE;
  333. }
  334. }
  335. void ChangeNameForFAT(char *name)
  336. {
  337. char *src, *dst, *next, *ptr, *dot, *start;
  338. static char invalid[] = ":;,=+\"[]<>| \t";
  339. if (isalpha(name[0]) && (name[1] == ':'))
  340. start = name + 2;
  341. else
  342. start = name;
  343. src = dst = start;
  344. if ((*src == '/') || (*src == '\\'))
  345. src++, dst++;
  346. while (*src)
  347. {
  348. for (next = src; *next && (*next != '/') && (*next != '\\'); next++);
  349. for (ptr = src, dot = NULL; ptr < next; ptr++)
  350. if (*ptr == '.')
  351. {
  352. dot = ptr; /* remember last dot */
  353. *ptr = '_';
  354. }
  355. if (dot == NULL)
  356. for (ptr = src; ptr < next; ptr++)
  357. if (*ptr == '_')
  358. dot = ptr; /* remember last _ as if it were a dot */
  359. if (dot && (dot > src) &&
  360. ((next - dot <= 4) ||
  361. ((next - src > 8) && (dot - src > 3))))
  362. {
  363. if (dot)
  364. *dot = '.';
  365. for (ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++)
  366. *dst++ = *ptr;
  367. for (ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++)
  368. *dst++ = *ptr;
  369. }
  370. else
  371. {
  372. if (dot && (next - src == 1))
  373. *dot = '.'; /* special case: "." as a path component */
  374. for (ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++)
  375. *dst++ = *ptr;
  376. }
  377. *dst++ = *next; /* either '/' or 0 */
  378. if (*next)
  379. {
  380. src = next + 1;
  381. if (*src == 0) /* handle trailing '/' on dirs ! */
  382. *dst = 0;
  383. }
  384. else
  385. break;
  386. }
  387. for (src = start; *src != 0; ++src)
  388. if ((strchr(invalid, *src) != NULL) || (*src == ' '))
  389. *src = '_';
  390. }
  391. /* .LONGNAME EA code */
  392. typedef struct
  393. {
  394. ULONG cbList; /* length of value + 22 */
  395. #ifdef __32BIT__
  396. ULONG oNext;
  397. #endif
  398. BYTE fEA; /* 0 */
  399. BYTE cbName; /* length of ".LONGNAME" = 9 */
  400. USHORT cbValue; /* length of value + 4 */
  401. BYTE szName[10]; /* ".LONGNAME" */
  402. USHORT eaType; /* 0xFFFD for length-preceded ASCII */
  403. USHORT eaSize; /* length of value */
  404. BYTE szValue[CCHMAXPATH];
  405. }
  406. FEALST;
  407. typedef struct
  408. {
  409. ULONG cbList;
  410. #ifdef __32BIT__
  411. ULONG oNext;
  412. #endif
  413. BYTE cbName;
  414. BYTE szName[10]; /* ".LONGNAME" */
  415. }
  416. GEALST;
  417. char *GetLongNameEA(const char *name)
  418. {
  419. EAOP eaop;
  420. GEALST gealst;
  421. static FEALST fealst;
  422. char *ptr;
  423. eaop.fpGEAList = (PGEALIST) &gealst;
  424. eaop.fpFEAList = (PFEALIST) &fealst;
  425. eaop.oError = 0;
  426. strcpy((char *) gealst.szName, ".LONGNAME");
  427. gealst.cbName = (BYTE) strlen((char *) gealst.szName);
  428. #ifdef __32BIT__
  429. gealst.oNext = 0;
  430. #endif
  431. gealst.cbList = sizeof(gealst);
  432. fealst.cbList = sizeof(fealst);
  433. if (DosQueryPathInfo(name, FIL_QUERYEASFROMLIST,
  434. (PBYTE) &eaop, sizeof(eaop)))
  435. return NULL;
  436. if (fealst.cbValue > 4 && fealst.eaType == 0xFFFD)
  437. {
  438. fealst.szValue[fealst.eaSize] = 0;
  439. for (ptr = fealst.szValue; *ptr; ptr++)
  440. if (*ptr == '/' || *ptr == '\\')
  441. *ptr = '!';
  442. return (char *) fealst.szValue;
  443. }
  444. return NULL;
  445. }
  446. char *GetLongPathEA(const char *name)
  447. {
  448. static char nbuf[CCHMAXPATH + 1];
  449. char tempbuf[CCHMAXPATH + 1];
  450. char *comp, *next, *ea, sep;
  451. BOOL bFound = FALSE;
  452. nbuf[0] = 0;
  453. strncpy(tempbuf, name, CCHMAXPATH);
  454. tempbuf[CCHMAXPATH] = '\0';
  455. next = tempbuf;
  456. while (*next)
  457. {
  458. comp = next;
  459. while (*next != '\\' && *next != '/' && *next != 0)
  460. next++;
  461. sep = *next;
  462. *next = 0;
  463. ea = GetLongNameEA(tempbuf);
  464. strcat(nbuf, ea ? ea : comp);
  465. bFound = bFound || (ea != NULL);
  466. if (sep)
  467. {
  468. strcat(nbuf, "\\");
  469. *next++ = sep;
  470. }
  471. }
  472. return (nbuf[0] != 0) && bFound ? nbuf : NULL;
  473. }
  474. /* general EA code */
  475. typedef struct
  476. {
  477. USHORT nID;
  478. USHORT nSize;
  479. ULONG lSize;
  480. }
  481. EFHEADER, *PEFHEADER;
  482. #ifdef __32BIT__
  483. /* Perhaps due to bugs in the current OS/2 2.0 kernel, the success or
  484. failure of the DosEnumAttribute() and DosQueryPathInfo() system calls
  485. depends on the area where the return buffers are allocated. This
  486. differs for the various compilers, for some alloca() works, for some
  487. malloc() works, for some, both work. We'll have to live with that. */
  488. /* The use of malloc() is not very convenient, because it requires
  489. backtracking (i.e. free()) at error returns. We do that for system
  490. calls that may fail, but not for malloc() calls, because they are VERY
  491. unlikely to fail. If ever, we just leave some memory allocated
  492. over the usually short lifetime of a zip process ... */
  493. #ifdef __GNUC__
  494. #define alloc(x) alloca(x)
  495. #define unalloc(x)
  496. #else
  497. #define alloc(x) malloc(x)
  498. #define unalloc(x) free(x)
  499. #endif
  500. void GetEAs(char *path, char **bufptr, size_t *size,
  501. char **cbufptr, size_t *csize)
  502. {
  503. FILESTATUS4 fs;
  504. PDENA2 pDENA, pFound;
  505. EAOP2 eaop;
  506. PGEA2 pGEA;
  507. PGEA2LIST pGEAlist;
  508. PFEA2LIST pFEAlist;
  509. PEFHEADER pEAblock;
  510. ULONG ulAttributes, ulMemoryBlock;
  511. ULONG nLength;
  512. ULONG nBlock;
  513. char szName[CCHMAXPATH];
  514. *size = *csize = 0;
  515. strcpy(szName, path);
  516. nLength = strlen(szName);
  517. if (szName[nLength - 1] == '/')
  518. szName[nLength - 1] = 0;
  519. if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs)))
  520. return;
  521. nBlock = max(fs.cbList, 65535);
  522. if ((pDENA = alloc((size_t) nBlock)) == NULL)
  523. return;
  524. ulAttributes = -1;
  525. if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, nBlock,
  526. &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
  527. || ulAttributes == 0
  528. || (pGEAlist = alloc((size_t) nBlock)) == NULL)
  529. {
  530. unalloc(pDENA);
  531. return;
  532. }
  533. pGEA = pGEAlist -> list;
  534. memset(pGEAlist, 0, nBlock);
  535. pFound = pDENA;
  536. while (ulAttributes--)
  537. {
  538. if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
  539. {
  540. pGEA -> cbName = pFound -> cbName;
  541. strcpy(pGEA -> szName, pFound -> szName);
  542. nLength = sizeof(GEA2) + strlen(pGEA -> szName);
  543. nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
  544. pGEA -> oNextEntryOffset = ulAttributes ? nLength : 0;
  545. pGEA = (PGEA2) ((PCH) pGEA + nLength);
  546. }
  547. pFound = (PDENA2) ((PCH) pFound + pFound -> oNextEntryOffset);
  548. }
  549. if (pGEA == pGEAlist -> list) /* no attributes to save */
  550. {
  551. unalloc(pDENA);
  552. unalloc(pGEAlist);
  553. return;
  554. }
  555. pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
  556. pFEAlist = (PVOID) pDENA; /* reuse buffer */
  557. pFEAlist -> cbList = nBlock;
  558. eaop.fpGEA2List = pGEAlist;
  559. eaop.fpFEA2List = pFEAlist;
  560. eaop.oError = 0;
  561. if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
  562. (PBYTE) &eaop, sizeof(eaop)))
  563. {
  564. unalloc(pDENA);
  565. unalloc(pGEAlist);
  566. return;
  567. }
  568. /* The maximum compressed size is (in case of STORE type) the
  569. uncompressed size plus the size of the compression type field
  570. plus the size of the CRC field + 2*5 deflate overhead bytes
  571. for uncompressable data.
  572. (5 bytes per 32Kb block, max compressed size = 2 blocks) */
  573. ulAttributes = pFEAlist -> cbList;
  574. ulMemoryBlock = ulAttributes +
  575. sizeof(USHORT) + sizeof(ULONG) + EB_DEFLAT_EXTRA;
  576. pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER) + ulMemoryBlock);
  577. if (pEAblock == NULL)
  578. {
  579. unalloc(pDENA);
  580. unalloc(pGEAlist);
  581. return;
  582. }
  583. *bufptr = (char *) pEAblock;
  584. *size = sizeof(EFHEADER);
  585. pEAblock -> nID = EF_OS2EA;
  586. pEAblock -> nSize = sizeof(pEAblock -> lSize);
  587. pEAblock -> lSize = ulAttributes; /* uncompressed size */
  588. nLength = memcompress((char *) (pEAblock + 1), ulMemoryBlock,
  589. (char *) pFEAlist, ulAttributes);
  590. *size += nLength;
  591. pEAblock -> nSize += nLength;
  592. if ((pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER))) == NULL)
  593. {
  594. unalloc(pDENA);
  595. unalloc(pGEAlist);
  596. return;
  597. }
  598. *cbufptr = (char *) pEAblock;
  599. *csize = sizeof(EFHEADER);
  600. pEAblock -> nID = EF_OS2EA;
  601. pEAblock -> nSize = sizeof(pEAblock -> lSize);
  602. pEAblock -> lSize = ulAttributes;
  603. if (noisy)
  604. printf(" (%ld bytes EA's)", ulAttributes);
  605. unalloc(pDENA);
  606. unalloc(pGEAlist);
  607. }
  608. #else /* !__32BIT__ */
  609. typedef struct
  610. {
  611. ULONG oNextEntryOffset;
  612. BYTE fEA;
  613. BYTE cbName;
  614. USHORT cbValue;
  615. CHAR szName[1];
  616. }
  617. FEA2, *PFEA2;
  618. typedef struct
  619. {
  620. ULONG cbList;
  621. FEA2 list[1];
  622. }
  623. FEA2LIST, *PFEA2LIST;
  624. void GetEAs(char *path, char **bufptr, size_t *size,
  625. char **cbufptr, size_t *csize)
  626. {
  627. FILESTATUS2 fs;
  628. PDENA1 pDENA, pFound;
  629. EAOP eaop;
  630. PGEALIST pGEAlist;
  631. PGEA pGEA;
  632. PFEALIST pFEAlist;
  633. PFEA pFEA;
  634. PFEA2LIST pFEA2list;
  635. PFEA2 pFEA2;
  636. EFHEADER *pEAblock;
  637. ULONG ulAttributes;
  638. USHORT nLength, nMaxSize;
  639. char szName[CCHMAXPATH];
  640. *size = *csize = 0;
  641. strcpy(szName, path);
  642. nLength = strlen(szName);
  643. if (szName[nLength - 1] == '/')
  644. szName[nLength - 1] = 0;
  645. if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs))
  646. || fs.cbList <= 2 * sizeof(ULONG))
  647. return;
  648. ulAttributes = -1;
  649. nMaxSize = (USHORT) min(fs.cbList * 2, 65520L);
  650. if ((pDENA = malloc((size_t) nMaxSize)) == NULL)
  651. return;
  652. if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, fs.cbList,
  653. &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
  654. || ulAttributes == 0
  655. || (pGEAlist = malloc(nMaxSize)) == NULL)
  656. {
  657. free(pDENA);
  658. return;
  659. }
  660. pGEA = pGEAlist -> list;
  661. pFound = pDENA;
  662. while (ulAttributes--)
  663. {
  664. nLength = strlen(pFound -> szName);
  665. if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
  666. {
  667. pGEA -> cbName = pFound -> cbName;
  668. strcpy(pGEA -> szName, pFound -> szName);
  669. pGEA++;
  670. pGEA = (PGEA) (((PCH) pGEA) + nLength);
  671. }
  672. pFound++;
  673. pFound = (PDENA1) (((PCH) pFound) + nLength);
  674. }
  675. if (pGEA == pGEAlist -> list)
  676. {
  677. free(pDENA);
  678. free(pGEAlist);
  679. return;
  680. }
  681. pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
  682. pFEAlist = (PFEALIST) pDENA; /* reuse buffer */
  683. pFEAlist -> cbList = fs.cbList;
  684. pFEA = pFEAlist -> list;
  685. eaop.fpGEAList = pGEAlist;
  686. eaop.fpFEAList = pFEAlist;
  687. eaop.oError = 0;
  688. if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
  689. (PBYTE) &eaop, sizeof(eaop)))
  690. {
  691. free(pDENA);
  692. free(pGEAlist);
  693. return;
  694. }
  695. /* now convert into new OS/2 2.0 32-bit format */
  696. pFEA2list = (PFEA2LIST) pGEAlist; /* reuse buffer */
  697. pFEA2 = pFEA2list -> list;
  698. while ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList)
  699. {
  700. nLength = sizeof(FEA) + pFEA -> cbName + 1 + pFEA -> cbValue;
  701. memcpy((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset), pFEA, nLength);
  702. memset((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset) + nLength, 0, 3);
  703. pFEA = (PFEA) ((PCH) pFEA + nLength);
  704. nLength = sizeof(FEA2) + pFEA2 -> cbName + 1 + pFEA2 -> cbValue;
  705. nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
  706. /* rounded up to 4-byte boundary */
  707. pFEA2 -> oNextEntryOffset =
  708. ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList) ? nLength : 0;
  709. pFEA2 = (PFEA2) ((PCH) pFEA2 + nLength);
  710. }
  711. pFEA2list -> cbList = (PCH) pFEA2 - (PCH) pFEA2list;
  712. ulAttributes = pFEA2list -> cbList;
  713. pEAblock = (PEFHEADER) pDENA; /* reuse buffer */
  714. *bufptr = (char *) pEAblock;
  715. *size = sizeof(EFHEADER);
  716. pEAblock -> nID = EF_OS2EA;
  717. pEAblock -> nSize = sizeof(pEAblock -> lSize);
  718. pEAblock -> lSize = ulAttributes; /* uncompressed size */
  719. nLength = (USHORT) memcompress((char *) (pEAblock + 1),
  720. nMaxSize - sizeof(EFHEADER), (char *) pFEA2list, ulAttributes);
  721. *size += nLength;
  722. pEAblock -> nSize += nLength;
  723. pEAblock = (PEFHEADER) pGEAlist;
  724. *cbufptr = (char *) pEAblock;
  725. *csize = sizeof(EFHEADER);
  726. pEAblock -> nID = EF_OS2EA;
  727. pEAblock -> nSize = sizeof(pEAblock -> lSize);
  728. pEAblock -> lSize = ulAttributes;
  729. if (noisy)
  730. printf(" (%ld bytes EA's)", ulAttributes);
  731. }
  732. #endif /* __32BIT__ */
  733. void GetACL(char *path, char **bufptr, size_t *size,
  734. char **cbufptr, size_t *csize)
  735. {
  736. static char *buffer;
  737. char *cbuffer;
  738. long bytes, cbytes;
  739. PEFHEADER pACLblock;
  740. if (buffer == NULL) /* avoid frequent allocation (for every file) */
  741. if ((buffer = malloc(ACL_BUFFERSIZE)) == NULL)
  742. return;
  743. if (acl_get(NULL, path, buffer))
  744. return; /* this will be the most likely case */
  745. bytes = strlen(buffer);
  746. /* The maximum compressed size is (in case of STORE type) the
  747. uncompressed size plus the size of the compression type field
  748. plus the size of the CRC field + 2*5 deflate overhead bytes
  749. for uncompressable data.
  750. (5 bytes per 32Kb block, max compressed size = 2 blocks) */
  751. cbytes = bytes + sizeof(USHORT) + sizeof(ULONG) + EB_DEFLAT_EXTRA;
  752. if ((*bufptr = realloc(*bufptr, *size + sizeof(EFHEADER) + cbytes)) == NULL)
  753. return;
  754. pACLblock = (PEFHEADER) (*bufptr + *size);
  755. cbuffer = (char *) (pACLblock + 1);
  756. cbytes = memcompress(cbuffer, cbytes, buffer, bytes);
  757. *size += sizeof(EFHEADER) + cbytes;
  758. pACLblock -> nID = EF_ACL;
  759. pACLblock -> nSize = sizeof(pACLblock -> lSize) + cbytes;
  760. pACLblock -> lSize = bytes; /* uncompressed size */
  761. if ((*cbufptr = realloc(*cbufptr, *csize + sizeof(EFHEADER))) == NULL)
  762. return;
  763. pACLblock = (PEFHEADER) (*cbufptr + *csize);
  764. *csize += sizeof(EFHEADER);
  765. pACLblock -> nID = EF_ACL;
  766. pACLblock -> nSize = sizeof(pACLblock -> lSize);
  767. pACLblock -> lSize = bytes;
  768. if (noisy)
  769. printf(" (%ld bytes ACL)", bytes);
  770. }
  771. #ifdef USE_EF_UT_TIME
  772. int GetExtraTime(struct zlist far *z, iztimes *z_utim)
  773. {
  774. int eb_c_size = EB_HEADSIZE + EB_UT_LEN(1);
  775. int eb_l_size = eb_c_size;
  776. char *eb_c_ptr;
  777. char *eb_l_ptr;
  778. unsigned long ultime;
  779. #ifdef IZ_CHECK_TZ
  780. if (!zp_tz_is_valid) return ZE_OK; /* skip silently no correct tz info */
  781. #endif
  782. eb_c_ptr = realloc(z->cextra, (z->cext + eb_c_size));
  783. if (eb_c_ptr == NULL)
  784. return ZE_MEM;
  785. z->cextra = eb_c_ptr;
  786. eb_c_ptr += z->cext;
  787. z->cext += eb_c_size;
  788. eb_c_ptr[0] = 'U';
  789. eb_c_ptr[1] = 'T';
  790. eb_c_ptr[2] = EB_UT_LEN(1); /* length of data part of e.f. */
  791. eb_c_ptr[3] = 0;
  792. eb_c_ptr[4] = EB_UT_FL_MTIME;
  793. ultime = (unsigned long) z_utim->mtime;
  794. eb_c_ptr[5] = (char)(ultime);
  795. eb_c_ptr[6] = (char)(ultime >> 8);
  796. eb_c_ptr[7] = (char)(ultime >> 16);
  797. eb_c_ptr[8] = (char)(ultime >> 24);
  798. if (z_utim->mtime != z_utim->atime || z_utim->mtime != z_utim->ctime)
  799. {
  800. eb_c_ptr[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
  801. eb_l_size = EB_HEADSIZE + EB_UT_LEN(3); /* only on HPFS they can differ */
  802. /* so only then it makes sense to store all three time stamps */
  803. }
  804. eb_l_ptr = realloc(z->extra, (z->ext + eb_l_size));
  805. if (eb_l_ptr == NULL)
  806. return ZE_MEM;
  807. z->extra = eb_l_ptr;
  808. eb_l_ptr += z->ext;
  809. z->ext += eb_l_size;
  810. memcpy(eb_l_ptr, eb_c_ptr, eb_c_size);
  811. if (eb_l_size > eb_c_size)
  812. {
  813. eb_l_ptr[2] = EB_UT_LEN(3);
  814. ultime = (unsigned long) z_utim->atime;
  815. eb_l_ptr[9] = (char)(ultime);
  816. eb_l_ptr[10] = (char)(ultime >> 8);
  817. eb_l_ptr[11] = (char)(ultime >> 16);
  818. eb_l_ptr[12] = (char)(ultime >> 24);
  819. ultime = (unsigned long) z_utim->ctime;
  820. eb_l_ptr[13] = (char)(ultime);
  821. eb_l_ptr[14] = (char)(ultime >> 8);
  822. eb_l_ptr[15] = (char)(ultime >> 16);
  823. eb_l_ptr[16] = (char)(ultime >> 24);
  824. }
  825. return ZE_OK;
  826. }
  827. #endif /* USE_EF_UT_TIME */
  828. int set_extra_field(struct zlist far *z, iztimes *z_utim)
  829. {
  830. /* store EA data in local header, and size only in central headers */
  831. GetEAs(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
  832. /* store ACL data in local header, and size only in central headers */
  833. GetACL(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
  834. #ifdef USE_EF_UT_TIME
  835. /* store extended time stamps in both headers */
  836. return GetExtraTime(z, z_utim);
  837. #else /* !USE_EF_UT_TIME */
  838. return ZE_OK;
  839. #endif /* ?USE_EF_UT_TIME */
  840. }
  841. #endif /* !UTIL */
  842. /* Initialize the table of uppercase characters including handling of
  843. country dependent characters. */
  844. void init_upper()
  845. {
  846. COUNTRYCODE cc;
  847. unsigned nCnt, nU;
  848. for (nCnt = 0; nCnt < sizeof(upper); nCnt++)
  849. upper[nCnt] = lower[nCnt] = (unsigned char) nCnt;
  850. cc.country = cc.codepage = 0;
  851. DosMapCase(sizeof(upper), &cc, (PCHAR) upper);
  852. for (nCnt = 0; nCnt < 256; nCnt++)
  853. {
  854. nU = upper[nCnt];
  855. if (nU != nCnt && lower[nU] == (unsigned char) nU)
  856. lower[nU] = (unsigned char) nCnt;
  857. }
  858. for (nCnt = 'A'; nCnt <= 'Z'; nCnt++)
  859. lower[nCnt] = (unsigned char) (nCnt - 'A' + 'a');
  860. }
  861. char *StringLower(char *szArg)
  862. {
  863. unsigned char *szPtr;
  864. for (szPtr = (unsigned char *) szArg; *szPtr; szPtr++)
  865. *szPtr = lower[*szPtr];
  866. return szArg;
  867. }
  868. #if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
  869. void DebugMalloc(void)
  870. {
  871. _dump_allocated(0); /* print out debug malloc memory statistics */
  872. }
  873. #endif
  874. /******************************/
  875. /* Function version_local() */
  876. /******************************/
  877. void version_local()
  878. {
  879. static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
  880. #if defined(__IBMC__) || defined(__WATCOMC__) || defined(_MSC_VER)
  881. char buf[80];
  882. #endif
  883. printf(CompiledWith,
  884. #ifdef __GNUC__
  885. # ifdef __EMX__ /* __EMX__ is defined as "1" only (sigh) */
  886. "emx+gcc ", __VERSION__,
  887. # else
  888. "gcc/2 ", __VERSION__,
  889. # endif
  890. #elif defined(__IBMC__)
  891. "IBM ",
  892. # if (__IBMC__ < 200)
  893. (sprintf(buf, "C Set/2 %d.%02d", __IBMC__/100,__IBMC__%100), buf),
  894. # elif (__IBMC__ < 300)
  895. (sprintf(buf, "C Set++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
  896. # else
  897. (sprintf(buf, "Visual Age C++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
  898. # endif
  899. #elif defined(__WATCOMC__)
  900. "Watcom C", (sprintf(buf, " (__WATCOMC__ = %d)", __WATCOMC__), buf),
  901. #elif defined(__TURBOC__)
  902. # ifdef __BORLANDC__
  903. "Borland C++",
  904. # if (__BORLANDC__ < 0x0460)
  905. " 1.0",
  906. # elif (__BORLANDC__ == 0x0460)
  907. " 1.5",
  908. # else
  909. " 2.0",
  910. # endif
  911. # else
  912. "Turbo C",
  913. # if (__TURBOC__ >= 661)
  914. "++ 1.0 or later",
  915. # elif (__TURBOC__ == 661)
  916. " 3.0?",
  917. # elif (__TURBOC__ == 397)
  918. " 2.0",
  919. # else
  920. " 1.0 or 1.5?",
  921. # endif
  922. # endif
  923. #elif defined(MSC)
  924. "Microsoft C ",
  925. # ifdef _MSC_VER
  926. (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
  927. # else
  928. "5.1 or earlier",
  929. # endif
  930. #else
  931. "unknown compiler", "",
  932. #endif /* __GNUC__ */
  933. "OS/2",
  934. /* GRR: does IBM C/2 identify itself as IBM rather than Microsoft? */
  935. #if (defined(MSC) || (defined(__WATCOMC__) && !defined(__386__)))
  936. # if defined(M_I86HM) || defined(__HUGE__)
  937. " (16-bit, huge)",
  938. # elif defined(M_I86LM) || defined(__LARGE__)
  939. " (16-bit, large)",
  940. # elif defined(M_I86MM) || defined(__MEDIUM__)
  941. " (16-bit, medium)",
  942. # elif defined(M_I86CM) || defined(__COMPACT__)
  943. " (16-bit, compact)",
  944. # elif defined(M_I86SM) || defined(__SMALL__)
  945. " (16-bit, small)",
  946. # elif defined(M_I86TM) || defined(__TINY__)
  947. " (16-bit, tiny)",
  948. # else
  949. " (16-bit)",
  950. # endif
  951. #else
  952. " 2.x/3.x (32-bit)",
  953. #endif
  954. #ifdef __DATE__
  955. " on ", __DATE__
  956. #else
  957. "", ""
  958. #endif
  959. );
  960. /* temporary debugging code for Borland compilers only */
  961. #ifdef __TURBOC__
  962. printf("\t(__TURBOC__ = 0x%04x = %d)\n", __TURBOC__, __TURBOC__);
  963. #ifdef __BORLANDC__
  964. printf("\t(__BORLANDC__ = 0x%04x)\n",__BORLANDC__);
  965. #else
  966. printf("\tdebug(__BORLANDC__ not defined)\n");
  967. #endif
  968. #ifdef __TCPLUSPLUS__
  969. printf("\t(__TCPLUSPLUS__ = 0x%04x)\n", __TCPLUSPLUS__);
  970. #else
  971. printf("\tdebug(__TCPLUSPLUS__ not defined)\n");
  972. #endif
  973. #ifdef __BCPLUSPLUS__
  974. printf("\t(__BCPLUSPLUS__ = 0x%04x)\n\n", __BCPLUSPLUS__);
  975. #else
  976. printf("\tdebug(__BCPLUSPLUS__ not defined)\n\n");
  977. #endif
  978. #endif /* __TURBOC__ */
  979. } /* end function version_local() */
  980. #endif /* OS2 */