First set of licensing changes
[mono.git] / mono / io-layer / locking.c
1 /*
2  * io.c:  File, console and find handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  * Copyright (c) 2002-2009 Novell, Inc.
9  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11 #include <config.h>
12 #include <stdio.h>
13 #include <glib.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <mono/io-layer/wapi.h>
17 #include <mono/io-layer/wapi-private.h>
18 #include <mono/io-layer/handles-private.h>
19 #include <mono/io-layer/io-private.h>
20 #include <mono/io-layer/io-trace.h>
21 #include <mono/utils/mono-logger-internals.h>
22
23 gboolean
24 _wapi_lock_file_region (int fd, off_t offset, off_t length)
25 {
26 #if defined(__native_client__)
27         printf("WARNING: locking.c: _wapi_lock_file_region(): fcntl() not available on Native Client!\n");
28         // behave as below -- locks are not available
29         return(TRUE);
30 #else
31         struct flock lock_data;
32         int ret;
33
34         if (offset < 0 || length < 0) {
35                 SetLastError (ERROR_INVALID_PARAMETER);
36                 return(FALSE);
37         }
38
39         lock_data.l_type = F_WRLCK;
40         lock_data.l_whence = SEEK_SET;
41         lock_data.l_start = offset;
42         lock_data.l_len = length;
43         
44         do {
45                 ret = fcntl (fd, F_SETLK, &lock_data);
46         } while(ret == -1 && errno == EINTR);
47         
48         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl returns %d", __func__, ret);
49
50         if (ret == -1) {
51                 /*
52                  * if locks are not available (NFS for example),
53                  * ignore the error
54                  */
55                 if (errno == ENOLCK
56 #ifdef EOPNOTSUPP
57                     || errno == EOPNOTSUPP
58 #endif
59 #ifdef ENOTSUP
60                     || errno == ENOTSUP
61 #endif
62                    ) {
63                         return (TRUE);
64                 }
65                 
66                 SetLastError (ERROR_LOCK_VIOLATION);
67                 return(FALSE);
68         }
69
70         return(TRUE);
71 #endif /* __native_client__ */
72 }
73
74 gboolean
75 _wapi_unlock_file_region (int fd, off_t offset, off_t length)
76 {
77 #if defined(__native_client__)
78         printf("WARNING: locking.c: _wapi_unlock_file_region(): fcntl() not available on Native Client!\n");
79         return (TRUE);
80 #else
81         struct flock lock_data;
82         int ret;
83
84         lock_data.l_type = F_UNLCK;
85         lock_data.l_whence = SEEK_SET;
86         lock_data.l_start = offset;
87         lock_data.l_len = length;
88         
89         do {
90                 ret = fcntl (fd, F_SETLK, &lock_data);
91         } while(ret == -1 && errno == EINTR);
92         
93         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl returns %d", __func__, ret);
94         
95         if (ret == -1) {
96                 /*
97                  * if locks are not available (NFS for example),
98                  * ignore the error
99                  */
100                 if (errno == ENOLCK
101 #ifdef EOPNOTSUPP
102                     || errno == EOPNOTSUPP
103 #endif
104 #ifdef ENOTSUP
105                     || errno == ENOTSUP
106 #endif
107                    ) {
108                         return (TRUE);
109                 }
110                 
111                 SetLastError (ERROR_LOCK_VIOLATION);
112                 return(FALSE);
113         }
114
115         return(TRUE);
116 #endif /* __native_client__ */
117 }
118
119 gboolean
120 LockFile (gpointer handle, guint32 offset_low, guint32 offset_high,
121           guint32 length_low, guint32 length_high)
122 {
123         struct _WapiHandle_file *file_handle;
124         gboolean ok;
125         off_t offset, length;
126         int fd = GPOINTER_TO_UINT(handle);
127         
128         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
129                                   (gpointer *)&file_handle);
130         if (ok == FALSE) {
131                 g_warning ("%s: error looking up file handle %p", __func__,
132                            handle);
133                 SetLastError (ERROR_INVALID_HANDLE);
134                 return(FALSE);
135         }
136
137         if (!(file_handle->fileaccess & GENERIC_READ) &&
138             !(file_handle->fileaccess & GENERIC_WRITE) &&
139             !(file_handle->fileaccess & GENERIC_ALL)) {
140                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
141                 SetLastError (ERROR_ACCESS_DENIED);
142                 return(FALSE);
143         }
144
145 #ifdef HAVE_LARGE_FILE_SUPPORT
146         offset = ((gint64)offset_high << 32) | offset_low;
147         length = ((gint64)length_high << 32) | length_low;
148
149         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locking handle %p, offset %lld, length %lld", __func__, handle, offset, length);
150 #else
151         if (offset_high > 0 || length_high > 0) {
152                 SetLastError (ERROR_INVALID_PARAMETER);
153                 return (FALSE);
154         }
155         offset = offset_low;
156         length = length_low;
157
158         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locking handle %p, offset %ld, length %ld", __func__,
159                    handle, offset, length);
160 #endif
161
162         return(_wapi_lock_file_region (fd, offset, length));
163 }
164
165 gboolean
166 UnlockFile (gpointer handle, guint32 offset_low,
167             guint32 offset_high, guint32 length_low,
168             guint32 length_high)
169 {
170         struct _WapiHandle_file *file_handle;
171         gboolean ok;
172         off_t offset, length;
173         int fd = GPOINTER_TO_UINT(handle);
174         
175         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
176                                   (gpointer *)&file_handle);
177         if (ok == FALSE) {
178                 g_warning ("%s: error looking up file handle %p", __func__,
179                            handle);
180                 SetLastError (ERROR_INVALID_HANDLE);
181                 return(FALSE);
182         }
183         
184         if (!(file_handle->fileaccess & GENERIC_READ) &&
185             !(file_handle->fileaccess & GENERIC_WRITE) &&
186             !(file_handle->fileaccess & GENERIC_ALL)) {
187                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
188                 SetLastError (ERROR_ACCESS_DENIED);
189                 return(FALSE);
190         }
191
192 #ifdef HAVE_LARGE_FILE_SUPPORT
193         offset = ((gint64)offset_high << 32) | offset_low;
194         length = ((gint64)length_high << 32) | length_low;
195
196         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking handle %p, offset %lld, length %lld", __func__, handle, offset, length);
197 #else
198         offset = offset_low;
199         length = length_low;
200
201         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking handle %p, offset %ld, length %ld", __func__, handle, offset, length);
202 #endif
203
204         return(_wapi_unlock_file_region (fd, offset, length));
205 }