3 * \author Copyright 2000 Scott Fritzinger
4 * \author Contributions Lutz Müller <lutz@users.sf.net> (2001)
5 * \author Copyright 2009 Marcus Meissner
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
29 #include <gphoto2/gphoto2-filesys.h>
36 #include <gphoto2/gphoto2-result.h>
37 #include <gphoto2/gphoto2-port-log.h>
38 #include <gphoto2/gphoto2-setting.h>
43 # include <libexif/exif-data.h>
49 # define _(String) dgettext (GETTEXT_PACKAGE, String)
51 # define N_(String) gettext_noop (String)
53 # define N_(String) (String)
56 # define textdomain(String) (String)
57 # define gettext(String) (String)
58 # define dgettext(Domain,Message) (Message)
59 # define dcgettext(Domain,Message,Type) (Message)
60 # define bindtextdomain(Domain,Directory) (Domain)
61 # define _(String) (String)
62 # define N_(String) (String)
65 #define GP_MODULE "libgphoto2"
68 # define PATH_MAX 4096
71 typedef struct _CameraFilesystemFile {
78 struct _CameraFilesystemFile *lru_prev;
79 struct _CameraFilesystemFile *lru_next;
87 struct _CameraFilesystemFile *next; /* in folder */
88 } CameraFilesystemFile;
90 typedef struct _CameraFilesystemFolder {
96 struct _CameraFilesystemFolder *next; /* chain in same folder */
97 struct _CameraFilesystemFolder *folders; /* childchain of this folder */
98 struct _CameraFilesystemFile *files; /* of this folder */
99 } CameraFilesystemFolder;
102 * The default number of pictures to keep in the internal cache,
103 * can be overriden by settings.
105 #define PICTURES_TO_KEEP 2
107 * The current number of pictures to keep in the internal cache,
108 * either from #PICTURES_TO_KEEP or from the settings.
110 static int pictures_to_keep = -1;
112 static int gp_filesystem_lru_clear (CameraFilesystem *fs);
113 static int gp_filesystem_lru_remove_one (CameraFilesystem *fs, CameraFilesystemFile *item);
117 static int gp_filesystem_get_file_impl (CameraFilesystem *, const char *,
118 const char *, CameraFileType, CameraFile *, GPContext *);
121 get_time_from_exif_tag(ExifEntry *e) {
124 e->data[4] = e->data[ 7] = e->data[10] = e->data[13] = e->data[16] = 0;
125 ts.tm_year = atoi ((char*)e->data) - 1900;
126 ts.tm_mon = atoi ((char*)(e->data + 5)) - 1;
127 ts.tm_mday = atoi ((char*)(e->data + 8));
128 ts.tm_hour = atoi ((char*)(e->data + 11));
129 ts.tm_min = atoi ((char*)(e->data + 14));
130 ts.tm_sec = atoi ((char*)(e->data + 17));
136 get_exif_mtime (const unsigned char *data, unsigned long size)
140 time_t t, t1 = 0, t2 = 0, t3 = 0;
142 ed = exif_data_new_from_data (data, size);
144 GP_DEBUG ("Could not parse data for EXIF information.");
149 * HP PhotoSmart C30 has the date and time in ifd_exif.
151 #ifdef HAVE_LIBEXIF_IFD
152 e = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_DATE_TIME);
154 t1 = get_time_from_exif_tag(e);
155 e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF],
156 EXIF_TAG_DATE_TIME_ORIGINAL);
158 t2 = get_time_from_exif_tag(e);
159 e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF],
160 EXIF_TAG_DATE_TIME_DIGITIZED);
162 t3 = get_time_from_exif_tag(e);
164 e = exif_content_get_entry (ed->ifd0, EXIF_TAG_DATE_TIME);
166 t1 = get_time_from_exif_tag(e);
169 e = exif_content_get_entry (ed->ifd_exif,
170 EXIF_TAG_DATE_TIME_ORIGINAL);
172 t2 = get_time_from_exif_tag(e);
175 e = exif_content_get_entry (ed->ifd_exif,
176 EXIF_TAG_DATE_TIME_DIGITIZED);
178 t3 = get_time_from_exif_tag(e);
182 exif_data_unref (ed);
183 if (!t1 && !t2 && !t3) {
184 GP_DEBUG ("EXIF data has not date/time tags.");
188 /* Perform some sanity checking on those tags */
189 t = t1; /* "last modified" */
191 if (t2 > t) /* "image taken" > "last modified" ? can not be */
193 if (t3 > t) /* "image digitized" > max(last two) ? can not be */
196 GP_DEBUG ("Found time in EXIF data: '%s'.", asctime (localtime (&t)));
201 gp_filesystem_get_exif_mtime (CameraFilesystem *fs, const char *folder,
202 const char *filename)
205 const char *data = NULL;
206 unsigned long int size = 0;
212 /* This is only useful for JPEGs. Avoid querying it for other types. */
213 if ( !strstr(filename,"jpg") && !strstr(filename,"JPG") &&
214 !strstr(filename,"jpeg") && !strstr(filename,"JPEG")
219 if (gp_filesystem_get_file (fs, folder, filename,
220 GP_FILE_TYPE_EXIF, file, NULL) != GP_OK) {
221 GP_DEBUG ("Could not get EXIF data of '%s' in folder '%s'.",
223 gp_file_unref (file);
227 gp_file_get_data_and_size (file, &data, &size);
228 t = get_exif_mtime ((unsigned char*)data, size);
229 gp_file_unref (file);
236 * \brief The internal camera filesystem structure
238 * The internals of the #CameraFilesystem are only visible to gphoto2. You
239 * can only access them using the functions provided by gphoto2.
241 struct _CameraFilesystem {
242 CameraFilesystemFolder *rootfolder;
244 CameraFilesystemFile *lru_first;
245 CameraFilesystemFile *lru_last;
246 unsigned long int lru_size;
248 CameraFilesystemGetInfoFunc get_info_func;
249 CameraFilesystemSetInfoFunc set_info_func;
252 CameraFilesystemListFunc file_list_func;
253 CameraFilesystemListFunc folder_list_func;
256 CameraFilesystemGetFileFunc get_file_func;
257 CameraFilesystemDeleteFileFunc delete_file_func;
260 CameraFilesystemPutFileFunc put_file_func;
261 CameraFilesystemDeleteAllFunc delete_all_func;
262 CameraFilesystemDirFunc make_dir_func;
263 CameraFilesystemDirFunc remove_dir_func;
266 CameraFilesystemStorageInfoFunc storage_info_func;
270 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
272 #define CHECK_NULL(r) {if (!(r)) return (GP_ERROR_BAD_PARAMETERS);}
273 #define CR(result) {int r = (result); if (r < 0) return (r);}
274 #define CHECK_MEM(m) {if (!(m)) return (GP_ERROR_NO_MEMORY);}
276 #define CL(result,list) \
281 gp_list_free (list); \
286 #define CU(result,file) \
291 gp_file_unref (file); \
296 #define CC(context) \
298 if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) \
299 return GP_ERROR_CANCEL; \
304 if ((f)[0] != '/') { \
305 gp_context_error ((c), \
306 _("The path '%s' is not absolute."), (f)); \
307 return (GP_ERROR_PATH_NOT_ABSOLUTE); \
312 delete_all_files (CameraFilesystem *fs, CameraFilesystemFolder *folder)
314 CameraFilesystemFile *file;
317 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Delete all files in folder %p/%s", folder, folder->name);
319 file = folder->files;
321 CameraFilesystemFile *next;
322 /* Get rid of cached files */
323 gp_filesystem_lru_remove_one (fs, file);
325 gp_file_unref (file->preview);
326 file->preview = NULL;
329 gp_file_unref (file->normal);
333 gp_file_unref (file->raw);
337 gp_file_unref (file->audio);
341 gp_file_unref (file->exif);
344 if (file->metadata) {
345 gp_file_unref (file->metadata);
346 file->metadata = NULL;
353 folder->files = NULL;
358 delete_folder (CameraFilesystem *fs, CameraFilesystemFolder **folder)
360 CameraFilesystemFolder *next;
363 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Delete one folder %p/%s", *folder, (*folder)->name);
364 next = (*folder)->next;
365 delete_all_files (fs, *folder);
366 free ((*folder)->name);
372 static CameraFilesystemFolder*
374 CameraFilesystem *fs,
375 CameraFilesystemFolder *folder, const char *foldername,
378 CameraFilesystemFolder *f;
379 const char *curpt = foldername;
382 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Lookup folder '%s'...", foldername);
384 /* handle multiple slashes, and slashes at the end */
385 while (curpt[0]=='/')
388 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Found! %s is %p", foldername, folder);
392 s = strchr(curpt,'/');
393 /* Check if we need to load the folder ... */
394 if (folder->folders_dirty) {
396 char *copy = strdup (foldername);
399 * The parent folder is dirty. List the folders in the parent
400 * folder to make it clean.
402 /* the character _before_ curpt is a /, overwrite it temporary with \0 */
403 copy[curpt-foldername] = '\0';
404 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Folder %s is dirty. "
405 "Listing folders in there to make folder clean...", copy);
406 ret = gp_list_new (&list);
408 ret = gp_filesystem_list_folders (fs, copy, list, context);
410 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Done making folder %s clean...", copy);
412 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Making folder %s clean failed: %d", copy, ret);
419 if (!strncmp(f->name,curpt, (s-curpt)) &&
420 (strlen(f->name) == (s-curpt))
427 if (!strcmp(f->name,curpt))
439 CameraFilesystem *fs,
440 const char *folder, const char *filename,
441 CameraFilesystemFolder **xfolder, CameraFilesystemFile **xfile,
444 CameraFilesystemFolder* xf;
445 CameraFilesystemFile* f;
447 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Lookup folder %s file %s", folder, filename);
448 xf = lookup_folder (fs, fs->rootfolder, folder, context);
449 if (!xf) return GP_ERROR_DIRECTORY_NOT_FOUND;
450 /* Check if we need to load the filelist of the folder ... */
451 if (xf->files_dirty) {
455 * The folder is dirty. List the files in it to make it clean.
457 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Folder %s is dirty. "
458 "Listing files in there to make folder clean...", folder);
459 ret = gp_list_new (&list);
461 ret = gp_filesystem_list_files (fs, folder, list, context);
463 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Done making folder %s clean...", folder);
466 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Making folder %s clean failed: %d", folder, ret);
471 if (!strcmp (f->name, filename)) {
478 return GP_ERROR_FILE_NOT_FOUND;
481 /* delete all folder content */
483 recurse_delete_folder (CameraFilesystem *fs, CameraFilesystemFolder *folder) {
484 CameraFilesystemFolder **f;
486 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Recurse delete folder %p/%s", folder, folder->name);
487 f = &folder->folders;
489 recurse_delete_folder (fs, *f);
490 delete_folder (fs, f); /* will also advance to next */
496 delete_all_folders (CameraFilesystem *fs, const char *foldername,
499 CameraFilesystemFolder *folder;
501 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Internally deleting "
502 "all folders from '%s'...", foldername);
504 CHECK_NULL (fs && foldername);
506 CA (foldername, context);
508 folder = lookup_folder (fs, fs->rootfolder, foldername, context);
509 return recurse_delete_folder (fs, folder);
512 /* create and append 1 new folder entry to the current folder */
515 CameraFilesystemFolder *folder,
517 CameraFilesystemFolder **newfolder
519 CameraFilesystemFolder *f;
521 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Append one folder %s", name);
522 CHECK_MEM (f = calloc(sizeof(CameraFilesystemFolder),1));
523 CHECK_MEM (f->name = strdup (name));
525 f->folders_dirty = 1;
527 /* Link into the current chain... perhaps later alphabetically? */
528 f->next = folder->folders;
530 if (newfolder) *newfolder = f;
534 /* This is a mix between lookup and folder creator */
536 append_to_folder (CameraFilesystemFolder *folder,
537 const char *foldername,
538 CameraFilesystemFolder **newfolder
540 CameraFilesystemFolder *f;
543 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Append to folder %p/%s - %s", folder, folder->name, foldername);
544 /* Handle multiple slashes, and slashes at the end */
545 while (foldername[0]=='/')
547 if (!foldername[0]) {
548 if (newfolder) *newfolder = folder;
552 s = strchr(foldername,'/');
556 if (!strncmp(f->name,foldername, (s-foldername)) &&
557 (strlen(f->name) == (s-foldername))
559 return append_to_folder (f, s+1, newfolder);
561 if (!strcmp(f->name,foldername)) {
562 if (newfolder) *newfolder = f;
568 /* Not found ... create new folder */
571 CHECK_MEM (x = calloc ((s-foldername)+1,1));
572 memcpy (x, foldername, (s-foldername));
574 CR (append_folder_one (folder, x, newfolder));
577 CR (append_folder_one (folder, foldername, newfolder));
583 append_folder (CameraFilesystem *fs,
585 CameraFilesystemFolder **newfolder,
588 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Appending folder %s...", folder);
592 CA (folder, context);
593 return append_to_folder (fs->rootfolder, folder, newfolder);
597 append_file (CameraFilesystem *fs, CameraFilesystemFolder *folder, CameraFile *file, GPContext *context)
599 CameraFilesystemFile **new;
602 CHECK_NULL (fs && file);
604 CR (gp_file_get_name (file, &name));
605 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Appending file %s...", name);
608 new = &folder->files;
610 if (!strcmp((*new)->name, name)) {
611 gp_log (GP_LOG_ERROR, "gphoto2-filesystem", "File %s already exists!", name);
614 new = &((*new)->next);
616 /* new now points to the location of the last ->next pointer,
617 * if we write to it, we set last->next */
618 CHECK_MEM ((*new) = calloc (sizeof (CameraFilesystemFile), 1));
619 (*new)->name = strdup (name);
620 (*new)->info_dirty = 1;
621 (*new)->normal = file;
627 * \brief Clear the filesystem
628 * \param fs the filesystem to be cleared
630 * Resets the filesystem. All cached information including the folder tree
631 * will get lost and will be queried again on demand.
633 * \return a gphoto2 error code.
636 gp_filesystem_reset (CameraFilesystem *fs)
638 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "resetting filesystem");
639 CR (gp_filesystem_lru_clear (fs));
640 CR (delete_all_folders (fs, "/", NULL));
641 if (fs->rootfolder) {
642 fs->rootfolder->files_dirty = 1;
643 fs->rootfolder->folders_dirty = 1;
645 gp_log (GP_LOG_ERROR,"gphoto2-filesys", "root folder is gone?");
651 * \brief Create a new filesystem struct
653 * \param fs a pointer to a #CameraFilesystem
655 * Creates a new empty #CameraFilesystem
657 * \return a gphoto2 error code.
660 gp_filesystem_new (CameraFilesystem **fs)
664 CHECK_MEM (*fs = malloc (sizeof (CameraFilesystem)));
666 memset(*fs,0,sizeof(CameraFilesystem));
668 (*fs)->rootfolder = calloc (sizeof (CameraFilesystemFolder), 1);
669 if (!(*fs)->rootfolder) {
671 return (GP_ERROR_NO_MEMORY);
673 (*fs)->rootfolder->name = strdup("/");
674 if (!(*fs)->rootfolder->name) {
675 free ((*fs)->rootfolder);
677 return (GP_ERROR_NO_MEMORY);
679 (*fs)->rootfolder->files_dirty = 1;
680 (*fs)->rootfolder->folders_dirty = 1;
685 * \brief Free filesystem struct
686 * \param fs a #CameraFilesystem
688 * Frees the #CameraFilesystem
690 * \return a gphoto2 error code.
693 gp_filesystem_free (CameraFilesystem *fs)
695 /* We don't care for success or failure */
696 gp_filesystem_reset (fs);
698 /* Now, we've only got left over the root folder. Free that and
700 free (fs->rootfolder->name);
701 free (fs->rootfolder);
707 * \brief Append a file to a folder in a filesystem
708 * \param fs a #CameraFilesystem
709 * \param folder the folder where to put the file in
710 * \param filename filename of the file
711 * \param context a #GPContext
713 * Tells the fs that there is a file called filename in folder
714 * called folder. Usually camera drivers will call this function after
715 * capturing an image in order to tell the fs about the new file.
716 * A front-end should not use this function.
718 * \return a gphoto2 error code.
721 gp_filesystem_append (CameraFilesystem *fs, const char *folder,
722 const char *filename, GPContext *context)
724 CameraFilesystemFile **new;
725 CameraFilesystemFolder *f;
727 CHECK_NULL (fs && folder);
729 CA (folder, context);
731 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Append %s/%s to filesystem", folder, filename);
732 /* Check folder for existence, if not, create it. */
733 f = lookup_folder (fs, fs->rootfolder, folder, context);
735 CR (append_folder (fs, folder, &f, context));
739 if (!strcmp((*new)->name, filename)) break;
740 new = &((*new)->next);
743 gp_context_error (context,
744 _("Could not append '%s' to folder '%s' because "
745 "this file already exists."), filename, folder);
746 return (GP_ERROR_FILE_EXISTS);
749 CHECK_MEM ((*new) = calloc (sizeof (CameraFilesystemFile), 1))
750 (*new)->name = strdup (filename);
754 return (GP_ERROR_NO_MEMORY);
756 (*new)->info_dirty = 1;
762 recursive_fs_dump (CameraFilesystemFolder *folder, int depth) {
763 CameraFilesystemFolder *f;
764 CameraFilesystemFile *xfile;
766 gp_log (GP_LOG_DEBUG, "gphoto2-filesys", "%*sFolder %s", depth, " ", folder->name);
768 xfile = folder->files;
770 gp_log (GP_LOG_DEBUG, "gphoto2-filesys", "%*s %s", depth, " ", xfile->name);
776 recursive_fs_dump (f, depth+4);
781 * \brief Dump the current filesystem.
782 * \param fs the #CameraFilesystem
783 * \return a gphoto error code
785 * Internal function to dump the current filesystem.
788 gp_filesystem_dump (CameraFilesystem *fs)
790 GP_DEBUG("Dumping Filesystem:");
791 recursive_fs_dump (fs->rootfolder, 0);
796 delete_file (CameraFilesystem *fs, CameraFilesystemFolder *folder, CameraFilesystemFile *file)
798 CameraFilesystemFile **prev;
800 gp_filesystem_lru_remove_one (fs, file);
801 /* Get rid of cached files */
803 gp_file_unref (file->preview);
804 file->preview = NULL;
807 gp_file_unref (file->normal);
811 gp_file_unref (file->raw);
815 gp_file_unref (file->audio);
819 gp_file_unref (file->exif);
822 if (file->metadata) {
823 gp_file_unref (file->metadata);
824 file->metadata = NULL;
827 prev = &(folder->files);
828 while ((*prev) && ((*prev) != file))
829 prev = &((*prev)->next);
840 gp_filesystem_delete_all_one_by_one (CameraFilesystem *fs, const char *folder,
847 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Deleting all 1 by 1 from %s", folder);
848 CR (gp_list_new (&list));
849 CL (gp_filesystem_list_files (fs, folder, list, context), list);
850 CL (count = gp_list_count (list), list);
851 for (x = count ; x--; ) {
852 CL (gp_list_get_name (list, x, &name), list);
853 CL (gp_filesystem_delete_file (fs, folder, name, context),list);
860 * \brief Delete all files in specified folder.
862 * \param fs a #CameraFilesystem
863 * \param folder the folder in which to delete all files
864 * \param context a #GPContext
866 * Deletes all files in the given folder from the fs. If the fs has not
867 * been supplied with a delete_all_func, it tries to delete the files
868 * one by one using the delete_file_func. If that function has not been
869 * supplied neither, an error is returned.
871 * \return a gphoto2 error code.
874 gp_filesystem_delete_all (CameraFilesystem *fs, const char *folder,
878 CameraFilesystemFolder *f;
880 CHECK_NULL (fs && folder);
882 CA (folder, context);
884 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Deleting all from %s", folder);
885 /* Make sure this folder exists */
886 f = lookup_folder (fs, fs->rootfolder, folder, context);
887 if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
889 if (!fs->delete_all_func)
890 return gp_filesystem_delete_all_one_by_one (fs, folder, context);
892 * Mark the folder dirty - it could be that an error
893 * happens, and then we don't know which files have been
894 * deleted and which not.
898 * First try to use the delete_all function. If that fails,
899 * fall back to deletion one-by-one.
901 r = fs->delete_all_func (fs, folder, fs->folder_data, context);
903 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem",
904 "delete_all failed (%s). Falling back to "
905 "deletion one-by-one.",
906 gp_result_as_string (r));
907 CR (gp_filesystem_delete_all_one_by_one (fs, folder,
910 /* delete from filesystem view too now */
911 CR (delete_all_files (fs, f));
914 * No error happened. We can be sure that all files have been
922 * \brief Get the list of files in a folder
923 * \param fs a #CameraFilesystem
924 * \param folder a folder of which a file list should be generated
925 * \param list a #CameraList where to put the list of files into
926 * \param context a #GPContext
928 * Lists the files in folder using either cached values or (if there
929 * aren't any) the file_list_func which (hopefully) has been previously
932 * \return a gphoto2 error code.
935 gp_filesystem_list_files (CameraFilesystem *fs, const char *folder,
936 CameraList *list, GPContext *context)
940 CameraFilesystemFolder *f;
941 CameraFilesystemFile *file;
943 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Listing files in %s", folder);
945 CHECK_NULL (fs && list && folder);
947 CA (folder, context);
949 gp_list_reset (list);
951 /* Search the folder */
952 f = lookup_folder (fs, fs->rootfolder, folder, context);
953 if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
955 /* If the folder is dirty, delete the contents and query the camera */
956 if (f->files_dirty && fs->file_list_func) {
957 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem",
958 "Querying folder %s...", folder);
959 CR (delete_all_files (fs, f));
960 CR (fs->file_list_func (fs, folder, list,
961 fs->list_data, context));
963 CR (count = gp_list_count (list));
964 for (y = 0; y < count; y++) {
965 CR (gp_list_get_name (list, y, &name));
966 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem",
968 CR (gp_filesystem_append (fs, folder, name, context));
970 gp_list_reset (list);
973 /* The folder is clean now */
978 gp_log (GP_LOG_DEBUG, "filesys",
979 "Listed '%s'", file->name);
980 CR (gp_list_append (list, file->name, NULL));
987 * \brief List all subfolders within a filesystem folder
988 * \param fs a #CameraFilesystem
989 * \param folder a folder
990 * \param list a #CameraList where subfolders should be listed
991 * \param context a #GPContext
993 * Generates a list of subfolders of the supplied folder either using
994 * cached values (if there are any) or the folder_list_func if it has been
995 * supplied previously. If not, it is assumed that only a root folder
996 * exists (which is the case for many cameras).
998 * \return a gphoto2 error code.
1001 gp_filesystem_list_folders (CameraFilesystem *fs, const char *folder,
1002 CameraList *list, GPContext *context)
1006 CameraFilesystemFolder *f, *new;
1008 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Listing folders in %s", folder);
1010 CHECK_NULL (fs && folder && list);
1012 CA (folder, context);
1014 gp_list_reset (list);
1016 /* Search the folder */
1017 f = lookup_folder (fs, fs->rootfolder, folder, context);
1018 if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1021 /* If the folder is dirty, query the contents. */
1022 if (f->folders_dirty && fs->folder_list_func) {
1023 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "... is dirty, getting from camera");
1024 CR (fs->folder_list_func (fs, folder, list,
1025 fs->list_data, context));
1026 CR (delete_all_folders (fs, folder, context));
1028 CR (count = gp_list_count (list));
1029 for (y = 0; y < count; y++) {
1030 CR (gp_list_get_name (list, y, &name));
1031 CR (append_folder_one (f, name, NULL));
1033 /* FIXME: why not just return (GP_OK); ? the list should be fine */
1034 gp_list_reset (list);
1039 CR (gp_list_append (list, new->name, NULL));
1042 /* The folder is clean now */
1043 f->folders_dirty = 0;
1044 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Folder %s contains %i "
1045 "subfolders.", folder, gp_list_count (list));
1050 * \brief Count files a folder of a filesystem.
1051 * \param fs a #CameraFilesystem
1052 * \param folder a folder in which to count the files
1053 * \param context a #GPContext
1055 * Counts the files in the folder.
1057 * \return The number of files in the folder or a gphoto2 error code.
1060 gp_filesystem_count (CameraFilesystem *fs, const char *folder,
1064 CameraFilesystemFolder *f;
1065 CameraFilesystemFile *file;
1067 CHECK_NULL (fs && folder);
1069 CA (folder, context);
1071 f = lookup_folder (fs, fs->rootfolder, folder, context);
1072 if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1084 * \brief Delete a file from a folder.
1085 * \param fs a #CameraFilesystem
1086 * \param folder a folder in which to delete the file
1087 * \param filename the name of the file to delete
1088 * \param context a #GPContext
1090 * If a delete_file_func has been supplied to the fs, this function will
1091 * be called and, if this function returns without error, the file will be
1092 * removed from the fs.
1094 * \return a gphoto2 error code.
1097 gp_filesystem_delete_file (CameraFilesystem *fs, const char *folder,
1098 const char *filename, GPContext *context)
1100 CameraFilesystemFolder *f;
1101 CameraFilesystemFile *file;
1103 CHECK_NULL (fs && folder && filename);
1105 CA (folder, context);
1107 /* First of all, do we support file deletion? */
1108 if (!fs->delete_file_func) {
1109 gp_context_error (context, _("You have been trying to delete "
1110 "'%s' from folder '%s', but the filesystem does not "
1111 "support deletion of files."), filename, folder);
1112 return (GP_ERROR_NOT_SUPPORTED);
1115 /* Search the folder and the file */
1116 CR (lookup_folder_file (fs, folder, filename, &f, &file, context));
1118 gp_context_status (context, _("Deleting '%s' from folder '%s'..."),
1120 /* Delete the file */
1121 CR (fs->delete_file_func (fs, folder, filename,
1122 fs->file_data, context));
1123 CR (delete_file (fs, f, file));
1128 * \brief Delete a virtal file from a folder in the filesystem
1129 * \param fs a #CameraFilesystem
1130 * \param folder a folder in which to delete the file
1131 * \param filename the name of the file to delete
1132 * \param context a #GPContext
1134 * Remove a file from the filesystem. Compared to gp_filesystem_delete_file()
1135 * this just removes the file from the libgphoto2 view of the filesystem, but
1136 * does not call the camera driver to delete it from the physical device.
1138 * \return a gphoto2 error code.
1141 gp_filesystem_delete_file_noop (CameraFilesystem *fs, const char *folder,
1142 const char *filename, GPContext *context)
1144 CameraFilesystemFolder *f;
1145 CameraFilesystemFile *file;
1147 CHECK_NULL (fs && folder && filename);
1149 CA (folder, context);
1150 /* Search the folder and the file */
1151 CR (lookup_folder_file (fs, folder, filename, &f, &file, context));
1152 return delete_file (fs, f, file);
1156 * \brief Create a subfolder within a folder
1157 * \param fs a #CameraFilesystem
1158 * \param folder the folder in which the directory should be created
1159 * \param name the name of the directory to be created
1160 * \param context a #GPContext
1162 * Creates a new directory called name in given folder.
1164 * \return a gphoto2 error code
1167 gp_filesystem_make_dir (CameraFilesystem *fs, const char *folder,
1168 const char *name, GPContext *context)
1170 CameraFilesystemFolder *f;
1172 CHECK_NULL (fs && folder && name);
1174 CA (folder, context);
1176 if (!fs->make_dir_func)
1177 return (GP_ERROR_NOT_SUPPORTED);
1179 /* Search the folder */
1180 f = lookup_folder (fs, fs->rootfolder, folder, context);
1181 if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1183 /* Create the directory */
1184 CR (fs->make_dir_func (fs, folder, name, fs->folder_data, context));
1185 /* and append to internal fs */
1186 return append_folder_one (f, name, NULL);
1190 * \brief Remove a subfolder from within a folder
1191 * \param fs a #CameraFilesystem
1192 * \param folder the folder in which the directory should be created
1193 * \param name the name of the directory to be created
1194 * \param context a #GPContext
1196 * Removes a directory called name from the given folder.
1198 * \return a gphoto2 error code
1201 gp_filesystem_remove_dir (CameraFilesystem *fs, const char *folder,
1202 const char *name, GPContext *context)
1204 CameraFilesystemFolder *f;
1205 CameraFilesystemFolder **prev;
1207 CHECK_NULL (fs && folder && name);
1209 CA (folder, context);
1211 if (!fs->remove_dir_func)
1212 return (GP_ERROR_NOT_SUPPORTED);
1215 * Make sure there are neither files nor folders in the folder
1216 * that is to be removed.
1218 f = lookup_folder (fs, fs->rootfolder, folder, context);
1219 if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1220 /* Check if we need to load the folder ... */
1221 if (f->folders_dirty) {
1225 * The owning folder is dirty. List the folders in it
1228 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Folder %s is dirty. "
1229 "Listing folders in there to make folder clean...", folder);
1230 ret = gp_list_new (&list);
1232 ret = gp_filesystem_list_folders (fs, folder, list, context);
1233 gp_list_free (list);
1234 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Done making folder %s clean...", folder);
1237 prev = &(f->folders);
1239 if (!strcmp (name, (*prev)->name))
1241 prev = &((*prev)->next);
1243 if (!*prev) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1245 if ((*prev)->folders) {
1246 gp_context_error (context, _("There are still subfolders in "
1247 "folder '%s/%s' that you are trying to remove."), folder, name);
1248 return (GP_ERROR_DIRECTORY_EXISTS);
1250 if ((*prev)->files) {
1251 gp_context_error (context, _("There are still files in "
1252 "folder '%s/%s' that you are trying to remove."), folder,name);
1253 return (GP_ERROR_FILE_EXISTS);
1256 /* Remove the directory */
1257 CR (fs->remove_dir_func (fs, folder, name, fs->folder_data, context));
1258 CR (delete_folder (fs, prev));
1263 * \brief Upload a file to a folder on the device filesystem
1264 * \param fs a #CameraFilesystem
1265 * \param folder the folder where to put the file into
1266 * \param file the file
1267 * \param context a #GPContext
1269 * Uploads a file to the camera if a put_file_func has been previously
1270 * supplied to the fs. If the upload is successful, the file will get
1273 * \return a gphoto2 error code.
1276 gp_filesystem_put_file (CameraFilesystem *fs, const char *folder,
1277 CameraFile *file, GPContext *context)
1279 CameraFilesystemFolder *f;
1281 CHECK_NULL (fs && folder && file);
1283 CA (folder, context);
1285 /* Do we support file upload? */
1286 if (!fs->put_file_func) {
1287 gp_context_error (context, _("The filesystem does not support "
1288 "upload of files."));
1289 return (GP_ERROR_NOT_SUPPORTED);
1292 /* Search the folder */
1293 f = lookup_folder (fs, fs->rootfolder, folder, context);
1294 if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1296 /* Upload the file */
1297 CR (fs->put_file_func (fs, folder, file, fs->folder_data, context));
1298 /* And upload it to internal structure too */
1299 return append_file (fs, f, file, context);
1303 * \brief Lookup the filename of an indexed file within a folder.
1304 * \param fs a #CameraFilesystem
1305 * \param folder the folder where to look up the file with the filenumber
1306 * \param filenumber the number of the file
1307 * \param filename pointer to a filename where the result is stored
1308 * \param context a #GPContext
1310 * Looks up the filename of file with given filenumber in given folder.
1311 * See gp_filesystem_number for exactly the opposite functionality.
1313 * \return a gphoto2 error code.
1316 gp_filesystem_name (CameraFilesystem *fs, const char *folder, int filenumber,
1317 const char **filename, GPContext *context)
1319 CameraFilesystemFolder *f;
1320 CameraFilesystemFile *file;
1322 CHECK_NULL (fs && folder);
1324 CA (folder, context);
1326 f = lookup_folder (fs, fs->rootfolder, folder, context);
1327 if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1332 if (filenumber == 0)
1340 gp_context_error (context, _("Folder '%s' only contains "
1341 "%i files, but you requested a file with number %i."),
1342 folder, count, filenumber);
1343 return (GP_ERROR_FILE_NOT_FOUND);
1345 *filename = file->name;
1350 * \brief Get the index of a file in specified folder
1351 * \param fs a #CameraFilesystem
1352 * \param folder the folder where to look for file called filename
1353 * \param filename the file to look for
1354 * \param context a #GPContext
1356 * Looks for a file called filename in the given folder. See
1357 * gp_filesystem_name for exactly the opposite functionality.
1359 * \return a gphoto2 error code.
1362 gp_filesystem_number (CameraFilesystem *fs, const char *folder,
1363 const char *filename, GPContext *context)
1365 CameraFilesystemFolder *f;
1366 CameraFilesystemFile *file;
1370 CHECK_NULL (fs && folder && filename);
1372 CA (folder, context);
1374 f = lookup_folder (fs, fs->rootfolder, folder, context);
1375 if (!f) return (GP_ERROR_DIRECTORY_NOT_FOUND);
1380 if (!strcmp (file->name, filename))
1386 /* Ok, we didn't find the file. Is the folder dirty? */
1387 if (!f->files_dirty) {
1388 gp_context_error (context, _("File '%s' could not be found "
1389 "in folder '%s'."), filename, folder);
1390 return (GP_ERROR_FILE_NOT_FOUND);
1392 /* The folder is dirty. List all files to make it clean */
1393 CR (gp_list_new(&list));
1394 CL (gp_filesystem_list_files (fs, folder, list, context), list);
1396 return (gp_filesystem_number (fs, folder, filename, context));
1400 gp_filesystem_scan (CameraFilesystem *fs, const char *folder,
1401 const char *filename, GPContext *context)
1408 gp_log (GP_LOG_DEBUG, "gphoto2-filesystem", "Scanning %s for %s...",
1411 CHECK_NULL (fs && folder && filename);
1413 CA (folder, context);
1415 CR (gp_list_new (&list));
1416 CL (gp_filesystem_list_files (fs, folder, list, context), list);
1417 CL (count = gp_list_count (list), list);
1418 for (x = 0; x < count; x++) {
1419 CL (gp_list_get_name (list, x, &name), list);
1420 if (!strcmp (filename, name)) {
1421 gp_list_free (list);
1426 CL (gp_filesystem_list_folders (fs, folder, list, context), list);
1427 CL (count = gp_list_count (list), list);
1428 for (x = 0; x < count; x++) {
1429 CL (gp_list_get_name (list, x, &name), list);
1430 strncpy (path, folder, sizeof (path));
1431 if (path[strlen (path) - 1] != '/')
1432 strncat (path, "/", sizeof (path) - strlen (path) - 1);
1433 strncat (path, name, sizeof (path) - strlen (path) - 1);
1434 CL (gp_filesystem_scan (fs, path, filename, context), list);
1436 gp_list_free (list);
1441 recursive_folder_scan (
1442 CameraFilesystemFolder *folder, const char *lookforfile,
1445 CameraFilesystemFile *file;
1446 CameraFilesystemFolder *f;
1449 file = folder->files;
1451 if (!strcmp(file->name, lookforfile)) {
1452 *foldername = strdup (folder->name);
1457 f = folder->folders;
1460 ret = recursive_folder_scan (f, lookforfile, &xfolder);
1462 (*foldername) = malloc (strlen (folder->name) + 1 + strlen (xfolder) + 1);
1463 strcpy ((*foldername),folder->name);
1464 strcat ((*foldername),"/");
1465 strcat ((*foldername),xfolder);
1471 /* thorugh all subfoilders */
1472 return GP_ERROR_FILE_NOT_FOUND;
1475 * \brief Search a folder that contains a given filename
1476 * \param fs a #CameraFilesystem
1477 * \param filename the name of the file to search in the fs
1478 * \param folder pointer to value where the string is stored in
1479 * \param context a #GPContext
1481 * Searches a file called filename in the fs and returns the first
1482 * occurrency. This functionality is needed for camera drivers that cannot
1483 * figure out where a file gets created after capturing an image although the
1484 * name of the image is known. Usually, those drivers will call
1485 * gp_filesystem_reset in order to tell the fs that something has
1486 * changed and then gp_filesystem_get_folder in order to find the file.
1488 * Note that you get a reference to the string stored in the filesystem structure,
1489 * so do not free it yourself.
1491 * \return a gphoto2 error code.
1494 gp_filesystem_get_folder (CameraFilesystem *fs, const char *filename,
1495 const char **folder, GPContext *context)
1499 CHECK_NULL (fs && filename && folder);
1502 CR (gp_filesystem_scan (fs, "/", filename, context));
1504 ret = recursive_folder_scan ( fs->rootfolder, filename, folder);
1505 if (ret == GP_OK) return ret;
1506 gp_context_error (context, _("Could not find file '%s'."), filename);
1507 return (GP_ERROR_FILE_NOT_FOUND);
1511 * \brief Set the functions to list folders and files
1512 * \param fs a #CameraFilesystem
1513 * \param file_list_func the function that will return listings of files
1514 * \param folder_list_func the function that will return listings of folders
1515 * \param data private data structure
1517 * Tells the fs which functions to use to retrieve listings of folders
1518 * and/or files. Typically, a camera driver would call this function
1519 * on initialization. Each function can be NULL indicating that this
1520 * functionality is not supported. For example, many cameras don't support
1521 * folders. In this case, you would supply NULL for folder_list_func. Then,
1522 * the fs assumes that there is only a root folder.
1524 * \return a gphoto2 error code.
1527 gp_filesystem_set_list_funcs (CameraFilesystem *fs,
1528 CameraFilesystemListFunc file_list_func,
1529 CameraFilesystemListFunc folder_list_func,
1534 fs->file_list_func = file_list_func;
1535 fs->folder_list_func = folder_list_func;
1536 fs->list_data = data;
1542 * \brief Set camera filesystem file related functions
1543 * \param fs a #CameraFilesystem
1544 * \param get_file_func the function downloading files
1545 * \param del_file_func the function deleting files
1546 * \param data private data structure
1548 * Tells the fs which functions to use for file download or file deletion.
1549 * Typically, a camera driver would call this function on initialization.
1550 * A function can be NULL indicating that this functionality is not supported.
1551 * For example, if a camera does not support file deletion, you would supply
1552 * NULL for del_file_func.
1554 * \return a gphoto2 error code.
1557 gp_filesystem_set_file_funcs (CameraFilesystem *fs,
1558 CameraFilesystemGetFileFunc get_file_func,
1559 CameraFilesystemDeleteFileFunc del_file_func,
1564 fs->delete_file_func = del_file_func;
1565 fs->get_file_func = get_file_func;
1566 fs->file_data = data;
1572 * \brief Set folder related functions of the filesystem
1573 * \param fs a #CameraFilesystem
1574 * \param put_file_func function used to upload files
1575 * \param delete_all_func function used to delete all files in a folder
1576 * \param make_dir_func function used to create a new directory
1577 * \param remove_dir_func function used to remove an existing directory
1578 * \param data a data object that will passed to all called functions
1580 * Tells the filesystem which functions to call for file upload, deletion
1581 * of all files in a given folder, creation or removal of a folder.
1582 * Typically, a camera driver would call this function on initialization.
1583 * If one functionality is not supported, NULL can be supplied.
1584 * If you don't call this function, the fs will assume that neither
1585 * of these features is supported.
1587 * The fs will try to compensate missing delete_all_func
1588 * functionality with the delete_file_func if such a function has been
1591 * \return a gphoto2 error code.
1594 gp_filesystem_set_folder_funcs (CameraFilesystem *fs,
1595 CameraFilesystemPutFileFunc put_file_func,
1596 CameraFilesystemDeleteAllFunc delete_all_func,
1597 CameraFilesystemDirFunc make_dir_func,
1598 CameraFilesystemDirFunc remove_dir_func,
1603 fs->put_file_func = put_file_func;
1604 fs->delete_all_func = delete_all_func;
1605 fs->make_dir_func = make_dir_func;
1606 fs->remove_dir_func = remove_dir_func;
1607 fs->folder_data = data;
1613 gp_filesystem_get_file_impl (CameraFilesystem *fs, const char *folder,
1614 const char *filename, CameraFileType type,
1615 CameraFile *file, GPContext *context)
1617 CameraFilesystemFolder *xfolder;
1618 CameraFilesystemFile *xfile;
1620 CHECK_NULL (fs && folder && file && filename);
1622 CA (folder, context);
1624 GP_DEBUG ("Getting file '%s' from folder '%s' (type %i)...",
1625 filename, folder, type);
1627 CR (gp_file_set_type (file, type));
1628 CR (gp_file_set_name (file, filename));
1630 if (!fs->get_file_func) {
1631 gp_context_error (context,
1632 _("The filesystem doesn't support getting files"));
1633 return (GP_ERROR_NOT_SUPPORTED);
1636 /* Search folder and file */
1637 CR( lookup_folder_file (fs, folder, filename, &xfolder, &xfile, context));
1640 case GP_FILE_TYPE_PREVIEW:
1642 return (gp_file_copy (file, xfile->preview));
1644 case GP_FILE_TYPE_NORMAL:
1646 return (gp_file_copy (file, xfile->normal));
1648 case GP_FILE_TYPE_RAW:
1650 return (gp_file_copy (file, xfile->raw));
1652 case GP_FILE_TYPE_AUDIO:
1654 return (gp_file_copy (file, xfile->audio));
1656 case GP_FILE_TYPE_EXIF:
1658 return (gp_file_copy (file, xfile->exif));
1660 case GP_FILE_TYPE_METADATA:
1661 if (xfile->metadata)
1662 return (gp_file_copy (file, xfile->metadata));
1665 gp_context_error (context, _("Unknown file type %i."), type);
1669 gp_context_status (context, _("Downloading '%s' from folder '%s'..."),
1671 CR (fs->get_file_func (fs, folder, filename, type, file,
1672 fs->file_data, context));
1674 /* We don't trust the camera drivers */
1675 CR (gp_file_set_type (file, type));
1676 CR (gp_file_set_name (file, filename));
1679 /* this disables LRU completely. */
1680 /* Cache this file */
1681 CR (gp_filesystem_set_file_noop (fs, folder, file, context));
1685 * Often, thumbnails are of a different mime type than the normal
1686 * picture. In this case, we should rename the file.
1688 if (type != GP_FILE_TYPE_NORMAL)
1689 CR (gp_file_adjust_name_for_mime_type (file));
1695 * \brief Get file data from the filesystem
1696 * \param fs a #CameraFilesystem
1697 * \param folder the folder in which the file can be found
1698 * \param filename the name of the file to download
1699 * \param type the type of the file
1700 * \param file the file that receives the data
1701 * \param context a #GPContext
1703 * Downloads the file called filename from the folder using the
1704 * get_file_func if such a function has been previously supplied. If the
1705 * file has been previously downloaded, the file is retrieved from cache.
1706 * The result is stored in the passed file structure.
1708 * \return a gphoto2 error code.
1711 gp_filesystem_get_file (CameraFilesystem *fs, const char *folder,
1712 const char *filename, CameraFileType type,
1713 CameraFile *file, GPContext *context)
1718 const char *data = NULL;
1720 unsigned int buf_size;
1721 unsigned long int size = 0;
1725 r = gp_filesystem_get_file_impl (fs, folder, filename, type,
1728 if ((r == GP_ERROR_NOT_SUPPORTED) &&
1729 (type == GP_FILE_TYPE_PREVIEW)) {
1732 * Could not get preview (unsupported operation). Some
1733 * cameras hide the thumbnail in EXIF data. Check it out.
1736 GP_DEBUG ("Getting previews is not supported. Trying "
1738 CR (gp_file_new (&efile));
1739 CU (gp_filesystem_get_file_impl (fs, folder, filename,
1740 GP_FILE_TYPE_EXIF, efile, context), efile);
1741 CU (gp_file_get_data_and_size (efile, &data, &size), efile);
1742 ed = exif_data_new_from_data ((unsigned char*)data, size);
1743 gp_file_unref (efile);
1745 GP_DEBUG ("Could not parse EXIF data of "
1746 "'%s' in folder '%s'.", filename, folder);
1747 return (GP_ERROR_CORRUPTED_DATA);
1750 GP_DEBUG ("EXIF data does not contain a thumbnail.");
1751 exif_data_unref (ed);
1756 * We found a thumbnail in EXIF data! Those
1757 * thumbnails are always JPEG. Set up the file.
1759 r = gp_file_set_data_and_size (file, (char*)ed->data, ed->size);
1761 exif_data_unref (ed);
1766 exif_data_unref (ed);
1767 CR (gp_file_set_type (file, GP_FILE_TYPE_PREVIEW));
1768 CR (gp_file_set_name (file, filename));
1769 CR (gp_file_set_mime_type (file, GP_MIME_JPEG));
1770 CR (gp_filesystem_set_file_noop (fs, folder, file, context));
1771 CR (gp_file_adjust_name_for_mime_type (file));
1773 GP_DEBUG ("Getting previews is not supported and "
1774 "libgphoto2 has been compiled without exif "
1778 } else if ((r == GP_ERROR_NOT_SUPPORTED) &&
1779 (type == GP_FILE_TYPE_EXIF)) {
1782 * Some cameras hide EXIF data in thumbnails (!). Check it
1786 GP_DEBUG ("Getting EXIF data is not supported. Trying "
1788 CR (gp_file_new (&efile));
1789 CU (gp_filesystem_get_file_impl (fs, folder, filename,
1790 GP_FILE_TYPE_PREVIEW, efile, context), efile);
1791 CU (gp_file_get_data_and_size (efile, &data, &size), efile);
1792 ed = exif_data_new_from_data ((unsigned char*)data, size);
1793 gp_file_unref (efile);
1795 GP_DEBUG ("Could not parse EXIF data of thumbnail of "
1796 "'%s' in folder '%s'.", filename, folder);
1797 return (GP_ERROR_CORRUPTED_DATA);
1799 exif_data_save_data (ed, &buf, &buf_size);
1800 exif_data_unref (ed);
1801 r = gp_file_set_data_and_size (file, (char*)buf, buf_size);
1806 CR (gp_file_set_type (file, GP_FILE_TYPE_EXIF));
1807 CR (gp_file_set_name (file, filename));
1808 CR (gp_file_set_mime_type (file, GP_MIME_EXIF));
1809 CR (gp_filesystem_set_file_noop (fs, folder, file, context));
1810 CR (gp_file_adjust_name_for_mime_type (file));
1812 GP_DEBUG ("Getting EXIF data is not supported and libgphoto2 "
1813 "has been compiled without EXIF support.");
1817 GP_DEBUG ("Download of '%s' from '%s' (type %i) failed. "
1818 "Reason: '%s'", filename, folder, type,
1819 gp_result_as_string (r));
1827 * \brief Set file information functions
1828 * \param fs a #CameraFilesystem
1829 * \param get_info_func the function to retrieve file information
1830 * \param set_info_func the function to set file information
1831 * \param data private data
1833 * Tells the filesystem which functions to call when file information
1834 * about a file should be retrieved or set. Typically, this function will
1835 * get called by the camera driver on initialization.
1837 * \return a gphoto2 error code.
1840 gp_filesystem_set_info_funcs (CameraFilesystem *fs,
1841 CameraFilesystemGetInfoFunc get_info_func,
1842 CameraFilesystemSetInfoFunc set_info_func,
1847 fs->get_info_func = get_info_func;
1848 fs->set_info_func = set_info_func;
1849 fs->info_data = data;
1855 * \brief Set all filesystem related function pointers
1856 * \param fs a #CameraFilesystem
1857 * \param funcs pointer to a struct of filesystem functions
1858 * \param data private data
1860 * Tells the filesystem which functions to call for camera/filesystem specific
1861 * functions, like listing, retrieving, uploading files and so on.
1863 * \return a gphoto2 error code.
1866 gp_filesystem_set_funcs (CameraFilesystem *fs,
1867 CameraFilesystemFuncs *funcs,
1872 fs->get_info_func = funcs->get_info_func;
1873 fs->set_info_func = funcs->set_info_func;
1874 fs->info_data = data;
1876 fs->put_file_func = funcs->put_file_func;
1877 fs->delete_all_func = funcs->delete_all_func;
1878 fs->make_dir_func = funcs->make_dir_func;
1879 fs->remove_dir_func = funcs->remove_dir_func;
1880 fs->folder_data = data;
1882 fs->file_list_func = funcs->file_list_func;
1883 fs->folder_list_func = funcs->folder_list_func;
1884 fs->list_data = data;
1886 fs->delete_file_func = funcs->del_file_func;
1887 fs->get_file_func = funcs->get_file_func;
1888 fs->file_data = data;
1890 fs->storage_info_func = funcs->storage_info_func;
1895 * \brief Get information about the specified file
1896 * \param fs a #CameraFilesystem
1897 * \param folder the folder that contains the file
1898 * \param filename the filename
1899 * \param info pointer to #CameraFileInfo that receives the information
1900 * \param context a #GPContext
1902 * \return a gphoto2 error code.
1905 gp_filesystem_get_info (CameraFilesystem *fs, const char *folder,
1906 const char *filename, CameraFileInfo *info,
1909 CameraFilesystemFolder *f;
1910 CameraFilesystemFile *file;
1915 CHECK_NULL (fs && folder && filename && info);
1917 CA (folder, context);
1919 GP_DEBUG ("Getting information about '%s' in '%s'...", filename,
1922 if (!fs->get_info_func) {
1923 gp_context_error (context,
1924 _("The filesystem doesn't support getting file "
1926 return (GP_ERROR_NOT_SUPPORTED);
1929 /* Search folder and file and get info if needed */
1930 CR ( lookup_folder_file (fs, folder, filename, &f, &file, context));
1932 if (file->info_dirty) {
1933 CR (fs->get_info_func (fs, folder, filename,
1935 fs->info_data, context));
1936 file->info_dirty = 0;
1940 * If we didn't get GP_FILE_INFO_MTIME, we'll have a look if we
1941 * can get it from EXIF data.
1944 if (!(file->info.file.fields & GP_FILE_INFO_MTIME)) {
1945 GP_DEBUG ("Did not get mtime. Trying EXIF information...");
1946 t = gp_filesystem_get_exif_mtime (fs, folder, filename);
1948 file->info.file.mtime = t;
1949 file->info.file.fields |= GP_FILE_INFO_MTIME;
1953 memcpy (info, &file->info, sizeof (CameraFileInfo));
1958 gp_filesystem_lru_clear (CameraFilesystem *fs)
1961 CameraFilesystemFile *ptr, *prev;
1963 GP_DEBUG ("Clearing fscache LRU list...");
1965 if (fs->lru_first == NULL) {
1966 GP_DEBUG ("fscache LRU list already empty");
1970 ptr = prev = fs->lru_first;
1971 while (ptr != NULL) {
1973 if (ptr->lru_prev != prev) {
1974 GP_DEBUG ("fscache LRU list corrupted (%i)", n);
1978 ptr = ptr->lru_next;
1980 prev->lru_prev = NULL;
1981 prev->lru_next = NULL;
1984 fs->lru_first = NULL;
1985 fs->lru_last = NULL;
1988 GP_DEBUG ("fscache LRU list cleared (removed %i items)", n);
1994 gp_filesystem_lru_remove_one (CameraFilesystem *fs, CameraFilesystemFile *item)
1996 if (item->lru_prev == NULL)
1999 /* Update the prev and next pointers. */
2000 if (item->lru_prev) item->lru_prev->lru_next = item->lru_next;
2001 if (item->lru_next) item->lru_next->lru_prev = item->lru_prev;
2002 if (fs->lru_last == item) {
2003 if (fs->lru_first == item) {
2006 * Case 1: ITEM is the only one in the list. We'll
2007 * remove it, and the list will be empty afterwards.
2009 fs->lru_last = NULL;
2010 fs->lru_first = NULL;
2013 /* Case 2: ITEM is the last in the list. */
2014 fs->lru_last = item->lru_prev;
2016 } else if (fs->lru_first == item) {
2018 /* Case 3: ITEM is the first in the list. */
2019 fs->lru_first = item->lru_next;
2020 /* the first item prev links back to itself */
2021 fs->lru_first->lru_prev = fs->lru_first;
2024 /* Clear the pointers */
2025 item->lru_prev = NULL;
2026 item->lru_next = NULL;
2032 gp_filesystem_lru_free (CameraFilesystem *fs)
2034 CameraFilesystemFile *ptr;
2035 unsigned long int size;
2037 CHECK_NULL (fs && fs->lru_first);
2039 ptr = fs->lru_first;
2041 GP_DEBUG ("Freeing cached data for file '%s'...", ptr->name);
2043 /* Remove it from the list. */
2044 fs->lru_first = ptr->lru_next;
2046 fs->lru_first->lru_prev = fs->lru_first;
2048 fs->lru_last = NULL;
2050 /* Free its content. */
2052 CR( gp_file_get_data_and_size (ptr->normal, NULL, &size));
2053 fs->lru_size -= size;
2054 gp_file_unref (ptr->normal);
2058 CR( gp_file_get_data_and_size (ptr->raw, NULL, &size));
2059 fs->lru_size -= size;
2060 gp_file_unref (ptr->raw);
2064 CR( gp_file_get_data_and_size (ptr->audio, NULL, &size));
2065 fs->lru_size -= size;
2066 gp_file_unref (ptr->audio);
2069 ptr->lru_next = ptr->lru_prev = NULL;
2074 gp_filesystem_lru_count (CameraFilesystem *fs)
2076 CameraFilesystemFile *ptr;
2080 ptr = fs->lru_first;
2082 if (ptr->normal || ptr->raw || ptr->audio)
2084 ptr = ptr->lru_next;
2090 gp_filesystem_lru_update (CameraFilesystem *fs, const char *folder,
2091 CameraFile *file, GPContext *context)
2093 CameraFilesystemFolder *f;
2094 CameraFilesystemFile *xfile;
2095 CameraFileType type;
2096 CameraFile *oldfile = NULL;
2097 const char *filename;
2098 unsigned long int size;
2100 char cached_images[1024];
2102 CHECK_NULL (fs && folder && file);
2104 CR (gp_file_get_name (file, &filename));
2105 CR (gp_file_get_type (file, &type));
2106 CR (gp_file_get_data_and_size (file, NULL, &size));
2109 * The following is a very simple case which is used to prune
2110 * the LRU. We keep PICTURES_TO_KEEP pictures in the LRU.
2112 * We have 2 main scenarios:
2113 * - query all thumbnails (repeatedly) ... they are cached and
2114 * are not pruned by lru free.
2115 * - download all images, linear. no real need for caching.
2116 * - skip back 1 image (in viewers) (really? I don't know.)
2118 * So lets just keep 2 pictures in memory.
2120 if (pictures_to_keep == -1) {
2121 if (gp_setting_get ("libgphoto", "cached-images", cached_images) == GP_OK) {
2122 pictures_to_keep = atoi(cached_images);
2124 /* store a default setting */
2125 sprintf (cached_images, "%d", PICTURES_TO_KEEP);
2126 gp_setting_set ("libgphoto", "cached-images", cached_images);
2130 if (pictures_to_keep < 0) /* also sanity check, but no upper limit. */
2131 pictures_to_keep = PICTURES_TO_KEEP;
2133 x = gp_filesystem_lru_count (fs);
2134 while (x > pictures_to_keep) {
2135 CR (gp_filesystem_lru_free (fs));
2136 x = gp_filesystem_lru_count (fs);
2139 GP_DEBUG ("Adding file '%s' from folder '%s' to the fscache LRU list "
2140 "(type %i)...", filename, folder, type);
2142 /* Search folder and file */
2143 CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2146 * If the file is already in the lru, we first remove it. Note that
2147 * we will only remove 'normal', 'raw' and 'audio' from cache.
2148 * See gp_filesystem_lru_free.
2150 if (xfile->lru_prev != NULL) {
2152 case GP_FILE_TYPE_NORMAL:
2153 oldfile = xfile->normal;
2155 case GP_FILE_TYPE_RAW:
2156 oldfile = xfile->raw;
2158 case GP_FILE_TYPE_AUDIO:
2159 oldfile = xfile->audio;
2161 case GP_FILE_TYPE_PREVIEW:
2162 case GP_FILE_TYPE_EXIF:
2163 case GP_FILE_TYPE_METADATA:
2166 gp_context_error (context, _("Unknown file type %i."),
2171 CR( gp_file_get_data_and_size (oldfile, NULL, &size));
2172 fs->lru_size -= size;
2175 CR (gp_filesystem_lru_remove_one (fs, xfile));
2178 /* Then add the file at the end of the LRU. */
2179 if (fs->lru_first == NULL) {
2180 fs->lru_first = xfile;
2181 fs->lru_last = xfile;
2184 * For the first item, prev point it itself to show that the
2185 * item is in the list.
2187 xfile->lru_prev = xfile;
2190 xfile->lru_next = NULL;
2191 xfile->lru_prev = fs->lru_last;
2192 fs->lru_last->lru_next = xfile;
2193 fs->lru_last = xfile;
2196 CR( gp_file_get_data_and_size (file, NULL, &size));
2197 fs->lru_size += size;
2199 GP_DEBUG ("File '%s' from folder '%s' added in fscache LRU list.",
2206 gp_filesystem_lru_check (CameraFilesystem *fs)
2209 CameraFilesystemFile *ptr, *prev;
2211 GP_DEBUG ("Checking fscache LRU list integrity...");
2213 if (fs->lru_first == NULL) {
2214 GP_DEBUG ("fscache LRU list empty");
2218 ptr = prev = fs->lru_first;
2219 while (ptr != NULL) {
2221 if (ptr->lru_prev != prev) {
2222 GP_DEBUG ("fscache LRU list corrupted (%i)", n);
2226 ptr = ptr->lru_next;
2229 GP_DEBUG ("fscache LRU list ok with %i items (%ld bytes)", n,
2236 * \brief Attach file content to a specified file.
2238 * \param fs a #CameraFilesystem
2239 * \param folder a folder in the filesystem
2240 * \param file a #CameraFile
2241 * \param context: a #GPContext
2243 * Tells the fs about a file. Typically, camera drivers will call this
2244 * function in case they get information about a file (i.e. preview) "for free"
2245 * on gp_camera_capture() or gp_camera_folder_list_files().
2247 * \return a gphoto2 error code.
2250 gp_filesystem_set_file_noop (CameraFilesystem *fs, const char *folder,
2251 CameraFile *file, GPContext *context)
2253 CameraFileType type;
2254 CameraFileInfo info;
2255 CameraFilesystemFolder *f;
2256 CameraFilesystemFile *xfile;
2257 const char *filename;
2261 CHECK_NULL (fs && folder && file);
2263 CA (folder, context);
2265 CR (gp_file_get_name (file, &filename));
2266 CR (gp_file_get_type (file, &type));
2267 GP_DEBUG ("Adding file '%s' to folder '%s' (type %i)...",
2268 filename, folder, type);
2270 /* Search folder and file */
2271 CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2274 * If we add a significant amount of data in the cache, we put (or
2275 * move) a reference to this file in the LRU linked list. We
2276 * assume that only GP_FILE_TYPE_[RAW,NORMAL,EXIF] will contain a
2277 * significant amount of data.
2279 if ((type == GP_FILE_TYPE_RAW) || (type == GP_FILE_TYPE_NORMAL) ||
2280 (type == GP_FILE_TYPE_AUDIO))
2281 CR (gp_filesystem_lru_update (fs, folder, file, context));
2283 /* Redundant sanity check. */
2284 CR (gp_filesystem_lru_check (fs));
2287 case GP_FILE_TYPE_PREVIEW:
2289 gp_file_unref (xfile->preview);
2290 xfile->preview = file;
2293 case GP_FILE_TYPE_NORMAL:
2295 gp_file_unref (xfile->normal);
2296 xfile->normal = file;
2299 case GP_FILE_TYPE_RAW:
2301 gp_file_unref (xfile->raw);
2305 case GP_FILE_TYPE_AUDIO:
2307 gp_file_unref (xfile->audio);
2308 xfile->audio = file;
2311 case GP_FILE_TYPE_EXIF:
2313 gp_file_unref (xfile->exif);
2317 case GP_FILE_TYPE_METADATA:
2318 if (xfile->metadata)
2319 gp_file_unref (xfile->metadata);
2320 xfile->metadata = file;
2324 gp_context_error (context, _("Unknown file type %i."), type);
2329 * If we didn't get a mtime, try to get it from the CameraFileInfo.
2331 CR (gp_file_get_mtime (file, &t));
2333 GP_DEBUG ("File does not contain mtime. Trying "
2334 "information on the file...");
2335 r = gp_filesystem_get_info (fs, folder, filename, &info, NULL);
2336 if ((r == GP_OK) && (info.file.fields & GP_FILE_INFO_MTIME))
2337 t = info.file.mtime;
2341 * If we still don't have the mtime and this is a normal
2342 * file, check if there is EXIF data in the file that contains
2343 * information on the mtime.
2346 if (!t && (type == GP_FILE_TYPE_NORMAL)) {
2347 unsigned long int size;
2350 GP_DEBUG ("Searching data for mtime...");
2351 CR (gp_file_get_data_and_size (file, NULL, &size));
2352 if (size < 32*1024*1024) { /* just assume stuff above 32MB is not EXIF capable */
2353 /* FIXME: Will leak on "fd" retrieval */
2354 CR (gp_file_get_data_and_size (file, &data, &size));
2355 t = get_exif_mtime ((unsigned char*)data, size);
2359 * Still no mtime? Let's see if the camera offers us data of type
2360 * GP_FILE_TYPE_EXIF that includes information on the mtime.
2363 GP_DEBUG ("Trying EXIF information...");
2364 t = gp_filesystem_get_exif_mtime (fs, folder, filename);
2369 CR (gp_file_set_mtime (file, t));
2375 * \brief Store the file information in the virtual fs
2376 * \param fs a #CameraFilesystem
2377 * \param folder the foldername
2378 * \param info the #CameraFileInfo to store
2379 * \param context a #GPContext
2381 * In contrast to #gp_filesystem_set_info, #gp_filesystem_set_info_noop
2382 * will only change the file information in the fs. Typically, camera
2383 * drivers will use this function in case they get file information "for free"
2384 * on #gp_camera_capture or #gp_camera_folder_list_files.
2386 * \return a gphoto2 error code
2389 gp_filesystem_set_info_noop (CameraFilesystem *fs, const char *folder,
2390 CameraFileInfo info, GPContext *context)
2392 CameraFilesystemFolder *f;
2393 CameraFilesystemFile *xfile;
2395 CHECK_NULL (fs && folder);
2397 CA (folder, context);
2399 /* Search folder and file */
2400 CR (lookup_folder_file (fs, folder, info.file.name, &f, &xfile, context));
2402 memcpy (&xfile->info, &info, sizeof (CameraFileInfo));
2403 xfile->info_dirty = 0;
2408 * \brief Set information about a file
2409 * \param fs a #CameraFilesystem
2410 * \param folder foldername where the file resides
2411 * \param filename the files name
2412 * \param info the #CameraFileInfo to set
2413 * \param context a #GPContext
2415 * Sets information about a file in the camera.
2417 * \return a gphoto2 error code.
2420 gp_filesystem_set_info (CameraFilesystem *fs, const char *folder,
2421 const char *filename, CameraFileInfo info,
2424 int result, name, e;
2425 CameraFilesystemFolder *f;
2426 CameraFilesystemFile *xfile;
2428 CHECK_NULL (fs && folder && filename);
2430 CA (folder, context);
2432 if (!fs->set_info_func) {
2433 gp_context_error (context,
2434 _("The filesystem doesn't support setting file "
2436 return (GP_ERROR_NOT_SUPPORTED);
2439 /* Search folder and file */
2440 CR (lookup_folder_file (fs, folder, filename, &f, &xfile, context));
2442 /* Check if people want to set read-only attributes */
2443 if ((info.file.fields & GP_FILE_INFO_TYPE) ||
2444 (info.file.fields & GP_FILE_INFO_SIZE) ||
2445 (info.file.fields & GP_FILE_INFO_WIDTH) ||
2446 (info.file.fields & GP_FILE_INFO_HEIGHT) ||
2447 (info.file.fields & GP_FILE_INFO_STATUS) ||
2448 (info.preview.fields & GP_FILE_INFO_TYPE) ||
2449 (info.preview.fields & GP_FILE_INFO_SIZE) ||
2450 (info.preview.fields & GP_FILE_INFO_WIDTH) ||
2451 (info.preview.fields & GP_FILE_INFO_HEIGHT) ||
2452 (info.preview.fields & GP_FILE_INFO_STATUS) ||
2453 (info.audio.fields & GP_FILE_INFO_TYPE) ||
2454 (info.audio.fields & GP_FILE_INFO_SIZE) ||
2455 (info.audio.fields & GP_FILE_INFO_STATUS)) {
2456 gp_context_error (context, _("Read-only file attributes "
2457 "like width and height can not be changed."));
2458 return (GP_ERROR_BAD_PARAMETERS);
2462 * Set the info. If anything goes wrong, mark info as dirty,
2463 * because the operation could have been partially successful.
2465 * Handle name changes in a separate round.
2467 name = (info.file.fields & GP_FILE_INFO_NAME);
2468 info.file.fields &= ~GP_FILE_INFO_NAME;
2469 result = fs->set_info_func (fs, folder, filename, info, fs->info_data,
2472 xfile->info_dirty = 1;
2475 if (info.file.fields & GP_FILE_INFO_PERMISSIONS)
2476 xfile->info.file.permissions = info.file.permissions;
2478 /* Handle name change */
2481 /* Make sure the file does not exist */
2482 e = gp_filesystem_number (fs, folder, info.file.name, context);
2483 if (e != GP_ERROR_FILE_NOT_FOUND)
2486 info.preview.fields = GP_FILE_INFO_NONE;
2487 info.file.fields = GP_FILE_INFO_NAME;
2488 info.audio.fields = GP_FILE_INFO_NONE;
2489 CR (fs->set_info_func (fs, folder, filename, info,
2490 fs->info_data, context));
2491 strncpy (xfile->info.file.name, info.file.name,
2492 sizeof (xfile->info.file.name));
2493 xname = strdup(info.file.name);
2496 xfile->name = xname;
2504 * \brief Get the storage information about this filesystem
2505 * \param fs the filesystem
2506 * \param storageinfo Pointer to receive a pointer to/array of storage info items
2507 * \param nrofstorageinfos Pointer to receive number of array entries
2508 * \param context a #GPContext
2510 * This function is only called from gp_camera_get_storageinfo(). You may
2511 * want to make sure this information is consistent with the information on
2512 * gp_camera_get_storageinfo().
2514 * Retrieves the storage information, like maximum and free space, for
2515 * the specified filesystem, if supported by the device. The storage
2516 * information is returned in an newly allocated array of
2517 * #CameraStorageInformation objects, to which the pointer pointed to
2518 * by #storageinfo will be set.
2520 * The variable pointed to by #nrofstorageinfos will be set to the
2521 * number of elements in that array.
2523 * It is the caller's responsibility to free the memory of the array.
2525 * \return a gphoto error code
2528 gp_filesystem_get_storageinfo (
2529 CameraFilesystem *fs,
2530 CameraStorageInformation **storageinfo,
2531 int *nrofstorageinfos,
2534 CHECK_NULL (fs && storageinfo && nrofstorageinfos);
2537 if (!fs->storage_info_func) {
2538 gp_context_error (context,
2539 _("The filesystem doesn't support getting storage "
2541 return (GP_ERROR_NOT_SUPPORTED);
2543 return fs->storage_info_func (fs,
2544 storageinfo, nrofstorageinfos,
2545 fs->info_data, context);