From: Daniel Elstner Date: Sat, 19 Sep 2015 18:43:25 +0000 (+0200) Subject: input: Use fseeko/ftello to get the size of a file X-Git-Tag: libsigrok-0.4.0~245 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=4619fab47acf4fb0a1c035072c2e8552b4bcbae3;p=libsigrok.git input: Use fseeko/ftello to get the size of a file Introduce the sr_file_get_size() utility function to retrieve the size of an open FILE stream. This is based on fseeko() followed by ftello(), which are POSIX functions but quite portable in practice. Since these calls operate on FILE streams instead of filenames, the issue of filename encoding no longer arises. --- diff --git a/src/input/input.c b/src/input/input.c index fa5a6f7c..e93925d2 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -19,10 +19,6 @@ #include #include -#include -#include -#include -#include #include #include #include @@ -407,6 +403,43 @@ SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in) return ret; } +/** Retrieve the size of the open stream @a file. + * This function only works on seekable streams. However, the set of seekable + * streams is generally congruent with the set of streams that have a size. + * Code that needs to work with any type of stream (including pipes) should + * require neither seekability nor advance knowledge of the size. + * On failure, the return value is negative and errno is set. + * @param file An I/O stream opened in binary mode. + * @return The size of @a file in bytes, or a negative value on failure. + */ +SR_PRIV int64_t sr_file_get_size(FILE *file) +{ + off_t filepos, filesize; + + /* ftello() and fseeko() are not standard C, but part of POSIX.1-2001. + * Thus, if these functions are available at all, they can reasonably + * be expected to also conform to POSIX semantics. In particular, this + * means that ftello() after fseeko(..., SEEK_END) has a defined result + * and can be used to get the size of a seekable stream. + * On Windows, the result is fully defined only for binary streams. + */ + filepos = ftello(file); + if (filepos < 0) + return -1; + + if (fseeko(file, 0, SEEK_END) < 0) + return -1; + + filesize = ftello(file); + if (filesize < 0) + return -1; + + if (fseeko(file, filepos, SEEK_SET) < 0) + return -1; + + return filesize; +} + /** * Try to find an input module that can parse the given file. * @@ -416,11 +449,11 @@ SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in) */ SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in) { + int64_t filesize; FILE *stream; const struct sr_input_module *imod; GHashTable *meta; GString *header; - struct stat st; size_t count; unsigned int midx, i; int ret; @@ -432,22 +465,18 @@ SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in) sr_err("Invalid filename."); return SR_ERR_ARG; } - - if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { - sr_err("No such file."); - return SR_ERR_ARG; - } - - if (stat(filename, &st) < 0) { - sr_err("%s", g_strerror(errno)); - return SR_ERR_ARG; - } - stream = g_fopen(filename, "rb"); if (!stream) { sr_err("Failed to open %s: %s", filename, g_strerror(errno)); return SR_ERR; } + filesize = sr_file_get_size(stream); + if (filesize < 0) { + sr_err("Failed to get size of %s: %s", + filename, g_strerror(errno)); + fclose(stream); + return SR_ERR; + } /* This actually allocates 256 bytes to allow for NUL termination. */ header = g_string_sized_new(255); count = fread(header->str, 1, header->allocated_len - 1, stream); @@ -465,7 +494,7 @@ SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in) g_hash_table_insert(meta, GINT_TO_POINTER(SR_INPUT_META_FILENAME), (char *)filename); g_hash_table_insert(meta, GINT_TO_POINTER(SR_INPUT_META_FILESIZE), - GSIZE_TO_POINTER(st.st_size)); + GSIZE_TO_POINTER(MIN(filesize, G_MAXSSIZE))); g_hash_table_insert(meta, GINT_TO_POINTER(SR_INPUT_META_HEADER), header); midx = 0; diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index 624a141c..c8940c89 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -25,6 +25,7 @@ #define LIBSIGROK_LIBSIGROK_INTERNAL_H #include +#include #include #ifdef HAVE_LIBUSB_1_0 #include @@ -585,6 +586,10 @@ struct drv_context { GSList *instances; }; +/*--- input/input.c ---------------------------------------------------------*/ + +SR_PRIV int64_t sr_file_get_size(FILE *file); + /*--- log.c -----------------------------------------------------------------*/ #if defined(G_OS_WIN32) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))