ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/gnome-vfs2-2.3.8-1.src.rpm
[gnome-vfs-httpcaptive.git] / monikers / bonobo-storage-fs.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * bonobo-storage-fs.c: Sample file-system based Storage implementation
4  *
5  * This is just a sample file-system based Storage implementation.
6  * it is only used for debugging purposes
7  *
8  * Authors:
9  *   Miguel de Icaza (miguel@gnu.org)
10  *   Michael Meeks   (michael@ximian.com)
11  *
12  * Copyright 2001, Ximian, Inc
13  */
14
15 #include <config.h>
16 #include "bonobo-storage-fs.h"
17
18 #include <stdio.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <string.h>
25
26 #include <libgnomevfs/gnome-vfs-mime.h>
27 #include <bonobo/bonobo-storage.h>
28
29 #include "bonobo-stream-fs.h"
30
31 static char *
32 concat_dir_and_file (const char *dir, const char *file)
33 {
34         g_return_val_if_fail (dir != NULL, NULL);
35         g_return_val_if_fail (file != NULL, NULL);
36
37         /* If the directory name doesn't have a / on the end, we need
38            to add one so we get a proper path to the file */
39         if (dir[0] != '\0' && dir [strlen(dir) - 1] != '/')
40                 return g_strconcat (dir, "/", file, NULL);
41         else
42                 return g_strconcat (dir, file, NULL);
43 }
44
45 static BonoboObjectClass *bonobo_storage_fs_parent_class;
46
47 static void
48 bonobo_storage_fs_finalize (GObject *object)
49 {
50         BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (object);
51
52         g_free (storage_fs->path);
53         storage_fs->path = NULL;
54
55         G_OBJECT_CLASS (bonobo_storage_fs_parent_class)->finalize (object);
56 }
57
58 static Bonobo_StorageInfo*
59 fs_get_info (PortableServer_Servant storage,
60              const CORBA_char *path,
61              const Bonobo_StorageInfoFields mask,
62              CORBA_Environment *ev)
63 {
64         BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (
65                 bonobo_object (storage));
66         Bonobo_StorageInfo *si;
67         struct stat st;
68         char *full = NULL;
69         gboolean dangling = FALSE;
70
71         if (mask & ~(Bonobo_FIELD_CONTENT_TYPE | Bonobo_FIELD_SIZE |
72                      Bonobo_FIELD_TYPE)) {
73                 CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
74                                      ex_Bonobo_Storage_NotSupported, NULL);
75                 return CORBA_OBJECT_NIL;
76         }
77
78         full = concat_dir_and_file (storage_fs->path, path);
79         if (stat (full, &st) == -1) {
80                 if (lstat (full, &st) == -1)
81                         goto get_info_except;
82                 else
83                         dangling = TRUE;
84         }
85
86         si = Bonobo_StorageInfo__alloc ();
87         
88         si->size = st.st_size;
89         si->name = CORBA_string_dup (path);
90
91         if (S_ISDIR (st.st_mode)) {
92                 si->type = Bonobo_STORAGE_TYPE_DIRECTORY;
93                 si->content_type = CORBA_string_dup ("x-directory/normal");
94         } else {
95                 si->type = Bonobo_STORAGE_TYPE_REGULAR;
96                 if (dangling)
97                         si->content_type =
98                                 CORBA_string_dup ("x-symlink/dangling");
99                 else
100                         si->content_type = 
101                                 CORBA_string_dup (
102                                         gnome_vfs_mime_type_from_name (full));
103         }
104
105         g_free (full);
106
107         return si;
108
109  get_info_except:
110
111         if (full)
112                 g_free (full);
113         
114         if (errno == EACCES) 
115                 CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
116                                      ex_Bonobo_Storage_NoPermission, 
117                                      NULL);
118         else if (errno == ENOENT) 
119                 CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
120                                      ex_Bonobo_Storage_NotFound, 
121                                      NULL);
122         else 
123                 CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
124                                      ex_Bonobo_Storage_IOError, NULL);
125         
126         return CORBA_OBJECT_NIL;
127 }
128
129 static void
130 fs_set_info (PortableServer_Servant         storage,
131              const CORBA_char              *path,
132              const Bonobo_StorageInfo      *info,
133              const Bonobo_StorageInfoFields mask,
134              CORBA_Environment             *ev)
135 {
136         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
137                              ex_Bonobo_Storage_NotSupported, 
138                              NULL);
139 }
140
141 static Bonobo_Stream
142 fs_open_stream (PortableServer_Servant  storage, 
143                 const CORBA_char       *path, 
144                 Bonobo_Storage_OpenMode mode, 
145                 CORBA_Environment      *ev)
146 {
147         BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (
148                 bonobo_object (storage));
149         BonoboObject *stream;
150         char *full;
151
152         full = concat_dir_and_file (storage_fs->path, path);
153         stream = BONOBO_OBJECT (
154                 bonobo_stream_fs_open (full, mode, 0644, ev));
155         g_free (full);
156
157         return CORBA_Object_duplicate (
158                 BONOBO_OBJREF (stream), ev);
159 }
160
161 static Bonobo_Storage
162 fs_open_storage (PortableServer_Servant  storage,
163                  const CORBA_char       *path, 
164                  Bonobo_Storage_OpenMode mode,
165                  CORBA_Environment      *ev)
166 {
167         BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (
168                 bonobo_object (storage));
169         BonoboObject *new_storage;
170         char *full;
171
172         full = concat_dir_and_file (storage_fs->path, path);
173         new_storage = BONOBO_OBJECT (
174                 bonobo_storage_fs_open (full, mode, 0644, ev));
175         g_free (full);
176
177         return CORBA_Object_duplicate (
178                 BONOBO_OBJREF (new_storage), ev);
179 }
180
181 static void
182 fs_copy_to (PortableServer_Servant storage,
183             Bonobo_Storage         dest,
184             CORBA_Environment     *ev)
185 {
186         BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (
187                 bonobo_object (storage));
188
189         bonobo_storage_copy_to (
190                 BONOBO_OBJREF (storage_fs), dest, ev);
191 }
192
193 static void
194 fs_rename (PortableServer_Servant storage,
195            const CORBA_char      *path, 
196            const CORBA_char      *new_path,
197            CORBA_Environment     *ev)
198 {
199         BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (
200                 bonobo_object (storage));
201         char *full_old, *full_new;
202
203         full_old = concat_dir_and_file (storage_fs->path, path);
204         full_new = concat_dir_and_file (storage_fs->path, new_path);
205
206         if (rename (full_old, full_new) == -1) {
207
208                 if ((errno == EACCES) || (errno == EPERM) || (errno == EROFS)) 
209                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
210                                              ex_Bonobo_Storage_NoPermission, 
211                                              NULL);
212                 else if (errno == ENOENT) 
213                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
214                                              ex_Bonobo_Storage_NotFound, 
215                                              NULL);
216                 else if ((errno == EEXIST) || (errno == ENOTEMPTY)) 
217                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
218                                              ex_Bonobo_Storage_NameExists, 
219                                              NULL);
220                 else 
221                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
222                                              ex_Bonobo_Storage_IOError, 
223                                              NULL);
224         }
225
226         g_free (full_old);
227         g_free (full_new);
228 }
229
230 static void
231 fs_commit (PortableServer_Servant storage,
232            CORBA_Environment     *ev)
233 {
234         CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
235                              ex_Bonobo_Stream_NotSupported, NULL);
236 }
237
238 static void
239 fs_revert (PortableServer_Servant storage,
240            CORBA_Environment     *ev)
241 {
242         CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
243                              ex_Bonobo_Stream_NotSupported, NULL);
244 }
245
246 static Bonobo_Storage_DirectoryList *
247 fs_list_contents (PortableServer_Servant   storage,
248                   const CORBA_char        *path, 
249                   Bonobo_StorageInfoFields mask,
250                   CORBA_Environment       *ev)
251 {
252         BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (
253                 bonobo_object (storage));
254         Bonobo_Storage_DirectoryList *list = NULL;
255         Bonobo_StorageInfo *buf;
256         struct dirent *de;
257         struct stat st;
258         DIR *dir = NULL;
259         gint i, max, v, num_entries = 0;
260         gchar *full = NULL;
261
262         if (mask & ~(Bonobo_FIELD_CONTENT_TYPE | Bonobo_FIELD_SIZE |
263                      Bonobo_FIELD_TYPE)) {
264                 CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
265                                      ex_Bonobo_Storage_NotSupported, NULL);
266                 return CORBA_OBJECT_NIL;
267         }
268
269         if (!(dir = opendir (storage_fs->path)))
270                         goto list_contents_except;
271         
272         for (max = 0; readdir (dir); max++)
273                 /* do nothing */;
274
275         rewinddir (dir);
276
277         buf = CORBA_sequence_Bonobo_StorageInfo_allocbuf (max);
278         list = Bonobo_Storage_DirectoryList__alloc();
279         list->_buffer = buf;
280         CORBA_sequence_set_release (list, TRUE); 
281         
282         for (i = 0; (de = readdir (dir)) && (i < max); i++) {
283                 
284                 if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
285                     (de->d_name[0] == '.' && de->d_name[1] == '.' 
286                      && de->d_name[2] == '\0')) {
287                         i--;
288                         continue; /* Ignore . and .. */
289                 }
290
291                 buf [i].name = CORBA_string_dup (de->d_name);
292                 buf [i].size = 0;
293                 buf [i].content_type = NULL;
294
295                 full = concat_dir_and_file (storage_fs->path, de->d_name);
296                 v = stat (full, &st);
297
298                 if (v == -1) {
299                         /*
300                          * The stat failed -- two common cases are where
301                          * the file was removed between the call to readdir
302                          * and the iteration, and where the file is a dangling
303                          * symlink.
304                          */
305                         if (errno == ENOENT || errno == ELOOP) {
306                                 v = lstat (full, &st);
307                                 if (v == 0) {
308                                         /* FIXME - x-symlink/dangling is odd */
309                                         buf [i].size = st.st_size;
310                                         buf [i].type = Bonobo_STORAGE_TYPE_REGULAR;
311                                         buf [i].content_type =
312                                                 CORBA_string_dup ("x-symlink/dangling");
313                                         g_free (full);
314                                         num_entries++;
315                                         continue;
316                                 }
317                         }
318
319                         /* Unless it's something grave, just skip the file */
320                         if (errno != ENOMEM && errno != EFAULT && errno != ENOTDIR) {
321                                 i--;
322                                 g_free (full);
323                                 continue;
324                         }
325
326                         goto list_contents_except;
327                 }
328
329                 buf [i].size = st.st_size;
330         
331                 if (S_ISDIR (st.st_mode)) { 
332                         buf [i].type = Bonobo_STORAGE_TYPE_DIRECTORY;
333                         buf [i].content_type = 
334                                 CORBA_string_dup ("x-directory/normal");
335                 } else { 
336                         buf [i].type = Bonobo_STORAGE_TYPE_REGULAR;
337                         buf [i].content_type = 
338                                 CORBA_string_dup (
339                                         gnome_vfs_mime_type_from_name (full));
340                 }
341
342                 g_free (full);
343
344                 num_entries++;
345         }
346
347         list->_length = num_entries; 
348
349         closedir (dir);
350         
351         return list; 
352
353  list_contents_except:
354
355         if (dir)
356                 closedir (dir);
357
358         if (list) 
359                 CORBA_free (list);
360
361         if (full)
362                 g_free (full);
363         
364         if (errno == ENOENT) 
365                 CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
366                                      ex_Bonobo_Storage_NotFound, 
367                                      NULL);
368         else if (errno == ENOTDIR) 
369                 CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
370                                      ex_Bonobo_Storage_NotStorage, 
371                                      NULL);
372         else 
373                 CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
374                                      ex_Bonobo_Storage_IOError, NULL);
375         
376         return CORBA_OBJECT_NIL;
377 }
378
379 static void
380 fs_erase (PortableServer_Servant storage,
381           const CORBA_char      *path,
382           CORBA_Environment     *ev)
383 {
384         BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (
385                 bonobo_object (storage));
386         char *full;
387
388         full = concat_dir_and_file (storage_fs->path, path);
389
390         if (remove (full) == -1) {
391
392                 if (errno == ENOENT) 
393                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
394                                              ex_Bonobo_Storage_NotFound, 
395                                              NULL);
396                 else if (errno == ENOTEMPTY || errno == EEXIST)
397                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
398                                              ex_Bonobo_Storage_NotEmpty, 
399                                              NULL);
400                 else if (errno == EACCES || errno == EPERM)
401                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
402                                              ex_Bonobo_Storage_NoPermission, 
403                                              NULL);
404                 else 
405                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
406                                              ex_Bonobo_Storage_IOError, NULL);
407         }
408
409         g_free (full);
410 }
411
412 static void
413 bonobo_storage_fs_class_init (BonoboStorageFSClass *klass)
414 {
415         GObjectClass *object_class = (GObjectClass *) klass;
416
417         POA_Bonobo_Storage__epv *epv = &klass->epv;
418         
419         bonobo_storage_fs_parent_class = 
420                 g_type_class_peek_parent (klass);
421
422         epv->getInfo       = fs_get_info;
423         epv->setInfo       = fs_set_info;
424         epv->openStream    = fs_open_stream;
425         epv->openStorage   = fs_open_storage;
426         epv->copyTo        = fs_copy_to;
427         epv->rename        = fs_rename;
428         epv->commit        = fs_commit;
429         epv->revert        = fs_revert;
430         epv->listContents  = fs_list_contents;
431         epv->erase         = fs_erase;
432         
433         object_class->finalize = bonobo_storage_fs_finalize;
434 }
435
436
437 static void 
438 bonobo_storage_fs_init (GObject *object)
439 {
440         /* nothing to do */
441 }
442
443 BONOBO_TYPE_FUNC_FULL (BonoboStorageFS,
444                        Bonobo_Storage,
445                        bonobo_object_get_type (),
446                        bonobo_storage_fs);
447
448 /** 
449  * bonobo_storage_fs_open:
450  * @path: path to existing directory that represents the storage
451  * @flags: open flags.
452  * @mode: mode used if @flags containst Bonobo_Storage_CREATE for the storage.
453  *
454  * Returns a BonoboStorage object that represents the storage at @path
455  */
456 BonoboStorageFS *
457 bonobo_storage_fs_open (const char *path, gint flags,
458                         gint mode, CORBA_Environment *ev)
459 {
460         BonoboStorageFS *storage_fs;
461         struct stat st;
462         
463         g_return_val_if_fail (path != NULL, NULL);
464         g_return_val_if_fail (ev != NULL, NULL);
465
466         /* Most storages are files */
467         mode = mode | 0111;
468
469         if ((flags & Bonobo_Storage_CREATE) &&
470             (mkdir (path, mode) == -1) && (errno != EEXIST)) {
471
472                 if (errno == EACCES) 
473                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
474                                              ex_Bonobo_Storage_NoPermission, 
475                                              NULL);
476                 else 
477                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
478                                              ex_Bonobo_Storage_IOError, NULL);
479                 return NULL;
480         }
481
482         if (stat (path, &st) == -1) {
483                 
484                 if (errno == ENOENT) 
485                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
486                                              ex_Bonobo_Storage_NotFound, 
487                                              NULL);
488                 else 
489                         CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
490                                              ex_Bonobo_Storage_IOError,
491                                              NULL);
492                 return NULL;
493         }
494
495         if (!S_ISDIR (st.st_mode)) { 
496                 CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
497                                      ex_Bonobo_Storage_NotStorage, NULL);
498                 return NULL;
499         }
500
501         storage_fs = g_object_new (bonobo_storage_fs_get_type (), NULL);
502         storage_fs->path = g_strdup (path);
503
504         return storage_fs;
505 }