static dav_error *
_load_in_place_chunk_info(const dav_resource *r, const char *path, struct content_textinfo_s *content,
		struct chunk_textinfo_s *chunk, GHashTable **comp_opt)
{
	dav_error *e = NULL;
	GError *ge = NULL;
	apr_pool_t *p = r->pool;
	dav_rawx_server_conf *conf = resource_get_server_config(r);
	
	
	apr_finfo_t finfo;

	/* check chunk presence */

	if(APR_SUCCESS != apr_stat(&finfo, path, APR_FINFO_NORM, p)) {
		return server_create_and_stat_error(conf, r->pool, HTTP_NOT_FOUND,
				0, "Chunk file not found");
	}

	if(!get_rawx_info_in_attr(path, &ge,
				content, chunk)) {
		if(NULL != ge) {	
			e = server_create_and_stat_error(conf, p, HTTP_CONFLICT,
				0, apr_pstrcat(p, "Failed to get chunk attributes: ", ge->message, NULL));
			g_clear_error(&ge);
		} else {
			e = server_create_and_stat_error(conf, p, HTTP_CONFLICT,
			                                0, "Failed to get chunk chunk attributes: No error specified");
		}
		return e;
	}

	str_replace_by_pooled_str(p, &(content->path));
	str_replace_by_pooled_str(p, &(content->size));
	str_replace_by_pooled_str(p, &(content->chunk_nb));
	str_replace_by_pooled_str(p, &(content->metadata));
	str_replace_by_pooled_str(p, &(content->system_metadata));
	str_replace_by_pooled_str(p, &(content->container_id));
	str_replace_by_pooled_str(p, &(chunk->id));
	str_replace_by_pooled_str(p, &(chunk->path));
	str_replace_by_pooled_str(p, &(chunk->size));
	str_replace_by_pooled_str(p, &(chunk->hash));
	str_replace_by_pooled_str(p, &(chunk->position));
	str_replace_by_pooled_str(p, &(chunk->metadata));
	str_replace_by_pooled_str(p, &(chunk->container_id));

	if(!get_compression_info_in_attr(path, &ge, comp_opt)){
		if(NULL != ge) {	
			e = server_create_and_stat_error(conf, p, HTTP_CONFLICT,
				0, apr_pstrcat(p, "Failed to get chunk compression attributes: ", ge->message, NULL));
			g_clear_error(&ge);
		} else {
			e = server_create_and_stat_error(conf, p, HTTP_CONFLICT,
			                                0, "Failed to get chunk compression attributes: No error specified");
		}
		return e;
	}

	return NULL;
}
static gboolean
check_uncompressed_chunk(const gchar* path, GError** error)
{
	gboolean status = FALSE;
	GHashTable *compress_opt =
		g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free);

	/* Check chunk not already compresssed */
	if (get_compression_info_in_attr(path, error, compress_opt)) {
		DEBUG("Compression info found");
		gchar *compression = NULL;
		compression = g_hash_table_lookup(compress_opt, NS_COMPRESSION_OPTION);
		if (compression && g_ascii_strcasecmp(compression, NS_COMPRESSION_ON) == 0) {
			/* read headers for ensure ? */
			GSETERROR (error, "Chunk already compressed\n");
			goto end;
		}
	} else {
			GSETERROR (error, "Failed to get compression info from extended attributes\n");
			goto end;
	}

	status = TRUE;

