[Israel.pm] Renaming folder using perl

Oron Peled oron at actcom.co.il
Tue May 5 13:02:53 PDT 2009


So many wrong assertions in so few paragraphs...

On 05.05.2009 sawyer x wrote:
> This seems like something that should fail regardless of the rename.
> It's insecure, can cause FS problems and doesn't make a lot of sense.

Insecure? FS problems?
Since these assertions are so far fetched, let's skip them and
continue with the real stuff.

> In UNIX (I'm not sure how it is with Windows), there is no
> "renaming" folders function. It doesn't exist.

Wrong, it's a system call. please RTFM:
   man 2 rename

> You "mv" stuff. That doesn't just rename it, it gives it a different
> inode and everything.

Wrong again. The mv(1) command calls rename(2). This means it's the same
inode (which means the same ownership/permissions/etc btw), only the
name changes.

The only exception to this is when you move something between different
file systems (e.g: separate partitions/disks). In this case the mv(1)
command tries to rename(2), fails with a specific errno and falls back
to copying and removing the original (which means it's a different inode).

This behavior can be easily verified even without going to the source code
simply by system call tracing:

 # Let's see what mv does
 strace -o output mv t.c /tmp           # My /tmp and /home are separate

Excerpt from output:
 ...
 rename("t.c", "/tmp/t.c")  = -1 EXDEV (Invalid cross-device link)
 ...
 open("t.c", O_RDONLY|O_LARGEFILE|O_NOFOLLOW) = 3
 ...
 open("/tmp/t.c", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0600) = 4
 ...
 read(3, "#include <stdio.h>\n#include <stdl"..., 524288) = 139
 write(4, "#include <stdio.h>\n#include <stdl"..., 139) = 139

> That means that - to the OS and FS - it's not the same folder. This
> detaches the script's environment, making it much easier to
> compromise. Beyond that, you can have serious errors trying to change
> or fetch environment variables. When running with FS functions, it
> usually calls environment variables or uses the environment in some
> way which a good point to target when trying to compromise the script.

Let's lower the science fiction factor, the only environment variable
that won't reflect reality is ... $ENV{PWD} (how surprising).

> There is no original "rename" function in UNIX. There is a "rename"
> utility Larry Wall wrote, that helps you change files.

I'm tired of repeating myself, let's run something instead...

1. A two-liner:

   #! /bin/sh
   mv $PWD $PWD/../t4
   /bin/pwd

2. But this is perl-il!

   #!/usr/bin/perl -w
   $cwd = readlink "/proc/self/cwd";
   rename("$cwd", "$cwd/../t4") or die "rename($cwd): $!";
   system "/bin/pwd";

Implementation notes:

 * Both scripts use absolute paths. Running mv . ../t4 won't work.
 * In the end I use /bin/pwd and not the shell's built in pwd.
   This is because the shell does not know the directory was moved
   under its feet.
 * As a bonus, you see an alternative (linux-only) way to get your
   current working directory "from the horse mouth" (the kernel).

> I think you better check modules that provide portability:

Good advice.

> My advice on your act is:
> - Run the script from outside

Good advice.

> - Do an atomic operation with rename so it wouldn't be a problem

Good, but rename(2) is atomic on any POSIX system.

Cheers,

-- 
Oron Peled                                 Voice: +972-4-8228492
oron at actcom.co.il                  http://www.actcom.co.il/~oron
"When you understand UNIX, you will understand the world.
When you understand NT....you will understand NT" - Richard Thieme



More information about the Perl mailing list