Mercurial > dovecot > core-2.2
view src/lib-storage/list/mailbox-list-fs-flags.c @ 17130:add8c00fb3cc
Updated copyright notices to include year 2014.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 04 Feb 2014 16:23:22 -0500 |
parents | 36ef72481934 |
children | 3009a1a6f6d5 |
line wrap: on
line source
/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "mailbox-list-fs.h" #include <sys/stat.h> /* Assume that if atime < mtime, there are new mails. If it's good enough for UW-IMAP, it's good enough for us. */ #define STAT_GET_MARKED_FILE(st) \ ((st).st_size == 0 ? MAILBOX_UNMARKED : \ (st).st_atime < (st).st_mtime ? MAILBOX_MARKED : MAILBOX_UNMARKED) static int list_is_maildir_mailbox(struct mailbox_list *list, const char *dir, const char *fname, enum mailbox_list_file_type type, enum mailbox_info_flags *flags_r) { const char *path, *maildir_path; struct stat st, st2; bool mailbox_files; switch (type) { case MAILBOX_LIST_FILE_TYPE_FILE: case MAILBOX_LIST_FILE_TYPE_OTHER: /* non-directories aren't valid */ *flags_r |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS; return 0; case MAILBOX_LIST_FILE_TYPE_DIR: case MAILBOX_LIST_FILE_TYPE_UNKNOWN: case MAILBOX_LIST_FILE_TYPE_SYMLINK: break; } path = t_strdup_printf("%s/%s", dir, fname); if (stat(path, &st) < 0) { if (errno == ENOENT) { *flags_r |= MAILBOX_NONEXISTENT; return 0; } else { /* non-selectable. probably either access denied, or symlink destination not found. don't bother logging errors. */ *flags_r |= MAILBOX_NOSELECT; return 1; } } if (!S_ISDIR(st.st_mode)) { if (strncmp(fname, ".nfs", 4) == 0) { /* temporary NFS file */ *flags_r |= MAILBOX_NONEXISTENT; } else { *flags_r |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS; } return 0; } /* ok, we've got a directory. see what we can do about it. */ /* 1st link is "." 2nd link is ".." 3rd link is either child mailbox or mailbox dir rest of the links are child mailboxes if mailboxes are files, then 3+ links are all child mailboxes. */ mailbox_files = (list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0; if (st.st_nlink == 2 && !mailbox_files) { *flags_r |= MAILBOX_NOSELECT; return 1; } /* we have at least one directory. see if this mailbox is selectable */ maildir_path = t_strconcat(path, "/", list->set.maildir_name, NULL); if (stat(maildir_path, &st2) < 0) *flags_r |= MAILBOX_NOSELECT | MAILBOX_CHILDREN; else if (!S_ISDIR(st2.st_mode)) { if (mailbox_files) { *flags_r |= st.st_nlink == 2 ? MAILBOX_NOCHILDREN : MAILBOX_CHILDREN; } else { *flags_r |= MAILBOX_NOSELECT | MAILBOX_CHILDREN; } } else { /* now we know what link count 3 means. */ if (st.st_nlink == 3) *flags_r |= MAILBOX_NOCHILDREN; else *flags_r |= MAILBOX_CHILDREN; } *flags_r |= MAILBOX_SELECT; return 1; } static bool is_inbox_file(struct mailbox_list *list, const char *path, const char *fname) { const char *inbox_path; if (strcasecmp(fname, "INBOX") != 0) return FALSE; if (mailbox_list_get_path(list, "INBOX", MAILBOX_LIST_PATH_TYPE_MAILBOX, &inbox_path) <= 0) i_unreached(); return strcmp(inbox_path, path) == 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; }