[Groonga-commit] groonga/groonga at a2397de [master] Add missing error report on opening file

Back to archive index

Kouhei Sutou null+****@clear*****
Mon Feb 8 16:24:59 JST 2016


Kouhei Sutou	2016-02-08 16:24:59 +0900 (Mon, 08 Feb 2016)

  New Revision: a2397def8defe7a4addf39f68fef529f9cdedc8e
  https://github.com/groonga/groonga/commit/a2397def8defe7a4addf39f68fef529f9cdedc8e

  Message:
    Add missing error report on opening file

  Modified files:
    lib/io.c
    test/command_line/suite/grndb/test_recover.rb

  Modified: lib/io.c (+53 -15)
===================================================================
--- lib/io.c    2016-02-08 14:39:44 +0900 (9913c8a)
+++ lib/io.c    2016-02-08 16:24:59 +0900 (6a63521)
@@ -518,36 +518,74 @@ grn_io_detect_type(grn_ctx *ctx, const char *path)
 grn_io *
 grn_io_open(grn_ctx *ctx, const char *path, grn_io_mode mode)
 {
+  size_t max_path_len = PATH_MAX - 4;
   grn_io *io;
   struct stat s;
   fileinfo fi;
   uint32_t flags = 0;
   uint32_t b;
   uint32_t header_size = 0, segment_size = 0, max_segment = 0, bs;
-  if (!path || !*path || (strlen(path) > PATH_MAX - 4)) { return NULL; }
+  if (!path || !*path) {
+    ERR(GRN_INVALID_ARGUMENT, "[io][open] path is missing");
+    return NULL;
+  }
+  if ((strlen(path) > max_path_len)) {
+    int truncate_length = 10;
+    ERR(GRN_INVALID_ARGUMENT,
+        "[io][open] path is too long: "
+        "<%" GRN_FMT_SIZE ">(max: %" GRN_FMT_SIZE "): <%.*s...>",
+        strlen(path),
+        max_path_len,
+        truncate_length,
+        path);
+    return NULL;
+  }
   {
     struct _grn_io_header h;
     int fd;
+    ssize_t read_bytes;
     grn_open(fd, path, O_RDWR | GRN_OPEN_FLAG_BINARY);
     if (fd == -1) {
       ERRNO_ERR("failed to open path: <%s>",
                 path);
       return NULL;
     }
-    if (fstat(fd, &s) != -1 && s.st_size >= sizeof(struct _grn_io_header)) {
-      if (grn_read(fd, &h, sizeof(struct _grn_io_header)) == sizeof(struct _grn_io_header)) {
-        if (!memcmp(h.idstr, GRN_IO_IDSTR, GRN_IO_IDSTR_LEN)) {
-          header_size = h.header_size;
-          segment_size = h.segment_size;
-          max_segment = h.max_segment;
-          flags = h.flags;
-        } else {
-          ERR(GRN_INCOMPATIBLE_FILE_FORMAT,
-              "failed to open: format ID is different: <%s>: <%.*s>",
-              path,
-              (int)GRN_IO_IDSTR_LEN, GRN_IO_IDSTR);
-        }
-      }
+    if (fstat(fd, &s) == -1) {
+      ERRNO_ERR("[io][open] failed to file status: <%s>",
+                path);
+      grn_close(fd);
+      return NULL;
+    }
+    if (s.st_size < sizeof(struct _grn_io_header)) {
+      ERR(GRN_INCOMPATIBLE_FILE_FORMAT,
+          "[io][open] file size is too small: "
+          "<%" GRN_FMT_SIZE ">(required: >= %" GRN_FMT_SIZE "): <%s>",
+          s.st_size,
+          sizeof(struct _grn_io_header),
+          path);
+      grn_close(fd);
+      return NULL;
+    }
+    read_bytes = grn_read(fd, &h, sizeof(struct _grn_io_header));
+    if (read_bytes != sizeof(struct _grn_io_header)) {
+      ERRNO_ERR("[io][open] failed to read header data: "
+                "<%" GRN_FMT_SSIZE ">(expected: %" GRN_FMT_SSIZE "): <%s>",
+                read_bytes,
+                sizeof(struct _grn_io_header),
+                path);
+      grn_close(fd);
+      return NULL;
+    }
+    if (!memcmp(h.idstr, GRN_IO_IDSTR, GRN_IO_IDSTR_LEN)) {
+      header_size = h.header_size;
+      segment_size = h.segment_size;
+      max_segment = h.max_segment;
+      flags = h.flags;
+    } else {
+      ERR(GRN_INCOMPATIBLE_FILE_FORMAT,
+          "failed to open: format ID is different: <%s>: <%.*s>",
+          path,
+          (int)GRN_IO_IDSTR_LEN, GRN_IO_IDSTR);
     }
     grn_close(fd);
     if (!segment_size) { return NULL; }

  Modified: test/command_line/suite/grndb/test_recover.rb (+59 -0)
===================================================================
--- test/command_line/suite/grndb/test_recover.rb    2016-02-08 14:39:44 +0900 (06286fc)
+++ test/command_line/suite/grndb/test_recover.rb    2016-02-08 16:24:59 +0900 (4302869)
@@ -50,4 +50,63 @@ object corrupt: <[db][recover] column may be broken: <Users.age>: please truncat
     result = grndb("recover")
     assert_equal("", result.error_output)
   end
+
+  def test_empty_file
+    groonga("table_create", "Users", "TABLE_HASH_KEY", "ShortText")
+    _id, _name, path, *_ = JSON.parse(groonga("table_list").output)[1][1]
+    FileUtils.rm(path)
+    FileUtils.touch(path)
+    error = assert_raise(CommandRunner::Error) do
+      grndb("recover")
+    end
+    assert_equal(<<-MESSAGE, error.error_output)
+Failed to recover database: <#{@database_path}>
+incompatible file format: <[io][open] file size is too small: <0>(required: >= 64): <#{path[0..68]}>(-65)
+    MESSAGE
+  end
+
+  def test_broken_id
+    groonga("table_create", "Users", "TABLE_HASH_KEY", "ShortText")
+    _id, _name, path, *_ = JSON.parse(groonga("table_list").output)[1][1]
+    data = File.binread(path)
+    data[0] = "X"
+    File.binwrite(path, data)
+    error = assert_raise(CommandRunner::Error) do
+      grndb("recover")
+    end
+    assert_equal(<<-MESSAGE, error.error_output)
+Failed to recover database: <#{@database_path}>
+incompatible file format: <failed to open: format ID is different: <#{path[0..85]}>(-65)
+    MESSAGE
+  end
+
+  def test_broken_type_hash
+    groonga("table_create", "Users", "TABLE_HASH_KEY", "ShortText")
+    _id, _name, path, *_ = JSON.parse(groonga("table_list").output)[1][1]
+    data = File.binread(path)
+    data[16] = "\0"
+    File.binwrite(path, data)
+    error = assert_raise(CommandRunner::Error) do
+      grndb("recover")
+    end
+    assert_equal(<<-MESSAGE, error.error_output)
+Failed to recover database: <#{@database_path}>
+invalid format: <[table][hash] file type must be 0x30: <0000>>(-54)
+    MESSAGE
+  end
+
+  def test_broken_type_array
+    groonga("table_create", "Logs", "TABLE_NO_KEY")
+    _id, _name, path, *_ = JSON.parse(groonga("table_list").output)[1][1]
+    data = File.binread(path)
+    data[16] = "\0"
+    File.binwrite(path, data)
+    error = assert_raise(CommandRunner::Error) do
+      grndb("recover")
+    end
+    assert_equal(<<-MESSAGE, error.error_output)
+Failed to recover database: <#{@database_path}>
+invalid format: <[table][array] file type must be 0x33: <0000>>(-54)
+    MESSAGE
+  end
 end
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index