]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_tar.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rgw / rgw_tar.h
CommitLineData
7c673cae 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
7c673cae 3
1e59de90 4#pragma once
7c673cae
FG
5
6#include <algorithm>
7#include <array>
8#include <cstring>
f67539c2 9#include <string_view>
7c673cae
FG
10#include <tuple>
11#include <utility>
12
13#include <boost/optional.hpp>
14#include <boost/range/adaptor/reversed.hpp>
7c673cae
FG
15
16namespace rgw {
17namespace tar {
18
19static constexpr size_t BLOCK_SIZE = 512;
20
21
22static inline std::pair<class StatusIndicator,
23 boost::optional<class HeaderView>>
24interpret_block(const StatusIndicator& status, ceph::bufferlist& bl);
25
26
27class StatusIndicator {
28 friend std::pair<class StatusIndicator,
29 boost::optional<class HeaderView>>
30 interpret_block(const StatusIndicator& status, ceph::bufferlist& bl);
31
32 bool is_empty;
33 bool is_eof;
34
35 StatusIndicator()
36 : is_empty(false),
37 is_eof(false) {
38 }
39
40 StatusIndicator(const StatusIndicator& prev_status,
41 const bool is_empty)
42 : is_empty(is_empty),
43 is_eof(is_empty && prev_status.empty()) {
44 }
45
46public:
47 bool empty() const {
48 return is_empty;
49 }
50
51 bool eof() const {
52 return is_eof;
53 }
54
55 static StatusIndicator create() {
56 return StatusIndicator();
57 }
58} /* class StatusIndicator */;
59
60
61enum class FileType : char {
62 UNKNOWN = '\0',
63
64 /* The tar format uses ASCII encoding. */
65 NORMAL_FILE = '0',
66 DIRECTORY = '5'
67}; /* enum class FileType */
68
69class HeaderView {
70protected:
1e59de90 71 /* Everything is char here (ASCII encoding), so we don't need to worry about
7c673cae
FG
72 * the struct padding. */
73 const struct header_t {
74 char filename[100];
75 char __filemode[8];
76 char __owner_id[8];
77 char __group_id[8];
78 char filesize[12];
79 char lastmod[12];
80 char checksum[8];
81 char filetype;
82 char __padding[355];
83 } *header;
84
85 static_assert(sizeof(*header) == BLOCK_SIZE,
86 "The TAR header must be exactly BLOCK_SIZE length");
87
1e59de90 88 /* The label is far more important from what the code really does. */
7c673cae
FG
89 static size_t pos2len(const size_t pos) {
90 return pos + 1;
91 }
92
93public:
11fdf7f2 94 explicit HeaderView(const char (&header)[BLOCK_SIZE])
7c673cae
FG
95 : header(reinterpret_cast<const header_t*>(header)) {
96 }
97
98 FileType get_filetype() const {
99 switch (header->filetype) {
100 case static_cast<char>(FileType::NORMAL_FILE):
101 return FileType::NORMAL_FILE;
102 case static_cast<char>(FileType::DIRECTORY):
103 return FileType::DIRECTORY;
104 default:
105 return FileType::UNKNOWN;
106 }
107 }
108
f67539c2
TL
109 std::string_view get_filename() const {
110 return std::string_view(header->filename,
7c673cae
FG
111 std::min(sizeof(header->filename),
112 strlen(header->filename)));
113 }
114
115 size_t get_filesize() const {
116 /* The string_ref is pretty suitable here because tar encodes its
117 * metadata in ASCII. */
f67539c2 118 const std::string_view raw(header->filesize, sizeof(header->filesize));
7c673cae
FG
119
120 /* We need to find where the padding ends. */
121 const auto pad_ends_at = std::min(raw.find_last_not_of('\0'),
122 raw.find_last_not_of(' '));
123 const auto trimmed = raw.substr(0,
f67539c2 124 pad_ends_at == std::string_view::npos ? std::string_view::npos
7c673cae
FG
125 : pos2len(pad_ends_at));
126
127 size_t sum = 0, mul = 1;
128 for (const char c : boost::adaptors::reverse(trimmed)) {
129 sum += (c - '0') * mul;
130 mul *= 8;
131 }
132
133 return sum;
134 }
135}; /* class Header */
136
137
138static inline std::pair<StatusIndicator,
139 boost::optional<HeaderView>>
140interpret_block(const StatusIndicator& status, ceph::bufferlist& bl) {
141 static constexpr std::array<char, BLOCK_SIZE> zero_block = {0, };
142 const char (&block)[BLOCK_SIZE] = \
143 reinterpret_cast<const char (&)[BLOCK_SIZE]>(*bl.c_str());
144
145 if (std::memcmp(zero_block.data(), block, BLOCK_SIZE) == 0) {
146 return std::make_pair(StatusIndicator(status, true), boost::none);
147 } else {
148 return std::make_pair(StatusIndicator(status, false), HeaderView(block));
149 }
150}
151
152} /* namespace tar */
153} /* namespace rgw */