>>Any thoughts on which is best if I want to rename AND move a file when
>>I know I'll be renaming cross-device?
>I'd use mv, rather than copying it myself. mv normally mmap's the input
>file, which is faster than read(). You could, of course, do that yourself,
>but all it saves is a fork()/exec(), which will be small compared to the
>move.
If speed is so critical that you want to use an mmap() solution, here
is a possible code outline. I wrote this program as an excuse to
learn mmap() so let me know if there's something wrong with it.
/*** begin prog ***/
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h> /* for fstat() */
#include <sys/mman.h> /* for mmap() */
#include <fcntl.h> /* for open() */
#include <unistd.h> /* for write() */
/*
* Move a file via mmap(). (Usefull for moving a file across
* filesystems.) Abort() is currently called if any error occurs.
*/
void move(const char *oldName, const char *newName)
{
int oFd, nFd;
int ret;
int mask;
struct stat st;
caddr_t nAddr, oAddr;
/*
* Open and map the old file name
*/
oFd = open(oldName, O_RDONLY);
assert( oFd > 0 );
/* get the size and protections for the old name */
ret = fstat(oFd, &st);
assert( ret == 0 );
/* map old. MAP_SHARED would behave the same as MAP_PRIVATE here */
oAddr = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, oFd, 0);
assert( oAddr != (caddr_t)-1 );
/* we don't need the descriptor once the file is mapped */
ret = close( oFd );
assert( ret == 0 );
/*
* Open and map the new file name. Keep old protections. According to
* the manpage we should be able to open this file with O_WRONLY as
* long as it's mapped with PROT_WRITE, but mmap() fails unless the
* file is opened with both read and write privs here. Explanations??
*/
mask = umask(0);
nFd = open(newName, O_CREAT | O_TRUNC | O_RDWR, st.st_mode);
assert( nFd > 0 );
umask(mask);
/* extend the new file name as mmap() won't do it for us */
ret = lseek(nFd, st.st_size - 1, SEEK_SET);
assert( ret != -1 );
ret = write(nFd, "", 1);
assert( ret == 1 );
/* map the new file */
nAddr = mmap(0, st.st_size, PROT_WRITE, MAP_SHARED, nFd, 0);
assert( nAddr != (caddr_t)-1 );
/* close descriptor */
ret = close( nFd );
assert( ret == 0 );
/* Copy the data over */
memcpy(nAddr, oAddr, st.st_size);
/* unmap both files */
ret = munmap(oAddr, st.st_size);
assert( ret == 0 );
ret = munmap(nAddr, st.st_size);
assert( ret == 0 );
/* unlink the old file name */
ret = remove( oldName );
assert( ret == 0 );
Quote:}
/*
* Usage: a.out <old path> <new path>
*/
int main(int argc, char *argv[])
{
assert( argc == 3 );
move(argv[1], argv[2]);
return 0;
Quote:}
/*** end prog ***/