/* * mooutils-fs.c * * Copyright (C) 2004-2006 by Yevgen Muntyan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * See COPYING file that comes with this distribution. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "mooutils/mooutils-fs.h" #include #include #include #include #include #include #include #ifdef __WIN32__ #define WIN32_LEAN_AND_MEAN #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif /* XXX fix this */ gboolean moo_save_file_utf8 (const char *name, const char *text, gssize len, GError **error) { GIOChannel *file; GIOStatus status; gsize bytes_written; gsize real_len; file = g_io_channel_new_file (name, "w", error); if (!file) return FALSE; real_len = len < 0 ? strlen (text) : (gsize) len; status = g_io_channel_write_chars (file, text, len, &bytes_written, error); if (status != G_IO_STATUS_NORMAL || bytes_written != real_len) { /* glib #320668 */ g_io_channel_flush (file, NULL); g_io_channel_shutdown (file, FALSE, NULL); g_io_channel_unref (file); return FALSE; } /* glib #320668 */ g_io_channel_flush (file, NULL); g_io_channel_shutdown (file, FALSE, NULL); g_io_channel_unref (file); return TRUE; } #ifndef __WIN32__ static gboolean rm_fr (const char *path) { GError *error = NULL; char **argv; char *child_err; int status; argv = g_new0 (char*, 5); argv[0] = g_strdup ("/bin/rm"); argv[1] = g_strdup ("-fr"); argv[2] = g_strdup ("--"); argv[3] = g_strdup (path); if (!g_spawn_sync (NULL, argv, NULL, G_SPAWN_STDOUT_TO_DEV_NULL, NULL, NULL, NULL, &child_err, &status, &error)) { g_warning ("%s: could not run 'rm' command: %s", G_STRLOC, error->message); g_error_free (error); g_strfreev (argv); return FALSE; } g_strfreev (argv); if (!WIFEXITED (status) || WEXITSTATUS (status)) { g_warning ("%s: 'rm' command failed: %s", G_STRLOC, child_err ? child_err : ""); g_free (child_err); return FALSE; } else { g_free (child_err); return TRUE; } } #endif /* __WIN32__ */ #ifdef __WIN32__ static gboolean rm_r (const char *path) { GDir *dir; GError *error = NULL; const char *file; char *file_path; gboolean success = TRUE; g_return_val_if_fail (path != NULL, FALSE); dir = g_dir_open (path, 0, &error); if (!dir) { g_critical ("%s: could not open directory '%s'", G_STRLOC, path); g_critical ("%s: %s", G_STRLOC, error->message); g_error_free (error); return FALSE; } while ((file = g_dir_read_name (dir))) { char *file_path = g_build_filename (path, file, NULL); if (m_remove (file_path)) { int err = errno; switch (err) { case ENOTEMPTY: case EEXIST: if (!rm_r (file_path)) success = FALSE; break; default: success = FALSE; g_warning ("%s: could not remove '%s'", G_STRLOC, file_path); g_warning ("%s: %s", G_STRLOC, g_strerror (err)); } } g_free (file_path); } g_dir_close (dir); if (m_remove (path)) { int err = errno; success = FALSE; g_warning ("%s: could not remove '%s'", G_STRLOC, path); g_warning ("%s: %s", G_STRLOC, g_strerror (err)); } return success; } #endif /* XXX set errno or use GError */ gboolean moo_rmdir (const char *path, gboolean recursive) { g_return_val_if_fail (path != NULL, FALSE); if (!recursive) return m_rmdir (path) == 0; #ifndef __WIN32__ return rm_fr (path); #else return rm_r (path); #endif } char ** moo_filenames_from_locale (char **files) { guint i; char **conv; if (!files) return NULL; conv = g_new0 (char*, g_strv_length (files) + 1); for (i = 0; files && *files; ++files) { #ifdef __WIN32__ conv[i] = g_locale_to_utf8 (*files, -1, NULL, NULL, NULL); if (!conv[i]) g_warning ("%s: could not convert '%s' to UTF8", G_STRLOC, *files); else ++i; #else conv[i++] = g_strdup (*files); #endif } return conv; } /**********************************************************************/ /* MSLU for poor */ #ifdef __WIN32__ static gpointer convert_filename (const char *filename, gboolean *use_wide_char_api) { if (G_WIN32_HAVE_WIDECHAR_API ()) { *use_wide_char_api = TRUE; return g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL); } else { *use_wide_char_api = FALSE; return g_locale_from_utf8 (filename, -1, NULL, NULL, NULL); } } #endif #define CCALL_1(_AFunc, _WFunc, path) \ G_STMT_START { \ gboolean use_wide_char_api; \ gpointer converted; \ int retval; \ int save_errno; \ \ converted = convert_filename (path, &use_wide_char_api); \ \ if (!converted) \ { \ errno = EINVAL; \ return -1; \ } \ \ if (use_wide_char_api) \ retval = _WFunc (converted); \ else \ retval = _AFunc (converted); \ \ save_errno = errno; \ g_free (converted); \ errno = save_errno; \ \ return retval; \ } G_STMT_END int m_unlink (const char *path) { #ifdef __WIN32__ CCALL_1 (unlink, _wunlink, path); #else return unlink (path); #endif } int m_rmdir (const char *path) { #ifdef __WIN32__ CCALL_1 (rmdir, _wrmdir, path); #else return rmdir (path); #endif } int m_mkdir (const char *path) { #ifdef __WIN32__ CCALL_1 (mkdir, _wmkdir, path); #else return mkdir (path, S_IRWXU); #endif } int m_remove (const char *path) { #ifdef __WIN32__ gboolean use_wide_char_api; gpointer converted; int retval; int save_errno; converted = convert_filename (path, &use_wide_char_api); if (!converted) { errno = EINVAL; return -1; } if (use_wide_char_api) retval = _wremove (converted); else retval = remove (converted); if (retval && errno == ENOENT) { if (use_wide_char_api) retval = _wrmdir (converted); else retval = rmdir (converted); } save_errno = errno; g_free (converted); errno = save_errno; return retval; #else return remove (path); #endif } gpointer m_fopen (const char *path, const char *mode) { #ifdef __WIN32__ gboolean use_wide_char_api; gpointer path_conv, mode_conv; FILE *retval; int save_errno; if (G_WIN32_HAVE_WIDECHAR_API ()) { use_wide_char_api = TRUE; path_conv = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL); mode_conv = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL); } else { use_wide_char_api = FALSE; path_conv = g_locale_from_utf8 (path, -1, NULL, NULL, NULL); mode_conv = g_locale_from_utf8 (mode, -1, NULL, NULL, NULL); } if (!path_conv || !mode_conv) { g_free (path_conv); g_free (mode_conv); errno = EINVAL; return NULL; } if (use_wide_char_api) retval = _wfopen (path_conv, mode_conv); else retval = fopen (path_conv, mode_conv); save_errno = errno; g_free (path_conv); g_free (mode_conv); errno = save_errno; return retval; #else return fopen (path, mode); #endif } int m_rename (const char *old_name, const char *new_name) { #ifdef __WIN32__ gboolean use_wide_char_api; gpointer old_conv, new_conv; int retval, save_errno; if (G_WIN32_HAVE_WIDECHAR_API ()) { use_wide_char_api = TRUE; old_conv = g_utf8_to_utf16 (old_name, -1, NULL, NULL, NULL); new_conv = g_utf8_to_utf16 (new_name, -1, NULL, NULL, NULL); } else { use_wide_char_api = FALSE; old_conv = g_locale_from_utf8 (old_name, -1, NULL, NULL, NULL); new_conv = g_locale_from_utf8 (new_name, -1, NULL, NULL, NULL); } if (!old_conv || !new_conv) { g_free (old_conv); g_free (new_conv); errno = EINVAL; return -1; } if (use_wide_char_api) retval = _wrename (old_conv, new_conv); else retval = rename (old_conv, new_conv); save_errno = errno; g_free (old_conv); g_free (new_conv); errno = save_errno; return retval; #else return rename (old_name, new_name); #endif }