summaryrefslogtreecommitdiffstats
path: root/maildrop/filelock.C
diff options
context:
space:
mode:
Diffstat (limited to 'maildrop/filelock.C')
-rw-r--r--maildrop/filelock.C82
1 files changed, 82 insertions, 0 deletions
diff --git a/maildrop/filelock.C b/maildrop/filelock.C
new file mode 100644
index 0000000..535ee3b
--- /dev/null
+++ b/maildrop/filelock.C
@@ -0,0 +1,82 @@
+#include "filelock.h"
+#include "mio.h"
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#include <errno.h>
+
+#include "liblock/config.h"
+#include "liblock/liblock.h"
+
+
+void FileLock::cleanup()
+{
+ UnLock();
+}
+
+void FileLock::forked()
+{
+ UnLock();
+}
+
+FileLock::FileLock() : fd(-1)
+{
+}
+
+FileLock::~FileLock()
+{
+ UnLock();
+}
+
+void FileLock::Lock(const char *filename)
+{
+ UnLock();
+
+ if ((fd=mopen(filename, O_CREAT | O_WRONLY, 0600)) < 0)
+ throw "Unable to create flock file.";
+
+ do_filelock(fd);
+}
+
+
+void FileLock::do_filelock(int fd)
+{
+int flockrc;
+
+ while ((flockrc=ll_lock_ex(fd)) < 0 && errno == EINTR)
+ ;
+
+ if (flockrc < 0)
+ {
+ struct stat stat_buf;
+
+ // FreeBSD has problems locking /dev/null. Presume that if
+ // you're writing to a device file, you know what you're doing.
+
+ if (fstat(fd, &stat_buf) >= 0 && (
+ S_ISREG(stat_buf.st_mode) || S_ISDIR(stat_buf.st_mode)))
+ {
+ return;
+ }
+
+ throw "flock() failed.";
+ }
+}
+
+void FileLock::UnLock()
+{
+ if (fd >= 0)
+ {
+ mclose(fd);
+ fd= -1;
+ }
+}