Implement trashing and filesystem::readonly for win32 (#517235) Patch from

2008-02-25  Alexander Larsson  <alexl@redhat.com>

        * glocalfile.c:
	Implement trashing and filesystem::readonly for win32 (#517235)
	Patch from Yevgen Muntyan


svn path=/trunk/; revision=6578
This commit is contained in:
Alexander Larsson 2008-02-25 08:15:35 +00:00 committed by Alexander Larsson
parent 81419b53de
commit 1d568f35d1
2 changed files with 158 additions and 19 deletions

View File

@ -1,3 +1,9 @@
2008-02-25 Alexander Larsson <alexl@redhat.com>
* glocalfile.c:
Implement trashing and filesystem::readonly for win32 (#517235)
Patch from Yevgen Muntyan
2008-02-23 Matthias Clasen <mclasen@redhat.com> 2008-02-23 Matthias Clasen <mclasen@redhat.com>
* gfileinfo.h: Documentation fixes. * gfileinfo.h: Documentation fixes.

View File

@ -84,6 +84,7 @@
#include "glibintl.h" #include "glibintl.h"
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
#define _WIN32_WINNT 0x0500
#include <windows.h> #include <windows.h>
#include <io.h> #include <io.h>
#include <direct.h> #include <direct.h>
@ -794,6 +795,111 @@ get_mount_info (GFileInfo *fs_info,
#endif #endif
#ifdef G_OS_WIN32
static gboolean
is_xp_or_later (void)
{
static int result = -1;
if (result == -1)
{
OSVERSIONINFOEX ver_info = {0};
DWORDLONG cond_mask = 0;
int op = VER_GREATER_EQUAL;
ver_info.dwOSVersionInfoSize = sizeof ver_info;
ver_info.dwMajorVersion = 5;
ver_info.dwMinorVersion = 1;
VER_SET_CONDITION (cond_mask, VER_MAJORVERSION, op);
VER_SET_CONDITION (cond_mask, VER_MINORVERSION, op);
result = VerifyVersionInfo (&ver_info,
VER_MAJORVERSION | VER_MINORVERSION,
cond_mask) != 0;
}
return result;
}
static wchar_t *
get_volume_for_path (const char *path)
{
long len;
wchar_t *wpath;
wchar_t *result;
wpath = g_utf8_to_utf16 (path, -1, NULL, &len, NULL);
result = g_new (wchar_t, len + 2);
if (!GetVolumePathNameW (wpath, result, len + 2))
{
char *msg = g_win32_error_message (GetLastError ());
g_critical ("GetVolumePathName failed: %s", msg);
g_free (msg);
g_free (result);
g_free (wpath);
return NULL;
}
len = wcslen (result);
if (len > 0 && result[len-1] != L'\\')
{
result = g_renew (wchar_t, result, len + 2);
result[len] = L'\\';
result[len + 1] = 0;
}
g_free (wpath);
return result;
}
static char *
find_mountpoint_for (const char *file, dev_t dev)
{
wchar_t *wpath;
char *utf8_path;
wpath = get_volume_for_path (file);
if (!wpath)
return NULL;
utf8_path = g_utf16_to_utf8 (wpath, -1, NULL, NULL, NULL);
g_free (wpath);
return utf8_path;
}
static void
get_filesystem_readonly (GFileInfo *info,
const char *path)
{
wchar_t *rootdir;
rootdir = get_volume_for_path (path);
if (rootdir)
{
if (is_xp_or_later ())
{
DWORD flags;
if (GetVolumeInformationW (rootdir, NULL, 0, NULL, NULL, &flags, NULL, 0))
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY,
(flags & FILE_READ_ONLY_VOLUME) != 0);
}
else
{
if (GetDriveTypeW (rootdir) == DRIVE_CDROM)
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
}
}
g_free (rootdir);
}
#endif /* G_OS_WIN32 */
static GFileInfo * static GFileInfo *
g_local_file_query_filesystem_info (GFile *file, g_local_file_query_filesystem_info (GFile *file,
const char *attributes, const char *attributes,
@ -902,7 +1008,7 @@ g_local_file_query_filesystem_info (GFile *file,
G_FILE_ATTRIBUTE_FILESYSTEM_READONLY)) G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
{ {
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
/* need to implement with *unix_mount* */ get_filesystem_readonly (info, local->filename);
#else #else
get_mount_info (info, local->filename, attribute_matcher); get_mount_info (info, local->filename, attribute_matcher);
#endif #endif
@ -1316,6 +1422,8 @@ expand_all_symlinks (const char *path)
return res; return res;
} }
#ifndef G_OS_WIN32
static char * static char *
find_mountpoint_for (const char *file, find_mountpoint_for (const char *file,
dev_t dev) dev_t dev)
@ -1343,8 +1451,6 @@ find_mountpoint_for (const char *file,
} }
} }
#ifndef G_OS_WIN32
static char * static char *
find_topdir_for (const char *file) find_topdir_for (const char *file)
{ {
@ -1358,8 +1464,6 @@ find_topdir_for (const char *file)
return find_mountpoint_for (dir, dir_dev); return find_mountpoint_for (dir, dir_dev);
} }
#endif
static char * static char *
get_unique_filename (const char *basename, get_unique_filename (const char *basename,
int id) int id)
@ -1468,10 +1572,8 @@ g_local_file_trash (GFile *file,
gboolean is_homedir_trash; gboolean is_homedir_trash;
char delete_time[32]; char delete_time[32];
int fd; int fd;
#ifndef G_OS_WIN32
struct stat trash_stat, global_stat; struct stat trash_stat, global_stat;
char *dirname, *globaldir; char *dirname, *globaldir;
#endif
if (g_lstat (local->filename, &file_stat) != 0) if (g_lstat (local->filename, &file_stat) != 0)
{ {
@ -1512,9 +1614,6 @@ g_local_file_trash (GFile *file,
} }
else else
{ {
#ifdef G_OS_WIN32
g_warning ("Recycle bin not implemented");
#else
uid_t uid; uid_t uid;
char uid_str[32]; char uid_str[32];
@ -1599,7 +1698,6 @@ g_local_file_trash (GFile *file,
} }
} }
} }
#endif
if (trashdir == NULL) if (trashdir == NULL)
{ {
@ -1704,13 +1802,6 @@ g_local_file_trash (GFile *file,
g_free (original_name); g_free (original_name);
g_free (topdir); g_free (topdir);
#ifdef G_OS_WIN32
{
GTimeVal now;
g_get_current_time (&now);
strncpy (delete_time, g_time_val_to_iso8601 (&now), sizeof (delete_time));
}
#else
{ {
time_t t; time_t t;
struct tm now; struct tm now;
@ -1719,7 +1810,6 @@ g_local_file_trash (GFile *file,
delete_time[0] = 0; delete_time[0] = 0;
strftime(delete_time, sizeof (delete_time), "%Y-%m-%dT%H:%M:%S", &now); strftime(delete_time, sizeof (delete_time), "%Y-%m-%dT%H:%M:%S", &now);
} }
#endif
data = g_strdup_printf ("[Trash Info]\nPath=%s\nDeletionDate=%s\n", data = g_strdup_printf ("[Trash Info]\nPath=%s\nDeletionDate=%s\n",
original_name_escaped, delete_time); original_name_escaped, delete_time);
@ -1733,6 +1823,49 @@ g_local_file_trash (GFile *file,
return TRUE; return TRUE;
} }
#else /* G_OS_WIN32 */
static gboolean
g_local_file_trash (GFile *file,
GCancellable *cancellable,
GError **error)
{
GLocalFile *local = G_LOCAL_FILE (file);
SHFILEOPSTRUCTW op = {0};
gboolean success;
wchar_t *wfilename;
long len;
wfilename = g_utf8_to_utf16 (local->filename, -1, NULL, &len, NULL);
/* SHFILEOPSTRUCT.pFrom is double-zero-terminated */
wfilename = g_renew (wchar_t, wfilename, len + 2);
wfilename[len + 1] = 0;
op.wFunc = FO_DELETE;
op.pFrom = wfilename;
op.fFlags = FOF_ALLOWUNDO;
success = SHFileOperationW (&op) == 0;
if (success && op.fAnyOperationsAborted)
{
if (cancellable && !g_cancellable_is_cancelled (cancellable))
g_cancellable_cancel (cancellable);
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_CANCELLED,
_("Unable to trash file: %s"),
_("cancelled"));
success = FALSE;
}
else if (!success)
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
_("Unable to trash file: %s"),
_("failed"));
g_free (wfilename);
return success;
}
#endif /* G_OS_WIN32 */
static gboolean static gboolean
g_local_file_make_directory (GFile *file, g_local_file_make_directory (GFile *file,