/
githubmirror
/
libreport
Обзор
Документация
Войти
/
githubmirror
/
libreport
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/lib/copyfd.c
226 строк
6 KB
Michal Fabik
internal_libreport: Fix namespacing with #defines
14 апр 2020, 12:42
14 апр 2020, 12:42
2beaddf
Код
Авторство
О чём код?
/* Copyright (C) 2010 ABRT team Copyright (C) 2010 RedHat Inc This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 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. */ /* * Utility routines. * */ #include "internal_libreport.h" #define CONFIG_FEATURE_COPYBUF_KB 4 static const char msg_write_error[] = "write error"; static const char msg_read_error[] = "read error"; static off_t full_fd_action(int src_fd, int dst_fd, off_t size, int flags) { int status = -1; off_t total = 0; int last_was_seek = 0; #if CONFIG_FEATURE_COPYBUF_KB <= 4 char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; enum { buffer_size = sizeof(buffer) }; #else char *buffer; int buffer_size; /* We want page-aligned buffer, just in case kernel is clever * and can do page-aligned io more efficiently */ buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, /* ignored: */ -1, 0); buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024; if (buffer == MAP_FAILED) { buffer = alloca(4 * 1024); buffer_size = 4 * 1024; } #endif if (src_fd < 0) goto out; if (!size) { size = buffer_size; status = 1; /* copy until eof */ } while (1) { ssize_t rd, towrite; rd = libreport_safe_read(src_fd, buffer, buffer_size); if (!rd) { /* eof - all done */ if (last_was_seek) { if (lseek(dst_fd, -1, SEEK_CUR) < 0 || libreport_safe_write(dst_fd, "", 1) != 1 ) { perror_msg("%s", msg_write_error); break; } } status = 0; break; } if (rd < 0) { perror_msg("%s", msg_read_error); break; } /* Add read Bytes before quiting the loop, because the caller * needs to be able to detect overflows (the return value > size). */ total += rd; towrite = rd > size ? size : rd; if (towrite == 0) { /* no more Bytes to write - all done */ status = 0; break; } /* dst_fd == -1 is a fake, else... */ if (dst_fd >= 0) { if (flags & COPYFD_SPARSE) { ssize_t cnt = towrite; while (--cnt >= 0) if (buffer[cnt] != 0) goto need2write; if (lseek(dst_fd, towrite, SEEK_CUR) < 0) { flags &= ~COPYFD_SPARSE; goto need2write; } last_was_seek = 1; } else { need2write: { ssize_t wr = libreport_full_write(dst_fd, buffer, towrite); if (wr < towrite) { perror_msg("%s", msg_write_error); break; } last_was_seek = 0; } } } if (status < 0) { /* if we aren't copying till EOF... */ size -= towrite; } } out: #if CONFIG_FEATURE_COPYBUF_KB > 4 if (buffer_size != 4 * 1024) munmap(buffer, buffer_size); #endif return status ? -1 : total; } off_t libreport_copyfd_ext_at(int src, int dir_fd, const char *name, int mode, uid_t uid, gid_t gid, int open_flags, int copy_flags, off_t size) { int dst = openat(dir_fd, name, open_flags, mode); if (dst < 0) { perror_msg("Can't open '%s'", name); return -1; } off_t r = full_fd_action(src, dst, size, copy_flags); if (uid != (uid_t)-1L) { if (fchown(dst, uid, gid) == -1) { r = -2; perror_msg("Can't change ownership of '%s' to %lu:%lu", name, (long)uid, (long)gid); } } close(dst); return r; } off_t libreport_copyfd_size(int fd1, int fd2, off_t size, int flags) { if (size) { off_t read = full_fd_action(fd1, fd2, size, flags); /* full_fd_action() writes only up to the size Bytes but returns the * number of read Bytes. Callers of this function expect * the return value not being greater then the size argument. */ return read > size ? size : read; } return 0; } void libreport_copyfd_exact_size(int fd1, int fd2, off_t size) { off_t sz = libreport_copyfd_size(fd1, fd2, size, /*flags:*/ 0); if (sz == size) return; if (sz != -1) error_msg_and_die("short read"); /* if sz == -1, copyfd_XX already complained */ libreport_xfunc_die(); } off_t libreport_copyfd_eof(int fd1, int fd2, int flags) { return full_fd_action(fd1, fd2, 0, flags); } off_t libreport_copy_file_ext_2at(int src_dir_fd, const char *src_name, int dir_fd, const char *name, int mode, uid_t uid, gid_t gid, int src_flags, int dst_flags) { off_t r; int src = openat(src_dir_fd, src_name, src_flags); if (src < 0) { perror_msg("Can't open '%s'", src_name); return -1; } r = libreport_copyfd_ext_at(src, dir_fd, name, mode, uid, gid, dst_flags, /*copy flags*/0, /*read all data*/0); close(src); return r; } off_t libreport_copy_file_ext_at(const char *src_name, int dir_fd, const char *name, int mode, uid_t uid, gid_t gid, int src_flags, int dst_flags) { off_t r; int src = open(src_name, src_flags); if (src < 0) { perror_msg("Can't open '%s'", src_name); return -1; } r = libreport_copyfd_ext_at(src, dir_fd, name, mode, uid, gid, dst_flags, /*copy flags*/0, /*read all data*/0); close(src); return r; } off_t libreport_copy_file_at(const char *src_name, int dir_fd, const char *name, int mode) { return libreport_copy_file_ext_at(src_name, dir_fd, name, mode, -1, -1, O_RDONLY, O_WRONLY | O_TRUNC | O_CREAT); } off_t libreport_copy_file(const char *src_name, const char *dst_name, int mode) { return libreport_copy_file_ext(src_name, dst_name, mode, -1, -1, O_RDONLY, O_WRONLY | O_TRUNC | O_CREAT); }