diff options
author | Marcus Meissner <marcus@jet.franken.de> | 2006-12-21 21:59:42 +0000 |
---|---|---|
committer | Marcus Meissner <marcus@jet.franken.de> | 2006-12-21 21:59:42 +0000 |
commit | 592c5897eadd7181701c46506eea28db99d39d30 (patch) | |
tree | f00286a5afec9381750bd696a362eb3d73498517 /libgphoto2/gphoto2-file.c | |
parent | 0eb800e7b77cf981388ba13c0119b41b4e320a1d (diff) | |
download | libgphoto2-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.c | 542 |
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; } |