end:
	if (compress_opt)
		g_hash_table_destroy(compress_opt);

	return status;
}
static dav_error *
_load_in_place_chunk_info(const dav_resource *r, const char *path, struct chunk_textinfo_s *chunk, GHashTable *comp_opt)
{
	dav_error *e = NULL;
	GError *ge = NULL;
	apr_pool_t *p = r->pool;
	dav_rawx_server_conf *conf = resource_get_server_config(r);

	/* No need to check for the chunk's presence, getting its attributes will
	 * fail if the chunk doesn't exists */
	if (!get_rawx_info_from_file(path, &ge, chunk)) {
		if (NULL != ge) {
			e = server_create_and_stat_error(conf, p, HTTP_CONFLICT, 0,
					apr_pstrcat(p, "Failed to get chunk attributes: ", ge->message, NULL));
			g_clear_error(&ge);
		} else {
			e = server_create_and_stat_error(conf, p, HTTP_CONFLICT, 0,
					"Failed to get chunk chunk attributes: No error specified");
		}
		return e;
	}

	str_replace_by_pooled_str(p, &(chunk->container_id));

	str_replace_by_pooled_str(p, &(chunk->content_id));
	str_replace_by_pooled_str(p, &(chunk->content_path));
	str_replace_by_pooled_str(p, &(chunk->content_version));
	str_replace_by_pooled_str(p, &(chunk->content_size));
	str_replace_by_pooled_str(p, &(chunk->content_chunk_nb));

	str_replace_by_pooled_str(p, &(chunk->content_storage_policy));
	str_replace_by_pooled_str(p, &(chunk->content_chunk_method));
	str_replace_by_pooled_str(p, &(chunk->content_mime_type));

	str_replace_by_pooled_str(p, &(chunk->chunk_id));
	str_replace_by_pooled_str(p, &(chunk->chunk_size));
	str_replace_by_pooled_str(p, &(chunk->chunk_position));
	str_replace_by_pooled_str(p, &(chunk->chunk_hash));

	if(!get_compression_info_in_attr(path, &ge, comp_opt)){
		if(NULL != ge) {
			e = server_create_and_stat_error(conf, p, HTTP_CONFLICT,
				0, apr_pstrcat(p, "Failed to get chunk compression attributes: ", ge->message, NULL));
			g_clear_error(&ge);
		} else {
			e = server_create_and_stat_error(conf, p, HTTP_CONFLICT,
			                                0, "Failed to get chunk compression attributes: No error specified");
		}
		return e;
	}

	return NULL;
}
Beispiel #4
0
int
uncompress_chunk2(const gchar* path, gboolean preserve, gboolean keep_pending,
		GError ** error)
{
	GError *local_error = NULL;
	int status = 0;
	TRACE("Uncompressing [%s]", path);
	gchar *tmp_path = NULL;
	gulong tmp_len;
	gint64 total_read;
	guint8* data = NULL;
	gint64 bufsize, nb_read;
	gint64 current_read;
	struct stat *buf = NULL;
	struct compressed_chunk_s *cp_chunk = NULL;
	struct compression_ctx_s *comp_ctx = NULL;
	

	FILE *dst = NULL;

	/* Check chunk exists */
	buf = g_malloc0(sizeof(struct stat));	

	DEBUG("Checking chunk exists");

	if(stat(path, buf) == -1) {
		GSETERROR (error, "stat() failed, chunk not found\n");
		goto end;
	}
	DEBUG("File [%s] found", path);
	
	GHashTable *compress_opt = NULL;
	compress_opt = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free);

	if(!get_compression_info_in_attr(path, error, &compress_opt)) {
		GSETERROR(error, "Failed to get compression info in attr, chunk may be not compressed");
		goto end;
	}
	
	gchar * compression = NULL;
	compression = (gchar*) g_hash_table_lookup(compress_opt, NS_COMPRESSION_OPTION);
	
	if (compression != NULL && g_ascii_strncasecmp(compression, NS_COMPRESSION_ON, strlen(compression)) != 0) {
		GSETERROR(error, "Chunk not compressed, cannot nothing to do");
		goto end;
	}

	/* init compression method according to algo choice */
	comp_ctx = g_malloc0(sizeof(struct compression_ctx_s));
	init_compression_ctx(comp_ctx, g_hash_table_lookup(compress_opt, NS_COMPRESS_ALGO_OPTION));
	cp_chunk = g_malloc0(sizeof(struct compressed_chunk_s));

	if (comp_ctx->chunk_initiator(cp_chunk, path) != 0) {
		GSETERROR(error, "Failed to init compressed chunk context");
		goto end;
	}
	

	DEBUG("Chunk check done");

	tmp_len = strlen(path) +sizeof(".pending");	
	tmp_path = g_malloc0(tmp_len);
	g_snprintf(tmp_path, tmp_len, "%s.pending", path);

	DEBUG("Checking chunk not busy");

	if(stat(tmp_path, buf) != -1) {
		DEBUG("Stats failed");
		GSETERROR (error, "stat() success on pending file, cannot process : busy chunk\n");
		goto end;
	}
	
	do {
	int fd;

	if((fd = open(tmp_path, O_WRONLY|O_CREAT|O_EXCL, 0644)) == -1) {
		GSETERROR(error, "Failed to create pending chunk file (%s)\n", strerror(errno));	
		goto end;
	}
	
	metautils_pclose(&fd);
	} while (0);

	if(!copy_fattr(path, tmp_path, error)) {
		GSETERROR(error, "Failed to copy extended attributes to destination file\n");
		goto end;
	}

	TRACE("xattr copied from src to dst");

	dst = fopen(tmp_path, "w");

	TRACE("Destination file opened");

	gint64 chunk_size;
	chunk_size = g_ascii_strtoll(cp_chunk->uncompressed_size, NULL, 10);

	total_read = 0;	

	DEBUG("Starting, total_read = %"G_GINT64_FORMAT", chunk_size = %"G_GINT64_FORMAT, total_read, chunk_size);

	while(total_read < chunk_size) {
		bufsize = MIN(DECOMPRESSION_MAX_BUFSIZE, (chunk_size - total_read));
		data = g_malloc0(bufsize);
		DEBUG("New buffer allocated sized %"G_GINT64_FORMAT" bytes", bufsize);
		nb_read = 0;
		current_read = 0;
		while(nb_read < bufsize) {
			current_read = comp_ctx->data_uncompressor(cp_chunk, 0, data + nb_read, bufsize - nb_read, &local_error);
			DEBUG("Currently read %"G_GINT64_FORMAT" bytes", current_read);
			if(current_read < 0) {
				if(local_error) {
					GSETERROR(error, "An error occured while decompressing chunk : %s", local_error->message);	
					g_clear_error(&local_error);
				} else
					GSETERROR(error, "An error occured while decompressing chunk\n"); 
				goto end;
			} else if (current_read == 0) {
				/* Premature end of file, will still write to pending */
				WARN("Read 0 bytes, original chunk may have been truncated");
				break;
			}
			nb_read += current_read;
		}
		TRACE("buffer filled");
		errno = 0;
		/* write buf to dst file */
		if(nb_read > 0 && fwrite(data, nb_read, 1, dst) != 1) {
			GSETERROR(error, "An error occured while writing data in destination file: %s",
					strerror(errno));
			goto end;
		}
		if (data) {
			g_free(data);
			data = NULL;
		}
		if (nb_read > 0)
			total_read += nb_read;
		else
			break;
	}

	if(!comp_ctx->integrity_checker(cp_chunk)) {
		GSETERROR(error, "Seems there is an error in decompression, invalid checksum\n");
		goto end;
	}

	status = 1;

