diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index edec7bdde..6f186957a 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -261,10 +261,12 @@ get_selinux_context (const char *path, #define g_fgetxattr(fd,name,value,size) fgetxattr(fd,name,value,size,0,0) #define g_flistxattr(fd,name,size) flistxattr(fd,name,size,0) #define g_setxattr(path,name,value,size) setxattr(path,name,value,size,0,0) +#define g_removexattr(path,name) removexattr(path,name,0) #else #define g_fgetxattr fgetxattr #define g_flistxattr flistxattr #define g_setxattr(path,name,value,size) setxattr(path,name,value,size,0) +#define g_removexattr(path,name) removexattr(path,name) #endif static gssize @@ -774,10 +776,10 @@ set_xattr (char *filename, return FALSE; } - if (attr_value->type != G_FILE_ATTRIBUTE_TYPE_STRING) + if (attr_value->type != G_FILE_ATTRIBUTE_TYPE_STRING && attr_value->type != G_FILE_ATTRIBUTE_TYPE_INVALID) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Invalid attribute type (string expected)")); + _("Invalid attribute type (string or invalid expected)")); return FALSE; } @@ -799,16 +801,27 @@ set_xattr (char *filename, escaped_attribute += strlen ("xattr-sys::"); is_user = FALSE; } - + attribute = hex_unescape_string (escaped_attribute, NULL, &free_attribute); - value = hex_unescape_string (attr_value->u.string, &val_len, &free_value); if (is_user) a = g_strconcat ("user.", attribute, NULL); else a = attribute; - - res = g_setxattr (filename, a, value, val_len); + + if (attr_value->type == G_FILE_ATTRIBUTE_TYPE_STRING) + { + value = hex_unescape_string (attr_value->u.string, &val_len, &free_value); + res = g_setxattr (filename, a, value, val_len); + } + else + { + value = NULL; + val_len = 0; + free_value = FALSE; + res = g_removexattr (filename, a); + } + errsv = errno; if (is_user) diff --git a/gio/tests/g-file-info.c b/gio/tests/g-file-info.c index 2786e75b7..427ebffcc 100644 --- a/gio/tests/g-file-info.c +++ b/gio/tests/g-file-info.c @@ -1015,7 +1015,7 @@ test_xattrs (void) { GFile *file = NULL; GFileIOStream *stream = NULL; - GFileInfo *file_info0 = NULL, *file_info1 = NULL; + GFileInfo *file_info0 = NULL, *file_info1 = NULL, *file_info2 = NULL; GError *local_error = NULL; g_test_summary ("Test setting and getting escaped xattrs"); @@ -1037,6 +1037,7 @@ test_xattrs (void) g_file_info_set_attribute_string (file_info0, "xattr::escaped", "hello\\x82\\x80\\xbd"); g_file_info_set_attribute_string (file_info0, "xattr::string", "hi there"); g_file_info_set_attribute_string (file_info0, "xattr::embedded-nul", "hi\\x00there"); + g_file_info_set_attribute_string (file_info0, "xattr::deleteme", "this attribute will be deleted"); g_file_set_attributes_from_info (file, file_info0, G_FILE_QUERY_INFO_NONE, NULL, &local_error); @@ -1061,8 +1062,19 @@ test_xattrs (void) g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::escaped"), ==, "hello\\x82\\x80\\xbd"); g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::string"), ==, "hi there"); g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::embedded-nul"), ==, "hi\\x00there"); + g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::deleteme"), ==, "this attribute will be deleted"); g_object_unref (file_info1); + + /* Check whether removing extended attributes works. */ + g_file_set_attribute (file, "xattr::deleteme", G_FILE_ATTRIBUTE_TYPE_INVALID, NULL, G_FILE_QUERY_INFO_NONE, NULL, &local_error); + g_assert_no_error (local_error); + file_info2 = g_file_query_info (file, "xattr::deleteme", G_FILE_QUERY_INFO_NONE, NULL, &local_error); + g_assert_no_error (local_error); + g_assert_nonnull (file_info2); + g_assert_cmpstr (g_file_info_get_attribute_string (file_info2, "xattr::deleteme"), ==, NULL); + + g_object_unref (file_info2); } /* Tidy up. */