1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "berberis/kernel_api/open_emulation.h"
18
19 // Documentation says that to get access to the constants used below one
20 // must include these three files. In reality it looks as if all constants
21 // are defined by <fcntl.h>, but we include all three as described in docs.
22 #include <fcntl.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25
26 #include "berberis/kernel_api/tracing.h"
27
28 #define GUEST_O_DIRECTORY 00040000
29 #define GUEST_O_NOFOLLOW 00100000
30 #define GUEST_O_DIRECT 00200000
31 #define GUEST_O_LARGEFILE 00400000
32
33 namespace berberis {
34
35 #if !defined(__i386__) && !defined(__x86_64__)
36 #error Currently open flags conversion is only supported on x86
37 #endif
38
39 // Glibc doesn't expose __O_SYNC
40 #if !defined(__O_SYNC)
41
42 #if defined(__BIONIC__)
43 #error __O_SYNC undefined in bionic
44 #endif
45
46 #define __O_SYNC 04000000
47
48 #endif
49
50 // Musl defines an O_SEARCH flag an includes it in O_ACCMODE,
51 // bionic and glibc don't.
52 #ifndef O_SEARCH
53 #define O_SEARCH 0
54 #endif
55
56 static_assert((O_ACCMODE & ~O_SEARCH) == 00000003);
57
58 // These flags should have the same value on all architectures.
59 static_assert(O_CREAT == 00000100);
60 static_assert(O_EXCL == 00000200);
61 static_assert(O_NOCTTY == 00000400);
62 static_assert(O_TRUNC == 00001000);
63 static_assert(O_APPEND == 00002000);
64 static_assert(O_NONBLOCK == 00004000);
65 static_assert(O_DSYNC == 00010000);
66 static_assert(FASYNC == 00020000);
67 static_assert(O_NOATIME == 01000000);
68 static_assert(O_CLOEXEC == 02000000);
69 static_assert(__O_SYNC == 04000000);
70 static_assert(O_SYNC == (O_DSYNC | __O_SYNC));
71 static_assert(O_PATH == 010000000);
72
73 namespace {
74
75 const int kCompatibleOpenFlags = O_ACCMODE | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | O_APPEND |
76 O_NONBLOCK | O_DSYNC | FASYNC | O_NOATIME | O_CLOEXEC | __O_SYNC |
77 O_PATH;
78
79 } // namespace
80
ToHostOpenFlags(int guest_flags)81 int ToHostOpenFlags(int guest_flags) {
82 const int kIncompatibleGuestOpenFlags =
83 GUEST_O_DIRECTORY | GUEST_O_NOFOLLOW | GUEST_O_DIRECT | GUEST_O_LARGEFILE;
84
85 int unknown_guest_flags = guest_flags & ~(kCompatibleOpenFlags | kIncompatibleGuestOpenFlags);
86 if (unknown_guest_flags) {
87 KAPI_TRACE("Unsupported guest open flags: original=0x%x unsupported=0x%x",
88 guest_flags,
89 unknown_guest_flags);
90 }
91
92 int host_flags = guest_flags & ~kIncompatibleGuestOpenFlags;
93
94 if (guest_flags & GUEST_O_DIRECTORY) {
95 host_flags |= O_DIRECTORY;
96 }
97 if (guest_flags & GUEST_O_NOFOLLOW) {
98 host_flags |= O_NOFOLLOW;
99 }
100 if (guest_flags & GUEST_O_DIRECT) {
101 host_flags |= O_DIRECT;
102 }
103 if (guest_flags & GUEST_O_LARGEFILE) {
104 host_flags |= O_LARGEFILE;
105 }
106
107 return host_flags;
108 }
109
ToGuestOpenFlags(int host_flags)110 int ToGuestOpenFlags(int host_flags) {
111 const int kIncompatibleHostOpenFlags = O_DIRECTORY | O_NOFOLLOW | O_DIRECT | O_LARGEFILE;
112
113 int unknown_host_flags = host_flags & ~(kCompatibleOpenFlags | kIncompatibleHostOpenFlags);
114 if (unknown_host_flags) {
115 KAPI_TRACE("Unsupported host open flags: original=0x%x unsupported=0x%x",
116 host_flags,
117 unknown_host_flags);
118 }
119
120 int guest_flags = host_flags & ~kIncompatibleHostOpenFlags;
121
122 if (host_flags & O_DIRECTORY) {
123 guest_flags |= GUEST_O_DIRECTORY;
124 }
125 if (host_flags & O_NOFOLLOW) {
126 guest_flags |= GUEST_O_NOFOLLOW;
127 }
128 if (host_flags & O_DIRECT) {
129 guest_flags |= GUEST_O_DIRECT;
130 }
131 if (host_flags & O_LARGEFILE) {
132 guest_flags |= GUEST_O_LARGEFILE;
133 }
134
135 return guest_flags;
136 }
137
138 } // namespace berberis
139