libgphoto2 photo camera library (libgphoto2) Internals  2.5.23
gphoto2-filesys.c
Go to the documentation of this file.
1 
26 #define _DEFAULT_SOURCE
27 
28 #include "config.h"
30 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 
35 #include <gphoto2/gphoto2-result.h>
38 
39 #include <limits.h>
40 
41 #ifdef HAVE_LIBEXIF
42 # include <libexif/exif-data.h>
43 #endif
44 
45 #ifdef ENABLE_NLS
46 # include <libintl.h>
47 # undef _
48 # define _(String) dgettext (GETTEXT_PACKAGE, String)
49 # ifdef gettext_noop
50 # define N_(String) gettext_noop (String)
51 # else
52 # define N_(String) (String)
53 # endif
54 #else
55 # define textdomain(String) (String)
56 # define gettext(String) (String)
57 # define dgettext(Domain,Message) (Message)
58 # define dcgettext(Domain,Message,Type) (Message)
59 # define bindtextdomain(Domain,Directory) (Domain)
60 # define _(String) (String)
61 # define N_(String) (String)
62 #endif
63 
64 #ifndef PATH_MAX
65 # define PATH_MAX 4096
66 #endif
67 
68 typedef struct _CameraFilesystemFile {
69  char *name;
70 
72 
74 
83 
84  struct _CameraFilesystemFile *next; /* in folder */
86 
87 typedef struct _CameraFilesystemFolder {
88  char *name;
89 
92 
93  struct _CameraFilesystemFolder *next; /* chain in same folder */
94  struct _CameraFilesystemFolder *folders; /* childchain of this folder */
95  struct _CameraFilesystemFile *files; /* of this folder */
97 
102 #define PICTURES_TO_KEEP 2
103 
107 static int pictures_to_keep = -1;
108 
112  const char *folder, const char *filename,
113  CameraFileType type,
114  CameraFile *file, GPContext *context);
115 
116 #ifdef HAVE_LIBEXIF
117 
118 static int gp_filesystem_get_file_impl (CameraFilesystem *, const char *,
119  const char *, CameraFileType, CameraFile *, GPContext *);
120 
121 static time_t
122 get_time_from_exif_tag(ExifEntry *e) {
123  struct tm ts;
124 
125  e->data[4] = e->data[ 7] = e->data[10] = e->data[13] = e->data[16] = 0;
126  ts.tm_year = atoi ((char*)e->data) - 1900;
127  ts.tm_mon = atoi ((char*)(e->data + 5)) - 1;
128  ts.tm_mday = atoi ((char*)(e->data + 8));
129  ts.tm_hour = atoi ((char*)(e->data + 11));
130  ts.tm_min = atoi ((char*)(e->data + 14));
131  ts.tm_sec = atoi ((char*)(e->data + 17));
132 
133  return mktime (&ts);
134 }
135 
136 static time_t
137 get_exif_mtime (const unsigned char *data, unsigned long size)
138 {
139  ExifData *ed;
140  ExifEntry *e;
141  time_t t, t1 = 0, t2 = 0, t3 = 0;
142 
143  ed = exif_data_new_from_data (data, size);
144  if (!ed) {
145  GP_LOG_E ("Could not parse data for EXIF information.");
146  return 0;
147  }
148 
149  /*
150  * HP PhotoSmart C30 has the date and time in ifd_exif.
151  */
152 #ifdef HAVE_LIBEXIF_IFD
153  e = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_DATE_TIME);
154  if (e)
155  t1 = get_time_from_exif_tag(e);
156  e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF],
157  EXIF_TAG_DATE_TIME_ORIGINAL);
158  if (e)
159  t2 = get_time_from_exif_tag(e);
160  e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF],
161  EXIF_TAG_DATE_TIME_DIGITIZED);
162  if (e)
163  t3 = get_time_from_exif_tag(e);
164 #else
165  e = exif_content_get_entry (ed->ifd0, EXIF_TAG_DATE_TIME);
166  if (e) {
167  t1 = get_time_from_exif_tag(e);
168  exif_data_unref (e);
169  }
170  e = exif_content_get_entry (ed->ifd_exif,
171  EXIF_TAG_DATE_TIME_ORIGINAL);
172  if (e) {
173  t2 = get_time_from_exif_tag(e);
174  exif_data_unref (e);
175  }
176  e = exif_content_get_entry (ed->ifd_exif,
177  EXIF_TAG_DATE_TIME_DIGITIZED);
178  if (e) {
179  t3 = get_time_from_exif_tag(e);
180  exif_data_unref (e);
181  }
182 #endif
183  exif_data_unref (ed);
184  if (!t1 && !t2 && !t3) {
185  GP_LOG_D ("EXIF data has not date/time tags.");
186  return 0;
187  }
188 
189  /* Perform some sanity checking on those tags */
190  t = t1; /* "last modified" */
191 
192  if (t2 > t) /* "image taken" > "last modified" ? can not be */
193  t = t2;
194  if (t3 > t) /* "image digitized" > max(last two) ? can not be */
195  t = t3;
196 
197  GP_LOG_D ("Found time in EXIF data: '%s'.", asctime (localtime (&t)));
198  return (t);
199 }
200 
201 static time_t
202 gp_filesystem_get_exif_mtime (CameraFilesystem *fs, const char *folder,
203  const char *filename)
204 {
205  CameraFile *file;
206  const char *data = NULL;
207  unsigned long int size = 0;
208  time_t t;
209 
210  if (!fs)
211  return 0;
212 
213  /* This is only useful for JPEGs. Avoid querying it for other types. */
214  if ( !strstr(filename,"jpg") && !strstr(filename,"JPG") &&
215  !strstr(filename,"jpeg") && !strstr(filename,"JPEG")
216  )
217  return 0;
218 
219  gp_file_new (&file);
220  if (gp_filesystem_get_file (fs, folder, filename,
221  GP_FILE_TYPE_EXIF, file, NULL) != GP_OK) {
222  GP_LOG_E ("Could not get EXIF data of '%s' in folder '%s'.",
223  filename, folder);
224  gp_file_unref (file);
225  return 0;
226  }
227 
228  gp_file_get_data_and_size (file, &data, &size);
229  t = get_exif_mtime ((unsigned char*)data, size);
230  gp_file_unref (file);
231 
232  return (t);
233 }
234 #endif
235 
244 
247  unsigned long int lru_size;
248 
261 
262  void *data;
263 };
264 
265 #undef MIN
266 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
267 
268 #define CR(result) {int __r = (result); if (__r < 0) return (__r);}
269 
270 #define CL(result,list) \
271 { \
272  int __r = (result); \
273  \
274  if (__r < 0) { \
275  gp_list_free (list); \
276  return (__r); \
277  } \
278 }
279 
280 #define CU(result,file) \
281 { \
282  int __r = (result); \
283  \
284  if (__r < 0) { \
285  gp_file_unref (file); \
286  return (__r); \
287  } \
288 }
289 
290 #define CC(context) \
291 { \
292  if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) \
293  return GP_ERROR_CANCEL; \
294 }
295 
296 #define CA(f,c) \
297 { \
298  if ((f)[0] != '/') { \
299  gp_context_error ((c), \
300  _("The path '%s' is not absolute."), (f)); \
301  return (GP_ERROR_PATH_NOT_ABSOLUTE); \
302  } \
303 }
304 
305 static int
307 {
308  CameraFilesystemFile *file;
309 
310  C_PARAMS (folder);
311  GP_LOG_D ("Delete all files in folder %p/%s", folder, folder->name);
312 
313  file = folder->files;
314  while (file) {
315  CameraFilesystemFile *next;
316  /* Get rid of cached files */
317  gp_filesystem_lru_remove_one (fs, file);
318  if (file->preview) {
319  gp_file_unref (file->preview);
320  file->preview = NULL;
321  }
322  if (file->normal) {
323  gp_file_unref (file->normal);
324  file->normal = NULL;
325  }
326  if (file->raw) {
327  gp_file_unref (file->raw);
328  file->raw = NULL;
329  }
330  if (file->audio) {
331  gp_file_unref (file->audio);
332  file->audio = NULL;
333  }
334  if (file->exif) {
335  gp_file_unref (file->exif);
336  file->exif = NULL;
337  }
338  if (file->metadata) {
339  gp_file_unref (file->metadata);
340  file->metadata = NULL;
341  }
342  next = file->next;
343  free (file->name);
344  free (file);
345  file = next;
346  }
347  folder->files = NULL;
348  return (GP_OK);
349 }
350 
351 static int
353 {
355  C_PARAMS (folder);
356 
357  GP_LOG_D ("Delete one folder %p/%s", *folder, (*folder)->name);
358  next = (*folder)->next;
359  delete_all_files (fs, *folder);
360  free ((*folder)->name);
361  free (*folder);
362  *folder = next;
363  return (GP_OK);
364 }
365 
368  CameraFilesystem *fs,
369  CameraFilesystemFolder *folder, const char *foldername,
370  GPContext *context
371 ) {
373  const char *curpt = foldername;
374  const char *s;
375 
376  GP_LOG_D ("Lookup folder '%s'...", foldername);
377  while (folder) {
378  /* handle multiple slashes, and slashes at the end */
379  while (curpt[0]=='/')
380  curpt++;
381  if (!curpt[0]) {
382  GP_LOG_D ("Found! %s is %p", foldername, folder);
383  return folder;
384  }
385 
386  s = strchr(curpt,'/');
387  /* Check if we need to load the folder ... */
388  if (folder->folders_dirty) {
389  CameraList *list;
390  char *copy = strdup (foldername);
391  int ret;
392  /*
393  * The parent folder is dirty. List the folders in the parent
394  * folder to make it clean.
395  */
396  /* the character _before_ curpt is a /, overwrite it temporary with \0 */
397  copy[curpt-foldername] = '\0';
398  GP_LOG_D ("Folder %s is dirty. "
399  "Listing folders in there to make folder clean...", copy);
400  ret = gp_list_new (&list);
401  if (ret == GP_OK) {
402  ret = gp_filesystem_list_folders (fs, copy, list, context);
403  gp_list_free (list);
404  GP_LOG_D ("Done making folder %s clean...", copy);
405  } else {
406  GP_LOG_D ("Making folder %s clean failed: %d", copy, ret);
407  }
408  free (copy);
409  }
410  f = folder->folders;
411  while (f) {
412  if (s) {
413  if (!strncmp(f->name,curpt, (s-curpt)) &&
414  (strlen(f->name) == (s-curpt))
415  ) {
416  folder = f;
417  curpt = s;
418  break;
419  }
420  } else {
421  if (!strcmp(f->name,curpt))
422  return f;
423  }
424  f = f->next;
425  }
426  folder = f;
427  }
428  return NULL;
429 }
430 
431 static int
433  CameraFilesystem *fs,
434  const char *folder, const char *filename,
435  CameraFilesystemFolder **xfolder, CameraFilesystemFile **xfile,
436  GPContext *context
437 ) {
440 
441  GP_LOG_D ("Lookup folder %s file %s", folder, filename);
442  xf = lookup_folder (fs, fs->rootfolder, folder, context);
443  if (!xf) return GP_ERROR_DIRECTORY_NOT_FOUND;
444  /* Check if we need to load the filelist of the folder ... */
445  if (xf->files_dirty) {
446  CameraList *list;
447  int ret;
448  /*
449  * The folder is dirty. List the files in it to make it clean.
450  */
451  GP_LOG_D ("Folder %s is dirty. "
452  "Listing files in there to make folder clean...", folder);
453  ret = gp_list_new (&list);
454  if (ret == GP_OK) {
455  ret = gp_filesystem_list_files (fs, folder, list, context);
456  gp_list_free (list);
457  GP_LOG_D ("Done making folder %s clean...", folder);
458  }
459  if (ret != GP_OK)
460  GP_LOG_D ("Making folder %s clean failed: %d", folder, ret);
461  }
462 
463  f = xf->files;
464  while (f) {
465  if (!strcmp (f->name, filename)) {
466  *xfile = f;
467  *xfolder = xf;
468  return GP_OK;
469  }
470  f = f->next;
471  }
473 }
474 
475 /* delete all folder content */
476 static int
479 
480  GP_LOG_D ("Recurse delete folder %p/%s", folder, folder->name);
481  f = &folder->folders;
482  while (*f) {
483  recurse_delete_folder (fs, *f);
484  delete_folder (fs, f); /* will also advance to next */
485  }
486  return GP_OK;
487 }
488 
489 static int
490 delete_all_folders (CameraFilesystem *fs, const char *foldername,
491  GPContext *context)
492 {
493  CameraFilesystemFolder *folder;
494 
495  GP_LOG_D ("Internally deleting "
496  "all folders from '%s'...", foldername);
497 
498  C_PARAMS (fs && foldername);
499  CC (context);
500  CA (foldername, context);
501 
502  folder = lookup_folder (fs, fs->rootfolder, foldername, context);
503  if (!folder) return GP_OK;
504  return recurse_delete_folder (fs, folder);
505 }
506 
507 /* create and append 1 new folder entry to the current folder */
508 static int
510  CameraFilesystemFolder *folder,
511  const char *name,
512  CameraFilesystemFolder **newfolder
513 ) {
515 
516  GP_LOG_D ("Append one folder %s", name);
517  C_MEM (f = calloc(1, sizeof(CameraFilesystemFolder)));
518  f->name = strdup (name);
519  if (!f->name) {
520  free (f);
521  return GP_ERROR_NO_MEMORY;
522  }
523  f->files_dirty = 1;
524  f->folders_dirty = 1;
525 
526  /* Link into the current chain... perhaps later alphabetically? */
527  f->next = folder->folders;
528  folder->folders = f;
529  if (newfolder) *newfolder = f;
530  return (GP_OK);
531 }
532 
533 /* This is a mix between lookup and folder creator */
534 static int
536  const char *foldername,
537  CameraFilesystemFolder **newfolder
538 ) {
540  char *s;
541 
542  GP_LOG_D ("Append to folder %p/%s - %s", folder, folder->name, foldername);
543  /* Handle multiple slashes, and slashes at the end */
544  while (foldername[0]=='/')
545  foldername++;
546  if (!foldername[0]) {
547  if (newfolder) *newfolder = folder;
548  return (GP_OK);
549  }
550 
551  s = strchr(foldername,'/');
552  f = folder->folders;
553  while (f) {
554  if (s) {
555  if (!strncmp(f->name,foldername, (s-foldername)) &&
556  (strlen(f->name) == (s-foldername))
557  )
558  return append_to_folder (f, s+1, newfolder);
559  } else {
560  if (!strcmp(f->name,foldername)) {
561  if (newfolder) *newfolder = f;
562  return (GP_OK);
563  }
564  }
565  f = f->next;
566  }
567  /* Not found ... create new folder */
568  if (s) {
569  char *x;
570  C_MEM (x = calloc ((s-foldername)+1,1));
571  memcpy (x, foldername, (s-foldername));
572  x[s-foldername] = 0;
573  CR (append_folder_one (folder, x, newfolder));
574  free (x);
575  } else {
576  CR (append_folder_one (folder, foldername, newfolder));
577  }
578  return (GP_OK);
579 }
580 
581 static int
583  const char *folder,
584  CameraFilesystemFolder **newfolder,
585  GPContext *context
586 ) {
587  GP_LOG_D ("Appending folder %s...", folder);
588  C_PARAMS (fs);
589  C_PARAMS (folder);
590  CC (context);
591  CA (folder, context);
592  return append_to_folder (fs->rootfolder, folder, newfolder);
593 }
594 
595 static int
596 append_file (CameraFilesystem *fs, CameraFilesystemFolder *folder, const char *name, CameraFile *file, GPContext *context)
597 {
598  CameraFilesystemFile **new;
599 
600  C_PARAMS (fs && file);
601  GP_LOG_D ("Appending file %s...", name);
602 
603  new = &folder->files;
604  while (*new) {
605  if (!strcmp((*new)->name, name)) {
606  GP_LOG_E ("File %s already exists!", name);
607  return (GP_ERROR);
608  }
609  new = &((*new)->next);
610  }
611  /* new now points to the location of the last ->next pointer,
612  * if we write to it, we set last->next */
613  C_MEM ((*new) = calloc (1, sizeof (CameraFilesystemFile)));
614  C_MEM ((*new)->name = strdup (name));
615  (*new)->info_dirty = 1;
616  (*new)->normal = file;
617  gp_file_ref (file);
618  return (GP_OK);
619 }
620 
630 int
632 {
633  GP_LOG_D ("resetting filesystem");
635  CR (delete_all_folders (fs, "/", NULL));
636  if (fs->rootfolder) {
637  fs->rootfolder->files_dirty = 1;
638  fs->rootfolder->folders_dirty = 1;
639  } else {
640  GP_LOG_E ("root folder is gone?");
641  }
642  return (GP_OK);
643 }
644 
654 int
656 {
657  C_PARAMS (fs);
658 
659  C_MEM (*fs = calloc (1, sizeof (CameraFilesystem)));
660 
661  (*fs)->rootfolder = calloc (sizeof (CameraFilesystemFolder), 1);
662  if (!(*fs)->rootfolder) {
663  free (*fs);
664  return (GP_ERROR_NO_MEMORY);
665  }
666  (*fs)->rootfolder->name = strdup("/");
667  if (!(*fs)->rootfolder->name) {
668  free ((*fs)->rootfolder);
669  free (*fs);
670  return (GP_ERROR_NO_MEMORY);
671  }
672  (*fs)->rootfolder->files_dirty = 1;
673  (*fs)->rootfolder->folders_dirty = 1;
674  return (GP_OK);
675 }
676 
685 int
687 {
688  /* We don't care for success or failure */
689  gp_filesystem_reset (fs);
690 
691  /* Now, we've only got left over the root folder. Free that and
692  * the filesystem. */
693  free (fs->rootfolder->name);
694  free (fs->rootfolder);
695  free (fs);
696  return (GP_OK);
697 }
698 
713 static int
715  const char *filename, GPContext *context)
716 {
717  CameraFilesystemFile **new;
718 
719  C_PARAMS (fs && f);
720 
721  GP_LOG_D ("Internal append %s to folder %s", filename, f->name);
722  /* Check folder for existence, if not, create it. */
723  new = &f->files;
724  while (*new) {
725  if (!strcmp((*new)->name, filename)) break;
726  new = &((*new)->next);
727  }
728  if (*new)
729  return (GP_ERROR_FILE_EXISTS);
730 
731  C_MEM ((*new) = calloc (sizeof (CameraFilesystemFile), 1));
732  (*new)->name = strdup (filename);
733  if (!(*new)->name) {
734  free (*new);
735  *new = NULL;
736  return (GP_ERROR_NO_MEMORY);
737  }
738  (*new)->info_dirty = 1;
739  return (GP_OK);
740 }
741 
742 int
743 gp_filesystem_append (CameraFilesystem *fs, const char *folder,
744  const char *filename, GPContext *context)
745 {
747  int ret;
748 
749  C_PARAMS (fs && folder);
750  CC (context);
751  CA (folder, context);
752 
753  GP_LOG_D ("Append %s/%s to filesystem", folder, filename);
754  /* Check folder for existence, if not, create it. */
755  f = lookup_folder (fs, fs->rootfolder, folder, context);
756  if (!f)
757  CR (append_folder (fs, folder, &f, context));
758  if (f->files_dirty) { /* Need to load folder from driver first ... capture case */
759  CameraList *xlist;
760  int ret;
761 
762  ret = gp_list_new (&xlist);
763  if (ret != GP_OK) return ret;
764  ret = gp_filesystem_list_files (fs, folder, xlist, context);
765  gp_list_free (xlist);
766  if (ret != GP_OK) return ret;
767  }
768 
769  // Only try to append the file if filename is not empty
770  if (filename && strlen(filename)!=0)
771  ret = internal_append (fs, f, filename, context);
772  if (ret == GP_ERROR_FILE_EXISTS) /* not an error here ... just in case we add files twice to the list */
773  ret = GP_OK;
774  return ret;
775 }
776 
777 
778 static void
781  CameraFilesystemFile *xfile;
782 
783  GP_LOG_D ("%*sFolder %s", depth, " ", folder->name);
784 
785  xfile = folder->files;
786  while (xfile) {
787  GP_LOG_D ("%*s %s", depth, " ", xfile->name);
788  xfile = xfile->next;
789  }
790 
791  f = folder->folders;
792  while (f) {
793  recursive_fs_dump (f, depth+4);
794  f = f->next;
795  }
796 }
804 int
806 {
807  GP_LOG_D ("Dumping Filesystem:");
808  recursive_fs_dump (fs->rootfolder, 0);
809  return (GP_OK);
810 }
811 
812 static int
814 {
815  CameraFilesystemFile **prev;
816 
817  gp_filesystem_lru_remove_one (fs, file);
818  /* Get rid of cached files */
819  if (file->preview) {
820  gp_file_unref (file->preview);
821  file->preview = NULL;
822  }
823  if (file->normal) {
824  gp_file_unref (file->normal);
825  file->normal = NULL;
826  }
827  if (file->raw) {
828  gp_file_unref (file->raw);
829  file->raw = NULL;
830  }
831  if (file->audio) {
832  gp_file_unref (file->audio);
833  file->audio = NULL;
834  }
835  if (file->exif) {
836  gp_file_unref (file->exif);
837  file->exif = NULL;
838  }
839  if (file->metadata) {
840  gp_file_unref (file->metadata);
841  file->metadata = NULL;
842  }
843 
844  prev = &(folder->files);
845  while ((*prev) && ((*prev) != file))
846  prev = &((*prev)->next);
847  if (!*prev)
848  return GP_ERROR;
849  *prev = file->next;
850  file->next = NULL;
851  free (file->name);
852  free (file);
853  return (GP_OK);
854 }
855 
856 static int
858  GPContext *context)
859 {
860  CameraList *list;
861  int count, x;
862  const char *name;
863 
864  GP_LOG_D ("Deleting all 1 by 1 from %s", folder);
865  CR (gp_list_new (&list));
866  CL (gp_filesystem_list_files (fs, folder, list, context), list);
867  CL (count = gp_list_count (list), list);
868  for (x = count ; x--; ) {
869  CL (gp_list_get_name (list, x, &name), list);
870  CL (gp_filesystem_delete_file (fs, folder, name, context),list);
871  }
872  gp_list_free(list);
873  return (GP_OK);
874 }
875 
890 int
892  GPContext *context)
893 {
894  int r;
896 
897  C_PARAMS (fs && folder);
898  CC (context);
899  CA (folder, context);
900 
901  GP_LOG_D ("Deleting all from %s", folder);
902  /* Make sure this folder exists */
903  f = lookup_folder (fs, fs->rootfolder, folder, context);
904  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
905 
906  if (!fs->delete_all_func)
907  return gp_filesystem_delete_all_one_by_one (fs, folder, context);
908  /*
909  * Mark the folder dirty - it could be that an error
910  * happens, and then we don't know which files have been
911  * deleted and which not.
912  */
913  f->files_dirty = 1;
914  /*
915  * First try to use the delete_all function. If that fails,
916  * fall back to deletion one-by-one.
917  */
918  r = fs->delete_all_func (fs, folder, fs->data, context);
919  if (r < 0) {
920  GP_LOG_D (
921  "delete_all failed (%s). Falling back to "
922  "deletion one-by-one.",
923  gp_result_as_string (r));
925  context));
926  } else {
927  /* delete from filesystem view too now */
928  CR (delete_all_files (fs, f));
929  }
930  /*
931  * No error happened. We can be sure that all files have been
932  * deleted.
933  */
934  f->files_dirty = 0;
935  return (GP_OK);
936 }
937 
951 int
953  CameraList *list, GPContext *context)
954 {
955  int count, y;
956  const char *name;
958  CameraFilesystemFile *file;
959 
960  GP_LOG_D ("Listing files in %s", folder);
961 
962  C_PARAMS (fs && list && folder);
963  CC (context);
964  CA (folder, context);
965 
966  gp_list_reset (list);
967 
968  /* Search the folder */
969  f = lookup_folder (fs, fs->rootfolder, folder, context);
970  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
971 
972  /* If the folder is dirty, delete the contents and query the camera */
973  if (f->files_dirty && fs->file_list_func) {
974  GP_LOG_D ("Querying folder %s...", folder);
975  CR (delete_all_files (fs, f));
976 
977  /* set it to non-dirty now, so we do not recurse via _append. */
978  f->files_dirty = 0;
979  CR (fs->file_list_func (fs, folder, list,
980  fs->data, context));
981 
982  CR (count = gp_list_count (list));
983  for (y = 0; y < count; y++) {
984  CR (gp_list_get_name (list, y, &name));
985  GP_LOG_D ("Added '%s'", name);
986  CR (internal_append (fs, f, name, context));
987  }
988  gp_list_reset (list);
989  }
990  /* The folder is clean now */
991  f->files_dirty = 0;
992 
993  file = f->files;
994  while (file) {
995  GP_LOG_D (
996  "Listed '%s'", file->name);
997  CR (gp_list_append (list, file->name, NULL));
998  file = file->next;
999  }
1000  return (GP_OK);
1001 }
1002 
1017 int
1019  CameraList *list, GPContext *context)
1020 {
1021  int y, count;
1022  const char *name;
1023  CameraFilesystemFolder *f, *new;
1024 
1025  GP_LOG_D ("Listing folders in %s", folder);
1026 
1027  C_PARAMS (fs && folder && list);
1028  CC (context);
1029  CA (folder, context);
1030 
1031  gp_list_reset (list);
1032 
1033  /* Search the folder */
1034  f = lookup_folder (fs, fs->rootfolder, folder, context);
1035  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1036 
1037 
1038  /* If the folder is dirty, query the contents. */
1039  if (f->folders_dirty && fs->folder_list_func) {
1040  GP_LOG_D ("... is dirty, getting from camera");
1041  CR (fs->folder_list_func (fs, folder, list,
1042  fs->data, context));
1043  CR (delete_all_folders (fs, folder, context));
1044 
1045  CR (count = gp_list_count (list));
1046  for (y = 0; y < count; y++) {
1047  CR (gp_list_get_name (list, y, &name));
1048  CR (append_folder_one (f, name, NULL));
1049  }
1050  /* FIXME: why not just return (GP_OK); ? the list should be fine */
1051  gp_list_reset (list);
1052  }
1053 
1054  new = f->folders;
1055  while (new) {
1056  CR (gp_list_append (list, new->name, NULL));
1057  new = new->next;
1058  }
1059  /* The folder is clean now */
1060  f->folders_dirty = 0;
1061  GP_LOG_D ("Folder %s contains %i subfolders.", folder, gp_list_count (list));
1062  return (GP_OK);
1063 }
1064 
1075 int
1076 gp_filesystem_count (CameraFilesystem *fs, const char *folder,
1077  GPContext *context)
1078 {
1079  int x;
1081  CameraFilesystemFile *file;
1082 
1083  C_PARAMS (fs && folder);
1084  CC (context);
1085  CA (folder, context);
1086 
1087  f = lookup_folder (fs, fs->rootfolder, folder, context);
1088  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1089 
1090  x = 0;
1091  file = f->files;
1092  while (file) {
1093  x++;
1094  file = file->next;
1095  }
1096  return x;
1097 }
1098 
1112 int
1114  const char *filename, GPContext *context)
1115 {
1117  CameraFilesystemFile *file;
1118 
1119  C_PARAMS (fs && folder && filename);
1120  CC (context);
1121  CA (folder, context);
1122 
1123  /* First of all, do we support file deletion? */
1124  if (!fs->delete_file_func) {
1125  gp_context_error (context, _("You have been trying to delete "
1126  "'%s' from folder '%s', but the filesystem does not "
1127  "support deletion of files."), filename, folder);
1128  return (GP_ERROR_NOT_SUPPORTED);
1129  }
1130 
1131  /* Search the folder and the file */
1132  CR (lookup_folder_file (fs, folder, filename, &f, &file, context));
1133 
1134  GP_LOG_D ("Deleting '%s' from folder '%s'...", filename, folder);
1135 
1136  /* Delete the file */
1137  CR (fs->delete_file_func (fs, folder, filename,
1138  fs->data, context));
1139  CR (delete_file (fs, f, file));
1140  return (GP_OK);
1141 }
1142 
1156 int
1158  const char *filename, GPContext *context)
1159 {
1161  CameraFilesystemFile *file;
1162 
1163  C_PARAMS (fs && folder && filename);
1164  CC (context);
1165  CA (folder, context);
1166  /* Search the folder and the file */
1167  CR (lookup_folder_file (fs, folder, filename, &f, &file, context));
1168  return delete_file (fs, f, file);
1169 }
1170 
1182 int
1183 gp_filesystem_make_dir (CameraFilesystem *fs, const char *folder,
1184  const char *name, GPContext *context)
1185 {
1187 
1188  C_PARAMS (fs && folder && name);
1189  CC (context);
1190  CA (folder, context);
1191 
1192  if (!fs->make_dir_func)
1193  return (GP_ERROR_NOT_SUPPORTED);
1194 
1195  /* Search the folder */
1196  f = lookup_folder (fs, fs->rootfolder, folder, context);
1197  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1198 
1199  /* Create the directory */
1200  CR (fs->make_dir_func (fs, folder, name, fs->data, context));
1201  /* and append to internal fs */
1202  return append_folder_one (f, name, NULL);
1203 }
1204 
1216 int
1218  const char *name, GPContext *context)
1219 {
1221  CameraFilesystemFolder **prev;
1222 
1223  C_PARAMS (fs && folder && name);
1224  CC (context);
1225  CA (folder, context);
1226 
1227  if (!fs->remove_dir_func)
1228  return (GP_ERROR_NOT_SUPPORTED);
1229 
1230  /*
1231  * Make sure there are neither files nor folders in the folder
1232  * that is to be removed.
1233  */
1234  f = lookup_folder (fs, fs->rootfolder, folder, context);
1235  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1236  /* Check if we need to load the folder ... */
1237  if (f->folders_dirty) {
1238  CameraList *list;
1239  int ret;
1240  /*
1241  * The owning folder is dirty. List the folders in it
1242  * to make it clean.
1243  */
1244  GP_LOG_D ("Folder %s is dirty. "
1245  "Listing folders in there to make folder clean...", folder);
1246  ret = gp_list_new (&list);
1247  if (ret == GP_OK) {
1248  ret = gp_filesystem_list_folders (fs, folder, list, context);
1249  gp_list_free (list);
1250  GP_LOG_D ("Done making folder %s clean...", folder);
1251  }
1252  }
1253  prev = &(f->folders);
1254  while (*prev) {
1255  if (!strcmp (name, (*prev)->name))
1256  break;
1257  prev = &((*prev)->next);
1258  }
1259  if (!*prev) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1260 
1261  if ((*prev)->folders) {
1262  gp_context_error (context, _("There are still subfolders in "
1263  "folder '%s/%s' that you are trying to remove."), folder, name);
1264  return (GP_ERROR_DIRECTORY_EXISTS);
1265  }
1266  if ((*prev)->files) {
1267  gp_context_error (context, _("There are still files in "
1268  "folder '%s/%s' that you are trying to remove."), folder,name);
1269  return (GP_ERROR_FILE_EXISTS);
1270  }
1271 
1272  /* Remove the directory */
1273  CR (fs->remove_dir_func (fs, folder, name, fs->data, context));
1274  CR (delete_folder (fs, prev));
1275  return (GP_OK);
1276 }
1277 
1291 int
1293  const char *folder, const char *filename,
1294  CameraFileType type,
1295  CameraFile *file, GPContext *context)
1296 {
1298  int ret;
1299 
1300  C_PARAMS (fs && folder && file);
1301  CC (context);
1302  CA (folder, context);
1303 
1304  /* Do we support file upload? */
1305  if (!fs->put_file_func) {
1306  gp_context_error (context, _("The filesystem does not support "
1307  "upload of files."));
1308  return (GP_ERROR_NOT_SUPPORTED);
1309  }
1310 
1311  /* Search the folder */
1312  f = lookup_folder (fs, fs->rootfolder, folder, context);
1313  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1314 
1315  /* Upload the file */
1316  CR (fs->put_file_func (fs, folder, filename, type, file, fs->data, context));
1317  /* And upload it to internal structure too */
1318  ret = append_file (fs, f, filename, file, context);
1319  if (type != GP_FILE_TYPE_NORMAL) /* FIXME perhaps check before append_file? */
1320  return GP_OK;
1321  return ret;
1322 }
1323 
1337 int
1338 gp_filesystem_name (CameraFilesystem *fs, const char *folder, int filenumber,
1339  const char **filename, GPContext *context)
1340 {
1342  CameraFilesystemFile *file;
1343  int count;
1344  C_PARAMS (fs && folder);
1345  CC (context);
1346  CA (folder, context);
1347 
1348  f = lookup_folder (fs, fs->rootfolder, folder, context);
1349  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1350 
1351  file = f->files;
1352  count = 0;
1353  while (file) {
1354  if (filenumber == 0)
1355  break;
1356  filenumber--;
1357  count++;
1358  file = file->next;
1359  }
1360 
1361  if (!file) {
1362  gp_context_error (context, _("Folder '%s' only contains "
1363  "%i files, but you requested a file with number %i."),
1364  folder, count, filenumber);
1365  return (GP_ERROR_FILE_NOT_FOUND);
1366  }
1367  *filename = file->name;
1368  return (GP_OK);
1369 }
1370 
1383 int
1384 gp_filesystem_number (CameraFilesystem *fs, const char *folder,
1385  const char *filename, GPContext *context)
1386 {
1388  CameraFilesystemFile *file;
1389  CameraList *list;
1390  int num;
1391 
1392  C_PARAMS (fs && folder && filename);
1393  CC (context);
1394  CA (folder, context);
1395 
1396  f = lookup_folder (fs, fs->rootfolder, folder, context);
1397  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1398 
1399  file = f->files;
1400  num = 0;
1401  while (file) {
1402  if (!strcmp (file->name, filename))
1403  return num;
1404  num++;
1405  file = file->next;
1406  }
1407 
1408  /* Ok, we didn't find the file. Is the folder dirty? */
1409  if (!f->files_dirty) {
1410  gp_context_error (context, _("File '%s' could not be found "
1411  "in folder '%s'."), filename, folder);
1412  return (GP_ERROR_FILE_NOT_FOUND);
1413  }
1414  /* The folder is dirty. List all files to make it clean */
1415  CR (gp_list_new(&list));
1416  CL (gp_filesystem_list_files (fs, folder, list, context), list);
1417  gp_list_free(list);
1418  return (gp_filesystem_number (fs, folder, filename, context));
1419 }
1420 
1421 static int
1422 gp_filesystem_scan (CameraFilesystem *fs, const char *folder,
1423  const char *filename, GPContext *context)
1424 {
1425  int count, x;
1426  CameraList *list;
1427  const char *name;
1428  char path[128];
1429 
1430  GP_LOG_D ("Scanning %s for %s...", folder, filename);
1431 
1432  C_PARAMS (fs && folder && filename);
1433  CC (context);
1434  CA (folder, context);
1435 
1436  CR (gp_list_new (&list));
1437  CL (gp_filesystem_list_files (fs, folder, list, context), list);
1438  CL (count = gp_list_count (list), list);
1439  for (x = 0; x < count; x++) {
1440  CL (gp_list_get_name (list, x, &name), list);
1441  if (!strcmp (filename, name)) {
1442  gp_list_free (list);
1443  return (GP_OK);
1444  }
1445  }
1446 
1447  CL (gp_filesystem_list_folders (fs, folder, list, context), list);
1448  CL (count = gp_list_count (list), list);
1449  for (x = 0; x < count; x++) {
1450  CL (gp_list_get_name (list, x, &name), list);
1451  strncpy (path, folder, sizeof (path));
1452  if (path[strlen (path) - 1] != '/')
1453  strncat (path, "/", sizeof (path) - strlen (path) - 1);
1454  strncat (path, name, sizeof (path) - strlen (path) - 1);
1455  CL (gp_filesystem_scan (fs, path, filename, context), list);
1456  }
1457  gp_list_free (list);
1458  return (GP_OK);
1459 }
1460 
1461 static int
1463  CameraFilesystemFolder *folder, const char *lookforfile,
1464  char **foldername
1465 ) {
1466  CameraFilesystemFile *file;
1468  int ret;
1469 
1470  file = folder->files;
1471  while (file) {
1472  if (!strcmp(file->name, lookforfile)) {
1473  *foldername = strdup (folder->name);
1474  return GP_OK;
1475  }
1476  file = file->next;
1477  }
1478  f = folder->folders;
1479  while (f) {
1480  char *xfolder;
1481  ret = recursive_folder_scan (f, lookforfile, &xfolder);
1482  if (ret == GP_OK) {
1483  C_MEM ((*foldername) = malloc (strlen (folder->name) + 1 + strlen (xfolder) + 1));
1484  strcpy ((*foldername),folder->name);
1485  strcat ((*foldername),"/");
1486  strcat ((*foldername),xfolder);
1487  free (xfolder);
1488  return GP_OK;
1489  }
1490  f = f->next;
1491  }
1492  /* thorugh all subfoilders */
1493  return GP_ERROR_FILE_NOT_FOUND;
1494 }
1514 int
1515 gp_filesystem_get_folder (CameraFilesystem *fs, const char *filename,
1516  char **folder, GPContext *context)
1517 {
1518  int ret;
1519 
1520  C_PARAMS (fs && filename && folder);
1521  CC (context);
1522 
1523  CR (gp_filesystem_scan (fs, "/", filename, context));
1524 
1525  ret = recursive_folder_scan ( fs->rootfolder, filename, folder);
1526  if (ret == GP_OK) return ret;
1527  gp_context_error (context, _("Could not find file '%s'."), filename);
1528  return (GP_ERROR_FILE_NOT_FOUND);
1529 }
1530 
1531 static int
1533  const char *filename, CameraFileType type,
1534  CameraFile *file, GPContext *context)
1535 {
1536  CameraFilesystemFolder *xfolder;
1537  CameraFilesystemFile *xfile;
1538  int ret;
1539 
1540  C_PARAMS (fs && folder && file && filename);
1541  CC (context);
1542  CA (folder, context);
1543 
1544  GP_LOG_D ("Getting file '%s' from folder '%s' (type %i)...",
1545  filename, folder, type);
1546 
1547  CR (gp_file_set_name (file, filename));
1548 
1549  if (!fs->get_file_func) {
1550  gp_context_error (context,
1551  _("The filesystem doesn't support getting files"));
1552  return (GP_ERROR_NOT_SUPPORTED);
1553  }
1554 
1555  /* Search folder and file */
1556  CR( lookup_folder_file (fs, folder, filename, &xfolder, &xfile, context));
1557 
1558  ret = GP_ERROR;
1559  switch (type) {
1560  case GP_FILE_TYPE_PREVIEW:
1561  if (xfile->preview)
1562  ret = gp_file_copy (file, xfile->preview);
1563  break;
1564  case GP_FILE_TYPE_NORMAL:
1565  if (xfile->normal)
1566  ret = gp_file_copy (file, xfile->normal);
1567  break;
1568  case GP_FILE_TYPE_RAW:
1569  if (xfile->raw)
1570  ret = gp_file_copy (file, xfile->raw);
1571  break;
1572  case GP_FILE_TYPE_AUDIO:
1573  if (xfile->audio)
1574  ret = gp_file_copy (file, xfile->audio);
1575  break;
1576  case GP_FILE_TYPE_EXIF:
1577  if (xfile->exif)
1578  ret = gp_file_copy (file, xfile->exif);
1579  break;
1580  case GP_FILE_TYPE_METADATA:
1581  if (xfile->metadata)
1582  ret = gp_file_copy (file, xfile->metadata);
1583  break;
1584  default:
1585  gp_context_error (context, _("Unknown file type %i."), type);
1586  return (GP_ERROR);
1587  }
1588  if (ret == GP_OK) {
1589  GP_LOG_D ("LRU cache used for type %d!", type);
1590  return GP_OK;
1591  }
1592 
1593  GP_LOG_D ("Downloading '%s' from folder '%s'...", filename, folder);
1594 
1595  CR (fs->get_file_func (fs, folder, filename, type, file,
1596  fs->data, context));
1597 
1598  /* We don't trust the camera drivers */
1599  CR (gp_file_set_name (file, filename));
1600 
1601 #if 0
1602  /* this disables LRU completely. */
1603  /* Cache this file */
1604  CR (gp_filesystem_set_file_noop (fs, folder, filename, type, file, context));
1605 #endif
1606 
1607  /*
1608  * Often, thumbnails are of a different mime type than the normal
1609  * picture. In this case, we should rename the file.
1610  */
1611  if (type != GP_FILE_TYPE_NORMAL)
1613 
1614  return (GP_OK);
1615 }
1616 
1633 int
1634 gp_filesystem_get_file (CameraFilesystem *fs, const char *folder,
1635  const char *filename, CameraFileType type,
1636  CameraFile *file, GPContext *context)
1637 {
1638  int r;
1639 #ifdef HAVE_LIBEXIF
1640  CameraFile *efile;
1641  const char *data = NULL;
1642  unsigned char *buf;
1643  unsigned int buf_size;
1644  unsigned long int size = 0;
1645  ExifData *ed;
1646 #endif
1647 
1648  r = gp_filesystem_get_file_impl (fs, folder, filename, type,
1649  file, context);
1650 
1651  if ((r == GP_ERROR_NOT_SUPPORTED) &&
1652  (type == GP_FILE_TYPE_PREVIEW)) {
1653 
1654  /*
1655  * Could not get preview (unsupported operation). Some
1656  * cameras hide the thumbnail in EXIF data. Check it out.
1657  */
1658 #ifdef HAVE_LIBEXIF
1659  GP_LOG_D ("Getting previews is not supported. Trying EXIF data...");
1660  CR (gp_file_new (&efile));
1661  CU (gp_filesystem_get_file_impl (fs, folder, filename,
1662  GP_FILE_TYPE_EXIF, efile, context), efile);
1663  CU (gp_file_get_data_and_size (efile, &data, &size), efile);
1664  ed = exif_data_new_from_data ((unsigned char*)data, size);
1665  gp_file_unref (efile);
1666  if (!ed) {
1667  GP_LOG_E ("Could not parse EXIF data of '%s' in folder '%s'.", filename, folder);
1668  return (GP_ERROR_CORRUPTED_DATA);
1669  }
1670  if (!ed->data) {
1671  GP_LOG_E ("EXIF data does not contain a thumbnail.");
1672  exif_data_unref (ed);
1673  return (r);
1674  }
1675 
1676  /*
1677  * We found a thumbnail in EXIF data! Those
1678  * thumbnails are always JPEG. Set up the file.
1679  */
1680  r = gp_file_set_data_and_size (file, (char*)ed->data, ed->size);
1681  if (r < 0) {
1682  exif_data_unref (ed);
1683  return (r);
1684  }
1685  ed->data = NULL;
1686  ed->size = 0;
1687  exif_data_unref (ed);
1688  CR (gp_file_set_name (file, filename));
1690  CR (gp_filesystem_set_file_noop (fs, folder, filename, GP_FILE_TYPE_PREVIEW, file, context));
1692 #else
1693  GP_LOG_D ("Getting previews is not supported and "
1694  "libgphoto2 has been compiled without exif "
1695  "support. ");
1696  return (r);
1697 #endif
1698  } else if ((r == GP_ERROR_NOT_SUPPORTED) &&
1699  (type == GP_FILE_TYPE_EXIF)) {
1700 
1701  /*
1702  * Some cameras hide EXIF data in thumbnails (!). Check it
1703  * out.
1704  */
1705 #ifdef HAVE_LIBEXIF
1706  GP_LOG_D ("Getting EXIF data is not supported. Trying thumbnail...");
1707  CR (gp_file_new (&efile));
1708  CU (gp_filesystem_get_file_impl (fs, folder, filename,
1709  GP_FILE_TYPE_PREVIEW, efile, context), efile);
1710  CU (gp_file_get_data_and_size (efile, &data, &size), efile);
1711  ed = exif_data_new_from_data ((unsigned char*)data, size);
1712  gp_file_unref (efile);
1713  if (!ed) {
1714  GP_LOG_D ("Could not parse EXIF data of thumbnail of "
1715  "'%s' in folder '%s'.", filename, folder);
1716  return (GP_ERROR_CORRUPTED_DATA);
1717  }
1718  exif_data_save_data (ed, &buf, &buf_size);
1719  exif_data_unref (ed);
1720  r = gp_file_set_data_and_size (file, (char*)buf, buf_size);
1721  if (r < 0) {
1722  free (buf);
1723  return (r);
1724  }
1725  CR (gp_file_set_name (file, filename));
1727  CR (gp_filesystem_set_file_noop (fs, folder, filename, GP_FILE_TYPE_EXIF, file, context));
1729 #else
1730  GP_LOG_D ("Getting EXIF data is not supported and libgphoto2 "
1731  "has been compiled without EXIF support.");
1732  return (r);
1733 #endif
1734  } else if (r < 0) {
1735  GP_LOG_D ("Download of '%s' from '%s' (type %i) failed. "
1736  "Reason: '%s'", filename, folder, type,
1737  gp_result_as_string (r));
1738  return (r);
1739  }
1740 
1741  return (GP_OK);
1742 }
1743 
1766 int
1768  const char *filename, CameraFileType type,
1769  uint64_t offset, char *buf, uint64_t *size,
1770  GPContext *context)
1771 {
1772  int r;
1773  const char *xdata;
1774  unsigned long xsize;
1775  CameraFile *file;
1776 
1777  C_PARAMS (fs && folder && filename && buf && size);
1778  CC (context);
1779  CA (folder, context);
1780 
1781  if (fs->read_file_func) {
1782  r = fs->read_file_func (fs, folder, filename, type,
1783  offset, buf, size, fs->data, context);
1784  if (r == GP_OK)
1785  return r;
1786  } else {
1787  return GP_ERROR_NOT_SUPPORTED;
1788  }
1789  return r;
1790  /* fallback code */
1791  CR (gp_file_new (&file));
1792  CR (gp_filesystem_get_file (fs, folder, filename, type,
1793  file, context));
1794  CR (gp_file_get_data_and_size (file, &xdata, &xsize));
1795  if (offset > *size) { /* EOF */
1796  gp_file_unref (file);
1797  *size = 0;
1798  return GP_OK;
1799  }
1800  if ((offset != 0) || (offset + *size != xsize)) {
1801  /* Cache this file in the LRU, but only if the user just
1802  * hasn't read all of it at once.
1803  */
1804  CR (gp_filesystem_set_file_noop (fs, folder, filename, type, file, context));
1805  }
1806  if (offset + (*size) > xsize)
1807  *size = xsize-offset;
1808  memcpy (buf, xdata+offset, *size);
1809  gp_file_unref (file);
1810  return GP_OK;
1811 }
1823 int
1825  CameraFilesystemFuncs *funcs,
1826  void *data)
1827 {
1828  C_PARAMS (fs);
1829 
1830  fs->get_info_func = funcs->get_info_func;
1831  fs->set_info_func = funcs->set_info_func;
1832  fs->put_file_func = funcs->put_file_func;
1833  fs->delete_all_func = funcs->delete_all_func;
1834  fs->make_dir_func = funcs->make_dir_func;
1835  fs->remove_dir_func = funcs->remove_dir_func;
1836  fs->file_list_func = funcs->file_list_func;
1837  fs->folder_list_func = funcs->folder_list_func;
1838  fs->delete_file_func = funcs->del_file_func;
1839  fs->get_file_func = funcs->get_file_func;
1840  fs->read_file_func = funcs->read_file_func;
1841  fs->storage_info_func = funcs->storage_info_func;
1842  fs->data = data;
1843  return (GP_OK);
1844 }
1845 
1856 int
1857 gp_filesystem_get_info (CameraFilesystem *fs, const char *folder,
1858  const char *filename, CameraFileInfo *info,
1859  GPContext *context)
1860 {
1862  CameraFilesystemFile *file;
1863 #ifdef HAVE_LIBEXIF
1864  time_t t;
1865 #endif
1866 
1867  C_PARAMS (fs && folder && filename && info);
1868  CC (context);
1869  CA (folder, context);
1870 
1871  GP_LOG_D ("Getting information about '%s' in '%s'...", filename,
1872  folder);
1873 
1874  if (!fs->get_info_func) {
1875  gp_context_error (context,
1876  _("The filesystem doesn't support getting file "
1877  "information"));
1878  return (GP_ERROR_NOT_SUPPORTED);
1879  }
1880 
1881  /* Search folder and file and get info if needed */
1882  CR ( lookup_folder_file (fs, folder, filename, &f, &file, context));
1883 
1884  if (file->info_dirty) {
1885  CR (fs->get_info_func (fs, folder, filename,
1886  &file->info,
1887  fs->data, context));
1888  file->info_dirty = 0;
1889  }
1890 
1891  /*
1892  * If we didn't get GP_FILE_INFO_MTIME, we'll have a look if we
1893  * can get it from EXIF data.
1894  */
1895 #ifdef HAVE_LIBEXIF
1896  if (!(file->info.file.fields & GP_FILE_INFO_MTIME)) {
1897  GP_LOG_D ("Did not get mtime. Trying EXIF information...");
1898  t = gp_filesystem_get_exif_mtime (fs, folder, filename);
1899  if (t) {
1900  file->info.file.mtime = t;
1902  }
1903  }
1904 #endif
1905  memcpy (info, &file->info, sizeof (CameraFileInfo));
1906  return (GP_OK);
1907 }
1908 
1909 static int
1911 {
1912  int n = 0;
1913  CameraFilesystemFile *ptr, *prev;
1914 
1915  GP_LOG_D ("Clearing fscache LRU list...");
1916 
1917  if (fs->lru_first == NULL) {
1918  GP_LOG_D ("fscache LRU list already empty");
1919  return (GP_OK);
1920  }
1921 
1922  ptr = prev = fs->lru_first;
1923  while (ptr != NULL) {
1924  n++;
1925  if (ptr->lru_prev != prev) {
1926  GP_LOG_D ("fscache LRU list corrupted (%i)", n);
1927  return (GP_ERROR);
1928  }
1929  prev = ptr;
1930  ptr = ptr->lru_next;
1931 
1932  prev->lru_prev = NULL;
1933  prev->lru_next = NULL;
1934  }
1935 
1936  fs->lru_first = NULL;
1937  fs->lru_last = NULL;
1938  fs->lru_size = 0;
1939 
1940  GP_LOG_D ("fscache LRU list cleared (removed %i items)", n);
1941 
1942  return (GP_OK);
1943 }
1944 
1945 static int
1947 {
1948  if (item->lru_prev == NULL)
1949  return (GP_ERROR);
1950 
1951  /* Update the prev and next pointers. */
1952  if (item->lru_prev) item->lru_prev->lru_next = item->lru_next;
1953  if (item->lru_next) item->lru_next->lru_prev = item->lru_prev;
1954  if (fs->lru_last == item) {
1955  if (fs->lru_first == item) {
1956 
1957  /*
1958  * Case 1: ITEM is the only one in the list. We'll
1959  * remove it, and the list will be empty afterwards.
1960  */
1961  fs->lru_last = NULL;
1962  fs->lru_first = NULL;
1963  } else {
1964 
1965  /* Case 2: ITEM is the last in the list. */
1966  fs->lru_last = item->lru_prev;
1967  }
1968  } else if (fs->lru_first == item) {
1969 
1970  /* Case 3: ITEM is the first in the list. */
1971  fs->lru_first = item->lru_next;
1972  /* the first item prev links back to itself */
1973  fs->lru_first->lru_prev = fs->lru_first;
1974  }
1975 
1976  /* Clear the pointers */
1977  item->lru_prev = NULL;
1978  item->lru_next = NULL;
1979 
1980  return (GP_OK);
1981 }
1982 
1983 static int
1985 {
1986  CameraFilesystemFile *ptr;
1987  unsigned long int size;
1988 
1989  C_PARAMS (fs && fs->lru_first);
1990 
1991  ptr = fs->lru_first;
1992 
1993  GP_LOG_D ("Freeing cached data for file '%s'...", ptr->name);
1994 
1995  /* Remove it from the list. */
1996  fs->lru_first = ptr->lru_next;
1997  if (fs->lru_first)
1998  fs->lru_first->lru_prev = fs->lru_first;
1999  else
2000  fs->lru_last = NULL;
2001 
2002  /* Free its content. */
2003  if (ptr->normal) {
2004  CR( gp_file_get_data_and_size (ptr->normal, NULL, &size));
2005  fs->lru_size -= size;
2006  gp_file_unref (ptr->normal);
2007  ptr->normal = NULL;
2008  }
2009  if (ptr->raw) {
2010  CR( gp_file_get_data_and_size (ptr->raw, NULL, &size));
2011  fs->lru_size -= size;
2012  gp_file_unref (ptr->raw);
2013  ptr->raw = NULL;
2014  }
2015  if (ptr->audio) {
2016  CR( gp_file_get_data_and_size (ptr->audio, NULL, &size));
2017  fs->lru_size -= size;
2018  gp_file_unref (ptr->audio);
2019  ptr->audio = NULL;
2020  }
2021  ptr->lru_next = ptr->lru_prev = NULL;
2022  return (GP_OK);
2023 }
2024 
2025 static int
2027 {
2028  CameraFilesystemFile *ptr;
2029  int count = 0;
2030 
2031  if (!fs) return 0;
2032  ptr = fs->lru_first;
2033  while (ptr) {
2034  if (ptr->normal || ptr->raw || ptr->audio)
2035  count++;
2036  ptr = ptr->lru_next;
2037  }
2038  return count;
2039 }
2040 
2041 static int
2043  const char *folder, const char *filename,
2044  CameraFileType type,
2045  CameraFile *file, GPContext *context)
2046 {
2048  CameraFilesystemFile *xfile;
2049  CameraFile *oldfile = NULL;
2050  unsigned long int size;
2051  int x;
2052  char cached_images[1024];
2053 
2054  C_PARAMS (fs && folder && file);
2055 
2056  CR (gp_file_get_data_and_size (file, NULL, &size));
2057 
2058  /*
2059  * The following is a very simple case which is used to prune
2060  * the LRU. We keep PICTURES_TO_KEEP pictures in the LRU.
2061  *
2062  * We have 2 main scenarios:
2063  * - query all thumbnails (repeatedly) ... they are cached and
2064  * are not pruned by lru free.
2065  * - download all images, linear. no real need for caching.
2066  * - skip back 1 image (in viewers) (really? I don't know.)
2067  *
2068  * So lets just keep 2 pictures in memory.
2069  */
2070  if (pictures_to_keep == -1) {
2071  if (gp_setting_get ("libgphoto", "cached-images", cached_images) == GP_OK) {
2072  pictures_to_keep = atoi(cached_images);
2073  } else {
2074  /* store a default setting */
2075  sprintf (cached_images, "%d", PICTURES_TO_KEEP);
2076  gp_setting_set ("libgphoto", "cached-images", cached_images);
2077  }
2078  }
2079 
2080  if (pictures_to_keep < 0) /* also sanity check, but no upper limit. */
2082 
2083  x = gp_filesystem_lru_count (fs);
2084  while (x > pictures_to_keep) {
2085  CR (gp_filesystem_lru_free (fs));
2086  x = gp_filesystem_lru_count (fs);
2087  }
2088 
2089  GP_LOG_D ("Adding file '%s' from folder '%s' to the fscache LRU list "
2090  "(type %i)...", filename, folder, type);
2091 
2092  /* Search folder and file */
2093  CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2094 
2095  /*
2096  * If the file is already in the lru, we first remove it. Note that
2097  * we will only remove 'normal', 'raw' and 'audio' from cache.
2098  * See gp_filesystem_lru_free.
2099  */
2100  if (xfile->lru_prev != NULL) {
2101  switch (type) {
2102  case GP_FILE_TYPE_NORMAL:
2103  oldfile = xfile->normal;
2104  break;
2105  case GP_FILE_TYPE_RAW:
2106  oldfile = xfile->raw;
2107  break;
2108  case GP_FILE_TYPE_AUDIO:
2109  oldfile = xfile->audio;
2110  break;
2111  case GP_FILE_TYPE_PREVIEW:
2112  case GP_FILE_TYPE_EXIF:
2113  case GP_FILE_TYPE_METADATA:
2114  break;
2115  default:
2116  gp_context_error (context, _("Unknown file type %i."),
2117  type);
2118  return (GP_ERROR);
2119  }
2120  if (oldfile) {
2121  CR( gp_file_get_data_and_size (oldfile, NULL, &size));
2122  fs->lru_size -= size;
2123  }
2124 
2125  CR (gp_filesystem_lru_remove_one (fs, xfile));
2126  }
2127 
2128  /* Then add the file at the end of the LRU. */
2129  if (fs->lru_first == NULL) {
2130  fs->lru_first = xfile;
2131  fs->lru_last = xfile;
2132 
2133  /*
2134  * For the first item, prev point it itself to show that the
2135  * item is in the list.
2136  */
2137  xfile->lru_prev = xfile;
2138 
2139  } else {
2140  xfile->lru_next = NULL;
2141  xfile->lru_prev = fs->lru_last;
2142  fs->lru_last->lru_next = xfile;
2143  fs->lru_last = xfile;
2144  }
2145 
2146  CR( gp_file_get_data_and_size (file, NULL, &size));
2147  fs->lru_size += size;
2148 
2149  GP_LOG_D ("File '%s' from folder '%s' added in fscache LRU list.",
2150  filename, folder);
2151 
2152  return (GP_OK);
2153 }
2154 
2155 static int
2157 {
2158  int n = 0;
2159  CameraFilesystemFile *ptr, *prev;
2160 
2161  GP_LOG_D ("Checking fscache LRU list integrity...");
2162 
2163  if (fs->lru_first == NULL) {
2164  GP_LOG_D ("fscache LRU list empty");
2165  return (GP_OK);
2166  }
2167 
2168  ptr = prev = fs->lru_first;
2169  while (ptr != NULL) {
2170  n++;
2171  if (ptr->lru_prev != prev) {
2172  GP_LOG_E ("fscache LRU list corrupted (%i)", n);
2173  return (GP_ERROR);
2174  }
2175  prev = ptr;
2176  ptr = ptr->lru_next;
2177  }
2178 
2179  GP_LOG_D ("fscache LRU list ok with %i items (%ld bytes)", n,
2180  fs->lru_size);
2181 
2182  return (GP_OK);
2183 }
2184 
2199 int
2201  const char *folder, const char *filename,
2202  CameraFileType type,
2203  CameraFile *file, GPContext *context)
2204 {
2205  CameraFileInfo info;
2207  CameraFilesystemFile *xfile;
2208  int r;
2209  time_t t;
2210 
2211  C_PARAMS (fs && folder && file);
2212  CC (context);
2213  CA (folder, context);
2214 
2215  GP_LOG_D ("Adding file '%s' to folder '%s' (type %i)...",
2216  filename, folder, type);
2217 
2218  /* Search folder and file */
2219  CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2220 
2221  /*
2222  * If we add a significant amount of data in the cache, we put (or
2223  * move) a reference to this file in the LRU linked list. We
2224  * assume that only GP_FILE_TYPE_[RAW,NORMAL,EXIF] will contain a
2225  * significant amount of data.
2226  */
2227  if ((type == GP_FILE_TYPE_RAW) || (type == GP_FILE_TYPE_NORMAL) ||
2228  (type == GP_FILE_TYPE_AUDIO))
2229  CR (gp_filesystem_lru_update (fs, folder, filename, type, file, context));
2230 
2231  /* Redundant sanity check. */
2232  CR (gp_filesystem_lru_check (fs));
2233 
2234  switch (type) {
2235  case GP_FILE_TYPE_PREVIEW:
2236  if (xfile->preview)
2237  gp_file_unref (xfile->preview);
2238  xfile->preview = file;
2239  gp_file_ref (file);
2240  break;
2241  case GP_FILE_TYPE_NORMAL:
2242  if (xfile->normal)
2243  gp_file_unref (xfile->normal);
2244  xfile->normal = file;
2245  gp_file_ref (file);
2246  break;
2247  case GP_FILE_TYPE_RAW:
2248  if (xfile->raw)
2249  gp_file_unref (xfile->raw);
2250  xfile->raw = file;
2251  gp_file_ref (file);
2252  break;
2253  case GP_FILE_TYPE_AUDIO:
2254  if (xfile->audio)
2255  gp_file_unref (xfile->audio);
2256  xfile->audio = file;
2257  gp_file_ref (file);
2258  break;
2259  case GP_FILE_TYPE_EXIF:
2260  if (xfile->exif)
2261  gp_file_unref (xfile->exif);
2262  xfile->exif = file;
2263  gp_file_ref (file);
2264  break;
2265  case GP_FILE_TYPE_METADATA:
2266  if (xfile->metadata)
2267  gp_file_unref (xfile->metadata);
2268  xfile->metadata = file;
2269  gp_file_ref (file);
2270  break;
2271  default:
2272  gp_context_error (context, _("Unknown file type %i."), type);
2273  return (GP_ERROR);
2274  }
2275 
2276  /*
2277  * If we didn't get a mtime, try to get it from the CameraFileInfo.
2278  */
2279  CR (gp_file_get_mtime (file, &t));
2280  if (!t) {
2281  GP_LOG_D ("File does not contain mtime. Trying information on the file...");
2282  r = gp_filesystem_get_info (fs, folder, filename, &info, NULL);
2283  if ((r == GP_OK) && (info.file.fields & GP_FILE_INFO_MTIME))
2284  t = info.file.mtime;
2285  }
2286 
2287  /*
2288  * If we still don't have the mtime and this is a normal
2289  * file, check if there is EXIF data in the file that contains
2290  * information on the mtime.
2291  */
2292 #ifdef HAVE_LIBEXIF
2293  if (!t && (type == GP_FILE_TYPE_NORMAL)) {
2294  unsigned long int size;
2295  const char *data;
2296 
2297  GP_LOG_D ("Searching data for mtime...");
2298  CR (gp_file_get_data_and_size (file, NULL, &size));
2299  if (size < 32*1024*1024) { /* just assume stuff above 32MB is not EXIF capable */
2300  CR (gp_file_get_data_and_size (file, &data, &size));
2301  t = get_exif_mtime ((unsigned char*)data, size);
2302  }
2303  }
2304  /*
2305  * Still no mtime? Let's see if the camera offers us data of type
2306  * GP_FILE_TYPE_EXIF that includes information on the mtime.
2307  */
2308  if (!t) {
2309  GP_LOG_D ("Trying EXIF information...");
2310  t = gp_filesystem_get_exif_mtime (fs, folder, filename);
2311  }
2312 #endif
2313 
2314  if (t)
2315  CR (gp_file_set_mtime (file, t));
2316 
2317  return (GP_OK);
2318 }
2319 
2334 int
2336  const char *folder, const char *filename,
2337  CameraFileInfo info, GPContext *context)
2338 {
2340  CameraFilesystemFile *xfile;
2341 
2342  C_PARAMS (fs && folder);
2343  CC (context);
2344  CA (folder, context);
2345 
2346  /* Search folder and file */
2347  CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2348 
2349  memcpy (&xfile->info, &info, sizeof (CameraFileInfo));
2350  xfile->info_dirty = 0;
2351  return (GP_OK);
2352 }
2353 
2366 int
2367 gp_filesystem_set_info (CameraFilesystem *fs, const char *folder,
2368  const char *filename, CameraFileInfo info,
2369  GPContext *context)
2370 {
2371  int result;
2373  CameraFilesystemFile *xfile;
2374 
2375  C_PARAMS (fs && folder && filename);
2376  CC (context);
2377  CA (folder, context);
2378 
2379  if (!fs->set_info_func) {
2380  gp_context_error (context,
2381  _("The filesystem doesn't support setting file "
2382  "information"));
2383  return (GP_ERROR_NOT_SUPPORTED);
2384  }
2385 
2386  /* Search folder and file */
2387  CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2388 
2389  /* Check if people want to set read-only attributes */
2390  if ((info.file.fields & GP_FILE_INFO_TYPE) ||
2391  (info.file.fields & GP_FILE_INFO_SIZE) ||
2392  (info.file.fields & GP_FILE_INFO_WIDTH) ||
2393  (info.file.fields & GP_FILE_INFO_HEIGHT) ||
2394  (info.file.fields & GP_FILE_INFO_STATUS) ||
2395  (info.preview.fields & GP_FILE_INFO_TYPE) ||
2396  (info.preview.fields & GP_FILE_INFO_SIZE) ||
2397  (info.preview.fields & GP_FILE_INFO_WIDTH) ||
2398  (info.preview.fields & GP_FILE_INFO_HEIGHT) ||
2399  (info.preview.fields & GP_FILE_INFO_STATUS) ||
2400  (info.audio.fields & GP_FILE_INFO_TYPE) ||
2401  (info.audio.fields & GP_FILE_INFO_SIZE) ||
2402  (info.audio.fields & GP_FILE_INFO_STATUS)) {
2403  gp_context_error (context, _("Read-only file attributes "
2404  "like width and height can not be changed."));
2405  return (GP_ERROR_BAD_PARAMETERS);
2406  }
2407 
2408  /*
2409  * Set the info. If anything goes wrong, mark info as dirty,
2410  * because the operation could have been partially successful.
2411  */
2412  result = fs->set_info_func (fs, folder, filename, info, fs->data,
2413  context);
2414  if (result < 0) {
2415  xfile->info_dirty = 1;
2416  return (result);
2417  }
2419  xfile->info.file.permissions = info.file.permissions;
2420 
2421  return (GP_OK);
2422 }
2423 
2448 int
2450  CameraFilesystem *fs,
2451  CameraStorageInformation **storageinfo,
2452  int *nrofstorageinfos,
2453  GPContext *context
2454 ) {
2455  C_PARAMS (fs && storageinfo && nrofstorageinfos);
2456  CC (context);
2457 
2458  if (!fs->storage_info_func) {
2459  gp_context_error (context,
2460  _("The filesystem doesn't support getting storage "
2461  "information"));
2462  return (GP_ERROR_NOT_SUPPORTED);
2463  }
2464  return fs->storage_info_func (fs,
2465  storageinfo, nrofstorageinfos,
2466  fs->data, context);
2467 }
gp_file_set_mime_type
int gp_file_set_mime_type(CameraFile *file, const char *mime_type)
Definition: gphoto2-file.c:1013
lookup_folder_file
static int lookup_folder_file(CameraFilesystem *fs, const char *folder, const char *filename, CameraFilesystemFolder **xfolder, CameraFilesystemFile **xfile, GPContext *context)
Definition: gphoto2-filesys.c:432
gp_filesystem_scan
static int gp_filesystem_scan(CameraFilesystem *fs, const char *folder, const char *filename, GPContext *context)
Definition: gphoto2-filesys.c:1422
gp_file_unref
int gp_file_unref(CameraFile *file)
Decrease reference counter for CameraFile object.
Definition: gphoto2-file.c:184
_CameraFilesystemFile::metadata
CameraFile * metadata
Definition: gphoto2-filesys.c:82
append_file
static int append_file(CameraFilesystem *fs, CameraFilesystemFolder *folder, const char *name, CameraFile *file, GPContext *context)
Definition: gphoto2-filesys.c:596
recursive_fs_dump
static void recursive_fs_dump(CameraFilesystemFolder *folder, int depth)
Definition: gphoto2-filesys.c:779
gp_file_adjust_name_for_mime_type
int gp_file_adjust_name_for_mime_type(CameraFile *file)
Definition: gphoto2-file.c:1083
_CameraFilesystemFile::info
CameraFileInfo info
Definition: gphoto2-filesys.c:73
gp_setting_set
int gp_setting_set(char *id, char *key, char *value)
Set a specific gphoto setting.
Definition: gphoto2-setting.c:107
_CameraFilesystemFuncs::file_list_func
CameraFilesystemListFunc file_list_func
Definition: gphoto2-filesys.h:349
_CameraFilesystem::put_file_func
CameraFilesystemPutFileFunc put_file_func
Definition: gphoto2-filesys.c:256
gp_file_get_mtime
int gp_file_get_mtime(CameraFile *file, time_t *mtime)
Definition: gphoto2-file.c:1130
gp_file_new
int gp_file_new(CameraFile **file)
Definition: gphoto2-file.c:83
gp_filesystem_get_folder
int gp_filesystem_get_folder(CameraFilesystem *fs, const char *filename, char **folder, GPContext *context)
Search a folder that contains a given filename.
Definition: gphoto2-filesys.c:1515
_CameraFilesystem::data
void * data
Definition: gphoto2-filesys.c:262
_CameraFilesystemFolder
Definition: gphoto2-filesys.c:87
CameraFilesystemDeleteFileFunc
int(* CameraFilesystemDeleteFileFunc)(CameraFilesystem *fs, const char *folder, const char *filename, void *data, GPContext *context)
Definition: gphoto2-filesys.h:307
_CameraFilesystemFolder::next
struct _CameraFilesystemFolder * next
Definition: gphoto2-filesys.c:93
gp_filesystem_get_info
int gp_filesystem_get_info(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileInfo *info, GPContext *context)
Get information about the specified file.
Definition: gphoto2-filesys.c:1857
_CameraFilesystem::remove_dir_func
CameraFilesystemDirFunc remove_dir_func
Definition: gphoto2-filesys.c:259
internal_append
static int internal_append(CameraFilesystem *fs, CameraFilesystemFolder *f, const char *filename, GPContext *context)
Append a file to a folder in a filesystem.
Definition: gphoto2-filesys.c:714
_CameraFilesystem::delete_all_func
CameraFilesystemDeleteAllFunc delete_all_func
Definition: gphoto2-filesys.c:257
_CameraFilesystemFuncs::set_info_func
CameraFilesystemSetInfoFunc set_info_func
Definition: gphoto2-filesys.h:354
gp_list_get_name
int gp_list_get_name(CameraList *list, int index, const char **name)
Definition: gphoto2-list.c:280
CL
#define CL(result, list)
Definition: gphoto2-filesys.c:270
gp_filesystem_make_dir
int gp_filesystem_make_dir(CameraFilesystem *fs, const char *folder, const char *name, GPContext *context)
Create a subfolder within a folder.
Definition: gphoto2-filesys.c:1183
GP_ERROR_FILE_NOT_FOUND
#define GP_ERROR_FILE_NOT_FOUND
Specified file was not found.
Definition: gphoto2-result.h:75
CameraFilesystemFolder
struct _CameraFilesystemFolder CameraFilesystemFolder
gp_filesystem_count
int gp_filesystem_count(CameraFilesystem *fs, const char *folder, GPContext *context)
Count files a folder of a filesystem.
Definition: gphoto2-filesys.c:1076
gp_filesystem_lru_remove_one
static int gp_filesystem_lru_remove_one(CameraFilesystem *fs, CameraFilesystemFile *item)
Definition: gphoto2-filesys.c:1946
gp_filesystem_append
int gp_filesystem_append(CameraFilesystem *fs, const char *folder, const char *filename, GPContext *context)
Definition: gphoto2-filesys.c:743
_CameraFilesystemFuncs::delete_all_func
CameraFilesystemDeleteAllFunc delete_all_func
Definition: gphoto2-filesys.h:352
_CameraFileInfo::preview
CameraFileInfoPreview preview
Definition: gphoto2-filesys.h:142
_CameraFilesystem::make_dir_func
CameraFilesystemDirFunc make_dir_func
Definition: gphoto2-filesys.c:258
_CameraFilesystemFile::audio
CameraFile * audio
Definition: gphoto2-filesys.c:80
CU
#define CU(result, file)
Definition: gphoto2-filesys.c:280
CameraFile
File structure.
GP_FILE_INFO_TYPE
@ GP_FILE_INFO_TYPE
The MIME type is set.
Definition: gphoto2-filesys.h:57
gp_filesystem_lru_free
static int gp_filesystem_lru_free(CameraFilesystem *fs)
Definition: gphoto2-filesys.c:1984
_CameraFilesystemFolder::files
struct _CameraFilesystemFile * files
Definition: gphoto2-filesys.c:95
delete_file
static int delete_file(CameraFilesystem *fs, CameraFilesystemFolder *folder, CameraFilesystemFile *file)
Definition: gphoto2-filesys.c:813
delete_all_folders
static int delete_all_folders(CameraFilesystem *fs, const char *foldername, GPContext *context)
Definition: gphoto2-filesys.c:490
gp_list_count
int gp_list_count(CameraList *list)
Definition: gphoto2-list.c:229
gp_filesystem_dump
int gp_filesystem_dump(CameraFilesystem *fs)
Dump the current filesystem.
Definition: gphoto2-filesys.c:805
gp_filesystem_reset
int gp_filesystem_reset(CameraFilesystem *fs)
Clear the filesystem.
Definition: gphoto2-filesys.c:631
GP_FILE_TYPE_PREVIEW
@ GP_FILE_TYPE_PREVIEW
Definition: gphoto2-file.h:74
_CameraFileInfoAudio::fields
CameraFileInfoFields fields
Bitmask containing the set members.
Definition: gphoto2-filesys.h:129
CameraFilesystemFile
struct _CameraFilesystemFile CameraFilesystemFile
CameraFilesystemGetInfoFunc
int(* CameraFilesystemGetInfoFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileInfo *info, void *data, GPContext *context)
Definition: gphoto2-filesys.h:279
_CameraFileInfoFile::permissions
CameraFilePermissions permissions
Permissions of the file.
Definition: gphoto2-filesys.h:102
_CameraFileInfo::audio
CameraFileInfoAudio audio
Definition: gphoto2-filesys.h:144
gp_list_reset
int gp_list_reset(CameraList *list)
Definition: gphoto2-list.c:148
GP_ERROR_NO_MEMORY
#define GP_ERROR_NO_MEMORY
Out of memory.
Definition: gphoto2-port-result.h:42
_CameraFilesystemFuncs::storage_info_func
CameraFilesystemStorageInfoFunc storage_info_func
Definition: gphoto2-filesys.h:360
_CameraFilesystemFuncs::folder_list_func
CameraFilesystemListFunc folder_list_func
Definition: gphoto2-filesys.h:350
GP_FILE_INFO_HEIGHT
@ GP_FILE_INFO_HEIGHT
The height is set.
Definition: gphoto2-filesys.h:60
GP_FILE_INFO_WIDTH
@ GP_FILE_INFO_WIDTH
The width is set.
Definition: gphoto2-filesys.h:59
GP_ERROR_FILE_EXISTS
#define GP_ERROR_FILE_EXISTS
File already exists.
Definition: gphoto2-result.h:50
CameraFilesystemStorageInfoFunc
int(* CameraFilesystemStorageInfoFunc)(CameraFilesystem *fs, CameraStorageInformation **, int *nrofstorageinformations, void *data, GPContext *context)
Definition: gphoto2-filesys.h:337
CameraFileType
CameraFileType
The type of view on the specified file.
Definition: gphoto2-file.h:73
gp_file_get_data_and_size
int gp_file_get_data_and_size(CameraFile *file, const char **data, unsigned long int *size)
Definition: gphoto2-file.c:398
_CameraFilesystem::file_list_func
CameraFilesystemListFunc file_list_func
Definition: gphoto2-filesys.c:251
result
int result
Definition: gphoto2-result.c:44
gp_file_set_name
int gp_file_set_name(CameraFile *file, const char *name)
Definition: gphoto2-file.c:996
gp_list_free
int gp_list_free(CameraList *list)
Definition: gphoto2-list.c:120
_CameraFilesystemFile::exif
CameraFile * exif
Definition: gphoto2-filesys.c:81
GP_FILE_INFO_STATUS
@ GP_FILE_INFO_STATUS
The status is set (downloaded).
Definition: gphoto2-filesys.h:62
gp_filesystem_set_info
int gp_filesystem_set_info(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileInfo info, GPContext *context)
Set information about a file.
Definition: gphoto2-filesys.c:2367
gp_filesystem_delete_file
int gp_filesystem_delete_file(CameraFilesystem *fs, const char *folder, const char *filename, GPContext *context)
Delete a file from a folder.
Definition: gphoto2-filesys.c:1113
_CameraFilesystem::get_info_func
CameraFilesystemGetInfoFunc get_info_func
Definition: gphoto2-filesys.c:249
_CameraFileInfoPreview::fields
CameraFileInfoFields fields
Bitmask containing the set members.
Definition: gphoto2-filesys.h:113
gp_filesystem_free
int gp_filesystem_free(CameraFilesystem *fs)
Free filesystem struct.
Definition: gphoto2-filesys.c:686
recurse_delete_folder
static int recurse_delete_folder(CameraFilesystem *fs, CameraFilesystemFolder *folder)
Definition: gphoto2-filesys.c:477
GP_FILE_TYPE_NORMAL
@ GP_FILE_TYPE_NORMAL
Definition: gphoto2-file.h:75
_CameraFilesystem::lru_size
unsigned long int lru_size
Definition: gphoto2-filesys.c:247
gp_list_append
int gp_list_append(CameraList *list, const char *name, const char *value)
Definition: gphoto2-list.c:174
_CameraFileInfoFile::fields
CameraFileInfoFields fields
Bitmask containing the set members.
Definition: gphoto2-filesys.h:96
GP_MIME_EXIF
#define GP_MIME_EXIF
Definition: gphoto2-file.h:53
gp_filesystem_put_file
int gp_filesystem_put_file(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, GPContext *context)
Upload a file to a folder on the device filesystem.
Definition: gphoto2-filesys.c:1292
gphoto2-result.h
_CameraFilesystemFile::lru_prev
struct _CameraFilesystemFile * lru_prev
Definition: gphoto2-filesys.c:75
_CameraFilesystemFolder::name
char * name
Definition: gphoto2-filesys.c:88
_
#define _(String)
Definition: gphoto2-filesys.c:60
GP_FILE_TYPE_RAW
@ GP_FILE_TYPE_RAW
Definition: gphoto2-file.h:76
_CameraFilesystem::set_info_func
CameraFilesystemSetInfoFunc set_info_func
Definition: gphoto2-filesys.c:250
delete_folder
static int delete_folder(CameraFilesystem *fs, CameraFilesystemFolder **folder)
Definition: gphoto2-filesys.c:352
gp_filesystem_set_file_noop
int gp_filesystem_set_file_noop(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, GPContext *context)
Attach file content to a specified file.
Definition: gphoto2-filesys.c:2200
_CameraFilesystem::lru_first
CameraFilesystemFile * lru_first
Definition: gphoto2-filesys.c:245
GP_ERROR_BAD_PARAMETERS
#define GP_ERROR_BAD_PARAMETERS
Bad parameters passed.
Definition: gphoto2-port-result.h:38
gp_filesystem_list_files
int gp_filesystem_list_files(CameraFilesystem *fs, const char *folder, CameraList *list, GPContext *context)
Get the list of files in a folder.
Definition: gphoto2-filesys.c:952
gp_filesystem_lru_update
static int gp_filesystem_lru_update(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, GPContext *context)
Definition: gphoto2-filesys.c:2042
gp_filesystem_read_file
int gp_filesystem_read_file(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, uint64_t offset, char *buf, uint64_t *size, GPContext *context)
Get partial file data from the filesystem.
Definition: gphoto2-filesys.c:1767
PICTURES_TO_KEEP
#define PICTURES_TO_KEEP
Definition: gphoto2-filesys.c:102
GP_OK
#define GP_OK
Everything is OK.
Definition: gphoto2-port-result.h:30
_CameraFilesystemFolder::folders
struct _CameraFilesystemFolder * folders
Definition: gphoto2-filesys.c:94
gp_filesystem_set_funcs
int gp_filesystem_set_funcs(CameraFilesystem *fs, CameraFilesystemFuncs *funcs, void *data)
Set all filesystem related function pointers.
Definition: gphoto2-filesys.c:1824
gp_filesystem_delete_file_noop
int gp_filesystem_delete_file_noop(CameraFilesystem *fs, const char *folder, const char *filename, GPContext *context)
Delete a virtal file from a folder in the filesystem.
Definition: gphoto2-filesys.c:1157
_CameraFilesystemFuncs::read_file_func
CameraFilesystemReadFileFunc read_file_func
Definition: gphoto2-filesys.h:358
recursive_folder_scan
static int recursive_folder_scan(CameraFilesystemFolder *folder, const char *lookforfile, char **foldername)
Definition: gphoto2-filesys.c:1462
CameraFilesystemListFunc
int(* CameraFilesystemListFunc)(CameraFilesystem *fs, const char *folder, CameraList *list, void *data, GPContext *context)
Definition: gphoto2-filesys.h:265
_CameraFilesystemFile::preview
CameraFile * preview
Definition: gphoto2-filesys.c:77
gphoto2-setting.h
gp_filesystem_lru_check
static int gp_filesystem_lru_check(CameraFilesystem *fs)
Definition: gphoto2-filesys.c:2156
GP_FILE_TYPE_EXIF
@ GP_FILE_TYPE_EXIF
Definition: gphoto2-file.h:80
gp_file_ref
int gp_file_ref(CameraFile *file)
Increase reference counter for CameraFile object.
Definition: gphoto2-file.c:167
CameraFilesystemGetFileFunc
int(* CameraFilesystemGetFileFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, void *data, GPContext *context)
Definition: gphoto2-filesys.h:292
_CameraFilesystemFuncs::get_file_func
CameraFilesystemGetFileFunc get_file_func
Definition: gphoto2-filesys.h:357
gp_filesystem_lru_count
static int gp_filesystem_lru_count(CameraFilesystem *fs)
Definition: gphoto2-filesys.c:2026
CameraFilesystemDirFunc
int(* CameraFilesystemDirFunc)(CameraFilesystem *fs, const char *folder, const char *name, void *data, GPContext *context)
Definition: gphoto2-filesys.h:332
_CameraFilesystemFolder::files_dirty
int files_dirty
Definition: gphoto2-filesys.c:90
_CameraFileInfoFile::mtime
time_t mtime
Modification time of the file.
Definition: gphoto2-filesys.h:103
_CameraFilesystemFile
Definition: gphoto2-filesys.c:68
_CameraFilesystem::get_file_func
CameraFilesystemGetFileFunc get_file_func
Definition: gphoto2-filesys.c:253
gp_filesystem_set_info_noop
int gp_filesystem_set_info_noop(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileInfo info, GPContext *context)
Store the file information in the virtual fs.
Definition: gphoto2-filesys.c:2335
CameraFilesystemDeleteAllFunc
int(* CameraFilesystemDeleteAllFunc)(CameraFilesystem *fs, const char *folder, void *data, GPContext *context)
Definition: gphoto2-filesys.h:329
_CameraFilesystemFuncs::remove_dir_func
CameraFilesystemDirFunc remove_dir_func
Definition: gphoto2-filesys.h:356
_CameraFilesystemFile::normal
CameraFile * normal
Definition: gphoto2-filesys.c:78
gphoto2-filesys.h
Filesystem related operations and declarations.
_CameraFileInfo
File information structure.
Definition: gphoto2-filesys.h:141
append_folder_one
static int append_folder_one(CameraFilesystemFolder *folder, const char *name, CameraFilesystemFolder **newfolder)
Definition: gphoto2-filesys.c:509
GP_ERROR
#define GP_ERROR
Generic Error.
Definition: gphoto2-port-result.h:34
gp_setting_get
int gp_setting_get(char *id, char *key, char *value)
Retrieve a specific gphoto setting.
Definition: gphoto2-setting.c:75
append_folder
static int append_folder(CameraFilesystem *fs, const char *folder, CameraFilesystemFolder **newfolder, GPContext *context)
Definition: gphoto2-filesys.c:582
CameraFilesystemPutFileFunc
int(* CameraFilesystemPutFileFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, void *data, GPContext *context)
Definition: gphoto2-filesys.h:322
CC
#define CC(context)
Definition: gphoto2-filesys.c:290
gp_filesystem_lru_clear
static int gp_filesystem_lru_clear(CameraFilesystem *fs)
Definition: gphoto2-filesys.c:1910
GP_FILE_INFO_PERMISSIONS
@ GP_FILE_INFO_PERMISSIONS
The access permissions are set.
Definition: gphoto2-filesys.h:61
CR
#define CR(result)
Definition: gphoto2-filesys.c:268
_CameraFilesystemFile::name
char * name
Definition: gphoto2-filesys.c:69
gp_result_as_string
const char * gp_result_as_string(int result)
Translate a gphoto error code into a localized string.
Definition: gphoto2-result.c:73
gp_filesystem_new
int gp_filesystem_new(CameraFilesystem **fs)
Create a new filesystem struct.
Definition: gphoto2-filesys.c:655
_CameraFilesystemFuncs::del_file_func
CameraFilesystemDeleteFileFunc del_file_func
Definition: gphoto2-filesys.h:359
GP_FILE_TYPE_AUDIO
@ GP_FILE_TYPE_AUDIO
Definition: gphoto2-file.h:79
_CameraFilesystemFile::next
struct _CameraFilesystemFile * next
Definition: gphoto2-filesys.c:84
_CameraFilesystemFile::info_dirty
int info_dirty
Definition: gphoto2-filesys.c:71
delete_all_files
static int delete_all_files(CameraFilesystem *fs, CameraFilesystemFolder *folder)
Definition: gphoto2-filesys.c:306
_CameraFilesystemFile::raw
CameraFile * raw
Definition: gphoto2-filesys.c:79
gp_context_error
void gp_context_error(GPContext *context, const char *format,...)
Definition: gphoto2-context.c:203
_CameraFilesystemFile::lru_next
struct _CameraFilesystemFile * lru_next
Definition: gphoto2-filesys.c:76
_CameraFilesystem::read_file_func
CameraFilesystemReadFileFunc read_file_func
Definition: gphoto2-filesys.c:254
gp_list_new
int gp_list_new(CameraList **list)
Creates a new CameraList.
Definition: gphoto2-list.c:63
CA
#define CA(f, c)
Definition: gphoto2-filesys.c:296
gp_file_set_mtime
int gp_file_set_mtime(CameraFile *file, time_t mtime)
Definition: gphoto2-file.c:1147
_CameraFilesystemFuncs
Definition: gphoto2-filesys.h:348
_CameraFilesystem::folder_list_func
CameraFilesystemListFunc folder_list_func
Definition: gphoto2-filesys.c:252
GP_FILE_INFO_SIZE
@ GP_FILE_INFO_SIZE
The filesize is set.
Definition: gphoto2-filesys.h:58
_CameraFilesystemFuncs::put_file_func
CameraFilesystemPutFileFunc put_file_func
Definition: gphoto2-filesys.h:351
_CameraList
Definition: gphoto2-list.c:47
_CameraFilesystemFuncs::make_dir_func
CameraFilesystemDirFunc make_dir_func
Definition: gphoto2-filesys.h:355
gphoto2-port-log.h
GP_ERROR_CORRUPTED_DATA
#define GP_ERROR_CORRUPTED_DATA
Corrupted data received.
Definition: gphoto2-result.h:42
gp_filesystem_get_file
int gp_filesystem_get_file(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, GPContext *context)
Get file data from the filesystem.
Definition: gphoto2-filesys.c:1634
_CameraFilesystem::storage_info_func
CameraFilesystemStorageInfoFunc storage_info_func
Definition: gphoto2-filesys.c:260
_CameraFilesystem
The internal camera filesystem structure.
Definition: gphoto2-filesys.c:242
gp_file_copy
int gp_file_copy(CameraFile *destination, CameraFile *source)
Definition: gphoto2-file.c:729
gp_filesystem_number
int gp_filesystem_number(CameraFilesystem *fs, const char *folder, const char *filename, GPContext *context)
Get the index of a file in specified folder.
Definition: gphoto2-filesys.c:1384
GP_MIME_JPEG
#define GP_MIME_JPEG
Definition: gphoto2-file.h:43
GP_FILE_TYPE_METADATA
@ GP_FILE_TYPE_METADATA
Definition: gphoto2-file.h:81
gp_filesystem_delete_all_one_by_one
static int gp_filesystem_delete_all_one_by_one(CameraFilesystem *fs, const char *folder, GPContext *context)
Definition: gphoto2-filesys.c:857
_CameraFilesystem::rootfolder
CameraFilesystemFolder * rootfolder
Definition: gphoto2-filesys.c:243
GP_FILE_INFO_MTIME
@ GP_FILE_INFO_MTIME
The modification time is set.
Definition: gphoto2-filesys.h:63
gp_filesystem_remove_dir
int gp_filesystem_remove_dir(CameraFilesystem *fs, const char *folder, const char *name, GPContext *context)
Remove a subfolder from within a folder.
Definition: gphoto2-filesys.c:1217
gp_filesystem_get_storageinfo
int gp_filesystem_get_storageinfo(CameraFilesystem *fs, CameraStorageInformation **storageinfo, int *nrofstorageinfos, GPContext *context)
Get the storage information about this filesystem.
Definition: gphoto2-filesys.c:2449
pictures_to_keep
static int pictures_to_keep
Definition: gphoto2-filesys.c:107
append_to_folder
static int append_to_folder(CameraFilesystemFolder *folder, const char *foldername, CameraFilesystemFolder **newfolder)
Definition: gphoto2-filesys.c:535
gp_filesystem_name
int gp_filesystem_name(CameraFilesystem *fs, const char *folder, int filenumber, const char **filename, GPContext *context)
Lookup the filename of an indexed file within a folder.
Definition: gphoto2-filesys.c:1338
_CameraFilesystem::delete_file_func
CameraFilesystemDeleteFileFunc delete_file_func
Definition: gphoto2-filesys.c:255
gp_filesystem_delete_all
int gp_filesystem_delete_all(CameraFilesystem *fs, const char *folder, GPContext *context)
Delete all files in specified folder.
Definition: gphoto2-filesys.c:891
CameraFilesystemSetInfoFunc
int(* CameraFilesystemSetInfoFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileInfo info, void *data, GPContext *context)
Definition: gphoto2-filesys.h:274
gp_file_set_data_and_size
int gp_file_set_data_and_size(CameraFile *file, char *data, unsigned long int size)
Definition: gphoto2-file.c:313
CameraFilesystemReadFileFunc
int(* CameraFilesystemReadFileFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, uint64_t offset, char *buf, uint64_t *size, void *data, GPContext *context)
Definition: gphoto2-filesys.h:298
_CameraFileInfo::file
CameraFileInfoFile file
Definition: gphoto2-filesys.h:143
_CameraFilesystemFolder::folders_dirty
int folders_dirty
Definition: gphoto2-filesys.c:91
GP_ERROR_DIRECTORY_EXISTS
#define GP_ERROR_DIRECTORY_EXISTS
Specified directory already exists.
Definition: gphoto2-result.h:83
gp_filesystem_get_file_impl
static int gp_filesystem_get_file_impl(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, GPContext *context)
Definition: gphoto2-filesys.c:1532
gp_filesystem_list_folders
int gp_filesystem_list_folders(CameraFilesystem *fs, const char *folder, CameraList *list, GPContext *context)
List all subfolders within a filesystem folder.
Definition: gphoto2-filesys.c:1018
GP_ERROR_DIRECTORY_NOT_FOUND
#define GP_ERROR_DIRECTORY_NOT_FOUND
Specified directory was not found.
Definition: gphoto2-result.h:67
GP_ERROR_NOT_SUPPORTED
#define GP_ERROR_NOT_SUPPORTED
Functionality not supported.
Definition: gphoto2-port-result.h:54
_CameraFilesystemFuncs::get_info_func
CameraFilesystemGetInfoFunc get_info_func
Definition: gphoto2-filesys.h:353
_GPContext
Definition: gphoto2-context.c:39
lookup_folder
static CameraFilesystemFolder * lookup_folder(CameraFilesystem *fs, CameraFilesystemFolder *folder, const char *foldername, GPContext *context)
Definition: gphoto2-filesys.c:367
_CameraFilesystem::lru_last
CameraFilesystemFile * lru_last
Definition: gphoto2-filesys.c:246
_CameraStorageInformation
Storage information structue.
Definition: gphoto2-filesys.h:214