/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1985-2012 AT&T Intellectual Property * * and is licensed under the * * Eclipse Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.eclipse.org/org/documents/epl-v10.html * * (with md5 checksum b35adb5213ca9657e911e9befb180842) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * David Korn * * Phong Vo * * * ***********************************************************************/ #pragma prototyped #include "asohdr.h" #if defined(_UWIN) && defined(_BLD_ast) || !_aso_fcntl NoN(aso_meth_fcntl) #else #include #include #include typedef struct APL_s { int fd; size_t size; char path[1]; } APL_t; static void* aso_init_fcntl(void* data, const char* details) { APL_t* apl = (APL_t*)data; char* path; char* opt; size_t size; size_t references; int n; int fd; int drop; int perm; struct flock lock; char buf[PATH_MAX]; char tmp[64]; if (apl) { lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = apl->size; lock.l_len = sizeof(references); if (fcntl(apl->fd, F_SETLKW, &lock) >= 0) { if (lseek(apl->fd, apl->size, SEEK_SET) != apl->size) references = 0; else if (read(apl->fd, &references, sizeof(references)) != sizeof(references)) references = 0; else if (references > 0) { references--; if (lseek(apl->fd, apl->size, SEEK_SET) != apl->size) references = 0; else if (write(apl->fd, &references, sizeof(references)) != sizeof(references)) references = 0; } lock.l_type = F_UNLCK; fcntl(apl->fd, F_SETLK, &lock); if (!references) remove(apl->path); } close(apl->fd); free(apl); return 0; } fd = -1; perm = S_IRUSR|S_IWUSR; drop = 0; size = 32 * 1024 - sizeof(references); if (path = (char*)details) while (opt = strchr(path, ',')) { if (strneq(path, "perm=", 5)) { if ((n = opt - (path + 5)) >= sizeof(tmp)) n = sizeof(tmp) - 1; memcpy(tmp, path + 5, n); tmp[n] = 0; perm = strperm(tmp, NiL, perm); } else if (strneq(path, "size=", 5)) { size = strtoul(path + 5, NiL, 0); if (size <= sizeof(references)) goto bad; size -= sizeof(references); } path = opt + 1; } if (!path || !*path) { if (!(path = pathtemp(buf, sizeof(buf), NiL, "aso", &fd))) return 0; drop = 1; } if (!(apl = newof(0, APL_t, 1, strlen(path)))) goto bad; if (fd >= 0 || (fd = open(path, O_RDWR|O_cloexec)) < 0 && (fd = open(path, O_CREAT|O_RDWR|O_cloexec, perm)) >= 0) { if (lseek(fd, size, SEEK_SET) != size) goto bad; references = 1; if (write(fd, &references, sizeof(references)) != sizeof(references)) goto bad; } else { if ((size = lseek(fd, 0, SEEK_END)) <= sizeof(references)) goto bad; size -= sizeof(references); lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = sizeof(references); if (fcntl(fd, F_SETLKW, &lock) < 0) goto bad; if (lseek(fd, size, SEEK_SET) != size) goto bad; if (read(fd, &references, sizeof(references)) != sizeof(references)) goto bad; references++; if (lseek(fd, size, SEEK_SET) != size) goto bad; if (write(fd, &references, sizeof(references)) != sizeof(references)) goto bad; lock.l_type = F_UNLCK; fcntl(fd, F_SETLK, &lock); } apl->fd = fd; apl->size = size; strcpy(apl->path, path); return apl; bad: if (apl) free(apl); if (fd >= 0) close(fd); if (drop) remove(path); return 0; } static ssize_t aso_lock_fcntl(void* data, ssize_t k, void volatile* p) { APL_t* apl = (APL_t*)data; struct flock lock; if (!apl) return -1; if (k > 0) lock.l_type = F_UNLCK; else { lock.l_type = F_WRLCK; k = HASH(p, apl->size) + 1; } lock.l_whence = SEEK_SET; lock.l_start = k - 1; lock.l_len = 1; return fcntl(apl->fd, F_SETLKW, &lock) < 0 ? -1 : k; } Asometh_t _aso_meth_fcntl = { "fcntl", ASO_PROCESS, aso_init_fcntl, aso_lock_fcntl }; #endif