Example #1
0
static uint32_t
mailbox_uidvalidity_next_rescan(struct mailbox_list *list, const char *path)
{
	DIR *d;
	struct dirent *dp;
	const char *fname, *dir, *prefix, *tmp;
	unsigned int i, prefix_len;
	uint32_t cur_value, min_value, max_value;
	mode_t old_mask;
	int fd;

	fname = strrchr(path, '/');
	if (fname == NULL) {
		dir = ".";
		fname = path;
	} else {
		dir = t_strdup_until(path, fname);
		fname++;
	}

	d = opendir(dir);
	if (d == NULL && errno == ENOENT) {
		/* FIXME: the PATH_TYPE_CONTROL should come as a parameter, but
		   that's an API change, do it in v2.3. it's not really a
		   problem though, since currently all backends use control
		   dirs for the uidvalidity file. */
		(void)mailbox_list_mkdir_root(list, dir, MAILBOX_LIST_PATH_TYPE_CONTROL);
		d = opendir(dir);
	}
	if (d == NULL) {
		i_error("opendir(%s) failed: %m", dir);
		return mailbox_uidvalidity_next_fallback();
	}
	prefix = t_strconcat(fname, ".", NULL);
	prefix_len = strlen(prefix);

	/* just in case there happens to be multiple matching uidvalidity
	   files, track the min/max values. use the max value and delete the
	   min value file. */
	max_value = 0; min_value = (uint32_t)-1;
	while ((dp = readdir(d)) != NULL) {
		if (strncmp(dp->d_name, prefix, prefix_len) == 0) {
			if (str_to_uint32_hex(dp->d_name + prefix_len, &cur_value) >= 0) {
				if (min_value > cur_value)
					min_value = cur_value;
				if (max_value < cur_value)
					max_value = cur_value;
			}
		}
	}
	if (closedir(d) < 0)
		i_error("closedir(%s) failed: %m", dir);

	if (max_value == 0) {
		/* no uidvalidity files. create one. */
		for (i = 0; i < RETRY_COUNT; i++) {
			cur_value = mailbox_uidvalidity_next_fallback();
			tmp = t_strdup_printf("%s.%08x", path, cur_value);
			/* the file is empty, don't bother with permissions */
			old_mask = umask(0);
			fd = open(tmp, O_RDWR | O_CREAT | O_EXCL, 0444);
			umask(old_mask);
			if (fd != -1 || errno != EEXIST)
				break;
			/* already exists. although it's quite unlikely we'll
			   hit this race condition. more likely we'll create
			   a duplicate file.. */
		}
		if (fd == -1) {
			i_error("creat(%s) failed: %m", tmp);
			return cur_value;
		}
		i_close_fd(&fd);
		mailbox_uidvalidity_write(list, path, cur_value);
		return cur_value;
	}
	if (min_value != max_value) {
		/* duplicate uidvalidity files, delete the oldest */
		tmp = t_strdup_printf("%s.%08x", path, min_value);
		i_unlink_if_exists(tmp);
	}

	cur_value = max_value;
	if (mailbox_uidvalidity_rename(path, &cur_value, TRUE) < 0)
		return mailbox_uidvalidity_next_fallback();
	mailbox_uidvalidity_write(list, path, cur_value);
	return cur_value;
}
Example #2
0
static uint32_t
mailbox_uidvalidity_next_rescan(struct mailbox_list *list, const char *path)
{
	DIR *d;
	struct dirent *dp;
	const char *fname, *dir, *prefix, *tmp;
	char *endp;
	unsigned int i, prefix_len;
	uint32_t cur_value, min_value, max_value;
	mode_t old_mask;
	int fd;

	fname = strrchr(path, '/');
	if (fname == NULL) {
		dir = ".";
		fname = path;
	} else {
		dir = t_strdup_until(path, fname);
		fname++;
	}

	d = opendir(dir);
	if (d == NULL) {
		i_error("opendir(%s) failed: %m", dir);
		return mailbox_uidvalidity_next_fallback();
	}
	prefix = t_strconcat(fname, ".", NULL);
	prefix_len = strlen(prefix);

	/* just in case there happens to be multiple matching uidvalidity
	   files, track the min/max values. use the max value and delete the
	   min value file. */
	max_value = 0; min_value = (uint32_t)-1;
	while ((dp = readdir(d)) != NULL) {
		if (strncmp(dp->d_name, prefix, prefix_len) == 0) {
			cur_value = strtoul(dp->d_name + prefix_len, &endp, 16);
			if (*endp == '\0') {
				if (min_value > cur_value)
					min_value = cur_value;
				if (max_value < cur_value)
					max_value = cur_value;
			}
		}
	}
	if (closedir(d) < 0)
		i_error("closedir(%s) failed: %m", dir);

	if (max_value == 0) {
		/* no uidvalidity files. create one. */
		for (i = 0; i < RETRY_COUNT; i++) {
			cur_value = mailbox_uidvalidity_next_fallback();
			tmp = t_strdup_printf("%s.%08x", path, cur_value);
			/* the file is empty, don't bother with permissions */
			old_mask = umask(0);
			fd = open(tmp, O_RDWR | O_CREAT | O_EXCL, 0444);
			umask(old_mask);
			if (fd != -1 || errno != EEXIST)
				break;
			/* already exists. although it's quite unlikely we'll
			   hit this race condition. more likely we'll create
			   a duplicate file.. */
		}
		if (fd == -1) {
			i_error("creat(%s) failed: %m", tmp);
			return cur_value;
		}
		i_close_fd(&fd);
		mailbox_uidvalidity_write(list, path, cur_value);
		return cur_value;
	}
	if (min_value != max_value) {
		/* duplicate uidvalidity files, delete the oldest */
		tmp = t_strdup_printf("%s.%08x", path, min_value);
		if (unlink(tmp) < 0 && errno != ENOENT)
			i_error("unlink(%s) failed: %m", tmp);
	}

	cur_value = max_value;
	if (mailbox_uidvalidity_rename(path, &cur_value, TRUE) < 0)
		return mailbox_uidvalidity_next_fallback();
	mailbox_uidvalidity_write(list, path, cur_value);
	return cur_value;
}