mirror of https://github.com/djcb/mu.git
lib/maildir: use mv for moving to avoid warnings
using gio gives some (false, we assume) valgrind warnings, so for now use 'mv' instead. Also slightly update the code with some mu_format overtaking format.
This commit is contained in:
parent
18490a818d
commit
f3bfdf5add
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** Copyright (C) 2008-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
** Copyright (C) 2008-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
**
|
**
|
||||||
** This program is free software; you can redistribute it and/or modify it
|
** 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
|
** under the terms of the GNU General Public License as published by the
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ get_target_fullpath(const std::string& src, const std::string& targetpath,
|
||||||
|
|
||||||
const auto srcfile{to_string_gchar(g_path_get_basename(src.c_str()))};
|
const auto srcfile{to_string_gchar(g_path_get_basename(src.c_str()))};
|
||||||
|
|
||||||
/* create targetpath; note: make the filename *cough* unique by
|
/* create target-path; note: make the filename *cough* unique by
|
||||||
* including a hash of the srcname in the targetname. This helps if
|
* including a hash of the srcname in the targetname. This helps if
|
||||||
* there are copies of a message (which all have the same basename)
|
* there are copies of a message (which all have the same basename)
|
||||||
*/
|
*/
|
||||||
|
@ -164,9 +165,9 @@ get_target_fullpath(const std::string& src, const std::string& targetpath,
|
||||||
if (unique_names)
|
if (unique_names)
|
||||||
fulltargetpath = join_paths(targetpath,
|
fulltargetpath = join_paths(targetpath,
|
||||||
in_cur ? "cur" : "new",
|
in_cur ? "cur" : "new",
|
||||||
format("%08x-%s",
|
mu_format("{:08x}-{}",
|
||||||
g_str_hash(src.c_str()),
|
g_str_hash(src.c_str()),
|
||||||
srcfile.c_str()));
|
srcfile));
|
||||||
else
|
else
|
||||||
fulltargetpath = join_paths(targetpath,
|
fulltargetpath = join_paths(targetpath,
|
||||||
in_cur ? "cur" : "new",
|
in_cur ? "cur" : "new",
|
||||||
|
@ -272,7 +273,7 @@ msg_move_verify(const std::string& src, const std::string& dst)
|
||||||
|
|
||||||
/* use GIO to move files; this is slower than rename() so only use
|
/* use GIO to move files; this is slower than rename() so only use
|
||||||
* this when needed: when moving across filesystems */
|
* this when needed: when moving across filesystems */
|
||||||
static Mu::Result<void>
|
G_GNUC_UNUSED static Mu::Result<void>
|
||||||
msg_move_g_file(const std::string& src, const std::string& dst)
|
msg_move_g_file(const std::string& src, const std::string& dst)
|
||||||
{
|
{
|
||||||
GFile *srcfile{g_file_new_for_path(src.c_str())};
|
GFile *srcfile{g_file_new_for_path(src.c_str())};
|
||||||
|
@ -288,17 +289,38 @@ msg_move_g_file(const std::string& src, const std::string& dst)
|
||||||
if (res)
|
if (res)
|
||||||
return Ok();
|
return Ok();
|
||||||
else
|
else
|
||||||
return Err(Error{Error::Code::File, &err/*consumed*/,
|
return Err(Error::Code::File, &err, "error moving {} -> {}", src, dst);
|
||||||
"error moving {} -> {}", src, dst});
|
}
|
||||||
|
|
||||||
|
/* use mv to move files; this is slower than rename() so only use this when
|
||||||
|
* needed: when moving across filesystems */
|
||||||
|
G_GNUC_UNUSED static Mu::Result<void>
|
||||||
|
msg_move_mv_file(const std::string& src, const std::string& dst)
|
||||||
|
{
|
||||||
|
const auto cmdline{mu_format("/bin/mv {} {}",
|
||||||
|
to_string_gchar(g_shell_quote(src.c_str())),
|
||||||
|
to_string_gchar(g_shell_quote(dst.c_str())))};
|
||||||
|
GError *err{};
|
||||||
|
int wait_status{};
|
||||||
|
|
||||||
|
mu_debug("{}", cmdline);
|
||||||
|
|
||||||
|
if (!g_spawn_command_line_sync(cmdline.c_str(), {}, {}, &wait_status, &err))
|
||||||
|
return Err(Error::Code::File, &err, "error moving {} -> {}", src, dst);
|
||||||
|
else if (auto&& res{WEXITSTATUS(wait_status)}; res != 0)
|
||||||
|
return Err(Error::Code::File, "error moving {} -> {}; err={}",
|
||||||
|
src, dst, res);
|
||||||
|
else
|
||||||
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Mu::Result<void>
|
static Mu::Result<void>
|
||||||
msg_move(const std::string& src, const std::string& dst, bool force_gio)
|
msg_move(const std::string& src, const std::string& dst, bool assume_remote)
|
||||||
{
|
{
|
||||||
if (::access(src.c_str(), R_OK) != 0)
|
if (::access(src.c_str(), R_OK) != 0)
|
||||||
return Err(Error{Error::Code::File, "cannot read {}", src});
|
return Err(Error{Error::Code::File, "cannot read {}", src});
|
||||||
|
|
||||||
if (!force_gio) { /* for testing */
|
if (!assume_remote) { /* for testing */
|
||||||
|
|
||||||
if (::rename(src.c_str(), dst.c_str()) == 0) /* seems it worked; double-check */
|
if (::rename(src.c_str(), dst.c_str()) == 0) /* seems it worked; double-check */
|
||||||
return msg_move_verify(src, dst);
|
return msg_move_verify(src, dst);
|
||||||
|
@ -308,16 +330,19 @@ msg_move(const std::string& src, const std::string& dst, bool force_gio)
|
||||||
src, dst, strerror(errno)});
|
src, dst, strerror(errno)});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the EXDEV / force-gio case -- source and target live on different
|
/* the EXDEV / assume-remote case -- source and target live on different
|
||||||
* filesystems */
|
* file systems
|
||||||
auto res = msg_move_g_file(src, dst);
|
*
|
||||||
if (!res)
|
* we can choose either msg_move_gio_file or msg_move_mv_file;
|
||||||
|
* we use the latter for now, since the former gives some (false)
|
||||||
|
* valgrind alarms.
|
||||||
|
* */
|
||||||
|
if (auto&& res{msg_move_mv_file(src, dst)}; !res)
|
||||||
return res;
|
return res;
|
||||||
else
|
else
|
||||||
return msg_move_verify(src, dst);
|
return msg_move_verify(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mu::Result<void>
|
Mu::Result<void>
|
||||||
Mu::maildir_move_message(const std::string& oldpath,
|
Mu::maildir_move_message(const std::string& oldpath,
|
||||||
const std::string& newpath,
|
const std::string& newpath,
|
||||||
|
@ -326,18 +351,18 @@ Mu::maildir_move_message(const std::string& oldpath,
|
||||||
if (oldpath == newpath)
|
if (oldpath == newpath)
|
||||||
return Ok(); // nothing to do.
|
return Ok(); // nothing to do.
|
||||||
|
|
||||||
mu_debug("moving {} --> {}", oldpath, newpath);
|
mu_debug("moving {} --> {} (force-gio:{})", oldpath, newpath, force_gio ? "yes": "no");
|
||||||
return msg_move(oldpath, newpath, force_gio);
|
return msg_move(oldpath, newpath, force_gio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string
|
static std::string
|
||||||
reinvent_filename_base()
|
reinvent_filename_base()
|
||||||
{
|
{
|
||||||
return format("%u.%08x%08x.%s",
|
return mu_format("{}.{:08x}{:08x}.{}",
|
||||||
static_cast<unsigned>(::time(NULL)),
|
::time({}),
|
||||||
g_random_int(),
|
g_random_int(),
|
||||||
static_cast<uint32_t>(g_get_monotonic_time()),
|
g_get_monotonic_time(),
|
||||||
g_get_host_name());
|
g_get_host_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -80,15 +80,15 @@ Result<void> maildir_clear_links(const std::string& dir);
|
||||||
*
|
*
|
||||||
* @param oldpath an absolute file system path to an existing message in an
|
* @param oldpath an absolute file system path to an existing message in an
|
||||||
* actual maildir
|
* actual maildir
|
||||||
* @param newpath the absolete full path to the target file
|
* @param newpath the absolute full path to the target file
|
||||||
* @param force_gio force the use of GIO for moving; this is done automatically
|
* @param assume_remote assume the target is on a different file-system,
|
||||||
* when needed; forcing is mostly useful for tests
|
* and hence rename() won't work and we need another method (this is for testing)
|
||||||
*
|
*
|
||||||
* @return a valid result (!!result) or an Error
|
* @return a valid result or an Error
|
||||||
*/
|
*/
|
||||||
Result<void> maildir_move_message(const std::string& oldpath,
|
Result<void> maildir_move_message(const std::string& oldpath,
|
||||||
const std::string& newpath,
|
const std::string& newpath,
|
||||||
bool force_gio = false);
|
bool assume_remote = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the target path for a to-be-moved message; i.e. this does not
|
* Determine the target path for a to-be-moved message; i.e. this does not
|
||||||
|
|
Loading…
Reference in New Issue