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