end:
	if(dst) {
		if(fclose(dst) != 0)
			WARN("Failed to fclose destination file");
		dst = NULL;
	}
	
	if(status == 1) {
		if(preserve) {
			/* Need to set old file info in new file */
			TRACE("Updating Access / Modify / Change informations");
			struct utimbuf* ut = NULL;
			ut = g_malloc0(sizeof(struct utimbuf));
			ut->actime = buf->st_atime;
			ut->modtime = buf->st_mtime;
			if (0 > chown(tmp_path, buf->st_uid, buf->st_gid)) {
				GSETERROR(error, "chown error: (%d) %s", errno, strerror(errno));
				status = 0;
			}
			if(utime(tmp_path, ut) != 0) {
				GSETERROR(error, "Failed to set correct access time to new file");
				status = 0;
			}
			if(ut)
				g_free(ut);
			if(status == 1) {
				if(rename(tmp_path, path) != 0) {
					GSETERROR(error, "Failed to rename tmp file");
					status = 0;
				}
			} else if (keep_pending) {
				INFO("Temporary file kept: %s", tmp_path);
			} else {
				/* remove tmp file */
				DEBUG("Removing failed file");
				if(remove(tmp_path) != 0)
					WARN("Failed to remove tmp file [%s]", tmp_path);
			}
		} else {
			DEBUG("Renaming pending file\n");
			if(rename(tmp_path, path) != 0) {
				GSETERROR(error, "Failed to rename tmp file");
				status = 0;
			} 
		}
	} else if (keep_pending) {
		INFO("Temporary file kept: %s", tmp_path);
	} else {
		/* remove tmp file */
		DEBUG("Removing pending file\n");
		if(remove(tmp_path) != 0)
			WARN("Failed to remove tmp file [%s]", tmp_path);
	}

	if(compress_opt)
		g_hash_table_destroy(compress_opt);

	if(buf)
		g_free(buf);

	if(data)
		g_free(data);

	if(tmp_path)
		g_free(tmp_path);
	
	return status;
}