Commit df627317 authored by Philip Withnall's avatar Philip Withnall

Merge branch 'win32-symlink-refactoring' into 'master'

Win32 symlink code refactoring

See merge request !269
parents c27eac87 357c5a47
Pipeline #67908 passed with stages
in 18 minutes and 14 seconds
......@@ -76,6 +76,7 @@ typedef struct _GFileInfoClass GFileInfoClass;
* A key in the "standard" namespace for checking if the file is a symlink.
* Typically the actual type is something else, if we followed the symlink
* to get the type.
* On Windows NTFS mountpoints are considered to be symlinks as well.
* Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
**/
#define G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK "standard::is-symlink" /* boolean */
......
......@@ -361,6 +361,15 @@ typedef enum {
* @G_FILE_TYPE_MOUNTABLE: File is a mountable location.
*
* Indicates the file's on-disk type.
*
* On Windows systems a file will never have %G_FILE_TYPE_SYMBOLIC_LINK type;
* use #GFileInfo and %G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK to determine
* whether a file is a symlink or not. This is due to the fact that NTFS does
* not have a single filesystem object type for symbolic links - it has
* files that symlink to files, and directories that symlink to directories.
* #GFileType enumeration cannot precisely represent this important distinction,
* which is why all Windows symlinks will continue to be reported as
* %G_FILE_TYPE_REGULAR or %G_FILE_TYPE_DIRECTORY.
**/
typedef enum {
G_FILE_TYPE_UNKNOWN = 0,
......
......@@ -161,7 +161,7 @@ _g_local_file_info_create_fs_id (GLocalFileStat *statbuf)
static gchar *
read_link (const gchar *full_name)
{
#if defined (HAVE_READLINK) || defined (G_OS_WIN32)
#if defined (HAVE_READLINK)
gchar *buffer;
guint size;
......@@ -171,12 +171,8 @@ read_link (const gchar *full_name)
while (1)
{
int read_size;
#ifndef G_OS_WIN32
read_size = readlink (full_name, buffer, size);
#else
read_size = GLIB_PRIVATE_CALL (g_win32_readlink_utf8) (full_name, buffer, size);
#endif
if (read_size < 0)
{
g_free (buffer);
......@@ -190,6 +186,17 @@ read_link (const gchar *full_name)
size *= 2;
buffer = g_realloc (buffer, size);
}
#elif defined (G_OS_WIN32)
gchar *buffer;
int read_size;
read_size = GLIB_PRIVATE_CALL (g_win32_readlink_utf8) (full_name, NULL, 0, &buffer, TRUE);
if (read_size < 0)
return NULL;
else if (read_size == 0)
return strdup ("");
else
return buffer;
#else
return NULL;
#endif
......@@ -957,8 +964,8 @@ set_info_from_stat (GFileInfo *info,
else if (S_ISLNK (statbuf->st_mode))
file_type = G_FILE_TYPE_SYMBOLIC_LINK;
#elif defined (G_OS_WIN32)
if (statbuf->reparse_tag == IO_REPARSE_TAG_SYMLINK ||
statbuf->reparse_tag == IO_REPARSE_TAG_MOUNT_POINT)
else if (statbuf->reparse_tag == IO_REPARSE_TAG_SYMLINK ||
statbuf->reparse_tag == IO_REPARSE_TAG_MOUNT_POINT)
file_type = G_FILE_TYPE_SYMBOLIC_LINK;
#endif
......@@ -966,15 +973,17 @@ set_info_from_stat (GFileInfo *info,
g_file_info_set_size (info, statbuf->st_size);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_DEVICE, statbuf->st_dev);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_NLINK, statbuf->st_nlink);
#ifndef G_OS_WIN32
/* Pointless setting these on Windows even if they exist in the struct */
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_INODE, statbuf->st_ino);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_NLINK, statbuf->st_nlink);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_UID, statbuf->st_uid);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_GID, statbuf->st_gid);
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_RDEV, statbuf->st_rdev);
#endif
/* FIXME: st_mode is mostly pointless on Windows, too. Set the attribute or not? */
/* Mostly pointless on Windows.
* Still, it allows for S_ISREG/S_ISDIR and IWRITE (read-only) checks.
*/
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_MODE, statbuf->st_mode);
#if defined (HAVE_STRUCT_STAT_ST_BLKSIZE)
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_BLOCK_SIZE, statbuf->st_blksize);
......
......@@ -291,10 +291,10 @@ test_internal_enhanced_stdio (void)
ft_programdata = g_file_info_get_file_type (fi_programdata);
ft_commondata = g_file_info_get_file_type (fi_commondata);
g_assert_cmpint (ft_allusers, ==, G_FILE_TYPE_SYMBOLIC_LINK);
g_assert_cmpint (ft_allusers, ==, G_FILE_TYPE_DIRECTORY);
g_assert_cmpint (ft_allusers_target, ==, G_FILE_TYPE_DIRECTORY);
g_assert_cmpint (ft_programdata, ==, G_FILE_TYPE_DIRECTORY);
g_assert_cmpint (ft_commondata, ==, G_FILE_TYPE_SYMBOLIC_LINK);
g_assert_cmpint (ft_commondata, ==, G_FILE_TYPE_DIRECTORY);
allusers_is_symlink = g_file_info_get_attribute_boolean (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
allusers_reparse_tag = g_file_info_get_attribute_uint32 (fi_allusers, G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG);
......
......@@ -2090,7 +2090,7 @@ gchar *
g_file_read_link (const gchar *filename,
GError **error)
{
#if defined (HAVE_READLINK) || defined (G_OS_WIN32)
#if defined (HAVE_READLINK)
gchar *buffer;
size_t size;
gssize read_size;
......@@ -2103,11 +2103,7 @@ g_file_read_link (const gchar *filename,
while (TRUE)
{
#ifndef G_OS_WIN32
read_size = readlink (filename, buffer, size);
#else
read_size = g_win32_readlink_utf8 (filename, buffer, size);
#endif
if (read_size < 0)
{
int saved_errno = errno;
......@@ -2128,6 +2124,27 @@ g_file_read_link (const gchar *filename,
size *= 2;
buffer = g_realloc (buffer, size);
}
#elif defined (G_OS_WIN32)
gchar *buffer;
gssize read_size;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
read_size = g_win32_readlink_utf8 (filename, NULL, 0, &buffer, TRUE);
if (read_size < 0)
{
int saved_errno = errno;
set_file_error (error,
filename,
_("Failed to read the symbolic link “%s”: %s"),
saved_errno);
return NULL;
}
else if (read_size == 0)
return strdup ("");
else
return buffer;
#else
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
......
......@@ -61,18 +61,20 @@ typedef struct {
/* See gstdio.c */
#ifdef G_OS_WIN32
int (* g_win32_stat_utf8) (const gchar *filename,
GWin32PrivateStat *buf);
int (* g_win32_stat_utf8) (const gchar *filename,
GWin32PrivateStat *buf);
int (* g_win32_lstat_utf8) (const gchar *filename,
GWin32PrivateStat *buf);
int (* g_win32_lstat_utf8) (const gchar *filename,
GWin32PrivateStat *buf);
int (* g_win32_readlink_utf8) (const gchar *filename,
gchar *buf,
gsize buf_size);
int (* g_win32_readlink_utf8) (const gchar *filename,
gchar *buf,
gsize buf_size,
gchar **alloc_buf,
gboolean terminate);
int (* g_win32_fstat) (int fd,
GWin32PrivateStat *buf);
int (* g_win32_fstat) (int fd,
GWin32PrivateStat *buf);
#endif
......
......@@ -75,3 +75,92 @@ _g_win32_strip_extended_ntobjm_prefix (gunichar2 *str,
return do_move;
}
static int
_g_win32_copy_and_maybe_terminate (const guchar *data,
gsize in_to_copy,
gunichar2 *buf,
gsize buf_size,
gunichar2 **alloc_buf,
gboolean terminate)
{
gsize to_copy = in_to_copy;
/* Number of bytes we can use to add extra zeroes for NUL-termination.
* 0 means that we can destroy up to 2 bytes of data,
* 1 means that we can destroy up to 1 byte of data,
* 2 means that we do not perform destructive NUL-termination
*/
gsize extra_bytes = terminate ? 2 : 0;
char *buf_in_chars;
if (to_copy == 0)
return 0;
/* 2 bytes is sizeof (wchar_t), for an extra NUL-terminator. */
if (buf)
{
if (to_copy >= buf_size)
{
extra_bytes = 0;
to_copy = buf_size;
}
else if (to_copy > buf_size - 2)
{
extra_bytes = 1;
}
memcpy (buf, data, to_copy);
}
else
{
/* Note that SubstituteNameLength is USHORT, so to_copy + 2, being
* gsize, never overflows.
*/
*alloc_buf = g_malloc (to_copy + extra_bytes);
memcpy (*alloc_buf, data, to_copy);
}
if (!terminate)
return to_copy;
if (buf)
buf_in_chars = (char *) buf;
else
buf_in_chars = (char *) *alloc_buf;
if (to_copy >= 2 && buf_in_chars[to_copy - 2] == 0 &&
buf_in_chars[to_copy - 1] == 0)
{
/* Fully NUL-terminated, do nothing */
}
else if ((to_copy == 1 || buf_in_chars[to_copy - 2] != 0) &&
buf_in_chars[to_copy - 1] == 0)
{
/* Have one zero, try to add another one */
if (extra_bytes > 0)
{
/* Append trailing zero */
buf_in_chars[to_copy] = 0;
/* Be precise about the number of bytes we return */
to_copy += 1;
}
else if (to_copy >= 2)
{
/* No space for appending, destroy one byte */
buf_in_chars[to_copy - 2] = 0;
}
/* else there's no space at all (to_copy == 1), do nothing */
}
else if (extra_bytes > 0 || to_copy >= 2)
{
buf_in_chars[to_copy - 2 + extra_bytes] = 0;
buf_in_chars[to_copy - 1 + extra_bytes] = 0;
to_copy += extra_bytes;
}
else /* extra_bytes == 0 && to_copy == 1 */
{
buf_in_chars[0] = 0;
}
return to_copy;
}
This diff is collapsed.
......@@ -51,9 +51,11 @@ int g_win32_stat_utf8 (const gchar *filename,
int g_win32_lstat_utf8 (const gchar *filename,
GWin32PrivateStat *buf);
int g_win32_readlink_utf8 (const gchar *filename,
gchar *buf,
gsize buf_size);
int g_win32_readlink_utf8 (const gchar *filename,
gchar *buf,
gsize buf_size,
gchar **alloc_buf,
gboolean terminate);
int g_win32_fstat (int fd,
GWin32PrivateStat *buf);
......
......@@ -889,6 +889,7 @@ test_stdio_wrappers (void)
struct utimbuf ut;
GError *error = NULL;
GStatBuf path_statbuf, cwd_statbuf;
time_t now;
/* The permissions tests here don’t work when running as root. */
#ifdef G_OS_UNIX
......@@ -958,14 +959,16 @@ test_stdio_wrappers (void)
g_assert_cmpint (ret, ==, 0);
#endif
ut.actime = ut.modtime = (time_t)0;
now = time (NULL);
ut.actime = ut.modtime = now;
ret = g_utime ("test-create", &ut);
g_assert_cmpint (ret, ==, 0);
ret = g_lstat ("test-create", &buf);
g_assert_cmpint (ret, ==, 0);
g_assert_cmpint (buf.st_atime, ==, (time_t)0);
g_assert_cmpint (buf.st_mtime, ==, (time_t)0);
g_assert_cmpint (buf.st_atime, ==, now);
g_assert_cmpint (buf.st_mtime, ==, now);
g_chdir ("..");
g_remove ("mkdir-test/test-create");
......@@ -1153,6 +1156,233 @@ test_win32_pathstrip (void)
}
}
#define g_assert_memcmp(m1, cmp, m2, memlen, m1hex, m2hex, testcase_num) \
G_STMT_START { \
if (memcmp (m1, m2, memlen) cmp 0); else \
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
#m1hex " " #cmp " " #m2hex, m1hex, #cmp, m2hex); \
} G_STMT_END
static gchar *
to_hex (const guchar *buf,
gsize len)
{
gsize i;
GString *s = g_string_new (NULL);
if (len > 0)
g_string_append_printf (s, "%02x", buf[0]);
for (i = 1; i < len; i++)
g_string_append_printf (s, " %02x", buf[i]);
return g_string_free (s, FALSE);
}
static void
test_win32_zero_terminate_symlink (void)
{
gsize i;
#define TESTCASE(data, len_mod, use_buf, buf_size, terminate, reported_len, returned_string) \
{ (const guchar *) data, wcslen (data) * 2 + len_mod, use_buf, buf_size, terminate, reported_len, (guchar *) returned_string},
struct
{
const guchar *data;
gsize data_size;
gboolean use_buf;
gsize buf_size;
gboolean terminate;
int reported_len;
const guchar *returned_string;
} testcases[] = {
TESTCASE (L"foobar", +2, TRUE, 12 + 4, FALSE, 12 + 2, "f\0o\0o\0b\0a\0r\0\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 + 3, FALSE, 12 + 2, "f\0o\0o\0b\0a\0r\0\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 + 2, FALSE, 12 + 2, "f\0o\0o\0b\0a\0r\0\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 + 1, FALSE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 + 0, FALSE, 12 + 0, "f\0o\0o\0b\0a\0r\0")
TESTCASE (L"foobar", +2, TRUE, 12 - 1, FALSE, 12 - 1, "f\0o\0o\0b\0a\0r")
TESTCASE (L"foobar", +2, TRUE, 12 - 2, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", +2, TRUE, 12 - 3, FALSE, 12 - 3, "f\0o\0o\0b\0a")
TESTCASE (L"foobar", +1, TRUE, 12 + 4, FALSE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 + 3, FALSE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 + 2, FALSE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 + 1, FALSE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 + 0, FALSE, 12 + 0, "f\0o\0o\0b\0a\0r\0")
TESTCASE (L"foobar", +1, TRUE, 12 - 1, FALSE, 12 - 1, "f\0o\0o\0b\0a\0r")
TESTCASE (L"foobar", +1, TRUE, 12 - 2, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", +1, TRUE, 12 - 3, FALSE, 12 - 3, "f\0o\0o\0b\0a")
TESTCASE (L"foobar", +0, TRUE, 12 + 4, FALSE, 12 + 0, "f\0o\0o\0b\0a\0r\0")
TESTCASE (L"foobar", +0, TRUE, 12 + 3, FALSE, 12 + 0, "f\0o\0o\0b\0a\0r\0")
TESTCASE (L"foobar", +0, TRUE, 12 + 2, FALSE, 12 + 0, "f\0o\0o\0b\0a\0r\0")
TESTCASE (L"foobar", +0, TRUE, 12 + 1, FALSE, 12 + 0, "f\0o\0o\0b\0a\0r\0")
TESTCASE (L"foobar", +0, TRUE, 12 + 0, FALSE, 12 + 0, "f\0o\0o\0b\0a\0r\0")
TESTCASE (L"foobar", +0, TRUE, 12 - 1, FALSE, 12 - 1, "f\0o\0o\0b\0a\0r")
TESTCASE (L"foobar", +0, TRUE, 12 - 2, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", +0, TRUE, 12 - 3, FALSE, 12 - 3, "f\0o\0o\0b\0a")
TESTCASE (L"foobar", -1, TRUE, 12 + 3, FALSE, 12 - 1, "f\0o\0o\0b\0a\0r")
TESTCASE (L"foobar", -1, TRUE, 12 + 2, FALSE, 12 - 1, "f\0o\0o\0b\0a\0r")
TESTCASE (L"foobar", -1, TRUE, 12 + 1, FALSE, 12 - 1, "f\0o\0o\0b\0a\0r")
TESTCASE (L"foobar", -1, TRUE, 12 + 0, FALSE, 12 - 1, "f\0o\0o\0b\0a\0r")
TESTCASE (L"foobar", -1, TRUE, 12 - 1, FALSE, 12 - 1, "f\0o\0o\0b\0a\0r")
TESTCASE (L"foobar", -1, TRUE, 12 - 2, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", -1, TRUE, 12 - 3, FALSE, 12 - 3, "f\0o\0o\0b\0a")
TESTCASE (L"foobar", -1, TRUE, 12 - 4, FALSE, 12 - 4, "f\0o\0o\0b\0")
TESTCASE (L"foobar", -2, TRUE, 12 + 2, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", -2, TRUE, 12 + 1, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", -2, TRUE, 12 + 0, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", -2, TRUE, 12 - 1, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", -2, TRUE, 12 - 2, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", -2, TRUE, 12 - 3, FALSE, 12 - 3, "f\0o\0o\0b\0a")
TESTCASE (L"foobar", -2, TRUE, 12 - 4, FALSE, 12 - 4, "f\0o\0o\0b\0")
TESTCASE (L"foobar", -2, TRUE, 12 - 5, FALSE, 12 - 5, "f\0o\0o\0b")
TESTCASE (L"foobar", +2, TRUE, 12 + 4, TRUE, 12 + 2, "f\0o\0o\0b\0a\0r\0\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 + 3, TRUE, 12 + 2, "f\0o\0o\0b\0a\0r\0\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 + 2, TRUE, 12 + 2, "f\0o\0o\0b\0a\0r\0\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 + 1, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 + 0, TRUE, 12 + 0, "f\0o\0o\0b\0a\0\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 - 1, TRUE, 12 - 1, "f\0o\0o\0b\0a\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 - 2, TRUE, 12 - 2, "f\0o\0o\0b\0\0\0")
TESTCASE (L"foobar", +2, TRUE, 12 - 3, TRUE, 12 - 3, "f\0o\0o\0b\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 + 4, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 + 3, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 + 2, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 + 1, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 + 0, TRUE, 12 + 0, "f\0o\0o\0b\0a\0\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 - 1, TRUE, 12 - 1, "f\0o\0o\0b\0a\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 - 2, TRUE, 12 - 2, "f\0o\0o\0b\0\0\0")
TESTCASE (L"foobar", +1, TRUE, 12 - 3, TRUE, 12 - 3, "f\0o\0o\0b\0\0")
TESTCASE (L"foobar", +0, TRUE, 12 + 4, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +0, TRUE, 12 + 3, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +0, TRUE, 12 + 2, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +0, TRUE, 12 + 1, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +0, TRUE, 12 + 0, TRUE, 12 + 0, "f\0o\0o\0b\0a\0\0\0")
TESTCASE (L"foobar", +0, TRUE, 12 - 1, TRUE, 12 - 1, "f\0o\0o\0b\0a\0\0")
TESTCASE (L"foobar", +0, TRUE, 12 - 2, TRUE, 12 - 2, "f\0o\0o\0b\0\0\0")
TESTCASE (L"foobar", +0, TRUE, 12 - 3, TRUE, 12 - 3, "f\0o\0o\0b\0\0")
TESTCASE (L"foobar", -1, TRUE, 12 + 3, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", -1, TRUE, 12 + 2, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", -1, TRUE, 12 + 1, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", -1, TRUE, 12 + 0, TRUE, 12 + 0, "f\0o\0o\0b\0a\0\0\0")
TESTCASE (L"foobar", -1, TRUE, 12 - 1, TRUE, 12 - 1, "f\0o\0o\0b\0a\0\0")
TESTCASE (L"foobar", -1, TRUE, 12 - 2, TRUE, 12 - 2, "f\0o\0o\0b\0\0\0")
TESTCASE (L"foobar", -1, TRUE, 12 - 3, TRUE, 12 - 3, "f\0o\0o\0b\0\0")
TESTCASE (L"foobar", -1, TRUE, 12 - 4, TRUE, 12 - 4, "f\0o\0o\0\0\0")
TESTCASE (L"foobar", -2, TRUE, 12 + 2, TRUE, 12 - 1, "f\0o\0o\0b\0a\0\0")
TESTCASE (L"foobar", -2, TRUE, 12 + 1, TRUE, 12 - 1, "f\0o\0o\0b\0a\0\0")
TESTCASE (L"foobar", -2, TRUE, 12 + 0, TRUE, 12 - 1, "f\0o\0o\0b\0a\0\0")
TESTCASE (L"foobar", -2, TRUE, 12 - 1, TRUE, 12 - 1, "f\0o\0o\0b\0a\0\0")
TESTCASE (L"foobar", -2, TRUE, 12 - 2, TRUE, 12 - 2, "f\0o\0o\0b\0\0\0")
TESTCASE (L"foobar", -2, TRUE, 12 - 3, TRUE, 12 - 3, "f\0o\0o\0b\0\0")
TESTCASE (L"foobar", -2, TRUE, 12 - 4, TRUE, 12 - 4, "f\0o\0o\0\0\0")
TESTCASE (L"foobar", -2, TRUE, 12 - 5, TRUE, 12 - 5, "f\0o\0o\0\0")
TESTCASE (L"foobar", +2, FALSE, 0, FALSE, 12 + 2, "f\0o\0o\0b\0a\0r\0\0\0")
TESTCASE (L"foobar", +1, FALSE, 0, FALSE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +0, FALSE, 0, FALSE, 12 + 0, "f\0o\0o\0b\0a\0r\0")
TESTCASE (L"foobar", -1, FALSE, 0, FALSE, 12 - 1, "f\0o\0o\0b\0a\0r")
TESTCASE (L"foobar", -2, FALSE, 0, FALSE, 12 - 2, "f\0o\0o\0b\0a\0")
TESTCASE (L"foobar", +2, FALSE, 0, TRUE, 12 + 2, "f\0o\0o\0b\0a\0r\0\0\0")
TESTCASE (L"foobar", +1, FALSE, 0, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", +0, FALSE, 0, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", -1, FALSE, 0, TRUE, 12 + 1, "f\0o\0o\0b\0a\0r\0\0")
TESTCASE (L"foobar", -2, FALSE, 0, TRUE, 12 - 1, "f\0o\0o\0b\0a\0\0")
TESTCASE (L"x", +2, TRUE, 2 + 4, FALSE, 2 + 2, "x\0\0\0")
TESTCASE (L"x", +2, TRUE, 2 + 3, FALSE, 2 + 2, "x\0\0\0")
TESTCASE (L"x", +2, TRUE, 2 + 2, FALSE, 2 + 2, "x\0\0\0")
TESTCASE (L"x", +2, TRUE, 2 + 1, FALSE, 2 + 1, "x\0\0")
TESTCASE (L"x", +2, TRUE, 2 + 0, FALSE, 2 + 0, "x\0")
TESTCASE (L"x", +2, TRUE, 2 - 1, FALSE, 2 - 1, "x")
TESTCASE (L"x", +2, TRUE, 2 - 2, FALSE, 2 - 2, "")
TESTCASE (L"x", +1, TRUE, 2 + 3, FALSE, 2 + 1, "x\0\0")
TESTCASE (L"x", +1, TRUE, 2 + 2, FALSE, 2 + 1, "x\0\0")
TESTCASE (L"x", +1, TRUE, 2 + 1, FALSE, 2 + 1, "x\0\0")
TESTCASE (L"x", +1, TRUE, 2 + 0, FALSE, 2 + 0, "x\0")
TESTCASE (L"x", +1, TRUE, 2 - 1, FALSE, 2 - 1, "x")
TESTCASE (L"x", +1, TRUE, 2 - 2, FALSE, 2 - 2, "")
TESTCASE (L"x", +0, TRUE, 2 + 2, FALSE, 2 + 0, "x\0")
TESTCASE (L"x", +0, TRUE, 2 + 1, FALSE, 2 + 0, "x\0")
TESTCASE (L"x", +0, TRUE, 2 + 0, FALSE, 2 + 0, "x\0")
TESTCASE (L"x", +0, TRUE, 2 - 1, FALSE, 2 - 1, "x")
TESTCASE (L"x", +0, TRUE, 2 - 2, FALSE, 2 - 2, "")
TESTCASE (L"x", -1, TRUE, 2 + 1, FALSE, 2 - 1, "x")
TESTCASE (L"x", -1, TRUE, 2 + 0, FALSE, 2 - 1, "x")
TESTCASE (L"x", -1, TRUE, 2 - 1, FALSE, 2 - 1, "x")
TESTCASE (L"x", -1, TRUE, 2 - 2, FALSE, 2 - 2, "")
TESTCASE (L"x", -2, TRUE, 2 + 0, FALSE, 2 - 2, "")
TESTCASE (L"x", -2, TRUE, 2 - 1, FALSE, 2 - 2, "")
TESTCASE (L"x", -2, TRUE, 2 - 2, FALSE, 2 - 2, "")
TESTCASE (L"x", +2, TRUE, 2 + 4, TRUE, 2 + 2, "x\0\0\0")
TESTCASE (L"x", +2, TRUE, 2 + 3, TRUE, 2 + 2, "x\0\0\0")
TESTCASE (L"x", +2, TRUE, 2 + 2, TRUE, 2 + 2, "x\0\0\0")
TESTCASE (L"x", +2, TRUE, 2 + 1, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", +2, TRUE, 2 + 0, TRUE, 2 + 0, "\0\0")
TESTCASE (L"x", +2, TRUE, 2 - 1, TRUE, 2 - 1, "\0")
TESTCASE (L"x", +2, TRUE, 2 - 2, TRUE, 2 - 2, "")
TESTCASE (L"x", +1, TRUE, 2 + 3, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", +1, TRUE, 2 + 2, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", +1, TRUE, 2 + 1, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", +1, TRUE, 2 + 0, TRUE, 2 + 0, "\0\0")
TESTCASE (L"x", +1, TRUE, 2 - 1, TRUE, 2 - 1, "\0")
TESTCASE (L"x", +1, TRUE, 2 - 2, TRUE, 2 - 2, "")
TESTCASE (L"x", +0, TRUE, 2 + 2, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", +0, TRUE, 2 + 1, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", +0, TRUE, 2 + 0, TRUE, 2 + 0, "\0\0")
TESTCASE (L"x", +0, TRUE, 2 - 1, TRUE, 2 - 1, "\0")
TESTCASE (L"x", +0, TRUE, 2 - 2, TRUE, 2 - 2, "")
TESTCASE (L"x", -1, TRUE, 2 + 1, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", -1, TRUE, 2 + 0, TRUE, 2 + 0, "\0\0")
TESTCASE (L"x", -1, TRUE, 2 - 1, TRUE, 2 - 1, "\0")
TESTCASE (L"x", -1, TRUE, 2 - 2, TRUE, 2 - 2, "")
TESTCASE (L"x", -2, TRUE, 2 + 0, TRUE, 2 - 2, "")
TESTCASE (L"x", -2, TRUE, 2 - 1, TRUE, 2 - 2, "")
TESTCASE (L"x", -2, TRUE, 2 - 2, TRUE, 2 - 2, "")
TESTCASE (L"x", +2, FALSE, 0, FALSE, 2 + 2, "x\0\0\0")
TESTCASE (L"x", +1, FALSE, 0, FALSE, 2 + 1, "x\0\0")
TESTCASE (L"x", +0, FALSE, 0, FALSE, 2 + 0, "x\0")
TESTCASE (L"x", -1, FALSE, 0, FALSE, 2 - 1, "x")
TESTCASE (L"x", -2, FALSE, 0, FALSE, 2 - 2, "")
TESTCASE (L"x", +2, FALSE, 0, TRUE, 2 + 2, "x\0\0\0")
TESTCASE (L"x", +1, FALSE, 0, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", +0, FALSE, 0, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", -1, FALSE, 0, TRUE, 2 + 1, "x\0\0")
TESTCASE (L"x", -2, FALSE, 0, TRUE, 2 - 2, "")
{ 0, },
};
#undef TESTCASE
for (i = 0; testcases[i].data != NULL; i++)
{
gunichar2 *buf;
int result;
gchar *buf_hex, *expected_hex;
if (testcases[i].use_buf)
buf = g_malloc0 (testcases[i].buf_size + 1); /* +1 to ensure it succeeds with buf_size == 0 */
else
buf = NULL;
result = _g_win32_copy_and_maybe_terminate (testcases[i].data,
testcases[i].data_size,
testcases[i].use_buf ? buf : NULL,
testcases[i].buf_size,
testcases[i].use_buf ? NULL : &buf,
testcases[i].terminate);
if (testcases[i].reported_len != result)
g_error ("Test %" G_GSIZE_FORMAT " failed, result %d != %d", i, result, testcases[i].reported_len);
if (buf == NULL && testcases[i].buf_size != 0)
g_error ("Test %" G_GSIZE_FORMAT " failed, buf == NULL", i);
g_assert_cmpint (testcases[i].reported_len, ==, result);
if ((testcases[i].use_buf && testcases[i].buf_size != 0) ||
(!testcases[i].use_buf && testcases[i].reported_len != 0))
{
g_assert_nonnull (buf);
buf_hex = to_hex ((const guchar *) buf, result);
expected_hex = to_hex (testcases[i].returned_string, testcases[i].reported_len);
if (memcmp (buf, testcases[i].returned_string, result) != 0)
g_error ("Test %" G_GSIZE_FORMAT " failed:\n%s !=\n%s", i, buf_hex, expected_hex);
g_assert_memcmp (buf, ==, testcases[i].returned_string, testcases[i].reported_len, buf_hex, expected_hex, testcases[i].line);
g_free (buf_hex);
g_free (expected_hex);
}
g_free (buf);
}
}
#endif
int
......@@ -1166,6 +1396,7 @@ main (int argc,
#ifdef G_OS_WIN32
g_test_add_func ("/fileutils/stdio-win32-pathstrip", test_win32_pathstrip);
g_test_add_func ("/fileutils/stdio-win32-zero-terminate-symlink", test_win32_zero_terminate_symlink);
#endif
g_test_add_func ("/fileutils/build-path", test_build_path);
g_test_add_func ("/fileutils/build-pathv", test_build_pathv);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment