jim-easterbrook / python-gphoto2

Python interface to libgphoto2
GNU Lesser General Public License v3.0
359 stars 59 forks source link

Create file from string #98

Closed robertbilling closed 4 years ago

robertbilling commented 4 years ago

I'm trying to write files containing a UUID to memory cards inside cameras and phones so that I can identify a card that has been seen before when a device is plugged in.

This works:


#Tag, untag and retag memory cards

import os
import sys
import gphoto2 as gp
from ctypes import *

def main():
    cam = gp . Camera ()
    cam . init ()
    val, tfile = gp . gp_file_open ( "orig.uui" )
    p = cam . folder_put_file ( "/store_00010001/DCIM", "elephant.uui", gp . GP_FILE_TYPE_NORMAL, tfile)

main()

It copies a UUID from a text file created by uuidgen to the card in the camera.

However I have completely failed to write a UUID from a Python text string without going via a disk file. I have tried creating a file and using set_data_and_size() but have not found any combination of parameters that will work.

This writes a file with the wrong contents and then crashes:

#!/usr/bin/python3

# Tag, untag and retag memory cards

import os
import sys
import gphoto2 as gp
from ctypes import *
text = "wombat!!!"

def main():
    cam = gp . Camera ()
    cam . init ()
    val, tfile = gp.gp_file_new ()
    tfile . set_data_and_size ( text, len ( text ) )
    p = cam . folder_put_file ( "/store_00010001/DCIM", "elephant.uui", \
                                gp . GP_FILE_TYPE_NORMAL, tfile)
main()

The output is:

[unclebob@portia elephant]$ ./ele-mem.py free(): double free detected in tcache 2 Aborted (core dumped)

Is there somewhere an example program for set_data_and_size() ?

jim-easterbrook commented 4 years ago

I've never tried to do anything with set_data_and_size(), so it's quite possible it's got bugs in it. I'll investigate further.

jim-easterbrook commented 4 years ago

It's definitely not doing what it should. Firstly there shouldn't be a size parameter, secondly it should probably accept any object with a "buffer interface".

jim-easterbrook commented 4 years ago

I've just done some tests. My camera won't let me write a file like this - I get a gphoto2.GPhoto2Error: [-1] Unspecified error from cam.folder_put_file. I get no error from tfile.set_data_and_size though. What versions of Python and libgphoto2 are you using?

jim-easterbrook commented 4 years ago

This is very odd. I've written the simplest test I can:

import gphoto2 as gp

text = 'Wombat!!!'

def main():
    tfile = gp.CameraFile()
    tfile.set_data_and_size(text, len(text))
    tfile.save('/tmp/temp.txt')

main()

This runs, but writes /tmp/temp to the output file, i.e. the first len(text) characters of the file name!

If I change text to text = "how now brown cow " * 100 then I get a core dump but the output file contains the expected string.

It's going to take me a few days to get to the bottom of this.

jim-easterbrook commented 4 years ago

Just found this clue to what's going on:

There is one major difference, and I suspect you are stumbling over it:

gp_file_append - the memory area passed stays in your control.

gp_file_set_data_and_size - the memory area passed is out of your control.

                        It has to be malloc()ed, but MUST NOT be freed after
                        the call. 

From http://gphoto-software.10949.n7.nabble.com/gp-file-append-and-gp-file-set-data-and-size-td4560.html

jim-easterbrook commented 4 years ago

Commit 8bc216c should fix this, with a change in the interface. gp_file_set_data_and_size and gp_file_append now take a single parameter - any object that exposes a readable simple buffer, such as a Python bytes string.

jim-easterbrook commented 4 years ago

Now released as version 2.1.0.