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