Copy non-directory over directory and vv - linux

How can I avoid the following types of errors, and force the
operation to occur?:
/bin/cp: cannot overwrite directory `./foo' with non-directory
/bin/cp: cannot overwrite non-directory `./usr/share/doc' with directory `/usr/share/doc'
To backup a partition, I want to copy a new version of a
directory onto an old version, to make them identical, with the
command:
/bin/cp -xau --remove-destination / .
The destination directory is in a ZFS filesystem that is being
regularly snapshotted. Relatively few files (or directories)
change.
That is why I don't want to just delete the whole
destination directory -- that will make the snapshot needlessly
large.
This is in Linux.
Thanks.

The following seems to work better (but not perfectly):
tar cf /mytmp/root.tar --one-file-system /
cd /backup/root
tar xvf /mytmp/root.tar --keep-newer-files
Note that this works better when /mytmp is not in the root
partition. :-)
The output from the 2nd tar command was 700K lines. I captured
it inside an emacs buffer and searched it for error messages.
There were two problems with not wanting to replace directories
with links, which I handled manually.

Related

Extract tar archive excluding a specific folder and its contents

With PHP I am using exec("tar -xf archive.tar -C /home/user/target/folder") to extract the contents of a specific archive (archive.tar) into the target directory (/home/user/target/folder), so that all existing contents of the target directory will be overwritten by the new ones that are contained in the archive.
It works fine and all files in the target directory are being overwritten after extract, but there is one directory in the archive that I would like to omit (from extracting and thus overwriting the existing one in the target folder)...
For example, the archive.tar contains:
folderA/
folderB/
folderC/
folderD/
fileA.php
fileB.php
fileC.xml
How could I extract (and overwrite) all except (for example) folderC/? In other words, I want folderC and its contents to remain intact in the user's directory and not be overwritten by the one contained in the tar archive.
Any suggestions?
(Tar on the hosting server is GNU version 1.23.)
You can use '--exclude' to omit a folder:
tar -xf archive.tar -C /home/user/target/folder" --exclude="folderC"
There is the --exclude PATTERN option in the tar tool.
Check: tar on linuxcommand.org
To be on the safe side, you could remove all write permissions from the folder. For example:
$ chmod 000 folderC/
An then do a normal tar extract (as regular user). You'll get some error messages on console, but your folder will remain untouched.... At the end of the tar, change back your folder original permissions. For example:
$ chmod 775 folderC/
Of course '--exclude' tar option is the right solution to this particular problem, but, if you are not completely 100% sure about a command syntax, and yor're handling critical data, my solution puts you on the safe side :-).
Write --exclude='./folder' at the beginning of the tar command.
In your case that is,
exec("tar -x --exclude='./C' -f archive.tar -C /home/user/target/folder")

How does the 'mv' command work?

I used the command mv to move files from directory /a/b to directory /v/c. I wanted the whole 'b' directory to be moved to the path /v/c.
Now while running this command- mv /a/b /v/c I interrupted it in middle where the source had a large amount of data. Later I deleted directory 'c' since I thought it had partial files.
Now my question is will the directory 'b' contain all the original files along with the files that where moved to path /v/c? Or did I lose files by deleting the directory 'c'?
mv across filesystems will:
create the destination directory
for each file: copy and remove original
remove origin directory
Thus, if you interrupt it, some of the files will have been moved but not all. A mv of a directory within the same filesystem is atomic as it's just re-linking the directory's inode to a new location.
At one time, mv could only do the latter.
I believe it depends on if the source and destination directories were on the same file system or different file systems. If they were on the same file system then a "move" just changes the path information for each file. But if they're on different file systems the "move" command will copy one file at a time, and subsequently delete it on the source.
So, in your scenario if the source and destination were on separate file systems then yes, you just lost files if you interrupted mv and then deleted "c".

Does `tar /home/user/file` change the /home owner to root?

I'm trying to back up some key files and directories of a machine, as root, including some of the /home data, hand-picking some files to reduce the tarball size. Everything is OK for the most part, since most files are owned by root anyway, but say I just try this:
# tar -cf backup.tar /home/user/file
When I restore the contents, /home/user/file is as expected owned by user, but /home/user is owned by root. I tried, however,
# tar -cf backup.tar /home
and in this case all /home owners are preserved. (Note that I don't need the -p flag as I'm root. Still I tried it...)
Is this normal behavior? If so, is there a way to hand-pick regular-user files to back up while keeping the /home ownership information? My goal is to simply untar everything from /.
Thanks!
To properly set permissions for directories, the tarball needs to contain entries for those directories, so you need to add them to the tarball.
When you create a tarball that only contains /home/user/file, and not /home/user, there is then no information about the permissions of /home/user in the tarball, so tar doesn't know what to do. It automatically creates the directories but has no permissions, owner or group to give them, so they get the defaults.
You could add the directories as well:
# tar -cf backup.tar --no-recursion /home/user /home/user/file
But this may not make things any simpler for you. Note the --no-recursion - that tells tar to not add everthing under a directory, just the directory itself. If you wanted to actually also add direcory trees, you would have to use find(1) to pass it every file under that directory manually. That would get ugly quickly.
Keep in mind that we are talking about backing up and restoring particular files. If you were to ever restore, you would presumably also create the unix accounts to restore to if they weren't there already. So there would be no need to set permissions on home directories, at least. The same cannot be said of subdirectories of those though.

