@@ -150,7 +150,7 @@ untar2 <- function(tarfile, files = NULL, list = FALSE, exdir = ".",
150150            if  (grepl(" ^[a-zA-Z]:" path )) {
151151                drv  <-  sub(" ^([a-zA-Z]:).*" " \\ 1" path )
152152                warning(sprintf(" removing drive '%s'" drv ))
153-                 path  <-  sub(" ^([a-zA-Z]:).* " " " path )
153+                 path  <-  sub(" ^([a-zA-Z]:)" " " path )
154154            }
155155            path  <-  gsub(" \\\\ " " /" path )
156156        }
@@ -164,19 +164,29 @@ untar2 <- function(tarfile, files = NULL, list = FALSE, exdir = ".",
164164        if  (" .." %in%  parts )
165165            stop(" path contains '..'" 
166166        if  (length(parts ) ==  0 )
167-             stop(" path is empty" 
168-         do.call(file.path , as.list(parts ))
167+             return (" ." 
168+         p  <-  " " 
169+         for (el  in  parts ) {
170+             if  (nzchar(p ))
171+                 p  <-  file.path(p , el )
172+             else 
173+                 p  <-  el 
174+             if (isTRUE(nzchar(Sys.readlink(p ), keepNA = TRUE )))
175+                 stop(" cannot extract through symlink" 
176+         }
177+         p 
169178    }
170179    mydir.create  <-  function (path , ... , .checkPath  =  TRUE ) {
171180        # # for Windows' sake
172181        path  <-  sub(" [\\ /]$" " " path )
173182        # # address path traversal vulnerability  (PR17853):
174183        if  (.checkPath )
175184            path  <-  checkPath(path )
176-         if (dir.exists(path )) return ()
177-         if (! dir.create(path , showWarnings  =  TRUE , recursive  =  TRUE , ... ))
178-            stop(gettextf(" failed to create directory %s" path )),
179-                 domain  =  NA )
185+         if (! dir.exists(path ) && 
186+            ! dir.create(path , showWarnings  =  TRUE , recursive  =  TRUE , ... ))
187+             stop(gettextf(" failed to create directory %s" path )),
188+                  domain  =  NA )
189+         path 
180190    }
181191
182192    warn1  <-  character ()
@@ -250,8 +260,10 @@ untar2 <- function(tarfile, files = NULL, list = FALSE, exdir = ".",
250260            dothis  <-  ! list 
251261            if (dothis  &&  length(files )) dothis  <-  name  %in%  files 
252262            if (dothis ) {
253-                 mydir.create(dirname(name ))
254-                 out  <-  file(name , " wb" 
263+                 dname  <-  mydir.create(dirname(name ))
264+                 fname  <-  file.path(dname , basename(name ))
265+                 unlink(fname )
266+                 out  <-  file(fname , " wb" 
255267            }
256268            for (i  in  seq_len(ceiling(size / 512L ))) {
257269                block  <-  readBin(con , " raw" n  =  512L )
@@ -264,8 +276,8 @@ untar2 <- function(tarfile, files = NULL, list = FALSE, exdir = ".",
264276            }
265277            if (dothis ) {
266278                close(out )
267-                 Sys.chmod(name , mode , FALSE ) #  override umask
268-                 if (restore_times ) Sys.setFileTime(name , ft )
279+                 Sys.chmod(fname , mode , FALSE ) #  override umask
280+                 if (restore_times ) Sys.setFileTime(fname , ft )
269281            }
270282        } else  if (ctype  %in%  c(" 1" " 2" 
271283            # # hard and symbolic links
@@ -276,27 +288,43 @@ untar2 <- function(tarfile, files = NULL, list = FALSE, exdir = ".",
276288            if (! is.null(llink )) {name2  <-  llink ; llink  <-  NULL }
277289            if (! list ) {
278290                if (ctype  ==  " 1" 
279-                     mydir.create(dirname(name ))
280-                     unlink(name )
291+                     dname  <-  mydir.create(dirname(name ))
292+                     fname  <-  file.path(dname , basename(name ))
293+                     unlink(fname )
281294                    if  (! file.link(name2 , name )) { #  will give a warning
282295                        # # link failed, so try a file copy
283-                         if (file.copy(name2 , name ))
284-                               warn1  <-  c(warn1 , " restoring hard link as a file copy" 
296+                         if (file.copy(name2 , fname ))
297+                             warn1  <-  c(warn1 , " restoring hard link as a file copy" 
285298                        else 
286-                             warning(gettextf(" failed to copy %s to %s" name2 ), sQuote(name )), domain  =  NA )
299+                             warning(gettextf(" failed to copy %s to %s" name2 ), sQuote(fname )), domain  =  NA )
287300                    }
288301                } else  {
289302                    if (.Platform $ OS.type  ==  " windows" 
290-                         # # this will not work for links to dirs
291-                         mydir.create(dirname(name ))
292-                         from  <-  file.path(dirname(name ), name2 )
293-                         if  (! file.copy(from , name ))
294-                             warning(gettextf(" failed to copy %s to %s" from ), sQuote(name )), domain  =  NA )
295-                         else 
296-                             warn1  <-  c(warn1 , " restoring symbolic link as a file copy" 
303+                         dname  <-  mydir.create(dirname(name ))
304+                         fname  <-  file.path(dname , basename(name ))
305+                         unlink(fname )
306+                         from  <-  file.path(dname , name2 )
307+                         if  (dir.exists(from )) {
308+                             tmpd  <-  tempfile(pattern  =  " untar_" tmpdir  =  dname )
309+                             dir.create(tmpd )
310+                             if  (! file.copy(from , tmpd , recursive  =  TRUE ) || 
311+                                 ! file.rename(file.path(tmpd , basename(name2 )), fname ) || 
312+                                 ! unlink(tmpd , recursive  =  TRUE ))
313+                                 warning(gettextf(" failed to copy %s to %s" from ), sQuote(fname )), domain  =  NA )
314+                             else 
315+                                 warn1  <-  c(warn1 , " restoring symbolic link as a file copy" 
316+                         } else  if  (! file.exists(from )) {
317+                             warning(gettextf(" cannot restore symbolic link from %s to %s as a file copy, because the source doesn't exist; try extracting again?" 
318+                                              sQuote(from ), sQuote(fname )), domain  =  NA )
319+                         } else  {
320+                             if  (! file.copy(from , fname ))
321+                                 warning(gettextf(" failed to copy %s to %s" from ), sQuote(fname )), domain  =  NA )
322+                             else 
323+                                 warn1  <-  c(warn1 , " restoring symbolic link as a file copy" 
324+                        }
297325                   } else  {
298-                        mydir.create(dirname(name ))
299-                        od0  <-  setwd(dirname( name ) )
326+                        dname   <-   mydir.create(dirname(name ))
327+                        od0  <-  setwd(dname )
300328                       nm  <-  basename(name )
301329                       unlink(nm )
302330                       if (! file.symlink(name2 , nm )) { #  will give a warning
@@ -317,9 +345,12 @@ untar2 <- function(tarfile, files = NULL, list = FALSE, exdir = ".",
317345            # # directory
318346            contents  <-  c(contents , name )
319347            if (! list ) {
320-                 mydir.create(name )
321-                 Sys.chmod(name , mode , TRUE ) #  FIXME: check result
322-                 # # no point is setting time, as dir will be populated later.
348+                 dname  <-  mydir.create(dirname(name ))
349+                 fname  <-  file.path(dname , basename(name ))
350+                 unlink(fname )
351+                 if (! dir.exists(fname ) &&  ! dir.create(fname , mode  =  mode ))
352+                     stop(gettextf(" failed to create directory %s" fname )))
353+                 # # no point in setting time, as dir will be populated later.
323354            }
324355        } else  if (ctype  ==  " 6" 
325356            # # 6 is a fifo
0 commit comments