Source code upload
[framework/connectivity/libgphoto2.git] / libgphoto2 / gphoto2-filesys.c
1 /** \file
2  *
3  * \author Copyright 2000 Scott Fritzinger
4  * \author Contributions Lutz Müller <lutz@users.sf.net> (2001)
5  * \author Copyright 2009 Marcus Meissner
6  *
7  * \par License
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * \par
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * \par
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 #define _BSD_SOURCE
27
28 #include "config.h"
29 #include <gphoto2/gphoto2-filesys.h>
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <unistd.h>
35
36 #include <gphoto2/gphoto2-result.h>
37 #include <gphoto2/gphoto2-port-log.h>
38 #include <gphoto2/gphoto2-setting.h>
39
40 #include <limits.h>
41
42 #ifdef HAVE_LIBEXIF
43 #  include <libexif/exif-data.h>
44 #endif
45
46 #ifdef ENABLE_NLS
47 #  include <libintl.h>
48 #  undef _
49 #  define _(String) dgettext (GETTEXT_PACKAGE, String)
50 #  ifdef gettext_noop
51 #    define N_(String) gettext_noop (String)
52 #  else
53 #    define N_(String) (String)
54 #  endif
55 #else
56 #  define textdomain(String) (String)
57 #  define gettext(String) (String)
58 #  define dgettext(Domain,Message) (Message)
59 #  define dcgettext(Domain,Message,Type) (Message)
60 #  define bindtextdomain(Domain,Directory) (Domain)
61 #  define _(String) (String)
62 #  define N_(String) (String)
63 #endif
64
65 #define GP_MODULE "libgphoto2"
66
67 #ifndef PATH_MAX
68 # define PATH_MAX 4096
69 #endif
70
71 typedef struct _CameraFilesystemFile {
72         char *name;
73
74         int info_dirty;
75
76         CameraFileInfo info;
77
78         struct _CameraFilesystemFile *lru_prev;
79         struct _CameraFilesystemFile *lru_next;
80         CameraFile *preview;
81         CameraFile *normal;
82         CameraFile *raw;
83         CameraFile *audio;
84         CameraFile *exif;
85         CameraFile *metadata;
86
87         struct _CameraFilesystemFile *next; /* in folder */
88 } CameraFilesystemFile;
89
90 typedef struct _CameraFilesystemFolder {
91         char *name;
92
93         int files_dirty;
94         int folders_dirty;
95
96         struct _CameraFilesystemFolder *next; /* chain in same folder */
97         struct _CameraFilesystemFolder *folders; /* childchain of this folder */
98         struct _CameraFilesystemFile *files; /* of this folder */
99 } CameraFilesystemFolder;
100
101 /**
102  * The default number of pictures to keep in the internal cache,
103  * can be overriden by settings.
104  */
105 #define PICTURES_TO_KEEP        2
106 /**
107  * The current number of pictures to keep in the internal cache,
108  * either from #PICTURES_TO_KEEP or from the settings.
109  */
110 static int pictures_to_keep = -1;
111
112 static int gp_filesystem_lru_clear (CameraFilesystem *fs);
113 static int gp_filesystem_lru_remove_one (CameraFilesystem *fs, CameraFilesystemFile *item);
114
115 #ifdef HAVE_LIBEXIF
116
117 static int gp_filesystem_get_file_impl (CameraFilesystem *, const char *,
118                 const char *, CameraFileType, CameraFile *, GPContext *);
119
120 static time_t
121 get_time_from_exif_tag(ExifEntry *e) {
122         struct tm ts;
123
124         e->data[4] = e->data[ 7] = e->data[10] = e->data[13] = e->data[16] = 0;
125         ts.tm_year = atoi ((char*)e->data) - 1900;
126         ts.tm_mon  = atoi ((char*)(e->data + 5)) - 1;
127         ts.tm_mday = atoi ((char*)(e->data + 8));
128         ts.tm_hour = atoi ((char*)(e->data + 11));
129         ts.tm_min  = atoi ((char*)(e->data + 14));
130         ts.tm_sec  = atoi ((char*)(e->data + 17));
131
132         return mktime (&ts);
133 }
134
135 static time_t
136 get_exif_mtime (const unsigned char *data, unsigned long size)
137 {
138         ExifData *ed;
139         ExifEntry *e;
140         time_t t, t1 = 0, t2 = 0, t3 = 0;
141
142         ed = exif_data_new_from_data (data, size);
143         if (!ed) {
144                 GP_DEBUG ("Could not parse data for EXIF information.");
145                 return 0;
146         }
147
148         /*
149          * HP PhotoSmart C30 has the date and time in ifd_exif.
150          */
151 #ifdef HAVE_LIBEXIF_IFD
152         e = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_DATE_TIME);
153         if (e)
154                 t1 = get_time_from_exif_tag(e);
155         e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF],
156                                     EXIF_TAG_DATE_TIME_ORIGINAL);
157         if (e)
158                 t2 = get_time_from_exif_tag(e);
159         e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF],
160                                     EXIF_TAG_DATE_TIME_DIGITIZED);
161         if (e)
162                 t3 = get_time_from_exif_tag(e);
163 #else
164         e = exif_content_get_entry (ed->ifd0, EXIF_TAG_DATE_TIME);
165         if (e) {
166                 t1 = get_time_from_exif_tag(e);
167                 exif_data_unref (e);
168         }
169         e = exif_content_get_entry (ed->ifd_exif,
170                                     EXIF_TAG_DATE_TIME_ORIGINAL);
171         if (e) {
172                 t2 = get_time_from_exif_tag(e);
173                 exif_data_unref (e);
174         }
175         e = exif_content_get_entry (ed->ifd_exif,
176                                     EXIF_TAG_DATE_TIME_DIGITIZED);
177         if (e) {
178                 t3 = get_time_from_exif_tag(e);
179                 exif_data_unref (e);
180         }
181 #endif
182         exif_data_unref (ed);
183         if (!t1 && !t2 && !t3) {
184                 GP_DEBUG ("EXIF data has not date/time tags.");
185                 return 0;
186         }
187
188         /* Perform some sanity checking on those tags */
189         t = t1; /* "last modified" */
190
191         if (t2 > t)     /* "image taken" > "last modified" ? can not be */
192                 t = t2;
193         if (t3 > t)     /* "image digitized" > max(last two) ? can not be */
194                 t = t3;
195
196         GP_DEBUG ("Found time in EXIF data: '%s'.", asctime (localtime (&t)));
197         return (t);
198 }
199
200 static time_t
201 gp_filesystem_get_exif_mtime (CameraFilesystem *fs, const char *folder,
202                               const char *filename)
203 {
204         CameraFile *file;
205         const char *data = NULL;
206         unsigned long int size = 0;
207         time_t t;
208
209         if (!fs)
210                 return 0;
211
212         /* This is only useful for JPEGs. Avoid querying it for other types. */
213         if (    !strstr(filename,"jpg")  && !strstr(filename,"JPG") &&
214                 !strstr(filename,"jpeg") && !strstr(filename,"JPEG")
215         )
216                 return 0;
217
218         gp_file_new (&file);
219         if (gp_filesystem_get_file (fs, folder, filename,
220                                 GP_FILE_TYPE_EXIF, file, NULL) != GP_OK) {
221                 GP_DEBUG ("Could not get EXIF data of '%s' in folder '%s'.",
222                           filename, folder);
223                 gp_file_unref (file);
224                 return 0;
225         }
226
227         gp_file_get_data_and_size (file, &data, &size);
228         t = get_exif_mtime ((unsigned char*)data, size);
229         gp_file_unref (file);
230
231         return (t);
232 }
233 #endif
234
235 /**
236  * \brief The internal camera filesystem structure
237  *
238  * The internals of the #CameraFilesystem are only visible to gphoto2. You
239  * can only access them using the functions provided by gphoto2.
240  **/
241 struct _CameraFilesystem {
242         CameraFilesystemFolder *rootfolder;
243
244         CameraFilesystemFile *lru_first;
245         CameraFilesystemFile *lru_last;
246         unsigned long int lru_size;
247
248         CameraFilesystemGetInfoFunc get_info_func;
249         CameraFilesystemSetInfoFunc set_info_func;
250         void *info_data;
251
252         CameraFilesystemListFunc file_list_func;
253         CameraFilesystemListFunc folder_list_func;
254         void *list_data;
255
256         CameraFilesystemGetFileFunc get_file_func;
257         CameraFilesystemDeleteFileFunc delete_file_func;
258         void *file_data;
259
260         CameraFilesystemPutFileFunc put_file_func;
261         CameraFilesystemDeleteAllFunc delete_all_func;
262         CameraFilesystemDirFunc make_dir_func;
263         CameraFilesystemDirFunc remove_dir_func;
264         void *folder_data;
265
266         CameraFilesystemStorageInfoFunc storage_info_func;
267 };
268
269 #undef  MIN
270 #define MIN(a, b)  (((a) < (b)) ? (a) : (b))
271
272 #define CHECK_NULL(r)        {if (!(r)) return (GP_ERROR_BAD_PARAMETERS);}
273 #define CR(result)           {int r = (result); if (r < 0) return (r);}
274 #define CHECK_MEM(m)         {if (!(m)) return (GP_ERROR_NO_MEMORY);}
275
276 #define CL(result,list)                 \
277 {                                       \
278         int r = (result);               \
279                                         \
280          if (r < 0) {                   \
281                 gp_list_free (list);    \
282                 return (r);             \
283         }                               \
284 }
285
286 #define CU(result,file)                 \
287 {                                       \
288         int r = (result);               \
289                                         \
290         if (r < 0) {                    \
291                 gp_file_unref (file);   \
292                 return (r);             \
293         }                               \
294 }
295
296 #define CC(context)                                                     \
297 {                                                                       \
298         if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL)  \
299                 return GP_ERROR_CANCEL;                                 \
300 }
301
302 #define CA(f,c)                                                 \
303 {                                                                       \
304         if ((f)[0] != '/') {                                            \
305                 gp_context_error ((c),                                  \
306                         _("The path '%s' is not absolute."), (f));      \
307                 return (GP_ERROR_PATH_NOT_ABSOLUTE);                    \
308         }                                                               \
309 }
310
311 static int
312 delete_all_files (CameraFilesystem *fs, CameraFilesystemFolder *folder)
313 {
314         CameraFilesystemFile    *file;
315
316         CHECK_NULL (folder);
317         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Delete all files in folder %p/%s", folder, folder->name);
318
319         file = folder->files;
320         while (file) {
321                 CameraFilesystemFile    *next;
322                 /* Get rid of cached files */
323                 gp_filesystem_lru_remove_one (fs, file);
324                 if (file->preview) {
325                         gp_file_unref (file->preview);
326                         file->preview = NULL;
327                 }
328                 if (file->normal) {
329                         gp_file_unref (file->normal);
330                         file->normal = NULL;
331                 }
332                 if (file->raw) {
333                         gp_file_unref (file->raw);
334                         file->raw = NULL;
335                 }
336                 if (file->audio) {
337                         gp_file_unref (file->audio);
338                         file->audio = NULL;
339                 }
340                 if (file->exif) {
341                         gp_file_unref (file->exif);
342                         file->exif = NULL;
343                 }
344                 if (file->metadata) {
345                         gp_file_unref (file->metadata);
346                         file->metadata = NULL;
347                 }
348                 next = file->next;
349                 free (file->name);
350                 free (file);
351                 file = next;
352         }
353         folder->files = NULL;
354         return (GP_OK);
355 }
356
357 static int
358 delete_folder (CameraFilesystem *fs, CameraFilesystemFolder **folder)
359 {
360         CameraFilesystemFolder *next;
361         CHECK_NULL (folder);
362
363         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Delete one folder %p/%s", *folder, (*folder)->name);
364         next = (*folder)->next;
365         delete_all_files (fs, *folder);
366         free ((*folder)->name);
367         free (*folder);
368         *folder = next;
369         return (GP_OK);
370 }
371
372 static CameraFilesystemFolder*
373 lookup_folder (
374         CameraFilesystem *fs,
375         CameraFilesystemFolder *folder, const char *foldername,
376         GPContext *context
377 ) {
378         CameraFilesystemFolder  *f;
379         const char      *curpt = foldername;
380         const char      *s;
381
382         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Lookup folder '%s'...", foldername);
383         while (folder) {
384                 /* handle multiple slashes, and slashes at the end */
385                 while (curpt[0]=='/')
386                         curpt++;
387                 if (!curpt[0]) {
388                         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Found! %s is %p", foldername, folder);
389                         return folder;
390                 }
391
392                 s = strchr(curpt,'/');
393                 /* Check if we need to load the folder ... */
394                 if (folder->folders_dirty) {
395                         CameraList      *list;
396                         char            *copy = strdup (foldername);
397                         int             ret;
398                         /*
399                          * The parent folder is dirty. List the folders in the parent 
400                          * folder to make it clean.
401                          */
402                         /* the character _before_ curpt is a /, overwrite it temporary with \0 */
403                         copy[curpt-foldername] = '\0';
404                         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Folder %s is dirty. "
405                                 "Listing folders in there to make folder clean...", copy);
406                         ret = gp_list_new (&list);
407                         if (ret == GP_OK) {
408                                 ret = gp_filesystem_list_folders (fs, copy, list, context);
409                                 gp_list_free (list);
410                                 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Done making folder %s clean...", copy);
411                         } else {
412                                 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Making folder %s clean failed: %d", copy, ret);
413                         }
414                         free (copy);
415                 }
416                 f = folder->folders;
417                 while (f) {
418                         if (s) {
419                                 if (!strncmp(f->name,curpt, (s-curpt)) &&
420                                     (strlen(f->name) == (s-curpt))
421                                 ) {
422                                         folder = f;
423                                         curpt = s;
424                                         break;
425                                 }
426                         } else {
427                                 if (!strcmp(f->name,curpt))
428                                         return f;
429                         }
430                         f = f->next;
431                 }
432                 folder = f;
433         }
434         return NULL;
435 }
436
437 static int
438 lookup_folder_file (
439         CameraFilesystem *fs,
440         const char *folder, const char *filename,
441         CameraFilesystemFolder **xfolder, CameraFilesystemFile **xfile,
442         GPContext *context
443 ) {
444         CameraFilesystemFolder* xf;
445         CameraFilesystemFile*   f;
446
447         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Lookup folder %s file %s", folder, filename);
448         xf = lookup_folder (fs, fs->rootfolder, folder, context);
449         if (!xf) return GP_ERROR_DIRECTORY_NOT_FOUND;
450         /* Check if we need to load the filelist of the folder ... */
451         if (xf->files_dirty) {
452                 CameraList      *list;
453                 int             ret;
454                 /*
455                  * The folder is dirty. List the files in it to make it clean.
456                  */
457                 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Folder %s is dirty. "
458                         "Listing files in there to make folder clean...", folder);
459                 ret = gp_list_new (&list);
460                 if (ret == GP_OK) {
461                         ret = gp_filesystem_list_files (fs, folder, list, context);
462                         gp_list_free (list);
463                         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Done making folder %s clean...", folder);
464                 }
465                 if (ret != GP_OK)
466                         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Making folder %s clean failed: %d", folder, ret);
467         }
468
469         f = xf->files;
470         while (f) {
471                 if (!strcmp (f->name, filename)) {
472                         *xfile = f;
473                         *xfolder = xf;
474                         return GP_OK;
475                 }
476                 f = f->next;
477         }
478         return GP_ERROR_FILE_NOT_FOUND;
479 }
480
481 /* delete all folder content */
482 static int
483 recurse_delete_folder (CameraFilesystem *fs, CameraFilesystemFolder *folder) {
484         CameraFilesystemFolder  **f;
485
486         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Recurse delete folder %p/%s", folder, folder->name);
487         f = &folder->folders;
488         while (*f) {
489                 recurse_delete_folder (fs, *f);
490                 delete_folder (fs, f); /* will also advance to next */
491         }
492         return (GP_OK);
493 }
494
495 static int
496 delete_all_folders (CameraFilesystem *fs, const char *foldername,
497                     GPContext *context)
498 {
499         CameraFilesystemFolder  *folder;
500
501         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Internally deleting "
502                 "all folders from '%s'...", foldername);
503
504         CHECK_NULL (fs && foldername);
505         CC (context);
506         CA (foldername, context);
507
508         folder = lookup_folder (fs, fs->rootfolder, foldername, context);
509         return recurse_delete_folder (fs, folder);
510 }
511
512 /* create and append 1 new folder entry to the current folder */
513 static int
514 append_folder_one (
515         CameraFilesystemFolder *folder,
516         const char *name,
517         CameraFilesystemFolder **newfolder
518 ) {
519         CameraFilesystemFolder *f;
520
521         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Append one folder %s", name);
522         CHECK_MEM (f = calloc(sizeof(CameraFilesystemFolder),1));
523         CHECK_MEM (f->name = strdup (name));
524         f->files_dirty = 1;
525         f->folders_dirty = 1;
526
527         /* Link into the current chain...  perhaps later alphabetically? */
528         f->next = folder->folders;
529         folder->folders = f;
530         if (newfolder) *newfolder = f;
531         return (GP_OK);
532 }
533
534 /* This is a mix between lookup and folder creator */
535 static int
536 append_to_folder (CameraFilesystemFolder *folder,
537         const char *foldername,
538         CameraFilesystemFolder **newfolder
539 ) {
540         CameraFilesystemFolder  *f;
541         char    *s;
542
543         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Append to folder %p/%s - %s", folder, folder->name, foldername);
544         /* Handle multiple slashes, and slashes at the end */
545         while (foldername[0]=='/')
546                 foldername++;
547         if (!foldername[0]) {
548                 if (newfolder) *newfolder = folder;
549                 return (GP_OK);
550         }
551
552         s = strchr(foldername,'/');
553         f = folder->folders;
554         while (f) {
555                 if (s) {
556                         if (!strncmp(f->name,foldername, (s-foldername)) &&
557                             (strlen(f->name) == (s-foldername))
558                         )
559                                 return append_to_folder (f, s+1, newfolder);
560                 } else {
561                         if (!strcmp(f->name,foldername)) {
562                                 if (newfolder) *newfolder = f;
563                                 return (GP_OK);
564                         }
565                 }
566                 f = f->next;
567         }
568         /* Not found ... create new folder */
569         if (s) {
570                 char *x;
571                 CHECK_MEM (x = calloc ((s-foldername)+1,1));
572                 memcpy (x, foldername, (s-foldername));
573                 x[s-foldername] = 0;
574                 CR (append_folder_one (folder, x, newfolder));
575                 free (x);
576         } else {
577                 CR (append_folder_one (folder, foldername, newfolder));
578         }
579         return (GP_OK);
580 }
581
582 static int
583 append_folder (CameraFilesystem *fs,
584         const char *folder,
585         CameraFilesystemFolder **newfolder,
586         GPContext *context
587 ) {
588         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Appending folder %s...", folder);
589         CHECK_NULL (fs);
590         CHECK_NULL (folder);
591         CC (context);
592         CA (folder, context);
593         return append_to_folder (fs->rootfolder, folder, newfolder);
594 }
595
596 static int
597 append_file (CameraFilesystem *fs, CameraFilesystemFolder *folder, CameraFile *file, GPContext *context)
598 {
599         CameraFilesystemFile **new;
600         const char *name;
601
602         CHECK_NULL (fs && file);
603
604         CR (gp_file_get_name (file, &name));
605         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Appending file %s...", name);
606
607
608         new = &folder->files;
609         while (*new) {
610                 if (!strcmp((*new)->name, name)) {
611                         gp_log (GP_LOG_ERROR, "gphoto2-filesystem", "File %s already exists!", name);
612                         return (GP_ERROR);
613                 }
614                 new = &((*new)->next);
615         }
616         /* new now points to the location of the last ->next pointer,
617          * if we write to it, we set last->next */
618         CHECK_MEM ((*new) = calloc (sizeof (CameraFilesystemFile), 1));
619         (*new)->name = strdup (name);
620         (*new)->info_dirty = 1;
621         (*new)->normal = file;
622         gp_file_ref (file);
623         return (GP_OK);
624 }
625
626 /**
627  * \brief Clear the filesystem
628  * \param fs the filesystem to be cleared
629  *
630  * Resets the filesystem. All cached information including the folder tree
631  * will get lost and will be queried again on demand.
632  *
633  * \return a gphoto2 error code.
634  **/
635 int
636 gp_filesystem_reset (CameraFilesystem *fs)
637 {
638         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "resetting filesystem");
639         CR (gp_filesystem_lru_clear (fs));
640         CR (delete_all_folders (fs, "/", NULL));
641         if (fs->rootfolder) {
642                 fs->rootfolder->files_dirty = 1;
643                 fs->rootfolder->folders_dirty = 1;
644         } else {
645                 gp_log (GP_LOG_ERROR,"gphoto2-filesys", "root folder is gone?");
646         }
647         return (GP_OK);
648 }
649
650 /**
651  * \brief Create a new filesystem struct
652  *
653  * \param fs a pointer to a #CameraFilesystem
654  *
655  * Creates a new empty #CameraFilesystem
656  *
657  * \return a gphoto2 error code.
658  **/
659 int
660 gp_filesystem_new (CameraFilesystem **fs)
661 {
662         CHECK_NULL (fs);
663
664         CHECK_MEM (*fs = malloc (sizeof (CameraFilesystem)));
665
666         memset(*fs,0,sizeof(CameraFilesystem));
667
668         (*fs)->rootfolder = calloc (sizeof (CameraFilesystemFolder), 1);
669         if (!(*fs)->rootfolder) {
670                 free (*fs);
671                 return (GP_ERROR_NO_MEMORY);
672         }
673         (*fs)->rootfolder->name = strdup("/");
674         if (!(*fs)->rootfolder->name) {
675                 free ((*fs)->rootfolder);
676                 free (*fs);
677                 return (GP_ERROR_NO_MEMORY);
678         }
679         (*fs)->rootfolder->files_dirty = 1;
680         (*fs)->rootfolder->folders_dirty = 1;
681         return (GP_OK);
682 }
683
684 /**
685  * \brief Free filesystem struct
686  * \param fs a #CameraFilesystem
687  *
688  * Frees the #CameraFilesystem
689  *
690  * \return a gphoto2 error code.
691  **/
692 int
693 gp_filesystem_free (CameraFilesystem *fs)
694 {
695         /* We don't care for success or failure */
696         gp_filesystem_reset (fs);
697
698         /* Now, we've only got left over the root folder. Free that and
699          * the filesystem. */
700         free (fs->rootfolder->name);
701         free (fs->rootfolder);
702         free (fs);
703         return (GP_OK);
704 }
705
706 /**
707  * \brief Append a file to a folder in a filesystem
708  * \param fs a #CameraFilesystem
709  * \param folder the folder where to put the file in
710  * \param filename filename of the file
711  * \param context a #GPContext
712  *
713  * Tells the fs that there is a file called filename in folder
714  * called folder. Usually camera drivers will call this function after
715  * capturing an image in order to tell the fs about the new file.
716  * A front-end should not use this function.
717  *
718  * \return a gphoto2 error code.
719  **/
720 int
721 gp_filesystem_append (CameraFilesystem *fs, const char *folder,
722                       const char *filename, GPContext *context)
723 {
724         CameraFilesystemFile **new;
725         CameraFilesystemFolder *f;
726
727         CHECK_NULL (fs && folder);
728         CC (context);
729         CA (folder, context);
730
731         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Append %s/%s to filesystem", folder, filename);
732         /* Check folder for existence, if not, create it. */
733         f = lookup_folder (fs, fs->rootfolder, folder, context);
734         if (!f)
735                 CR (append_folder (fs, folder, &f, context));
736
737         new = &f->files;
738         while (*new) {
739                 if (!strcmp((*new)->name, filename)) break;
740                 new = &((*new)->next);
741         }
742         if (*new) {
743                 gp_context_error (context,
744                         _("Could not append '%s' to folder '%s' because "
745                           "this file already exists."), filename, folder);
746                 return (GP_ERROR_FILE_EXISTS);
747         }
748
749         CHECK_MEM ((*new) = calloc (sizeof (CameraFilesystemFile), 1))
750         (*new)->name = strdup (filename);
751         if (!(*new)->name) {
752                 free (*new);
753                 *new = NULL;
754                 return (GP_ERROR_NO_MEMORY);
755         }
756         (*new)->info_dirty = 1;
757         f->files_dirty = 0;
758         return (GP_OK);
759 }
760
761 static void
762 recursive_fs_dump (CameraFilesystemFolder *folder, int depth) {
763         CameraFilesystemFolder  *f;
764         CameraFilesystemFile    *xfile;
765
766         gp_log (GP_LOG_DEBUG, "gphoto2-filesys", "%*sFolder %s", depth, " ", folder->name);
767
768         xfile = folder->files;
769         while (xfile) {
770                 gp_log (GP_LOG_DEBUG, "gphoto2-filesys", "%*s    %s", depth, " ", xfile->name);
771                 xfile = xfile->next;
772         }
773         
774         f = folder->folders;
775         while (f) {
776                 recursive_fs_dump (f, depth+4);
777                 f = f->next;
778         }
779 }
780 /**
781  * \brief Dump the current filesystem.
782  * \param fs the #CameraFilesystem
783  * \return a gphoto error code
784  *
785  * Internal function to dump the current filesystem.
786  */
787 int
788 gp_filesystem_dump (CameraFilesystem *fs)
789 {
790         GP_DEBUG("Dumping Filesystem:");
791         recursive_fs_dump (fs->rootfolder, 0);
792         return (GP_OK);
793 }
794
795 static int
796 delete_file (CameraFilesystem *fs, CameraFilesystemFolder *folder, CameraFilesystemFile *file)
797 {
798         CameraFilesystemFile **prev;
799
800         gp_filesystem_lru_remove_one (fs, file);
801         /* Get rid of cached files */
802         if (file->preview) {
803                 gp_file_unref (file->preview);
804                 file->preview = NULL;
805         }
806         if (file->normal) {
807                 gp_file_unref (file->normal);
808                 file->normal = NULL;
809         }
810         if (file->raw) {
811                 gp_file_unref (file->raw);
812                 file->raw = NULL;
813         }
814         if (file->audio) {
815                 gp_file_unref (file->audio);
816                 file->audio = NULL;
817         }
818         if (file->exif) {
819                 gp_file_unref (file->exif);
820                 file->exif = NULL;
821         }
822         if (file->metadata) {
823                 gp_file_unref (file->metadata);
824                 file->metadata = NULL;
825         }
826
827         prev = &(folder->files);
828         while ((*prev) && ((*prev) != file))
829                 prev = &((*prev)->next);
830         if (!*prev)
831                 return GP_ERROR;
832         *prev = file->next;
833         file->next = NULL;
834         free (file->name);
835         free (file);
836         return (GP_OK);
837 }
838
839 static int
840 gp_filesystem_delete_all_one_by_one (CameraFilesystem *fs, const char *folder,
841                                      GPContext *context)
842 {
843         CameraList *list;
844         int count, x;
845         const char *name;
846
847         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Deleting all 1 by 1 from %s", folder);
848         CR (gp_list_new (&list));
849         CL (gp_filesystem_list_files (fs, folder, list, context), list);
850         CL (count = gp_list_count (list), list);
851         for (x = count ; x--; ) {
852                 CL (gp_list_get_name (list, x, &name), list);
853                 CL (gp_filesystem_delete_file (fs, folder, name, context),list);
854         }
855         gp_list_free(list);
856         return (GP_OK);
857 }
858
859 /**
860  * \brief Delete all files in specified folder.
861  *
862  * \param fs a #CameraFilesystem
863  * \param folder the folder in which to delete all files
864  * \param context a #GPContext
865  *
866  * Deletes all files in the given folder from the fs. If the fs has not
867  * been supplied with a delete_all_func, it tries to delete the files
868  * one by one using the delete_file_func. If that function has not been
869  * supplied neither, an error is returned.
870  *
871  * \return a gphoto2 error code.
872  **/
873 int
874 gp_filesystem_delete_all (CameraFilesystem *fs, const char *folder,
875                           GPContext *context)
876 {
877         int r;
878         CameraFilesystemFolder *f;
879
880         CHECK_NULL (fs && folder);
881         CC (context);
882         CA (folder, context);
883
884         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Deleting all from %s", folder);
885         /* Make sure this folder exists */
886         f = lookup_folder (fs, fs->rootfolder, folder, context);
887         if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
888
889         if (!fs->delete_all_func)
890                 return gp_filesystem_delete_all_one_by_one (fs, folder, context);
891         /*
892          * Mark the folder dirty - it could be that an error
893          * happens, and then we don't know which files have been
894          * deleted and which not.
895          */
896         f->files_dirty = 1;
897         /*
898          * First try to use the delete_all function. If that fails,
899          * fall back to deletion one-by-one.
900          */
901         r = fs->delete_all_func (fs, folder, fs->folder_data, context);
902         if (r < 0) {
903                 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem",
904                         "delete_all failed (%s). Falling back to "
905                         "deletion one-by-one.",
906                         gp_result_as_string (r));
907                 CR (gp_filesystem_delete_all_one_by_one (fs, folder,
908                                                          context));
909         } else {
910                 /* delete from filesystem view too now */
911                 CR (delete_all_files (fs, f));
912         }
913         /*
914          * No error happened. We can be sure that all files have been
915          * deleted.
916          */
917         f->files_dirty = 0;
918         return (GP_OK);
919 }
920
921 /**
922  * \brief Get the list of files in a folder
923  * \param fs a #CameraFilesystem
924  * \param folder a folder of which a file list should be generated
925  * \param list a #CameraList where to put the list of files into
926  * \param context a #GPContext
927  *
928  * Lists the files in folder using either cached values or (if there
929  * aren't any) the file_list_func which (hopefully) has been previously
930  * supplied.
931  *
932  * \return a gphoto2 error code.
933  **/
934 int
935 gp_filesystem_list_files (CameraFilesystem *fs, const char *folder,
936                           CameraList *list, GPContext *context)
937 {
938         int count, y;
939         const char *name;
940         CameraFilesystemFolder  *f;
941         CameraFilesystemFile    *file;
942
943         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Listing files in %s", folder);
944
945         CHECK_NULL (fs && list && folder);
946         CC (context);
947         CA (folder, context);
948
949         gp_list_reset (list);
950
951         /* Search the folder */
952         f = lookup_folder (fs, fs->rootfolder, folder, context);
953         if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
954
955         /* If the folder is dirty, delete the contents and query the camera */
956         if (f->files_dirty && fs->file_list_func) {
957                 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem",
958                         "Querying folder %s...", folder);
959                 CR (delete_all_files (fs, f));
960                 CR (fs->file_list_func (fs, folder, list,
961                                         fs->list_data, context));
962
963                 CR (count = gp_list_count (list));
964                 for (y = 0; y < count; y++) {
965                         CR (gp_list_get_name (list, y, &name));
966                         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem",
967                                          "Added '%s'", name);
968                         CR (gp_filesystem_append (fs, folder, name, context));
969                 }
970                 gp_list_reset (list);
971         }
972
973         /* The folder is clean now */
974         f->files_dirty = 0;
975
976         file = f->files;
977         while (file) {
978                 gp_log (GP_LOG_DEBUG, "filesys",
979                         "Listed '%s'", file->name);
980                 CR (gp_list_append (list, file->name, NULL));
981                 file = file->next;
982         }
983         return (GP_OK);
984 }
985
986 /**
987  * \brief List all subfolders within a filesystem folder
988  * \param fs a #CameraFilesystem
989  * \param folder a folder
990  * \param list a #CameraList where subfolders should be listed
991  * \param context a #GPContext
992  *
993  * Generates a list of subfolders of the supplied folder either using
994  * cached values (if there are any) or the folder_list_func if it has been
995  * supplied previously. If not, it is assumed that only a root folder
996  * exists (which is the case for many cameras).
997  *
998  * \return a gphoto2 error code.
999  **/
1000 int
1001 gp_filesystem_list_folders (CameraFilesystem *fs, const char *folder,
1002                             CameraList *list, GPContext *context)
1003 {
1004         int y, count;
1005         const char *name;
1006         CameraFilesystemFolder  *f, *new;
1007
1008         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Listing folders in %s", folder);
1009
1010         CHECK_NULL (fs && folder && list);
1011         CC (context);
1012         CA (folder, context);
1013
1014         gp_list_reset (list);
1015
1016         /* Search the folder */
1017         f = lookup_folder (fs, fs->rootfolder, folder, context);
1018         if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1019
1020
1021         /* If the folder is dirty, query the contents. */
1022         if (f->folders_dirty && fs->folder_list_func) {
1023                 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "... is dirty, getting from camera");
1024                 CR (fs->folder_list_func (fs, folder, list,
1025                                           fs->list_data, context));
1026                 CR (delete_all_folders (fs, folder, context));
1027
1028                 CR (count = gp_list_count (list));
1029                 for (y = 0; y < count; y++) {
1030                         CR (gp_list_get_name (list, y, &name));
1031                         CR (append_folder_one (f, name, NULL));
1032                 }
1033                 /* FIXME: why not just return (GP_OK); ? the list should be fine */
1034                 gp_list_reset (list);
1035         }
1036
1037         new = f->folders;
1038         while (new) {
1039                 CR (gp_list_append (list, new->name, NULL));
1040                 new = new->next;
1041         }
1042         /* The folder is clean now */
1043         f->folders_dirty = 0;
1044         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Folder %s contains %i "
1045                 "subfolders.", folder, gp_list_count (list));
1046         return (GP_OK);
1047 }
1048
1049 /**
1050  * \brief Count files a folder of a filesystem.
1051  * \param fs a #CameraFilesystem
1052  * \param folder a folder in which to count the files
1053  * \param context a #GPContext
1054  *
1055  * Counts the files in the folder.
1056  *
1057  * \return The number of files in the folder or a gphoto2 error code.
1058  **/
1059 int
1060 gp_filesystem_count (CameraFilesystem *fs, const char *folder,
1061                      GPContext *context)
1062 {
1063         int x;
1064         CameraFilesystemFolder  *f;
1065         CameraFilesystemFile    *file;
1066
1067         CHECK_NULL (fs && folder);
1068         CC (context);
1069         CA (folder, context);
1070
1071         f = lookup_folder (fs, fs->rootfolder, folder, context);
1072         if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1073
1074         x = 0;
1075         file = f->files;
1076         while (file) {
1077                 x++;
1078                 file = file->next;
1079         }
1080         return x;
1081 }
1082
1083 /**
1084  * \brief Delete a file from a folder.
1085  * \param fs a #CameraFilesystem
1086  * \param folder a folder in which to delete the file
1087  * \param filename the name of the file to delete
1088  * \param context a #GPContext
1089  *
1090  * If a delete_file_func has been supplied to the fs, this function will
1091  * be called and, if this function returns without error, the file will be
1092  * removed from the fs.
1093  *
1094  * \return a gphoto2 error code.
1095  **/
1096 int
1097 gp_filesystem_delete_file (CameraFilesystem *fs, const char *folder,
1098                            const char *filename, GPContext *context)
1099 {
1100         CameraFilesystemFolder  *f;
1101         CameraFilesystemFile    *file;
1102
1103         CHECK_NULL (fs && folder && filename);
1104         CC (context);
1105         CA (folder, context);
1106
1107         /* First of all, do we support file deletion? */
1108         if (!fs->delete_file_func) {
1109                 gp_context_error (context, _("You have been trying to delete "
1110                         "'%s' from folder '%s', but the filesystem does not "
1111                         "support deletion of files."), filename, folder);
1112                 return (GP_ERROR_NOT_SUPPORTED);
1113         }
1114
1115         /* Search the folder and the file */
1116         CR (lookup_folder_file (fs, folder, filename, &f, &file, context));
1117
1118         gp_context_status (context, _("Deleting '%s' from folder '%s'..."),
1119                            filename, folder);
1120         /* Delete the file */
1121         CR (fs->delete_file_func (fs, folder, filename,
1122                                   fs->file_data, context));
1123         CR (delete_file (fs, f, file));
1124         return (GP_OK);
1125 }
1126
1127 /**
1128  * \brief Delete a virtal file from a folder in the filesystem
1129  * \param fs a #CameraFilesystem
1130  * \param folder a folder in which to delete the file
1131  * \param filename the name of the file to delete
1132  * \param context a #GPContext
1133  *
1134  * Remove a file from the filesystem. Compared to gp_filesystem_delete_file()
1135  * this just removes the file from the libgphoto2 view of the filesystem, but
1136  * does not call the camera driver to delete it from the physical device.
1137  *
1138  * \return a gphoto2 error code.
1139  **/
1140 int
1141 gp_filesystem_delete_file_noop (CameraFilesystem *fs, const char *folder,
1142                                 const char *filename, GPContext *context)
1143 {
1144         CameraFilesystemFolder  *f;
1145         CameraFilesystemFile    *file;
1146
1147         CHECK_NULL (fs && folder && filename);
1148         CC (context);
1149         CA (folder, context);
1150         /* Search the folder and the file */
1151         CR (lookup_folder_file (fs, folder, filename, &f, &file, context));
1152         return delete_file (fs, f, file);
1153 }
1154
1155 /**
1156  * \brief Create a subfolder within a folder
1157  * \param fs a #CameraFilesystem
1158  * \param folder the folder in which the directory should be created
1159  * \param name the name of the directory to be created
1160  * \param context a #GPContext
1161  *
1162  * Creates a new directory called name in given folder.
1163  *
1164  * \return a gphoto2 error code
1165  **/
1166 int
1167 gp_filesystem_make_dir (CameraFilesystem *fs, const char *folder,
1168                         const char *name, GPContext *context)
1169 {
1170         CameraFilesystemFolder  *f;
1171
1172         CHECK_NULL (fs && folder && name);
1173         CC (context);
1174         CA (folder, context);
1175
1176         if (!fs->make_dir_func)
1177                 return (GP_ERROR_NOT_SUPPORTED);
1178
1179         /* Search the folder */
1180         f = lookup_folder (fs, fs->rootfolder, folder, context);
1181         if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1182
1183         /* Create the directory */
1184         CR (fs->make_dir_func (fs, folder, name, fs->folder_data, context));
1185         /* and append to internal fs */
1186         return append_folder_one (f, name, NULL);
1187 }
1188
1189 /**
1190  * \brief Remove a subfolder from within a folder
1191  * \param fs a #CameraFilesystem
1192  * \param folder the folder in which the directory should be created
1193  * \param name the name of the directory to be created
1194  * \param context a #GPContext
1195  *
1196  * Removes a directory called name from the given folder.
1197  *
1198  * \return a gphoto2 error code
1199  **/
1200 int
1201 gp_filesystem_remove_dir (CameraFilesystem *fs, const char *folder,
1202                           const char *name, GPContext *context)
1203 {
1204         CameraFilesystemFolder *f;
1205         CameraFilesystemFolder **prev;
1206
1207         CHECK_NULL (fs && folder && name);
1208         CC (context);
1209         CA (folder, context);
1210
1211         if (!fs->remove_dir_func)
1212                 return (GP_ERROR_NOT_SUPPORTED);
1213
1214         /*
1215          * Make sure there are neither files nor folders in the folder
1216          * that is to be removed.
1217          */
1218         f = lookup_folder (fs, fs->rootfolder, folder, context);
1219         if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1220         /* Check if we need to load the folder ... */
1221         if (f->folders_dirty) {
1222                 CameraList      *list;
1223                 int             ret;
1224                 /*
1225                  * The owning folder is dirty. List the folders in it 
1226                  * to make it clean.
1227                  */
1228                 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Folder %s is dirty. "
1229                         "Listing folders in there to make folder clean...", folder);
1230                 ret = gp_list_new (&list);
1231                 if (ret == GP_OK) {
1232                         ret = gp_filesystem_list_folders (fs, folder, list, context);
1233                         gp_list_free (list);
1234                         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Done making folder %s clean...", folder);
1235                 }
1236         }
1237         prev = &(f->folders);
1238         while (*prev) {
1239                 if (!strcmp (name, (*prev)->name))
1240                         break;
1241                 prev = &((*prev)->next);
1242         }
1243         if (!*prev) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1244
1245         if ((*prev)->folders) {
1246                 gp_context_error (context, _("There are still subfolders in "
1247                         "folder '%s/%s' that you are trying to remove."), folder, name);
1248                 return (GP_ERROR_DIRECTORY_EXISTS);
1249         }
1250         if ((*prev)->files) {
1251                 gp_context_error (context, _("There are still files in "
1252                         "folder '%s/%s' that you are trying to remove."), folder,name);
1253                 return (GP_ERROR_FILE_EXISTS);
1254         }
1255
1256         /* Remove the directory */
1257         CR (fs->remove_dir_func (fs, folder, name, fs->folder_data, context));
1258         CR (delete_folder (fs, prev));
1259         return (GP_OK);
1260 }
1261
1262 /**
1263  * \brief Upload a file to a folder on the device filesystem
1264  * \param fs a #CameraFilesystem
1265  * \param folder the folder where to put the file into
1266  * \param file the file
1267  * \param context a #GPContext
1268  *
1269  * Uploads a file to the camera if a put_file_func has been previously
1270  * supplied to the fs. If the upload is successful, the file will get
1271  * cached in the fs.
1272  *
1273  * \return a gphoto2 error code.
1274  **/
1275 int
1276 gp_filesystem_put_file (CameraFilesystem *fs, const char *folder,
1277                         CameraFile *file, GPContext *context)
1278 {
1279         CameraFilesystemFolder  *f;
1280
1281         CHECK_NULL (fs && folder && file);
1282         CC (context);
1283         CA (folder, context);
1284
1285         /* Do we support file upload? */
1286         if (!fs->put_file_func) {
1287                 gp_context_error (context, _("The filesystem does not support "
1288                         "upload of files."));
1289                 return (GP_ERROR_NOT_SUPPORTED);
1290         }
1291
1292         /* Search the folder */
1293         f = lookup_folder (fs, fs->rootfolder, folder, context);
1294         if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1295
1296         /* Upload the file */
1297         CR (fs->put_file_func (fs, folder, file, fs->folder_data, context));
1298         /* And upload it to internal structure too */
1299         return append_file (fs, f, file, context);
1300 }
1301
1302 /**
1303  * \brief Lookup the filename of an indexed file within a folder.
1304  * \param fs a #CameraFilesystem
1305  * \param folder the folder where to look up the file with the filenumber
1306  * \param filenumber the number of the file
1307  * \param filename pointer to a filename where the result is stored
1308  * \param context a #GPContext
1309  *
1310  * Looks up the filename of file with given filenumber in given folder.
1311  * See gp_filesystem_number for exactly the opposite functionality.
1312  *
1313  * \return a gphoto2 error code.
1314  **/
1315 int
1316 gp_filesystem_name (CameraFilesystem *fs, const char *folder, int filenumber,
1317                     const char **filename, GPContext *context)
1318 {
1319         CameraFilesystemFolder  *f;
1320         CameraFilesystemFile    *file;
1321         int count;
1322         CHECK_NULL (fs && folder);
1323         CC (context);
1324         CA (folder, context);
1325
1326         f = lookup_folder (fs, fs->rootfolder, folder, context);
1327         if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1328
1329         file = f->files;
1330         count = 0;
1331         while (file) {
1332                 if (filenumber == 0)
1333                         break;
1334                 filenumber--;
1335                 count++;
1336                 file = file->next;
1337         }
1338
1339         if (!file) {
1340                 gp_context_error (context, _("Folder '%s' only contains "
1341                         "%i files, but you requested a file with number %i."),
1342                         folder, count, filenumber);
1343                 return (GP_ERROR_FILE_NOT_FOUND);
1344         }
1345         *filename = file->name;
1346         return (GP_OK);
1347 }
1348
1349 /**
1350  * \brief Get the index of a file in specified folder
1351  * \param fs a #CameraFilesystem
1352  * \param folder the folder where to look for file called filename
1353  * \param filename the file to look for
1354  * \param context a #GPContext
1355  *
1356  * Looks for a file called filename in the given folder. See
1357  * gp_filesystem_name for exactly the opposite functionality.
1358  *
1359  * \return a gphoto2 error code.
1360  **/
1361 int
1362 gp_filesystem_number (CameraFilesystem *fs, const char *folder,
1363                       const char *filename, GPContext *context)
1364 {
1365         CameraFilesystemFolder  *f;
1366         CameraFilesystemFile    *file;
1367         CameraList *list;
1368         int num;
1369
1370         CHECK_NULL (fs && folder && filename);
1371         CC (context);
1372         CA (folder, context);
1373
1374         f = lookup_folder (fs, fs->rootfolder, folder, context);
1375         if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1376
1377         file = f->files;
1378         num = 0;
1379         while (file) {
1380                 if (!strcmp (file->name, filename))
1381                         return num;
1382                 num++;
1383                 file = file->next;
1384         }
1385
1386         /* Ok, we didn't find the file. Is the folder dirty? */
1387         if (!f->files_dirty) {
1388                 gp_context_error (context, _("File '%s' could not be found "
1389                         "in folder '%s'."), filename, folder);
1390                 return (GP_ERROR_FILE_NOT_FOUND);
1391         }
1392         /* The folder is dirty. List all files to make it clean */
1393         CR (gp_list_new(&list));
1394         CL (gp_filesystem_list_files (fs, folder, list, context), list);
1395         gp_list_free(list);
1396         return (gp_filesystem_number (fs, folder, filename, context));
1397 }
1398
1399 static int
1400 gp_filesystem_scan (CameraFilesystem *fs, const char *folder,
1401                     const char *filename, GPContext *context)
1402 {
1403         int count, x;
1404         CameraList *list;
1405         const char *name;
1406         char path[128];
1407
1408         gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Scanning %s for %s...",
1409                 folder, filename);
1410
1411         CHECK_NULL (fs && folder && filename);
1412         CC (context);
1413         CA (folder, context);
1414
1415         CR (gp_list_new (&list));
1416         CL (gp_filesystem_list_files (fs, folder, list, context), list);
1417         CL (count = gp_list_count (list), list);
1418         for (x = 0; x < count; x++) {
1419                 CL (gp_list_get_name (list, x, &name), list);
1420                 if (!strcmp (filename, name)) {
1421                         gp_list_free (list);
1422                         return (GP_OK);
1423                 }
1424         }
1425
1426         CL (gp_filesystem_list_folders (fs, folder, list, context), list);
1427         CL (count = gp_list_count (list), list);
1428         for (x = 0; x < count; x++) {
1429                 CL (gp_list_get_name (list, x, &name), list);
1430                 strncpy (path, folder, sizeof (path));
1431                 if (path[strlen (path) - 1] != '/')
1432                         strncat (path, "/", sizeof (path) - strlen (path) - 1);
1433                 strncat (path, name, sizeof (path) - strlen (path) - 1);
1434                 CL (gp_filesystem_scan (fs, path, filename, context), list);
1435         }
1436         gp_list_free (list);
1437         return (GP_OK);
1438 }
1439
1440 static int
1441 recursive_folder_scan (
1442         CameraFilesystemFolder *folder, const char *lookforfile,
1443         char **foldername
1444 ) {
1445         CameraFilesystemFile    *file;
1446         CameraFilesystemFolder  *f;
1447         int ret;
1448
1449         file = folder->files;
1450         while (file) {
1451                 if (!strcmp(file->name, lookforfile)) {
1452                         *foldername = strdup (folder->name);
1453                         return GP_OK;
1454                 }
1455                 file = file->next;
1456         }
1457         f = folder->folders;
1458         while (f) {
1459                 char *xfolder;
1460                 ret = recursive_folder_scan (f, lookforfile, &xfolder);
1461                 if (ret == GP_OK) {
1462                         (*foldername) = malloc (strlen (folder->name) + 1 + strlen (xfolder) + 1);
1463                         strcpy ((*foldername),folder->name);
1464                         strcat ((*foldername),"/");
1465                         strcat ((*foldername),xfolder);
1466                         free (xfolder);
1467                         return GP_OK;
1468                 }
1469                 f = f->next;
1470         }
1471         /* thorugh all subfoilders */
1472         return GP_ERROR_FILE_NOT_FOUND;
1473 }
1474 /**
1475  * \brief Search a folder that contains a given filename
1476  * \param fs a #CameraFilesystem
1477  * \param filename the name of the file to search in the fs
1478  * \param folder pointer to value where the string is stored in
1479  * \param context a #GPContext
1480  *
1481  * Searches a file called filename in the fs and returns the first
1482  * occurrency. This functionality is needed for camera drivers that cannot
1483  * figure out where a file gets created after capturing an image although the
1484  * name of the image is known. Usually, those drivers will call
1485  * gp_filesystem_reset in order to tell the fs that something has
1486  * changed and then gp_filesystem_get_folder in order to find the file.
1487  *
1488  * Note that you get a reference to the string stored in the filesystem structure,
1489  * so do not free it yourself.
1490  *
1491  * \return a gphoto2 error code.
1492  **/
1493 int
1494 gp_filesystem_get_folder (CameraFilesystem *fs, const char *filename,
1495                           const char **folder, GPContext *context)
1496 {
1497         int ret;
1498
1499         CHECK_NULL (fs && filename && folder);
1500         CC (context);
1501
1502         CR (gp_filesystem_scan (fs, "/", filename, context));
1503
1504         ret = recursive_folder_scan ( fs->rootfolder, filename, folder);
1505         if (ret == GP_OK) return ret;
1506         gp_context_error (context, _("Could not find file '%s'."), filename);
1507         return (GP_ERROR_FILE_NOT_FOUND);
1508 }
1509
1510 /**
1511  * \brief Set the functions to list folders and files
1512  * \param fs a #CameraFilesystem
1513  * \param file_list_func the function that will return listings of files
1514  * \param folder_list_func the function that will return listings of folders
1515  * \param data private data structure
1516  *
1517  * Tells the fs which functions to use to retrieve listings of folders
1518  * and/or files. Typically, a camera driver would call this function
1519  * on initialization. Each function can be NULL indicating that this
1520  * functionality is not supported. For example, many cameras don't support
1521  * folders. In this case, you would supply NULL for folder_list_func. Then,
1522  * the fs assumes that there is only a root folder.
1523  *
1524  * \return a gphoto2 error code.
1525  **/
1526 int
1527 gp_filesystem_set_list_funcs (CameraFilesystem *fs,
1528                               CameraFilesystemListFunc file_list_func,
1529                               CameraFilesystemListFunc folder_list_func,
1530                               void *data)
1531 {
1532         CHECK_NULL (fs);
1533
1534         fs->file_list_func = file_list_func;
1535         fs->folder_list_func = folder_list_func;
1536         fs->list_data = data;
1537
1538         return (GP_OK);
1539 }
1540
1541 /**
1542  * \brief Set camera filesystem file related functions
1543  * \param fs a #CameraFilesystem
1544  * \param get_file_func the function downloading files
1545  * \param del_file_func the function deleting files
1546  * \param data private data structure
1547  *
1548  * Tells the fs which functions to use for file download or file deletion.
1549  * Typically, a camera driver would call this function on initialization.
1550  * A function can be NULL indicating that this functionality is not supported.
1551  * For example, if a camera does not support file deletion, you would supply
1552  * NULL for del_file_func.
1553  *
1554  * \return a gphoto2 error code.
1555  **/
1556 int
1557 gp_filesystem_set_file_funcs (CameraFilesystem *fs,
1558                               CameraFilesystemGetFileFunc get_file_func,
1559                               CameraFilesystemDeleteFileFunc del_file_func,
1560                               void *data)
1561 {
1562         CHECK_NULL (fs);
1563
1564         fs->delete_file_func = del_file_func;
1565         fs->get_file_func = get_file_func;
1566         fs->file_data = data;
1567
1568         return (GP_OK);
1569 }
1570
1571 /**
1572  * \brief Set folder related functions of the filesystem
1573  * \param fs a #CameraFilesystem
1574  * \param put_file_func function used to upload files
1575  * \param delete_all_func function used to delete all files in a folder
1576  * \param make_dir_func function used to create a new directory
1577  * \param remove_dir_func function used to remove an existing directory
1578  * \param data a data object that will passed to all called functions
1579  *
1580  * Tells the filesystem which functions to call for file upload, deletion
1581  * of all files in a given folder, creation or removal of a folder.
1582  * Typically, a camera driver would call this function on initialization.
1583  * If one functionality is not supported, NULL can be supplied.
1584  * If you don't call this function, the fs will assume that neither
1585  * of these features is supported.
1586  *
1587  * The fs will try to compensate missing delete_all_func
1588  * functionality with the delete_file_func if such a function has been
1589  * supplied.
1590  *
1591  * \return a gphoto2 error code.
1592  **/
1593 int
1594 gp_filesystem_set_folder_funcs (CameraFilesystem *fs,
1595                                 CameraFilesystemPutFileFunc put_file_func,
1596                                 CameraFilesystemDeleteAllFunc delete_all_func,
1597                                 CameraFilesystemDirFunc make_dir_func,
1598                                 CameraFilesystemDirFunc remove_dir_func,
1599                                 void *data)
1600 {
1601         CHECK_NULL (fs);
1602
1603         fs->put_file_func = put_file_func;
1604         fs->delete_all_func = delete_all_func;
1605         fs->make_dir_func = make_dir_func;
1606         fs->remove_dir_func = remove_dir_func;
1607         fs->folder_data = data;
1608
1609         return (GP_OK);
1610 }
1611
1612 static int
1613 gp_filesystem_get_file_impl (CameraFilesystem *fs, const char *folder,
1614                              const char *filename, CameraFileType type,
1615                              CameraFile *file, GPContext *context)
1616 {
1617         CameraFilesystemFolder  *xfolder;
1618         CameraFilesystemFile    *xfile;
1619
1620         CHECK_NULL (fs && folder && file && filename);
1621         CC (context);
1622         CA (folder, context);
1623
1624         GP_DEBUG ("Getting file '%s' from folder '%s' (type %i)...",
1625                   filename, folder, type);
1626
1627         CR (gp_file_set_type (file, type));
1628         CR (gp_file_set_name (file, filename));
1629
1630         if (!fs->get_file_func) {
1631                 gp_context_error (context,
1632                         _("The filesystem doesn't support getting files"));
1633                 return (GP_ERROR_NOT_SUPPORTED);
1634         }
1635
1636         /* Search folder and file */
1637         CR( lookup_folder_file (fs, folder, filename, &xfolder, &xfile, context));
1638
1639         switch (type) {
1640         case GP_FILE_TYPE_PREVIEW:
1641                 if (xfile->preview)
1642                         return (gp_file_copy (file, xfile->preview));
1643                 break;
1644         case GP_FILE_TYPE_NORMAL:
1645                 if (xfile->normal)
1646                         return (gp_file_copy (file, xfile->normal));
1647                 break;
1648         case GP_FILE_TYPE_RAW:
1649                 if (xfile->raw)
1650                         return (gp_file_copy (file, xfile->raw));
1651                 break;
1652         case GP_FILE_TYPE_AUDIO:
1653                 if (xfile->audio)
1654                         return (gp_file_copy (file, xfile->audio));
1655                 break;
1656         case GP_FILE_TYPE_EXIF:
1657                 if (xfile->exif)
1658                         return (gp_file_copy (file, xfile->exif));
1659                 break;
1660         case GP_FILE_TYPE_METADATA:
1661                 if (xfile->metadata)
1662                         return (gp_file_copy (file, xfile->metadata));
1663                 break;
1664         default:
1665                 gp_context_error (context, _("Unknown file type %i."), type);
1666                 return (GP_ERROR);
1667         }
1668
1669         gp_context_status (context, _("Downloading '%s' from folder '%s'..."),
1670                            filename, folder);
1671         CR (fs->get_file_func (fs, folder, filename, type, file,
1672                                fs->file_data, context));
1673
1674         /* We don't trust the camera drivers */
1675         CR (gp_file_set_type (file, type));
1676         CR (gp_file_set_name (file, filename));
1677
1678 #if 0
1679         /* this disables LRU completely. */
1680         /* Cache this file */
1681         CR (gp_filesystem_set_file_noop (fs, folder, file, context));
1682 #endif
1683
1684         /*
1685          * Often, thumbnails are of a different mime type than the normal
1686          * picture. In this case, we should rename the file.
1687          */
1688         if (type != GP_FILE_TYPE_NORMAL)
1689                 CR (gp_file_adjust_name_for_mime_type (file));
1690
1691         return (GP_OK);
1692 }
1693
1694 /**
1695  * \brief Get file data from the filesystem
1696  * \param fs a #CameraFilesystem
1697  * \param folder the folder in which the file can be found
1698  * \param filename the name of the file to download
1699  * \param type the type of the file
1700  * \param file the file that receives the data
1701  * \param context a #GPContext
1702  *
1703  * Downloads the file called filename from the folder using the
1704  * get_file_func if such a function has been previously supplied. If the
1705  * file has been previously downloaded, the file is retrieved from cache.
1706  * The result is stored in the passed file structure.
1707  *
1708  * \return a gphoto2 error code.
1709  **/
1710 int
1711 gp_filesystem_get_file (CameraFilesystem *fs, const char *folder,
1712                         const char *filename, CameraFileType type,
1713                         CameraFile *file, GPContext *context)
1714 {
1715         int r;
1716 #ifdef HAVE_LIBEXIF
1717         CameraFile *efile;
1718         const char *data = NULL;
1719         unsigned char *buf;
1720         unsigned int buf_size;
1721         unsigned long int size = 0;
1722         ExifData *ed;
1723 #endif
1724
1725         r = gp_filesystem_get_file_impl (fs, folder, filename, type,
1726                                          file, context);
1727
1728         if ((r == GP_ERROR_NOT_SUPPORTED) &&
1729             (type == GP_FILE_TYPE_PREVIEW)) {
1730
1731                 /*
1732                  * Could not get preview (unsupported operation). Some
1733                  * cameras hide the thumbnail in EXIF data. Check it out.
1734                  */
1735 #ifdef HAVE_LIBEXIF
1736                 GP_DEBUG ("Getting previews is not supported. Trying "
1737                           "EXIF data...");
1738                 CR (gp_file_new (&efile));
1739                 CU (gp_filesystem_get_file_impl (fs, folder, filename,
1740                                 GP_FILE_TYPE_EXIF, efile, context), efile);
1741                 CU (gp_file_get_data_and_size (efile, &data, &size), efile);
1742                 ed = exif_data_new_from_data ((unsigned char*)data, size);
1743                 gp_file_unref (efile);
1744                 if (!ed) {
1745                         GP_DEBUG ("Could not parse EXIF data of "
1746                                 "'%s' in folder '%s'.", filename, folder);
1747                         return (GP_ERROR_CORRUPTED_DATA);
1748                 }
1749                 if (!ed->data) {
1750                         GP_DEBUG ("EXIF data does not contain a thumbnail.");
1751                         exif_data_unref (ed);
1752                         return (r);
1753                 }
1754
1755                 /*
1756                  * We found a thumbnail in EXIF data! Those
1757                  * thumbnails are always JPEG. Set up the file.
1758                  */
1759                 r = gp_file_set_data_and_size (file, (char*)ed->data, ed->size);
1760                 if (r < 0) {
1761                         exif_data_unref (ed);
1762                         return (r);
1763                 }
1764                 ed->data = NULL;
1765                 ed->size = 0;
1766                 exif_data_unref (ed);
1767                 CR (gp_file_set_type (file, GP_FILE_TYPE_PREVIEW));
1768                 CR (gp_file_set_name (file, filename));
1769                 CR (gp_file_set_mime_type (file, GP_MIME_JPEG));
1770                 CR (gp_filesystem_set_file_noop (fs, folder, file, context));
1771                 CR (gp_file_adjust_name_for_mime_type (file));
1772 #else
1773                 GP_DEBUG ("Getting previews is not supported and "
1774                         "libgphoto2 has been compiled without exif "
1775                         "support. ");
1776                 return (r);
1777 #endif
1778         } else if ((r == GP_ERROR_NOT_SUPPORTED) &&
1779                    (type == GP_FILE_TYPE_EXIF)) {
1780
1781                 /*
1782                  * Some cameras hide EXIF data in thumbnails (!). Check it
1783                  * out.
1784                  */
1785 #ifdef HAVE_LIBEXIF
1786                 GP_DEBUG ("Getting EXIF data is not supported. Trying "
1787                           "thumbnail...");
1788                 CR (gp_file_new (&efile));
1789                 CU (gp_filesystem_get_file_impl (fs, folder, filename,
1790                                 GP_FILE_TYPE_PREVIEW, efile, context), efile);
1791                 CU (gp_file_get_data_and_size (efile, &data, &size), efile);
1792                 ed = exif_data_new_from_data ((unsigned char*)data, size);
1793                 gp_file_unref (efile);
1794                 if (!ed) {
1795                         GP_DEBUG ("Could not parse EXIF data of thumbnail of "
1796                                 "'%s' in folder '%s'.", filename, folder);
1797                         return (GP_ERROR_CORRUPTED_DATA);
1798                 }
1799                 exif_data_save_data (ed, &buf, &buf_size);
1800                 exif_data_unref (ed);
1801                 r = gp_file_set_data_and_size (file, (char*)buf, buf_size);
1802                 if (r < 0) {
1803                         free (buf);
1804                         return (r);
1805                 }
1806                 CR (gp_file_set_type (file, GP_FILE_TYPE_EXIF));
1807                 CR (gp_file_set_name (file, filename));
1808                 CR (gp_file_set_mime_type (file, GP_MIME_EXIF));
1809                 CR (gp_filesystem_set_file_noop (fs, folder, file, context));
1810                 CR (gp_file_adjust_name_for_mime_type (file));
1811 #else
1812                 GP_DEBUG ("Getting EXIF data is not supported and libgphoto2 "
1813                         "has been compiled without EXIF support.");
1814                 return (r);
1815 #endif
1816         } else if (r < 0) {
1817                 GP_DEBUG ("Download of '%s' from '%s' (type %i) failed. "
1818                         "Reason: '%s'", filename, folder, type,
1819                         gp_result_as_string (r));
1820                 return (r);
1821         }
1822
1823         return (GP_OK);
1824 }
1825
1826 /**
1827  * \brief Set file information functions
1828  * \param fs a #CameraFilesystem
1829  * \param get_info_func the function to retrieve file information
1830  * \param set_info_func the function to set file information
1831  * \param data private data
1832  *
1833  * Tells the filesystem which functions to call when file information
1834  * about a file should be retrieved or set. Typically, this function will
1835  * get called by the camera driver on initialization.
1836  *
1837  * \return a gphoto2 error code.
1838  **/
1839 int
1840 gp_filesystem_set_info_funcs (CameraFilesystem *fs,
1841                               CameraFilesystemGetInfoFunc get_info_func,
1842                               CameraFilesystemSetInfoFunc set_info_func,
1843                               void *data)
1844 {
1845         CHECK_NULL (fs);
1846
1847         fs->get_info_func = get_info_func;
1848         fs->set_info_func = set_info_func;
1849         fs->info_data = data;
1850
1851         return (GP_OK);
1852 }
1853
1854 /**
1855  * \brief Set all filesystem related function pointers
1856  * \param fs a #CameraFilesystem
1857  * \param funcs pointer to a struct of filesystem functions
1858  * \param data private data
1859  *
1860  * Tells the filesystem which functions to call for camera/filesystem specific
1861  * functions, like listing, retrieving, uploading files and so on.
1862  *
1863  * \return a gphoto2 error code.
1864  **/
1865 int
1866 gp_filesystem_set_funcs (CameraFilesystem *fs,
1867                          CameraFilesystemFuncs *funcs,
1868                          void *data)
1869 {
1870         CHECK_NULL (fs);
1871
1872         fs->get_info_func       = funcs->get_info_func;
1873         fs->set_info_func       = funcs->set_info_func;
1874         fs->info_data = data;
1875
1876         fs->put_file_func       = funcs->put_file_func;
1877         fs->delete_all_func     = funcs->delete_all_func;
1878         fs->make_dir_func       = funcs->make_dir_func;
1879         fs->remove_dir_func     = funcs->remove_dir_func;
1880         fs->folder_data = data;
1881
1882         fs->file_list_func      = funcs->file_list_func;
1883         fs->folder_list_func    = funcs->folder_list_func;
1884         fs->list_data = data;
1885
1886         fs->delete_file_func    = funcs->del_file_func;
1887         fs->get_file_func       = funcs->get_file_func;
1888         fs->file_data = data;
1889
1890         fs->storage_info_func   = funcs->storage_info_func;
1891         return (GP_OK);
1892 }
1893
1894 /**
1895  * \brief Get information about the specified file
1896  * \param fs a #CameraFilesystem
1897  * \param folder the folder that contains the file
1898  * \param filename the filename
1899  * \param info pointer to #CameraFileInfo that receives the information
1900  * \param context a #GPContext
1901  *
1902  * \return a gphoto2 error code.
1903  **/
1904 int
1905 gp_filesystem_get_info (CameraFilesystem *fs, const char *folder,
1906                         const char *filename, CameraFileInfo *info,
1907                         GPContext *context)
1908 {
1909         CameraFilesystemFolder  *f;
1910         CameraFilesystemFile    *file;
1911 #ifdef HAVE_LIBEXIF
1912         time_t t;
1913 #endif
1914
1915         CHECK_NULL (fs && folder && filename && info);
1916         CC (context);
1917         CA (folder, context);
1918
1919         GP_DEBUG ("Getting information about '%s' in '%s'...", filename,
1920                   folder);
1921
1922         if (!fs->get_info_func) {
1923                 gp_context_error (context,
1924                         _("The filesystem doesn't support getting file "
1925                           "information"));
1926                 return (GP_ERROR_NOT_SUPPORTED);
1927         }
1928
1929         /* Search folder and file and get info if needed */
1930         CR ( lookup_folder_file (fs, folder, filename, &f, &file, context));
1931
1932         if (file->info_dirty) {
1933                 CR (fs->get_info_func (fs, folder, filename,
1934                                                 &file->info,
1935                                                 fs->info_data, context));
1936                 file->info_dirty = 0;
1937         }
1938
1939         /*
1940          * If we didn't get GP_FILE_INFO_MTIME, we'll have a look if we
1941          * can get it from EXIF data.
1942          */
1943 #ifdef HAVE_LIBEXIF
1944         if (!(file->info.file.fields & GP_FILE_INFO_MTIME)) {
1945                 GP_DEBUG ("Did not get mtime. Trying EXIF information...");
1946                 t = gp_filesystem_get_exif_mtime (fs, folder, filename);
1947                 if (t) {
1948                         file->info.file.mtime = t;
1949                         file->info.file.fields |= GP_FILE_INFO_MTIME;
1950                 }
1951         }
1952 #endif
1953         memcpy (info, &file->info, sizeof (CameraFileInfo));
1954         return (GP_OK);
1955 }
1956
1957 static int
1958 gp_filesystem_lru_clear (CameraFilesystem *fs)
1959 {
1960         int n = 0;
1961         CameraFilesystemFile *ptr, *prev;
1962
1963         GP_DEBUG ("Clearing fscache LRU list...");
1964
1965         if (fs->lru_first == NULL) {
1966                 GP_DEBUG ("fscache LRU list already empty");
1967                 return (GP_OK);
1968         }
1969
1970         ptr = prev = fs->lru_first;
1971         while (ptr != NULL) {
1972                 n++;
1973                 if (ptr->lru_prev != prev) {
1974                         GP_DEBUG ("fscache LRU list corrupted (%i)", n);
1975                         return (GP_ERROR);
1976                 }
1977                 prev = ptr;
1978                 ptr = ptr->lru_next;
1979
1980                 prev->lru_prev = NULL;
1981                 prev->lru_next = NULL;
1982         }
1983
1984         fs->lru_first = NULL;
1985         fs->lru_last = NULL;
1986         fs->lru_size = 0;
1987
1988         GP_DEBUG ("fscache LRU list cleared (removed %i items)", n);
1989
1990         return (GP_OK);
1991 }
1992
1993 static int
1994 gp_filesystem_lru_remove_one (CameraFilesystem *fs, CameraFilesystemFile *item)
1995 {
1996         if (item->lru_prev == NULL)
1997                 return (GP_ERROR);
1998
1999         /* Update the prev and next pointers. */
2000         if (item->lru_prev) item->lru_prev->lru_next = item->lru_next;
2001         if (item->lru_next) item->lru_next->lru_prev = item->lru_prev;
2002         if (fs->lru_last == item) {
2003                 if (fs->lru_first == item) {
2004
2005                         /*
2006                          * Case 1: ITEM is the only one in the list. We'll
2007                          * remove it, and the list will be empty afterwards.
2008                          */
2009                         fs->lru_last  = NULL;
2010                         fs->lru_first = NULL;
2011                 } else {
2012
2013                         /* Case 2: ITEM is the last in the list. */
2014                         fs->lru_last = item->lru_prev;
2015                 }
2016         } else if (fs->lru_first == item) {
2017
2018                 /* Case 3: ITEM is the first in the list. */
2019                 fs->lru_first = item->lru_next;
2020                 /* the first item prev links back to itself */
2021                 fs->lru_first->lru_prev = fs->lru_first;
2022         }
2023
2024         /* Clear the pointers */
2025         item->lru_prev = NULL;
2026         item->lru_next = NULL;
2027
2028         return (GP_OK);
2029 }
2030
2031 static int
2032 gp_filesystem_lru_free (CameraFilesystem *fs)
2033 {
2034         CameraFilesystemFile *ptr;
2035         unsigned long int size;
2036
2037         CHECK_NULL (fs && fs->lru_first);
2038
2039         ptr = fs->lru_first;
2040
2041         GP_DEBUG ("Freeing cached data for file '%s'...", ptr->name);
2042
2043         /* Remove it from the list. */
2044         fs->lru_first = ptr->lru_next;
2045         if (fs->lru_first)
2046                 fs->lru_first->lru_prev = fs->lru_first;
2047         else
2048                 fs->lru_last = NULL;
2049
2050         /* Free its content. */
2051         if (ptr->normal) {
2052                 CR( gp_file_get_data_and_size (ptr->normal, NULL, &size));
2053                 fs->lru_size -= size;
2054                 gp_file_unref (ptr->normal);
2055                 ptr->normal = NULL;
2056         }
2057         if (ptr->raw) {
2058                 CR( gp_file_get_data_and_size (ptr->raw, NULL, &size));
2059                 fs->lru_size -= size;
2060                 gp_file_unref (ptr->raw);
2061                 ptr->raw = NULL;
2062         }
2063         if (ptr->audio) {
2064                 CR( gp_file_get_data_and_size (ptr->audio, NULL, &size));
2065                 fs->lru_size -= size;
2066                 gp_file_unref (ptr->audio);
2067                 ptr->audio = NULL;
2068         }
2069         ptr->lru_next = ptr->lru_prev = NULL;
2070         return (GP_OK);
2071 }
2072
2073 static int
2074 gp_filesystem_lru_count (CameraFilesystem *fs)
2075 {
2076         CameraFilesystemFile *ptr;
2077         int count = 0;
2078
2079         if (!fs) return 0;
2080         ptr = fs->lru_first;
2081         while (ptr) {
2082                 if (ptr->normal || ptr->raw || ptr->audio)
2083                         count++;
2084                 ptr = ptr->lru_next;
2085         }
2086         return count;
2087 }
2088
2089 static int
2090 gp_filesystem_lru_update (CameraFilesystem *fs, const char *folder,
2091                           CameraFile *file, GPContext *context)
2092 {
2093         CameraFilesystemFolder  *f;
2094         CameraFilesystemFile    *xfile;
2095         CameraFileType type;
2096         CameraFile *oldfile = NULL;
2097         const char *filename;
2098         unsigned long int size;
2099         int x;
2100         char cached_images[1024];
2101
2102         CHECK_NULL (fs && folder && file);
2103
2104         CR (gp_file_get_name (file, &filename));
2105         CR (gp_file_get_type (file, &type));
2106         CR (gp_file_get_data_and_size (file, NULL, &size));
2107
2108         /*
2109          * The following is a very simple case which is used to prune
2110          * the LRU. We keep PICTURES_TO_KEEP pictures in the LRU.
2111          *
2112          * We have 2 main scenarios:
2113          *      - query all thumbnails (repeatedly) ... they are cached and
2114          *        are not pruned by lru free.
2115          *      - download all images, linear.  no real need for caching.
2116          *      - skip back 1 image (in viewers) (really? I don't know.)
2117          *
2118          * So lets just keep 2 pictures in memory.
2119          */
2120         if (pictures_to_keep == -1) {
2121                 if (gp_setting_get ("libgphoto", "cached-images", cached_images) == GP_OK) {
2122                         pictures_to_keep = atoi(cached_images);
2123                 } else {
2124                         /* store a default setting */
2125                         sprintf (cached_images, "%d", PICTURES_TO_KEEP);
2126                         gp_setting_set ("libgphoto", "cached-images", cached_images);
2127                 }
2128         }
2129
2130         if (pictures_to_keep < 0) /* also sanity check, but no upper limit. */
2131                 pictures_to_keep = PICTURES_TO_KEEP;
2132
2133         x = gp_filesystem_lru_count (fs);
2134         while (x > pictures_to_keep) {
2135                 CR (gp_filesystem_lru_free (fs));
2136                 x = gp_filesystem_lru_count (fs);
2137         }
2138
2139         GP_DEBUG ("Adding file '%s' from folder '%s' to the fscache LRU list "
2140                   "(type %i)...", filename, folder, type);
2141
2142         /* Search folder and file */
2143         CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2144
2145         /*
2146          * If the file is already in the lru, we first remove it. Note that
2147          * we will only remove 'normal', 'raw' and 'audio' from cache.
2148          * See gp_filesystem_lru_free.
2149          */
2150         if (xfile->lru_prev != NULL) {
2151                 switch (type) {
2152                 case GP_FILE_TYPE_NORMAL:
2153                         oldfile = xfile->normal;
2154                         break;
2155                 case GP_FILE_TYPE_RAW:
2156                         oldfile = xfile->raw;
2157                         break;
2158                 case GP_FILE_TYPE_AUDIO:
2159                         oldfile = xfile->audio;
2160                         break;
2161                 case GP_FILE_TYPE_PREVIEW:
2162                 case GP_FILE_TYPE_EXIF:
2163                 case GP_FILE_TYPE_METADATA:
2164                         break;
2165                 default:
2166                         gp_context_error (context, _("Unknown file type %i."),
2167                                           type);
2168                         return (GP_ERROR);
2169                 }
2170                 if (oldfile) {
2171                         CR( gp_file_get_data_and_size (oldfile, NULL, &size));
2172                         fs->lru_size -= size;
2173                 }
2174
2175                 CR (gp_filesystem_lru_remove_one (fs, xfile));
2176         }
2177
2178         /* Then add the file at the end of the LRU. */
2179         if (fs->lru_first == NULL) {
2180                 fs->lru_first = xfile;
2181                 fs->lru_last = xfile;
2182
2183                 /*
2184                  * For the first item, prev point it itself to show that the
2185                  * item is in the list.
2186                  */
2187                 xfile->lru_prev = xfile;
2188
2189         } else {
2190                 xfile->lru_next = NULL;
2191                 xfile->lru_prev = fs->lru_last;
2192                 fs->lru_last->lru_next = xfile;
2193                 fs->lru_last = xfile;
2194         }
2195
2196         CR( gp_file_get_data_and_size (file, NULL, &size));
2197         fs->lru_size += size;
2198
2199         GP_DEBUG ("File '%s' from folder '%s' added in fscache LRU list.",
2200                   filename, folder);
2201
2202         return (GP_OK);
2203 }
2204
2205 static int
2206 gp_filesystem_lru_check (CameraFilesystem *fs)
2207 {
2208         int n = 0;
2209         CameraFilesystemFile *ptr, *prev;
2210
2211         GP_DEBUG ("Checking fscache LRU list integrity...");
2212
2213         if (fs->lru_first == NULL) {
2214                 GP_DEBUG ("fscache LRU list empty");
2215                 return (GP_OK);
2216         }
2217
2218         ptr = prev = fs->lru_first;
2219         while (ptr != NULL) {
2220                 n++;
2221                 if (ptr->lru_prev != prev) {
2222                         GP_DEBUG ("fscache LRU list corrupted (%i)", n);
2223                         return (GP_ERROR);
2224                 }
2225                 prev = ptr;
2226                 ptr = ptr->lru_next;
2227         }
2228
2229         GP_DEBUG ("fscache LRU list ok with %i items (%ld bytes)", n,
2230                   fs->lru_size);
2231
2232         return (GP_OK);
2233 }
2234
2235 /**
2236  * \brief Attach file content to a specified file.
2237  *
2238  * \param fs a #CameraFilesystem
2239  * \param folder a folder in the filesystem
2240  * \param file a #CameraFile
2241  * \param context: a #GPContext
2242  *
2243  * Tells the fs about a file. Typically, camera drivers will call this
2244  * function in case they get information about a file (i.e. preview) "for free"
2245  * on gp_camera_capture() or gp_camera_folder_list_files().
2246  *
2247  * \return a gphoto2 error code.
2248  **/
2249 int
2250 gp_filesystem_set_file_noop (CameraFilesystem *fs, const char *folder,
2251                              CameraFile *file, GPContext *context)
2252 {
2253         CameraFileType type;
2254         CameraFileInfo info;
2255         CameraFilesystemFolder  *f;
2256         CameraFilesystemFile    *xfile;
2257         const char *filename;
2258         int r;
2259         time_t t;
2260
2261         CHECK_NULL (fs && folder && file);
2262         CC (context);
2263         CA (folder, context);
2264
2265         CR (gp_file_get_name (file, &filename));
2266         CR (gp_file_get_type (file, &type));
2267         GP_DEBUG ("Adding file '%s' to folder '%s' (type %i)...",
2268                   filename, folder, type);
2269
2270         /* Search folder and file */
2271         CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2272
2273         /*
2274          * If we add a significant amount of data in the cache, we put (or
2275          * move) a reference to this file in the LRU linked list. We
2276          * assume that only GP_FILE_TYPE_[RAW,NORMAL,EXIF] will contain a
2277          * significant amount of data.
2278          */
2279         if ((type == GP_FILE_TYPE_RAW) || (type == GP_FILE_TYPE_NORMAL) ||
2280             (type == GP_FILE_TYPE_AUDIO))
2281                 CR (gp_filesystem_lru_update (fs, folder, file, context));
2282
2283         /* Redundant sanity check. */
2284         CR (gp_filesystem_lru_check (fs));
2285
2286         switch (type) {
2287         case GP_FILE_TYPE_PREVIEW:
2288                 if (xfile->preview)
2289                         gp_file_unref (xfile->preview);
2290                 xfile->preview = file;
2291                 gp_file_ref (file);
2292                 break;
2293         case GP_FILE_TYPE_NORMAL:
2294                 if (xfile->normal)
2295                         gp_file_unref (xfile->normal);
2296                 xfile->normal = file;
2297                 gp_file_ref (file);
2298                 break;
2299         case GP_FILE_TYPE_RAW:
2300                 if (xfile->raw)
2301                         gp_file_unref (xfile->raw);
2302                 xfile->raw = file;
2303                 gp_file_ref (file);
2304                 break;
2305         case GP_FILE_TYPE_AUDIO:
2306                 if (xfile->audio)
2307                         gp_file_unref (xfile->audio);
2308                 xfile->audio = file;
2309                 gp_file_ref (file);
2310                 break;
2311         case GP_FILE_TYPE_EXIF:
2312                 if (xfile->exif)
2313                         gp_file_unref (xfile->exif);
2314                 xfile->exif = file;
2315                 gp_file_ref (file);
2316                 break;
2317         case GP_FILE_TYPE_METADATA:
2318                 if (xfile->metadata)
2319                         gp_file_unref (xfile->metadata);
2320                 xfile->metadata = file;
2321                 gp_file_ref (file);
2322                 break;
2323         default:
2324                 gp_context_error (context, _("Unknown file type %i."), type);
2325                 return (GP_ERROR);
2326         }
2327
2328         /*
2329          * If we didn't get a mtime, try to get it from the CameraFileInfo.
2330          */
2331         CR (gp_file_get_mtime (file, &t));
2332         if (!t) {
2333                 GP_DEBUG ("File does not contain mtime. Trying "
2334                           "information on the file...");
2335                 r = gp_filesystem_get_info (fs, folder, filename, &info, NULL);
2336                 if ((r == GP_OK) && (info.file.fields & GP_FILE_INFO_MTIME))
2337                         t = info.file.mtime;
2338         }
2339
2340         /*
2341          * If we still don't have the mtime and this is a normal
2342          * file, check if there is EXIF data in the file that contains
2343          * information on the mtime.
2344          */
2345 #ifdef HAVE_LIBEXIF
2346         if (!t && (type == GP_FILE_TYPE_NORMAL)) {
2347                 unsigned long int size;
2348                 const char *data;
2349
2350                 GP_DEBUG ("Searching data for mtime...");
2351                 CR (gp_file_get_data_and_size (file, NULL, &size));
2352                 if (size < 32*1024*1024) { /* just assume stuff above 32MB is not EXIF capable */
2353                         /* FIXME: Will leak on "fd" retrieval */
2354                         CR (gp_file_get_data_and_size (file, &data, &size));
2355                         t = get_exif_mtime ((unsigned char*)data, size);
2356                 }
2357         }
2358         /*
2359          * Still no mtime? Let's see if the camera offers us data of type
2360          * GP_FILE_TYPE_EXIF that includes information on the mtime.
2361          */
2362         if (!t) {
2363                 GP_DEBUG ("Trying EXIF information...");
2364                 t = gp_filesystem_get_exif_mtime (fs, folder, filename);
2365         }
2366 #endif
2367
2368         if (t)
2369                 CR (gp_file_set_mtime (file, t));
2370
2371         return (GP_OK);
2372 }
2373
2374 /**
2375  * \brief Store the file information in the virtual fs
2376  * \param fs a #CameraFilesystem
2377  * \param folder the foldername
2378  * \param info the #CameraFileInfo to store
2379  * \param context a #GPContext
2380  *
2381  * In contrast to #gp_filesystem_set_info, #gp_filesystem_set_info_noop
2382  * will only change the file information in the fs. Typically, camera
2383  * drivers will use this function in case they get file information "for free"
2384  * on #gp_camera_capture or #gp_camera_folder_list_files.
2385  *
2386  * \return a gphoto2 error code
2387  **/
2388 int
2389 gp_filesystem_set_info_noop (CameraFilesystem *fs, const char *folder,
2390                              CameraFileInfo info, GPContext *context)
2391 {
2392         CameraFilesystemFolder  *f;
2393         CameraFilesystemFile    *xfile;
2394
2395         CHECK_NULL (fs && folder);
2396         CC (context);
2397         CA (folder, context);
2398
2399         /* Search folder and file */
2400         CR (lookup_folder_file (fs, folder, info.file.name, &f, &xfile, context));
2401
2402         memcpy (&xfile->info, &info, sizeof (CameraFileInfo));
2403         xfile->info_dirty = 0;
2404         return (GP_OK);
2405 }
2406
2407 /**
2408  * \brief Set information about a file
2409  * \param fs a #CameraFilesystem
2410  * \param folder foldername where the file resides
2411  * \param filename the files name
2412  * \param info the #CameraFileInfo to set
2413  * \param context a #GPContext
2414  *
2415  * Sets information about a file in the camera.
2416  *
2417  * \return a gphoto2 error code.
2418  **/
2419 int
2420 gp_filesystem_set_info (CameraFilesystem *fs, const char *folder,
2421                         const char *filename, CameraFileInfo info,
2422                         GPContext *context)
2423 {
2424         int result, name, e;
2425         CameraFilesystemFolder  *f;
2426         CameraFilesystemFile    *xfile;
2427
2428         CHECK_NULL (fs && folder && filename);
2429         CC (context);
2430         CA (folder, context);
2431
2432         if (!fs->set_info_func) {
2433                 gp_context_error (context,
2434                         _("The filesystem doesn't support setting file "
2435                           "information"));
2436                 return (GP_ERROR_NOT_SUPPORTED);
2437         }
2438
2439         /* Search folder and file */
2440         CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2441
2442         /* Check if people want to set read-only attributes */
2443         if ((info.file.fields    & GP_FILE_INFO_TYPE)   ||
2444             (info.file.fields    & GP_FILE_INFO_SIZE)   ||
2445             (info.file.fields    & GP_FILE_INFO_WIDTH)  ||
2446             (info.file.fields    & GP_FILE_INFO_HEIGHT) ||
2447             (info.file.fields    & GP_FILE_INFO_STATUS) ||
2448             (info.preview.fields & GP_FILE_INFO_TYPE)   ||
2449             (info.preview.fields & GP_FILE_INFO_SIZE)   ||
2450             (info.preview.fields & GP_FILE_INFO_WIDTH)  ||
2451             (info.preview.fields & GP_FILE_INFO_HEIGHT) ||
2452             (info.preview.fields & GP_FILE_INFO_STATUS) ||
2453             (info.audio.fields   & GP_FILE_INFO_TYPE)   ||
2454             (info.audio.fields   & GP_FILE_INFO_SIZE)   ||
2455             (info.audio.fields   & GP_FILE_INFO_STATUS)) {
2456                 gp_context_error (context, _("Read-only file attributes "
2457                         "like width and height can not be changed."));
2458                 return (GP_ERROR_BAD_PARAMETERS);
2459         }
2460
2461         /*
2462          * Set the info. If anything goes wrong, mark info as dirty,
2463          * because the operation could have been partially successful.
2464          *
2465          * Handle name changes in a separate round.
2466          */
2467         name = (info.file.fields & GP_FILE_INFO_NAME);
2468         info.file.fields &= ~GP_FILE_INFO_NAME;
2469         result = fs->set_info_func (fs, folder, filename, info, fs->info_data,
2470                                     context);
2471         if (result < 0) {
2472                 xfile->info_dirty = 1;
2473                 return (result);
2474         }
2475         if (info.file.fields & GP_FILE_INFO_PERMISSIONS)
2476                 xfile->info.file.permissions = info.file.permissions;
2477
2478         /* Handle name change */
2479         if (name) {
2480                 char *xname;
2481                 /* Make sure the file does not exist */
2482                 e = gp_filesystem_number (fs, folder, info.file.name, context);
2483                 if (e != GP_ERROR_FILE_NOT_FOUND)
2484                         return (e);
2485
2486                 info.preview.fields = GP_FILE_INFO_NONE;
2487                 info.file.fields = GP_FILE_INFO_NAME;
2488                 info.audio.fields = GP_FILE_INFO_NONE;
2489                 CR (fs->set_info_func (fs, folder, filename, info,
2490                                        fs->info_data, context));
2491                 strncpy (xfile->info.file.name, info.file.name,
2492                          sizeof (xfile->info.file.name));
2493                 xname = strdup(info.file.name);
2494                 if (xname) {
2495                         free (xfile->name);
2496                         xfile->name = xname;
2497                 }
2498         }
2499
2500         return (GP_OK);
2501 }
2502
2503 /**
2504  * \brief Get the storage information about this filesystem
2505  * \param fs the filesystem
2506  * \param storageinfo Pointer to receive a pointer to/array of storage info items
2507  * \param nrofstorageinfos Pointer to receive number of array entries
2508  * \param context a #GPContext
2509  *
2510  * This function is only called from gp_camera_get_storageinfo(). You may
2511  * want to make sure this information is consistent with the information on
2512  * gp_camera_get_storageinfo().
2513  *
2514  * Retrieves the storage information, like maximum and free space, for
2515  * the specified filesystem, if supported by the device. The storage
2516  * information is returned in an newly allocated array of
2517  * #CameraStorageInformation objects, to which the pointer pointed to
2518  * by #storageinfo will be set.
2519  *
2520  * The variable pointed to by #nrofstorageinfos will be set to the
2521  * number of elements in that array.
2522  *
2523  * It is the caller's responsibility to free the memory of the array.
2524  *
2525  * \return a gphoto error code
2526  **/
2527 int
2528 gp_filesystem_get_storageinfo (
2529         CameraFilesystem *fs,
2530         CameraStorageInformation **storageinfo,
2531         int *nrofstorageinfos,
2532         GPContext *context
2533 ) {
2534         CHECK_NULL (fs && storageinfo && nrofstorageinfos);
2535         CC (context);
2536
2537         if (!fs->storage_info_func) {
2538                 gp_context_error (context,
2539                         _("The filesystem doesn't support getting storage "
2540                           "information"));
2541                 return (GP_ERROR_NOT_SUPPORTED);
2542         }
2543         return fs->storage_info_func (fs,
2544                 storageinfo, nrofstorageinfos,
2545                 fs->info_data, context);
2546 }