aboutsummaryrefslogtreecommitdiffstats
path: root/ports/linux/guts/openat.c
blob: 673ea6e673738c56756851c6e4a8221d5b598eb6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/* 
 * Copyright (c) 2008-2010, 2013 Wind River Systems; see
 * guts/COPYRIGHT for information.
 *
 * SPDX-License-Identifier: LGPL-2.1-only
 *
 * static int
 * wrap_openat(int dirfd, const char *path, int flags, ...mode_t mode) {
 *	int rc = -1;
 */
	struct stat64 buf;
	int overly_magic_nonblocking = 0;
	int existed = 1;
	int save_errno;
	sigset_t local_saved_sigmask;

	/* mask out mode bits appropriately */
	mode = mode & ~pseudo_umask;

#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
	if (dirfd != AT_FDCWD) {
		errno = ENOSYS;
		return -1;
	}
#endif

#ifdef PSEUDO_FORCE_ASYNC
        /* Yes, I'm aware that every Linux system I've seen has
         * DSYNC and RSYNC being the same value as SYNC.
         */

        flags &= ~(O_SYNC
#ifdef O_DIRECT
                | O_DIRECT
#endif
#ifdef O_DSYNC
                | O_DSYNC
#endif
#ifdef O_RSYNC
                | O_RSYNC
#endif
        );
#endif

#ifdef O_TMPFILE
	/* don't handle O_CREAT the same way if O_TMPFILE exists
	 * and is set.
	 */
	if ((flags & O_TMPFILE) == O_TMPFILE) {
		existed = 0;
	} else
#endif
	/* if a creation has been requested, check whether file exists */
	/* note "else" in #ifdef O_TMPFILE above */
	if (flags & O_CREAT) {
		save_errno = errno;
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
		rc = real___xstat64(_STAT_VER, path, &buf);
#else
		rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0);
#endif
		existed = (rc != -1);
		if (!existed)
			pseudo_debug(PDBGF_FILE, "openat_creat: %s -> 0%o\n", path, mode);
		errno = save_errno;
	}

	/* if a pipe is opened without O_NONBLOCK, for only reading or
	 * only writing, it can block forever. We need to do extra magic
	 * in that case...
	 */
	if (!(flags & O_NONBLOCK) && ((flags & (O_WRONLY | O_RDONLY | O_RDWR)) != O_RDWR)) {
		save_errno = errno;
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
		rc = real___xstat64(_STAT_VER, path, &buf);
#else
		rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0);
#endif
		if (rc != -1 && S_ISFIFO(buf.st_mode)) {
			overly_magic_nonblocking = 1;
		}
	}

	/* this is a horrible special case and i do not know whether it will work */
	if (overly_magic_nonblocking) {
		pseudo_droplock();
		sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, &local_saved_sigmask);
	}
	/* because we are not actually root, secretly mask in 0600 to the
	 * underlying mode.  The ", 0" is because the only time mode matters
	 * is if a file is going to be created, in which case it's
	 * not a directory.
	 */
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
	rc = real_open(path, flags, PSEUDO_FS_MODE(mode, 0));
#else
	rc = real_openat(dirfd, path, flags, PSEUDO_FS_MODE(mode, 0));
#endif
	if (overly_magic_nonblocking) {
		save_errno = errno;
		sigprocmask(SIG_SETMASK, &local_saved_sigmask, NULL);
		/* well this is a problem. we can't NOT proceed; we may have
		 * already opened the file! we can't even return up the call
		 * stack to stuff that's going to try to drop the lock.
		 */
		if (pseudo_getlock()) {
			pseudo_diag("PANIC: after opening a readonly/writeonly FIFO (path '%s', fd %d, errno %d, saved errno %d), could not regain lock. unrecoverable. sorry. bye.\n",
				path, rc, errno, save_errno);
			abort();
		}
		errno = save_errno;
	}

	if (rc != -1) {
		save_errno = errno;
		int stat_rc;
#ifdef O_TMPFILE
		/* in O_TMPFILE case, nothing gets put in the
		 * database, because there's no directory entries for
		 * the file yet.
		 */
		if ((flags & O_TMPFILE) == O_TMPFILE) {
			real_fchmod(rc, PSEUDO_FS_MODE(mode, 0));
			errno = save_errno;
			return rc;
		}
#endif
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
		stat_rc = real___xstat64(_STAT_VER, path, &buf);
#else
		stat_rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0);
#endif

		if (stat_rc != -1) {
			buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode);
			if (!existed) {
				real_fchmod(rc, PSEUDO_FS_MODE(mode, 0));
				// file has no path, but has been created
				pseudo_client_op(OP_CREAT, 0, -1, dirfd, path, &buf);
			}
				pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(flags), rc, dirfd, path, &buf);
		} else {
			pseudo_debug(PDBGF_FILE, "openat (fd %d, path %d/%s, flags %d) succeeded, but stat failed (%s).\n",
				rc, dirfd, path, flags, strerror(errno));
			pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(flags), rc, dirfd, path, 0);
		}
		errno = save_errno;
	}

/*	return rc;
 * }
 */