varnish-cache/lib/libvarnish/vfl.c
0
/*-
1
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
2
 *
3
 * Copyright (c) 2007-2009 Dag-Erling Coïdan Smørgrav
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer
11
 *    in this position and unchanged.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 * Derived from:
28
 * $FreeBSD: head/lib/libutil/flopen.c 326219 2017-11-26 02:00:33Z pfg $
29
 */
30
31
#include "config.h"
32
33
#include <sys/file.h>
34
#include <sys/stat.h>
35
36
#include <errno.h>
37
#include <fcntl.h>
38
#include <stdarg.h>
39
#include <string.h>
40
#include <unistd.h>
41
42
#include "vfl.h"
43
44
/*
45
 * Reliably open and lock a file.
46
 *
47
 * Please do not modify this code without first reading the revision history
48
 * and discussing your changes with <des@freebsd.org>.  Don't be fooled by the
49
 * code's apparent simplicity; there would be no need for this function if it
50
 * was easy to get right.
51
 */
52
static int
53 49280
vflopenat(int dirfd, const char *path, int flags, va_list ap)
54
{
55
        int fd, operation, serrno, trunc;
56
        struct stat sb, fsb;
57
        mode_t mode;
58
59
#ifdef O_EXLOCK
60 49280
        flags &= ~O_EXLOCK;
61
#endif
62
63 49280
        mode = 0;
64 49280
        if (flags & O_CREAT) {
65 49280
                mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */
66 49280
        }
67
68 49280
        operation = LOCK_EX;
69 49280
        if (flags & O_NONBLOCK)
70 49280
                operation |= LOCK_NB;
71
72 49280
        trunc = (flags & O_TRUNC);
73 49280
        flags &= ~O_TRUNC;
74
75 49280
        for (;;) {
76 49280
                if ((fd = openat(dirfd, path, flags, mode)) == -1)
77
                        /* non-existent or no access */
78 28
                        return (-1);
79 49252
                if (flock(fd, operation) == -1) {
80
                        /* unsupported or interrupted */
81 56
                        serrno = errno;
82 56
                        (void)close(fd);
83 56
                        errno = serrno;
84 56
                        return (-1);
85
                }
86 49196
                if (fstatat(dirfd, path, &sb, 0) == -1) {
87
                        /* disappeared from under our feet */
88 0
                        (void)close(fd);
89 0
                        continue;
90
                }
91 49196
                if (fstat(fd, &fsb) == -1) {
92
                        /* can't happen [tm] */
93 0
                        serrno = errno;
94 0
                        (void)close(fd);
95 0
                        errno = serrno;
96 0
                        return (-1);
97
                }
98 49196
                if (sb.st_dev != fsb.st_dev ||
99 49196
                    sb.st_ino != fsb.st_ino) {
100
                        /* changed under our feet */
101 0
                        (void)close(fd);
102 0
                        continue;
103
                }
104 49196
                if (trunc && ftruncate(fd, 0) != 0) {
105
                        /* can't happen [tm] */
106 0
                        serrno = errno;
107 0
                        (void)close(fd);
108 0
                        errno = serrno;
109 0
                        return (-1);
110
                }
111
                /*
112
                 * The following change is provided as a specific example to
113
                 * avoid.
114
                 */
115
#if 0
116
                if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
117
                        serrno = errno;
118
                        (void)close(fd);
119
                        errno = serrno;
120
                        return (-1);
121
                }
122
#endif
123 49196
                return (fd);
124
        }
125 49280
}
126
127
int
128 49280
VFL_Open(const char *path, int flags, ...)
129
{
130
        va_list ap;
131
        int ret;
132
133 49280
        va_start(ap, flags);
134 49280
        ret = vflopenat(AT_FDCWD, path, flags, ap);
135 49280
        va_end(ap);
136 49280
        return (ret);
137
}