MySensors Library & Examples  2.3.2-62-ge298769
FileLockFunctions.h
1 #include <sys/stat.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 
6 #ifdef _WIN32
7 #define W_OK 02
8 #define R_OK 04
9 #define X_OK 04
10 #include <direct.h>
11 #include <windows.h>
12 #include <io.h>
13 #include <sys/locking.h>
14 #define access _access
15 #define lseek _lseek
16 #define locking _locking
17 #define open _open
18 #define write _write
19 #define read _read
20 #define close _close
21 #else
22 #include <sys/vfs.h>
23 #include <sys/procfs.h>
24 #endif
25 
26 
27 //-----------------------------------------------------------------------------
28 int CheckIfDir(const char *name)
29 //-----------------------------------------------------------------------------
30 /* testing if name is a directory */
31 {
32  struct stat s_buf;
33  return ((stat(name, &s_buf) != -1) && ((s_buf.st_mode & S_IFMT) == S_IFDIR));
34 }
35 
36 
37 //-----------------------------------------------------------------------------
38 int CheckIfFile(const char *name)
39 //-----------------------------------------------------------------------------
40 /* testing if name is a file */
41 {
42  struct stat s_buf;
43  return ((stat(name, &s_buf) != -1) && ((s_buf.st_mode & S_IFMT) == S_IFREG));
44 }
45 
46 
47 //-----------------------------------------------------------------------------
48 int CheckForWrite(const char *filepath)
49 //-----------------------------------------------------------------------------
50 /* test if a file or directory is writable for current user */
51 {
52  struct stat s_buf;
53  return ((stat(filepath, &s_buf) != -1) && s_buf.st_mode && (access(filepath, W_OK) != -1));
54 }
55 
56 
57 //-----------------------------------------------------------------------------
58 int CheckForRead(const char *filepath)
59 //-----------------------------------------------------------------------------
60 /* testing if a file or directory is readable for current user */
61 {
62  struct stat s_buf;
63  return ((stat(filepath, &s_buf) != -1) && s_buf.st_mode && (access(filepath, R_OK) != -1));
64 }
65 
66 
67 //-----------------------------------------------------------------------------
68 int CheckForExe(const char *filepath)
69 //-----------------------------------------------------------------------------
70 /* testing if a file or directory is readable for current user */
71 {
72  struct stat s_buf;
73  return ((stat(filepath, &s_buf) != -1) && s_buf.st_mode && (access(filepath, X_OK) != -1));
74 }
75 
76 
77 //-----------------------------------------------------------------------------
78 int GetFileSize(const char *filepath)
79 //-----------------------------------------------------------------------------
80 /* testing if a file or directory and return the actual size of the file */
81 {
82  struct stat s_buf;
83 
84  if ( stat( filepath, &s_buf) == -1) {
85  return (-1);
86  } else {
87  return (s_buf.st_size);
88  }
89 }
90 
91 
92 // Returns 1 if the section is locked, 0 otherwise. If an error occurs, the
93 // return value will indicate that the section is locked, to avoid possible
94 // access collisions or file corruptions.
95 // NOTE: This function will return 1 if it is not possible to get the requested
96 // lock because of an already existing lock. If bExclusive is 1 then this is
97 // straight-forward: a return value of 0 means that no locks are present.
98 //-----------------------------------------------------------------------------
99 int IsFileSectionLocked(const int iFileNo, // the fileno
100  const int nPosition, // start position
101  const int nSize, // size of section to test
102  const int bExclusive) // write or read lock
103 //-----------------------------------------------------------------------------
104 {
105 #ifdef _WIN32
106  if (nPosition>=0) {
107  lseek(iFileNo, nPosition, SEEK_SET);
108  }
109  if (locking(iFileNo, LK_NBLCK, nSize)!=0) {
110  return(1);
111  }
112  locking(iFileNo, LK_UNLCK, nSize);
113  return(0);
114 #else
115  struct flock fl;
116  fl.l_whence = 0;
117  fl.l_start = nPosition;
118  fl.l_len = nSize;
119  fl.l_pid = 0;
120  int fno = iFileNo;
121  if (fno==-1) {
122  return(1);
123  }
124 
125  fl.l_type = bExclusive ? F_WRLCK : F_RDLCK;
126 
127  if (fcntl(fno, F_GETLK, &fl)!=0) {
128  printf("IsFileSectionLocked: fcntl(F_GETLK,...) failed "
129  "with error %d (%s)\n", errno, strerror(errno));
130  return(1);
131  }
132  return (fl.l_type != F_UNLCK);
133 #endif
134 }
135 
136 
137 //-----------------------------------------------------------------------------
138 int LockFileSection(const int iFileNo, // the fileno
139  const int nPosition, // start position
140  const int nSize, // size of section to lock
141  const int bLock, // 1=lock, 0=unlock
142  const int bExclusive, // write or read lock
143  const int bNonBlocking) // blocking or non-blocking
144 //-----------------------------------------------------------------------------
145 {
146 #ifdef _WIN32
147  // set position
148  if (nPosition>=0) {
149  lseek(iFileNo, nPosition, SEEK_SET);
150  }
151 
152  // get the windows file handle
153  HANDLE hFile = (void *) _get_osfhandle(iFileNo);
154  if (hFile == INVALID_HANDLE_VALUE) {
155  printf("LockFileSection: get_ofshandle failed for file %d\n", iFileNo);
156  return(0);
157  }
158 
159  // lock or unlock
160  struct _OVERLAPPED ol;
161  ol.Offset = nPosition;
162  ol.OffsetHigh = 0;
163  ol.hEvent = 0;
164  int bOK = 1;
165  if (bLock) {
166  // blocking or non-blocking?
167  int nMode = LOCKFILE_EXCLUSIVE_LOCK;
168  if (bNonBlocking) {
169  nMode |= LOCKFILE_FAIL_IMMEDIATELY;
170  }
171 
172  // Try to lock, repeat until success, an unexpected error,
173  // or exceeding the max time.
174  int nRetries = 0, nMaxRetries = 0, iLastErr = 0;
175  if (!bNonBlocking) {
176  nMaxRetries = 1000000000;
177  }
178  do {
179  bOK = LockFileEx(hFile, nMode, 0, nSize, 0, &ol);
180  if (!bOK) {
181  iLastErr = GetLastError();
182  }
183  if (iLastErr!=ERROR_LOCK_VIOLATION) {
184  break;
185  }
186  Sleep(100);
187  } while (!bOK && (nMaxRetries>nRetries++));
188  } else {
189  // unlock
190  bOK = UnlockFileEx(hFile, 0, nSize, 0, &ol);
191  }
192 
193  // log error if any
194  if (!bOK) {
195  DWORD iLastErr = GetLastError();
196  LPVOID lpMsgBuf;
197  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
198  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
199  NULL, iLastErr,
200  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
201  (LPTSTR) &lpMsgBuf, 0, NULL);
202  printf("%s of file %d returned error %d (%s)\n",
203  (const char *)(bLock ? "Locking" : "Unlocking"),
204  iFileNo, iLastErr, (const char*)(LPCTSTR) lpMsgBuf);
205  LocalFree(lpMsgBuf);
206  return(0);
207  }
208  return(1);
209 #else
210  struct flock fl;
211  fl.l_whence = 0;
212  fl.l_start = nPosition;
213  fl.l_len = nSize<0 ? 0 : nSize;
214  fl.l_pid = 0;
215  int fno = iFileNo;
216  if (fno==-1) {
217  return(0);
218  }
219 
220  // Now take care to use the lock type specified. If we are trying to
221  // get a write lock on a file opened for reading only, this will result
222  // in a 'Bad file number' error (errno 9) on some Unix platforms.
223  fl.l_type = bExclusive ? F_WRLCK : F_RDLCK;
224  int retval = 0;
225  if (bLock) {
226  if (bNonBlocking) { // non-blocking
227  retval = (fcntl(fno, F_SETLK, &fl)==0);
228  } else { // blocking
229  retval = (fcntl(fno, F_SETLKW, &fl)==0);
230  if (!retval) {
231  if (errno == EAGAIN) {
232  printf("LockFileSection: "
233  "Lock is being held by process %d\n", fl.l_pid);
234  } else {
235  printf("Lock of file %d (proc=%d) returned error %d (%s)\n",
236  fno, fl.l_pid, errno, strerror(errno));
237  }
238  }
239  }
240  } else {
241  fl.l_type = F_UNLCK;
242  retval = (fcntl(fno, F_SETLKW, &fl)==0);
243  if (retval==0) {
244  printf("LockFileSection: Unlock failed with error %d (%s)\n", errno, strerror(errno));
245  }
246  }
247  return(retval);
248 #endif
249 }
250 
251 
252 #ifdef _WIN32
253 #undef W_OK
254 #undef R_OK
255 #undef X_OK
256 #endif
257