[PATCH 2/5] ptp-gadget: Add delete object support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch extends PTP gadget to support DeleteObject
operation.

Signed-off-by: Anatolij Gustschin <agust@xxxxxxx>
---
 ptp.c |  206 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 203 insertions(+), 3 deletions(-)

diff --git a/ptp.c b/ptp.c
index b887176..134fde9 100644
--- a/ptp.c
+++ b/ptp.c
@@ -397,7 +397,8 @@ static const char storage_desc[] = PTP_STORAGE_DESC;
 	__constant_cpu_to_le16(PIMA15740_OP_GET_OBJECT_HANDLES),\
 	__constant_cpu_to_le16(PIMA15740_OP_GET_OBJECT_INFO),	\
 	__constant_cpu_to_le16(PIMA15740_OP_GET_OBJECT),	\
-	__constant_cpu_to_le16(PIMA15740_OP_GET_THUMB),
+	__constant_cpu_to_le16(PIMA15740_OP_GET_THUMB),		\
+	__constant_cpu_to_le16(PIMA15740_OP_DELETE_OBJECT),
 
 static uint16_t dummy_supported_operations[] = {
 	SUPPORTED_OPERATIONS
@@ -1148,7 +1149,6 @@ static int send_object_info(void *recv_buf, void *send_buf, size_t send_len)
 		goto send_resp;
 	}
 
-	/* We do not support PIMA15740_OP_DELETE_OBJECT yet, but maybe we will some time */
 	for (obj = images; obj; obj = obj->next)
 		if (obj->handle == handle)
 			break;
@@ -1204,7 +1204,6 @@ static int send_object_or_thumb(void *recv_buf, void *send_buf, size_t send_len,
 	param = (uint32_t *)r_container->payload;
 	handle = __le32_to_cpu(*param);
 
-	/* We do not support PIMA15740_OP_DELETE_OBJECT yet, but maybe we will some time */
 	for (obj = images; obj; obj = obj->next)
 		if (obj->handle == handle)
 			break;
@@ -1373,6 +1372,199 @@ static int send_storage_info(void *recv_buf, void *send_buf, size_t send_len)
 	return 0;
 }
 
