libs/EDocBFD/bfd_utils.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003    Copyright (C) 2007 Brendon Costa
00004 
00005    This code is free software; you can redistribute it and/or modify 
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2, or (at your option)
00008    any later version.
00009 
00010    This code is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this code; see the file COPYING.  If not, write to
00017    the Free Software Foundation, 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 
00020 *******************************************************************************/
00021 #include "config.h"
00022 #include "EDocBFD/bfd_utils.h"
00023 
00024 #include "EDocBFD/Section.h"
00025 #include "EDocBFD/BFDArchive.h"
00026 
00027 #include "EDoc/utils.h"
00028 #include "EDocBFD/exceptions.h"
00029 #include "EDoc/persistence_data.h"
00030 
00031 #ifdef HAVE_STRING_H
00032    #include <string.h>
00033 #endif
00034 
00035 #ifdef HAVE_FCNTL_H
00036    #include <fcntl.h>
00037 #endif
00038 
00039 #ifdef HAVE_UNISTD_H
00040    #include <unistd.h>
00041 #endif
00042 
00043 #ifdef HAVE_ERRNO_H
00044    #include <errno.h>
00045 #endif
00046 
00047 #ifdef HAVE_SYS_STAT_H
00048    #include <sys/stat.h>
00049 #endif
00050 
00051 namespace EDocBFD
00052 {
00053    //===========================================================================
00054    /** \brief
00055     */
00056    bool bfd_initialised = false;
00057 
00058    //===========================================================================
00059    void ProcessReadBFD(std::list<EDoc::ManagedFile>& input_files, 
00060       struct bfd* abfd, const EDoc::ManagedFile& filename)
00061    {
00062       // Only accept archives and object file formats. Not core dump files.
00063       if (!bfd_check_format(abfd, bfd_object) && 
00064           !bfd_check_format(abfd, bfd_archive))
00065       {
00066          EDOC_THROW_EXCEPTION(BFDException, "Unknown binary format.", "");
00067       }
00068 
00069       EDOC_Debug(std::cerr << "BFD Format of file: " << filename.GetFileNameRep()
00070          << " is: " << bfd_format_string(abfd->format));
00071 
00072       // If the BFD is an archive then process each of its internal files.
00073       if (bfd_check_format(abfd, bfd_archive))
00074       {
00075          for (struct bfd* ibfd = bfd_openr_next_archived_file(abfd, NULL); 
00076             ibfd; ibfd = bfd_openr_next_archived_file(abfd, ibfd))
00077          {
00078             // @@@Brendon Not sure if the filename of ibfd is the name of the 
00079             // archived file?
00080             // Construct a temporary managed file object to store the name of 
00081             // the bfd archive item.
00082             //std::list<std::string> id = filename.GetIdentifier();
00083             //id.push_back(ibfd->filename);
00084             //ret.push_back(ManagedFile(id, filename, NULL));
00085             ProcessReadBFD(input_files, ibfd, filename);
00086          }
00087          
00088          // @@@Brendon Not sure if this return should be here.
00089          // Returns as we assume that a BFD archive does not itself contain any
00090          // .edoc sections.
00091          return;
00092       }
00093       
00094       // Otherwise here we expect the bfd to be an object. Process its sections.
00095       EDOC_Debug("Received object format BFD.");
00096       try
00097       {
00098          if (!abfd->sections)
00099          {
00100             EDOC_Debug("Contains no sections.");
00101             return;
00102          }
00103 
00104          // Dont use: bfd_map_over_sections as it does not work with exceptions.
00105          asection* p;
00106          bool has_edoc_data = false;
00107 
00108          for (p = abfd->sections; p != NULL; p = p->next)
00109          {
00110             if (strcmp(p->name, EDOC_SECTION_NAME))
00111             {
00112                continue;
00113             }
00114 
00115             std::list<EDoc::ManagedFile> files(HandleEDocSection(abfd, p, filename));
00116             if (files.size())
00117             {
00118                has_edoc_data = true;
00119                EDOC_Fine("Appending: " << files.size() 
00120                   << " edoc files to input files list.");
00121                EDoc::Append(input_files, files);
00122             }
00123          }
00124       }
00125       catch(...)
00126       {
00127          EDOC_Fine("An error occured looking for input files.");
00128          EDoc::Erase(input_files);
00129          throw;
00130       }
00131 
00132    }
00133    //===========================================================================
00134    void InitialiseBFD()
00135    {
00136       if (bfd_initialised)
00137       {
00138          bfd_init();
00139          bfd_initialised = true;
00140       }
00141    }
00142    //===========================================================================
00143    struct bfd* OpenBFDFile(std::string filename)
00144    {
00145       // Ensure that bfd has been initialised.
00146       InitialiseBFD();
00147 
00148       // Then we assume it is a binary file with embedded edoc data.
00149       struct bfd* abfd = bfd_openr(filename.c_str(), "default");
00150       if (abfd == NULL)
00151       {
00152          bfd_error_type error_code = bfd_get_error();
00153          EDOC_THROW_EXCEPTION(BFDException, bfd_errmsg(error_code), "");
00154       }
00155 
00156       try
00157       {
00158          // Only accept archives and object file formats. Not core dump files.
00159          if (!bfd_check_format(abfd, bfd_object) && 
00160              !bfd_check_format(abfd, bfd_archive))
00161          {
00162             EDOC_THROW_EXCEPTION(BFDException, 
00163                "Unknown binary format.", "");
00164          }
00165 
00166          EDOC_Debug("BFD Format of file: " << filename
00167             << " is: " << bfd_format_string(abfd->format));
00168       }
00169       catch(...)
00170       {
00171          bfd_close(abfd);
00172          throw;
00173       }
00174 
00175       return abfd;
00176    }
00177    //===========================================================================
00178    std::list<EDoc::ManagedFile> HandleEDocSection(bfd* abfd, asection* asect,
00179       const EDoc::ManagedFile& arch)
00180    {
00181       std::list<EDoc::ManagedFile> ret;
00182       Section section(abfd, asect);
00183 
00184       try
00185       {
00186          while (!section.IsEof())
00187          {
00188             std::string data;
00189 
00190             // Need to read the 1st 4 bytes for the block size.
00191             data = section.ReadEx(4);
00192             uint32_t block_size = 0;
00193             block_size = ( ((uint32_t)((uint8_t)data[0]) << 24) |
00194                            ((uint32_t)((uint8_t)data[1]) << 16) |
00195                            ((uint32_t)((uint8_t)data[2]) << 8)  |
00196                            ((uint32_t)((uint8_t)data[3]) << 0));
00197             EDOC_Finest("Got block size: " << block_size);
00198 
00199             // read the filename size.
00200             data = section.ReadEx(4);
00201             uint32_t filename_size = 0;
00202             filename_size = ( ((uint32_t)((uint8_t)data[0]) << 24) |
00203                               ((uint32_t)((uint8_t)data[1]) << 16) |
00204                               ((uint32_t)((uint8_t)data[2]) << 8)  |
00205                               ((uint32_t)((uint8_t)data[3]) << 0));
00206 
00207             EDOC_Finest("Got filename size: " << filename_size);
00208             std::string filename = section.ReadEx(filename_size);
00209             EDOC_Debug("Extracted: " << filename 
00210                << " of size: " << (block_size - filename_size));
00211 
00212             // Read the data in chunks and write it to a temp file.
00213             std::string outfile = EDoc::CreateTempFilename();
00214             int fd = open(outfile.c_str(), O_WRONLY, O_TRUNC);
00215             if (fd == -1)
00216             {
00217                EDOC_THROW_EXCEPTION(BFDException, "", "");
00218             }
00219 
00220             std::list<std::string> id = arch.GetIdentifier();
00221             id.push_back(filename);
00222             ret.push_back(EDoc::ManagedFile(id, outfile, 
00223                new ExtractedBFDFile(outfile)));
00224 
00225             // -4 because of the file size value is included into the 
00226             // block size.
00227             uint32_t file_size = block_size - filename_size - 8;
00228 
00229             char temp[1024];
00230             size_t blocks_to_read = file_size / 1024;
00231             for (size_t i = 0; i < blocks_to_read; i++)
00232             {
00233                ssize_t result = section.ReadEx(temp, 1024);
00234                if (write(fd, temp, result) != result)
00235                {
00236                   EDOC_THROW_EXCEPTION(BFDException, "", "");
00237                }
00238             }
00239 
00240             if (file_size % 1024)
00241             {
00242                ssize_t result = section.ReadEx(temp, file_size % 1024);
00243                if (write(fd, temp, result) != result)
00244                {
00245                   EDOC_THROW_EXCEPTION(BFDException, "", "");
00246                }
00247             }
00248 
00249             close(fd);
00250             EDOC_Finest("Completed writing contents of extrated file to "
00251                "temp file.");
00252          }
00253       }
00254       catch(...)
00255       {
00256          EDOC_Debug("An error occured re-throwing.");
00257          EDoc::Erase(ret);
00258          throw;
00259       }
00260 
00261       return ret;
00262    }
00263    //===========================================================================
00264    void EmbedFileInBinary(const std::string& file_to_embed, 
00265       const std::string embedded_name,
00266       const std::string& binary_file, 
00267       std::string section)
00268    {
00269       std::string tmpfile = EDoc::CreateTempFilename();
00270       int fd = open(tmpfile.c_str(), O_WRONLY, O_TRUNC);
00271       if (fd == -1)
00272       {
00273          EDOC_THROW_EXCEPTION(BFDException, "", "");
00274       }
00275 
00276       try
00277       {
00278          // Write the block size
00279          // Write the filename size
00280          // Write the filename
00281          // Copy the data
00282 
00283 
00284          struct stat buffer;
00285          int result = stat(file_to_embed.c_str(), &buffer);
00286          if ((result == -1) || !(buffer.st_mode & S_IFREG))
00287          {
00288             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00289          }
00290 
00291          size_t block_size = embedded_name.size() + 8 + buffer.st_size;
00292          unsigned char c = 0;
00293 
00294          c = (block_size & 0xFF000000) >> 24;
00295          result = write(fd, &c, 1);
00296          if (result != 1)
00297          {
00298             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00299          }
00300 
00301          c = (block_size & 0x00FF0000) >> 16;
00302          result = write(fd, &c, 1);
00303          if (result != 1)
00304          {
00305             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00306          }
00307 
00308          c = (block_size & 0x0000FF00) >> 8;
00309          result = write(fd, &c, 1);
00310          if (result != 1)
00311          {
00312             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00313          }
00314 
00315          c = (block_size & 0x000000FF) >> 0;
00316          result = write(fd, &c, 1);
00317          if (result != 1)
00318          {
00319             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00320          }
00321 
00322          c = (embedded_name.size() & 0xFF000000) >> 24;
00323          result = write(fd, &c, 1);
00324          if (result != 1)
00325          {
00326             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00327          }
00328 
00329          c = (embedded_name.size() & 0x00FF0000) >> 16;
00330          result = write(fd, &c, 1);
00331          if (result != 1)
00332          {
00333             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00334          }
00335 
00336          c = (embedded_name.size() & 0x0000FF00) >> 8;
00337          result = write(fd, &c, 1);
00338          if (result != 1)
00339          {
00340             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00341          }
00342 
00343          c = (embedded_name.size() & 0x000000FF) >> 0;
00344          result = write(fd, &c, 1);
00345          if (result != 1)
00346          {
00347             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00348          }
00349 
00350          result = write(fd, embedded_name.c_str(), embedded_name.size());
00351          if (result != (ssize_t)embedded_name.size())
00352          {
00353             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00354          }
00355 
00356          // Open the file to be embedded to read from.
00357          int fd2 = open(file_to_embed.c_str(), O_RDONLY, 0);
00358          if (fd2 == -1)
00359          {
00360             EDOC_THROW_EXCEPTION(BFDException, "", "");
00361          }
00362 
00363          // Write the contents of the file.
00364          char temp[1024];
00365          size_t blocks_to_write = buffer.st_size / 1024;
00366 
00367          for (size_t i = 0; i < blocks_to_write; i++)
00368          {
00369             ssize_t result = read(fd2, temp, 1024);
00370             if (result == 0)
00371             {
00372                EDOC_THROW_EXCEPTION(BFDException, "", "");
00373             }
00374             if (write(fd, temp, result) != result)
00375             {
00376                EDOC_THROW_EXCEPTION(BFDException, "", "");
00377             }
00378          }
00379 
00380          if (buffer.st_size % 1024)
00381          {
00382             ssize_t result = read(fd2, temp, buffer.st_size % 1024);
00383             if (result == 0)
00384             {
00385                EDOC_THROW_EXCEPTION(BFDException, "", "");
00386             }
00387             if (write(fd, temp, result) != result)
00388             {
00389                EDOC_THROW_EXCEPTION(BFDException, "", "");
00390             }
00391          }
00392 
00393          close(fd2);
00394          close(fd);
00395 
00396 
00397          std::ostringstream stream;
00398          stream << "objcopy --remove-section=" << section << " --add-section "
00399             << section << "=" << tmpfile
00400             << " " << binary_file;
00401          if (EDoc::RunProgram(stream.str()) != 0)
00402          {
00403             EDOC_THROW_EXCEPTION(EDoc::BugException, "", "");
00404          }
00405 
00406          // Delete the temporary file.
00407          unlink(tmpfile.c_str());
00408       }
00409       catch(...)
00410       {
00411          unlink(tmpfile.c_str());
00412          throw;
00413       }
00414    }
00415    //===========================================================================
00416    
00417 }

Generated on Tue Jan 20 18:26:07 2009 for EDoc-0.2.1 by  doxygen 1.5.1