📄 zipfile.c
字号:
PUTLG(z->tim, f); PUTLG(z->crc, f); PUTLG(z->siz, f); PUTLG(z->len, f); PUTSH(z->nam, f); PUTSH(z->cext, f); PUTSH(z->com, f); PUTSH(z->dsk, f); PUTSH(z->att, f); PUTLG(z->atx, f); PUTLG(z->off, f);#ifdef EBCDIC if (z->com) memtoasc(z->comment, z->comment, z->com);#endif /* EBCDIC */ if (fwrite(z->iname, 1, z->nam, f) != z->nam || (z->cext && fwrite(z->cextra, 1, z->cext, f) != z->cext) || (z->com && fwrite(z->comment, 1, z->com, f) != z->com)) return ZE_TEMP; return ZE_OK;}int putend(n, s, c, m, z, f)unsigned n; /* number of entries in central directory */ulg s; /* size of central directory */ulg c; /* offset of central directory */extent m; /* length of zip file comment (0 if none) */char *z; /* zip file comment if m != 0 */FILE *f; /* file to write to *//* Write the end of central directory data to file *f. Return an error code in the ZE_ class. */{ PUTLG(ENDSIG, f); PUTSH(0, f); PUTSH(0, f); PUTSH(n, f); PUTSH(n, f); PUTLG(s, f); PUTLG(c, f); PUTSH(m, f);/* Write the comment, if any */#ifdef EBCDIC memtoasc(z, z, m);#endif if (m && fwrite(z, 1, m, f) != m) return ZE_TEMP;#ifdef HANDLE_AMIGA_SFX if (amiga_sfx_offset && zipbeg /* -J zeroes this */) { s = ftell(f); while (s & 3) s++, putc(0, f); /* final marker must be longword aligned */ PUTLG(0xF2030000 /* 1010 in Motorola byte order */, f); c = (s - amiga_sfx_offset - 4) / 4; /* size of archive part in longwords */ if (fseek(f, amiga_sfx_offset, SEEK_SET) != 0) return ZE_TEMP; c = ((c >> 24) & 0xFF) | ((c >> 8) & 0xFF00) | ((c & 0xFF00) << 8) | ((c & 0xFF) << 24); /* invert byte order */ PUTLG(c, f); fseek(f, 0, SEEK_END); /* just in case */ }#endif return ZE_OK;}/* Note: a zip "entry" includes a local header (which includes the file name), an encryption header if encrypting, the compressed data and possibly an extended local header. */int zipcopy(z, x, y)struct zlist far *z; /* zip entry to copy */FILE *x, *y; /* source and destination files *//* Copy the zip entry described by *z from file *x to file *y. Return an error code in the ZE_ class. Also update tempzn by the number of bytes copied. */{ ulg n; /* holds local header offset */ Trace((stderr, "zipcopy %s\n", z->zname)); n = (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext; if (fix > 1) { if (fseek(x, z->off + n, SEEK_SET)) /* seek to compressed data */ return ferror(x) ? ZE_READ : ZE_EOF; if (fix > 2) { /* Update length of entry's name, it may have been changed. This is needed to support the ZipNote ability to rename archive entries. */ z->nam = strlen(z->iname); n = (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext; } /* do not trust the old compressed size */ if (putlocal(z, y) != ZE_OK) return ZE_TEMP; z->off = tempzn; tempzn += n; n = z->siz; } else { if (fseek(x, z->off, SEEK_SET)) /* seek to local header */ return ferror(x) ? ZE_READ : ZE_EOF; z->off = tempzn; n += z->siz; } /* copy the compressed data and the extended local header if there is one */ if (z->lflg & 8) n += 16; tempzn += n; return fcopy(x, y, n);}#ifndef UTIL#ifdef USE_EF_UT_TIMElocal int ef_scan_ut_time(ef_buf, ef_len, ef_is_cent, z_utim)char *ef_buf; /* buffer containing extra field */extent ef_len; /* total length of extra field */int ef_is_cent; /* flag indicating "is central extra field" */iztimes *z_utim; /* return storage: atime, mtime, ctime *//* This function scans the extra field for EF_TIME or EF_IZUNIX blocks * containing Unix style time_t (GMT) values for the entry's access, creation * and modification time. * If a valid block is found, all time stamps are copied to the iztimes * structure. * The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring * all data from probably present obsolete EF_IZUNIX blocks. * If multiple blocks of the same type are found, only the information from * the last block is used. * The return value is the EF_TIME Flags field (simulated in case of an * EF_IZUNIX block) or 0 in case of failure. */{ int flags = 0; unsigned eb_id; extent eb_len; int have_new_type_eb = FALSE; if (ef_len == 0 || ef_buf == NULL) return 0; Trace((stderr,"\nef_scan_ut_time: scanning extra field of length %u\n", ef_len)); while (ef_len >= EB_HEADSIZE) { eb_id = SH(EB_ID + ef_buf); eb_len = SH(EB_LEN + ef_buf); if (eb_len > (ef_len - EB_HEADSIZE)) { /* Discovered some extra field inconsistency! */ Trace((stderr,"ef_scan_ut_time: block length %u > rest ef_size %u\n", eb_len, ef_len - EB_HEADSIZE)); break; } switch (eb_id) { case EF_TIME: flags &= ~0x00ff; /* ignore previous IZUNIX or EF_TIME fields */ have_new_type_eb = TRUE; if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) { unsigned eb_idx = EB_UT_TIME1; Trace((stderr,"ef_scan_ut_time: Found TIME extra field\n")); flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x00ff); if ((flags & EB_UT_FL_MTIME)) { if ((eb_idx+4) <= eb_len) { z_utim->mtime = LG((EB_HEADSIZE+eb_idx) + ef_buf); eb_idx += 4; Trace((stderr," Unix EF modtime = %ld\n", z_utim->mtime)); } else { flags &= ~EB_UT_FL_MTIME; Trace((stderr," Unix EF truncated, no modtime\n")); } } if (ef_is_cent) { break; /* central version of TIME field ends here */ } if (flags & EB_UT_FL_ATIME) { if ((eb_idx+4) <= eb_len) { z_utim->atime = LG((EB_HEADSIZE+eb_idx) + ef_buf); eb_idx += 4; Trace((stderr," Unix EF acctime = %ld\n", z_utim->atime)); } else { flags &= ~EB_UT_FL_ATIME; } } if (flags & EB_UT_FL_CTIME) { if ((eb_idx+4) <= eb_len) { z_utim->ctime = LG((EB_HEADSIZE+eb_idx) + ef_buf); /* eb_idx += 4; */ /* superfluous for now ... */ Trace((stderr," Unix EF cretime = %ld\n", z_utim->ctime)); } else { flags &= ~EB_UT_FL_CTIME; } } } break; case EF_IZUNIX2: if (!have_new_type_eb) { flags &= ~0x00ff; /* ignore any previous IZUNIX field */ have_new_type_eb = TRUE; } break; case EF_IZUNIX: if (eb_len >= EB_UX_MINLEN) { Trace((stderr,"ef_scan_ut_time: Found IZUNIX extra field\n")); if (have_new_type_eb) { break; /* Ignore IZUNIX extra field block ! */ } z_utim->atime = LG((EB_HEADSIZE+EB_UX_ATIME) + ef_buf); z_utim->mtime = LG((EB_HEADSIZE+EB_UX_MTIME) + ef_buf); Trace((stderr," Unix EF access time = %ld\n",z_utim->atime)); Trace((stderr," Unix EF modif. time = %ld\n",z_utim->mtime)); flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME); /* signal success */ } break; case EF_THEOS:/* printf("Not implemented yet\n"); */ break; default: break; } /* Skip this extra field block */ ef_buf += (eb_len + EB_HEADSIZE); ef_len -= (eb_len + EB_HEADSIZE); } return flags;}int get_ef_ut_ztime(z, z_utim)struct zlist far *z;iztimes *z_utim;{ int r;#ifdef IZ_CHECK_TZ if (!zp_tz_is_valid) return 0;#endif /* First, scan local extra field. */ r = ef_scan_ut_time(z->extra, z->ext, FALSE, z_utim); /* If this was not successful, try central extra field, but only if it is really different. */ if (!r && z->cext > 0 && z->cextra != z->extra) r = ef_scan_ut_time(z->cextra, z->cext, TRUE, z_utim); return r;}#endif /* USE_EF_UT_TIME */local void cutpath(p, delim)char *p; /* path string */int delim; /* path component separator char *//* Cut the last path component off the name *p in place. * This should work on both internal and external names. */{ char *r; /* pointer to last path delimiter */#ifdef VMS /* change [w.x.y]z to [w.x]y.DIR */ if ((r = MBSRCHR(p, ']')) != NULL) { *r = 0; if ((r = MBSRCHR(p, '.')) != NULL) { *r = ']'; strcat(r, ".DIR;1"); /* this assumes a little padding--see PAD */ } else { *p = 0; } } else { if ((r = MBSRCHR(p, delim)) != NULL) *r = 0; else *p = 0; }#else /* !VMS */ if ((r = MBSRCHR(p, delim)) != NULL) *r = 0; else *p = 0;#endif /* ?VMS */}int trash()/* Delete the compressed files and the directories that contained the deleted files, if empty. Return an error code in the ZE_ class. Failure of destroy() or deletedir() is ignored. */{ extent i; /* counter on deleted names */ extent n; /* number of directories to delete */ struct zlist far **s; /* table of zip entries to handle, sorted */ struct zlist far *z; /* current zip entry */ /* Delete marked names and count directories */ n = 0; for (z = zfiles; z != NULL; z = z->nxt) if (z->mark == 1 || z->trash) { z->mark = 1; if (z->iname[z->nam - 1] != (char)0x2f) { /* don't unlink directory */ if (verbose) fprintf(mesg, "zip diagnostic: deleting file %s\n", z->name); if (destroy(z->name)) { zipwarn("error deleting ", z->name); } /* Try to delete all paths that lead up to marked names. This is * necessary only with the -D option. */ if (!dirnames) { cutpath(z->name, '/'); /* XXX wrong ??? */ cutpath(z->iname, 0x2f); /* 0x2f = ascii['/'] */ z->nam = strlen(z->iname); if (z->nam > 0) { z->iname[z->nam - 1] = (char)0x2f; z->iname[z->nam++] = '\0'; } if (z->nam > 0) n++; } } else { n++; } } /* Construct the list of all marked directories. Some may be duplicated * if -D was used. */ if (n) { if ((s = (struct zlist far **)malloc(n*sizeof(struct zlist far *))) == NULL) return ZE_MEM; n = 0; for (z = zfiles; z != NULL; z = z->nxt) { if (z->mark && z->nam > 0 && z->iname[z->nam - 1] == (char)0x2f /* '/' */ && (n == 0 || strcmp(z->name, s[n-1]->name) != 0)) { s[n++] = z; } } /* Sort the files in reverse order to get subdirectories first. * To avoid problems with strange naming conventions as in VMS, * we sort on the internal names, so x/y/z will always be removed * before x/y. On VMS, x/y/z > x/y but [x.y.z] < [x.y] */ qsort((char *)s, n, sizeof(struct zlist far *), rqcmp); for (i = 0; i < n; i++) { char *p = s[i]->name; if (*p == '\0') continue; if (p[strlen(p) - 1] == '/') { /* keep VMS [x.y]z.dir;1 intact */ p[strlen(p) - 1] = '\0'; } if (i == 0 || strcmp(s[i]->name, s[i-1]->name) != 0) { if (verbose) { fprintf(mesg, "deleting directory %s (if empty) \n", s[i]->name); } deletedir(s[i]->name); } } free((zvoid *)s); } return ZE_OK;}#endif /* !UTIL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -