Commit 5b3ac30a 5b3ac30a697287b6b72e3d7f717e19a159cae821 by Sergey Poznyakoff

Bugfixes in AMD code.

* libproto/include/amd.h (new_msg_file_name): Add an argument indicating
whether an actual expunsion is going to take place, as opposed to saving
message flags.
* libproto/maildir/mbox.c (maildir_new_message_name): Sync with above changes.
* libproto/mh/mbox.c (_mh_new_message_name): Likewise.
* mailbox/amd.c (_amd_message_save): Handle unlink requests
(new_msg_file_name returning NULL name). This avoids creating temp files.
(amd_expunge): Remove messages that have had MU_ATTRIBUTE_DELETED on mailbox
open, if the underlying mailbox implementation allows that.
1 parent 47b3b9bc
......@@ -72,7 +72,7 @@ struct _amd_data
const mu_message_t);
void (*msg_free) (struct _amd_message *);
int (*cur_msg_file_name) (struct _amd_message *, char **);
int (*new_msg_file_name) (struct _amd_message *, int attr_flags, char **);
int (*new_msg_file_name) (struct _amd_message *, int, int, char **);
int (*scan0) (mu_mailbox_t mailbox, size_t msgno, size_t *pcount,
int do_notify);
int (*mailbox_size) (mu_mailbox_t mailbox, mu_off_t *psize);
......
......@@ -342,14 +342,13 @@ maildir_cur_message_name (struct _amd_message *amsg, char **pname)
}
static int
maildir_new_message_name (struct _amd_message *amsg, int flags, char **pname)
maildir_new_message_name (struct _amd_message *amsg, int flags, int expunge,
char **pname)
{
struct _maildir_message *msg = (struct _maildir_message *) amsg;
if (flags & MU_ATTRIBUTE_DELETED)
if (expunge && (flags & MU_ATTRIBUTE_DELETED))
{
/* Force amd.c to unlink the file.
FIXME: We could also add a 'T' info to it. Should
we have an option deciding which approach to take? */
/* Force amd.c to unlink the file. */
*pname = NULL;
}
else if (strcmp (msg->dir, CURSUF) == 0)
......
......@@ -126,7 +126,9 @@ _mh_cur_message_name (struct _amd_message *amsg, char **pname)
/* Return newfilename for the message.
NOTE: Allocates memory. */
static int
_mh_new_message_name (struct _amd_message *amsg, int flags, char **pname)
_mh_new_message_name (struct _amd_message *amsg, int flags,
int expunge MU_ARG_UNUSED,
char **pname)
{
int status = 0;
struct _mh_message *mhm = (struct _mh_message *) amsg;
......
......@@ -600,7 +600,7 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
int expunge)
{
mu_stream_t stream = NULL;
char *name = NULL, *buf = NULL, *msg_name;
char *name = NULL, *buf = NULL, *msg_name, *old_name;
size_t n, off = 0;
size_t bsize;
size_t nlines, nbytes;
......@@ -618,9 +618,27 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
if (status)
return status;
status = amd->new_msg_file_name (mhm, mhm->attr_flags, expunge, &msg_name);
if (status)
return status;
if (!msg_name)
{
/* Unlink the original file */
char *old_name;
status = amd->cur_msg_file_name (mhm, &old_name);
free (msg_name);
if (status == 0 && unlink (old_name))
status = errno;
free (old_name);
return status;
}
fp = _amd_tempfile (mhm->amd, &name);
if (!fp)
return errno;
{
free (msg_name);
return errno;
}
/* Try to allocate large buffer */
for (; bsize > 1; bsize /= 2)
......@@ -628,7 +646,12 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
break;
if (!bsize)
return ENOMEM;
{
unlink (name);
free (name);
free (msg_name);
return ENOMEM;
}
/* Copy flags */
mu_message_get_header (msg, &hdr);
......@@ -724,42 +747,37 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
free (buf);
fclose (fp);
status = amd->new_msg_file_name (mhm, mhm->attr_flags, &msg_name);
status = amd->cur_msg_file_name (mhm, &old_name);
if (status == 0)
{
char *old_name;
status = amd->cur_msg_file_name (mhm, &old_name);
if (status == 0)
if (rename (name, msg_name))
status = errno;
else
{
if (rename (name, msg_name))
status = errno;
else
{
mode_t perms;
mode_t perms;
perms = mu_stream_flags_to_mode (amd->mailbox->flags, 0);
if (perms != 0)
{
/* It is documented that the mailbox permissions are
affected by the current umask, so take it into account
here.
FIXME: I'm still not sure we should honor umask, though.
--gray
*/
mode_t mask = umask (0);
chmod (msg_name, (0600 | perms) & ~mask);
umask (mask);
}
if (strcmp (old_name, msg_name))
/* Unlink original message */
unlink (old_name);
perms = mu_stream_flags_to_mode (amd->mailbox->flags, 0);
if (perms != 0)
{
/* It is documented that the mailbox permissions are
affected by the current umask, so take it into account
here.
FIXME: I'm still not sure we should honor umask, though.
--gray
*/
mode_t mask = umask (0);
chmod (msg_name, (0600 | perms) & ~mask);
umask (mask);
}
free (old_name);
mhm->orig_flags = mhm->attr_flags;
if (strcmp (old_name, msg_name))
/* Unlink original message */
unlink (old_name);
}
free (msg_name);
free (old_name);
mhm->orig_flags = mhm->attr_flags;
}
free (msg_name);
free (name);
return status;
......@@ -1065,33 +1083,38 @@ amd_expunge (mu_mailbox_t mailbox)
if (mhm->attr_flags & MU_ATTRIBUTE_DELETED)
{
if (!(mhm->orig_flags & MU_ATTRIBUTE_DELETED))
int rc;
char *old_name;
char *new_name;
rc = amd->cur_msg_file_name (mhm, &old_name);
if (rc)
return rc;
rc = amd->new_msg_file_name (mhm, mhm->attr_flags, 1,
&new_name);
if (rc)
{
int rc;
char *old_name;
char *new_name;
rc = amd->cur_msg_file_name (mhm, &old_name);
if (rc)
return rc;
rc = amd->new_msg_file_name (mhm, mhm->attr_flags, &new_name);
if (rc)
{
free (old_name);
return rc;
}
if (new_name)
{
/* Rename original message */
rename (old_name, new_name);
free (new_name);
}
else
/* Unlink original file */
unlink (old_name);
free (old_name);
return rc;
}
if (new_name)
{
/* FIXME: It may be a good idea to have a capability flag
in struct _amd_data indicating that no actual removal
is needed (e.g. for traditional MH). It will allow to
bypass lots of no-op code here. */
if (strcmp (old_name, new_name))
/* Rename original message */
rename (old_name, new_name);
}
else
/* Unlink original file */
unlink (old_name);
free (old_name);
free (new_name);
_amd_message_delete (amd, mhm);
updated = 1;
/* Do not increase i! */
......