+static void delete_thumb(struct obj_list *obj)
+{
+	char thumb[256];
+	char *dot;
+
+	if (obj->info.thumb_format != PIMA15740_FMT_I_JFIF)
+		return;
+
+	dot = strrchr(obj->name, '.');
+	if (!dot || dot == obj->name)
+		return;
+
+	*dot = 0;
+	snprintf(thumb, sizeof(thumb), THUMB_LOCATION "%s.thumb.jpeg",
+		 obj->name);
+	*dot = '.';
+
+	if (unlink(thumb)) {
+		fprintf(stderr, "Cannot delete %s: %s\n",
+			thumb, strerror(errno));
+	}
+}
+
+static int delete_file(const char *name,
+		       enum pima15740_response_code *resp_code)
+{
+	struct stat st;
+	int ret;
+	uid_t euid;
+	gid_t egid;
+
+	/* access() is unreliable on NFS, we use stat() instead */
+	ret = stat(name, &st);
+	if (ret < 0) {
+		fprintf(stderr, "Cannot stat %s: %s\n", name, strerror(errno));
+		*resp_code = PIMA15740_RESP_GENERAL_ERROR;
+		return -1;
+	}
+
+	euid = geteuid();
+	if (euid == st.st_uid) {
+		if (!(st.st_mode & S_IWUSR)) {
+			*resp_code = PIMA15740_RESP_OBJECT_WRITE_PROTECTED;
+			return -1;
+		}
+		goto del;
+	}
+
+	egid = getegid();
+	if (egid == st.st_gid) {
+		if (!(st.st_mode & S_IWGRP)) {
+			*resp_code = PIMA15740_RESP_OBJECT_WRITE_PROTECTED;
+			return -1;
+		}
+		goto del;
+	}
+
+	if (!(st.st_mode & S_IWOTH)) {
+		*resp_code = PIMA15740_RESP_OBJECT_WRITE_PROTECTED;
+		return -1;
+	}
+
+del:
+	ret = unlink(name);
+	if (ret) {
+		fprintf(stderr, "Cannot delete %s: %s\n",
+			name, strerror(errno));
+		*resp_code = PIMA15740_RESP_GENERAL_ERROR;
+		return -1;
+	}
+
+	*resp_code = PIMA15740_RESP_OK;
+	return 0;
+}
+
+static int update_free_space(void)
+{
+	unsigned long long bytes;
+	struct statfs fs;
+	int ret;
+
+	ret = statfs(root, &fs);
+	if (ret < 0) {
+		fprintf(stderr, "statfs %s: %s\n", root, strerror(errno));
+		return ret;
+	}
+
+	if (verbose > 1)
+		fprintf(stdout, "Block-size %d, total 0x%lx, free 0x%lx\n",
+			fs.f_bsize, fs.f_blocks, fs.f_bfree);
+
+	bytes = (unsigned long long)fs.f_bsize * fs.f_bfree;
+	storage_info.free_space_in_bytes = __cpu_to_le64(bytes);
+	return 0;
+}
+
+static void delete_object(void *recv_buf, void *send_buf)
+{
+	struct ptp_container *r_container = recv_buf;
+	struct ptp_container *s_container = send_buf;
+	enum pima15740_response_code code = PIMA15740_RESP_OK;
+	uint32_t format, handle;
+	uint32_t *param;
+	unsigned long length;
+	int ret = 0;
+
+	length = __le32_to_cpu(r_container->length);
+
+	param = (uint32_t *)r_container->payload;
+	handle = __le32_to_cpu(*param);
+	format = __le32_to_cpu(*(param + 1));
+
+	if (length > 16 && format != PTP_PARAM_UNUSED) {
+		/* ObjectFormatCode not supported */
+		code = PIMA15740_RESP_SPECIFICATION_BY_FORMAT_NOT_SUPPORTED;
+		goto resp;
+	} else if (handle == 1 || handle == 2) {
+		/* read-only /DCIM and /DCIM/100LINUX */
+		code = PIMA15740_RESP_OBJECT_WRITE_PROTECTED;
+		goto resp;
+	}
+
+	ret = chdir(root);
+	if (ret) {
+		fprintf(stderr, "chdir %s: %s\n", root, strerror(errno));
+		code = PIMA15740_RESP_GENERAL_ERROR;
+		goto resp;
+	}
+
+	if (handle == PTP_PARAM_ANY) {
+		struct obj_list *obj, **anchor;
+		int partial = 0;
+
+		anchor = &images;
+		obj = images;
+
+		if (!obj) {
+			code = PIMA15740_RESP_INVALID_OBJECT_HANDLE;
+			goto resp;
+		}
+
+		while (obj) {
+			delete_file(obj->name, &code);
+			if (code == PIMA15740_RESP_OK) {
+				delete_thumb(obj);
+				*anchor = obj->next;
+				free(obj);
+				obj = *anchor;
+				object_number--;
+			} else {
+				anchor = &obj->next;
+				obj = obj->next;
+				partial++;
+			}
+		}
+
+		if (partial)
+			code = PIMA15740_RESP_PARTIAL_DELETION;
+
+	} else {
+		struct obj_list *obj, **anchor;
+
+		anchor = &images;
+		obj = images;
+
+		while (obj) {
+			if (obj->handle == handle)
+				break;
+			anchor = &obj->next;
+			obj = obj->next;
+		}
+
+		if (obj) {
+			delete_file(obj->name, &code);
+			if (code == PIMA15740_RESP_OK) {
+				delete_thumb(obj);
+				*anchor = obj->next;
+				free(obj);
+				object_number--;
+			}
+		} else
+			code = PIMA15740_RESP_INVALID_OBJECT_HANDLE;
+
+	}
+
+	ret = update_free_space();
+	if (ret < 0)
+		code = PIMA15740_RESP_STORE_NOT_AVAILABLE;
+
+resp:
+	make_response(s_container, r_container, code, sizeof(*s_container));
+}
+
 static int process_one_request(void *recv_buf, size_t *recv_size, void *send_buf, size_t *send_size)
 {
 	struct ptp_container *r_container = recv_buf;
@@ -1555,6 +1747,14 @@ static int process_one_request(void *recv_buf, size_t *recv_size, void *send_buf
 			ret = send_object_or_thumb(recv_buf, send_buf, *send_size, 1);
 			count = ret; /* even if ret is negative, handled below */
 			break;
+		case PIMA15740_OP_DELETE_OBJECT:
+			CHECK_COUNT(count, 16, 20, "DELETE_OBJECT");
+			CHECK_SESSION(s_container, r_container, &count, &ret);
+
+			delete_object(recv_buf, send_buf);
+			count = 0;
+			ret = 0;
+			break;
 		}
 		break;
 	}
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux