From 09db59a37d048a90da58df219b2d8a249812f472 Mon Sep 17 00:00:00 2001 From: Paul Jarc Date: Sun, 25 Jan 2004 05:26:46 +0000 Subject: [PATCH] * nnmaildir.el (nnmaildir--num-file, nnmaildir--mkfile, nnmaildir--emlink-p, nnmaildir--eexist-p, nnmaildir--new-number): New macros and functions. * nnmaildir.el (nnmaildir--group-maxnum, nnmaildir--update-nov): Handle > NLINK_MAX messages. * nnmaildir.el (nnmaildir-request-set-mark): Use nnmaildir--emlink-p and nnmaildir--eexist-p. --- lisp/ChangeLog | 10 ++++ lisp/nnmaildir.el | 117 +++++++++++++++++++++++++++++++--------------- 2 files changed, 89 insertions(+), 38 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 8d9ef317a..82fc3104e 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,13 @@ +2004-01-25 Paul Jarc + + * nnmaildir.el (nnmaildir--num-file, nnmaildir--mkfile, + nnmaildir--emlink-p, nnmaildir--eexist-p, nnmaildir--new-number): + New macros and functions. + * nnmaildir.el (nnmaildir--group-maxnum, nnmaildir--update-nov): + Handle > NLINK_MAX messages. + * nnmaildir.el (nnmaildir-request-set-mark): Use + nnmaildir--emlink-p and nnmaildir--eexist-p. + 2004-01-25 Alex Schroeder * spam-stat.el (spam-stat-process-directory-age): New option. diff --git a/lisp/nnmaildir.el b/lisp/nnmaildir.el index c6d776568..bd498a5cc 100644 --- a/lisp/nnmaildir.el +++ b/lisp/nnmaildir.el @@ -229,7 +229,6 @@ by nnmaildir-request-article.") (defmacro nnmaildir--nov-dir (dir) `(nnmaildir--subdir ,dir "nov")) (defmacro nnmaildir--marks-dir (dir) `(nnmaildir--subdir ,dir "marks")) (defmacro nnmaildir--num-dir (dir) `(nnmaildir--subdir ,dir "num")) -(defmacro nnmaildir--num-file (dir) `(concat ,dir ":")) (defmacro nnmaildir--unlink (file-arg) `(let ((file ,file-arg)) @@ -237,20 +236,36 @@ by nnmaildir-request-article.") (defun nnmaildir--mkdir (dir) (or (file-exists-p (file-name-as-directory dir)) (make-directory-internal (directory-file-name dir)))) +(defun nnmaildir--mkfile (file) + (write-region "" nil file nil 'no-message)) (defun nnmaildir--delete-dir-files (dir ls) (when (file-attributes dir) (mapcar 'delete-file (funcall ls dir 'full "\\`[^.]" 'nosort)) (delete-directory dir))) (defun nnmaildir--group-maxnum (server group) - (if (zerop (nnmaildir--grp-count group)) 0 - (let ((x (nnmaildir--srvgrp-dir (nnmaildir--srv-dir server) - (nnmaildir--grp-name group)))) - (setq x (nnmaildir--nndir x) - x (nnmaildir--num-dir x) - x (nnmaildir--num-file x) - x (file-attributes x)) - (if x (1- (nth 1 x)) 0)))) + (catch 'return + (if (zerop (nnmaildir--grp-count group)) (throw 'return 0)) + (let ((dir (nnmaildir--srvgrp-dir (nnmaildir--srv-dir server) + (nnmaildir--grp-name group))) + (number-opened 1) + attr ino-opened nlink number-linked) + (setq dir (nnmaildir--nndir dir) + dir (nnmaildir--num-dir dir)) + (while t + (setq attr (file-attributes + (concat dir (number-to-string number-opened)))) + (or attr (throw 'return (1- number-opened))) + (setq ino-opened (nth 10 attr) + nlink (nth 1 attr) + number-linked (+ number-opened nlink)) + (if (or (< nlink 1) (< number-linked nlink)) + (signal 'error '("Arithmetic overflow"))) + (setq attr (file-attributes + (concat dir (number-to-string number-linked)))) + (or attr (throw 'return (1- number-linked))) + (if (/= ino-opened (nth 10 attr)) + (setq number-opened number-linked)))))) ;; Make the given server, if non-nil, be the current server. Then make the ;; given group, if non-nil, be the current group of the current server. Then @@ -287,6 +302,56 @@ by nnmaildir-request-article.") (setq pos (match-end 0)))) string) +(defun nnmaildir--emlink-p (err) + (and (eq (car err) 'file-error) + (string= (caddr err) "too many links"))) + +(defun nnmaildir--eexist-p (err) + (eq (car err) 'file-already-exists)) + +(defun nnmaildir--new-number (nndir) + "Allocate a new article number by atomically creating a file under NNDIR." + (let ((numdir (nnmaildir--num-dir nndir)) + (make-new-file t) + (number-open 1) + number-link previous-number-link path-open path-link ino-open) + (nnmaildir--mkdir numdir) + (catch 'return + (while t + (setq path-open (concat numdir (number-to-string number-open))) + (if (not make-new-file) + (setq previous-number-link number-link) + (nnmaildir--mkfile path-open) + ;; If Emacs had O_CREAT|O_EXCL, we could return number-open here. + (setq make-new-file nil + previous-number-link 0)) + (let* ((attr (file-attributes path-open)) + (nlink (nth 1 attr))) + (setq ino-open (nth 10 attr) + number-link (+ number-open nlink)) + (if (or (< nlink 1) (< number-link nlink)) + (signal 'error '("Arithmetic overflow")))) + (if (= number-link previous-number-link) + ;; We've already tried this number, in the previous loop iteration, + ;; and failed. + (signal 'error `("Corrupt internal nnmaildir data" ,path-open))) + (setq path-link (concat numdir (number-to-string number-link))) + (condition-case err + (progn + (add-name-to-file path-open path-link) + (throw 'return number-link)) + (error + (cond + ((nnmaildir--emlink-p err) + (setq make-new-file t + number-open number-link)) + ((nnmaildir--eexist-p err) + (let ((attr (file-attributes path-link))) + (if (/= (nth 10 attr) ino-open) + (setq number-open number-link + number-link 0)))) + (t (signal (car err) (cdr err)))))))))) + (defun nnmaildir--update-nov (server group article) (let ((nnheader-file-coding-system 'binary) (srv-dir (nnmaildir--srv-dir server)) @@ -398,30 +463,7 @@ by nnmaildir-request-article.") nnmaildir--extra) num (nnmaildir--art-num article)) (unless num - ;; Allocate a new article number. - (erase-buffer) - (setq numdir (nnmaildir--num-dir dir) - file (nnmaildir--num-file numdir) - num -1) - (nnmaildir--mkdir numdir) - (write-region "" nil file nil 'no-message) - (while file - ;; Get the number of links to file. - (setq attr (nth 1 (file-attributes file))) - (if (= attr num) - ;; We've already tried this number, in the previous loop - ;; iteration, and failed. - (signal 'error `("Corrupt internal nnmaildir data" ,numdir))) - ;; If attr is 123, try to link file to "123". This atomically - ;; increases the link count and creates the "123" link, failing - ;; if that link was already created by another Gnus, just after - ;; we stat()ed file. - (condition-case nil - (progn - (add-name-to-file file (concat numdir (format "%x" attr))) - (setq file nil)) ;; Stop looping. - (file-already-exists nil)) - (setq num attr)) + (setq num (nnmaildir--new-number dir)) (setf (nnmaildir--art-num article) num)) ;; Store this new NOV data in a file (erase-buffer) @@ -1502,16 +1544,15 @@ by nnmaildir-request-article.") (add-name-to-file permarkfile mfile) (error (cond - ((eq (car err) 'file-already-exists)) + ((nnmaildir--eexist-p err)) ((and (eq (car err) 'file-error) (string= (caddr err) "no such file or directory")) (nnmaildir--mkdir mdir) - (write-region "" nil permarkfile nil 'no-message) + (nnmaildir--mkfile permarkfile) (add-name-to-file permarkfile mfile)) - ((and (eq (car err) 'file-error) - (string= (caddr err) "too many links")) + ((nnmaildir--emlink-p err) (let ((permarkfilenew (concat permarkfile "{new}"))) - (write-region "" nil permarkfilenew nil 'no-message) + (nnmaildir--mkfile permarkfilenew) (rename-file permarkfilenew permarkfile 'replace) (add-name-to-file permarkfile mfile))) (t (signal (car err) (cdr err))))))) -- 2.25.1