• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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