Wolfgang Thallergcc16 merge934c3885 months agoHistory
505 lines · 15.8 KB · C++
RawDownload
/* Copyright (C) 2021-2026 Free Software Foundation, Inc.   Contributed by Oracle.    This file is part of GNU Binutils.    This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3, or (at your option)   any later version.    This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.    You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, 51 Franklin Street - Fifth Floor, Boston,   MA 02110-1301, USA.  */ #include "config.h"#include <sys/types.h>#include <fcntl.h>#include <unistd.h>#include <errno.h> #include "zlib.h"#include "util.h"#include "DbeJarFile.h"#include "Data_window.h"#include "vec.h" static uint32_tget_u1 (unsigned char *b){  return (uint32_t) ((b)[0]);} static uint32_tget_u2 (unsigned char *b){  return (get_u1 (b + 1) << 8) | get_u1 (b);} static uint32_tget_u4 (unsigned char *b){  return (get_u2 (b + 2) << 16) | get_u2 (b);} static uint64_tget_u8 (unsigned char *b){  return (((uint64_t) get_u4 (b + 4)) << 32) | get_u4 (b);} enum{  END_CENT_DIR_SIZE     = 22,  LOC_FILE_HEADER_SIZE  = 30,  CENT_FILE_HEADER_SIZE = 46,  ZIP64_LOCATOR_SIZE    = 20,  ZIP64_CENT_DIR_SIZE   = 56,  ZIP_BUF_SIZE          = 65536}; struct EndCentDir{  uint64_t count;  uint64_t size;  uint64_t offset;}; class ZipEntry{public:   ZipEntry ()  {    name = NULL;    data_offset = 0;  }   ~ZipEntry ()  {    free (name);  }   int  compare (ZipEntry *ze)  {    return dbe_strcmp (name, ze->name);  }   char *name;       // entry name  int time;         // modification time  int64_t size;     // size of uncompressed data  int64_t csize;    // size of compressed data (zero if uncompressed)  uint32_t compressionMethod;  int64_t offset;   // offset of LOC header  int64_t data_offset;}; static intcmp_names (const void *a, const void *b){  ZipEntry *e1 = *((ZipEntry **) a);  ZipEntry *e2 = *((ZipEntry **) b);  return e1->compare (e2);} template<> void Vector<ZipEntry *>::dump (const char *msg){  Dprintf (1, NTXT ("Vector<ZipEntry *> %s  [%lld]\n"), msg ? msg : NTXT (""), (long long) size ());  for (long i = 0, sz = size (); i < sz; i++)    {      ZipEntry *ze = get (i);      Dprintf (1, NTXT ("  %lld offset:%lld (0x%llx) size: %lld --> %lld %s\n"),	       (long long) i, (long long) ze->offset, (long long) ze->offset,	       (long long) ze->csize, (long long) ze->size, STR (ze->name));    }} DbeJarFile::DbeJarFile (const char *jarName){  name = xstrdup (jarName);  fnames = NULL;  dwin = new Data_window (name);  get_entries ();} DbeJarFile::~DbeJarFile (){  free (name);  delete fnames;} voidDbeJarFile::get_entries (){  Dprintf (DUMP_JAR_FILE, NTXT ("\nArchive: %s\n"), STR (name));  if (dwin->not_opened ())    {      append_msg (CMSG_ERROR, GTXT ("Cannot open file `%s'"), name);      return;    }  struct EndCentDir endCentDir;  if (get_EndCentDir (&endCentDir) == 0)    return;   if (endCentDir.count == 0)    {      append_msg (CMSG_WARN, GTXT ("No files in %s"), name);      return;    }  unsigned char *b = (unsigned char *) dwin->bind (endCentDir.offset, endCentDir.size);  if (b == NULL)    {      append_msg (CMSG_ERROR, GTXT ("%s: cannot read the central directory record"), name);      return;    }   fnames = new Vector<ZipEntry*>(endCentDir.count);  for (uint64_t i = 0, offset = endCentDir.offset, last = endCentDir.offset + endCentDir.size; i < endCentDir.count; i++)    {      if ((last - offset) < CENT_FILE_HEADER_SIZE)	{	  append_msg (CMSG_ERROR, GTXT ("%s: cannot read the central file header (%lld (from %lld), offset=0x%016llx last=0x%016llx"),		      name, (long long) i, (long long) endCentDir.count, (long long) offset, (long long) last);	  break;	}      b = (unsigned char *) dwin->bind (offset, CENT_FILE_HEADER_SIZE);      //  Central file header      //  Offset Bytes    Description      //     0     4   central file header signature = 0x02014b50      //     4     2   version made by      //     6     2   version needed to extract      //     8     2   general purpose bit flag      //    10     2   compression method      //    12     2   last mod file time      //    14     2   last mod file date      //    16     4   crc-32      //    20     4   compressed size      //    24     4   uncompressed size      //    28     2   file name length      //    30     2   extra field length      //    32     2   file comment length      //    34     2   disk number start      //    36     2   internal file attributes      //    38     4   external file attributes      //    42     4   relative offset of local header      //    46         file name (variable size)      //               extra field (variable size)      //               file comment (variable size)      uint32_t signature = get_u4 (b);      if (signature != 0x02014b50)	{	  append_msg (CMSG_ERROR, GTXT ("%s: wrong header signature (%lld (total %lld), offset=0x%016llx last=0x%016llx"),		      name, (long long) i, (long long) endCentDir.count, (long long) offset, (long long) last);	  break;	}      ZipEntry *ze = new ZipEntry ();      fnames->append (ze);      uint32_t name_len = get_u2 (b + 28);      uint32_t extra_len = get_u2 (b + 30);      uint32_t comment_len = get_u2 (b + 32);      ze->compressionMethod = get_u2 (b + 10);      ze->csize = get_u4 (b + 20);      ze->size = get_u4 (b + 24);      ze->offset = get_u4 (b + 42);      char *nm = (char *) dwin->bind (offset + 46, name_len);      if (nm)	{	  ze->name = (char *) xmalloc (name_len + 1);	  strncpy (ze->name, nm, name_len);	  ze->name[name_len] = 0;	}      offset += CENT_FILE_HEADER_SIZE + name_len + extra_len + comment_len;    }  fnames->sort (cmp_names);  if (DUMP_JAR_FILE)    fnames->dump (get_basename (name));} intDbeJarFile::get_entry (const char *fname){  if (fnames == NULL)    return -1;  ZipEntry zipEntry, *ze = &zipEntry;  ze->name = (char *) fname;  int ind = fnames->bisearch (0, -1, &ze, cmp_names);  ze->name = NULL;  return ind;} long longDbeJarFile::copy (char *toFileNname, int fromEntryNum){  if (fromEntryNum < 0 || fromEntryNum >= VecSize (fnames))    return -1;  ZipEntry *ze = fnames->get (fromEntryNum);  if (ze->data_offset == 0)    {      //  Local file header      //  Offset Bytes    Description      //     0     4   local file header signature = 0x04034b50      //     4     2   version needed to extract      //     6     2   general purpose bit flag      //     8     2   compression method      //    10     2   last mod file time      //    12     2   last mod file date      //    14     4   crc-32      //    18     4   compressed size      //    22     4   uncompressed size      //    26     2   file name length      //    28     2   extra field length      //    30     2   file name (variable size)      //               extra field (variable size)      unsigned char *b = (unsigned char *) dwin->bind (ze->offset, LOC_FILE_HEADER_SIZE);      if (b == NULL)	{	  append_msg (CMSG_ERROR,		 GTXT ("%s: Cannot read a local file header (%s offset=0x%lld"),		 name, STR (ze->name), (long long) ze->offset);	  return -1;	}      uint32_t signature = get_u4 (b);      if (signature != 0x04034b50)	{	  append_msg (CMSG_ERROR,		      GTXT ("%s: wrong local header signature ('%s' offset=%lld (0x%llx)"),		      name, STR (ze->name), (long long) ze->offset,		      (long long) ze->offset);	  return -1;	}      ze->data_offset = ze->offset + LOC_FILE_HEADER_SIZE + get_u2 (b + 26) + get_u2 (b + 28);    }   if (ze->compressionMethod == 0)    {      int fd = open (toFileNname, O_CREAT | O_WRONLY | O_LARGEFILE, 0644);      if (fd == -1)	{	  append_msg (CMSG_ERROR, GTXT ("Cannot create file %s (%s)"), toFileNname, STR (strerror (errno)));	  return -1;	}      long long len = dwin->copy_to_file (fd, ze->data_offset, ze->size);      close (fd);      if (len != ze->size)	{	  append_msg (CMSG_ERROR, GTXT ("%s: Cannot write %lld bytes (only %lld)"),		      toFileNname, (long long) ze->size, (long long) len);	  unlink (toFileNname);	  return -1;	}      return len;    }   unsigned char *b = (unsigned char *) dwin->bind (ze->data_offset, ze->csize);  if (b == NULL)    {      append_msg (CMSG_ERROR,		  GTXT ("%s: Cannot extract file %s (offset=0x%lld csize=%lld)"),		  name, STR (ze->name), (long long) ze->offset,		  (long long) ze->csize);      return -1;    }  z_stream strm;  strm.zalloc = Z_NULL;  strm.zfree = Z_NULL;  strm.opaque = Z_NULL;  strm.next_in = Z_NULL;  strm.avail_in = 0;  if (inflateInit2 (&strm, -MAX_WBITS) != Z_OK)    {      append_msg (CMSG_ERROR, GTXT ("%s: inflateInit2 failed (%s)"), STR (ze->name), STR (strm.msg));      return -1;    }  strm.avail_in = ze->csize;  strm.next_in = b;  int retval = ze->size;  unsigned char *buf = (unsigned char *) xmalloc (ze->size);  for (;;)    {      strm.next_out = buf;      strm.avail_out = ze->size;      int ret = inflate (&strm, Z_SYNC_FLUSH);      if ((ret == Z_NEED_DICT) || (ret == Z_DATA_ERROR) || (ret == Z_MEM_ERROR) || (ret == Z_STREAM_ERROR))	{	  append_msg (CMSG_ERROR, GTXT ("%s: inflate('%s') error %d (%s)"), name, STR (ze->name), ret, STR (strm.msg));	  retval = -1;	  break;	}      if (strm.avail_out != 0)	break;    }  inflateEnd (&strm);  if (retval != -1)    {      int fd = open (toFileNname, O_CREAT | O_WRONLY | O_LARGEFILE, 0644);      if (fd == -1)	{	  append_msg (CMSG_ERROR, GTXT ("Cannot create file %s (%s)"), toFileNname, STR (strerror (errno)));	  retval = -1;	}      else	{	  long long len = write (fd, buf, ze->size);	  if (len != ze->size)	    {	      append_msg (CMSG_ERROR, GTXT ("%s: Cannot write %lld bytes (only %lld)"),			  toFileNname, (long long) strm.avail_out, (long long) len);	      retval = -1;	    }	  close (fd);	}    }  free (buf);  return retval;} intDbeJarFile::get_EndCentDir (struct EndCentDir *endCentDir){  int64_t fsize = dwin->get_fsize ();  int64_t sz = (fsize < ZIP_BUF_SIZE) ? fsize : ZIP_BUF_SIZE;   // Find the end of central directory record:  unsigned char *b = (unsigned char *) dwin->bind (fsize - sz, sz);  if (b == NULL)    {      append_msg (CMSG_ERROR, GTXT ("%s: cannot find the central directory record (fsize=%lld)"),		  name, (long long) fsize);      return 0;    }   //  End of central directory record:  //  Offset Bytes    Description  //     0     4    end of central directory signature = 0x06054b50  //     4     2    number of this disk  //     6     2    disk where central directory starts  //     8     2    number of central directory records on this disk  //    10     2    total number of central directory records  //    12     4    size of central directory(bytes)  //    16     4    offset of start of central directory, relative to start of archive  //    20     2    comment length(n)  //    22     n    comment   endCentDir->count = 0;  endCentDir->size = 0;  endCentDir->offset = 0;  int64_t ecdrOffset = fsize;  for (int64_t i = END_CENT_DIR_SIZE; i < sz; i++)    {      b = (unsigned char *) dwin->bind (fsize - i, END_CENT_DIR_SIZE);      if (b == NULL)	{	  append_msg (CMSG_ERROR, GTXT ("%s: read failed (offset:0x%llx  bytes:%lld"),		      name, (long long) (fsize - i), (long long) END_CENT_DIR_SIZE);	  break;	}      uint32_t signature = get_u4 (b);      if (signature == 0x06054b50)	{	  int64_t len_comment = get_u2 (b + 20);	  if (i != (len_comment + END_CENT_DIR_SIZE))	    continue;	  ecdrOffset = fsize - i;	  endCentDir->count = get_u2 (b + 10);	  endCentDir->size = get_u4 (b + 12);	  endCentDir->offset = get_u4 (b + 16);	  Dprintf (DUMP_JAR_FILE,		   "  Zip archive file size:              %10lld (0x%016llx)\n"		   "  end-cent-dir record offset:         %10lld (0x%016llx)\n"		   "  cent-dir offset:                    %10lld (0x%016llx)\n"		   "  cent-dir size:                      %10lld (0x%016llx)\n"		   "  cent-dir entries:                   %10lld\n",		   (long long) fsize, (long long) fsize,		   (long long) ecdrOffset, (long long) ecdrOffset,		   (long long) endCentDir->offset, (long long) endCentDir->offset,		   (long long) endCentDir->size, (long long) endCentDir->size,		   (long long) endCentDir->count);	  break;	}    }  if (ecdrOffset == fsize)    {      append_msg (CMSG_ERROR,		  GTXT ("%s: cannot find the central directory record"), name);      return 0;    }  if (endCentDir->count == 0xffff || endCentDir->offset == 0xffffffff      || endCentDir->size == 0xffffffff)    {      // Zip64 format:      //      Zip64 end of central directory record      //      Zip64 end of central directory locator  ( Can be absent )      //      End of central directory record      b = (unsigned char *) dwin->bind (ecdrOffset - ZIP64_LOCATOR_SIZE,					ZIP64_LOCATOR_SIZE);      if (b == NULL)	{	  append_msg (CMSG_ERROR,	     GTXT ("%s: cannot find the Zip64 central directory record"), name);	  return 0;	}      uint32_t signature = get_u4 (b);      if (signature == 0x07064b50)	{ // Get an offset from the Zip64 cent-dir locator	  //  Zip64 end of central directory locator	  //  Offset Bytes    Description	  //     0     4    Zip64 end of central dir locator signature = 0x07064b50	  //     4     4    number of the disk with the start of the zip64 end of central directory	  //     8     8    relative offset of the Zip64 end of central directory record	  //    12     4    total number of disks	  Dprintf (DUMP_JAR_FILE, "    cent-dir locator offset           %10lld (0x%016llx)\n",		   (long long) (ecdrOffset - ZIP64_LOCATOR_SIZE), (long long) (ecdrOffset - ZIP64_LOCATOR_SIZE));	  ecdrOffset = get_u8 (b + 8);	}      else   // the Zip64 end of central directory locator is absent	ecdrOffset -= ZIP64_CENT_DIR_SIZE;      Dprintf (DUMP_JAR_FILE, NTXT ("  Zip64 end-cent-dir record offset:   %10lld (0x%016llx)\n"),	       (long long) ecdrOffset, (long long) ecdrOffset);       b = (unsigned char *) dwin->bind (ecdrOffset, ZIP64_CENT_DIR_SIZE);      if (b == NULL)	{	  append_msg (CMSG_ERROR,	     GTXT ("%s: cannot find the Zip64 central directory record"), name);	  return 0;	}      //  Zip64 end of central directory record      //  Offset Bytes    Description      //     0     4    Zip64 end of central dir signature = 0x06064b50      //     4     8    size of zip64 end of central directory record      //    12     2    version made by      //    14     2    version needed to extract      //    16     4    number of this disk      //    20     4    number of the disk with the start of the central directory      //    24     8    total number of entries in the central directory on this disk      //    32     8    total number of entries in the central directory      //    40     8    size of the central directory      //    48     8    offset of start of centraldirectory with respect to the starting disk number      //    56          Zip64 extensible data sector (variable size)      signature = get_u4 (b);      if (signature != 0x06064b50)	{	  append_msg (CMSG_ERROR, GTXT ("%s: cannot find the Zip64 central directory record"), name);	  return 0;	}      endCentDir->count = get_u8 (b + 32);      endCentDir->size = get_u8 (b + 40);      endCentDir->offset = get_u8 (b + 48);      Dprintf (DUMP_JAR_FILE,	       NTXT ("  cent-dir offset:                    %10lld (0x%016llx)\n"		     "  cent-dir size:                      %10lld (0x%016llx)\n"		     "  cent-dir entries:                   %10lld\n"),	       (long long) endCentDir->offset, (long long) endCentDir->offset,	       (long long) endCentDir->size, (long long) endCentDir->size,

Lines 1–500 of 505.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t