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, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module iv
.lockfile
/*is aliced*/;
22 // ////////////////////////////////////////////////////////////////////////// //
23 private struct LockFileImpl
{
26 char[] fname
; // malloced, 0-terminated (but 0 is not in slice)
32 import core
.stdc
.stdlib
: free
;
33 import core
.sys
.posix
.unistd
: getpid
, close
;
37 import core
.sys
.posix
.fcntl
;
40 lk
.l_whence
= 0/*SEEK_SET*/;
44 fcntl(fd
, F_SETLK
, &lk
);
51 import core
.stdc
.stdio
: remove
;
58 // this will return `false` for already locked file!
60 import core
.sys
.posix
.fcntl
;
61 import core
.sys
.posix
.unistd
: getpid
;
63 if (locked
) return false;
66 lk
.l_whence
= 0/*SEEK_SET*/;
70 if (fcntl(fd
, F_SETLK
/*W*/, &lk
) == 0) locked
= true;
75 usize
create (const(char)[] afname
) {
76 import core
.sys
.posix
.fcntl
/*: open*/;
77 import core
.sys
.posix
.unistd
: close
;
78 import core
.sys
.posix
.stdlib
: malloc
, free
;
79 if (afname
.length
== 0) return 0;
80 auto namep
= cast(char*)malloc(afname
.length
+1);
81 if (namep
is null) return 0;
82 namep
[0..afname
.length
+1] = 0;
83 namep
[0..afname
.length
] = afname
[];
84 auto xfd
= open(namep
, O_RDWR|O_CREAT
/*|O_CLOEXEC*/, 0x1b6/*0o666*/);
85 if (xfd
< 0) { free(namep
); return 0; }
86 auto fimp
= cast(ubyte*)malloc(LockFileImpl
.sizeof
);
87 if (fimp
is null) { close(xfd
); free(namep
); return 0; }
88 fimp
[0..LockFileImpl
.sizeof
] = 0;
89 auto res
= cast(LockFileImpl
*)fimp
;
90 res
.fname
= namep
[0..afname
.length
];
93 return cast(usize
)fimp
;
98 // ////////////////////////////////////////////////////////////////////////// //
99 public struct LockFile
{
103 nothrow @trusted @nogc:
106 auto lcp
= cast(LockFileImpl
*)lci
;
107 if (--lcp
.rc
== 0) lcp
.kill
;
113 this (const(char)[] fname
) { lci
= LockFileImpl
.create(fname
); }
114 ~this () { pragma(inline
, true); if (lci
) decref(); }
115 this (this) { pragma(inline
, true); if (lci
) { ++(cast(LockFileImpl
*)lci
).rc
; } }
116 void opAssign (in LockFile fl
) {
117 if (fl
.lci
) ++(cast(LockFileImpl
*)fl
.lci
).rc
;
122 void close () { pragma(inline
, true); if (lci
!= 0) decref(); }
124 @property bool valid () const pure { pragma(inline
, true); return (lci
!= 0); }
125 @property bool locked () const pure { pragma(inline
, true); return (lci
!= 0 ?
(cast(LockFileImpl
*)lci
).locked
: false); }
127 // this will return `false` for already locked file!
128 bool tryLock () { pragma(inline
, true); return (lci
== 0 ?
false : (cast(LockFileImpl
*)lci
).tryLock
); }
132 // ////////////////////////////////////////////////////////////////////////// //
134 __gshared LockFile prjLockFile;
135 prjLockFile = LockFile(pfn~".lock");
136 if (!prjLockFile.tryLock) {