summaryrefslogtreecommitdiff
path: root/camlibs/canon
diff options
context:
space:
mode:
authorMarcus Meissner <marcus@jet.franken.de>2013-05-05 13:11:45 +0000
committerMarcus Meissner <marcus@jet.franken.de>2013-05-05 13:11:45 +0000
commit001963026a80bb792a13667bad5dcf396020568a (patch)
treeb0199ff8eb4db713dc70d7688e7bd88491f5453a /camlibs/canon
parent98c11f3f4c00996962af6d23d77289b823e5968d (diff)
downloadlibgphoto2-001963026a80bb792a13667bad5dcf396020568a.tar.gz
set the "mtime" of the CameraFile during retrieval from the
CameraFileInfo to avoid "0" as mtime in filenames more complete get_info_func, although it should not be called actually git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@14399 67ed7778-7388-44ab-90cf-0a291f65f57c
Diffstat (limited to 'camlibs/canon')
-rw-r--r--camlibs/canon/canon.c304
-rw-r--r--camlibs/canon/canon.h1
-rw-r--r--camlibs/canon/library.c8
3 files changed, 311 insertions, 2 deletions
diff --git a/camlibs/canon/canon.c b/camlibs/canon/canon.c
index 66a57088b..fece45060 100644
--- a/camlibs/canon/canon.c
+++ b/camlibs/canon/canon.c
@@ -1735,7 +1735,9 @@ canon_int_get_release_params (Camera *camera, GPContext *context)
status = canon_int_do_control_dialogue (camera,
CANON_USB_CONTROL_GET_PARAMS,
0x00, 0, &response, &len);
-
+ if ( status != GP_OK )
+ return status;
+
if ( response == NULL )
return GP_ERROR_OS_FAILURE;
break;
@@ -3675,6 +3677,306 @@ canon_int_wait_for_event (Camera *camera, int timeout,
return GP_ERROR;
}
+/* NOTE:
+ * This function should actually not be necessary, as
+ * canon_int_list_directory preps the filesystem info backing store with
+ * all the CameraFileInfos it needs.
+ * It might never be called.
+ */
+int
+canon_int_get_info_func (Camera *camera, const char *folder,
+ const char *filename, CameraFileInfo *info,
+ GPContext *context)
+{
+ /* FIXME: big copy and paste mess from canon_int_list_directory */
+ int res;
+ unsigned int dirents_length;
+ unsigned char *dirent_data = NULL;
+ unsigned char *end_of_data, *temp_ch, *pos;
+ const char *canonfolder = gphoto2canonpath (camera, folder, context);
+
+ GP_DEBUG ("BEGIN canon_int_get_info_func() folder '%s' aka '%s' filename %s", folder, canonfolder, filename);
+
+ if ( canonfolder == NULL ) {
+ GP_DEBUG ( "Error: canon_int_get_info_func called with null name for camera folder" );
+ return GP_ERROR;
+ }
+
+ /* Fetch all directory entries from the camera */
+ switch (camera->port->type) {
+ case GP_PORT_USB:
+ res = canon_usb_get_dirents (camera, &dirent_data, &dirents_length,
+ canonfolder, context);
+ break;
+ case GP_PORT_SERIAL:
+ res = canon_serial_get_dirents (camera, &dirent_data, &dirents_length,
+ canonfolder, context);
+ break;
+ GP_PORT_DEFAULT
+ }
+ if (res != GP_OK)
+ return res;
+
+ end_of_data = dirent_data + dirents_length;
+
+ if (dirents_length < CANON_MINIMUM_DIRENT_SIZE) {
+ gp_context_error (context,
+ _("canon_int_get_info_func: ERROR: "
+ "initial message too short (%i < minimum %i)"),
+ dirents_length, CANON_MINIMUM_DIRENT_SIZE);
+ free (dirent_data);
+ dirent_data = NULL;
+ return GP_ERROR_CORRUPTED_DATA;
+ }
+
+ /* The first data we have got here is the dirent for the
+ * directory we are reading. Skip over 10 bytes
+ * (2 for attributes, 4 date and 4 size) and then go find
+ * the end of the directory name so that we get to the next
+ * dirent which is actually the first one we are interested
+ * in
+ */
+ GP_DEBUG ("canon_int_get_info_func: Camera directory listing for directory '%s'",
+ dirent_data + CANON_DIRENT_NAME);
+
+ for (pos = dirent_data + CANON_DIRENT_NAME; pos < end_of_data && *pos != 0; pos++)
+ /* do nothing */ ;
+ if (pos == end_of_data || *pos != 0) {
+ gp_log (GP_LOG_ERROR, "canon_int_get_info_func",
+ "Reached end of packet while examining the first dirent");
+ free (dirent_data);
+ dirent_data = NULL;
+ return GP_ERROR_CORRUPTED_DATA;
+ }
+ pos++; /* skip NULL byte terminating directory name */
+
+ /* we are now positioned at the first interesting dirent */
+
+ /* This is the main loop, for every directory entry returned */
+ while (pos < end_of_data) {
+ int is_dir, is_file;
+ uint16_t dirent_attrs; /* attributes of dirent */
+ uint32_t dirent_file_size; /* size of dirent in octets */
+ uint32_t dirent_time; /* time stamp of dirent (Unix Epoch) */
+ uint8_t *dirent_name; /* name of dirent */
+ size_t dirent_name_len; /* length of dirent_name */
+ size_t dirent_ent_size; /* size of dirent in octets */
+ uint32_t tmp_time;
+ time_t date;
+ struct tm *tm;
+
+ dirent_attrs = le16atoh (pos + CANON_DIRENT_ATTRS);
+ dirent_file_size = le32atoh (pos + CANON_DIRENT_SIZE);
+ dirent_name = pos + CANON_DIRENT_NAME;
+
+ /* see canon_int_set_time() for timezone handling */
+ tmp_time = le32atoh (pos + CANON_DIRENT_TIME);
+ if (tmp_time != 0) {
+ /* FIXME: I just want the tm_gmtoff/timezone info */
+ date = time(NULL);
+ tm = localtime (&date);
+#ifdef HAVE_TM_GMTOFF
+ dirent_time = tmp_time - tm->tm_gmtoff;
+ GP_DEBUG ("canon_int_get_info_func: converted %ld to UTC %ld (tm_gmtoff is %ld)",
+ (long)tmp_time, (long)dirent_time, (long)tm->tm_gmtoff);
+#else
+ dirent_time = tmp_time + timezone;
+ GP_DEBUG ("canon_int_get_info_func: converted %ld to UTC %ld (timezone is %ld)",
+ (long)tmp_time, (long)dirent_time, (long)timezone);
+#endif
+ } else {
+ dirent_time = tmp_time;
+ }
+
+ is_dir = ((dirent_attrs & CANON_ATTR_NON_RECURS_ENT_DIR) != 0)
+ || ((dirent_attrs & CANON_ATTR_RECURS_ENT_DIR) != 0);
+ is_file = !is_dir;
+
+ gp_log (GP_LOG_DATA, "canon/canon.c",
+ "canon_int_get_info_func: "
+ "reading dirent at position %li of %li (0x%lx of 0x%lx)",
+ (long)(pos - dirent_data), (long)(end_of_data - dirent_data),
+ (long)(pos - dirent_data), (long)(end_of_data - dirent_data) );
+
+ if (pos + CANON_MINIMUM_DIRENT_SIZE > end_of_data) {
+ if (camera->port->type == GP_PORT_SERIAL) {
+ /* check to see if it is only NULL bytes left,
+ * that is not an error for serial cameras
+ * (at least the A50 adds five zero bytes at the end)
+ */
+ for (temp_ch = pos; (temp_ch < end_of_data) && (!*temp_ch); temp_ch++) ; /* do nothing */
+
+ if (temp_ch == end_of_data) {
+ GP_DEBUG ("canon_int_get_info_func: "
+ "the last %li bytes were all 0 - ignoring.",
+ (long)(temp_ch - pos));
+ break;
+ } else {
+ GP_DEBUG ("canon_int_get_info_func: "
+ "byte[%li=0x%lx] == %i=0x%x", (long)(temp_ch - pos),
+ (long)(temp_ch - pos), *temp_ch, *temp_ch);
+ GP_DEBUG ("canon_int_get_info_func: "
+ "pos is %p, end_of_data is %p, temp_ch is %p - diff is 0x%lx",
+ pos, end_of_data, temp_ch, (long)(temp_ch - pos));
+ }
+ }
+ GP_DEBUG ("canon_int_get_info_func: "
+ "dirent at position %li=0x%lx of %li=0x%lx is too small, "
+ "minimum dirent is %i bytes",
+ (long)(pos - dirent_data), (long)(pos - dirent_data),
+ (long)(end_of_data - dirent_data), (long)(end_of_data - dirent_data),
+ CANON_MINIMUM_DIRENT_SIZE);
+ gp_log (GP_LOG_ERROR,"canon_int_get_info_func", "truncated directory entry encountered");
+ free (dirent_data);
+ dirent_data = NULL;
+ return GP_ERROR_CORRUPTED_DATA;
+ }
+
+ /* Check end of this dirent, 10 is to skip over
+ * 2 attributes + 0x00
+ * 4 file size
+ * 4 file date (UNIX localtime)
+ * to where the direntry name begins.
+ */
+ for (temp_ch = dirent_name; temp_ch < end_of_data && *temp_ch != 0;
+ temp_ch++) ;
+
+ if (temp_ch == end_of_data || *temp_ch != 0) {
+ GP_DEBUG ("canon_int_get_info_func: "
+ "dirent at position %li of %li has invalid name in it."
+ "bailing out with what we've got.",
+ (long)(pos - dirent_data),
+ (long)(end_of_data - dirent_data));
+ break;
+ }
+ dirent_name_len = strlen ((char *)dirent_name);
+ dirent_ent_size = CANON_MINIMUM_DIRENT_SIZE + dirent_name_len;
+
+ /* check that length of name in this dirent is not of unreasonable size.
+ * 256 was picked out of the blue
+ */
+ if (dirent_name_len > 256) {
+ GP_DEBUG ("canon_int_get_info_func: "
+ "the name in dirent at position %li of %li is too long. (%li bytes)."
+ "bailing out with what we've got.",
+ (long)(pos - dirent_data), (long)(end_of_data - dirent_data),
+ (long)dirent_name_len);
+ break;
+ }
+
+ /* 10 bytes of attributes, size and date, a name and a NULL terminating byte */
+ /* don't use GP_DEBUG since we log this with GP_LOG_DATA */
+ gp_log (GP_LOG_DATA, "canon/canon.c",
+ "canon_int_get_info_func: dirent determined to be %li=0x%lx bytes :",
+ (long)dirent_ent_size, (long)dirent_ent_size);
+ gp_log_data ("canon", (char *)pos, dirent_ent_size);
+ if (dirent_name_len) {
+ /* OK, this directory entry has a name in it. */
+
+ if (!strcmp(filename, (char*)dirent_name)) {
+ /* we're going to fill out the info structure
+ in this block */
+
+ /* We start with nothing and continously add stuff */
+ info->file.fields = GP_FILE_INFO_NONE;
+
+ info->file.mtime = dirent_time;
+ if (info->file.mtime != 0)
+ info->file.fields |= GP_FILE_INFO_MTIME;
+
+ if (is_file) {
+ /* determine file type based on file name
+ * this stuff only makes sense for files, not for folders
+ */
+
+ strncpy (info->file.type,
+ filename2mimetype (filename),
+ sizeof (info->file.type));
+ info->file.fields |= GP_FILE_INFO_TYPE;
+
+ if ((dirent_attrs & CANON_ATTR_DOWNLOADED) == 0)
+ info->file.status = GP_FILE_STATUS_DOWNLOADED;
+ else
+ info->file.status =
+ GP_FILE_STATUS_NOT_DOWNLOADED;
+ info->file.fields |= GP_FILE_INFO_STATUS;
+
+ /* the size is located at offset 2 and is 4
+ * bytes long, re-order little/big endian */
+ info->file.size = dirent_file_size;
+ info->file.fields |= GP_FILE_INFO_SIZE;
+
+ /* file access modes */
+ if ((dirent_attrs & CANON_ATTR_WRITE_PROTECTED) == 0)
+ info->file.permissions =
+ GP_FILE_PERM_READ |
+ GP_FILE_PERM_DELETE;
+ else
+ info->file.permissions = GP_FILE_PERM_READ;
+ info->file.fields |= GP_FILE_INFO_PERMISSIONS;
+ }
+
+ /* print dirent as text */
+ GP_DEBUG ("Raw info: name=%s is_dir=%i, is_file=%i, attrs=0x%x",
+ dirent_name, is_dir, is_file, dirent_attrs);
+ debug_fileinfo (info);
+
+ if (is_file) {
+ /*
+ * Append directly to the filesystem instead of to the list,
+ * because we have additional information.
+ */
+ if (!camera->pl->list_all_files
+ && !is_image (filename)
+ && !is_movie (filename)
+ && !is_audio (filename)) {
+ /* FIXME: Find associated main file and add it there */
+ /* do nothing */
+ GP_DEBUG ("Ignored %s/%s", folder, filename);
+ } else {
+ const char *thumbname;
+
+
+ thumbname = canon_int_filename2thumbname (camera,
+ filename);
+ if (thumbname == NULL) {
+ /* no thumbnail */
+ } else {
+ if ( is_cr2 ( filename ) ) {
+ /* We get the first part of the raw file as the thumbnail;
+ this is (almost) a valid EXIF file. */
+ info->preview.fields = GP_FILE_INFO_TYPE;
+ strcpy (info->preview.type, GP_MIME_EXIF);
+ } else {
+ /* Older Canon cams have JPEG thumbs */
+ info->preview.fields = GP_FILE_INFO_TYPE;
+ strcpy (info->preview.type, GP_MIME_JPEG);
+ }
+ }
+ GP_DEBUG ( "file \"%s\" has preview of MIME type \"%s\"",
+ filename, info->preview.type );
+ }
+ }
+ /* found ... leave loop */
+ break;
+ }
+ }
+
+ /* make 'pos' point to next dirent in packet.
+ * first we skip 10 bytes of attribute, size and date,
+ * then we skip the name plus 1 for the NULL
+ * termination bytes.
+ */
+ pos += dirent_ent_size;
+ }
+ free (dirent_data);
+ dirent_data = NULL;
+
+ GP_DEBUG ("END canon_int_get_info_func() folder '%s' aka '%s' fn '%s'", folder, canonfolder, filename);
+
+ return GP_OK;
+}
+
/**
* canon_int_extract_jpeg_thumb:
diff --git a/camlibs/canon/canon.h b/camlibs/canon/canon.h
index d21406862..4950d3c20 100644
--- a/camlibs/canon/canon.h
+++ b/camlibs/canon/canon.h
@@ -688,6 +688,7 @@ int canon_int_capture_preview (Camera *camera, unsigned char **data, unsigned in
int canon_int_get_disk_name_info(Camera *camera, const char *name,int *capacity,int *available, GPContext *context);
int canon_int_list_directory (Camera *camera, const char *folder, CameraList *list, const canonDirlistFunctionBits flags, GPContext *context);
+int canon_int_get_info_func (Camera *camera, const char *folder, const char *filename, CameraFileInfo * info, GPContext *context);
int canon_int_get_file(Camera *camera, const char *name, unsigned char **data, unsigned int *length, GPContext *context);
int canon_int_get_thumbnail(Camera *camera, const char *name, unsigned char **retdata, unsigned int *length, GPContext *context);
diff --git a/camlibs/canon/library.c b/camlibs/canon/library.c
index 36bc618e4..39fab0b08 100644
--- a/camlibs/canon/library.c
+++ b/camlibs/canon/library.c
@@ -805,6 +805,10 @@ get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
folder,
context),
attr, context);
+
+ /* we cannot easily retrieve it except by reading the directory */
+ if (info.file.fields & GP_FILE_INFO_MTIME)
+ gp_file_set_mtime (file, info.file.mtime);
}
break;
@@ -2380,6 +2384,7 @@ get_info_func (CameraFilesystem __unused__ *fs, const char *folder,
CameraFileInfo * info,
void __unused__ *data, GPContext __unused__ *context)
{
+ Camera *camera = data;
GP_DEBUG ("get_info_func() called for '%s'/'%s'", folder, filename);
info->preview.fields = GP_FILE_INFO_TYPE;
@@ -2400,7 +2405,8 @@ get_info_func (CameraFilesystem __unused__ *fs, const char *folder,
strcpy (info->file.type, GP_MIME_WAV);
else
strcpy (info->file.type, GP_MIME_UNKNOWN);
- return GP_OK;
+ /* let it fill driver specific info */
+ return canon_int_get_info_func (camera, folder, filename, info, context);
}
static int