Only if libc reports errno 95 Operation not supported the method should return that extended attributes are not supported. Also add a debug information about the result of the call to get further information in the log file
145 lines
4.9 KiB
Python
145 lines
4.9 KiB
Python
# Copyright (c) 2015 SUSE Linux GmbH. All rights reserved.
|
|
#
|
|
# This file is part of kiwi.
|
|
#
|
|
# kiwi is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# kiwi is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with kiwi. If not, see <http://www.gnu.org/licenses/>
|
|
#
|
|
import os
|
|
import errno
|
|
import logging
|
|
from stat import ST_MODE
|
|
from typing import List
|
|
|
|
# project
|
|
from kiwi.command import Command
|
|
|
|
log = logging.getLogger('kiwi')
|
|
|
|
|
|
class DataSync:
|
|
"""
|
|
**Sync data from a source directory to a target directory**
|
|
"""
|
|
def __init__(self, source_dir: str, target_dir: str) -> None:
|
|
"""
|
|
Create a new DataSync instance and initialize
|
|
sync source and target
|
|
|
|
:param str source_dir: source directory path name
|
|
:param str target_dir: target directory path name
|
|
"""
|
|
self.source_dir = source_dir
|
|
self.target_dir = target_dir
|
|
|
|
def sync_data(
|
|
self, options: List[str] = [], exclude: List[str] = [],
|
|
force_trailing_slash: bool = False
|
|
) -> None:
|
|
"""
|
|
Sync data from source to target using the rsync protocol
|
|
|
|
:param list options: rsync options
|
|
:param list exclude: file patterns to exclude
|
|
:param bool force_trailing_slash: add '/' to source_dir if not present
|
|
|
|
A speciality of the rsync tool is that it behaves differently
|
|
if the given source_dir ends with a '/' or not. If it ends
|
|
with a slash the data structure below will be synced to the
|
|
target_dir. If it does not end with a slash the source_dir
|
|
and its contents are synced to the target_dir. For example
|
|
|
|
.. code:: bash
|
|
|
|
source
|
|
└── some_data
|
|
|
|
1. $ rsync -a source target
|
|
|
|
target
|
|
└── source
|
|
└── some_data
|
|
|
|
2. $ rsync -a source/ target
|
|
|
|
target
|
|
└── some_data
|
|
|
|
The parameter force_trailing_slash can be used to make
|
|
sure rsync behaves like shown in the second case. If
|
|
set to true a '/' is appended to the given source_dir
|
|
if not already present
|
|
"""
|
|
if force_trailing_slash and not self.source_dir.endswith(os.sep):
|
|
self.source_dir += os.sep
|
|
target_entry_permissions = None
|
|
exclude_options = []
|
|
rsync_options = []
|
|
if options:
|
|
rsync_options = options
|
|
if not self.target_supports_extended_attributes():
|
|
warn_me = False
|
|
if '--xattrs' in rsync_options:
|
|
rsync_options.remove('--xattrs')
|
|
warn_me = True
|
|
if '--acls' in rsync_options:
|
|
rsync_options.remove('--acls')
|
|
warn_me = True
|
|
if warn_me:
|
|
log.warning(
|
|
'Extended attributes not supported for target: %s',
|
|
self.target_dir
|
|
)
|
|
if exclude:
|
|
for item in exclude:
|
|
exclude_options.append('--exclude')
|
|
exclude_options.append(
|
|
'/' + item
|
|
)
|
|
if os.path.exists(self.target_dir):
|
|
target_entry_permissions = os.stat(self.target_dir)[ST_MODE]
|
|
Command.run(
|
|
['rsync'] + rsync_options + exclude_options + [
|
|
self.source_dir, self.target_dir
|
|
]
|
|
)
|
|
if target_entry_permissions:
|
|
# rsync applies the permissions of the source directory
|
|
# also to the target directory which is unwanted because
|
|
# only permissions of the files and directories from the
|
|
# source directory and its contents should be transfered
|
|
# but not from the source directory itself. Therefore
|
|
# the permission bits of the target directory before the
|
|
# sync are applied back after sync to ensure they have
|
|
# not changed
|
|
os.chmod(self.target_dir, target_entry_permissions)
|
|
|
|
def target_supports_extended_attributes(self) -> bool:
|
|
"""
|
|
Check if the target directory supports extended filesystem
|
|
attributes
|
|
|
|
:return: True or False
|
|
|
|
:rtype: bool
|
|
"""
|
|
try:
|
|
os.getxattr(self.target_dir, 'user.mime_type')
|
|
except OSError as e:
|
|
log.debug(
|
|
f'Check for extended attributes on {self.target_dir} said: {e}'
|
|
)
|
|
if e.errno == errno.ENOTSUP:
|
|
return False
|
|
return True
|