Directory: | cvmfs/ |
---|---|
File: | cvmfs/network/sink_mem.cc |
Date: | 2025-02-09 02:34:19 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 40 | 49 | 81.6% |
Branches: | 23 | 42 | 54.8% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | #include <cassert> | ||
6 | #include <cstring> | ||
7 | #include <string> | ||
8 | |||
9 | #include "util/smalloc.h" | ||
10 | #include "util/string.h" | ||
11 | |||
12 | #include "sink_mem.h" | ||
13 | |||
14 | namespace cvmfs { | ||
15 | |||
16 | ✗ | MemSink::MemSink(size_t size) : Sink(true), size_(size), | |
17 | ✗ | pos_(0), max_size_(kMaxMemSize) { | |
18 | ✗ | data_ = static_cast<unsigned char *>(smalloc(size)); | |
19 | } | ||
20 | |||
21 | /** | ||
22 | * Appends data to the sink | ||
23 | * If the sink is too small and | ||
24 | * - the sink is the owner of data_: sink size is doubled | ||
25 | * - the sink is NOT the owner of data_: fails with -ENOSPC | ||
26 | * | ||
27 | * @returns on success: number of bytes written | ||
28 | * on failure: -errno. | ||
29 | */ | ||
30 | 110 | int64_t MemSink::Write(const void *buf, uint64_t sz) { | |
31 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 107 times.
|
110 | if (pos_ + sz > size_) { |
32 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (is_owner_) { |
33 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | size_t new_size = pos_ + sz < size_ * 2 ? size_ * 2 : pos_ + sz + 1; |
34 | 2 | data_ = static_cast<unsigned char *>(srealloc(data_, new_size)); | |
35 | 2 | size_ = new_size; | |
36 | } else { | ||
37 | 1 | return -ENOSPC; | |
38 | } | ||
39 | } | ||
40 | |||
41 | 109 | memcpy(data_ + pos_, buf, sz); | |
42 | 109 | pos_ += sz; | |
43 | 109 | return static_cast<int64_t>(sz); | |
44 | } | ||
45 | |||
46 | /** | ||
47 | * Truncate all written data and start over at position zero. | ||
48 | * | ||
49 | * @returns Success = 0 | ||
50 | * Failure = -errno | ||
51 | */ | ||
52 | 12 | int MemSink::Reset() { | |
53 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (is_owner_) { |
54 | 12 | free(data_); | |
55 | 12 | data_ = NULL; | |
56 | 12 | size_ = 0; | |
57 | } | ||
58 | |||
59 | 12 | pos_ = 0; | |
60 | |||
61 | 12 | return 0; | |
62 | } | ||
63 | |||
64 | /** | ||
65 | * @returns true if the object is correctly initialized. | ||
66 | */ | ||
67 | 92 | bool MemSink::IsValid() { | |
68 |
5/6✓ Branch 0 taken 89 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 89 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 88 times.
|
96 | return (size_ == 0 && pos_ == 0 && data_ == NULL) || |
69 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
96 | (size_ > 0 && pos_ >= 0 && data_ != NULL); |
70 | } | ||
71 | |||
72 | /** | ||
73 | * Reserves new space in sinks that require reservation (see RequiresReserve) | ||
74 | * | ||
75 | * Successful if the requested size is smaller than already space reserved, or | ||
76 | * if the sink is the owner of the data and can allocate enough new space. | ||
77 | * | ||
78 | * @note If successful, always resets the current position to 0. | ||
79 | * | ||
80 | * Fails if | ||
81 | * 1) sink is not the owner of the data and more than the current size is | ||
82 | * requested | ||
83 | * 2) more space is requested than allowed (max_size_) | ||
84 | * | ||
85 | * @returns success = true | ||
86 | * failure = false | ||
87 | */ | ||
88 | 161 | bool MemSink::Reserve(size_t size) { | |
89 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 87 times.
|
161 | if (size <= size_) { |
90 | 74 | pos_ = 0; | |
91 | 74 | return true; | |
92 | } | ||
93 |
3/4✓ Branch 0 taken 86 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
|
87 | if (!is_owner_ || size > max_size_) { |
94 | 1 | return false; | |
95 | } | ||
96 | |||
97 | 86 | FreeData(); | |
98 | |||
99 | 86 | size_ = size; | |
100 | 86 | pos_ = 0; | |
101 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (size == 0) { |
102 | ✗ | data_ = NULL; | |
103 | } else { | ||
104 | 86 | data_ = static_cast<unsigned char *>(smalloc(size)); | |
105 | } | ||
106 | 86 | return true; | |
107 | } | ||
108 | |||
109 | /** | ||
110 | * Return a string representation describing the type of sink and its status | ||
111 | */ | ||
112 | ✗ | std::string MemSink::Describe() { | |
113 | ✗ | std::string result = "Memory sink with "; | |
114 | ✗ | result += "size: " + StringifyUint(size_); | |
115 | ✗ | result += " - current pos: " + StringifyUint(pos_); | |
116 | ✗ | return result; | |
117 | } | ||
118 | |||
119 | /** | ||
120 | * Allows the sink to adopt data that was initialized outside this class. | ||
121 | * The sink can become the new owner of the data, or not. | ||
122 | */ | ||
123 | 4 | void MemSink::Adopt(size_t size, size_t pos, unsigned char *data, | |
124 | bool is_owner) { | ||
125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | assert(size >= pos); |
126 | |||
127 | 4 | FreeData(); | |
128 | |||
129 | 4 | is_owner_ = is_owner; | |
130 | 4 | size_ = size; | |
131 | 4 | pos_ = pos; | |
132 | 4 | data_ = data; | |
133 | 4 | } | |
134 | |||
135 | } // namespace cvmfs | ||
136 |