Lumiera  0.pre.03
»edityourfreedom«
filedescriptor.c
Go to the documentation of this file.
1 /*
2  FileDescriptor - file handling
3 
4  Copyright (C) Lumiera.org
5  2008, Christian Thaeter <ct@pipapo.org>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
23 
30 #include "include/logging.h"
31 #include "lib/mutex.h"
32 #include "lib/safeclib.h"
33 #include "lib/tmpbuf.h"
34 
35 #include "backend/file.h"
36 #include "backend/filedescriptor.h"
38 #include "backend/filehandle.h"
40 
41 #include <sys/types.h>
42 #include <fcntl.h>
43 #include <limits.h>
44 #include <unistd.h>
45 #include <errno.h>
46 
47 
48 
49 /* lookup and creation of files, initialised in backend.c */
50 
52 
53 
55 lumiera_filedescriptor_acquire (const char* name, int flags, LList filenode)
56 {
57  TRACE (filedescriptor_dbg, "%s", name);
58  REQUIRE (llist_is_empty (filenode));
59 
61 
63  {
64  lumiera_filedescriptor fdesc;
65  fdesc.flags = flags;
66 
67  if (stat (name, &fdesc.stat) != 0)
68  {
69  if (errno == ENOENT && flags&O_CREAT)
70  {
71  errno = 0;
72  char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX);
73  char* slash = dir;
74  while ((slash = strchr (slash+1, '/')))
75  {
76  *slash = '\0';
77  INFO (filedescriptor_dbg, "try creating dir: %s", dir);
78  if (mkdir (dir, 0777) == -1 && errno != EEXIST)
79  {
80  LUMIERA_ERROR_SET_CRITICAL (file, ERRNO, name);
81  goto error;
82  }
83  *slash = '/';
84  }
85  int fd;
86  INFO (filedescriptor_dbg, "try creating file: %s", name);
87  TODO ("create mode from config");
88  fd = creat (name, 0666);
89  if (fd == -1)
90  {
91  LUMIERA_ERROR_SET_CRITICAL (file, ERRNO, name);
92  goto error;
93  }
94  close (fd);
95  if (stat (name, &fdesc.stat) != 0)
96  {
97  /* finally, no luck */
98  LUMIERA_ERROR_SET_CRITICAL (file, ERRNO, name);
99  goto error;
100  }
101  }
102  }
103 
104  /* lookup/create descriptor */
106 
107  if (dest)
108  llist_insert_head (&dest->files, filenode);
109 
110  error:
111  ;
112  }
113 
114  return dest;
115 }
116 
117 
118 
119 
120 void
122 {
123  TRACE (filedescriptor_dbg);
124 
125  if (filenode)
126  LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock)
127  {
128  REQUIRE (llist_is_member (&self->files, filenode));
129  llist_unlink (filenode);
130  }
131 
132  if (llist_is_empty (&self->files))
133  lumiera_filedescriptor_delete (self, name);
134 }
135 
136 
137 int
139 {
140  TRACE (filedescriptor_dbg);
141 
142  int fd = -1;
143 
144  LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock)
145  {
146  if (!self->handle)
147  /* no handle yet, get a new one */
149  else
150  lumiera_filehandlecache_checkout (self->handle);
151 
152  fd = lumiera_filehandle_handle (self->handle);
153  }
154 
155  return fd;
156 }
157 
158 
159 void
161 {
162  TRACE (filedescriptor_dbg);
163  REQUIRE (self->handle);
164 
165  LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock)
166  lumiera_filehandlecache_checkin (self->handle);
167 }
168 
169 
170 const char*
172 {
173  REQUIRE (!llist_is_empty (&self->files));
174 
175  return ((LumieraFile)(llist_head (&self->files)))->name;
176 }
177 
178 
179 int
181 {
182  return self->flags;
183 }
184 
185 
186 int
188 {
189  if (self->stat.st_dev == stat->st_dev && self->stat.st_ino == stat->st_ino)
190  return 1;
191 
192  return 0;
193 }
194 
195 
198 {
199  LumieraFiledescriptor self = lumiera_malloc (sizeof (lumiera_filedescriptor));
200  TRACE (filedescriptor_dbg, "at %p", self);
201 
202  psplaynode_init (&self->node);
203  self->stat = template->stat;
204 
205  self->realsize = template->stat.st_size;
206  self->flags = template->flags;
207  self->handle = NULL;
208  self->mmapings = NULL;
209  llist_init (&self->files);
210 
211  RESOURCE_USER_INIT(self->filelock_rh);
212 
213  lumiera_mutex_init (&self->lock, "filedescriptor", &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT);
214 
215  lumiera_rwlock_init (&self->filelock, "filelock", &NOBUG_FLAG (filedescriptor_dbg), NOBUG_CONTEXT);
216  self->lock_cnt = 0;
217 
218  return self;
219 }
220 
221 
222 void
224 {
225  TRACE (filedescriptor_dbg, "%p %s", self, name);
226 
227  REQUIRE (!self->lock_cnt, "File still locked");
228  REQUIRE (llist_is_empty (&self->files));
229 
231 
232  TODO ("destroy other members (WIP)");
233 
234  lumiera_mmapings_delete (self->mmapings);
235 
236  if (self->handle && name && ((self->flags & O_RDWR) == O_RDWR))
237  {
238  TRACE (filedescriptor_dbg, "truncate %s to %lld", name, (long long)self->realsize);
239  lumiera_filehandlecache_checkout (self->handle);
240  int dummy = ftruncate (lumiera_filehandle_handle (self->handle), self->realsize);
241  (void) dummy; /* this is present to silence a warning */
242  TODO ("handle error case better");
243  lumiera_filehandlecache_checkin (self->handle);
244  TODO ("really release filehandle");
245  }
246 
247  lumiera_rwlock_destroy (&self->filelock, &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT);
248  lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT);
249 
250  lumiera_free (self);
251 }
252 
253 
256 {
257  TRACE (filedescriptor_dbg);
258 
259  if (self)
260  {
261  lumiera_rwlock_rdlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT);
262 
264  int err = 0;
265 
266  LUMIERA_MUTEX_SECTION (mutex_dbg, &self->lock)
267  {
268  if (!self->lock_cnt)
269  {
270 
271  struct flock lock;
272  lock.l_type = F_RDLCK;
273  lock.l_whence = SEEK_SET;
274  lock.l_start = 0;
275  lock.l_len = 0;
276 
277  while ((err = fcntl (fd, F_SETLKW, &lock)) == -1 && errno == EINTR)
278  ;
279 
280  }
281  if (!err)
282  ++self->lock_cnt;
283  }
284 
285  if (err)
286  {
288  lumiera_rwlock_unlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT);
289 
290  LUMIERA_ERROR_SET_WARNING (filedescriptor_dbg, ERRNO, lumiera_filedescriptor_name (self));
291  self = NULL;
292  }
293  }
294 
295  return self;
296 }
297 
298 
299 
302 {
303  TRACE (filedescriptor_dbg);
304 
305  if (self)
306  {
307  lumiera_rwlock_wrlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT);
308 
310  int err = 0;
311 
312  LUMIERA_MUTEX_SECTION(mutex_dbg, &self->lock)
313  {
314 
315  struct flock lock;
316  lock.l_type = F_WRLCK;
317  lock.l_whence = SEEK_SET;
318  lock.l_start = 0;
319  lock.l_len = 0;
320 
321  while ((err = fcntl (fd, F_SETLKW, &lock)) == -1 && errno == EINTR)
322  ;
323 
324  if (!err)
325  self->lock_cnt = -1;
326 
327  }
328 
329  if (err)
330  {
332  lumiera_rwlock_unlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT);
333  LUMIERA_ERROR_SET_WARNING (filedescriptor_dbg, ERRNO, lumiera_filedescriptor_name (self));
334  self = NULL;
335  }
336  }
337 
338  return self;
339 }
340 
341 
344 {
345  TRACE (filedescriptor_dbg);
346 
347  if (self)
348  {
349  int fd = lumiera_filehandle_get (self->handle);
350  REQUIRE (fd >= 0, "was not locked?");
351  int err = 0;
352 
353  LUMIERA_MUTEX_SECTION(mutex_dbg, &self->lock)
354  {
355  if (self->lock_cnt == -1)
356  self->lock_cnt = 0;
357  else
358  --self->lock_cnt;
359 
360  if (!self->lock_cnt)
361  {
362 
363  struct flock lock;
364  lock.l_type = F_UNLCK;
365  lock.l_whence = SEEK_SET;
366  lock.l_start = 0;
367  lock.l_len = 0;
368 
369  while ((err = fcntl (fd, F_SETLK, &lock)) == -1 && errno == EINTR)
370  ;
371  }
372  }
373 
374  if (err)
375  {
376  LUMIERA_ERROR_SET_WARNING (filedescriptor_dbg, ERRNO, lumiera_filedescriptor_name (self));
377  self = NULL;
378  }
379  else
380  {
382  lumiera_rwlock_unlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT);
383  }
384  }
385 
386  return self;
387 }
388 
389 
390 /*
391 // Local Variables:
392 // mode: C
393 // c-file-style: "gnu"
394 // indent-tabs-mode: nil
395 // End:
396 */
void lumiera_filedescriptorregistry_remove(LumieraFiledescriptor self)
Removes a file descriptor from the registry.
Portable and safe wrappers around some C-Lib functions.
LumieraFiledescriptor lumiera_filedescriptorregistry_ensure(LumieraFiledescriptor template)
Ensures that a filedescriptor is in the registry.
#define LUMIERA_ERROR_SET_WARNING(flag, err, extra)
Helper macro to raise an error for the current thread.
Definition: error.h:136
LumieraRWLock lumiera_rwlock_init(LumieraRWLock self, const char *purpose, struct nobug_flag *flag, const struct nobug_context ctx)
Initialize a rwlock.
Definition: rwlock.c:32
char * lumiera_tmpbuf_strndup(const char *src, size_t size)
Duplicate string to a tmpbuf.
Definition: tmpbuf.c:111
lumiera_file * LumieraFile
Definition: file.h:49
File descriptors are the underlying working horse in accessing files.
LumieraFiledescriptor lumiera_filedescriptor_wrlock(LumieraFiledescriptor self)
LumieraFilehandle lumiera_filehandlecache_checkout(LumieraFilehandle handle)
Remove a filehandle from cache aging Filehandles which are subject of cache aging must be checked out...
Registry for used file descriptors.
#define LUMIERA_MUTEX_SECTION(nobugflag, mtx)
Mutual exclusive section.
Definition: mutex.h:41
File management.
#define llist_insert_head(list, element)
Definition: llist.h:105
static int lumiera_filehandle_get(LumieraFilehandle self)
just accessor, no safety net
Definition: filehandle.h:95
This header is for including and configuring NoBug.
void lumiera_mmapings_delete(LumieraMMapings self)
destroy and free mmapings container and all its resources
Definition: mmapings.c:88
Round robin temporary buffers.
static void lumiera_free(void *mem)
Free previously allocated memory.
Definition: safeclib.h:82
int lumiera_filehandle_handle(LumieraFilehandle self)
Definition: filehandle.c:81
void lumiera_filehandlecache_checkin(LumieraFilehandle handle)
Put a filehandle into the cache Filehandles which are checked in are subject of cache aging and might...
lumiera_mutex lumiera_filecreate_mutex
Protect lookup and creation of files.
#define llist_head
Definition: llist.h:107
int lumiera_filedescriptor_flags(LumieraFiledescriptor self)
int lumiera_filedescriptor_handle_acquire(LumieraFiledescriptor self)
static void lumiera_rwlock_unlock(LumieraRWLock self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Definition: rwlock.h:334
LumieraFiledescriptor lumiera_filedescriptor_rdlock(LumieraFiledescriptor self)
return NULL
Definition: llist.h:596
LumieraRWLock lumiera_rwlock_destroy(LumieraRWLock self, struct nobug_flag *flag, const struct nobug_context ctx)
destroy a rwlock
Definition: rwlock.c:50
#define LUMIERA_ERROR_SET_CRITICAL(flag, err, extra)
Helper macro to raise an error for the current thread.
Definition: error.h:121
void lumiera_filedescriptor_delete(LumieraFiledescriptor self, const char *name)
Delete a filedescriptor Called whenever its reference count drops to zero.
Filehandles manage the underlying POSIX filehandle for a file descriptor.
void lumiera_filedescriptor_release(LumieraFiledescriptor self, const char *name, LList filenode)
Release a filedescriptor.
LumieraFiledescriptor lumiera_filedescriptor_unlock(LumieraFiledescriptor self)
LumieraFiledescriptor lumiera_filedescriptor_acquire(const char *name, int flags, LList filenode)
Find existing filedescriptor or create one.
void * lumiera_malloc(size_t size)
Allocate memory.
Definition: safeclib.c:67
Mutual exclusion locking, header.
lumiera_filedescriptor * LumieraFiledescriptor
static LumieraRWLock lumiera_rwlock_wrlock(LumieraRWLock self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Definition: rwlock.h:254
TRACE(test, "inserted %d", data)
int lumiera_filedescriptor_samestat(LumieraFiledescriptor self, struct stat *stat)
void lumiera_filedescriptor_handle_release(LumieraFiledescriptor self)
LumieraFiledescriptor lumiera_filedescriptor_new(LumieraFiledescriptor template)
Allocate a new filedescriptor cloned from a template.
LumieraMutex lumiera_mutex_init(LumieraMutex self, const char *purpose, struct nobug_flag *flag, const struct nobug_context ctx)
Initialise a mutex variable This initialises a &#39;fast&#39; default mutex which must not be locked recursiv...
Definition: mutex.c:30
hard wired safety limits.
LumieraFilehandle lumiera_filehandlecache_handle_acquire(LumieraFiledescriptor desc)
Get a fresh filehandle.
static LumieraRWLock lumiera_rwlock_rdlock(LumieraRWLock self, struct nobug_flag *flag, struct nobug_resource_user **handle, const struct nobug_context ctx)
Definition: rwlock.h:166
const char * lumiera_filedescriptor_name(LumieraFiledescriptor self)
Caching and management of filehandles.
PSplaynode psplaynode_init(PSplaynode self)
Initialise a splay tree node The user has to place this nodes within his datastructure and must Initi...
Definition: psplay.c:131
LumieraMutex lumiera_mutex_destroy(LumieraMutex self, struct nobug_flag *flag, const struct nobug_context ctx)
Destroy a mutex variable.
Definition: mutex.c:48
llist * LList
Definition: llist.h:91