3615
3677
return GP_ERROR;
3681
* This function should actually not be necessary, as
3682
* canon_int_list_directory preps the filesystem info backing store with
3683
* all the CameraFileInfos it needs.
3684
* It might never be called.
3687
canon_int_get_info_func (Camera *camera, const char *folder,
3688
const char *filename, CameraFileInfo *info,
3691
/* FIXME: big copy and paste mess from canon_int_list_directory */
3693
unsigned int dirents_length;
3694
unsigned char *dirent_data = NULL;
3695
unsigned char *end_of_data, *temp_ch, *pos;
3696
const char *canonfolder = gphoto2canonpath (camera, folder, context);
3698
GP_DEBUG ("BEGIN canon_int_get_info_func() folder '%s' aka '%s' filename %s", folder, canonfolder, filename);
3700
if ( canonfolder == NULL ) {
3701
GP_DEBUG ( "Error: canon_int_get_info_func called with null name for camera folder" );
3705
/* Fetch all directory entries from the camera */
3706
switch (camera->port->type) {
3708
res = canon_usb_get_dirents (camera, &dirent_data, &dirents_length,
3709
canonfolder, context);
3711
case GP_PORT_SERIAL:
3712
res = canon_serial_get_dirents (camera, &dirent_data, &dirents_length,
3713
canonfolder, context);
3720
end_of_data = dirent_data + dirents_length;
3722
if (dirents_length < CANON_MINIMUM_DIRENT_SIZE) {
3723
gp_context_error (context,
3724
_("canon_int_get_info_func: ERROR: "
3725
"initial message too short (%i < minimum %i)"),
3726
dirents_length, CANON_MINIMUM_DIRENT_SIZE);
3729
return GP_ERROR_CORRUPTED_DATA;
3732
/* The first data we have got here is the dirent for the
3733
* directory we are reading. Skip over 10 bytes
3734
* (2 for attributes, 4 date and 4 size) and then go find
3735
* the end of the directory name so that we get to the next
3736
* dirent which is actually the first one we are interested
3739
GP_DEBUG ("canon_int_get_info_func: Camera directory listing for directory '%s'",
3740
dirent_data + CANON_DIRENT_NAME);
3742
for (pos = dirent_data + CANON_DIRENT_NAME; pos < end_of_data && *pos != 0; pos++)
3744
if (pos == end_of_data || *pos != 0) {
3745
gp_log (GP_LOG_ERROR, "canon_int_get_info_func",
3746
"Reached end of packet while examining the first dirent");
3749
return GP_ERROR_CORRUPTED_DATA;
3751
pos++; /* skip NULL byte terminating directory name */
3753
/* we are now positioned at the first interesting dirent */
3755
/* This is the main loop, for every directory entry returned */
3756
while (pos < end_of_data) {
3757
int is_dir, is_file;
3758
uint16_t dirent_attrs; /* attributes of dirent */
3759
uint32_t dirent_file_size; /* size of dirent in octets */
3760
uint32_t dirent_time; /* time stamp of dirent (Unix Epoch) */
3761
uint8_t *dirent_name; /* name of dirent */
3762
size_t dirent_name_len; /* length of dirent_name */
3763
size_t dirent_ent_size; /* size of dirent in octets */
3768
dirent_attrs = le16atoh (pos + CANON_DIRENT_ATTRS);
3769
dirent_file_size = le32atoh (pos + CANON_DIRENT_SIZE);
3770
dirent_name = pos + CANON_DIRENT_NAME;
3772
/* see canon_int_set_time() for timezone handling */
3773
tmp_time = le32atoh (pos + CANON_DIRENT_TIME);
3774
if (tmp_time != 0) {
3775
/* FIXME: I just want the tm_gmtoff/timezone info */
3777
tm = localtime (&date);
3778
#ifdef HAVE_TM_GMTOFF
3779
dirent_time = tmp_time - tm->tm_gmtoff;
3780
GP_DEBUG ("canon_int_get_info_func: converted %ld to UTC %ld (tm_gmtoff is %ld)",
3781
(long)tmp_time, (long)dirent_time, (long)tm->tm_gmtoff);
3783
dirent_time = tmp_time + timezone;
3784
GP_DEBUG ("canon_int_get_info_func: converted %ld to UTC %ld (timezone is %ld)",
3785
(long)tmp_time, (long)dirent_time, (long)timezone);
3788
dirent_time = tmp_time;
3791
is_dir = ((dirent_attrs & CANON_ATTR_NON_RECURS_ENT_DIR) != 0)
3792
|| ((dirent_attrs & CANON_ATTR_RECURS_ENT_DIR) != 0);
3795
gp_log (GP_LOG_DATA, "canon/canon.c",
3796
"canon_int_get_info_func: "
3797
"reading dirent at position %li of %li (0x%lx of 0x%lx)",
3798
(long)(pos - dirent_data), (long)(end_of_data - dirent_data),
3799
(long)(pos - dirent_data), (long)(end_of_data - dirent_data) );
3801
if (pos + CANON_MINIMUM_DIRENT_SIZE > end_of_data) {
3802
if (camera->port->type == GP_PORT_SERIAL) {
3803
/* check to see if it is only NULL bytes left,
3804
* that is not an error for serial cameras
3805
* (at least the A50 adds five zero bytes at the end)
3807
for (temp_ch = pos; (temp_ch < end_of_data) && (!*temp_ch); temp_ch++) ; /* do nothing */
3809
if (temp_ch == end_of_data) {
3810
GP_DEBUG ("canon_int_get_info_func: "
3811
"the last %li bytes were all 0 - ignoring.",
3812
(long)(temp_ch - pos));
3815
GP_DEBUG ("canon_int_get_info_func: "
3816
"byte[%li=0x%lx] == %i=0x%x", (long)(temp_ch - pos),
3817
(long)(temp_ch - pos), *temp_ch, *temp_ch);
3818
GP_DEBUG ("canon_int_get_info_func: "
3819
"pos is %p, end_of_data is %p, temp_ch is %p - diff is 0x%lx",
3820
pos, end_of_data, temp_ch, (long)(temp_ch - pos));
3823
GP_DEBUG ("canon_int_get_info_func: "
3824
"dirent at position %li=0x%lx of %li=0x%lx is too small, "
3825
"minimum dirent is %i bytes",
3826
(long)(pos - dirent_data), (long)(pos - dirent_data),
3827
(long)(end_of_data - dirent_data), (long)(end_of_data - dirent_data),
3828
CANON_MINIMUM_DIRENT_SIZE);
3829
gp_log (GP_LOG_ERROR,"canon_int_get_info_func", "truncated directory entry encountered");
3832
return GP_ERROR_CORRUPTED_DATA;
3835
/* Check end of this dirent, 10 is to skip over
3836
* 2 attributes + 0x00
3838
* 4 file date (UNIX localtime)
3839
* to where the direntry name begins.
3841
for (temp_ch = dirent_name; temp_ch < end_of_data && *temp_ch != 0;
3844
if (temp_ch == end_of_data || *temp_ch != 0) {
3845
GP_DEBUG ("canon_int_get_info_func: "
3846
"dirent at position %li of %li has invalid name in it."
3847
"bailing out with what we've got.",
3848
(long)(pos - dirent_data),
3849
(long)(end_of_data - dirent_data));
3852
dirent_name_len = strlen ((char *)dirent_name);
3853
dirent_ent_size = CANON_MINIMUM_DIRENT_SIZE + dirent_name_len;
3855
/* check that length of name in this dirent is not of unreasonable size.
3856
* 256 was picked out of the blue
3858
if (dirent_name_len > 256) {
3859
GP_DEBUG ("canon_int_get_info_func: "
3860
"the name in dirent at position %li of %li is too long. (%li bytes)."
3861
"bailing out with what we've got.",
3862
(long)(pos - dirent_data), (long)(end_of_data - dirent_data),
3863
(long)dirent_name_len);
3867
/* 10 bytes of attributes, size and date, a name and a NULL terminating byte */
3868
/* don't use GP_DEBUG since we log this with GP_LOG_DATA */
3869
gp_log (GP_LOG_DATA, "canon/canon.c",
3870
"canon_int_get_info_func: dirent determined to be %li=0x%lx bytes :",
3871
(long)dirent_ent_size, (long)dirent_ent_size);
3872
gp_log_data ("canon", (char *)pos, dirent_ent_size);
3873
if (dirent_name_len) {
3874
/* OK, this directory entry has a name in it. */
3876
if (!strcmp(filename, (char*)dirent_name)) {
3877
/* we're going to fill out the info structure
3880
/* We start with nothing and continously add stuff */
3881
info->file.fields = GP_FILE_INFO_NONE;
3883
info->file.mtime = dirent_time;
3884
if (info->file.mtime != 0)
3885
info->file.fields |= GP_FILE_INFO_MTIME;
3888
/* determine file type based on file name
3889
* this stuff only makes sense for files, not for folders
3892
strncpy (info->file.type,
3893
filename2mimetype (filename),
3894
sizeof (info->file.type));
3895
info->file.fields |= GP_FILE_INFO_TYPE;
3897
if ((dirent_attrs & CANON_ATTR_DOWNLOADED) == 0)
3898
info->file.status = GP_FILE_STATUS_DOWNLOADED;
3901
GP_FILE_STATUS_NOT_DOWNLOADED;
3902
info->file.fields |= GP_FILE_INFO_STATUS;
3904
/* the size is located at offset 2 and is 4
3905
* bytes long, re-order little/big endian */
3906
info->file.size = dirent_file_size;
3907
info->file.fields |= GP_FILE_INFO_SIZE;
3909
/* file access modes */
3910
if ((dirent_attrs & CANON_ATTR_WRITE_PROTECTED) == 0)
3911
info->file.permissions =
3913
GP_FILE_PERM_DELETE;
3915
info->file.permissions = GP_FILE_PERM_READ;
3916
info->file.fields |= GP_FILE_INFO_PERMISSIONS;
3919
/* print dirent as text */
3920
GP_DEBUG ("Raw info: name=%s is_dir=%i, is_file=%i, attrs=0x%x",
3921
dirent_name, is_dir, is_file, dirent_attrs);
3922
debug_fileinfo (info);
3926
* Append directly to the filesystem instead of to the list,
3927
* because we have additional information.
3929
if (!camera->pl->list_all_files
3930
&& !is_image (filename)
3931
&& !is_movie (filename)
3932
&& !is_audio (filename)) {
3933
/* FIXME: Find associated main file and add it there */
3935
GP_DEBUG ("Ignored %s/%s", folder, filename);
3937
const char *thumbname;
3940
thumbname = canon_int_filename2thumbname (camera,
3942
if (thumbname == NULL) {
3945
if ( is_cr2 ( filename ) ) {
3946
/* We get the first part of the raw file as the thumbnail;
3947
this is (almost) a valid EXIF file. */
3948
info->preview.fields = GP_FILE_INFO_TYPE;
3949
strcpy (info->preview.type, GP_MIME_EXIF);
3951
/* Older Canon cams have JPEG thumbs */
3952
info->preview.fields = GP_FILE_INFO_TYPE;
3953
strcpy (info->preview.type, GP_MIME_JPEG);
3956
GP_DEBUG ( "file \"%s\" has preview of MIME type \"%s\"",
3957
filename, info->preview.type );
3960
/* found ... leave loop */
3965
/* make 'pos' point to next dirent in packet.
3966
* first we skip 10 bytes of attribute, size and date,
3967
* then we skip the name plus 1 for the NULL
3968
* termination bytes.
3970
pos += dirent_ent_size;
3975
GP_DEBUG ("END canon_int_get_info_func() folder '%s' aka '%s' fn '%s'", folder, canonfolder, filename);
3620
3982
* canon_int_extract_jpeg_thumb: