ontherocks
ontherocks

Reputation: 1999

Perl chmod files exceeding 260 character limit path length

I have enabled Windows 10 Long Paths following the instructions at https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation#enable-long-paths-in-windows-10-version-1607-and-later I did this so I can chmod files exceeding the 260 characters Windows max path length limit in perl.

my $ret = chmod(oct(0555), '<path_length_greater_than_260_characters>\somefile.txt');
print "$ret\n";

It fails to chmod, $ret is 0. What are my options?

Upvotes: 1

Views: 620

Answers (2)

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118148

For reasons @ikegami explained, you can use Win32::LongPath. From the module's synopsis:

use File::Spec::Functions;
use Win32::LongPath;
use utf8;
 
# make a really long path w/Unicode from around the world
$path = 'c:';
while (length ($path) < 5000) {
  $path = catdir ($path, 'ελληνικά-русский-日本語-한국-中國的-עִברִית-عربي');
  if (!testL ('e', $path)) {
    mkdirL ($path) or die "unable to create $path ($^E)";
  }
}
print 'ShortPath: ' . shortpathL ($path) . "\n";
 
# next, create a file in the path
$file = catfile ('more interesting characters فارسی-தமிழர்-​ພາສາ​ລາວ');
openL (\$FH, '>:encoding(UTF-8)', $file)
  or die ("unable to open $file ($^E)");
print $FH "writing some more Unicode characters\n";
print $FH "דאס שרייבט אַ שורה אין ייִדיש.\n";
close $FH;
 
# now undo everything
unlinkL ($file) or die "unable to delete file ($^E)";
while ($path =~ /[\/\\]/) {
  rmdirL ($path) or die "unable to remove $path ($^E)";
  $path =~ s#[/\\][^/\\]+$##;
}

As for chmod on Windows, note this caution from perlport:

(Win32) Only good for changing "owner" read-write access; "group" and "other" bits are meaningless.

For setting Windows specific file access permissions, see File Security and Access Rights and SetNamedSecurityInfo. I haven't used the module, but Win32::Security::NamedObject might be helpful here.

Upvotes: 0

ikegami
ikegami

Reputation: 386331

There are two versions of each function that accepts/returns a string, an A(NSI) version which accepts/returns a string encoded using the ANSI/Active Code Page, and a W(ide) version which accepts/returns a string a encoded using UTF-16le.

Perl uses the A version of functions.

The change you made only applies to some W functions.

These are the directory management functions that no longer have MAX_PATH restrictions if you opt-in to long path behavior: CreateDirectoryW, CreateDirectoryExW GetCurrentDirectoryW RemoveDirectoryW SetCurrentDirectoryW.

These are the file management functions that no longer have MAX_PATH restrictions if you opt-in to long path behavior: CopyFileW, CopyFile2, CopyFileExW, CreateFileW, CreateFile2, CreateHardLinkW, CreateSymbolicLinkW, DeleteFileW, FindFirstFileW, FindFirstFileExW, FindNextFileW, GetFileAttributesW, GetFileAttributesExW, SetFileAttributesW, GetFullPathNameW, GetLongPathNameW, MoveFileW, MoveFileExW, MoveFileWithProgressW, ReplaceFileW, SearchPathW, FindFirstFileNameW, FindNextFileNameW, FindFirstStreamW, FindNextStreamW, GetCompressedFileSizeW, GetFinalPathNameByHandleW.

You can use Win32::Unicode to access most of those. You could also access them using Win32::API or FFI::Platypus.


By the way, you can also get around the limit by prefixing the path with \\?\ (or replacing \\ with \\?\UNC\ for paths already starting with \\). For example, something of the form \\?\d:\dir\file would be limited to 32,767 characters instead of 260. This works even without enabling the feature mentioned in the OP. That said, this too only works with the W functions.

Upvotes: 2

Related Questions