예제 #1
0
static int mbox_mailbox_open(struct mailbox *box)
{
	struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
	struct stat st;
	int ret;

	if (box->input != NULL) {
		i_stream_ref(box->input);
		mbox->mbox_file_stream = box->input;
		mbox->backend_readonly = TRUE;
		mbox->backend_readonly_set = TRUE;
		mbox->no_mbox_file = TRUE;
		return mbox_mailbox_open_finish(mbox, FALSE);
	}

	ret = stat(mailbox_get_path(box), &st);
	if (ret == 0) {
		if (!S_ISDIR(st.st_mode))
			return mbox_mailbox_open_existing(mbox);
		mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
				       "Mailbox isn't selectable");
		return -1;
	} else if (ENOTFOUND(errno)) {
		mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
			T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
		return -1;
	} else if (mail_storage_set_error_from_errno(box->storage)) {
		return -1;
	} else {
		mail_storage_set_critical(box->storage,
			"stat(%s) failed: %m", mailbox_get_path(box));
		return -1;
	}
}
예제 #2
0
int mailbox_list_delete_mailbox_file(struct mailbox_list *list,
				     const char *name, const char *path)
{
	/* we can simply unlink() the file */
	if (unlink(path) == 0)
		return 0;
	else if (ENOTFOUND(errno)) {
		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
				       T_MAILBOX_LIST_ERR_NOT_FOUND(list, name));
		return -1;
	} else {
		if (!mailbox_list_set_error_from_errno(list)) {
			mailbox_list_set_critical(list,
				"unlink(%s) failed: %m", path);
		}
		return -1;
	}
}
예제 #3
0
bool mail_error_from_errno(enum mail_error *error_r,
			   const char **error_string_r)
{
	if (ENOACCESS(errno)) {
		*error_r = MAIL_ERROR_PERM;
		*error_string_r = MAIL_ERRSTR_NO_PERMISSION;
	} else if (ENOQUOTA(errno)) {
		*error_r = MAIL_ERROR_NOQUOTA;
		*error_string_r = MAIL_ERRSTR_NO_QUOTA;
	} else if (ENOTFOUND(errno)) {
		*error_r = MAIL_ERROR_NOTFOUND;
		*error_string_r = errno != ELOOP ? "Not found" :
			"Directory structure is broken";
	} else {
		return FALSE;
	}
	return TRUE;
}
예제 #4
0
int index_storage_mailbox_exists_full(struct mailbox *box, const char *subdir,
				      enum mailbox_existence *existence_r)
{
	struct stat st;
	enum mail_error error;
	const char *path, *path2;
	int ret;

	/* see if it's selectable */
	ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX, &path);
	if (ret < 0) {
		mailbox_list_get_last_error(box->list, &error);
		if (error != MAIL_ERROR_NOTFOUND)
			return -1;
		*existence_r = MAILBOX_EXISTENCE_NONE;
		return 0;
	}
	if (ret == 0) {
		/* no mailboxes in this storage? */
		*existence_r = MAILBOX_EXISTENCE_NONE;
		return 0;
	}
	if (subdir != NULL)
		path = t_strconcat(path, "/", subdir, NULL);
	if (stat(path, &st) == 0) {
		*existence_r = MAILBOX_EXISTENCE_SELECT;
		return 0;
	}
	if (!ENOTFOUND(errno) && errno != EACCES) {
		mail_storage_set_critical(box->storage,
					  "stat(%s) failed: %m", path);
		return -1;
	}

	/* see if it's non-selectable */
	if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_DIR, &path2) <= 0 ||
	    (strcmp(path, path2) != 0 && stat(path2, &st) == 0)) {
		*existence_r = MAILBOX_EXISTENCE_NOSELECT;
		return 0;
	}
	*existence_r = MAILBOX_EXISTENCE_NONE;
	return 0;
}
예제 #5
0
int mailbox_list_delete_maildir_via_trash(struct mailbox_list *list,
					  const char *name,
					  const char *trash_dir)
{
	const char *src, *trash_dest;
	unsigned int count;

	src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
	if (mailbox_list_check_root_delete(list, name, src) < 0)
		return -1;

	/* rename the mailbox dir to trash dir, which atomically
	   marks it as being deleted. */
	count = 0; trash_dest = trash_dir;
	for (; rename(src, trash_dest) < 0; count++) {
		if (ENOTFOUND(errno)) {
			if (trash_dest != trash_dir && count < 5) {
				/* either the source was just deleted or
				   the trash dir was deleted. */
				trash_dest = trash_dir;
				continue;
			}
			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
			return -1;
		}
		if (errno == EXDEV) {
			/* can't do this the fast way */
			return 0;
		}
		if (!EDESTDIREXISTS(errno)) {
			if (mailbox_list_set_error_from_errno(list))
				return -1;
			mailbox_list_set_critical(list,
				"rename(%s, %s) failed: %m", src, trash_dest);
			return -1;
		}

		/* trash dir already exists. the reasons for this are:

		   a) another process is in the middle of deleting it
		   b) previous process crashed and didn't delete it
		   c) NFS: mailbox was recently deleted, but some connection
		      still has that mailbox open. the directory contains .nfs*
		      files that can't be deleted until the mailbox is closed.

		   Because of c) we'll first try to rename the mailbox under
		   the trash directory and only later try to delete the entire
		   trash directory. */
		if (trash_dir == trash_dest) {
			trash_dest = t_strconcat(trash_dir, "/",
						 unique_fname(), NULL);
		} else if (mailbox_list_delete_trash(trash_dest) < 0 &&
			   (errno != ENOTEMPTY || count >= 5)) {
			mailbox_list_set_critical(list,
				"unlink_directory(%s) failed: %m", trash_dest);
			return -1;
		}
	}

	if (mailbox_list_delete_trash(trash_dir) < 0 &&
	    errno != ENOTEMPTY && errno != EBUSY) {
		mailbox_list_set_critical(list,
			"unlink_directory(%s) failed: %m", trash_dir);

		/* it's already renamed to trash dir, which means it's
		   deleted as far as the client is concerned. Report
		   success. */
	}
	return 1;
}
예제 #6
0
int fs_list_get_mailbox_flags(struct mailbox_list *list,
			      const char *dir, const char *fname,
			      enum mailbox_list_file_type type,
			      enum mailbox_info_flags *flags_r)
{
	struct stat st;
	const char *path;

