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

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

 



Looks good in general, some comments below:

On Fri, 9 Apr 2010, Anatolij Gustschin wrote:

> 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..87adbd4 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 (__le16_to_cpu(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));
> +	}

Please, remove superfluous braces.

> +}
> +
> +static int delete_file(const char *name,
> +		       enum pima15740_response_code *resp_code)

I don't like this very much. delete_file() returns an int, which is 
ignored by callers, and the actual return code is passed as a parameter. 
Please, either make it void or return the response 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;
> +	}

Isn't there an easier and less error-prone way to verify? Maybe just try 
to delete, if errno == EPERM - return write-protected? Any specific reason 
for doing it this way? Would this also cover SELinux, ACL,... Notice, I 
have no idea about either of them, please, explain.

> +
> +del:
> +	ret = unlink(name);
> +	if (ret) {
> +		fprintf(stderr, "Cannot delete %s: %s\n",
> +			name, strerror(errno));
> +		*resp_code = PIMA15740_RESP_GENERAL_ERROR;

If you accept my proposal to just try to unlink, you'd check for EACCESS / 
EPERM here, and then set PIMA15740_RESP_OBJECT_WRITE_PROTECTED response 
code, otherwise 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 %d, free %d\n",
> +			fs.f_bsize, (int)fs.f_blocks, (int)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) {

I think, you can allow format == PTP_PARAM_ANY at no additional cost - you 
anyway support deletion of all objects, and they are all images so far...

> +		/* 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;

Shall we not return in this case - we have been requested to delete all 
objects, and there are none. This looks like a success to me;) Then you 
wouldn't have to special case this at all.

> +			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;
> +

Superfluous empty line

> +	} 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;

Missing "{}"

> +

Superfluous empty line

> +	}
> +
> +	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.6.3.3

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
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