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