00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "lib/mutex.h"
00023 #include "lib/safeclib.h"
00024
00025 #include "backend/file.h"
00026 #include "backend/filedescriptor.h"
00027 #include "backend/filehandle.h"
00028 #include "backend/filehandlecache.h"
00029
00030 #include <sys/types.h>
00031 #include <fcntl.h>
00032 #include <limits.h>
00033 #include <unistd.h>
00034 #include <errno.h>
00035
00036
00037 NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
00038
00039
00040
00041
00042
00043
00044 static PSplay registry = NULL;
00045 static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER};
00046
00047
00048 static int
00049 cmp_fn (const void* keya, const void* keyb)
00050 {
00051 const LumieraFiledescriptor a = (const LumieraFiledescriptor)keya;
00052 const LumieraFiledescriptor b = (const LumieraFiledescriptor)keyb;
00053
00054 if (a->stat.st_dev < b->stat.st_dev)
00055 return -1;
00056 else if (a->stat.st_dev > b->stat.st_dev)
00057 return 1;
00058
00059 if (a->stat.st_ino < b->stat.st_ino)
00060 return -1;
00061 else if (a->stat.st_ino > b->stat.st_ino)
00062 return 1;
00063
00064 if ((a->flags&LUMIERA_FILE_MASK) < (b->flags&LUMIERA_FILE_MASK))
00065 return -1;
00066 else if ((a->flags&LUMIERA_FILE_MASK) > (b->flags&LUMIERA_FILE_MASK))
00067 return 1;
00068
00069 return 0;
00070 }
00071
00072
00073 static void
00074 delete_fn (PSplaynode node)
00075 {
00076 lumiera_filedescriptor_delete ((LumieraFiledescriptor) node);
00077 }
00078
00079
00080 static const void*
00081 key_fn (const PSplaynode node)
00082 {
00083 return node;
00084 }
00085
00086
00087
00088 void
00089 lumiera_filedescriptor_registry_init (void)
00090 {
00091 NOBUG_INIT_FLAG (filedescriptor);
00092 TRACE (filedescriptor);
00093 REQUIRE (!registry);
00094
00095 registry = psplay_new (cmp_fn, key_fn, delete_fn);
00096 if (!registry)
00097 LUMIERA_DIE (NO_MEMORY);
00098
00099 TODO ("LumieraMutex lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);");
00100
00101
00102 RESOURCE_ANNOUNCE (filedescriptor, "mutex", "filedescriptor registry", ®istry, registry_mutex.rh);
00103 }
00104
00105 void
00106 lumiera_filedescriptor_registry_destroy (void)
00107 {
00108 TRACE (filedescriptor);
00109 REQUIRE (!psplay_nelements (registry));
00110
00111 RESOURCE_FORGET (filedescriptor, registry_mutex.rh);
00112
00113 TODO ("LumieraMutex lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag);");
00114
00115 if (registry)
00116 psplay_destroy (registry);
00117 registry = NULL;
00118 }
00119
00120
00121 LumieraFiledescriptor
00122 lumiera_filedescriptor_acquire (const char* name, int flags)
00123 {
00124 TRACE (filedescriptor, "%s", name);
00125 REQUIRE (registry, "not initialized");
00126
00127 LumieraFiledescriptor dest = NULL;
00128
00129 LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex)
00130 {
00131 lumiera_filedescriptor fdesc;
00132 fdesc.flags = flags;
00133
00134 if (stat (name, &fdesc.stat) != 0)
00135 {
00136 if (errno == ENOENT && flags&O_CREAT)
00137 {
00138 char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX);
00139 char* slash = dir;
00140 while ((slash = strchr (slash+1, '/')))
00141 {
00142 *slash = '\0';
00143 INFO (filedescriptor, "try creating dir: %s", dir);
00144 if (mkdir (dir, 0777) == -1 && errno != EEXIST)
00145 {
00146 LUMIERA_ERROR_SET (filedescriptor, ERRNO);
00147 goto error;
00148 }
00149 *slash = '/';
00150 }
00151 int fd;
00152 INFO (filedescriptor, "try creating file: %s", name);
00153 fd = creat (name, 0777);
00154 if (fd == -1)
00155 {
00156 LUMIERA_ERROR_SET (filedescriptor, ERRNO);
00157 goto error;
00158 }
00159 close (fd);
00160 if (stat (name, &fdesc.stat) != 0)
00161 {
00162
00163 LUMIERA_ERROR_SET (filedescriptor, ERRNO);
00164 goto error;
00165 }
00166 }
00167 }
00168
00169
00170 dest = (LumieraFiledescriptor) psplay_find (registry, &fdesc, 100);
00171
00172 if (!dest)
00173 {
00174 TRACE (filedescriptor, "Descriptor not found");
00175
00176 dest = lumiera_filedescriptor_new (&fdesc);
00177 if (!dest)
00178 goto error;
00179
00180 psplay_insert (registry, &dest->node, 100);
00181 }
00182 else
00183 {
00184 TRACE (filedescriptor, "Descriptor already existing");
00185 ++dest->refcount;
00186 }
00187 error: ;
00188 }
00189
00190 return dest;
00191 }
00192
00193
00194 void
00195 lumiera_filedescriptor_release (LumieraFiledescriptor self)
00196 {
00197 TRACE (filedescriptor, "%p", self);
00198 if (!--self->refcount)
00199 lumiera_filedescriptor_delete (self);
00200 }
00201
00202
00203 LumieraFiledescriptor
00204 lumiera_filedescriptor_new (LumieraFiledescriptor template)
00205 {
00206 LumieraFiledescriptor self = lumiera_malloc (sizeof (lumiera_filedescriptor));
00207 TRACE (filedescriptor, "at %p", self);
00208
00209 psplaynode_init (&self->node);
00210 self->stat = template->stat;
00211
00212 self->flags = template->flags;
00213 self->refcount = 1;
00214 self->handle = 0;
00215
00216 lumiera_mutex_init (&self->lock, "filedescriptor", &NOBUG_FLAG (filedescriptor));
00217
00218 return self;
00219 }
00220
00221
00222 void
00223 lumiera_filedescriptor_delete (LumieraFiledescriptor self)
00224 {
00225 TRACE (filedescriptor, "%p", self);
00226
00227 LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex)
00228 {
00229 REQUIRE (self->refcount == 0);
00230
00231 psplay_remove (registry, &self->node);
00232
00233 TODO ("destruct other members (WIP)");
00234
00235
00236 TODO ("release filehandle");
00237
00238 lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (filedescriptor));
00239 lumiera_free (self);
00240 }
00241 }