Add helper functions and files for gpt tests.
Review URL: http://codereview.chromium.org/1729006
diff --git a/cgptlib/Makefile b/cgptlib/Makefile
new file mode 100644
index 0000000..418163c
--- /dev/null
+++ b/cgptlib/Makefile
@@ -0,0 +1,24 @@
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+CFLAGS ?= -Wall -Werror -ansi
+INCLUDES += tests
+SUBDIRS = tests
+
+all: cgpt.a
+ for i in $(SUBDIRS); do \
+ ( cd $$i ; $(MAKE)) ; \
+ done
+
+.c.o:
+ $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+cgpt.a: cgpt.o
+ $(AR) rs cgpt.a $<
+
+clean:
+ for i in $(SUBDIRS); do \
+ ( $(MAKE) -C $$i clean ) ; \
+ done
+ rm -f cgpt cgpt-host *.o *~ *.a
diff --git a/cgptlib/cgpt.c b/cgptlib/cgpt.c
index 4504a61..4865473 100644
--- a/cgptlib/cgpt.c
+++ b/cgptlib/cgpt.c
@@ -4,24 +4,42 @@
*/
#include "cgpt.h"
+#include <string.h>
+#include "gpt.h"
+#include "utility.h"
/* stub code */
static int start[] = { 34, 10034 };
-int GPTInit(GPTData_t *gpt) {
+int GptInit(GptData_t *gpt) {
+ int valid_headers[2] = {1, 1};
+
+ /* check header signature */
+ if (Memcmp(gpt->primary_header, GPT_HEADER_SIGNATURE,
+ GPT_HEADER_SIGNATURE_SIZE))
+ valid_headers[0] = 0;
+ if (Memcmp(gpt->secondary_header, GPT_HEADER_SIGNATURE,
+ GPT_HEADER_SIGNATURE_SIZE))
+ valid_headers[1] = 0;
+
+ if (!valid_headers[0] && !valid_headers[1])
+ return GPT_ERROR_INVALID_HEADERS;
+
gpt->current_kernel = 1;
- return 0;
+ return GPT_SUCCESS;
}
-int GPTNextKernelEntry(GPTData_t *gpt, uint64_t *start_sector, uint64_t *size) {
+int GptNextKernelEntry(GptData_t *gpt, uint64_t *start_sector, uint64_t *size) {
+ /* FIXME: the following code is not really code, just returns anything */
gpt->current_kernel ^= 1;
if (start_sector) *start_sector = start[gpt->current_kernel];
if (size) *size = 10000;
- return 0;
+ return GPT_SUCCESS;
}
-int GPTUpdateKernelEntry(GPTData_t *gpt, uint32_t update_type) {
+int GptUpdateKernelEntry(GptData_t *gpt, uint32_t update_type) {
+ /* FIXME: the following code is not really code, just return anything */
gpt->modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1) <<
gpt->current_kernel;
- return 0;
+ return GPT_SUCCESS;
}
diff --git a/cgptlib/cgpt.h b/cgptlib/cgpt.h
index c9cd04d..ba32bb0 100644
--- a/cgptlib/cgpt.h
+++ b/cgptlib/cgpt.h
@@ -9,7 +9,8 @@
#include <stdint.h>
enum {
- GPT_ERROR_NO_VALID_KERNEL = 1,
+ GPT_SUCCESS = 0,
+ GPT_ERROR_NO_VALID_KERNEL,
GPT_ERROR_INVALID_HEADERS,
GPT_ERROR_INVALID_ENTRIES,
GPT_ERROR_INVALID_SECTOR_SIZE,
@@ -28,32 +29,32 @@
/* The currently selected kernel partition failed validation. Mark entry as
* invalid. */
-struct GPTData {
- /* Fill in the following fields before calling GPTInit() */
- uint8_t *header1; /* GPT primary header, from sector 1 of disk
- * (size: 512 bytes) */
- uint8_t *header2; /* GPT secondary header, from last sector of
- * disk (size: 512 bytes) */
- uint8_t *entries1; /* primary GPT table, follows primary header
- * (size: 16 KB) */
- uint8_t *entries2; /* secondary GPT table, precedes secondary
- * header (size: 16 KB) */
- uint32_t sector_bytes; /* Size of a LBA sector, in bytes */
- uint64_t drive_sectors; /* Size of drive in LBA sectors, in sectors */
+struct GptData {
+ /* Fill in the following fields before calling GptInit() */
+ uint8_t *primary_header; /* GPT primary header, from sector 1 of disk
+ * (size: 512 bytes) */
+ uint8_t *secondary_header; /* GPT secondary header, from last sector of
+ * disk (size: 512 bytes) */
+ uint8_t *primary_entries; /* primary GPT table, follows primary header
+ * (size: 16 KB) */
+ uint8_t *secondary_entries; /* secondary GPT table, precedes secondary
+ * header (size: 16 KB) */
+ uint32_t sector_bytes; /* Size of a LBA sector, in bytes */
+ uint64_t drive_sectors; /* Size of drive in LBA sectors, in sectors */
/* Outputs */
- uint8_t modified; /* Which inputs have been modified?
- * 0x01 = header1
- * 0x02 = header2
- * 0x04 = table1
- * 0x08 = table2 */
+ uint8_t modified; /* Which inputs have been modified?
+ * 0x01 = header1
+ * 0x02 = header2
+ * 0x04 = table1
+ * 0x08 = table2 */
/* Internal state */
- uint8_t current_kernel; // the current kernel index
+ uint8_t current_kernel; /* the current kernel index */
};
-typedef struct GPTData GPTData_t;
+typedef struct GptData GptData_t;
-int GPTInit(GPTData_t *gpt);
+int GptInit(GptData_t *gpt);
/* Initializes the GPT data structure's internal state. The header1, header2,
* table1, table2, and drive_size fields should be filled in first.
*
@@ -69,7 +70,7 @@
* GPT_ERROR_INVALID_SECTOR_NUMBER, number of sectors in drive is invalid (too
* small) */
-int GPTNextKernelEntry(GPTData_t *gpt, uint64_t *start_sector, uint64_t *size);
+int GptNextKernelEntry(GptData_t *gpt, uint64_t *start_sector, uint64_t *size);
/* Provides the location of the next kernel partition, in order of decreasing
* priority. On return the start_sector parameter contains the LBA sector
* for the start of the kernel partition, and the size parameter contains the
@@ -78,7 +79,7 @@
* Returns 0 if successful, else
* GPT_ERROR_NO_VALID_KERNEL, no avaliable kernel, enters recovery mode */
-int GPTUpdateKernelEntry(GPTData_t *gpt, uint32_t update_type);
+int GptUpdateKernelEntry(GptData_t *gpt, uint32_t update_type);
/* Updates the kernel entry with the specified index, using the specified type
* of update (GPT_UPDATE_ENTRY_*).
*
diff --git a/cgptlib/gpt.h b/cgptlib/gpt.h
new file mode 100644
index 0000000..95f0efb
--- /dev/null
+++ b/cgptlib/gpt.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Defines EFI related structure. See more details in EFI 2.3 spec.
+ *
+ * To download EFI standard, please visit UEFI homepage:
+ * http://www.uefi.org/
+ */
+#ifndef VBOOT_REFERENCE_CGPTLIB_GPT_H_
+#define VBOOT_REFERENCE_CGPTLIB_GPT_H_
+
+#include <stdint.h>
+
+#define GPT_HEADER_SIGNATURE "EFI PART"
+#define GPT_HEADER_SIGNATURE_SIZE sizeof(GPT_HEADER_SIGNATURE)
+#define GPT_HEADER_REVISION 0x00010000
+
+#define GPT_ENT_TYPE_EFI \
+ {{Uuid: {0xc12a7328,0xf81f,0x11d2,0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}}}}
+#define GPT_ENT_TYPE_UNUSED \
+ {{Uuid: {0x00000000,0x0000,0x0000,0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}}}}
+#define GPT_ENT_TYPE_CHROMEOS_KERNEL \
+ {{Uuid: {0xfe3a2a5d,0x4f32,0x41a7,0xb7,0x25,{0xac,0xcc,0x32,0x85,0xa3,0x09}}}}
+#define GPT_ENT_TYPE_CHROMEOS_ROOTFS \
+ {{Uuid: {0x3cb8e202,0x3b7e,0x47dd,0x8a,0x3c,{0x7f,0xf2,0xa1,0x3c,0xfc,0xec}}}}
+#define GPT_ENT_TYPE_CHROMEOS_RESERVED \
+ {{Uuid: {0x2e0a753d,0x9e48,0x43b0,0x83,0x37,{0xb1,0x51,0x92,0xcb,0x1b,0x5e}}}}
+
+#define UUID_NODE_LEN 6
+#define GUID_SIZE 16
+
+/* GUID definition.
+ * Defined in appendix A of EFI standard.
+ */
+typedef struct {
+ union {
+ struct {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_high_and_version;
+ uint8_t clock_seq_high_and_reserved;
+ uint8_t clock_seq_low;
+ uint8_t node[UUID_NODE_LEN];
+ } Uuid;
+ uint8_t raw[GUID_SIZE];
+ };
+} __attribute__((packed)) Guid;
+
+/* GPT header defines how many partitions exist on a drive and sectors managed.
+ * For every drive device, there are 2 headers, primary and secondary.
+ * Most of fields are duplicated except my_lba and entries_lba.
+ *
+ * You may find more details in chapter 5 of EFI standard.
+ */
+typedef struct {
+ char signature[8];
+ uint32_t revision;
+ uint32_t size;
+ uint32_t header_crc32;
+ uint32_t reserved;
+ uint64_t my_lba;
+ uint64_t alternate_lba;
+ uint64_t first_usable_lba;
+ uint64_t last_usable_lba;
+ Guid disk_uuid;
+
+ uint64_t entries_lba;
+ uint32_t number_of_entries;
+ uint32_t size_of_entry;
+ uint32_t entries_crc32;
+ uint32_t padding; /* since header size must be a multiple of 8, pad here. */
+} GptHeader;
+
+/* GPT partition entry defines the starting and ending LBAs of a partition.
+ * It also contains the unique GUID, type, and attribute bits.
+ *
+ * You may find more details in chapter 5 of EFI standard.
+ */
+typedef struct {
+ Guid type;
+ Guid unique;
+ uint64_t starting_lba;
+ uint64_t ending_lba;
+ uint64_t attributes;
+ uint16_t name[36]; /* UTF-16 encoded partition name */
+} GptEntry;
+
+#endif /* VBOOT_REFERENCE_CGPTLIB_GPT_H_ */
diff --git a/cgptlib/tests/Makefile b/cgptlib/tests/Makefile
new file mode 100644
index 0000000..60871fa
--- /dev/null
+++ b/cgptlib/tests/Makefile
@@ -0,0 +1,20 @@
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+CC ?= cc
+CFLAGS ?= -Wall -DNDEBUG -Werror -ansi
+LIBS = ../cgpt.a ../../common/libcommon.a
+OBJS = cgpt_test.o
+OUT = cgpt_test
+
+all: $(OUT)
+
+$(OUT): $(OBJS) $(LIBS)
+ $(CC) -o $@ $^
+
+.c.o:
+ $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+clean:
+ rm -rf $(OUT) $(OBJS)
diff --git a/cgptlib/tests/cgpt_test.c b/cgptlib/tests/cgpt_test.c
index b5b26e7..a451838 100644
--- a/cgptlib/tests/cgpt_test.c
+++ b/cgptlib/tests/cgpt_test.c
@@ -3,12 +3,219 @@
* found in the LICENSE file.
*/
-#include "cgpt.h"
#include "cgpt_test.h"
+#include <string.h>
+#include "cgpt.h"
+#include "gpt.h"
+#include "utility.h"
+
+/* Testing partition layout (sector_bytes=512)
+ *
+ * LBA Size Usage
+ * 0 1 PMBR
+ * 1 1 primary partition header
+ * 2 32 primary partition entries (128B * 128)
+ * 34 100 kernel A
+ * 134 100 kernel B
+ * 234 100 root A
+ * 334 100 root B
+ * 434 32 secondary partition entries
+ * 466 1 secondary partition header
+ * 467
+ */
+#define DEFAULT_SECTOR_SIZE 512
+#define MAX_SECTOR_SIZE 4096
+#define DEFAULT_DRIVE_SECTORS 467
+#define PARTITION_ENTRIES_SIZE (16*1024)
#define TEST_CASE(func) #func, func
typedef int (*test_func)(void);
+/* NOT A REAL CRC32, it is fake before I call real one . FIXME */
+uint32_t CalculateCrc32(const uint8_t *start, size_t len) {
+ uint32_t buf = 0;
+ int i;
+ for (i = 0; i < len; i += 4, len -= 4) {
+ buf ^= *(uint32_t*)&start[i];
+ }
+ if (len >= 3) buf ^= start[i-2] << 16;
+ if (len >= 2) buf ^= start[i-3] << 8;
+ if (len >= 1) buf ^= start[i-4];
+ return buf;
+}
+
+/* Given a GptData pointer, first re-calculate entries CRC32 value,
+ * then reset header CRC32 value to 0, and calculate header CRC32 value.
+ * Both primary and secondary are updated. */
+void RefreshCrc32(struct GptData *gpt) {
+ GptHeader *header, *header2;
+ GptEntry *entries, *entries2;
+
+ header = (GptHeader*)gpt->primary_header;
+ entries = (GptEntry*)gpt->primary_entries;
+ header2 = (GptHeader*)gpt->secondary_header;
+ entries2 = (GptEntry*)gpt->secondary_entries;
+
+ header->entries_crc32 = CalculateCrc32((uint8_t*)entries,
+ sizeof(GptEntry));
+ header->header_crc32 = 0;
+ header->header_crc32 = CalculateCrc32((uint8_t*)header,
+ header->size);
+ header2->entries_crc32 = CalculateCrc32((uint8_t*)entries2,
+ sizeof(GptEntry));
+ header2->header_crc32 = 0;
+ header2->header_crc32 = CalculateCrc32((uint8_t*)header2,
+ header2->size);
+}
+
+/* Returns a pointer to a static GptData instance (no free is required).
+ * All fields are zero except 4 pointers linking to header and entries.
+ * All content of headers and entries are zero. */
+struct GptData* GetAClearGptData() {
+ static GptData_t gpt;
+ static uint8_t primary_header[MAX_SECTOR_SIZE];
+ static uint8_t primary_entries[PARTITION_ENTRIES_SIZE];
+ static uint8_t secondary_header[MAX_SECTOR_SIZE];
+ static uint8_t secondary_entries[PARTITION_ENTRIES_SIZE];
+
+ Memset(&gpt, 0, sizeof(gpt));
+ Memset(&primary_header, 0, sizeof(primary_header));
+ Memset(&primary_entries, 0, sizeof(primary_entries));
+ Memset(&secondary_header, 0, sizeof(secondary_header));
+ Memset(&secondary_entries, 0, sizeof(secondary_entries));
+
+ gpt.primary_header = primary_header;
+ gpt.primary_entries = primary_entries;
+ gpt.secondary_header = secondary_header;
+ gpt.secondary_entries = secondary_entries;
+
+ return &gpt;
+}
+
+/* Fills in most of fields and creates the layout described in the top of this
+ * file. */
+struct GptData*
+BuildTestGptData(uint32_t sector_bytes) {
+ GptData_t *gpt;
+ GptHeader *header, *header2;
+ GptEntry *entries, *entries2;
+ Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
+
+ gpt = GetAClearGptData();
+ gpt->sector_bytes = sector_bytes;
+ gpt->drive_sectors = DEFAULT_DRIVE_SECTORS;
+
+ /* build primary */
+ header = (GptHeader*)gpt->primary_header;
+ entries = (GptEntry*)gpt->primary_entries;
+ Memcpy(header->signature, GPT_HEADER_SIGNATURE, sizeof(GPT_HEADER_SIGNATURE));
+ header->revision = GPT_HEADER_REVISION;
+ header->size = sizeof(GptHeader) - sizeof(header->padding);
+ header->my_lba = 1;
+ header->first_usable_lba = 34;
+ header->last_usable_lba = DEFAULT_DRIVE_SECTORS - 1 - 32 - 1; /* 433 */
+ header->entries_lba = 2;
+ header->number_of_entries = 128; /* 512B / 128B * 32sectors = 128 entries */
+ header->size_of_entry = 128; /* bytes */
+ Memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel));
+ entries[0].starting_lba = 34;
+ entries[0].ending_lba = 133;
+ Memcpy(&entries[1].type, &chromeos_kernel, sizeof(chromeos_kernel));
+ entries[1].starting_lba = 134;
+ entries[1].ending_lba = 233;
+ Memcpy(&entries[2].type, &chromeos_kernel, sizeof(chromeos_kernel));
+ entries[2].starting_lba = 234;
+ entries[2].ending_lba = 333;
+ Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
+ entries[3].starting_lba = 334;
+ entries[3].ending_lba = 433;
+
+ /* build secondary */
+ header2 = (GptHeader*)gpt->secondary_header;
+ entries2 = (GptEntry*)gpt->secondary_entries;
+ Memcpy(header2, header, sizeof(header));
+ Memcpy(entries2, entries, sizeof(entries));
+ header2->my_lba = DEFAULT_DRIVE_SECTORS - 1; /* 466 */
+ header2->entries_lba = DEFAULT_DRIVE_SECTORS - 1 - 32; /* 434 */
+
+ RefreshCrc32(gpt);
+ return gpt;
+}
+
+/* Dumps memory starting from [vp] with [len] bytes.
+ * Prints [memo] if not NULL. Example output:
+ *
+ * 00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f
+ * 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f
+ * ...
+ */
+static void dump(void *vp, int len, char* memo) {
+ uint8_t *start = vp;
+ int i;
+ if (memo) printf("--[%s]----------\n", memo);
+ for (i = 0; i < len; ++i) {
+ printf("%02x%s", start[i],
+ (!(~i & 15) ? "\n" :
+ !(~i & 7) ? " - ": " "));
+ }
+ if (i&15) printf("\n");
+}
+
+/* More formatted dump with GptData. */
+void DumpGptData(struct GptData *gpt) {
+ printf("DumpGptData(%p)...\n", gpt);
+ dump(gpt, sizeof(gpt), NULL);
+ dump(gpt->primary_header, sizeof(GptHeader), "Primary header");
+ dump(gpt->primary_entries, sizeof(GptEntry) * 8, "Primary entries");
+ dump(gpt->secondary_header, sizeof(GptHeader), "Secondary header");
+ dump(gpt->secondary_entries, sizeof(GptEntry) * 8,
+ "Secondary entries");
+}
+
+/* Tests if signature ("EFI PART") is checked. */
+int SignatureTest() {
+ int i;
+ GptData_t *gpt;
+ GptHeader *primary_header, *secondary_header;
+
+ gpt = BuildTestGptData(DEFAULT_SECTOR_SIZE);
+ primary_header = (GptHeader*)gpt->primary_header;
+ secondary_header = (GptHeader*)gpt->secondary_header;
+
+ EXPECT(GPT_SUCCESS == GptInit(gpt));
+
+ /* change every char in signature of primary. Secondary is still valid. */
+ for (i = 0; i < 8; ++i) {
+ gpt->primary_header[i] ^= 0xff;
+ RefreshCrc32(gpt);
+ EXPECT(GPT_SUCCESS == GptInit(gpt));
+ gpt->primary_header[i] ^= 0xff;
+ RefreshCrc32(gpt);
+ }
+
+ /* change every char in signature of secondary. Primary is still valid. */
+ for (i = 0; i < 8; ++i) {
+ gpt->secondary_header[i] ^= 0xff;
+ RefreshCrc32(gpt);
+ EXPECT(GPT_SUCCESS == GptInit(gpt));
+ gpt->secondary_header[i] ^= 0xff;
+ RefreshCrc32(gpt);
+ }
+
+ /* change every char in signature of primary and secondary. Expect fail. */
+ for (i = 0; i < 8; ++i) {
+ gpt->primary_header[i] ^= 0xff;
+ gpt->secondary_header[i] ^= 0xff;
+ RefreshCrc32(gpt);
+ EXPECT(GPT_ERROR_INVALID_HEADERS == GptInit(gpt));
+ gpt->primary_header[i] ^= 0xff;
+ gpt->secondary_header[i] ^= 0xff;
+ RefreshCrc32(gpt);
+ }
+
+ return TEST_OK;
+}
+
/* Tests if header CRC in two copies are calculated. */
int HeaderCrcTest() {
return TEST_FAIL;
@@ -45,7 +252,7 @@
return TEST_FAIL;
}
-/* Tests if GPTInit() handles non-identical partition entries well.
+/* Tests if GptInit() handles non-identical partition entries well.
* Two copies of partition table entries must be identical. If not, we trust the
* primary table entries, and mark secondary as modified (see Caller's write-
* back order below). */
@@ -53,7 +260,7 @@
return TEST_FAIL;
}
-/* Tests if GPTInit() handles non-identical headers well.
+/* Tests if GptInit() handles non-identical headers well.
* Two partition headers must be identical. If not, we trust the primary
* partition header, and mark secondary as modified (see Caller's write-back
* order below). */
@@ -84,7 +291,7 @@
return TEST_FAIL;
}
-/* Tests if GPTNextKernelEntry() can survive in different corrupt header/entries
+/* Tests if GptNextKernelEntry() can survive in different corrupt header/entries
* combinations, like:
* primary GPT header - valid
* primary partition table - invalid
@@ -102,6 +309,8 @@
test_func fp;
int retval;
} test_cases[] = {
+ { TEST_CASE(SignatureTest), },
+#if 0
{ TEST_CASE(HeaderCrcTest), },
{ TEST_CASE(MyLbaTest), },
{ TEST_CASE(SizeOfPartitionEntryTest), },
@@ -114,6 +323,7 @@
{ TEST_CASE(ValidEntryTest), },
{ TEST_CASE(NoOverlappedPartitionTest), },
{ TEST_CASE(CorruptCombinationTest), },
+#endif
};
for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) {
diff --git a/cgptlib/tests/cgpt_test.h b/cgptlib/tests/cgpt_test.h
index 0dcb637..4a8b115 100644
--- a/cgptlib/tests/cgpt_test.h
+++ b/cgptlib/tests/cgpt_test.h
@@ -7,7 +7,10 @@
#include <stdio.h>
-#define TEST_FAIL -1
+enum {
+ TEST_FAIL = -1,
+ TEST_OK = 0,
+};
/* ANSI Color coding sequences. */
#define COL_GREEN "\e[1;32m"
diff --git a/common/include/utility.h b/common/include/utility.h
index 8619cd2..a5df8fa 100644
--- a/common/include/utility.h
+++ b/common/include/utility.h
@@ -40,6 +40,12 @@
/* Free memory pointed by [ptr] previously allocated by Malloc(). */
void Free(void* ptr);
+/* Compare [n] bytes in [src1] and [src2]
+ * Returns an integer less than, equal to, or greater than zero if the first [n]
+ * bytes of [src1] is found, respectively, to be less than, to match, or be
+ * greater than the first n bytes of [src2]. */
+int Memcmp(const void* src1, const void* src2, size_t n);
+
/* Copy [n] bytes from [src] to [dest]. */
void* Memcpy(void* dest, const void* src, size_t n);
diff --git a/common/utility_stub.c b/common/utility_stub.c
index d2244c7..6613270 100644
--- a/common/utility_stub.c
+++ b/common/utility_stub.c
@@ -42,6 +42,10 @@
free(ptr);
}
+int Memcmp(const void* src1, const void* src2, size_t n) {
+ return memcmp(src1, src2, n);
+}
+
void* Memcpy(void* dest, const void* src, size_t n) {
return memcpy(dest, src, n);
}