/***
This file is part of systemd.
Copyright 2015 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <sys/sendfile.h>
/* When we include libgen.h because we need dirname() we immediately
* undefine basename() since libgen.h defines it as a macro to the POSIX
* version which is really broken. We prefer GNU basename(). */
#include <libgen.h>
#include "sd-daemon.h"
#include "alloc-util.h"
#include "btrfs-util.h"
#include "copy.h"
#include "export-raw.h"
#include "fd-util.h"
#include "fileio.h"
#include "import-common.h"
#include "ratelimit.h"
#include "string-util.h"
#include "util.h"
struct RawExport {
void *userdata;
char *path;
int input_fd;
int output_fd;
void *buffer;
unsigned last_percent;
bool eof;
bool tried_reflink;
bool tried_sendfile;
};
if (!e)
return NULL;
import_compress_free(&e->compress);
sd_event_unref(e->event);
safe_close(e->input_fd);
free(e);
return NULL;
}
int raw_export_new(
void *userdata) {
int r;
if (!e)
return -ENOMEM;
e->on_finished = on_finished;
e->last_percent = (unsigned) -1;
if (event)
else {
r = sd_event_default(&e->event);
if (r < 0)
return r;
}
*ret = e;
e = NULL;
return 0;
}
unsigned percent;
assert(e);
percent = 100;
else
if (percent == e->last_percent)
return;
if (!ratelimit_test(&e->progress_rate_limit))
return;
e->last_percent = percent;
}
ssize_t l;
int r;
assert(e);
/* If we shall take an uncompressed snapshot we can
* reflink source to destination directly. Let's see
* if this works. */
if (r >= 0) {
r = 0;
goto finish;
}
e->tried_reflink = true;
}
if (l < 0) {
return 0;
e->tried_sendfile = true;
} else if (l == 0) {
r = 0;
goto finish;
} else {
e->written_uncompressed += l;
e->written_compressed += l;
return 0;
}
}
while (e->buffer_size <= 0) {
if (e->eof) {
r = 0;
goto finish;
}
if (l < 0) {
goto finish;
}
if (l == 0) {
e->eof = true;
} else {
e->written_uncompressed += l;
}
if (r < 0) {
r = log_error_errno(r, "Failed to encode: %m");
goto finish;
}
}
if (l < 0) {
return 0;
goto finish;
}
e->buffer_size -= l;
e->written_compressed += l;
return 0;
if (r >= 0) {
}
if (e->on_finished)
e->on_finished(e, r, e->userdata);
else
sd_event_exit(e->event, r);
return 0;
}
return raw_export_process(i);
}
return raw_export_process(i);
}
char *p, *d;
int new_fd, r;
d = dirname(p);
if (new_fd < 0) {
_cleanup_free_ char *t = NULL;
if (r < 0)
return r;
if (new_fd < 0)
return -errno;
(void) unlink(t);
}
if (r < 0) {
return r;
}
return new_fd;
}
int r;
assert(e);
if (e->output_fd >= 0)
return -EBUSY;
r = fd_nonblock(fd, true);
if (r < 0)
return r;
if (r < 0)
return r;
if (sfd < 0)
return -errno;
return -errno;
return -ENOTTY;
/* Try to take a reflink snapshot of the file, if we can t make the export atomic */
if (tfd >= 0) {
tfd = -1;
} else {
sfd = -1;
}
if (r < 0)
return r;
if (r == -EPERM) {
if (r < 0)
return r;
}
if (r < 0)
return r;
return r;
}