#include <stdio.h>
int main(int argc, char *argv[])
{
int err;
if(argc != 3) {
printf("Usage: mmv <origin file> <dest file>\n");
exit(1);
}
err = rename(argv[1], argv[2]);
if(err == 0)
printf("move %s -> %s.\n", argv[1], argv[2]);
else
perror("failed");
return 0;
}
it works if I (suppose the binary executable file after compile is
mmv)
mmv /tmp/log1 /tmp/file/log1
but if
mmv /tmp/log1 /home/user/log1
I got:
failed: Invalid cross-device link
so that means I can only use rename() to move files inside one
devices?
Thanks.
--
comp.lang.c.moderated - moderation address: cl...@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line. Sorry.
> err = rename(argv[1], argv[2]);
> I got:
> failed: Invalid cross-device link
>
> so that means I can only use rename() to move files inside one
> devices?
yeah, it says that on the label. (man 2 rename)
--
⚂⚃ 100% natural
That would appear to be the case with the implementation you are using.
The C Standard notes (in a footnote) that one of the many reasons that
rename() can fail is because the implementation would have to copy the
contents of the file to effectuate the renaming, which is exactly this
case.
--
Larry Jones
I wonder if you can refuse to inherit the world. -- Calvin
> #include <stdio.h>
>
> int main(int argc, char *argv[])
> {
> int err;
>
> if(argc != 3) {
> printf("Usage: mmv <origin file> <dest file>\n");
> exit(1);
> }
>
> err = rename(argv[1], argv[2]);
>
> if(err == 0)
> printf("move %s -> %s.\n", argv[1], argv[2]);
> else
> perror("failed");
>
> return 0;
> }
Please do /not/ exit with a status code indicating success (which
returning 0 from `main' does) if you program actually failed. It's
also good form to put your program name in the error message, along with
any information which you think a user might find handy in diagnosing
the problem -- e.g., in this case the fact that you were trying to
rename things, and what the filenames in question were.
(Not all systems actually put useful information in `errno' when things
like `rename' fail, though it's a plausible guess. Those systems simply
don' have a portable way of extracting error information, which blows
mightily.)
> mmv /tmp/log1 /home/user/log1
>
> I got:
> failed: Invalid cross-device link
>
> so that means I can only use rename() to move files inside one
> devices?
This here is, strictly, a system-specific failure mode, but I don't know
of many systems in which `rename' can move a file between physical
storage devices. The error message you quote suggests a Unix-based
system, and Unix certainly won't let you rename between separately
mounted filesystems. (Further discussion of Unix filesystem
peculiarities is off-topic in this group.)
-- [mdw]
>it works if I (suppose the binary executable file after compile is
>mmv)
>mmv /tmp/log1 /tmp/file/log1
>
>but if
>mmv /tmp/log1 /home/user/log1
>
>I got:
>failed: Invalid cross-device link
>
>so that means I can only use rename() to move files inside one
>devices?
This is system-dependent but on UNIX systems rename() doesn't work
across filesystems (not "one device" - if your hard disk is partitioned
into several filesystems, you can't rename() a file from one
filesystem to another, even though you may think they are on the
same device). rename() under POSIX provides a guarantee of being
atomic (if the target existed before the rename(), it will exist
as the old or new file always. You won't end up with a timing
window where the file doesn't exist at all.) and having to copy a
terabyte file and still stay atomic is a problem.
The "mv" command in UNIX falls back to a file copy if rename() gets
a cross-device link error. There are also a bunch of other errors
possible related to file permissions and perhaps renaming the file
on top of itself.
It wouldn't surprise me if there was some system where rename()
will not work unless the source and destination are in the same
directory. CP/M qualifies but it cheats by not allowing a hierarchical
directory structure at all, having only one directory per filesystem.
Obviously the rename function is not the same as the mv unix command
you are thinking of.
The purpose of rename is to change a file's name (in place), not to
move it to another location with a possible name change.
Better: exit(EXIT_FAILURE) (which requires <stdlib.h>).
> }
>
> err = rename(argv[1], argv[2]);
>
> if(err == 0)
> printf("move %s -> %s.\n", argv[1], argv[2]);
> else
> perror("failed");
>
> return 0;
> }
>
> it works if I (suppose the binary executable file after compile is
> mmv)
> mmv /tmp/log1 /tmp/file/log1
>
> but if
> mmv /tmp/log1 /home/user/log1
>
> I got:
> failed: Invalid cross-device link
>
> so that means I can only use rename() to move files inside one
> devices?
That depends on your implementation. What the C standard has to say
about it is (C99 7.19.4.2):
Description
The rename function causes the file whose name is the string
pointed to by old to be henceforth known by the name given by
the string pointed to by new. The file named old is no longer
accessible by that name. If a file named by the string pointed
to by new exists prior to the call to the rename function,
the behavior is implementation-defined.
Returns
The rename function returns zero if the operation succeeds, nonzero
if it fails, in which case if the file existed previously it is
still known by its original name.
With a footnote:
Among the reasons the implementation may cause the rename function
to fail are that the file is open or that it is necessary to copy
its contents to effectuate its renaming.
Basically, rename() can fail for any reason the system feels like
imposing.
The C standard says nothing about how the file system is implemented.
In particular, it has no concept of multiple devices. But it appears
you're running into the last clause of the footnote.
<OT>
On any Unix-like system, rename() isn't going to be able to rename
a file across file systems, since that would require copying it.
(The mv command checks for this and copies the file if necessary.)
</OT>
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
IIRC later versions of CP/M had one dir PER USER per volume, but a
program could only access the current one. TOPS-10 similarly had one
dir per user (per filestructure) but you could only access one. I
think RSX-11 the same, but I saw that only secondhand. RT-11
definitely had one dir per volume, although in its later days it had a
'virtual disk' driver that allowed you to nest one volume-with-dir
within another, but you couldn't rename across them. CMS, at least
when I used it, had one dir per (normally?) virtual disk aka minidisc.
Probably only that last has any hope of serious use today.
Well, if you looked at how it was implemented, it wasn't really one
dir per user. Entries for users were mixed together. It had to
search through one user's files to find one for a different user.
The total number of directory slots limit (64 files for a single-density
8" floppy) counted against all users. Effectively, each file name
had a prefix consisting of the user number as one "character" (or
at least 4 bits of one). It would have been possible to do a "change
owner of file" command that simply changed 4 bits in a directory
entry (per file extent: CP/M had multiple directory entries for
longer files). Of course, the conventional CP/M system call
for "rename file" didn't include that function.
Also, I think there was some special rule that user 0 files could
be seen by anyone, eliminating the need for multiple copies of some
of the common non-built-in commands.
Of course, none of this was available through Standard C, or the
best approximation of it available at the time. I had BDS C, written
by Leor Zolman (I hope I recall the name correctly). No floating
point. The guys here could probably tear it apart for non-compliance.
Of course, it was written well before C90. Compiler was rather
slow, but what do you expect loading from floppies, and with only
64k (or less!) of memory?
I don't recall anyone making system-dependent functions for this
to go with the new OS system calls to handle it. However, there
were general functions available in most C implementations to call
the OS loading up certain registers with values you need, so defining
one could in many cases be done with a one-line macro.
Of course, there was no real security. You could read the raw
directory if you stepped outside the standard system calls. And
changing users was trivial. You could also blow away most of the
OS and do your own thing, then to be nice exit by doing a "cold"
boot.
>TOPS-10 similarly had one
>dir per user (per filestructure) but you could only access one. I
>think RSX-11 the same, but I saw that only secondhand. RT-11
>definitely had one dir per volume, although in its later days it had a
>'virtual disk' driver that allowed you to nest one volume-with-dir
>within another, but you couldn't rename across them. CMS, at least
>when I used it, had one dir per (normally?) virtual disk aka minidisc.
I suspect these had better user security to the point that it wasn't
possible for one user to impersonate another by accident by sneezing
in the wrong direction (or small buffer overflow). You had to put
a little effort into it, like looking at the sticky on the guy's
terminal.