1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 
11 #ifndef BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP
12 #define BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP
13 
14 #ifndef BOOST_CONFIG_HPP
15 #  include <boost/config.hpp>
16 #endif
17 #
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
19 #pragma once
20 #endif
21 
22 #include <boost/interprocess/detail/config_begin.hpp>
23 #include <boost/interprocess/detail/workaround.hpp>
24 
25 #include <sstream>
26 #include <string>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <errno.h>
30 #include <cstddef>
31 #include <boost/interprocess/detail/os_file_functions.hpp>
32 
33 #include <boost/interprocess/detail/shared_dir_helpers.hpp>
34 
35 #if defined(BOOST_INTERPROCESS_WINDOWS)
36 
37 #include <fcntl.h>
38 #include <io.h>
39 #include <sys/locking.h>
40 
41 #else //defined(BOOST_INTERPROCESS_WINDOWS)
42 
43 #include <fcntl.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 
47 #endif   //defined(BOOST_INTERPROCESS_WINDOWS)
48 
49 namespace boost{
50 namespace interprocess{
51 namespace ipcdetail{
52 
53 #if defined(BOOST_INTERPROCESS_WINDOWS)
54 
55 struct locking_file_serial_id
56 {
57    int fd;
58    unsigned long dwVolumeSerialNumber;
59    unsigned long nFileIndexHigh;
60    unsigned long nFileIndexLow;
61    //This reference count counts the number of modules attached
62    //to the shared memory and lock file. This serves to unlink
63    //the locking file and shared memory when all modules are
64    //done with the global memory (shared memory)
65    volatile boost::uint32_t modules_attached_to_gmem_count;
66 };
67 
lock_locking_file(int fd)68 inline bool lock_locking_file(int fd)
69 {
70    int ret = 0;
71    while(ret != 0 && errno == EDEADLK){
72       ret = _locking(fd, _LK_LOCK, 1/*lock_file_contents_length()*/);
73    }
74    return 0 == ret;
75 }
76 
try_lock_locking_file(int fd)77 inline bool try_lock_locking_file(int fd)
78 {
79    return 0 == _locking(fd, _LK_NBLCK , 1);
80 }
81 
open_or_create_and_lock_file(const char * name)82 inline int open_or_create_and_lock_file(const char *name)
83 {
84    permissions p;
85    p.set_unrestricted();
86    while(1){
87       file_handle_t handle = create_or_open_file(name, read_write, p);
88       int fd = _open_osfhandle((intptr_t)handle, _O_TEXT);
89       if(fd < 0){
90          close_file(handle);
91          return fd;
92       }
93       if(!try_lock_locking_file(fd)){
94          _close(fd);
95          return -1;
96       }
97       struct _stat s;
98       if(0 == _stat(name, &s)){
99          return fd;
100       }
101       else{
102          _close(fd);
103       }
104    }
105 }
106 
try_open_and_lock_file(const char * name)107 inline int try_open_and_lock_file(const char *name)
108 {
109    file_handle_t handle = open_existing_file(name, read_write);
110    int fd = _open_osfhandle((intptr_t)handle, _O_TEXT);
111    if(fd < 0){
112       close_file(handle);
113       return fd;
114    }
115    if(!try_lock_locking_file(fd)){
116       _close(fd);
117       return -1;
118    }
119    return fd;
120 }
121 
close_lock_file(int fd)122 inline void close_lock_file(int fd)
123 {  _close(fd); }
124 
is_valid_fd(int fd)125 inline bool is_valid_fd(int fd)
126 {
127    struct _stat s;
128    return EBADF != _fstat(fd, &s);
129 }
130 
is_normal_file(int fd)131 inline bool is_normal_file(int fd)
132 {
133    if(_isatty(fd))
134       return false;
135    struct _stat s;
136    if(0 != _fstat(fd, &s))
137       return false;
138    return 0 != (s.st_mode & _S_IFREG);
139 }
140 
get_size(int fd)141 inline std::size_t get_size(int fd)
142 {
143    struct _stat s;
144    if(0 != _fstat(fd, &s))
145       return 0u;
146    return (std::size_t)s.st_size;
147 }
148 
fill_file_serial_id(int fd,locking_file_serial_id & id)149 inline bool fill_file_serial_id(int fd, locking_file_serial_id &id)
150 {
151    winapi::interprocess_by_handle_file_information info;
152    if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info))
153       return false;
154    id.fd = fd;
155    id.dwVolumeSerialNumber = info.dwVolumeSerialNumber;
156    id.nFileIndexHigh = info.nFileIndexHigh;
157    id.nFileIndexLow = info.nFileIndexLow;
158    id.modules_attached_to_gmem_count = 1; //Initialize attached count
159    return true;
160 }
161 
compare_file_serial(int fd,const locking_file_serial_id & id)162 inline bool compare_file_serial(int fd, const locking_file_serial_id &id)
163 {
164    winapi::interprocess_by_handle_file_information info;
165    if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info))
166       return false;
167 
168    return   id.dwVolumeSerialNumber == info.dwVolumeSerialNumber  &&
169             id.nFileIndexHigh       == info.nFileIndexHigh        &&
170             id.nFileIndexLow        == info.nFileIndexLow;
171 }
172 
173 #else //UNIX
174 
175 struct locking_file_serial_id
176 {
177    int fd;
178    dev_t st_dev;
179    ino_t st_ino;
180    //This reference count counts the number of modules attached
181    //to the shared memory and lock file. This serves to unlink
182    //the locking file and shared memory when all modules are
183    //done with the global memory (shared memory)
184    volatile boost::uint32_t modules_attached_to_gmem_count;
185 };
186 
187 inline bool lock_locking_file(int fd)
188 {
189    int ret = 0;
190    while(ret != 0 && errno != EINTR){
191       struct flock lock;
192       lock.l_type = F_WRLCK;
193       lock.l_whence = SEEK_SET;
194       lock.l_start = 0;
195       lock.l_len = 1;
196       ret = fcntl (fd, F_SETLKW, &lock);
197    }
198    return 0 == ret;
199 }
200 
201 inline bool try_lock_locking_file(int fd)
202 {
203    struct flock lock;
204    lock.l_type = F_WRLCK;
205    lock.l_whence = SEEK_SET;
206    lock.l_start = 0;
207    lock.l_len = 1;
208    return 0 == fcntl (fd, F_SETLK, &lock);
209 }
210 
211 inline int open_or_create_and_lock_file(const char *name)
212 {
213    permissions p;
214    p.set_unrestricted();
215    while(1){
216       int fd = create_or_open_file(name, read_write, p);
217       if(fd < 0){
218          return fd;
219       }
220       if(!try_lock_locking_file(fd)){
221          close(fd);
222          return -1;
223       }
224       struct stat s;
225       if(0 == stat(name, &s)){
226          return fd;
227       }
228       else{
229          close(fd);
230       }
231    }
232 }
233 
234 inline int try_open_and_lock_file(const char *name)
235 {
236    int fd = open_existing_file(name, read_write);
237    if(fd < 0){
238       return fd;
239    }
240    if(!try_lock_locking_file(fd)){
241       close(fd);
242       return -1;
243    }
244    return fd;
245 }
246 
247 inline void close_lock_file(int fd)
248 {  close(fd); }
249 
250 inline bool is_valid_fd(int fd)
251 {
252    struct stat s;
253    return EBADF != fstat(fd, &s);
254 }
255 
256 inline bool is_normal_file(int fd)
257 {
258    struct stat s;
259    if(0 != fstat(fd, &s))
260       return false;
261    return 0 != (s.st_mode & S_IFREG);
262 }
263 
264 inline std::size_t get_size(int fd)
265 {
266    struct stat s;
267    if(0 != fstat(fd, &s))
268       return 0u;
269    return (std::size_t)s.st_size;
270 }
271 
272 inline bool fill_file_serial_id(int fd, locking_file_serial_id &id)
273 {
274    struct stat s;
275    if(0 != fstat(fd, &s))
276       return false;
277    id.fd = fd;
278    id.st_dev = s.st_dev;
279    id.st_ino = s.st_ino;
280    id.modules_attached_to_gmem_count = 1; //Initialize attached count
281    return true;
282 }
283 
284 inline bool compare_file_serial(int fd, const locking_file_serial_id &id)
285 {
286    struct stat info;
287    if(0 != fstat(fd, &info))
288       return false;
289 
290    return   id.st_dev == info.st_dev  &&
291             id.st_ino == info.st_ino;
292 }
293 
294 #endif
295 
296 }  //namespace ipcdetail{
297 }  //namespace interprocess{
298 }  //namespace boost{
299 
300 #include <boost/interprocess/detail/config_end.hpp>
301 
302 #endif   //BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP
303