libgphoto2 photo camera library (libgphoto2) Internals  2.5.26
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
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  ((ssize_t)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  ((ssize_t)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 
637  /* the recurse delete will not delete the files in /, only in subdirs */
638  delete_all_files (fs, fs->rootfolder);
639 
640  if (fs->rootfolder) {
641  fs->rootfolder->files_dirty = 1;
642  fs->rootfolder->folders_dirty = 1;
643  } else {
644  GP_LOG_E ("root folder is gone?");
645  }
646  return (GP_OK);
647 }
648 
658 int
660 {
661  C_PARAMS (fs);
662 
663  C_MEM (*fs = calloc (1, sizeof (CameraFilesystem)));
664 
665  (*fs)->rootfolder = calloc (sizeof (CameraFilesystemFolder), 1);
666  if (!(*fs)->rootfolder) {
667  free (*fs);
668  return (GP_ERROR_NO_MEMORY);
669  }
670  (*fs)->rootfolder->name = strdup("/");
671  if (!(*fs)->rootfolder->name) {
672  free ((*fs)->rootfolder);
673  free (*fs);
674  return (GP_ERROR_NO_MEMORY);
675  }
676  (*fs)->rootfolder->files_dirty = 1;
677  (*fs)->rootfolder->folders_dirty = 1;
678  return (GP_OK);
679 }
680 
689 int
691 {
692  /* We don't care for success or failure */
693  gp_filesystem_reset (fs);
694 
695  /* Now, we've only got left over the root folder. Free that and
696  * the filesystem. */
697  free (fs->rootfolder->name);
698  free (fs->rootfolder);
699  free (fs);
700  return (GP_OK);
701 }
702 
717 static int
719  const char *filename, GPContext *context)
720 {
721  CameraFilesystemFile **new;
722 
723  C_PARAMS (fs && f);
724 
725  GP_LOG_D ("Internal append %s to folder %s", filename, f->name);
726  /* Check folder for existence, if not, create it. */
727  new = &f->files;
728  while (*new) {
729  if (!strcmp((*new)->name, filename)) break;
730  new = &((*new)->next);
731  }
732  if (*new)
733  return (GP_ERROR_FILE_EXISTS);
734 
735  C_MEM ((*new) = calloc (sizeof (CameraFilesystemFile), 1));
736  (*new)->name = strdup (filename);
737  if (!(*new)->name) {
738  free (*new);
739  *new = NULL;
740  return (GP_ERROR_NO_MEMORY);
741  }
742  (*new)->info_dirty = 1;
743  return (GP_OK);
744 }
745 
746 int
747 gp_filesystem_append (CameraFilesystem *fs, const char *folder,
748  const char *filename, GPContext *context)
749 {
751  int ret;
752 
753  C_PARAMS (fs && folder);
754  CC (context);
755  CA (folder, context);
756 
757  GP_LOG_D ("Append %s/%s to filesystem", folder, filename);
758  /* Check folder for existence, if not, create it. */
759  f = lookup_folder (fs, fs->rootfolder, folder, context);
760  if (!f)
761  CR (append_folder (fs, folder, &f, context));
762  if (f->files_dirty) { /* Need to load folder from driver first ... capture case */
763  CameraList *xlist;
764  int ret;
765 
766  ret = gp_list_new (&xlist);
767  if (ret != GP_OK) return ret;
768  ret = gp_filesystem_list_files (fs, folder, xlist, context);
769  gp_list_free (xlist);
770  if (ret != GP_OK) return ret;
771  }
772 
773  // Only try to append the file if filename is not empty
774  if (filename && strlen(filename)!=0)
775  ret = internal_append (fs, f, filename, context);
776  if (ret == GP_ERROR_FILE_EXISTS) /* not an error here ... just in case we add files twice to the list */
777  ret = GP_OK;
778  return ret;
779 }
780 
781 
782 static void
785  CameraFilesystemFile *xfile;
786 
787  GP_LOG_D ("%*sFolder %s", depth, " ", folder->name);
788 
789  xfile = folder->files;
790  while (xfile) {
791  GP_LOG_D ("%*s %s", depth, " ", xfile->name);
792  xfile = xfile->next;
793  }
794 
795  f = folder->folders;
796  while (f) {
797  recursive_fs_dump (f, depth+4);
798  f = f->next;
799  }
800 }
808 int
810 {
811  GP_LOG_D ("Dumping Filesystem:");
812  recursive_fs_dump (fs->rootfolder, 0);
813  return (GP_OK);
814 }
815 
816 static int
818 {
819  CameraFilesystemFile **prev;
820 
821  gp_filesystem_lru_remove_one (fs, file);
822  /* Get rid of cached files */
823  if (file->preview) {
824  gp_file_unref (file->preview);
825  file->preview = NULL;
826  }
827  if (file->normal) {
828  gp_file_unref (file->normal);
829  file->normal = NULL;
830  }
831  if (file->raw) {
832  gp_file_unref (file->raw);
833  file->raw = NULL;
834  }
835  if (file->audio) {
836  gp_file_unref (file->audio);
837  file->audio = NULL;
838  }
839  if (file->exif) {
840  gp_file_unref (file->exif);
841  file->exif = NULL;
842  }
843  if (file->metadata) {
844  gp_file_unref (file->metadata);
845  file->metadata = NULL;
846  }
847 
848  prev = &(folder->files);
849  while ((*prev) && ((*prev) != file))
850  prev = &((*prev)->next);
851  if (!*prev)
852  return GP_ERROR;
853  *prev = file->next;
854  file->next = NULL;
855  free (file->name);
856  free (file);
857  return (GP_OK);
858 }
859 
860 static int
862  GPContext *context)
863 {
864  CameraList *list;
865  int count, x;
866  const char *name;
867 
868  GP_LOG_D ("Deleting all 1 by 1 from %s", folder);
869  CR (gp_list_new (&list));
870  CL (gp_filesystem_list_files (fs, folder, list, context), list);
871  CL (count = gp_list_count (list), list);
872  for (x = count ; x--; ) {
873  CL (gp_list_get_name (list, x, &name), list);
874  CL (gp_filesystem_delete_file (fs, folder, name, context),list);
875  }
876  gp_list_free(list);
877  return (GP_OK);
878 }
879 
894 int
896  GPContext *context)
897 {
898  int r;
900 
901  C_PARAMS (fs && folder);
902  CC (context);
903  CA (folder, context);
904 
905  GP_LOG_D ("Deleting all from %s", folder);
906  /* Make sure this folder exists */
907  f = lookup_folder (fs, fs->rootfolder, folder, context);
908  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
909 
910  if (!fs->delete_all_func)
911  return gp_filesystem_delete_all_one_by_one (fs, folder, context);
912  /*
913  * Mark the folder dirty - it could be that an error
914  * happens, and then we don't know which files have been
915  * deleted and which not.
916  */
917  f->files_dirty = 1;
918  /*
919  * First try to use the delete_all function. If that fails,
920  * fall back to deletion one-by-one.
921  */
922  r = fs->delete_all_func (fs, folder, fs->data, context);
923  if (r < 0) {
924  GP_LOG_D (
925  "delete_all failed (%s). Falling back to "
926  "deletion one-by-one.",
927  gp_result_as_string (r));
929  context));
930  } else {
931  /* delete from filesystem view too now */
932  CR (delete_all_files (fs, f));
933  }
934  /*
935  * No error happened. We can be sure that all files have been
936  * deleted.
937  */
938  f->files_dirty = 0;
939  return (GP_OK);
940 }
941 
955 int
957  CameraList *list, GPContext *context)
958 {
959  int count, y;
960  const char *name;
962  CameraFilesystemFile *file;
963 
964  GP_LOG_D ("Listing files in %s", folder);
965 
966  C_PARAMS (fs && list && folder);
967  CC (context);
968  CA (folder, context);
969 
970  gp_list_reset (list);
971 
972  /* Search the folder */
973  f = lookup_folder (fs, fs->rootfolder, folder, context);
974  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
975 
976  /* If the folder is dirty, delete the contents and query the camera */
977  if (f->files_dirty && fs->file_list_func) {
978  GP_LOG_D ("Querying folder %s...", folder);
979  CR (delete_all_files (fs, f));
980 
981  /* set it to non-dirty now, so we do not recurse via _append. */
982  f->files_dirty = 0;
983  CR (fs->file_list_func (fs, folder, list,
984  fs->data, context));
985 
986  CR (count = gp_list_count (list));
987  for (y = 0; y < count; y++) {
988  CR (gp_list_get_name (list, y, &name));
989  GP_LOG_D ("Added '%s'", name);
990  CR (internal_append (fs, f, name, context));
991  }
992  gp_list_reset (list);
993  }
994  /* The folder is clean now */
995  f->files_dirty = 0;
996 
997  file = f->files;
998  while (file) {
999  GP_LOG_D (
1000  "Listed '%s'", file->name);
1001  CR (gp_list_append (list, file->name, NULL));
1002  file = file->next;
1003  }
1004  return (GP_OK);
1005 }
1006 
1021 int
1023  CameraList *list, GPContext *context)
1024 {
1025  int y, count;
1026  const char *name;
1027  CameraFilesystemFolder *f, *new;
1028 
1029  GP_LOG_D ("Listing folders in %s", folder);
1030 
1031  C_PARAMS (fs && folder && list);
1032  CC (context);
1033  CA (folder, context);
1034 
1035  gp_list_reset (list);
1036 
1037  /* Search the folder */
1038  f = lookup_folder (fs, fs->rootfolder, folder, context);
1039  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1040 
1041 
1042  /* If the folder is dirty, query the contents. */
1043  if (f->folders_dirty && fs->folder_list_func) {
1044  GP_LOG_D ("... is dirty, getting from camera");
1045  CR (fs->folder_list_func (fs, folder, list,
1046  fs->data, context));
1047  CR (delete_all_folders (fs, folder, context));
1048 
1049  CR (count = gp_list_count (list));
1050  for (y = 0; y < count; y++) {
1051  CR (gp_list_get_name (list, y, &name));
1052  CR (append_folder_one (f, name, NULL));
1053  }
1054  /* FIXME: why not just return (GP_OK); ? the list should be fine */
1055  gp_list_reset (list);
1056  }
1057 
1058  new = f->folders;
1059  while (new) {
1060  CR (gp_list_append (list, new->name, NULL));
1061  new = new->next;
1062  }
1063  /* The folder is clean now */
1064  f->folders_dirty = 0;
1065  GP_LOG_D ("Folder %s contains %i subfolders.", folder, gp_list_count (list));
1066  return (GP_OK);
1067 }
1068 
1079 int
1080 gp_filesystem_count (CameraFilesystem *fs, const char *folder,
1081  GPContext *context)
1082 {
1083  int x;
1085  CameraFilesystemFile *file;
1086 
1087  C_PARAMS (fs && folder);
1088  CC (context);
1089  CA (folder, context);
1090 
1091  f = lookup_folder (fs, fs->rootfolder, folder, context);
1092  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1093 
1094  x = 0;
1095  file = f->files;
1096  while (file) {
1097  x++;
1098  file = file->next;
1099  }
1100  return x;
1101 }
1102 
1116 int
1118  const char *filename, GPContext *context)
1119 {
1121  CameraFilesystemFile *file;
1122 
1123  C_PARAMS (fs && folder && filename);
1124  CC (context);
1125  CA (folder, context);
1126 
1127  /* First of all, do we support file deletion? */
1128  if (!fs->delete_file_func) {
1129  gp_context_error (context, _("You have been trying to delete "
1130  "'%s' from folder '%s', but the filesystem does not "
1131  "support deletion of files."), filename, folder);
1132  return (GP_ERROR_NOT_SUPPORTED);
1133  }
1134 
1135  /* Search the folder and the file */
1136  CR (lookup_folder_file (fs, folder, filename, &f, &file, context));
1137 
1138  GP_LOG_D ("Deleting '%s' from folder '%s'...", filename, folder);
1139 
1140  /* Delete the file */
1141  CR (fs->delete_file_func (fs, folder, filename,
1142  fs->data, context));
1143  CR (delete_file (fs, f, file));
1144  return (GP_OK);
1145 }
1146 
1160 int
1162  const char *filename, GPContext *context)
1163 {
1165  CameraFilesystemFile *file;
1166 
1167  C_PARAMS (fs && folder && filename);
1168  CC (context);
1169  CA (folder, context);
1170  /* Search the folder and the file */
1171  CR (lookup_folder_file (fs, folder, filename, &f, &file, context));
1172  return delete_file (fs, f, file);
1173 }
1174 
1186 int
1187 gp_filesystem_make_dir (CameraFilesystem *fs, const char *folder,
1188  const char *name, GPContext *context)
1189 {
1191 
1192  C_PARAMS (fs && folder && name);
1193  CC (context);
1194  CA (folder, context);
1195 
1196  if (!fs->make_dir_func)
1197  return (GP_ERROR_NOT_SUPPORTED);
1198 
1199  /* Search the folder */
1200  f = lookup_folder (fs, fs->rootfolder, folder, context);
1201  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1202 
1203  /* Create the directory */
1204  CR (fs->make_dir_func (fs, folder, name, fs->data, context));
1205  /* and append to internal fs */
1206  return append_folder_one (f, name, NULL);
1207 }
1208 
1220 int
1222  const char *name, GPContext *context)
1223 {
1225  CameraFilesystemFolder **prev;
1226 
1227  C_PARAMS (fs && folder && name);
1228  CC (context);
1229  CA (folder, context);
1230 
1231  if (!fs->remove_dir_func)
1232  return (GP_ERROR_NOT_SUPPORTED);
1233 
1234  /*
1235  * Make sure there are neither files nor folders in the folder
1236  * that is to be removed.
1237  */
1238  f = lookup_folder (fs, fs->rootfolder, folder, context);
1239  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1240  /* Check if we need to load the folder ... */
1241  if (f->folders_dirty) {
1242  CameraList *list;
1243  int ret;
1244  /*
1245  * The owning folder is dirty. List the folders in it
1246  * to make it clean.
1247  */
1248  GP_LOG_D ("Folder %s is dirty. "
1249  "Listing folders in there to make folder clean...", folder);
1250  ret = gp_list_new (&list);
1251  if (ret == GP_OK) {
1252  ret = gp_filesystem_list_folders (fs, folder, list, context);
1253  gp_list_free (list);
1254  GP_LOG_D ("Done making folder %s clean...", folder);
1255  }
1256  }
1257  prev = &(f->folders);
1258  while (*prev) {
1259  if (!strcmp (name, (*prev)->name))
1260  break;
1261  prev = &((*prev)->next);
1262  }
1263  if (!*prev) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1264 
1265  if ((*prev)->folders) {
1266  gp_context_error (context, _("There are still subfolders in "
1267  "folder '%s/%s' that you are trying to remove."), folder, name);
1268  return (GP_ERROR_DIRECTORY_EXISTS);
1269  }
1270  if ((*prev)->files) {
1271  gp_context_error (context, _("There are still files in "
1272  "folder '%s/%s' that you are trying to remove."), folder,name);
1273  return (GP_ERROR_FILE_EXISTS);
1274  }
1275 
1276  /* Remove the directory */
1277  CR (fs->remove_dir_func (fs, folder, name, fs->data, context));
1278  CR (delete_folder (fs, prev));
1279  return (GP_OK);
1280 }
1281 
1295 int
1297  const char *folder, const char *filename,
1298  CameraFileType type,
1299  CameraFile *file, GPContext *context)
1300 {
1302  int ret;
1303 
1304  C_PARAMS (fs && folder && file);
1305  CC (context);
1306  CA (folder, context);
1307 
1308  /* Do we support file upload? */
1309  if (!fs->put_file_func) {
1310  gp_context_error (context, _("The filesystem does not support "
1311  "upload of files."));
1312  return (GP_ERROR_NOT_SUPPORTED);
1313  }
1314 
1315  /* Search the folder */
1316  f = lookup_folder (fs, fs->rootfolder, folder, context);
1317  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1318 
1319  /* Upload the file */
1320  CR (fs->put_file_func (fs, folder, filename, type, file, fs->data, context));
1321  /* And upload it to internal structure too */
1322  ret = append_file (fs, f, filename, file, context);
1323  if (type != GP_FILE_TYPE_NORMAL) /* FIXME perhaps check before append_file? */
1324  return GP_OK;
1325  return ret;
1326 }
1327 
1341 int
1342 gp_filesystem_name (CameraFilesystem *fs, const char *folder, int filenumber,
1343  const char **filename, GPContext *context)
1344 {
1346  CameraFilesystemFile *file;
1347  int count;
1348  C_PARAMS (fs && folder);
1349  CC (context);
1350  CA (folder, context);
1351 
1352  f = lookup_folder (fs, fs->rootfolder, folder, context);
1353  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1354 
1355  file = f->files;
1356  count = 0;
1357  while (file) {
1358  if (filenumber == 0)
1359  break;
1360  filenumber--;
1361  count++;
1362  file = file->next;
1363  }
1364 
1365  if (!file) {
1366  gp_context_error (context, _("Folder '%s' only contains "
1367  "%i files, but you requested a file with number %i."),
1368  folder, count, filenumber);
1369  return (GP_ERROR_FILE_NOT_FOUND);
1370  }
1371  *filename = file->name;
1372  return (GP_OK);
1373 }
1374 
1387 int
1388 gp_filesystem_number (CameraFilesystem *fs, const char *folder,
1389  const char *filename, GPContext *context)
1390 {
1392  CameraFilesystemFile *file;
1393  CameraList *list;
1394  int num;
1395 
1396  C_PARAMS (fs && folder && filename);
1397  CC (context);
1398  CA (folder, context);
1399 
1400  f = lookup_folder (fs, fs->rootfolder, folder, context);
1401  if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1402 
1403  file = f->files;
1404  num = 0;
1405  while (file) {
1406  if (!strcmp (file->name, filename))
1407  return num;
1408  num++;
1409  file = file->next;
1410  }
1411 
1412  /* Ok, we didn't find the file. Is the folder dirty? */
1413  if (!f->files_dirty) {
1414  gp_context_error (context, _("File '%s' could not be found "
1415  "in folder '%s'."), filename, folder);
1416  return (GP_ERROR_FILE_NOT_FOUND);
1417  }
1418  /* The folder is dirty. List all files to make it clean */
1419  CR (gp_list_new(&list));
1420  CL (gp_filesystem_list_files (fs, folder, list, context), list);
1421  gp_list_free(list);
1422  return (gp_filesystem_number (fs, folder, filename, context));
1423 }
1424 
1425 static int
1426 gp_filesystem_scan (CameraFilesystem *fs, const char *folder,
1427  const char *filename, GPContext *context)
1428 {
1429  int count, x;
1430  CameraList *list;
1431  const char *name;
1432  char path[128];
1433 
1434  GP_LOG_D ("Scanning %s for %s...", folder, filename);
1435 
1436  C_PARAMS (fs && folder && filename);
1437  CC (context);
1438  CA (folder, context);
1439 
1440  CR (gp_list_new (&list));
1441  CL (gp_filesystem_list_files (fs, folder, list, context), list);
1442  CL (count = gp_list_count (list), list);
1443  for (x = 0; x < count; x++) {
1444  CL (gp_list_get_name (list, x, &name), list);
1445  if (!strcmp (filename, name)) {
1446  gp_list_free (list);
1447  return (GP_OK);
1448  }
1449  }
1450 
1451  CL (gp_filesystem_list_folders (fs, folder, list, context), list);
1452  CL (count = gp_list_count (list), list);
1453  for (x = 0; x < count; x++) {
1454  CL (gp_list_get_name (list, x, &name), list);
1455  strncpy (path, folder, sizeof (path));
1456  if (path[strlen (path) - 1] != '/')
1457  strncat (path, "/", sizeof (path) - strlen (path) - 1);
1458  strncat (path, name, sizeof (path) - strlen (path) - 1);
1459  CL (gp_filesystem_scan (fs, path, filename, context), list);
1460  }
1461  gp_list_free (list);
1462  return (GP_OK);
1463 }
1464 
1465 static int
1467  CameraFilesystemFolder *folder, const char *lookforfile,
1468  char **foldername
1469 ) {
1470  CameraFilesystemFile *file;
1472  int ret;
1473 
1474  file = folder->files;
1475  while (file) {
1476  if (!strcmp(file->name, lookforfile)) {
1477  *foldername = strdup (folder->name);
1478  return GP_OK;
1479  }
1480  file = file->next;
1481  }
1482  f = folder->folders;
1483  while (f) {
1484  char *xfolder;
1485  ret = recursive_folder_scan (f, lookforfile, &xfolder);
1486  if (ret == GP_OK) {
1487  C_MEM ((*foldername) = malloc (strlen (folder->name) + 1 + strlen (xfolder) + 1));
1488  strcpy ((*foldername),folder->name);
1489  strcat ((*foldername),"/");
1490  strcat ((*foldername),xfolder);
1491  free (xfolder);
1492  return GP_OK;
1493  }
1494  f = f->next;
1495  }
1496  /* thorugh all subfoilders */
1497  return GP_ERROR_FILE_NOT_FOUND;
1498 }
1518 int
1519 gp_filesystem_get_folder (CameraFilesystem *fs, const char *filename,
1520  char **folder, GPContext *context)
1521 {
1522  int ret;
1523 
1524  C_PARAMS (fs && filename && folder);
1525  CC (context);
1526 
1527  CR (gp_filesystem_scan (fs, "/", filename, context));
1528 
1529  ret = recursive_folder_scan ( fs->rootfolder, filename, folder);
1530  if (ret == GP_OK) return ret;
1531  gp_context_error (context, _("Could not find file '%s'."), filename);
1532  return (GP_ERROR_FILE_NOT_FOUND);
1533 }
1534 
1535 static int
1537  const char *filename, CameraFileType type,
1538  CameraFile *file, GPContext *context)
1539 {
1540  CameraFilesystemFolder *xfolder;
1541  CameraFilesystemFile *xfile;
1542  int ret;
1543 
1544  C_PARAMS (fs && folder && file && filename);
1545  CC (context);
1546  CA (folder, context);
1547 
1548  GP_LOG_D ("Getting file '%s' from folder '%s' (type %i)...",
1549  filename, folder, type);
1550 
1551  CR (gp_file_set_name (file, filename));
1552 
1553  if (!fs->get_file_func) {
1554  gp_context_error (context,
1555  _("The filesystem doesn't support getting files"));
1556  return (GP_ERROR_NOT_SUPPORTED);
1557  }
1558 
1559  /* Search folder and file */
1560  CR( lookup_folder_file (fs, folder, filename, &xfolder, &xfile, context));
1561 
1562  ret = GP_ERROR;
1563  switch (type) {
1564  case GP_FILE_TYPE_PREVIEW:
1565  if (xfile->preview)
1566  ret = gp_file_copy (file, xfile->preview);
1567  break;
1568  case GP_FILE_TYPE_NORMAL:
1569  if (xfile->normal)
1570  ret = gp_file_copy (file, xfile->normal);
1571  break;
1572  case GP_FILE_TYPE_RAW:
1573  if (xfile->raw)
1574  ret = gp_file_copy (file, xfile->raw);
1575  break;
1576  case GP_FILE_TYPE_AUDIO:
1577  if (xfile->audio)
1578  ret = gp_file_copy (file, xfile->audio);
1579  break;
1580  case GP_FILE_TYPE_EXIF:
1581  if (xfile->exif)
1582  ret = gp_file_copy (file, xfile->exif);
1583  break;
1584  case GP_FILE_TYPE_METADATA:
1585  if (xfile->metadata)
1586  ret = gp_file_copy (file, xfile->metadata);
1587  break;
1588  default:
1589  gp_context_error (context, _("Unknown file type %i."), type);
1590  return (GP_ERROR);
1591  }
1592  if (ret == GP_OK) {
1593  GP_LOG_D ("LRU cache used for type %d!", type);
1594  return GP_OK;
1595  }
1596 
1597  GP_LOG_D ("Downloading '%s' from folder '%s'...", filename, folder);
1598 
1599  CR (fs->get_file_func (fs, folder, filename, type, file,
1600  fs->data, context));
1601 
1602  /* We don't trust the camera drivers */
1603  CR (gp_file_set_name (file, filename));
1604 
1605 #if 0
1606  /* this disables LRU completely. */
1607  /* Cache this file */
1608  CR (gp_filesystem_set_file_noop (fs, folder, filename, type, file, context));
1609 #endif
1610 
1611  /*
1612  * Often, thumbnails are of a different mime type than the normal
1613  * picture. In this case, we should rename the file.
1614  */
1615  if (type != GP_FILE_TYPE_NORMAL)
1617 
1618  return (GP_OK);
1619 }
1620 
1637 int
1638 gp_filesystem_get_file (CameraFilesystem *fs, const char *folder,
1639  const char *filename, CameraFileType type,
1640  CameraFile *file, GPContext *context)
1641 {
1642  int r;
1643 #ifdef HAVE_LIBEXIF
1644  CameraFile *efile;
1645  const char *data = NULL;
1646  unsigned char *buf;
1647  unsigned int buf_size;
1648  unsigned long int size = 0;
1649  ExifData *ed;
1650 #endif
1651 
1652  r = gp_filesystem_get_file_impl (fs, folder, filename, type,
1653  file, context);
1654 
1655  if ((r == GP_ERROR_NOT_SUPPORTED) &&
1656  (type == GP_FILE_TYPE_PREVIEW)) {
1657 
1658  /*
1659  * Could not get preview (unsupported operation). Some
1660  * cameras hide the thumbnail in EXIF data. Check it out.
1661  */
1662 #ifdef HAVE_LIBEXIF
1663  GP_LOG_D ("Getting previews is not supported. Trying EXIF data...");
1664  CR (gp_file_new (&efile));
1665  CU (gp_filesystem_get_file_impl (fs, folder, filename,
1666  GP_FILE_TYPE_EXIF, efile, context), efile);
1667  CU (gp_file_get_data_and_size (efile, &data, &size), efile);
1668  ed = exif_data_new_from_data ((unsigned char*)data, size);
1669  gp_file_unref (efile);
1670  if (!ed) {
1671  GP_LOG_E ("Could not parse EXIF data of '%s' in folder '%s'.", filename, folder);
1672  return (GP_ERROR_CORRUPTED_DATA);
1673  }
1674  if (!ed->data) {
1675  GP_LOG_E ("EXIF data does not contain a thumbnail.");
1676  exif_data_unref (ed);
1677  return (r);
1678  }
1679 
1680  /*
1681  * We found a thumbnail in EXIF data! Those
1682  * thumbnails are always JPEG. Set up the file.
1683  */
1684  r = gp_file_set_data_and_size (file, (char*)ed->data, ed->size);
1685  if (r < 0) {
1686  exif_data_unref (ed);
1687  return (r);
1688  }
1689  ed->data = NULL;
1690  ed->size = 0;
1691  exif_data_unref (ed);
1692  CR (gp_file_set_name (file, filename));
1694  CR (gp_filesystem_set_file_noop (fs, folder, filename, GP_FILE_TYPE_PREVIEW, file, context));
1696 #else
1697  GP_LOG_D ("Getting previews is not supported and "
1698  "libgphoto2 has been compiled without exif "
1699  "support. ");
1700  return (r);
1701 #endif
1702  } else if ((r == GP_ERROR_NOT_SUPPORTED) &&
1703  (type == GP_FILE_TYPE_EXIF)) {
1704 
1705  /*
1706  * Some cameras hide EXIF data in thumbnails (!). Check it
1707  * out.
1708  */
1709 #ifdef HAVE_LIBEXIF
1710  GP_LOG_D ("Getting EXIF data is not supported. Trying thumbnail...");
1711  CR (gp_file_new (&efile));
1712  CU (gp_filesystem_get_file_impl (fs, folder, filename,
1713  GP_FILE_TYPE_PREVIEW, efile, context), efile);
1714  CU (gp_file_get_data_and_size (efile, &data, &size), efile);
1715  ed = exif_data_new_from_data ((unsigned char*)data, size);
1716  gp_file_unref (efile);
1717  if (!ed) {
1718  GP_LOG_D ("Could not parse EXIF data of thumbnail of "
1719  "'%s' in folder '%s'.", filename, folder);
1720  return (GP_ERROR_CORRUPTED_DATA);
1721  }
1722  exif_data_save_data (ed, &buf, &buf_size);
1723  exif_data_unref (ed);
1724  r = gp_file_set_data_and_size (file, (char*)buf, buf_size);
1725  if (r < 0) {
1726  free (buf);
1727  return (r);
1728  }
1729  CR (gp_file_set_name (file, filename));
1731  CR (gp_filesystem_set_file_noop (fs, folder, filename, GP_FILE_TYPE_EXIF, file, context));
1733 #else
1734  GP_LOG_D ("Getting EXIF data is not supported and libgphoto2 "
1735  "has been compiled without EXIF support.");
1736  return (r);
1737 #endif
1738  } else if (r < 0) {
1739  GP_LOG_D ("Download of '%s' from '%s' (type %i) failed. "
1740  "Reason: '%s'", filename, folder, type,
1741  gp_result_as_string (r));
1742  return (r);
1743  }
1744 
1745  return (GP_OK);
1746 }
1747 
1770 int
1772  const char *filename, CameraFileType type,
1773  uint64_t offset, char *buf, uint64_t *size,
1774  GPContext *context)
1775 {
1776  int r;
1777  const char *xdata;
1778  unsigned long xsize;
1779  CameraFile *file;
1780 
1781  C_PARAMS (fs && folder && filename && buf && size);
1782  CC (context);
1783  CA (folder, context);
1784 
1785  if (fs->read_file_func) {
1786  r = fs->read_file_func (fs, folder, filename, type,
1787  offset, buf, size, fs->data, context);
1788  if (r == GP_OK)
1789  return r;
1790  } else {
1791  return GP_ERROR_NOT_SUPPORTED;
1792  }
1793  return r;
1794  /* fallback code */
1795  CR (gp_file_new (&file));
1796  CR (gp_filesystem_get_file (fs, folder, filename, type,
1797  file, context));
1798  CR (gp_file_get_data_and_size (file, &xdata, &xsize));
1799  if (offset > *size) { /* EOF */
1800  gp_file_unref (file);
1801  *size = 0;
1802  return GP_OK;
1803  }
1804  if ((offset != 0) || (offset + *size != xsize)) {
1805  /* Cache this file in the LRU, but only if the user just
1806  * hasn't read all of it at once.
1807  */
1808  CR (gp_filesystem_set_file_noop (fs, folder, filename, type, file, context));
1809  }
1810  if (offset + (*size) > xsize)
1811  *size = xsize-offset;
1812  memcpy (buf, xdata+offset, *size);
1813  gp_file_unref (file);
1814  return GP_OK;
1815 }
1827 int
1829  CameraFilesystemFuncs *funcs,
1830  void *data)
1831 {
1832  C_PARAMS (fs);
1833 
1834  fs->get_info_func = funcs->get_info_func;
1835  fs->set_info_func = funcs->set_info_func;
1836  fs->put_file_func = funcs->put_file_func;
1837  fs->delete_all_func = funcs->delete_all_func;
1838  fs->make_dir_func = funcs->make_dir_func;
1839  fs->remove_dir_func = funcs->remove_dir_func;
1840  fs->file_list_func = funcs->file_list_func;
1841  fs->folder_list_func = funcs->folder_list_func;
1842  fs->delete_file_func = funcs->del_file_func;
1843  fs->get_file_func = funcs->get_file_func;
1844  fs->read_file_func = funcs->read_file_func;
1845  fs->storage_info_func = funcs->storage_info_func;
1846  fs->data = data;
1847  return (GP_OK);
1848 }
1849 
1860 int
1861 gp_filesystem_get_info (CameraFilesystem *fs, const char *folder,
1862  const char *filename, CameraFileInfo *info,
1863  GPContext *context)
1864 {
1866  CameraFilesystemFile *file;
1867 #ifdef HAVE_LIBEXIF
1868  time_t t;
1869 #endif
1870 
1871  C_PARAMS (fs && folder && filename && info);
1872  CC (context);
1873  CA (folder, context);
1874 
1875  GP_LOG_D ("Getting information about '%s' in '%s'...", filename,
1876  folder);
1877 
1878  if (!fs->get_info_func) {
1879  gp_context_error (context,
1880  _("The filesystem doesn't support getting file "
1881  "information"));
1882  return (GP_ERROR_NOT_SUPPORTED);
1883  }
1884 
1885  /* Search folder and file and get info if needed */
1886  CR ( lookup_folder_file (fs, folder, filename, &f, &file, context));
1887 
1888  if (file->info_dirty) {
1889  CR (fs->get_info_func (fs, folder, filename,
1890  &file->info,
1891  fs->data, context));
1892  file->info_dirty = 0;
1893  }
1894 
1895  /*
1896  * If we didn't get GP_FILE_INFO_MTIME, we'll have a look if we
1897  * can get it from EXIF data.
1898  */
1899 #ifdef HAVE_LIBEXIF
1900  if (!(file->info.file.fields & GP_FILE_INFO_MTIME)) {
1901  GP_LOG_D ("Did not get mtime. Trying EXIF information...");
1902  t = gp_filesystem_get_exif_mtime (fs, folder, filename);
1903  if (t) {
1904  file->info.file.mtime = t;
1906  }
1907  }
1908 #endif
1909  memcpy (info, &file->info, sizeof (CameraFileInfo));
1910  return (GP_OK);
1911 }
1912 
1913 static int
1915 {
1916  int n = 0;
1917  CameraFilesystemFile *ptr, *prev;
1918 
1919  GP_LOG_D ("Clearing fscache LRU list...");
1920 
1921  if (fs->lru_first == NULL) {
1922  GP_LOG_D ("fscache LRU list already empty");
1923  return (GP_OK);
1924  }
1925 
1926  ptr = prev = fs->lru_first;
1927  while (ptr != NULL) {
1928  n++;
1929  if (ptr->lru_prev != prev) {
1930  GP_LOG_D ("fscache LRU list corrupted (%i)", n);
1931  return (GP_ERROR);
1932  }
1933  prev = ptr;
1934  ptr = ptr->lru_next;
1935 
1936  prev->lru_prev = NULL;
1937  prev->lru_next = NULL;
1938  }
1939 
1940  fs->lru_first = NULL;
1941  fs->lru_last = NULL;
1942  fs->lru_size = 0;
1943 
1944  GP_LOG_D ("fscache LRU list cleared (removed %i items)", n);
1945 
1946  return (GP_OK);
1947 }
1948 
1949 static int
1951 {
1952  if (item->lru_prev == NULL)
1953  return (GP_ERROR);
1954 
1955  /* Update the prev and next pointers. */
1956  if (item->lru_prev) item->lru_prev->lru_next = item->lru_next;
1957  if (item->lru_next) item->lru_next->lru_prev = item->lru_prev;
1958  if (fs->lru_last == item) {
1959  if (fs->lru_first == item) {
1960 
1961  /*
1962  * Case 1: ITEM is the only one in the list. We'll
1963  * remove it, and the list will be empty afterwards.
1964  */
1965  fs->lru_last = NULL;
1966  fs->lru_first = NULL;
1967  } else {
1968 
1969  /* Case 2: ITEM is the last in the list. */
1970  fs->lru_last = item->lru_prev;
1971  }
1972  } else if (fs->lru_first == item) {
1973 
1974  /* Case 3: ITEM is the first in the list. */
1975  fs->lru_first = item->lru_next;
1976  /* the first item prev links back to itself */
1977  fs->lru_first->lru_prev = fs->lru_first;
1978  }
1979 
1980  /* Clear the pointers */
1981  item->lru_prev = NULL;
1982  item->lru_next = NULL;
1983 
1984  return (GP_OK);
1985 }
1986 
1987 static int
1989 {
1990  CameraFilesystemFile *ptr;
1991  unsigned long int size;
1992 
1993  C_PARAMS (fs && fs->lru_first);
1994 
1995  ptr = fs->lru_first;
1996 
1997  GP_LOG_D ("Freeing cached data for file '%s'...", ptr->name);
1998 
1999  /* Remove it from the list. */
2000  fs->lru_first = ptr->lru_next;
2001  if (fs->lru_first)
2002  fs->lru_first->lru_prev = fs->lru_first;
2003  else
2004  fs->lru_last = NULL;
2005 
2006  /* Free its content. */
2007  if (ptr->normal) {
2008  CR( gp_file_get_data_and_size (ptr->normal, NULL, &size));
2009  fs->lru_size -= size;
2010  gp_file_unref (ptr->normal);
2011  ptr->normal = NULL;
2012  }
2013  if (ptr->raw) {
2014  CR( gp_file_get_data_and_size (ptr->raw, NULL, &size));
2015  fs->lru_size -= size;
2016  gp_file_unref (ptr->raw);
2017  ptr->raw = NULL;
2018  }
2019  if (ptr->audio) {
2020  CR( gp_file_get_data_and_size (ptr->audio, NULL, &size));
2021  fs->lru_size -= size;
2022  gp_file_unref (ptr->audio);
2023  ptr->audio = NULL;
2024  }
2025  ptr->lru_next = ptr->lru_prev = NULL;
2026  return (GP_OK);
2027 }
2028 
2029 static int
2031 {
2032  CameraFilesystemFile *ptr;
2033  int count = 0;
2034 
2035  if (!fs) return 0;
2036  ptr = fs->lru_first;
2037  while (ptr) {
2038  if (ptr->normal || ptr->raw || ptr->audio)
2039  count++;
2040  ptr = ptr->lru_next;
2041  }
2042  return count;
2043 }
2044 
2045 static int
2047  const char *folder, const char *filename,
2048  CameraFileType type,
2049  CameraFile *file, GPContext *context)
2050 {
2052  CameraFilesystemFile *xfile;
2053  CameraFile *oldfile = NULL;
2054  unsigned long int size;
2055  int x;
2056  char cached_images[1024];
2057 
2058  C_PARAMS (fs && folder && file);
2059 
2060  CR (gp_file_get_data_and_size (file, NULL, &size));
2061 
2062  /*
2063  * The following is a very simple case which is used to prune
2064  * the LRU. We keep PICTURES_TO_KEEP pictures in the LRU.
2065  *
2066  * We have 2 main scenarios:
2067  * - query all thumbnails (repeatedly) ... they are cached and
2068  * are not pruned by lru free.
2069  * - download all images, linear. no real need for caching.
2070  * - skip back 1 image (in viewers) (really? I don't know.)
2071  *
2072  * So lets just keep 2 pictures in memory.
2073  */
2074  if (pictures_to_keep == -1) {
2075  if (gp_setting_get ("libgphoto", "cached-images", cached_images) == GP_OK) {
2076  pictures_to_keep = atoi(cached_images);
2077  } else {
2078  /* store a default setting */
2079  sprintf (cached_images, "%d", PICTURES_TO_KEEP);
2080  gp_setting_set ("libgphoto", "cached-images", cached_images);
2081  }
2082  }
2083 
2084  if (pictures_to_keep < 0) /* also sanity check, but no upper limit. */
2086 
2087  x = gp_filesystem_lru_count (fs);
2088  while (x > pictures_to_keep) {
2089  CR (gp_filesystem_lru_free (fs));
2090  x = gp_filesystem_lru_count (fs);
2091  }
2092 
2093  GP_LOG_D ("Adding file '%s' from folder '%s' to the fscache LRU list "
2094  "(type %i)...", filename, folder, type);
2095 
2096  /* Search folder and file */
2097  CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2098 
2099  /*
2100  * If the file is already in the lru, we first remove it. Note that
2101  * we will only remove 'normal', 'raw' and 'audio' from cache.
2102  * See gp_filesystem_lru_free.
2103  */
2104  if (xfile->lru_prev != NULL) {
2105  switch (type) {
2106  case GP_FILE_TYPE_NORMAL:
2107  oldfile = xfile->normal;
2108  break;
2109  case GP_FILE_TYPE_RAW:
2110  oldfile = xfile->raw;
2111  break;
2112  case GP_FILE_TYPE_AUDIO:
2113  oldfile = xfile->audio;
2114  break;
2115  case GP_FILE_TYPE_PREVIEW:
2116  case GP_FILE_TYPE_EXIF:
2117  case GP_FILE_TYPE_METADATA:
2118  break;
2119  default:
2120  gp_context_error (context, _("Unknown file type %i."),
2121  type);
2122  return (GP_ERROR);
2123  }
2124  if (oldfile) {
2125  CR( gp_file_get_data_and_size (oldfile, NULL, &size));
2126  fs->lru_size -= size;
2127  }
2128 
2129  CR (gp_filesystem_lru_remove_one (fs, xfile));
2130  }
2131 
2132  /* Then add the file at the end of the LRU. */
2133  if (fs->lru_first == NULL) {
2134  fs->lru_first = xfile;
2135  fs->lru_last = xfile;
2136 
2137  /*
2138  * For the first item, prev point it itself to show that the
2139  * item is in the list.
2140  */
2141  xfile->lru_prev = xfile;
2142 
2143  } else {
2144  xfile->lru_next = NULL;
2145  xfile->lru_prev = fs->lru_last;
2146  fs->lru_last->lru_next = xfile;
2147  fs->lru_last = xfile;
2148  }
2149 
2150  CR( gp_file_get_data_and_size (file, NULL, &size));
2151  fs->lru_size += size;
2152 
2153  GP_LOG_D ("File '%s' from folder '%s' added in fscache LRU list.",
2154  filename, folder);
2155 
2156  return (GP_OK);
2157 }
2158 
2159 static int
2161 {
2162  int n = 0;
2163  CameraFilesystemFile *ptr, *prev;
2164 
2165  GP_LOG_D ("Checking fscache LRU list integrity...");
2166 
2167  if (fs->lru_first == NULL) {
2168  GP_LOG_D ("fscache LRU list empty");
2169  return (GP_OK);
2170  }
2171 
2172  ptr = prev = fs->lru_first;
2173  while (ptr != NULL) {
2174  n++;
2175  if (ptr->lru_prev != prev) {
2176  GP_LOG_E ("fscache LRU list corrupted (%i)", n);
2177  return (GP_ERROR);
2178  }
2179  prev = ptr;
2180  ptr = ptr->lru_next;
2181  }
2182 
2183  GP_LOG_D ("fscache LRU list ok with %i items (%ld bytes)", n,
2184  fs->lru_size);
2185 
2186  return (GP_OK);
2187 }
2188 
2203 int
2205  const char *folder, const char *filename,
2206  CameraFileType type,
2207  CameraFile *file, GPContext *context)
2208 {
2209  CameraFileInfo info;
2211  CameraFilesystemFile *xfile;
2212  int r;
2213  time_t t;
2214 
2215  C_PARAMS (fs && folder && file);
2216  CC (context);
2217  CA (folder, context);
2218 
2219  GP_LOG_D ("Adding file '%s' to folder '%s' (type %i)...",
2220  filename, folder, type);
2221 
2222  /* Search folder and file */
2223  CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2224 
2225  /*
2226  * If we add a significant amount of data in the cache, we put (or
2227  * move) a reference to this file in the LRU linked list. We
2228  * assume that only GP_FILE_TYPE_[RAW,NORMAL,EXIF] will contain a
2229  * significant amount of data.
2230  */
2231  if ((type == GP_FILE_TYPE_RAW) || (type == GP_FILE_TYPE_NORMAL) ||
2232  (type == GP_FILE_TYPE_AUDIO))
2233  CR (gp_filesystem_lru_update (fs, folder, filename, type, file, context));
2234 
2235  /* Redundant sanity check. */
2236  CR (gp_filesystem_lru_check (fs));
2237 
2238  switch (type) {
2239  case GP_FILE_TYPE_PREVIEW:
2240  if (xfile->preview)
2241  gp_file_unref (xfile->preview);
2242  xfile->preview = file;
2243  gp_file_ref (file);
2244  break;
2245  case GP_FILE_TYPE_NORMAL:
2246  if (xfile->normal)
2247  gp_file_unref (xfile->normal);
2248  xfile->normal = file;
2249  gp_file_ref (file);
2250  break;
2251  case GP_FILE_TYPE_RAW:
2252  if (xfile->raw)
2253  gp_file_unref (xfile->raw);
2254  xfile->raw = file;
2255  gp_file_ref (file);
2256  break;
2257  case GP_FILE_TYPE_AUDIO:
2258  if (xfile->audio)
2259  gp_file_unref (xfile->audio);
2260  xfile->audio = file;
2261  gp_file_ref (file);
2262  break;
2263  case GP_FILE_TYPE_EXIF:
2264  if (xfile->exif)
2265  gp_file_unref (xfile->exif);
2266  xfile->exif = file;
2267  gp_file_ref (file);
2268  break;
2269  case GP_FILE_TYPE_METADATA:
2270  if (xfile->metadata)
2271  gp_file_unref (xfile->metadata);
2272  xfile->metadata = file;
2273  gp_file_ref (file);
2274  break;
2275  default:
2276  gp_context_error (context, _("Unknown file type %i."), type);
2277  return (GP_ERROR);
2278  }
2279 
2280  /*
2281  * If we didn't get a mtime, try to get it from the CameraFileInfo.
2282  */
2283  CR (gp_file_get_mtime (file, &t));
2284  if (!t) {
2285  GP_LOG_D ("File does not contain mtime. Trying information on the file...");
2286  r = gp_filesystem_get_info (fs, folder, filename, &info, NULL);
2287  if ((r == GP_OK) && (info.file.fields & GP_FILE_INFO_MTIME))
2288  t = info.file.mtime;
2289  }
2290 
2291  /*
2292  * If we still don't have the mtime and this is a normal
2293  * file, check if there is EXIF data in the file that contains
2294  * information on the mtime.
2295  */
2296 #ifdef HAVE_LIBEXIF
2297  if (!t && (type == GP_FILE_TYPE_NORMAL)) {
2298  unsigned long int size;
2299  const char *data;
2300 
2301  GP_LOG_D ("Searching data for mtime...");
2302  CR (gp_file_get_data_and_size (file, NULL, &size));
2303  if (size < 32*1024*1024) { /* just assume stuff above 32MB is not EXIF capable */
2304  CR (gp_file_get_data_and_size (file, &data, &size));
2305  t = get_exif_mtime ((unsigned char*)data, size);
2306  }
2307  }
2308  /*
2309  * Still no mtime? Let's see if the camera offers us data of type
2310  * GP_FILE_TYPE_EXIF that includes information on the mtime.
2311  */
2312  if (!t) {
2313  GP_LOG_D ("Trying EXIF information...");
2314  t = gp_filesystem_get_exif_mtime (fs, folder, filename);
2315  }
2316 #endif
2317 
2318  if (t)
2319  CR (gp_file_set_mtime (file, t));
2320 
2321  return (GP_OK);
2322 }
2323 
2338 int
2340  const char *folder, const char *filename,
2341  CameraFileInfo info, GPContext *context)
2342 {
2344  CameraFilesystemFile *xfile;
2345 
2346  C_PARAMS (fs && folder);
2347  CC (context);
2348  CA (folder, context);
2349 
2350  /* Search folder and file */
2351  CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2352 
2353  memcpy (&xfile->info, &info, sizeof (CameraFileInfo));
2354  xfile->info_dirty = 0;
2355  return (GP_OK);
2356 }
2357 
2370 int
2371 gp_filesystem_set_info (CameraFilesystem *fs, const char *folder,
2372  const char *filename, CameraFileInfo info,
2373  GPContext *context)
2374 {
2375  int result;
2377  CameraFilesystemFile *xfile;
2378 
2379  C_PARAMS (fs && folder && filename);
2380  CC (context);
2381  CA (folder, context);
2382 
2383  if (!fs->set_info_func) {
2384  gp_context_error (context,
2385  _("The filesystem doesn't support setting file "
2386  "information"));
2387  return (GP_ERROR_NOT_SUPPORTED);
2388  }
2389 
2390  /* Search folder and file */
2391  CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2392 
2393  /* Check if people want to set read-only attributes */
2394  if ((info.file.fields & GP_FILE_INFO_TYPE) ||
2395  (info.file.fields & GP_FILE_INFO_SIZE) ||
2396  (info.file.fields & GP_FILE_INFO_WIDTH) ||
2397  (info.file.fields & GP_FILE_INFO_HEIGHT) ||
2398  (info.file.fields & GP_FILE_INFO_STATUS) ||
2399  (info.preview.fields & GP_FILE_INFO_TYPE) ||
2400  (info.preview.fields & GP_FILE_INFO_SIZE) ||
2401  (info.preview.fields & GP_FILE_INFO_WIDTH) ||
2402  (info.preview.fields & GP_FILE_INFO_HEIGHT) ||
2403  (info.preview.fields & GP_FILE_INFO_STATUS) ||
2404  (info.audio.fields & GP_FILE_INFO_TYPE) ||
2405  (info.audio.fields & GP_FILE_INFO_SIZE) ||
2406  (info.audio.fields & GP_FILE_INFO_STATUS)) {
2407  gp_context_error (context, _("Read-only file attributes "
2408  "like width and height can not be changed."));
2409  return (GP_ERROR_BAD_PARAMETERS);
2410  }
2411 
2412  /*
2413  * Set the info. If anything goes wrong, mark info as dirty,
2414  * because the operation could have been partially successful.
2415  */
2416  result = fs->set_info_func (fs, folder, filename, info, fs->data,
2417  context);
2418  if (result < 0) {
2419  xfile->info_dirty = 1;
2420  return (result);
2421  }
2423  xfile->info.file.permissions = info.file.permissions;
2424 
2425  return (GP_OK);
2426 }
2427 
2452 int
2454  CameraFilesystem *fs,
2455  CameraStorageInformation **storageinfo,
2456  int *nrofstorageinfos,
2457  GPContext *context
2458 ) {
2459  C_PARAMS (fs && storageinfo && nrofstorageinfos);
2460  CC (context);
2461 
2462  if (!fs->storage_info_func) {
2463  gp_context_error (context,
2464  _("The filesystem doesn't support getting storage "
2465  "information"));
2466  return (GP_ERROR_NOT_SUPPORTED);
2467  }
2468  return fs->storage_info_func (fs,
2469  storageinfo, nrofstorageinfos,
2470  fs->data, context);
2471 }
void gp_context_error(GPContext *context, const char *format,...)
int gp_file_adjust_name_for_mime_type(CameraFile *file)
int gp_file_set_data_and_size(CameraFile *file, char *data, unsigned long int size)
Definition: gphoto2-file.c:313
int gp_file_copy(CameraFile *destination, CameraFile *source)
Definition: gphoto2-file.c:729
int gp_file_unref(CameraFile *file)
Decrease reference counter for CameraFile object.
Definition: gphoto2-file.c:184
int gp_file_set_mime_type(CameraFile *file, const char *mime_type)
int gp_file_set_name(CameraFile *file, const char *name)
Definition: gphoto2-file.c:996
int gp_file_get_mtime(CameraFile *file, time_t *mtime)
int gp_file_ref(CameraFile *file)
Increase reference counter for CameraFile object.
Definition: gphoto2-file.c:167
int gp_file_set_mtime(CameraFile *file, time_t mtime)
int gp_file_new(CameraFile **file)
Definition: gphoto2-file.c:83
int gp_file_get_data_and_size(CameraFile *file, const char **data, unsigned long int *size)
Definition: gphoto2-file.c:398
#define GP_MIME_JPEG
Definition: gphoto2-file.h:43
CameraFileType
The type of view on the specified file.
Definition: gphoto2-file.h:73
@ GP_FILE_TYPE_PREVIEW
Definition: gphoto2-file.h:74
@ GP_FILE_TYPE_METADATA
Definition: gphoto2-file.h:81
@ GP_FILE_TYPE_AUDIO
Definition: gphoto2-file.h:79
@ GP_FILE_TYPE_NORMAL
Definition: gphoto2-file.h:75
@ GP_FILE_TYPE_EXIF
Definition: gphoto2-file.h:80
@ GP_FILE_TYPE_RAW
Definition: gphoto2-file.h:76
#define GP_MIME_EXIF
Definition: gphoto2-file.h:53
static int delete_folder(CameraFilesystem *fs, CameraFilesystemFolder **folder)
int gp_filesystem_get_folder(CameraFilesystem *fs, const char *filename, char **folder, GPContext *context)
Search a folder that contains a given filename.
int gp_filesystem_free(CameraFilesystem *fs)
Free filesystem struct.
int gp_filesystem_dump(CameraFilesystem *fs)
Dump the current filesystem.
static int recurse_delete_folder(CameraFilesystem *fs, CameraFilesystemFolder *folder)
static int gp_filesystem_lru_count(CameraFilesystem *fs)
static int delete_all_files(CameraFilesystem *fs, CameraFilesystemFolder *folder)
static int append_folder(CameraFilesystem *fs, const char *folder, CameraFilesystemFolder **newfolder, GPContext *context)
#define CC(context)
#define _(String)
static int gp_filesystem_delete_all_one_by_one(CameraFilesystem *fs, const char *folder, GPContext *context)
#define CL(result, list)
static int gp_filesystem_lru_free(CameraFilesystem *fs)
int gp_filesystem_new(CameraFilesystem **fs)
Create a new filesystem struct.
static int gp_filesystem_lru_update(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, GPContext *context)
int gp_filesystem_set_info(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileInfo info, GPContext *context)
Set information about a file.
static int gp_filesystem_get_file_impl(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, GPContext *context)
static CameraFilesystemFolder * lookup_folder(CameraFilesystem *fs, CameraFilesystemFolder *folder, const char *foldername, GPContext *context)
int gp_filesystem_make_dir(CameraFilesystem *fs, const char *folder, const char *name, GPContext *context)
Create a subfolder within a folder.
#define PICTURES_TO_KEEP
int gp_filesystem_delete_file(CameraFilesystem *fs, const char *folder, const char *filename, GPContext *context)
Delete a file from a folder.
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.
static int internal_append(CameraFilesystem *fs, CameraFilesystemFolder *f, const char *filename, GPContext *context)
Append a file to a folder in a filesystem.
static int append_to_folder(CameraFilesystemFolder *folder, const char *foldername, CameraFilesystemFolder **newfolder)
int gp_filesystem_reset(CameraFilesystem *fs)
Clear the filesystem.
static int recursive_folder_scan(CameraFilesystemFolder *folder, const char *lookforfile, char **foldername)
static int append_file(CameraFilesystem *fs, CameraFilesystemFolder *folder, const char *name, CameraFile *file, GPContext *context)
int gp_filesystem_delete_all(CameraFilesystem *fs, const char *folder, GPContext *context)
Delete all files in specified folder.
static int gp_filesystem_scan(CameraFilesystem *fs, const char *folder, const char *filename, GPContext *context)
int gp_filesystem_set_funcs(CameraFilesystem *fs, CameraFilesystemFuncs *funcs, void *data)
Set all filesystem related function pointers.
#define CR(result)
#define CA(f, c)
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.
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.
int gp_filesystem_count(CameraFilesystem *fs, const char *folder, GPContext *context)
Count files a folder of a filesystem.
static int append_folder_one(CameraFilesystemFolder *folder, const char *name, CameraFilesystemFolder **newfolder)
struct _CameraFilesystemFile CameraFilesystemFile
int gp_filesystem_list_files(CameraFilesystem *fs, const char *folder, CameraList *list, GPContext *context)
Get the list of files in a folder.
static int gp_filesystem_lru_check(CameraFilesystem *fs)
struct _CameraFilesystemFolder CameraFilesystemFolder
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.
static int gp_filesystem_lru_remove_one(CameraFilesystem *fs, CameraFilesystemFile *item)
int gp_filesystem_append(CameraFilesystem *fs, const char *folder, const char *filename, GPContext *context)
static int delete_file(CameraFilesystem *fs, CameraFilesystemFolder *folder, CameraFilesystemFile *file)
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.
static int gp_filesystem_lru_clear(CameraFilesystem *fs)
static int delete_all_folders(CameraFilesystem *fs, const char *foldername, GPContext *context)
int gp_filesystem_get_info(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileInfo *info, GPContext *context)
Get information about the specified file.
static int pictures_to_keep
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.
static void recursive_fs_dump(CameraFilesystemFolder *folder, int depth)
int gp_filesystem_list_folders(CameraFilesystem *fs, const char *folder, CameraList *list, GPContext *context)
List all subfolders within a filesystem folder.
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.
#define CU(result, file)
static int lookup_folder_file(CameraFilesystem *fs, const char *folder, const char *filename, CameraFilesystemFolder **xfolder, CameraFilesystemFile **xfile, GPContext *context)
int gp_filesystem_remove_dir(CameraFilesystem *fs, const char *folder, const char *name, GPContext *context)
Remove a subfolder from within a folder.
int gp_filesystem_get_storageinfo(CameraFilesystem *fs, CameraStorageInformation **storageinfo, int *nrofstorageinfos, GPContext *context)
Get the storage information about this filesystem.
int gp_filesystem_number(CameraFilesystem *fs, const char *folder, const char *filename, GPContext *context)
Get the index of a file in specified folder.
Filesystem related operations and declarations.
int(* CameraFilesystemDeleteFileFunc)(CameraFilesystem *fs, const char *folder, const char *filename, void *data, GPContext *context)
int(* CameraFilesystemReadFileFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, uint64_t offset, char *buf, uint64_t *size, void *data, GPContext *context)
@ GP_FILE_INFO_WIDTH
The width is set.
@ GP_FILE_INFO_HEIGHT
The height is set.
@ GP_FILE_INFO_TYPE
The MIME type is set.
@ GP_FILE_INFO_STATUS
The status is set (downloaded).
@ GP_FILE_INFO_SIZE
The filesize is set.
@ GP_FILE_INFO_MTIME
The modification time is set.
@ GP_FILE_INFO_PERMISSIONS
The access permissions are set.
int(* CameraFilesystemDeleteAllFunc)(CameraFilesystem *fs, const char *folder, void *data, GPContext *context)
int(* CameraFilesystemListFunc)(CameraFilesystem *fs, const char *folder, CameraList *list, void *data, GPContext *context)
int(* CameraFilesystemStorageInfoFunc)(CameraFilesystem *fs, CameraStorageInformation **, int *nrofstorageinformations, void *data, GPContext *context)
int(* CameraFilesystemGetFileFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, void *data, GPContext *context)
int(* CameraFilesystemDirFunc)(CameraFilesystem *fs, const char *folder, const char *name, void *data, GPContext *context)
int(* CameraFilesystemPutFileFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, void *data, GPContext *context)
int(* CameraFilesystemGetInfoFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileInfo *info, void *data, GPContext *context)
int(* CameraFilesystemSetInfoFunc)(CameraFilesystem *fs, const char *folder, const char *filename, CameraFileInfo info, void *data, GPContext *context)
int gp_list_new(CameraList **list)
Creates a new CameraList.
Definition: gphoto2-list.c:63
int gp_list_reset(CameraList *list)
Definition: gphoto2-list.c:148
int gp_list_free(CameraList *list)
Definition: gphoto2-list.c:120
int gp_list_append(CameraList *list, const char *name, const char *value)
Definition: gphoto2-list.c:174
int gp_list_count(CameraList *list)
Definition: gphoto2-list.c:229
int gp_list_get_name(CameraList *list, int index, const char **name)
Definition: gphoto2-list.c:280
#define GP_ERROR_NO_MEMORY
Out of memory.
#define GP_OK
Everything is OK.
#define GP_ERROR_NOT_SUPPORTED
Functionality not supported.
#define GP_ERROR_BAD_PARAMETERS
Bad parameters passed.
#define GP_ERROR
Generic Error.
int result
const char * gp_result_as_string(int result)
Translate a gphoto error code into a localized string.
#define GP_ERROR_FILE_EXISTS
File already exists.
#define GP_ERROR_FILE_NOT_FOUND
Specified file was not found.
#define GP_ERROR_DIRECTORY_NOT_FOUND
Specified directory was not found.
#define GP_ERROR_DIRECTORY_EXISTS
Specified directory already exists.
#define GP_ERROR_CORRUPTED_DATA
Corrupted data received.
int gp_setting_get(char *id, char *key, char *value)
Retrieve a specific gphoto setting.
int gp_setting_set(char *id, char *key, char *value)
Set a specific gphoto setting.
File structure.
CameraFileInfoFields fields
Bitmask containing the set members.
CameraFileInfoFields fields
Bitmask containing the set members.
CameraFilePermissions permissions
Permissions of the file.
time_t mtime
Modification time of the file.
CameraFileInfoFields fields
Bitmask containing the set members.
File information structure.
CameraFileInfoPreview preview
CameraFileInfoAudio audio
CameraFileInfoFile file
struct _CameraFilesystemFile * next
struct _CameraFilesystemFile * lru_next
struct _CameraFilesystemFile * lru_prev
struct _CameraFilesystemFolder * next
struct _CameraFilesystemFile * files
struct _CameraFilesystemFolder * folders
CameraFilesystemListFunc file_list_func
CameraFilesystemStorageInfoFunc storage_info_func
CameraFilesystemListFunc folder_list_func
CameraFilesystemDirFunc remove_dir_func
CameraFilesystemGetInfoFunc get_info_func
CameraFilesystemGetFileFunc get_file_func
CameraFilesystemSetInfoFunc set_info_func
CameraFilesystemDeleteAllFunc delete_all_func
CameraFilesystemReadFileFunc read_file_func
CameraFilesystemDirFunc make_dir_func
CameraFilesystemPutFileFunc put_file_func
CameraFilesystemDeleteFileFunc del_file_func
The internal camera filesystem structure.
CameraFilesystemDirFunc remove_dir_func
CameraFilesystemGetFileFunc get_file_func
CameraFilesystemDeleteAllFunc delete_all_func
CameraFilesystemListFunc folder_list_func
CameraFilesystemDirFunc make_dir_func
CameraFilesystemReadFileFunc read_file_func
CameraFilesystemGetInfoFunc get_info_func
CameraFilesystemStorageInfoFunc storage_info_func
unsigned long int lru_size
CameraFilesystemDeleteFileFunc delete_file_func
CameraFilesystemPutFileFunc put_file_func
CameraFilesystemSetInfoFunc set_info_func
CameraFilesystemListFunc file_list_func
CameraFilesystemFile * lru_last
CameraFilesystemFile * lru_first
CameraFilesystemFolder * rootfolder
Storage information structue.