Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: getAbsolutePathname() to prepend \\?\ for too long pathnames? #102

Open
HenrikBengtsson opened this issue Oct 16, 2019 · 1 comment

Comments

@HenrikBengtsson
Copy link
Owner

On Windows, there's a 260 character limit on the canonical pathname, cf. https://www.aroma-project.org/howtos/UseLongFilenamesOnWindows/ and https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation.

However, as https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17631 suggests, it is possible to work around this by using a \\?\ on the absolute path, which then supports 32,767 characters.

Should getAbsolutePathname() automatically prepend \\?\ for long path/pathnames on Windows?

@HenrikBengtsson
Copy link
Owner Author

Hmm... although better than 259 characters, there seems to be an upper limit of 298 even when using the \\?\ trick.

Example:

long_pathname <- function(n=259L, path=tempdir(), unc=FALSE) {
  fsep <- if (.Platform$OS.type == "windows") "\\" else "/"
  filename <- paste(rep(letters, length.out=n-1L-nchar(path)), collapse="")
  normalizePath(file.path(path, filename, fsep=fsep), mustWork=FALSE)
}

unc <- function(pathname) {
  paste0("\\\\?\\", pathname)
}

First of all, here is the regular limitation:

pn <- long_pathname(n=259)
cat("hello", file=pn)
readLines(pn, warn=FALSE)
## [1] "hello"

pn <- long_pathname(n=260)
cat("hello", file=pn)
## Error in file(file, ifelse(append, "a", "w")) : 
##   cannot open the connection
## In addition: Warning message:
## In file(file, ifelse(append, "a", "w")) :
##   cannot open file 'C:\Users\hb\AppData\Local\Temp\RtmpszjQBA\abc...j': No such file or directory

This can be somewhat circumvented with \\?\;

pn <- unc(long_pathname(n=259))
cat("hello", file=pn)
readLines(pn, warn=FALSE)
## [1] "hello"

pn <- unc(long_pathname(n=260))
cat("hello", file=pn)
readLines(pn, warn=FALSE)
## [1] "hello"

pn <- unc(long_pathname(n=297))
cat("hello", file=pn)
readLines(pn, warn=FALSE)
## [1] "hello"

but even this will hit an upper limit;

pn <- unc(long_pathname(n=298))
cat("hello", file=pn)
## Error in file(file, ifelse(append, "a", "w")) : 
##   cannot open the connection
## In addition: Warning message:
## In file(file, ifelse(append, "a", "w")) :
##   cannot open file '\\?\C:\Users\hb\AppData\Local\Temp\RtmpszjQBA\abc...v': Invalid argument

BTW, note also that file.exists() doesn't work with UNC pathnames, e.g.

> pn <- unc(tempfile())
> pn
[1] "\\\\?\\C:\\Users\\hb\\AppData\\Local\\Temp\\RtmpszjQBA\\file1da4bd969df"
> cat("hello", file=pn)
> readLines(pn, warn=FALSE)
[1] "hello"
> file.exists(pn)
[1] FALSE

Session info

> sessionInfo()
R version 3.6.1 Patched (2019-09-11 r77179)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 18362)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252    LC_MONETARY=English_United States.1252 LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] compiler_3.6.1 tools_3.6.1 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant