Files
s390-tools/genprotimg/src/utils/file_utils.c
Marc Hartmayer b6bdd7744a genprotimg: use pv_ namespace for our Buffer implementation
Use `pv_` namespace for our Buffer implementation so a symbol clash with other
libraries is less likely.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/109
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-24 18:33:44 +01:00

235 lines
4.8 KiB
C

/*
* General file utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <fcntl.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "pv/pv_error.h"
#include "align.h"
#include "buffer.h"
#include "common.h"
#include "file_utils.h"
FILE *file_open(const gchar *filename, const gchar *mode, GError **err)
{
FILE *f = fopen(filename, mode);
if (!f) {
g_set_error(err, G_FILE_ERROR,
(gint)g_file_error_from_errno(errno),
_("Failed to open file '%s': %s"), filename,
g_strerror(errno));
return NULL;
}
return f;
}
gint file_size(const gchar *filename, gsize *size, GError **err)
{
GStatBuf st_buf;
g_assert(size);
if (g_stat(filename, &st_buf) != 0) {
g_set_error(err, G_FILE_ERROR,
(gint)g_file_error_from_errno(errno),
_("Failed to get file status '%s': %s"), filename,
g_strerror(errno));
return -1;
}
if (!S_ISREG(st_buf.st_mode)) {
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
_("File '%s' is not a regular file"), filename);
return -1;
}
if (st_buf.st_size < 0) {
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
_("Invalid file size for '%s': %zu"), filename,
st_buf.st_size);
return -1;
}
*size = (gsize)st_buf.st_size;
return 0;
}
/* Returns 0 on success, otherwise -1. Stores the total number of
* elements successfully read in @count_read
*/
gint file_read(FILE *in, void *ptr, gsize size, gsize count,
gsize *count_read, GError **err)
{
gsize tmp_count_read;
tmp_count_read = fread(ptr, size, count, in);
if (count_read)
*count_read = tmp_count_read;
if (ferror(in)) {
g_set_error(err, G_FILE_ERROR, 0, _("Failed to read file"));
return -1;
}
return 0;
}
gint file_write(FILE *out, const void *ptr, gsize size, gsize count,
gsize *count_written, GError **err)
{
gsize tmp_count_written;
tmp_count_written = fwrite(ptr, size, count, out);
if (count_written)
*count_written = tmp_count_written;
if (tmp_count_written != count || ferror(out)) {
g_set_error(err, G_FILE_ERROR, 0, _("Failed to write file"));
return -1;
}
return 0;
}
static gint file_seek(FILE *f, uint64_t offset, GError **err)
{
gint rc;
if (offset > LONG_MAX) {
g_set_error(err, PV_ERROR, 0, _("Offset is too large"));
return -1;
}
rc = fseek(f, (long)offset, SEEK_SET);
if (rc != 0) {
g_set_error(err, G_FILE_ERROR,
(gint)g_file_error_from_errno(errno),
_("Failed to seek: '%s'"), g_strerror(errno));
return -1;
}
return 0;
}
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
GError **err)
{
gsize bytes_read, bytes_written;
gsize total_bytes_read = 0;
FILE *i = NULL;
gchar buf[4096];
gint ret = -1;
if (file_seek(o, offset, err) < 0)
return -1;
i = file_open(ifile->path, "rb", err);
if (!i)
return -1;
do {
if (file_read(i, buf, 1, sizeof(buf), &bytes_read, err) < 0) {
g_prefix_error(err, _("Failed to read file '%s': "),
ifile->path);
goto err;
}
if (bytes_read == 0)
break;
total_bytes_read += bytes_read;
if (file_write(o, buf, bytes_read, 1, &bytes_written, err) < 0)
goto err;
} while (bytes_written != 0);
if (ifile->size != total_bytes_read) {
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
_("'%s' has changed during the preparation"),
ifile->path);
goto err;
}
ret = 0;
err:
fclose(i);
return ret;
}
gint seek_and_write_buffer(FILE *o, const PvBuffer *buf, uint64_t offset,
GError **err)
{
if (file_seek(o, offset, err) < 0)
return -1;
if (pv_buffer_write(buf, o, err) < 0)
return -1;
return 0;
}
gint pad_file_right(const gchar *path_out, const gchar *path_in, gsize *size_out,
guint padding, GError **err)
{
FILE *f_in, *f_out = NULL;
guchar buf[padding];
gsize num_bytes_written;
gsize num_bytes_read;
uint64_t size_in = 0;
gint ret = -1;
*size_out = 0;
f_in = file_open(path_in, "rb", err);
if (!f_in)
goto err;
f_out = file_open(path_out, "wb", err);
if (!f_out)
goto err;
do {
memset(buf, 0, sizeof(buf));
if (file_read(f_in, buf, 1, sizeof(buf), &num_bytes_read, err) < 0) {
g_prefix_error(err, _("Failed to read file '%s': "),
path_in);
goto err;
}
size_in += num_bytes_read;
if (file_write(f_out, buf, 1, sizeof(buf), &num_bytes_written, err)) {
g_prefix_error(err, _("Failed to write file '%s': "),
path_out);
goto err;
}
*size_out += num_bytes_written;
} while (num_bytes_read == padding);
g_assert(num_bytes_written == ALIGN(num_bytes_read, padding));
ret = 0;
err:
if (f_out)
fclose(f_out);
if (f_in)
fclose(f_in);
return ret;
}