-
Notifications
You must be signed in to change notification settings - Fork 256
/
unix_tape_device.cc
113 lines (100 loc) · 3.4 KB
/
unix_tape_device.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
BAREOS® - Backup Archiving REcovery Open Sourced
Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
Copyright (C) 2013-2013 Planets Communications B.V.
Copyright (C) 2013-2023 Bareos GmbH & Co. KG
This program is Free Software; you can redistribute it and/or
modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation and included
in the file LICENSE.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
/*
* Marco van Wieringen, December 2013
*
* UNIX Tape API device abstraction.
*
* Stacking is the following:
*
* unix_tape_device::
* |
* v
* generic_tape_device::
* |
* v
* Device::
*
*/
/**
* @file
* UNIX Tape API device abstraction.
*/
#include <algorithm>
#include <vector>
#include <sys/ioctl.h>
#include <unistd.h>
#include "include/bareos.h"
#include "stored/stored.h"
#include "stored/sd_backends.h"
#include "generic_tape_device.h"
#include "unix_tape_device.h"
namespace storagedaemon {
static std::vector<std::size_t> bufsizes(std::size_t count)
{
constexpr std::size_t mb = 1024 * 1024;
std::vector<std::size_t> sizes{1 * mb, 2 * mb, 4 * mb, 8 * mb, 16 * mb};
sizes.erase(sizes.begin(),
std::upper_bound(sizes.begin(), sizes.end(), count));
return sizes;
}
int unix_tape_device::d_ioctl(int fd, ioctl_req_t request, char* op)
{
return ::ioctl(fd, request, op);
}
unix_tape_device::unix_tape_device()
{
SetCap(CAP_ADJWRITESIZE); /* Adjust write size to min/max */
}
ssize_t unix_tape_device::d_read(int fd, void* buffer, size_t count)
{
ssize_t ret = ::read(fd, buffer, count);
/* If the driver fails to `read()` with `ENOMEM`, then the provided buffer
* was too small. By re-reading with a temporary buffer that is enlarged
* step-by-step, we can read the block and return the first `count` bytes.
* This allows the calling code to read the block header and resize its buffer
* according to the size recorded in that header.
*/
if (ret == -1 && errno == ENOMEM && HasCap(CAP_BSR)) {
for (auto bufsize : bufsizes(count)) {
// first go back one block so we can re-read
if (!bsr(1)) {
/* when backward-spacing fails for some reason, there's not much we
* can do, so we just return the original ENOMEM and hope that the
* caller knows the device is in a non well-defined state.
*/
errno = ENOMEM;
return -1;
}
block_num++; // re-increment the block counter bsr() just decremented
std::vector<char> tmpbuf(bufsize);
if (auto tmpret = ::read(fd, tmpbuf.data(), tmpbuf.size());
tmpret != -1) {
memcpy(buffer, tmpbuf.data(), count);
ret = std::min(tmpret, static_cast<ssize_t>(count));
break; // successful read
} else if (errno != ENOMEM) {
break; // some other error occured
}
}
}
return ret;
}
REGISTER_SD_BACKEND(tape, unix_tape_device)
} /* namespace storagedaemon */