00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <config.h>
00022
00023 #include "flint_lock.h"
00024
00025 #ifndef __WIN32__
00026 #include "safeerrno.h"
00027
00028 #include "safefcntl.h"
00029 #include <unistd.h>
00030 #include <stdlib.h>
00031 #include <sys/types.h>
00032
00033
00034
00035
00036
00037
00038 #ifdef _NEWLIB_VERSION
00039
00040
00041 #include <netinet/in.h>
00042 #endif
00043 #include <sys/socket.h>
00044 #include <sys/wait.h>
00045 #include <signal.h>
00046 #endif
00047
00048 #include "omassert.h"
00049
00050 #ifdef __CYGWIN__
00051 #include <sys/cygwin.h>
00052 #endif
00053
00054 FlintLock::reason
00055 FlintLock::lock(bool exclusive) {
00056
00057 (void)exclusive;
00058 Assert(exclusive);
00059 #if defined __CYGWIN__ || defined __WIN32__
00060 Assert(hFile == INVALID_HANDLE_VALUE);
00061 #ifdef __CYGWIN__
00062 char fnm[MAX_PATH];
00063 cygwin_conv_to_win32_path(filename.c_str(), fnm);
00064 #else
00065 const char *fnm = filename.c_str();
00066 #endif
00067 hFile = CreateFile(fnm, GENERIC_WRITE, FILE_SHARE_READ,
00068 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
00069 if (hFile != INVALID_HANDLE_VALUE) return SUCCESS;
00070 if (GetLastError() == ERROR_ALREADY_EXISTS) return INUSE;
00071 return UNKNOWN;
00072 #elif defined __EMX__
00073 APIRET rc;
00074 ULONG ulAction;
00075 rc = DosOpen((PCSZ)filename.c_str(), &hFile, &ulAction, 0, FILE_NORMAL,
00076 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
00077 OPEN_SHARE_DENYWRITE | OPEN_ACCESS_WRITEONLY,
00078 NULL);
00079 if (rc == NO_ERROR) return SUCCESS;
00080 if (rc == ERROR_ACCESS_DENIED) return INUSE;
00081 return UNKNOWN;
00082 #else
00083 Assert(fd == -1);
00084 int lockfd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
00085 if (lockfd < 0) return UNKNOWN;
00086
00087 int fds[2];
00088 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fds) < 0) {
00089
00090 close(lockfd);
00091 return UNKNOWN;
00092 }
00093
00094 pid_t child = fork();
00095 if (child == 0) {
00096
00097 close(fds[0]);
00098
00099 reason why = SUCCESS;
00100 {
00101 struct flock fl;
00102 fl.l_type = F_WRLCK;
00103 fl.l_whence = SEEK_SET;
00104 fl.l_start = 0;
00105 fl.l_len = 1;
00106 while (fcntl(lockfd, F_SETLK, &fl) == -1) {
00107 if (errno != EINTR) {
00108
00109
00110 if (errno == EACCES || errno == EAGAIN) {
00111 why = INUSE;
00112 } else if (errno == ENOLCK) {
00113 why = UNSUPPORTED;
00114 } else {
00115 _exit(0);
00116 }
00117 break;
00118 }
00119 }
00120 }
00121
00122 {
00123
00124 char ch = static_cast<char>(why);
00125 while (write(fds[1], &ch, 1) < 0) {
00126
00127
00128
00129
00130 if (errno != EINTR) _exit(1);
00131 }
00132 if (why != SUCCESS) _exit(0);
00133 }
00134
00135
00136
00137 dup2(fds[1], 0);
00138
00139 execl("/bin/cat", "/bin/cat", (void*)NULL);
00140
00141 char ch;
00142 while (read(0, &ch, 1) != 0) { }
00143 _exit(0);
00144 }
00145
00146 close(lockfd);
00147
00148 if (child == -1) {
00149
00150 close(fds[0]);
00151 close(fds[1]);
00152 return UNKNOWN;
00153 }
00154
00155
00156 close(fds[1]);
00157 while (true) {
00158 char ch;
00159 int n = read(fds[0], &ch, 1);
00160 if (n == 1) {
00161 reason why = static_cast<reason>(ch);
00162 if (why == SUCCESS) break;
00163 close(fds[0]);
00164 return why;
00165 }
00166 if (n == 0 || errno != EINTR) {
00167
00168
00169 close(fds[0]);
00170 return UNKNOWN;
00171 }
00172 }
00173
00174 fd = fds[0];
00175 pid = child;
00176 return SUCCESS;
00177 #endif
00178 }
00179
00180 void
00181 FlintLock::release() {
00182 #if defined __CYGWIN__ || defined __WIN32__
00183 if (hFile == INVALID_HANDLE_VALUE) return;
00184 CloseHandle(hFile);
00185 hFile = INVALID_HANDLE_VALUE;
00186 #elif defined __EMX__
00187 if (hFile == NULLHANDLE) return;
00188 DosClose(hFile);
00189 hFile = NULLHANDLE;
00190 #else
00191 if (fd < 0) return;
00192 close(fd);
00193 fd = -1;
00194
00195
00196
00197
00198 if (kill(pid, SIGHUP) == 0) {
00199 int status;
00200 while (waitpid(pid, &status, 0) < 0) {
00201 if (errno != EINTR) break;
00202 }
00203 }
00204 #endif
00205 }