1 /* Written by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3 of the License ONLY.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 module iv
.lockfile
/*is aliced*/;
21 // ////////////////////////////////////////////////////////////////////////// //
22 private struct LockFileImpl
{
25 char[] fname
; // malloced, 0-terminated (but 0 is not in slice)
31 import core
.stdc
.stdlib
: free
;
32 import core
.sys
.posix
.unistd
: getpid
, close
;
36 import core
.sys
.posix
.fcntl
;
39 lk
.l_whence
= 0/*SEEK_SET*/;
43 fcntl(fd
, F_SETLK
, &lk
);
50 import core
.stdc
.stdio
: remove
;
57 // this will return `false` for already locked file!
59 import core
.sys
.posix
.fcntl
;
60 import core
.sys
.posix
.unistd
: getpid
;
62 if (locked
) return false;
65 lk
.l_whence
= 0/*SEEK_SET*/;
69 if (fcntl(fd
, F_SETLK
/*W*/, &lk
) == 0) locked
= true;
74 usize
create (const(char)[] afname
) {
75 import core
.sys
.posix
.fcntl
/*: open*/;
76 import core
.sys
.posix
.unistd
: close
;
77 import core
.sys
.posix
.stdlib
: malloc
, free
;
78 if (afname
.length
== 0) return 0;
79 auto namep
= cast(char*)malloc(afname
.length
+1);
80 if (namep
is null) return 0;
81 namep
[0..afname
.length
+1] = 0;
82 namep
[0..afname
.length
] = afname
[];
83 auto xfd
= open(namep
, O_RDWR|O_CREAT
/*|O_CLOEXEC*/, 0x1b6/*0o666*/);
84 if (xfd
< 0) { free(namep
); return 0; }
85 auto fimp
= cast(ubyte*)malloc(LockFileImpl
.sizeof
);
86 if (fimp
is null) { close(xfd
); free(namep
); return 0; }
87 fimp
[0..LockFileImpl
.sizeof
] = 0;
88 auto res
= cast(LockFileImpl
*)fimp
;
89 res
.fname
= namep
[0..afname
.length
];
92 return cast(usize
)fimp
;
97 // ////////////////////////////////////////////////////////////////////////// //
98 public struct LockFile
{
102 nothrow @trusted @nogc:
105 auto lcp
= cast(LockFileImpl
*)lci
;
106 if (--lcp
.rc
== 0) lcp
.kill
;
112 this (const(char)[] fname
) { lci
= LockFileImpl
.create(fname
); }
113 ~this () { pragma(inline
, true); if (lci
) decref(); }
114 this (this) { pragma(inline
, true); if (lci
) { ++(cast(LockFileImpl
*)lci
).rc
; } }
115 void opAssign (in LockFile fl
) {
116 if (fl
.lci
) ++(cast(LockFileImpl
*)fl
.lci
).rc
;
121 void close () { pragma(inline
, true); if (lci
!= 0) decref(); }
123 @property bool valid () const pure { pragma(inline
, true); return (lci
!= 0); }
124 @property bool locked () const pure { pragma(inline
, true); return (lci
!= 0 ?
(cast(LockFileImpl
*)lci
).locked
: false); }
126 // this will return `false` for already locked file!
127 bool tryLock () { pragma(inline
, true); return (lci
== 0 ?
false : (cast(LockFileImpl
*)lci
).tryLock
); }
131 // ////////////////////////////////////////////////////////////////////////// //
133 __gshared LockFile prjLockFile;
134 prjLockFile = LockFile(pfn~".lock");
135 if (!prjLockFile.tryLock) {