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