summaryrefslogtreecommitdiff
path: root/libgphoto2/gphoto2-file.c
diff options
context:
space:
mode:
authorMarcus Meissner <marcus@jet.franken.de>2006-12-21 21:59:42 +0000
committerMarcus Meissner <marcus@jet.franken.de>2006-12-21 21:59:42 +0000
commit592c5897eadd7181701c46506eea28db99d39d30 (patch)
treef00286a5afec9381750bd696a362eb3d73498517 /libgphoto2/gphoto2-file.c
parent0eb800e7b77cf981388ba13c0119b41b4e320a1d (diff)
downloadlibgphoto2-592c5897eadd7181701c46506eea28db99d39d30.tar.gz
Make it possible to associate CameraFile with UNIX fds.
New API gp_file_new_from_fd(). git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@9695 67ed7778-7388-44ab-90cf-0a291f65f57c
Diffstat (limited to 'libgphoto2/gphoto2-file.c')
-rw-r--r--libgphoto2/gphoto2-file.c542
1 files changed, 452 insertions, 90 deletions
diff --git a/libgphoto2/gphoto2-file.c b/libgphoto2/gphoto2-file.c
index 59b7f39e9..f1f893646 100644
--- a/libgphoto2/gphoto2-file.c
+++ b/libgphoto2/gphoto2-file.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
@@ -53,15 +54,20 @@
* \internal
*/
struct _CameraFile {
- CameraFileType type;
- char mime_type [64];
- char name [MAX_PATH];
- unsigned long int size;
- unsigned char *data;
- long bytes_read;
- int ref_count;
-
- time_t mtime;
+ CameraFileType type;
+ char mime_type [64];
+ char name [MAX_PATH];
+ int ref_count;
+ time_t mtime;
+
+ CameraFileAccessType accesstype;
+
+ /* for GP_FILE_ACCESSTYPE_MEMORY files */
+ unsigned long size;
+ unsigned char *data;
+
+ /* for GP_FILE_ACCESSTYPE_FD files */
+ int fd;
};
@@ -83,7 +89,32 @@ gp_file_new (CameraFile **file)
(*file)->type = GP_FILE_TYPE_NORMAL;
strcpy ((*file)->mime_type, "unknown/unknown");
(*file)->ref_count = 1;
+ (*file)->accesstype = GP_FILE_ACCESSTYPE_MEMORY;
+ return (GP_OK);
+}
+
+
+/*! Create new #CameraFile object from a UNIX filedescriptor.
+ *
+ * \param file a pointer to a #CameraFile
+ * \param fd a UNIX filedescriptor
+ * \return a gphoto2 error code.
+ */
+int
+gp_file_new_from_fd (CameraFile **file, int fd)
+{
+ CHECK_NULL (file);
+ *file = malloc (sizeof (CameraFile));
+ if (!*file)
+ return (GP_ERROR_NO_MEMORY);
+ memset (*file, 0, sizeof (CameraFile));
+
+ (*file)->type = GP_FILE_TYPE_NORMAL;
+ strcpy ((*file)->mime_type, "unknown/unknown");
+ (*file)->ref_count = 1;
+ (*file)->accesstype = GP_FILE_ACCESSTYPE_FD;
+ (*file)->fd = fd;
return (GP_OK);
}
@@ -99,8 +130,10 @@ int gp_file_free (CameraFile *file)
CHECK_RESULT (gp_file_clean (file));
+ if (file->accesstype == GP_FILE_ACCESSTYPE_FD)
+ close (file->fd);
+
free (file);
-
return (GP_OK);
}
@@ -156,19 +189,39 @@ gp_file_append (CameraFile *file, const char *data,
CHECK_NULL (file);
- if (!file->data)
- file->data = malloc (sizeof(char) * (size));
- else {
- t = realloc (file->data, sizeof (char) * (file->size + size));
- if (!t)
- return GP_ERROR_NO_MEMORY;
- file->data = t;
- }
- memcpy (&file->data[file->size], data, size);
-
- file->bytes_read = size;
- file->size += size;
-
+ switch (file->accesstype) {
+ case GP_FILE_ACCESSTYPE_MEMORY:
+ if (!file->data)
+ file->data = malloc (sizeof(char) * (size));
+ else {
+ t = realloc (file->data, sizeof (char) * (file->size + size));
+ if (!t)
+ return GP_ERROR_NO_MEMORY;
+ file->data = t;
+ }
+ memcpy (&file->data[file->size], data, size);
+ file->size += size;
+ break;
+ case GP_FILE_ACCESSTYPE_FD: {
+ unsigned long int curwritten = 0;
+ while (curwritten < size) {
+ size_t res = write (file->fd, data+curwritten, size-curwritten);
+ if (res == -1) {
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d writing to fd.", errno);
+ return GP_ERROR_IO_WRITE;
+ }
+ if (!res) { /* no progress is bad too */
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered 0 bytes written to fd.");
+ return GP_ERROR_IO_WRITE;
+ }
+ curwritten += res;
+ }
+ break;
+ }
+ default:
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Unknown file access type %d", file->accesstype);
+ return GP_ERROR;
+ }
return (GP_OK);
}
@@ -186,12 +239,47 @@ gp_file_set_data_and_size (CameraFile *file, char *data,
{
CHECK_NULL (file);
- if (file->data)
- free (file->data);
- file->data = data;
- file->size = size;
- file->bytes_read = size;
-
+ switch (file->accesstype) {
+ case GP_FILE_ACCESSTYPE_MEMORY:
+ if (file->data)
+ free (file->data);
+ file->data = data;
+ file->size = size;
+ break;
+ case GP_FILE_ACCESSTYPE_FD: {
+ int curwritten = 0;
+
+ /* truncate */
+ if (-1 == lseek (file->fd, SEEK_SET, 0)) {
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d lseeking to 0.", errno);
+ /* might happen on pipes ... just ignore it */
+ }
+ if (-1 == ftruncate (file->fd, 0)) {
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d ftruncating to 0.", errno);
+ /* might happen on pipes ... just ignore it */
+ }
+ while (curwritten < size) {
+ size_t res = write (file->fd, data+curwritten, size-curwritten);
+ if (res == -1) {
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d writing to fd.", errno);
+ return GP_ERROR_IO_WRITE;
+ }
+ if (!res) { /* no progress is bad too */
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered 0 bytes written to fd.");
+ return GP_ERROR_IO_WRITE;
+ }
+ curwritten += res;
+ }
+ /* This function takes over the responsibility for "data", aka
+ * it has to free it. So we do.
+ */
+ free (data);
+ break;
+ }
+ default:
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Unknown file access type %d", file->accesstype);
+ return GP_ERROR;
+ }
return (GP_OK);
}
@@ -213,11 +301,58 @@ gp_file_get_data_and_size (CameraFile *file, const char **data,
{
CHECK_NULL (file);
- if (data)
- *data = file->data;
- if (size)
- *size = file->size;
-
+ switch (file->accesstype) {
+ case GP_FILE_ACCESSTYPE_MEMORY:
+ if (data)
+ *data = file->data;
+ if (size)
+ *size = file->size;
+ break;
+ case GP_FILE_ACCESSTYPE_FD: {
+ off_t offset;
+ unsigned long int curread = 0;
+
+ if (-1 == lseek (file->fd, SEEK_END, 0)) {
+ if (errno == EBADF) return GP_ERROR_IO;
+ /* Might happen for pipes or sockets. Umm. Hard. */
+ /* FIXME */
+ }
+ if (-1 == (offset = lseek (file->fd, SEEK_CUR, 0))) {
+ /* should not happen if we passed the above case */
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d lseekin to CUR.", errno);
+ return GP_ERROR_IO_READ;
+ }
+ if (-1 == lseek (file->fd, SEEK_SET, 0)) {
+ /* should not happen if we passed the above cases */
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d lseekin to CUR.", errno);
+ return GP_ERROR_IO_READ;
+ }
+ if (size) *size = offset;
+ if (!data) /* just the size... */
+ return GP_OK;
+ *data = malloc (offset);
+ if (!*data)
+ return GP_ERROR_NO_MEMORY;
+ while (curread < offset) {
+ unsigned int res = read (file->fd, (char*)((*data)+curread), offset-curread);
+ if (res == -1) {
+ free ((char*)*data);
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d reading.", errno);
+ return GP_ERROR_IO_READ;
+ }
+ if (res == 0) {
+ free ((char*)*data);
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "No progress during reading.");
+ return GP_ERROR_IO_READ;
+ }
+ curread += res;
+ }
+ break;
+ }
+ default:
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Unknown file access type %d", file->accesstype);
+ return GP_ERROR;
+ }
return (GP_OK);
}
@@ -236,18 +371,74 @@ gp_file_save (CameraFile *file, const char *filename)
CHECK_NULL (file && filename);
- if (!(fp = fopen (filename, "wb")))
- return (GP_ERROR);
-
- if (fwrite (file->data, (size_t)sizeof(char), (size_t)file->size, fp) != (size_t)file->size) {
- gp_log (GP_LOG_ERROR, "libgphoto2",
- "Not enough space on device in "
- "order to save '%s'.", filename);
- unlink (filename);
- return (GP_ERROR);
+ switch (file->accesstype) {
+ case GP_FILE_ACCESSTYPE_MEMORY:
+ if (!(fp = fopen (filename, "wb")))
+ return GP_ERROR;
+ if (fwrite (file->data, (size_t)sizeof(char), (size_t)file->size, fp) != (size_t)file->size) {
+ gp_log (GP_LOG_ERROR, "libgphoto2",
+ "Not enough space on device in "
+ "order to save '%s'.", filename);
+ fclose (fp);
+ unlink (filename);
+ return GP_ERROR;
+ }
+ fclose (fp);
+ break;
+ case GP_FILE_ACCESSTYPE_FD: {
+ char *data;
+ unsigned long int curread = 0;
+ off_t offset;
+
+ if (-1 == lseek (file->fd, SEEK_END, 0))
+ return GP_ERROR_IO;
+ if (-1 == (offset = lseek (file->fd, SEEK_CUR, 0))) {
+ /* should not happen if we passed the above case */
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d lseekin to CUR.", errno);
+ return GP_ERROR_IO_READ;
+ }
+ if (-1 == lseek (file->fd, SEEK_SET, 0)) {
+ /* should not happen if we passed the above case */
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d lseekin to BEGIN.", errno);
+ return GP_ERROR_IO_READ;
+ }
+ data = malloc(65536);
+ if (!data)
+ return GP_ERROR_NO_MEMORY;
+ if (!(fp = fopen (filename, "wb")))
+ return GP_ERROR;
+ while (curread < offset) {
+ int toread, res;
+
+ toread = 65536;
+ if (toread > (offset-curread))
+ toread = offset-curread;
+ res = read (file->fd, data, toread);
+ if (res <= 0) {
+ free (data);
+ fclose (fp);
+ unlink (filename);
+ return GP_ERROR_IO_READ;
+ }
+ if (fwrite (data, 1, res, fp) != res) {
+ gp_log (GP_LOG_ERROR, "libgphoto2",
+ "Not enough space on device in "
+ "order to save '%s'.", filename);
+ free (data);
+ fclose (fp);
+ unlink (filename);
+ return GP_ERROR;
+ }
+ curread += res;
+ }
+ free (data);
+ fclose (fp);
+ break;
+ }
+ default:
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Unknown file access type %d", file->accesstype);
+ return GP_ERROR;
}
-
- fclose (fp);
if (file->mtime) {
u.actime = file->mtime;
@@ -309,18 +500,60 @@ gp_file_open (CameraFile *file, const char *filename)
size = ftell (fp);
rewind (fp);
- file->data = malloc (sizeof(char)*(size + 1));
- if (!file->data)
- return (GP_ERROR_NO_MEMORY);
- size_read = fread (file->data, (size_t)sizeof(char), (size_t)size, fp);
- if (ferror(fp)) {
- gp_file_clean (file);
- return (GP_ERROR);
- }
- fclose(fp);
-
- file->size = size_read;
- file->data[size_read] = 0;
+ switch (file->accesstype) {
+ case GP_FILE_ACCESSTYPE_MEMORY:
+ file->data = malloc (sizeof(char)*(size + 1));
+ if (!file->data)
+ return (GP_ERROR_NO_MEMORY);
+ size_read = fread (file->data, (size_t)sizeof(char), (size_t)size, fp);
+ if (ferror(fp)) {
+ gp_file_clean (file);
+ fclose (fp);
+ return (GP_ERROR);
+ }
+ fclose(fp);
+ file->size = size_read;
+ file->data[size_read] = 0;
+ break;
+ case GP_FILE_ACCESSTYPE_FD: {
+ unsigned long curread = 0;
+ char *data;
+
+ data = malloc(65536);
+ if (!data)
+ return GP_ERROR;
+ lseek (file->fd, SEEK_SET, 0);
+ while (curread < size) {
+ int res, toread = 65536;
+ unsigned long curwritten = 0;
+
+ if (toread > (size-curread))
+ toread = size-curread;
+ res = fread (data, (size_t)sizeof(char), (size_t)toread, fp);
+ if (ferror(fp)) {
+ gp_file_clean (file);
+ free (data);
+ fclose (fp);
+ return (GP_ERROR);
+ }
+ while (curwritten < res) {
+ int res2 = write (file->fd, data+curwritten, res-curwritten);
+ if (res2 <= 0) {
+ free (data);
+ fclose (fp);
+ return GP_ERROR_IO_READ;
+ }
+ curwritten += res2;
+ }
+ curread += res;
+ }
+ free (data);
+ fclose (fp);
+ break;
+ }
+ default:
+ break;
+ }
name = strrchr (filename, '/');
if (name)
@@ -376,11 +609,17 @@ gp_file_clean (CameraFile *file)
CHECK_NULL (file);
- if (file->data != NULL)
- free(file->data);
- file->data = NULL;
- file->size = 0;
- file->bytes_read = 0;
+ switch (file->accesstype) {
+ case GP_FILE_ACCESSTYPE_MEMORY:
+ if (file->data != NULL)
+ free(file->data);
+ file->data = NULL;
+ file->size = 0;
+ break;
+ case GP_FILE_ACCESSTYPE_FD:
+ break;
+ default:break;
+ }
strcpy (file->name, "");
return (GP_OK);
}
@@ -394,28 +633,126 @@ gp_file_clean (CameraFile *file)
int
gp_file_copy (CameraFile *destination, CameraFile *source)
{
- int ref_count;
-
CHECK_NULL (destination && source);
gp_log (GP_LOG_DEBUG, "gphoto2-file", "Copying '%s' onto '%s'...",
source->name, destination->name);
- ref_count = destination->ref_count;
- if (destination->data) {
- free (destination->data);
- destination->data = NULL;
+ /* struct members we can just copy. All generic ones, but not refcount. */
+ memcpy (destination->name, source->name, sizeof (source->name));
+ memcpy (destination->mime_type, source->mime_type, sizeof (source->mime_type));
+ destination->type = source->type;
+ destination->mtime = source->mtime;
+
+ if ((destination->accesstype == GP_FILE_ACCESSTYPE_MEMORY) &&
+ (source->accesstype == GP_FILE_ACCESSTYPE_MEMORY)) {
+ if (destination->data) {
+ free (destination->data);
+ destination->data = NULL;
+ }
+ destination->size = source->size;
+ destination->data = malloc (sizeof (char) * source->size);
+ if (!destination->data)
+ return (GP_ERROR_NO_MEMORY);
+ memcpy (destination->data, source->data, source->size);
+ return (GP_OK);
}
-
- memcpy (destination, source, sizeof (CameraFile));
- destination->ref_count = ref_count;
-
- destination->data = malloc (sizeof (char) * source->size);
- if (!destination->data)
- return (GP_ERROR_NO_MEMORY);
- memcpy (destination->data, source->data, source->size);
-
- return (GP_OK);
+ if ( (destination->accesstype == GP_FILE_ACCESSTYPE_MEMORY) &&
+ (source->accesstype == GP_FILE_ACCESSTYPE_FD)
+ ) {
+ off_t offset;
+ unsigned long int curread = 0;
+
+ if (destination->data) {
+ free (destination->data);
+ destination->data = NULL;
+ }
+ if (-1 == lseek (source->fd, SEEK_END, 0)) {
+ if (errno == EBADF) return GP_ERROR_IO;
+ /* Might happen for pipes or sockets. Umm. Hard. */
+ /* FIXME */
+ }
+ if (-1 == (offset = lseek (source->fd, SEEK_CUR, 0))) {
+ /* should not happen if we passed the above case */
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d lseekin to CUR.", errno);
+ return GP_ERROR_IO_READ;
+ }
+ if (-1 == lseek (source->fd, SEEK_SET, 0)) {
+ /* should not happen if we passed the above cases */
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d lseekin to CUR.", errno);
+ return GP_ERROR_IO_READ;
+ }
+ destination->size = offset;
+ destination->data = malloc (offset);
+ if (!destination->data)
+ return GP_ERROR_NO_MEMORY;
+ while (curread < offset) {
+ unsigned int res = read (source->fd, destination->data+curread, offset-curread);
+ if (res == -1) {
+ free (destination->data);
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Encountered error %d reading.", errno);
+ return GP_ERROR_IO_READ;
+ }
+ if (res == 0) {
+ free (destination->data);
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "No progress during reading.");
+ return GP_ERROR_IO_READ;
+ }
+ curread += res;
+ }
+ return GP_OK;
+ }
+ if ( (destination->accesstype == GP_FILE_ACCESSTYPE_FD) &&
+ (source->accesstype == GP_FILE_ACCESSTYPE_FD)
+ ) {
+ char *data;
+
+ lseek (destination->fd, SEEK_SET, 0);
+ ftruncate (destination->fd, 0);
+ lseek (source->fd, SEEK_SET, 0);
+ data = malloc (65536);
+ while (1) {
+ unsigned long curwritten = 0;
+ int res;
+
+ res = read (source->fd, data, 65536);
+ if (res == -1) {
+ free (data);
+ return GP_ERROR_IO_READ;
+ }
+ if (res == 0)
+ break;
+ while (curwritten < res) {
+ int res2 = write (destination->fd, data+curwritten, res-curwritten);
+ if (res2 == -1) {
+ free (data);
+ return GP_ERROR_IO_WRITE;
+ }
+ if (res2 == 0)
+ break;
+ curwritten += res2;
+ }
+ if (res < 65536) /* end of file */
+ break;
+ }
+ return GP_OK;
+ }
+ if ( (destination->accesstype == GP_FILE_ACCESSTYPE_FD) &&
+ (source->accesstype == GP_FILE_ACCESSTYPE_MEMORY)
+ ) {
+ unsigned long curwritten = 0;
+ while (curwritten < source->size) {
+ int res = write (destination->fd, source->data+curwritten, source->size-curwritten);
+
+ if (res == -1)
+ return GP_ERROR_IO_WRITE;
+ if (!res) /* no progress? */
+ return GP_ERROR_IO_WRITE;
+ curwritten += res;
+ }
+ }
+ gp_log (GP_LOG_ERROR, "gphoto2-file", "Unhandled cases in gp_copy_file. Bad!");
+ return GP_ERROR;
}
/**
@@ -500,18 +837,43 @@ gp_file_detect_mime_type (CameraFile *file)
CHECK_NULL (file);
- /* image/tiff */
- if ((file->size >= 5) && !memcmp (file->data, TIFF_SOI_MARKER, 5))
- CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_TIFF))
-
- /* image/jpeg */
- else if ((file->size >= 2) && !memcmp (file->data, JPEG_SOI_MARKER, 2))
- CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_JPEG))
-
- else
- CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_RAW));
-
- return (GP_OK);
+ switch (file->accesstype) {
+ case GP_FILE_ACCESSTYPE_MEMORY:
+ /* image/tiff */
+ if ((file->size >= 5) && !memcmp (file->data, TIFF_SOI_MARKER, 5))
+ CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_TIFF))
+
+ /* image/jpeg */
+ else if ((file->size >= 2) && !memcmp (file->data, JPEG_SOI_MARKER, 2))
+ CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_JPEG))
+ else
+ CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_RAW));
+ return GP_OK;
+ case GP_FILE_ACCESSTYPE_FD: {
+ char data[5];
+ off_t offset;
+ int res;
+
+ offset = lseek (file->fd, SEEK_SET, 0);
+ res = read (file->fd, data, sizeof(data));
+ if (res == -1)
+ return GP_ERROR_IO_READ;
+ /* image/tiff */
+ if ((res >= 5) && !memcmp (data, TIFF_SOI_MARKER, 5))
+ CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_TIFF))
+
+ /* image/jpeg */
+ else if ((res >= 2) && !memcmp (data, JPEG_SOI_MARKER, 2))
+ CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_JPEG))
+ else
+ CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_RAW));
+ lseek (file->fd, SEEK_SET, offset);
+ break;
+ }
+ default:
+ break;
+ }
+ return GP_OK;
}