* Reliably open and lock a file. * * Please do not modify this code without first reading the revision history * and discussing your changes with . Don't be fooled by the * code's apparent simplicity; there would be no need for this function if it * was easy to get right. */
| 48 | * was easy to get right. |
| 49 | */ |
| 50 | static int |
| 51 | vflopenat(int dirfd, const char *path, int flags, va_list ap) |
| 52 | { |
| 53 | int fd, operation, serrno, trunc; |
| 54 | struct stat sb, fsb; |
| 55 | mode_t mode; |
| 56 | |
| 57 | #ifdef O_EXLOCK |
| 58 | flags &= ~O_EXLOCK; |
| 59 | #endif |
| 60 | |
| 61 | mode = 0; |
| 62 | if (flags & O_CREAT) { |
| 63 | mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */ |
| 64 | } |
| 65 | |
| 66 | operation = LOCK_EX; |
| 67 | if (flags & O_NONBLOCK) |
| 68 | operation |= LOCK_NB; |
| 69 | |
| 70 | trunc = (flags & O_TRUNC); |
| 71 | flags &= ~O_TRUNC; |
| 72 | |
| 73 | for (;;) { |
| 74 | if ((fd = openat(dirfd, path, flags, mode)) == -1) |
| 75 | /* non-existent or no access */ |
| 76 | return (-1); |
| 77 | if (flock(fd, operation) == -1) { |
| 78 | /* unsupported or interrupted */ |
| 79 | serrno = errno; |
| 80 | (void)close(fd); |
| 81 | errno = serrno; |
| 82 | return (-1); |
| 83 | } |
| 84 | if (fstatat(dirfd, path, &sb, 0) == -1) { |
| 85 | /* disappeared from under our feet */ |
| 86 | (void)close(fd); |
| 87 | continue; |
| 88 | } |
| 89 | if (fstat(fd, &fsb) == -1) { |
| 90 | /* can't happen [tm] */ |
| 91 | serrno = errno; |
| 92 | (void)close(fd); |
| 93 | errno = serrno; |
| 94 | return (-1); |
| 95 | } |
| 96 | if (sb.st_dev != fsb.st_dev || |
| 97 | sb.st_ino != fsb.st_ino) { |
| 98 | /* changed under our feet */ |
| 99 | (void)close(fd); |
| 100 | continue; |
| 101 | } |
| 102 | if (trunc && ftruncate(fd, 0) != 0) { |
| 103 | /* can't happen [tm] */ |
| 104 | serrno = errno; |
| 105 | (void)close(fd); |
| 106 | errno = serrno; |
| 107 | return (-1); |