vms_pk.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. /*
  2. Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
  3. See the accompanying file LICENSE, version 2007-Mar-4 or later
  4. (the contents of which are also included in zip.h) for terms of use.
  5. If, for some reason, all these files are missing, the Info-ZIP license
  6. also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
  7. */
  8. /*
  9. * vms_pk.c by Igor Mandrichenko
  10. *
  11. * version 2.0 20-Mar-1993
  12. * Generates PKWARE version of VMS attributes
  13. * extra field according to appnote 2.0.
  14. * Uses low level QIO-ACP interface.
  15. * version 2.0-1 10-Apr-1993
  16. * Save ACLs
  17. * version 2.1 24-Aug-1993
  18. * By default produce 0x010C extra record ID instead of
  19. * PKWARE's 0x000C. The format is mostly compatible with
  20. * PKWARE.
  21. * Incompatibility (?): zip produces multiple ACE
  22. * fields.
  23. * version 2.1-1 Clean extra fields in vms_get_attributes().
  24. * Fixed bug with EOF.
  25. * version 2.1-2 15-Sep-1995, Chr. Spieler
  26. * Removed extra fields cleanup from vms_get_attributes().
  27. * This is now done in zipup.c
  28. * Modified (according to UnZip's vms.[ch]) the fib stuff
  29. * for DEC C (AXP,VAX) support.
  30. * version 2.2 28-Sep-1995, Chr. Spieler
  31. * Reorganized code for easier maintance of the two
  32. * incompatible flavours (IM style and PK style) VMS
  33. * attribute support. Generic functions (common to
  34. * both flavours) are now collected in a `wrapper'
  35. * source file that includes one of the VMS attribute
  36. * handlers.
  37. * Made extra block header conforming to PKware's
  38. * specification (extra block header has a length
  39. * of four bytes, two bytes for a signature, and two
  40. * bytes for the length of the block excluding this
  41. * header.
  42. * version 2.2-1 19-Oct-1995, Chr. Spieler
  43. * Fixed bug in CRC calculation.
  44. * Use official PK VMS extra field id.
  45. * version 2.2-2 21-Nov-1997, Chr. Spieler
  46. * Fixed bug in vms_get_attributes() for directory
  47. * entries (access to uninitialized ioctx record).
  48. * Removed unused second arg for vms_open().
  49. * version 2.2-3 04-Apr-1999, Chr. Spieler
  50. * Changed calling interface of vms_get_attributes()
  51. * to accept a void pointer as first argument.
  52. * version 2.2-4 26-Jan-2002, Chr. Spieler
  53. * Modified vms_read() to handle files larger than 2GByte
  54. * (up to size limit of "unsigned long", resp. 4GByte).
  55. * version 3.0 20-Oct-2004, Steven Schweda.
  56. * Changed vms_read() to read all the allocated
  57. * blocks in a file, for sure. Changed the default
  58. * chunk size from 16K to 32K. Changed to use the
  59. * new typedef for the ioctx structure. Moved the
  60. * VMS_PK_EXTRA test into here from VMS.C to allow
  61. * more general automatic dependency generation.
  62. * 08-Feb-2005, SMS.
  63. * Changed to accomodate ODS5 extended file names:
  64. * NAM structure -> NAM[L], and so on. (VMS.H.)
  65. * Added some should-never-appear error messages in
  66. * vms_open().
  67. */
  68. #ifdef VMS /* For VMS only ! */
  69. #ifdef VMS_PK_EXTRA
  70. #include <ssdef.h>
  71. #ifndef VMS_ZIP
  72. #define VMS_ZIP
  73. #endif
  74. #include "crc32.h"
  75. #include "vms.h"
  76. #include "vmsdefs.h"
  77. #ifndef ERR
  78. #define ERR(x) (((x)&1)==0)
  79. #endif
  80. #ifndef NULL
  81. #define NULL (void*)(0L)
  82. #endif
  83. #ifndef UTIL
  84. static PK_info_t PK_def_info =
  85. {
  86. ATR$C_RECATTR, ATR$S_RECATTR, {0},
  87. ATR$C_UCHAR, ATR$S_UCHAR, {0},
  88. ATR$C_CREDATE, ATR$S_CREDATE, {0},
  89. ATR$C_REVDATE, ATR$S_REVDATE, {0},
  90. ATR$C_EXPDATE, ATR$S_EXPDATE, {0},
  91. ATR$C_BAKDATE, ATR$S_BAKDATE, {0},
  92. ATR$C_ASCDATES, sizeof(ush), 0,
  93. ATR$C_UIC, ATR$S_UIC, {0},
  94. ATR$C_FPRO, ATR$S_FPRO, {0},
  95. ATR$C_RPRO, ATR$S_RPRO, {0},
  96. ATR$C_JOURNAL, ATR$S_JOURNAL, {0}
  97. };
  98. /* File description structure for Zip low level I/O */
  99. typedef struct
  100. {
  101. struct iosb iosb;
  102. long vbn;
  103. uzoff_t size;
  104. uzoff_t rest;
  105. int status;
  106. ush chan;
  107. ush chan_pad; /* alignment member */
  108. long acllen;
  109. uch aclbuf[ATR$S_READACL];
  110. PK_info_t PKi;
  111. } ioctx_t;
  112. /* Forward declarations of public functions: */
  113. ioctx_t *vms_open(char *file);
  114. unsigned int vms_read(register ioctx_t *ctx,
  115. register char *buf, register unsigned int size);
  116. int vms_error(ioctx_t *ctx);
  117. int vms_rewind(ioctx_t *ctx);
  118. int vms_get_attributes(ioctx_t *ctx, struct zlist far *z,
  119. iztimes *z_utim);
  120. int vms_close(ioctx_t *ctx);
  121. #define BLOCK_BYTES 512
  122. /*---------------*
  123. | vms_open() |
  124. *---------------*
  125. | This routine opens file for reading fetching its attributes.
  126. | Returns pointer to file description structure.
  127. */
  128. ioctx_t *vms_open(file)
  129. char *file;
  130. {
  131. static struct atrdef Atr[VMS_MAX_ATRCNT+1];
  132. static struct NAM_STRUCT Nam;
  133. static struct fibdef Fib;
  134. static struct dsc$descriptor FibDesc =
  135. {sizeof(Fib),DSC$K_DTYPE_Z,DSC$K_CLASS_S,(char *)&Fib};
  136. static struct dsc$descriptor_s DevDesc =
  137. {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,&Nam.NAM_DVI[1]};
  138. static char EName[NAM_MAXRSS];
  139. static char RName[NAM_MAXRSS];
  140. struct FAB Fab;
  141. register ioctx_t *ctx;
  142. register struct fatdef *fat;
  143. int status;
  144. int i;
  145. ulg efblk;
  146. ulg hiblk;
  147. if ( (ctx=(ioctx_t *)malloc(sizeof(ioctx_t))) == NULL )
  148. return NULL;
  149. ctx -> PKi = PK_def_info;
  150. #define FILL_REQ(ix,id,b) { \
  151. Atr[ix].atr$l_addr = GVTC &(b); \
  152. Atr[ix].atr$w_type = (id); \
  153. Atr[ix].atr$w_size = sizeof(b); \
  154. }
  155. FILL_REQ(0, ATR$C_RECATTR, ctx->PKi.ra);
  156. FILL_REQ(1, ATR$C_UCHAR, ctx->PKi.uc);
  157. FILL_REQ(2, ATR$C_REVDATE, ctx->PKi.rd);
  158. FILL_REQ(3, ATR$C_EXPDATE, ctx->PKi.ed);
  159. FILL_REQ(4, ATR$C_CREDATE, ctx->PKi.cd);
  160. FILL_REQ(5, ATR$C_BAKDATE, ctx->PKi.bd);
  161. FILL_REQ(6, ATR$C_ASCDATES, ctx->PKi.rn);
  162. FILL_REQ(7, ATR$C_JOURNAL, ctx->PKi.jr);
  163. FILL_REQ(8, ATR$C_RPRO, ctx->PKi.rp);
  164. FILL_REQ(9, ATR$C_FPRO, ctx->PKi.fp);
  165. FILL_REQ(10,ATR$C_UIC, ctx->PKi.ui);
  166. FILL_REQ(11,ATR$C_ACLLENGTH,ctx->acllen);
  167. FILL_REQ(12,ATR$C_READACL, ctx->aclbuf);
  168. Atr[13].atr$w_type = 0; /* End of ATR list */
  169. Atr[13].atr$w_size = 0;
  170. Atr[13].atr$l_addr = GVTC NULL;
  171. /* Initialize RMS structures. We need a NAM[L] to retrieve the FID. */
  172. Fab = cc$rms_fab;
  173. Nam = CC_RMS_NAM;
  174. Fab.FAB_NAM = &Nam; /* FAB has an associated NAM[L]. */
  175. #ifdef NAML$C_MAXRSS
  176. Fab.fab$l_dna =(char *) -1; /* Using NAML for default name. */
  177. Fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
  178. #endif /* def NAML$C_MAXRSS */
  179. FAB_OR_NAML( Fab, Nam).FAB_OR_NAML_FNA = file ; /* File name. */
  180. FAB_OR_NAML( Fab, Nam).FAB_OR_NAML_FNS = strlen(file);
  181. Nam.NAM_ESA = EName; /* expanded filename */
  182. Nam.NAM_ESS = sizeof(EName);
  183. Nam.NAM_RSA = RName; /* resultant filename */
  184. Nam.NAM_RSS = sizeof(RName);
  185. /* Do $PARSE and $SEARCH here. */
  186. status = sys$parse(&Fab);
  187. if (!(status & 1))
  188. {
  189. fprintf( stderr,
  190. " vms_open(): $parse sts = %%x%08x.\n", status);
  191. return NULL;
  192. }
  193. #ifdef NAML$M_OPEN_SPECIAL
  194. /* 2007-02-28 SMS.
  195. * If processing symlinks as symlinks ("-y"), then $SEARCH for the
  196. * link, not the target file.
  197. */
  198. if (linkput)
  199. {
  200. Nam.naml$v_open_special = 1;
  201. }
  202. #endif /* def NAML$M_OPEN_SPECIAL */
  203. /* Search for the first file. If none, signal error. */
  204. status = sys$search(&Fab);
  205. if (!(status & 1))
  206. {
  207. fprintf( stderr,
  208. " vms_open(): $search sts = %%x%08x.\n", status);
  209. return NULL;
  210. }
  211. /* Initialize Device name length. Note that this points into the
  212. NAM[L] to get the device name filled in by the $PARSE, $SEARCH
  213. services.
  214. */
  215. DevDesc.dsc$w_length = Nam.NAM_DVI[0];
  216. status = sys$assign(&DevDesc,&ctx->chan,0,0);
  217. if (!(status & 1))
  218. {
  219. fprintf( stderr,
  220. " vms_open(): $assign sts = %%x%08x.\n", status);
  221. return NULL;
  222. }
  223. /* Move the FID (and not the DID) into the FIB.
  224. 2005=02-08 SMS.
  225. Note that only the FID is needed, not the DID, and not the file
  226. name. Setting these other items causes failures on ODS5.
  227. */
  228. Fib.FIB$L_ACCTL = FIB$M_NOWRITE;
  229. for (i = 0; i < 3; i++)
  230. {
  231. Fib.FIB$W_FID[ i] = Nam.NAM_FID[ i];
  232. Fib.FIB$W_DID[ i] = 0;
  233. }
  234. /* Use the IO$_ACCESS function to return info about the file. */
  235. status = sys$qiow( 0, ctx->chan,
  236. (IO$_ACCESS| IO$M_ACCESS), &ctx->iosb, 0, 0,
  237. &FibDesc, 0, 0, 0, Atr, 0);
  238. if (ERR(status) || ERR(status = ctx->iosb.status))
  239. {
  240. vms_close(ctx);
  241. fprintf( stderr,
  242. " vms_open(): $qiow (access) sts = %%x%08x, iosb sts = %%x%08x.\n",
  243. status, ctx->iosb.status);
  244. return NULL;
  245. }
  246. fat = (struct fatdef *)&(ctx -> PKi.ra);
  247. #define SWAPW(x) ( (((x)>>16)&0xFFFF) + ((x)<<16) )
  248. efblk = SWAPW(fat->fat$l_efblk);
  249. hiblk = SWAPW(fat->fat$l_hiblk);
  250. if (efblk == 0)
  251. {
  252. /* Only known size is all allocated blocks.
  253. (This occurs with a zero-length file, for example.)
  254. */
  255. ctx -> size =
  256. ctx -> rest = ((uzoff_t) hiblk)* BLOCK_BYTES;
  257. }
  258. else
  259. {
  260. /* Store normal (used) size in ->size.
  261. If only one -V, store normal (used) size in ->rest.
  262. If multiple -V, store allocated-blocks size in ->rest.
  263. */
  264. ctx -> size =
  265. (((uzoff_t) efblk)- 1)* BLOCK_BYTES+ fat -> fat$w_ffbyte;
  266. if (vms_native < 2)
  267. ctx -> rest = ctx -> size;
  268. else
  269. ctx -> rest = ((uzoff_t) hiblk)* BLOCK_BYTES;
  270. }
  271. ctx -> status = SS$_NORMAL;
  272. ctx -> vbn = 1;
  273. return ctx;
  274. }
  275. #define KByte (2* BLOCK_BYTES)
  276. #define MAX_READ_BYTES (32* KByte)
  277. /*----------------*
  278. | vms_read() |
  279. *----------------*
  280. | Reads file in (multi-)block-sized chunks into the buffer.
  281. | Stops on EOF. Returns number of bytes actually read.
  282. | Note: This function makes no sense (and will error) if the buffer
  283. | size ("size") is not a multiple of the disk block size (512).
  284. */
  285. size_t vms_read( ctx, buf, size)
  286. ioctx_t *ctx;
  287. char *buf;
  288. size_t size;
  289. {
  290. int act_cnt;
  291. uzoff_t rest_rndup;
  292. int status;
  293. size_t bytes_read = 0;
  294. /* If previous read hit EOF, fail early. */
  295. if (ctx -> status == SS$_ENDOFFILE)
  296. return 0; /* EOF. */
  297. /* If no more expected to be read, fail early. */
  298. if (ctx -> rest == 0)
  299. return 0; /* Effective EOF. */
  300. /* If request is smaller than a whole block, fail.
  301. This really should never happen. (assert()?)
  302. */
  303. if (size < BLOCK_BYTES)
  304. return 0;
  305. /* Note that on old VMS VAX versions (like V5.5-2), QIO[W] may fail
  306. with status %x0000034c (= %SYSTEM-F-IVBUFLEN, invalid buffer
  307. length) when size is not a multiple of 512. Thus the requested
  308. size is boosted as needed, but the IOSB byte count returned is
  309. reduced when it exceeds the actual bytes remaining (->rest).
  310. */
  311. /* Adjust request size as appropriate. */
  312. if (size > MAX_READ_BYTES)
  313. {
  314. /* Restrict request to MAX_READ_BYTES. */
  315. size = MAX_READ_BYTES;
  316. }
  317. else
  318. {
  319. /* Round odd-ball request up to the next whole block.
  320. This really should never happen. (assert()?)
  321. */
  322. size = (size+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
  323. }
  324. rest_rndup = (ctx -> rest+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
  325. /* Read (QIOW) until error or "size" bytes have been read. */
  326. do
  327. {
  328. /* Reduce "size" when next (last) read would overrun the EOF,
  329. but never below one block (so we'll always get a nice EOF).
  330. */
  331. if (size > rest_rndup)
  332. size = rest_rndup;
  333. status = sys$qiow( 0, ctx->chan, IO$_READVBLK,
  334. &ctx->iosb, 0, 0,
  335. buf, size, ctx->vbn, 0, 0, 0);
  336. /* If initial status was good, use final status. */
  337. if ( !ERR(status) )
  338. status = ctx->iosb.status;
  339. if ( !ERR(status) || status == SS$_ENDOFFILE )
  340. {
  341. act_cnt = ctx->iosb.count;
  342. /* Ignore whole-block boost when remainder is smaller. */
  343. if (act_cnt > ctx->rest)
  344. {
  345. act_cnt = ctx->rest;
  346. status = SS$_ENDOFFILE;
  347. }
  348. /* Adjust counters/pointers according to delivered bytes. */
  349. size -= act_cnt;
  350. buf += act_cnt;
  351. bytes_read += act_cnt;
  352. ctx->vbn += ctx->iosb.count/ BLOCK_BYTES;
  353. }
  354. } while ( !ERR(status) && (size > 0) );
  355. if (!ERR(status))
  356. {
  357. /* Record any successful status as SS$_NORMAL. */
  358. ctx -> status = SS$_NORMAL;
  359. }
  360. else if (status == SS$_ENDOFFILE)
  361. {
  362. /* Record EOF as SS$_ENDOFFILE. (Ignore error status codes?) */
  363. ctx -> status = SS$_ENDOFFILE;
  364. }
  365. /* Decrement bytes-to-read. Return the total bytes read. */
  366. ctx -> rest -= bytes_read;
  367. return bytes_read;
  368. }
  369. /*-----------------*
  370. | vms_error() |
  371. *-----------------*
  372. | Returns whether last operation on the file caused an error
  373. */
  374. int vms_error(ctx)
  375. ioctx_t *ctx;
  376. { /* EOF is not actual error */
  377. return ERR(ctx->status) && (ctx->status != SS$_ENDOFFILE);
  378. }
  379. /*------------------*
  380. | vms_rewind() |
  381. *------------------*
  382. | Rewinds file to the beginning for the next vms_read().
  383. */
  384. int vms_rewind(ctx)
  385. ioctx_t *ctx;
  386. {
  387. ctx -> vbn = 1;
  388. ctx -> rest = ctx -> size;
  389. return 0;
  390. }
  391. /*--------------------------*
  392. | vms_get_attributes() |
  393. *--------------------------*
  394. | Malloc a PKWARE extra field and fill with file attributes. Returns
  395. | error number of the ZE_??? class.
  396. | If the passed ioctx record "FILE *" pointer is NULL, vms_open() is
  397. | called to fetch the file attributes.
  398. | When `vms_native' is not set, a generic "UT" type timestamp extra
  399. | field is generated instead.
  400. |
  401. | 2004-11-11 SMS.
  402. | Changed to use separate storage for ->extra and ->cextra. Zip64
  403. | processing may move (reallocate) one and not the other.
  404. */
  405. int vms_get_attributes(ctx, z, z_utim)
  406. ioctx_t *ctx; /* Internal file control structure. */
  407. struct zlist far *z; /* Zip entry to compress. */
  408. iztimes *z_utim;
  409. {
  410. byte *p;
  411. byte *xtra;
  412. byte *cxtra;
  413. struct PK_header *h;
  414. extent l;
  415. int notopened;
  416. if ( !vms_native )
  417. {
  418. #ifdef USE_EF_UT_TIME
  419. /*
  420. * A `portable' zipfile entry is created. Create an "UT" extra block
  421. * containing UNIX style modification time stamp in UTC, which helps
  422. * maintaining the `real' "last modified" time when the archive is
  423. * transfered across time zone boundaries.
  424. */
  425. # ifdef IZ_CHECK_TZ
  426. if (!zp_tz_is_valid)
  427. return ZE_OK; /* skip silently if no valid TZ info */
  428. # endif
  429. if ((xtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
  430. return ZE_MEM;
  431. if ((cxtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
  432. return ZE_MEM;
  433. /* Fill xtra[] with data. */
  434. xtra[ 0] = 'U';
  435. xtra[ 1] = 'T';
  436. xtra[ 2] = EB_UT_LEN(1); /* length of data part of e.f. */
  437. xtra[ 3] = 0;
  438. xtra[ 4] = EB_UT_FL_MTIME;
  439. xtra[ 5] = (byte) (z_utim->mtime);
  440. xtra[ 6] = (byte) (z_utim->mtime >> 8);
  441. xtra[ 7] = (byte) (z_utim->mtime >> 16);
  442. xtra[ 8] = (byte) (z_utim->mtime >> 24);
  443. /* Copy xtra[] data into cxtra[]. */
  444. memcpy( cxtra, xtra, (EB_HEADSIZE+ EB_UT_LEN( 1)));
  445. /* Set sizes and pointers. */
  446. z->cext = z->ext = (EB_HEADSIZE+ EB_UT_LEN( 1));
  447. z->extra = (char*) xtra;
  448. z->cextra = (char*) cxtra;
  449. #endif /* USE_EF_UT_TIME */
  450. return ZE_OK;
  451. }
  452. notopened = (ctx == NULL);
  453. if ( notopened && ((ctx = vms_open(z->name)) == NULL) )
  454. return ZE_OPEN;
  455. l = PK_HEADER_SIZE + sizeof(ctx->PKi);
  456. if (ctx->acllen > 0)
  457. l += PK_FLDHDR_SIZE + ctx->acllen;
  458. if ((xtra = (uch *) malloc( l)) == NULL)
  459. return ZE_MEM;
  460. if ((cxtra = (uch *) malloc( l)) == NULL)
  461. return ZE_MEM;
  462. /* Fill xtra[] with data. */
  463. h = (struct PK_header *) xtra;
  464. h->tag = PK_SIGNATURE;
  465. h->size = l - EB_HEADSIZE;
  466. p = (h->data);
  467. /* Copy default set of attributes */
  468. memcpy(h->data, (char*)&(ctx->PKi), sizeof(ctx->PKi));
  469. p += sizeof(ctx->PKi);
  470. if ( ctx->acllen > 0 )
  471. {
  472. struct PK_field *f;
  473. if (dosify)
  474. zipwarn("file has ACL, may be incompatible with PKUNZIP","");
  475. f = (struct PK_field *)p;
  476. f->tag = ATR$C_ADDACLENT;
  477. f->size = ctx->acllen;
  478. memcpy((char *)&(f->value[0]), ctx->aclbuf, ctx->acllen);
  479. p += PK_FLDHDR_SIZE + ctx->acllen;
  480. }
  481. h->crc32 = CRCVAL_INITIAL; /* Init CRC register */
  482. h->crc32 = crc32(h->crc32, (uch *)(h->data), l - PK_HEADER_SIZE);
  483. /* Copy xtra[] data into cxtra[]. */
  484. memcpy( cxtra, xtra, l);
  485. /* Set sizes and pointers. */
  486. z->ext = z->cext = l;
  487. z->extra = (char *) xtra;
  488. z->cextra = (char *) cxtra;
  489. if (notopened) /* close "ctx", if we have opened it here */
  490. vms_close(ctx);
  491. return ZE_OK;
  492. }
  493. int vms_close(ctx)
  494. ioctx_t *ctx;
  495. {
  496. sys$dassgn(ctx->chan);
  497. free(ctx);
  498. return 0;
  499. }
  500. #endif /* !_UTIL */
  501. #endif /* def VMS_PK_EXTRA */
  502. #endif /* VMS */