qcom_msm8916_64_android5.0/sources/twrp/bootable/recovery/libtar/block.c
int
th_read(TAR *t)
{
	int i, j;
	size_t sz;
	char *ptr;

#ifdef DEBUG
	printf("==> th_read(t=0x%lx)\n", t);
#endif

	if (t->th_buf.gnu_longname != NULL)
		free(t->th_buf.gnu_longname);
	if (t->th_buf.gnu_longlink != NULL)
		free(t->th_buf.gnu_longlink);
#ifdef HAVE_SELINUX
	if (t->th_buf.selinux_context != NULL)
		free(t->th_buf.selinux_context);
#endif

	memset(&(t->th_buf), 0, sizeof(struct tar_header));

	i = th_read_internal(t);
	if (i == 0)
		return 1;
	else if (i != T_BLOCKSIZE)
	{
		if (i != -1)
			errno = EINVAL;
		return -1;
	}

	/* check for GNU long link extention */
	if (TH_ISLONGLINK(t))
	{
		sz = th_get_size(t);
		j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
#ifdef DEBUG
		printf("    th_read(): GNU long linkname detected "
		       "(%ld bytes, %d blocks)\n", sz, j);
#endif
		t->th_buf.gnu_longlink = (char *)malloc(j * T_BLOCKSIZE);
		if (t->th_buf.gnu_longlink == NULL)
			return -1;

		for (ptr = t->th_buf.gnu_longlink; j > 0;
		     j--, ptr += T_BLOCKSIZE)
		{
#ifdef DEBUG
			printf("    th_read(): reading long linkname "
			       "(%d blocks left, ptr == %ld)\n", j, ptr);
#endif
			i = tar_block_read(t, ptr);
			if (i != T_BLOCKSIZE)
			{
				if (i != -1)
					errno = EINVAL;
				return -1;
			}
#ifdef DEBUG
			printf("    th_read(): read block == \"%s\"\n", ptr);
#endif
		}
#ifdef DEBUG
		printf("    th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
		       t->th_buf.gnu_longlink);
#endif

		i = th_read_internal(t);
		if (i != T_BLOCKSIZE)
		{
			if (i != -1)
				errno = EINVAL;
			return -1;
		}
	}

	/* check for GNU long name extention */
	if (TH_ISLONGNAME(t))
	{
		sz = th_get_size(t);
		j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
#ifdef DEBUG
		printf("    th_read(): GNU long filename detected "
		       "(%ld bytes, %d blocks)\n", sz, j);
#endif
		t->th_buf.gnu_longname = (char *)malloc(j * T_BLOCKSIZE);
		if (t->th_buf.gnu_longname == NULL)
			return -1;

		for (ptr = t->th_buf.gnu_longname; j > 0;
		     j--, ptr += T_BLOCKSIZE)
		{
#ifdef DEBUG
			printf("    th_read(): reading long filename "
			       "(%d blocks left, ptr == %ld)\n", j, ptr);
#endif
			i = tar_block_read(t, ptr);
			if (i != T_BLOCKSIZE)
			{
				if (i != -1)
					errno = EINVAL;
				return -1;
			}
#ifdef DEBUG
			printf("    th_read(): read block == \"%s\"\n", ptr);
#endif
		}
#ifdef DEBUG
		printf("    th_read(): t->th_buf.gnu_longname == \"%s\"\n",
		       t->th_buf.gnu_longname);
#endif

		i = th_read_internal(t);
		if (i != T_BLOCKSIZE)
		{
			if (i != -1)
				errno = EINVAL;
			return -1;
		}
	}

#ifdef HAVE_SELINUX
	if(TH_ISEXTHEADER(t))
	{
		sz = th_get_size(t);

		if(sz >= T_BLOCKSIZE) // Not supported
		{
#ifdef DEBUG
			printf("    th_read(): Extended header is too long!\n");
#endif
		}
		else
		{
			char buf[T_BLOCKSIZE];
			i = tar_block_read(t, buf);
			if (i != T_BLOCKSIZE)
			{
				if (i != -1)
					errno = EINVAL;
				return -1;
			}

			// To be sure
			buf[T_BLOCKSIZE-1] = 0;

			int len = strlen(buf);
			char *start = strstr(buf, SELINUX_TAG);
			if(start && start+SELINUX_TAG_LEN < buf+len)
			{
				start += SELINUX_TAG_LEN;
				char *end = strchr(start, '\n');
				if(end)
				{
					t->th_buf.selinux_context = strndup(start, end-start);
#ifdef DEBUG
					printf("    th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context);
#endif
				}
			}
		}

		i = th_read_internal(t);
		if (i != T_BLOCKSIZE)
		{
			if (i != -1)
				errno = EINVAL;
			return -1;
		}
	}
#endif

#if 0
	/*
	** work-around for old archive files with broken typeflag fields
	** NOTE: I fixed this in the TH_IS*() macros instead
	*/

	/*
	** (directories are signified with a trailing '/')
	*/
	if (t->th_buf.typeflag == AREGTYPE
	    && t->th_buf.name[strlen(t->th_buf.name) - 1] == '/')
		t->th_buf.typeflag = DIRTYPE;

	/*
	** fallback to using mode bits
	*/
	if (t->th_buf.typeflag == AREGTYPE)
	{
		mode = (mode_t)oct_to_int(t->th_buf.mode);

		if (S_ISREG(mode))
			t->th_buf.typeflag = REGTYPE;
		else if (S_ISDIR(mode))
			t->th_buf.typeflag = DIRTYPE;
		else if (S_ISFIFO(mode))
			t->th_buf.typeflag = FIFOTYPE;
		else if (S_ISCHR(mode))
			t->th_buf.typeflag = CHRTYPE;
		else if (S_ISBLK(mode))
			t->th_buf.typeflag = BLKTYPE;
		else if (S_ISLNK(mode))
			t->th_buf.typeflag = SYMTYPE;
	}
#endif

	return 0;
}
/* wrapper function for th_read_internal() to handle GNU extensions */
wrapper function for th_read_internal() to handle GNU extensions
wrapper function for th_read_internal () to handle GNU extensions
int
th_read(TAR *t)
{
	int i, j;
	size_t sz;
	char *ptr;
#ifdef DEBUG
	printf("==> th_read(t=0x%lx)\n", t);
#endif
	if (t->th_buf.gnu_longname != NULL)
		free(t->th_buf.gnu_longname);
	if (t->th_buf.gnu_longlink != NULL)
		free(t->th_buf.gnu_longlink);
#ifdef HAVE_SELINUX
	if (t->th_buf.selinux_context != NULL)
		free(t->th_buf.selinux_context);
#endif
	memset(&(t->th_buf), 0, sizeof(struct tar_header));
	i = th_read_internal(t);
	if (i == 0)
		return 1;
	else if (i != T_BLOCKSIZE)
	{
		if (i != -1)
			errno = EINVAL;
		return -1;
	}
	if (TH_ISLONGLINK(t))
	{
		sz = th_get_size(t);
		j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
#ifdef DEBUG
		printf("    th_read(): GNU long linkname detected "
		       "(%ld bytes, %d blocks)\n", sz, j);
#endif
		t->th_buf.gnu_longlink = (char *)malloc(j * T_BLOCKSIZE);
		if (t->th_buf.gnu_longlink == NULL)
			return -1;
		for (ptr = t->th_buf.gnu_longlink; j > 0;
		     j--, ptr += T_BLOCKSIZE)
		{
#ifdef DEBUG
			printf("    th_read(): reading long linkname "
			       "(%d blocks left, ptr == %ld)\n", j, ptr);
#endif
			i = tar_block_read(t, ptr);
			if (i != T_BLOCKSIZE)
			{
				if (i != -1)
					errno = EINVAL;
				return -1;
			}
#ifdef DEBUG
			printf("    th_read(): read block == \"%s\"\n", ptr);
#endif
		}
#ifdef DEBUG
		printf("    th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
		       t->th_buf.gnu_longlink);
#endif
		i = th_read_internal(t);
		if (i != T_BLOCKSIZE)
		{
			if (i != -1)
				errno = EINVAL;
			return -1;
		}
	}
	if (TH_ISLONGNAME(t))
	{
		sz = th_get_size(t);
		j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
#ifdef DEBUG
		printf("    th_read(): GNU long filename detected "
		       "(%ld bytes, %d blocks)\n", sz, j);
#endif
		t->th_buf.gnu_longname = (char *)malloc(j * T_BLOCKSIZE);
		if (t->th_buf.gnu_longname == NULL)
			return -1;
		for (ptr = t->th_buf.gnu_longname; j > 0;
		     j--, ptr += T_BLOCKSIZE)
		{
#ifdef DEBUG
			printf("    th_read(): reading long filename "
			       "(%d blocks left, ptr == %ld)\n", j, ptr);
#endif
			i = tar_block_read(t, ptr);
			if (i != T_BLOCKSIZE)
			{
				if (i != -1)
					errno = EINVAL;
				return -1;
			}
#ifdef DEBUG
			printf("    th_read(): read block == \"%s\"\n", ptr);
#endif
		}
#ifdef DEBUG
		printf("    th_read(): t->th_buf.gnu_longname == \"%s\"\n",
		       t->th_buf.gnu_longname);
#endif
		i = th_read_internal(t);
		if (i != T_BLOCKSIZE)
		{
			if (i != -1)
				errno = EINVAL;
			return -1;
		}
	}
#ifdef HAVE_SELINUX
	if(TH_ISEXTHEADER(t))
	{
		sz = th_get_size(t);
		if(sz >= T_BLOCKSIZE) 
		{
#ifdef DEBUG
			printf("    th_read(): Extended header is too long!\n");
#endif
		}
		else
		{
			char buf[T_BLOCKSIZE];
			i = tar_block_read(t, buf);
			if (i != T_BLOCKSIZE)
			{
				if (i != -1)
					errno = EINVAL;
				return -1;
			}
			buf[T_BLOCKSIZE-1] = 0;
			int len = strlen(buf);
			char *start = strstr(buf, SELINUX_TAG);
			if(start && start+SELINUX_TAG_LEN < buf+len)
			{
				start += SELINUX_TAG_LEN;
				char *end = strchr(start, '\n');
				if(end)
				{
					t->th_buf.selinux_context = strndup(start, end-start);
#ifdef DEBUG
					printf("    th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context);
#endif
				}
			}
		}
		i = th_read_internal(t);
		if (i != T_BLOCKSIZE)
		{
			if (i != -1)
				errno = EINVAL;
			return -1;
		}
	}
#endif
#if 0
	if (t->th_buf.typeflag == AREGTYPE
	    && t->th_buf.name[strlen(t->th_buf.name) - 1] == '/')
		t->th_buf.typeflag = DIRTYPE;
	if (t->th_buf.typeflag == AREGTYPE)
	{
		mode = (mode_t)oct_to_int(t->th_buf.mode);
		if (S_ISREG(mode))
			t->th_buf.typeflag = REGTYPE;
		else if (S_ISDIR(mode))
			t->th_buf.typeflag = DIRTYPE;
		else if (S_ISFIFO(mode))
			t->th_buf.typeflag = FIFOTYPE;
		else if (S_ISCHR(mode))
			t->th_buf.typeflag = CHRTYPE;
		else if (S_ISBLK(mode))
			t->th_buf.typeflag = BLKTYPE;
		else if (S_ISLNK(mode))
			t->th_buf.typeflag = SYMTYPE;
	}
#endif
	return 0;
}
int th_read ( TAR * t ) { int i , j ; size_t sz ; char * ptr ; #ifdef DEBUG printf ( " \n " , t ) ; #endif if ( t -> th_buf . gnu_longname != NULL ) free ( t -> th_buf . gnu_longname ) ; if ( t -> th_buf . gnu_longlink != NULL ) free ( t -> th_buf . gnu_longlink ) ; #ifdef HAVE_SELINUX if ( t -> th_buf . selinux_context != NULL ) free ( t -> th_buf . selinux_context ) ; #endif memset ( & ( t -> th_buf ) , 0 , sizeof ( struct tar_header ) ) ; i = th_read_internal ( t ) ; if ( i == 0 ) return 1 ; else if ( i != T_BLOCKSIZE ) { if ( i != -1 ) errno = EINVAL ; return -1 ; } if ( TH_ISLONGLINK ( t ) ) { sz = th_get_size ( t ) ; j = ( sz / T_BLOCKSIZE ) + ( sz % T_BLOCKSIZE ? 1 : 0 ) ; #ifdef DEBUG printf ( " " " \n " , sz , j ) ; #endif t -> th_buf . gnu_longlink = ( char * ) malloc ( j * T_BLOCKSIZE ) ; if ( t -> th_buf . gnu_longlink == NULL ) return -1 ; for ( ptr = t -> th_buf . gnu_longlink ; j > 0 ; j -- , ptr += T_BLOCKSIZE ) { #ifdef DEBUG printf ( " " " \n " , j , ptr ) ; #endif i = tar_block_read ( t , ptr ) ; if ( i != T_BLOCKSIZE ) { if ( i != -1 ) errno = EINVAL ; return -1 ; } #ifdef DEBUG printf ( " \" \" \n " , ptr ) ; #endif } #ifdef DEBUG printf ( " \" \" \n " , t -> th_buf . gnu_longlink ) ; #endif i = th_read_internal ( t ) ; if ( i != T_BLOCKSIZE ) { if ( i != -1 ) errno = EINVAL ; return -1 ; } } if ( TH_ISLONGNAME ( t ) ) { sz = th_get_size ( t ) ; j = ( sz / T_BLOCKSIZE ) + ( sz % T_BLOCKSIZE ? 1 : 0 ) ; #ifdef DEBUG printf ( " " " \n " , sz , j ) ; #endif t -> th_buf . gnu_longname = ( char * ) malloc ( j * T_BLOCKSIZE ) ; if ( t -> th_buf . gnu_longname == NULL ) return -1 ; for ( ptr = t -> th_buf . gnu_longname ; j > 0 ; j -- , ptr += T_BLOCKSIZE ) { #ifdef DEBUG printf ( " " " \n " , j , ptr ) ; #endif i = tar_block_read ( t , ptr ) ; if ( i != T_BLOCKSIZE ) { if ( i != -1 ) errno = EINVAL ; return -1 ; } #ifdef DEBUG printf ( " \" \" \n " , ptr ) ; #endif } #ifdef DEBUG printf ( " \" \" \n " , t -> th_buf . gnu_longname ) ; #endif i = th_read_internal ( t ) ; if ( i != T_BLOCKSIZE ) { if ( i != -1 ) errno = EINVAL ; return -1 ; } } #ifdef HAVE_SELINUX if ( TH_ISEXTHEADER ( t ) ) { sz = th_get_size ( t ) ; if ( sz >= T_BLOCKSIZE ) { #ifdef DEBUG printf ( " \n " ) ; #endif } else { char buf [ T_BLOCKSIZE ] ; i = tar_block_read ( t , buf ) ; if ( i != T_BLOCKSIZE ) { if ( i != -1 ) errno = EINVAL ; return -1 ; } buf [ T_BLOCKSIZE - 1 ] = 0 ; int len = strlen ( buf ) ; char * start = strstr ( buf , SELINUX_TAG ) ; if ( start && start + SELINUX_TAG_LEN < buf + len ) { start += SELINUX_TAG_LEN ; char * end = strchr ( start , ' \n ' ) ; if ( end ) { t -> th_buf . selinux_context = strndup ( start , end - start ) ; #ifdef DEBUG printf ( " \n " , t -> th_buf . selinux_context ) ; #endif } } } i = th_read_internal ( t ) ; if ( i != T_BLOCKSIZE ) { if ( i != -1 ) errno = EINVAL ; return -1 ; } } #endif #if 0 if ( t -> th_buf . typeflag == AREGTYPE && t -> th_buf . name [ strlen ( t -> th_buf . name ) - 1 ] == ' ' ) t -> th_buf . typeflag = DIRTYPE ; if ( t -> th_buf . typeflag == AREGTYPE ) { mode = ( mode_t ) oct_to_int ( t -> th_buf . mode ) ; if ( S_ISREG ( mode ) ) t -> th_buf . typeflag = REGTYPE ; else if ( S_ISDIR ( mode ) ) t -> th_buf . typeflag = DIRTYPE ; else if ( S_ISFIFO ( mode ) ) t -> th_buf . typeflag = FIFOTYPE ; else if ( S_ISCHR ( mode ) ) t -> th_buf . typeflag = CHRTYPE ; else if ( S_ISBLK ( mode ) ) t -> th_buf . typeflag = BLKTYPE ; else if ( S_ISLNK ( mode ) ) t -> th_buf . typeflag = SYMTYPE ; } #endif return 0 ; }
wrapper function for th_read_internal() to handle GNU extensions
wrapper function for th_read_internal () to handle GNU extensions
/* check for GNU long link extention */ /* check for GNU long name extention */ // Not supported // To be sure /*
	** work-around for old archive files with broken typeflag fields
	** NOTE: I fixed this in the TH_IS*() macros instead
	*/ /*
	** (directories are signified with a trailing '/')
	*/ /*
	** fallback to using mode bits
	*/