1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #pragma prototyped 23 24 #include "asohdr.h" 25 26 #if defined(_UWIN) && defined(_BLD_ast) || !_aso_fcntl 27 28 NoN(aso_meth_fcntl) 29 30 #else 31 32 #include <sys/stat.h> 33 #include <fcntl.h> 34 #include <unistd.h> 35 36 typedef struct APL_s 37 { 38 int fd; 39 size_t size; 40 char path[1]; 41 } APL_t; 42 43 static void* 44 aso_init_fcntl(void* data, const char* details) 45 { 46 APL_t* apl = (APL_t*)data; 47 char* path; 48 char* opt; 49 size_t size; 50 size_t references; 51 int n; 52 int fd; 53 int drop; 54 int perm; 55 struct flock lock; 56 char buf[PATH_MAX]; 57 char tmp[64]; 58 59 if (apl) 60 { 61 lock.l_type = F_WRLCK; 62 lock.l_whence = SEEK_SET; 63 lock.l_start = apl->size; 64 lock.l_len = sizeof(references); 65 if (fcntl(apl->fd, F_SETLKW, &lock) >= 0) 66 { 67 if (lseek(apl->fd, apl->size, SEEK_SET) != apl->size) 68 references = 0; 69 else if (read(apl->fd, &references, sizeof(references)) != sizeof(references)) 70 references = 0; 71 else if (references > 0) 72 { 73 references--; 74 if (lseek(apl->fd, apl->size, SEEK_SET) != apl->size) 75 references = 0; 76 else if (write(apl->fd, &references, sizeof(references)) != sizeof(references)) 77 references = 0; 78 } 79 lock.l_type = F_UNLCK; 80 fcntl(apl->fd, F_SETLK, &lock); 81 if (!references) 82 remove(apl->path); 83 } 84 close(apl->fd); 85 free(apl); 86 return 0; 87 } 88 fd = -1; 89 perm = S_IRUSR|S_IWUSR; 90 drop = 0; 91 size = 32 * 1024 - sizeof(references); 92 if (path = (char*)details) 93 while (opt = strchr(path, ',')) 94 { 95 if (strneq(path, "perm=", 5)) 96 { 97 if ((n = opt - (path + 5)) >= sizeof(tmp)) 98 n = sizeof(tmp) - 1; 99 memcpy(tmp, path + 5, n); 100 tmp[n] = 0; 101 perm = strperm(tmp, NiL, perm); 102 } 103 else if (strneq(path, "size=", 5)) 104 { 105 size = strtoul(path + 5, NiL, 0); 106 if (size <= sizeof(references)) 107 goto bad; 108 size -= sizeof(references); 109 } 110 path = opt + 1; 111 } 112 if (!path || !*path) 113 { 114 if (!(path = pathtemp(buf, sizeof(buf), NiL, "aso", &fd))) 115 return 0; 116 drop = 1; 117 } 118 if (!(apl = newof(0, APL_t, 1, strlen(path)))) 119 goto bad; 120 if (fd >= 0 || (fd = open(path, O_RDWR|O_cloexec)) < 0 && (fd = open(path, O_CREAT|O_RDWR|O_cloexec, perm)) >= 0) 121 { 122 if (lseek(fd, size, SEEK_SET) != size) 123 goto bad; 124 references = 1; 125 if (write(fd, &references, sizeof(references)) != sizeof(references)) 126 goto bad; 127 } 128 else 129 { 130 if ((size = lseek(fd, 0, SEEK_END)) <= sizeof(references)) 131 goto bad; 132 size -= sizeof(references); 133 lock.l_type = F_WRLCK; 134 lock.l_whence = SEEK_SET; 135 lock.l_start = 0; 136 lock.l_len = sizeof(references); 137 if (fcntl(fd, F_SETLKW, &lock) < 0) 138 goto bad; 139 if (lseek(fd, size, SEEK_SET) != size) 140 goto bad; 141 if (read(fd, &references, sizeof(references)) != sizeof(references)) 142 goto bad; 143 references++; 144 if (lseek(fd, size, SEEK_SET) != size) 145 goto bad; 146 if (write(fd, &references, sizeof(references)) != sizeof(references)) 147 goto bad; 148 lock.l_type = F_UNLCK; 149 fcntl(fd, F_SETLK, &lock); 150 } 151 apl->fd = fd; 152 apl->size = size; 153 strcpy(apl->path, path); 154 return apl; 155 bad: 156 if (apl) 157 free(apl); 158 if (fd >= 0) 159 close(fd); 160 if (drop) 161 remove(path); 162 return 0; 163 } 164 165 static ssize_t 166 aso_lock_fcntl(void* data, ssize_t k, void volatile* p) 167 { 168 APL_t* apl = (APL_t*)data; 169 struct flock lock; 170 171 if (!apl) 172 return -1; 173 if (k > 0) 174 lock.l_type = F_UNLCK; 175 else 176 { 177 lock.l_type = F_WRLCK; 178 k = HASH(p, apl->size) + 1; 179 } 180 lock.l_whence = SEEK_SET; 181 lock.l_start = k - 1; 182 lock.l_len = 1; 183 return fcntl(apl->fd, F_SETLKW, &lock) < 0 ? -1 : k; 184 } 185 186 Asometh_t _aso_meth_fcntl = { "fcntl", ASO_PROCESS, aso_init_fcntl, aso_lock_fcntl }; 187 188 #endif 189