	*flags_r = 0;

	if (*list->set.maildir_name != '\0') {
		/* maildir_name is set: the code is common for all
		   storage types */
		return list_is_maildir_mailbox(list, dir, fname, type, flags_r);
	}
	if (list->v.is_internal_name != NULL &&
	    list->v.is_internal_name(list, fname)) {
		/* skip internal dirs */
		*flags_r |= MAILBOX_NOSELECT;
		return 0;
	}

	switch (type) {
	case MAILBOX_LIST_FILE_TYPE_DIR:
		if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
			*flags_r |= MAILBOX_NOSELECT;
			return 1;
		}
		break;
	case MAILBOX_LIST_FILE_TYPE_FILE:
		if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0) {
			*flags_r |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
			return 0;
		}
		break;
	default:
		break;
	}

	/* we've done all filtering we can before stat()ing */
	path = t_strconcat(dir, "/", fname, NULL);
	if (stat(path, &st) < 0) {
		if (ENOTFOUND(errno)) {
			*flags_r |= MAILBOX_NONEXISTENT;
			return 0;
		} else if (ENOACCESS(errno)) {
			*flags_r |= MAILBOX_NOSELECT;
			return 1;
		} else {
			/* non-selectable. probably either access denied, or
			   symlink destination not found. don't bother logging
			   errors. */
			mailbox_list_set_critical(list, "stat(%s) failed: %m",
						  path);
			return -1;
		}
	}

	if (!S_ISDIR(st.st_mode)) {
		if (strncmp(fname, ".nfs", 4) == 0) {
			/* temporary NFS file */
			*flags_r |= MAILBOX_NONEXISTENT;
			return 0;
		}

		if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0) {
			*flags_r |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
			return 0;
		}
		/* looks like a valid mailbox file */
		if (is_inbox_file(list, path, fname) &&
		    strcmp(fname, "INBOX") != 0) {
			/* it's possible for INBOX to have child
			   mailboxes as long as the inbox file itself
			   isn't in <mail root>/INBOX */
		} else {
			*flags_r |= MAILBOX_NOINFERIORS;
		}
	} else {
		if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
			*flags_r |= MAILBOX_NOSELECT | MAILBOX_CHILDREN;
			return 1;
		}
	}

	if ((list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0) {
		*flags_r |= STAT_GET_MARKED_FILE(st);
	} else if (list->v.is_internal_name == NULL) {
		/* link count < 2 can happen with filesystems that don't
		   support link counts. we'll just ignore them for now.. */
		if (st.st_nlink == 2)
			*flags_r |= MAILBOX_NOCHILDREN;
		else if (st.st_nlink > 2)
			*flags_r |= MAILBOX_CHILDREN;
	}
	return 1;
}