]> sigrok.org Git - libsigrok.git/commitdiff
input: Use fseeko/ftello to get the size of a file
authorDaniel Elstner <redacted>
Sat, 19 Sep 2015 18:43:25 +0000 (20:43 +0200)
committerDaniel Elstner <redacted>
Thu, 1 Oct 2015 13:44:55 +0000 (15:44 +0200)
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.

src/input/input.c
src/libsigrok-internal.h

index fa5a6f7c4f709e72dd6ab52697d35d54a019f148..e93925d2b1c590572d7eb5b66ad7fa839b57d283 100644 (file)
 
 #include <config.h>
 #include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <errno.h>
 #include <glib.h>
 #include <glib/gstdio.h>
@@ -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;
index 624a141c7e34fb39ad9662c5a9eae361d0ab825e..c8940c89ad109ae1adbcc562f5e066af57a34bfb 100644 (file)
@@ -25,6 +25,7 @@
 #define LIBSIGROK_LIBSIGROK_INTERNAL_H
 
 #include <stdarg.h>
+#include <stdio.h>
 #include <glib.h>
 #ifdef HAVE_LIBUSB_1_0
 #include <libusb.h>
@@ -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))