How to update tar (NOT append)

I want to update an existing tar file with newer files.
At GNU, I read:
4.2.3 Updating an Archive
In the previous section, you learned how to use ‘--append’ to add a
file to an existing archive. A related operation is ‘--update’ (‘-u’).
The ‘--update’ operation updates a tar archive by comparing the date
of the specified archive members against the date of the file with the
same name. If the file has been modified more recently than the
archive member, then the newer version of the file is added to the
archive (as with ‘--append’).
However,
When I run my tar update command, the files are appended even though their modification dates are exactly the same. I want to ONLY append where modification dates of files to be tarred are newer than those already in the tar...
tar -uf ./tarfile.tar /localdirectory/ >/dev/null 2>&1
Currently, every time I update, the tar doubles in size...
The update you describe implies that the file within the archive is replaced. If the new copy is smaller than what's in the archive, it could be directly rewritten. If the new copy however is larger, tar would have to zero the existing archive entry and append. Such updates would leave runs of '\0's or other unused bytes, so any normal computer user would want that such sections are removed, which would be done by "moving up" bytes comprising the archive contents towards the start of the file (think C's memmove).
Such an in-place move operation however, which would involve seek-read-seek-write cycles, is costly, especially when you look at it in the context of tapes — which tar was designed for originally —, i.e. devices with a seek performance that is not comparable to harddisks. You'd wear out the tape rather quickly with such move ops. Oh and of course, WORM devices don't support this move op either.
If you do not want to use the "-P" switch tar -u... works correctly if the current directory is the parent directory of the one we are going to update, and the path to this directory in the tar command will not be an absolute path.
For exmple:
We want to update catalog /home/blabla/Dir. We do it like that:
cd /home/blabla
tar -u -f tarfile.tar Dir
In general, the update must be made from the same place as the creation, so that the paths agree.
It is also possible:
cd /home/blabla/Dir
tar-u -f /path/to/tarfile.tar .
You may simply create (instead of update) the archive each time:
tar -cvpf tarfile.tar *
This will solve the problem of your archive doubling in size each time. But of course, it is generating the whole archive every time.
By default tar strips the leading / from member names, but it does this after deciding what needs to be updated.
Therefore if you are archiving an absolute path, you either need to cd / and use relative paths, or add the -P/--absolute-names option.
cd /
tar -uf "$OLDPWD/tarfile.tar" localdirectory/ >/dev/null 2>&1
tar -cPf tarfile.tar /localdirectory/ >/dev/null 2>&1
tar -uPf tarfile.tar /localdirectory/ >/dev/null 2>&1
However, the updated items will still be appended. A tar (tape archive) file cannot be modified excpet by appending.
Warning! When speaking about "dates" it means any date, and that includes the access time.
Should your files have been accessed in any such way (a simple ls -l is enough) then tar is right to do what it does!
You need to find another way to do what you want. Probably use a sentinel file and see if its modification date is less than the files you wish to append.

How can I recursively copy a directory into another and replace only the files that have not changed?

I am looking to do a specific copy in Fedora.
I have two folders:
'webroot': holding ALL web files/images etc
'export': folder containing thousands of PHP, CSS, JS documents that are exported from my SVN repo.
The export directory contains many of the same files/folders that the root does, however the root contains additional ones not found in export.
I'd like to merge all of the contents of export with my webroot with the following options:
Overwriting the file in webroot if export's version contains different code than what
is inside of webroot's version (live)
Preserve the permissions/users/groups of the file if it is overwritten (the export
version replacing the live version) *NOTE I would like the webroots permissions/ownership maintained, but with export's contents
No prompting/stopping of the copy
of any kind (ie not verbose)
Recursive copy - obviously I
would like to copy all* files
folders and subfolders found in
export
I've done a bit of research into cp - would this do the job?:
cp -pruf ./export /path/to/webroot
It might, but any time the corresponding files in export and webroot have the same content but different modification times, you'd wind up performing an unnecessary copy operation. You'd probably get slightly smarter behavior from rsync:
rsync -pr ./export /path/to/webroot
Besides, rsync can copy files from one host to another over an SSH connection, if you ever have a need to do that. Plus, it has a zillion options you can specify to tweak its behavior - look in the man page for details.
EDIT: with respect to your clarification about what you mean by preserving permissions: you'd probably want to leave off the -p option.
-u overwrites existing files folder if the destination is older than source
-p perserves the permission and dates
-f turns off verbosity
-r makes the copy recursive
So looks like you got all the correct args to cp
Sounds like a job for cpio (and hence, probably, GNU tar can do it too):
cd export
find . -print | cpio -pvdm /path/to/webroot
If you need owners preserved, you have to do it as root, of course. The -p option is 'pass mode', meaning copy between locations; -v is verbose (but not interactive; there's a difference); -d means create directories as necessary; -m means preserve modification time. By default, without the -u option, cpio won't overwrite files in the target area that are newer than the one from the source area.

Resources