11/* 
22 *  R : A Computer Language for Statistical Data Analysis 
33 *  file dounzip.c 
4-  *  first part Copyright (C) 2002-2023   The R Core Team 
4+  *  first part Copyright (C) 2002-2025   The R Core Team 
55 *  second part Copyright (C) 1998-2010 Gilles Vollant 
66 * 
77 *  This program is free software; you can redistribute it and/or modify 
3333#endif 
3434#include  <errno.h> 
3535#include  <stdlib.h> 
36+ #include  <string.h> 
3637
3738#ifdef  Win32 
3839#include  <io.h>  /* for mkdir */ 
@@ -149,17 +150,28 @@ extract_one(unzFile uf, const char *const dest, const char * const filename,
149150    R_fixslash (outname ); /* ensure path separator is / */ 
150151#endif 
151152    p  =  outname  +  strlen (outname ) -  1 ;
153+     bool  warned  =  FALSE;
152154    if  (* p  ==  '/' ) { /* Directories are stored with trailing slash */ 
153155	if  (!junk ) {
154156	    * p  =  '\0' ;
155157	    if  (!R_FileExists (outname )) {
156158		/* make parents as required: have already checked dest exists */ 
157159		pp  =  outname  +  strlen (dest ) +  1 ;
158160		while ((p  =  Rf_strchr (pp , '/' ))) {
159- 		    strcpy (dirs , outname );
160- 		    dirs [p  -  outname ] =  '\0' ;
161- 		    if  (!R_FileExists (dirs )) R_mkdir (dirs );
162- 		    pp  =  p  +  1 ;
161+ 		    if  (p  -  pp  ==  2  &&  !strncmp (pp , ".." , 2 )) {
162+ 			if  (!warned ) {
163+ 			    warning (
164+ 			      _ ("skipped \"../\" path component(s) in '%s'" ),
165+ 			      fn );
166+ 			    warned  =  true;
167+ 			}
168+ 			memmove (pp , p  +  1 , strlen (p  +  1 ) +  1 );
169+ 		    } else  {
170+ 			strcpy (dirs , outname );
171+ 			dirs [p  -  outname ] =  '\0' ;
172+ 			if  (!R_FileExists (dirs )) R_mkdir (dirs );
173+ 			pp  =  p  +  1 ;
174+ 		    }
163175		}
164176		err  =  R_mkdir (outname );
165177	    }
@@ -168,11 +180,21 @@ extract_one(unzFile uf, const char *const dest, const char * const filename,
168180	/* make parents as required: have already checked dest exists */ 
169181	pp  =  outname  +  strlen (dest ) +  1 ;
170182	while ((p  =  Rf_strchr (pp , '/' ))) {
171- 	    strcpy (dirs , outname );
172- 	    dirs [p  -  outname ] =  '\0' ;
173- 	    /* Rprintf("dirs is %s\n", dirs); */ 
174- 	    if  (!R_FileExists (dirs )) R_mkdir (dirs );
175- 	    pp  =  p  +  1 ;
183+ 	    if  (p  -  pp  ==  2  &&  !strncmp (pp , ".." , 2 )) {
184+ 		if  (!warned ) {
185+ 		    warning (
186+ 		      _ ("skipped \"../\" path component(s) in '%s'" ),
187+ 		      fn );
188+ 		    warned  =  true;
189+ 		}
190+ 		memmove (pp , p  +  1 , strlen (p  +  1 ) +  1 );
191+ 	    } else  {
192+ 		strcpy (dirs , outname );
193+ 		dirs [p  -  outname ] =  '\0' ;
194+ 		/* Rprintf("dirs is %s\n", dirs); */ 
195+ 		if  (!R_FileExists (dirs )) R_mkdir (dirs );
196+ 		pp  =  p  +  1 ;
197+ 	    }
176198	}
177199	/* Rprintf("extracting %s\n", outname); */ 
178200	if  (!overwrite  &&  R_FileExists (outname )) {
0 commit comments