1 // Copyright (C) 2018 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 #pragma once 15 #include <sys/types.h> // for gid_t, mode_t, uid_t 16 #include <cstdint> // for uint64_t, uint8_t 17 #include <iosfwd> // for basic_ios 18 #include <ostream> // for istream, ostream 19 #include <string> // for string 20 #include "android/utils/file_io.h" // for android_mkdir, android_stat 21 22 #ifdef _MSC_VER 23 #include "aemu/base/msvc.h" 24 using uid_t = uint32_t; 25 using gid_t = uint32_t; 26 #endif 27 28 namespace android { 29 namespace base { 30 31 enum TarType { 32 REGTYPE = 0, // regular file 33 LNKTYPE = 1, // link (inside tarfile) 34 SYMTYPE = 2, // symbolic link 35 CHRTYPE = 3, // character special device 36 BLKTYPE = 4, // block special device 37 DIRTYPE = 5, // directory 38 FIFOTYPE = 6, // fifo special device 39 CONTTYPE = 7, // contiguous file 40 }; 41 42 enum HeaderTypes : char { 43 XHDTYPE = 'x', // POSIX.1-2001 extended header 44 XGLTYPE = 'g', // POSIX.1-2001 global header 45 SOLARIS_XHDTYPE = 'X', // Solaris extended header 46 GNUTYPE_LONGNAME = 'L', // GNU tar longname 47 GNUTYPE_LONGLINK = 'K', // GNU tar longlink 48 GNUTYPE_SPARSE = 'S' // GNU tar sparse file 49 }; 50 51 enum class TarFormat { 52 USTAR_FORMAT = 0, // POSIX.1-1988 (ustar) format 53 GNU_FORMAT = 1, // GNU tar format 54 PAX_FORMAT = 2 // POSIX.1-2001 (pax) format 55 }; 56 57 // MAGIC USTAR HEADER 58 #define USTAR "ustar " 59 #define TARBLOCK 512 60 61 /* POSIX header. */ 62 using octalnr = char; 63 64 /* tar Header Block, from POSIX 1003.1-1990. 65 should be exactly the size of a tarblock. 66 */ 67 struct posix_header { /* byte offset */ 68 char name[100]; /* 0 */ 69 octalnr mode[8]; /* 100 */ 70 octalnr uid[8]; /* 108 */ 71 octalnr gid[8]; /* 116 */ 72 octalnr size[12]; /* 124 */ 73 octalnr mtime[12]; /* 136 */ 74 octalnr chksum[8]; /* 148 */ 75 uint8_t typeflag; /* 156 */ 76 char linkname[100]; /* 157 */ 77 char magic[6]; /* 257, should contain "ustar\0" */ 78 octalnr version[2]; /* 263 */ 79 char uname[32]; /* 265 */ 80 char gname[32]; /* 297 */ 81 octalnr devmajor[8]; /* 329 */ 82 octalnr devminor[8]; /* 337 */ 83 octalnr prefix[155]; /* 345 */ 84 octalnr padding[12]; /* 500 */ 85 /* 512 */ 86 }; 87 static_assert(sizeof(posix_header) == TARBLOCK, 88 "Size of the tar header should be 512 bytes"); 89 90 // A class that can add files/directories to a stream as tar objects. 91 // The tar entries will be written using the ustar fromat. 92 // Only files and directories are supported (no symlinks). 93 // And filenames up to 99 characters in length. 94 // 95 // Make sure to call close when you are finished adding files. 96 class TarWriter : public std::ios { 97 public: 98 TarWriter(std::string cwd, std::ostream& dest, size_t bufsize = 4096); 99 ~TarWriter(); 100 101 // Add a file entry using the given stream, filename and stats. 102 bool addFileEntryFromStream(std::istream& src, 103 std::string fname, 104 struct stat sb); 105 bool addFileEntry(std::string fname); 106 bool addDirectoryEntry(std::string dname); 107 bool addDirectory(std::string dname); 108 109 // Closes the tar archive and flushes the underlying stream. 110 bool close(); error_msg()111 std::string error_msg() { return mErrMsg; }; 112 113 private: 114 bool error(std::string msg); 115 bool writeTarHeader(std::string name); 116 bool writeTarHeader(std::string fname, bool isDir, struct stat sb); 117 std::ostream& mDest; 118 std::string mCwd{}; 119 std::string mErrMsg{}; 120 bool mClosed = false; 121 size_t mBufferSize; 122 }; 123 124 struct TarInfo { 125 std::string name; // member name 126 mode_t mode = 0644; // file permissions 127 uid_t uid = 0; // user id 128 gid_t gid = 0; // group id 129 uint64_t size = 0; // file size 130 uint64_t mtime = 0; // modification time 131 TarType type = REGTYPE; // member type 132 std::string uname = ""; // user name 133 std::string gname = ""; // group name 134 uint64_t offset = 0; // offset in stream 135 bool valid = false; // True if this is a valid entry. 136 }; 137 138 class TarReader : public std::ios { 139 public: 140 TarReader(std::string cwd, std::istream& src, bool has_seek = false); 141 TarInfo next(TarInfo from); first()142 TarInfo first() { return next({}); } 143 bool extract(TarInfo src); error_msg()144 std::string error_msg() { return mErrMsg; }; 145 146 private: 147 void seekg(std::streampos pos); 148 bool error(std::string msg); 149 std::istream& mSrc; 150 std::string mCwd{}; 151 std::string mErrMsg{}; 152 bool mSeek = false; 153 }; 154 155 } // namespace base 156 } // namespace android 157