Commit eed8a3dc eed8a3dcd60e0bede0df3bd8e867a8eff62a7be6 by Sergey Poznyakoff

Fix size calculation for MH and Maildir mailboxes

Exclude from calculation any eventual nested mailboxes.

* libproto/maildir/mbox.c: Provide the mailbox_size method.
* libproto/mh/mbox.c: Likewise.
1 parent 9ba3833f
...@@ -666,44 +666,63 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname) ...@@ -666,44 +666,63 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname)
666 size_t index; 666 size_t index;
667 int rc = 0; 667 int rc = 0;
668 int need_sort = 0; 668 int need_sort = 0;
669 struct stat st;
669 670
670 while ((entry = readdir (dir))) 671 while ((entry = readdir (dir)))
671 { 672 {
672 switch (entry->d_name[0]) 673 char *fname;
674
675 if (entry->d_name[0] == '.')
676 continue;
677
678 rc = maildir_mkfilename (amd->name, dirname, entry->d_name, &fname);
679 if (rc)
673 { 680 {
674 case '.': 681 mu_diag_funcall (MU_DIAG_ERROR, "maildir_mkfilename",
675 break; 682 entry->d_name, rc);
683 continue;
684 }
685
686 if (stat (fname, &st))
687 {
688 rc = errno;
689 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
690 ("can't stat %s: %s", fname, mu_strerror (rc)));
691 free (fname);
692 continue;
693 }
676 694
677 default: 695 free (fname);
678 /* Message not found. Index points to the array cell where it
679 would be placed */
680 msg = calloc (1, sizeof (*msg));
681 if (!msg)
682 {
683 rc = ENOMEM;
684 break;
685 }
686 key.file_name = entry->d_name;
687 if (!amd_msg_lookup (amd, (struct _amd_message *) &key, &index))
688 continue;
689 rc = _amd_message_append (amd, (struct _amd_message *) msg);
690 if (rc)
691 {
692 free (msg);
693 break;
694 }
695
696 msg->dir = dirname;
697 msg->file_name = strdup (entry->d_name);
698 696
699 p = maildir_name_info_ptr (msg->file_name); 697 if (!S_ISREG (st.st_mode))
700 if (p) 698 continue;
701 msg->amd_message.attr_flags = info_to_flags (p); 699
702 else 700 msg = calloc (1, sizeof (*msg));
703 msg->amd_message.attr_flags = 0; 701 if (!msg)
704 msg->amd_message.orig_flags = msg->amd_message.attr_flags; 702 {
705 need_sort = 1; 703 rc = ENOMEM;
704 break;
706 } 705 }
706 key.file_name = entry->d_name;
707 if (!amd_msg_lookup (amd, (struct _amd_message *) &key, &index))
708 continue;
709 rc = _amd_message_append (amd, (struct _amd_message *) msg);
710 if (rc)
711 {
712 free (msg);
713 break;
714 }
715
716 msg->dir = dirname;
717 msg->file_name = strdup (entry->d_name);
718
719 p = maildir_name_info_ptr (msg->file_name);
720 if (p)
721 msg->amd_message.attr_flags = info_to_flags (p);
722 else
723 msg->amd_message.attr_flags = 0;
724 msg->amd_message.orig_flags = msg->amd_message.attr_flags;
725 need_sort = 1;
707 } 726 }
708 727
709 if (rc == 0 && need_sort) 728 if (rc == 0 && need_sort)
...@@ -712,9 +731,7 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname) ...@@ -712,9 +731,7 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname)
712 } 731 }
713 732
714 static int 733 static int
715 maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, 734 maildir_scan_unlocked (mu_mailbox_t mailbox, size_t *pcount, int do_notify)
716 size_t *pcount,
717 int do_notify)
718 { 735 {
719 struct _amd_data *amd = mailbox->data; 736 struct _amd_data *amd = mailbox->data;
720 DIR *dir; 737 DIR *dir;
...@@ -723,12 +740,6 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, ...@@ -723,12 +740,6 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED,
723 struct stat st; 740 struct stat st;
724 size_t i; 741 size_t i;
725 742
726 if (amd == NULL)
727 return EINVAL;
728 if (mailbox->flags & MU_STREAM_APPEND)
729 return 0;
730 mu_monitor_wrlock (mailbox->monitor);
731
732 /* 1st phase: Flush tmp/ */ 743 /* 1st phase: Flush tmp/ */
733 maildir_flush (amd); 744 maildir_flush (amd);
734 745
...@@ -748,11 +759,11 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, ...@@ -748,11 +759,11 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED,
748 } 759 }
749 free (name); 760 free (name);
750 761
762 /* 3rd phase: Scan cur/ */
751 status = maildir_mkfilename (amd->name, CURSUF, NULL, &name); 763 status = maildir_mkfilename (amd->name, CURSUF, NULL, &name);
752 if (status) 764 if (status)
753 return status; 765 return status;
754 766
755 /* 3rd phase: Scan cur/ */
756 status = maildir_opendir (&dir, name, 767 status = maildir_opendir (&dir, name,
757 PERMS | 768 PERMS |
758 mu_stream_flags_to_mode (mailbox->flags, 1)); 769 mu_stream_flags_to_mode (mailbox->flags, 1));
...@@ -778,11 +789,120 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, ...@@ -778,11 +789,120 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED,
778 if (pcount) 789 if (pcount)
779 *pcount = amd->msg_count; 790 *pcount = amd->msg_count;
780 791
781 /* Clean up the things */
782 amd_cleanup (mailbox);
783 return status; 792 return status;
784 } 793 }
785 794
795 static int
796 maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED,
797 size_t *pcount,
798 int do_notify)
799 {
800 struct _amd_data *amd = mailbox->data;
801 int rc;
802
803 if (amd == NULL)
804 return EINVAL;
805 if (mailbox->flags & MU_STREAM_APPEND)
806 return 0;
807 mu_monitor_wrlock (mailbox->monitor);
808 rc = maildir_scan_unlocked (mailbox, pcount, do_notify);
809 mu_monitor_unlock (mailbox->monitor);
810 return rc;
811 }
812
813 static int
814 maildir_size_dir (struct _amd_data *amd, char *dirsuf, mu_off_t *psize)
815 {
816 DIR *dir;
817 struct dirent *entry;
818 int rc = 0;
819 struct stat st;
820 char *name;
821
822 rc = maildir_mkfilename (amd->name, dirsuf, NULL, &name);
823 if (rc)
824 return rc;
825 dir = opendir (name);
826
827 if (!dir)
828 {
829 rc = errno;
830 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
831 ("can't open directory %s: %s", name, mu_strerror (rc)));
832 free (name);
833 if (rc == ENOENT)
834 return 0;
835 return rc;
836 }
837
838 while ((entry = readdir (dir)))
839 {
840 char *fname;
841
842 if (entry->d_name[0] == '.')
843 continue;
844
845 rc = maildir_mkfilename (amd->name, dirsuf, entry->d_name, &fname);
846 if (rc)
847 {
848 mu_diag_funcall (MU_DIAG_ERROR, "maildir_mkfilename",
849 entry->d_name, rc);
850 continue;
851 }
852
853 if (stat (fname, &st))
854 {
855 rc = errno;
856 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
857 ("can't stat %s: %s", fname, mu_strerror (rc)));
858 free (fname);
859 continue;
860 }
861
862 free (fname);
863
864 if (S_ISREG (st.st_mode))
865 *psize += st.st_size;
866 }
867
868 closedir (dir);
869 free (name);
870
871 return 0;
872 }
873
874 static int
875 maildir_size_unlocked (struct _amd_data *amd, mu_off_t *psize)
876 {
877 mu_off_t size = 0;
878 int rc;
879
880 rc = maildir_size_dir (amd, NEWSUF, &size);
881 if (rc)
882 return rc;
883 rc = maildir_size_dir (amd, CURSUF, &size);
884 if (rc)
885 return rc;
886 *psize = size;
887 return 0;
888 }
889
890 static int
891 maildir_size (mu_mailbox_t mailbox, mu_off_t *psize)
892 {
893 struct _amd_data *amd = mailbox->data;
894 int rc;
895
896 if (amd == NULL)
897 return EINVAL;
898
899 mu_monitor_wrlock (mailbox->monitor);
900 rc = maildir_size_unlocked (amd, psize);
901 mu_monitor_unlock (mailbox->monitor);
902
903 return rc;
904 }
905
786 906
787 static int 907 static int
788 maildir_qfetch (struct _amd_data *amd, mu_message_qid_t qid) 908 maildir_qfetch (struct _amd_data *amd, mu_message_qid_t qid)
...@@ -926,6 +1046,7 @@ _mailbox_maildir_init (mu_mailbox_t mailbox) ...@@ -926,6 +1046,7 @@ _mailbox_maildir_init (mu_mailbox_t mailbox)
926 amd->remove = maildir_remove; 1046 amd->remove = maildir_remove;
927 amd->chattr_msg = maildir_chattr_msg; 1047 amd->chattr_msg = maildir_chattr_msg;
928 amd->capabilities = MU_AMD_STATUS; 1048 amd->capabilities = MU_AMD_STATUS;
1049 amd->mailbox_size = maildir_size;
929 1050
930 /* Set our properties. */ 1051 /* Set our properties. */
931 { 1052 {
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
62 #include <mailutils/observer.h> 62 #include <mailutils/observer.h>
63 #include <mailutils/io.h> 63 #include <mailutils/io.h>
64 #include <mailutils/cctype.h> 64 #include <mailutils/cctype.h>
65 #include <mailutils/cstr.h>
65 #include <mailutils/mh.h> 66 #include <mailutils/mh.h>
66 #include <mailutils/sys/mailbox.h> 67 #include <mailutils/sys/mailbox.h>
67 #include <mailutils/sys/registrar.h> 68 #include <mailutils/sys/registrar.h>
...@@ -281,14 +282,78 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount, ...@@ -281,14 +282,78 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount,
281 } 282 }
282 /* Clean up the things */ 283 /* Clean up the things */
283 284
285 mu_locker_unlock (mailbox->locker);
284 amd_cleanup (mailbox); 286 amd_cleanup (mailbox);
285 #ifdef WITH_PTHREAD 287 #ifdef WITH_PTHREAD
286 pthread_cleanup_pop (0); 288 pthread_cleanup_pop (0);
287 #endif 289 #endif
288 return status; 290 return status;
289 } 291 }
292
293 static int
294 mh_size_unlocked (struct _amd_data *amd, mu_off_t *psize)
295 {
296 mu_off_t size = 0;
297 int rc;
298 struct stat st;
299 DIR *dir;
300 struct dirent *entry;
301
302 dir = opendir (amd->name);
303 if (!dir)
304 return errno;
305
306 while ((entry = readdir (dir)))
307 {
308 if (*mu_str_skip_class (entry->d_name, MU_CTYPE_DIGIT) == 0)
309 {
310 char *fname = mu_make_file_name (amd->name, entry->d_name);
311 if (!fname)
312 continue;
313 if (stat (fname, &st))
314 {
315 rc = errno;
316 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
317 ("can't stat %s: %s", fname, mu_strerror (rc)));
318 free (fname);
319 continue;
320 }
321 if (S_ISREG (st.st_mode))
322 size += st.st_size;
323 }
324 }
325
326 *psize = size;
327
328 closedir (dir);
329
330 return 0;
331 }
290 332
291 static int 333 static int
334 mh_size (mu_mailbox_t mailbox, mu_off_t *psize)
335 {
336 struct _amd_data *amd = mailbox->data;
337 int rc;
338
339 mu_monitor_wrlock (mailbox->monitor);
340 #ifdef WITH_PTHREAD
341 pthread_cleanup_push (amd_cleanup, (void *)mailbox);
342 #endif
343 mu_locker_lock (mailbox->locker);
344
345 rc = mh_size_unlocked (amd, psize);
346
347 mu_locker_unlock (mailbox->locker);
348 mu_monitor_unlock (mailbox->monitor);
349 #ifdef WITH_PTHREAD
350 pthread_cleanup_pop (0);
351 #endif
352 return rc;
353 }
354
355
356 static int
292 mh_qfetch (struct _amd_data *amd, mu_message_qid_t qid) 357 mh_qfetch (struct _amd_data *amd, mu_message_qid_t qid)
293 { 358 {
294 char *p; 359 char *p;
...@@ -467,7 +532,8 @@ _mailbox_mh_init (mu_mailbox_t mailbox) ...@@ -467,7 +532,8 @@ _mailbox_mh_init (mu_mailbox_t mailbox)
467 amd->message_uid = mh_message_uid; 532 amd->message_uid = mh_message_uid;
468 amd->next_uid = _mh_next_seq; 533 amd->next_uid = _mh_next_seq;
469 amd->remove = mh_remove; 534 amd->remove = mh_remove;
470 535 amd->mailbox_size = mh_size;
536
471 mailbox->_get_property = mh_get_property; 537 mailbox->_get_property = mh_get_property;
472 mailbox->_translate = mh_translate; 538 mailbox->_translate = mh_translate;
473 539
......