cp ile Gelişmiş Kopyalama: İzinleri ve Linkleri Koruma

Dosyaları kopyalamak kulağa basit bir iş gibi gelir. cp kaynak hedef yazarsın, biter. Ama işler biraz daha karmaşıklaştığında, yani production sunucusundaki bir dizini yedeklemeniz gerektiğinde, sembolik linklerin hedefte de sembolik link olarak kalmasını istediğinizde ya da dosya sahipliği ve izinlerin birebir korunmasını şart koştuğunuzda, basit cp komutunun yetersiz kaldığını görürsünüz. Bu yazıda cp komutunun gelişmiş kullanımını, özellikle izin koruma, link yönetimi ve gerçek dünya yedekleme senaryolarını ele alacağız.

cp Komutunun Temel Parametreleri

Çoğu sysadmin cp komutunu ya -r ile ya da -i ile kullanır, gerisine pek bakılmaz. Ama man sayfasına girdiğinizde onlarca parametre sizi karşılar. Hepsini ezberlemek gerekmez ama kritik olanları bilmek, bir gün sizi gerçek bir felaketten kurtarabilir.

Sık kullandığım temel parametreler şunlar:

  • -r veya -R: Dizinleri özyinelemeli (recursive) olarak kopyalar
  • -p: Dosya izinlerini, sahipliğini ve zaman damgalarını korur
  • -a: Arşiv modu; -dR --preserve=all ile eşdeğerdir
  • -v: Kopyalanan her dosyayı ekrana yazar (verbose)
  • -i: Üzerine yazmadan önce onay ister
  • -n: Mevcut dosyaların üzerine yazmaz
  • -u: Sadece kaynak daha yeniyse kopyalar
  • -l: Kopyalamak yerine hard link oluşturur
  • -s: Kopyalamak yerine sembolik link oluşturur
  • -d: Sembolik linkleri takip etmez, linkin kendisini kopyalar
  • –preserve: Hangi özelliklerin korunacağını belirtmenizi sağlar

İzinleri Koruma: -p ve –preserve

Bir uygulama sunucusunda /var/www/html dizinini başka bir sunucuya taşıdığınızı düşünün. Eğer dosya izinlerini korumadan kopyalarsanız, karşı tarafta tüm dosyalar kopyalama işlemini yapan kullanıcının izinleriyle oluşturulur. Bu durum, özellikle www-data veya nginx gibi özel kullanıcıların sahip olduğu dosyalarda ciddi sorunlara yol açar.

# İzinleri koruyarak kopyalama
cp -p kaynak_dosya.conf hedef_dosya.conf

# Dizini izinleriyle birlikte kopyalama
cp -rp /var/www/html /backup/www_backup

# Ne kopyalandığını görmek için verbose ekle
cp -rpv /etc/nginx /backup/nginx_backup

-p parametresi şu bilgileri korur:

  • mod: Dosya izinleri (rwxr-xr-x gibi)
  • ownership: Kullanıcı ve grup sahipliği
  • timestamps: Erişim ve değiştirme zamanları

Ancak daha granüler bir kontrol istiyorsanız --preserve parametresini kullanmanız gerekir. Bu parametre, neyi koruyacağınızı tek tek belirtmenize imkan tanır.

# Sadece izinleri ve zaman damgalarını koru, sahipliği değil
cp --preserve=mode,timestamps kaynak.txt hedef.txt

# Tüm özellikleri koru (sahiplik dahil - root gerektirebilir)
cp --preserve=all kaynak.txt hedef.txt

# Sadece sahipliği koru
cp --preserve=ownership kaynak.txt hedef.txt

--preserve parametresinin alabileceği değerler:

  • mode: Dosya izin bitleri
  • ownership: Kullanıcı ve grup ID’leri
  • timestamps: Erişim ve değiştirme zamanları
  • links: Hard link ilişkilerini koru
  • context: SELinux güvenlik bağlamı
  • xattr: Genişletilmiş özellikler (extended attributes)
  • all: Yukarıdakilerin tamamı

Şunu belirtmeliyim: ownership koruması genellikle root yetkisi gerektirir. Normal kullanıcı olarak dosya sahipliğini başkasına atayamazsınız. Bu yüzden bu tür kopyalama işlemlerini root olarak veya sudo ile yapmanız gerekir.

Arşiv Modu: -a Parametresi

Sistem yöneticilerinin sevgilisi -a parametresi, aslında birden fazla parametrenin birleşimidir. -dR --preserve=all kombinasyonuna eşdeğerdir ve çoğu yedekleme senaryosu için biçilmiş kaftandır.

# Arşiv modunda kopyalama
cp -a /home/kullanici /backup/home_backup

# Verbose ile birlikte
cp -av /etc /backup/etc_$(date +%Y%m%d)

# Birden fazla kaynağı arşiv modunda kopyalama
cp -a /var/www/site1 /var/www/site2 /backup/sites/

Gerçek bir senaryo üzerinden gidelim. Diyelim ki bir web sunucusunda deployment öncesi mevcut dizini yedekliyorsunuz:

# Deployment öncesi backup alma
BACKUP_DIR="/backup/deployments/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
cp -a /var/www/uygulama/* "$BACKUP_DIR/"
echo "Backup alindi: $BACKUP_DIR"

Bu komut dizisi çalıştırıldığında, /var/www/uygulama altındaki tüm dosyalar ve dizinler; sahiplikleri, izinleri, zaman damgaları ve link yapılarıyla birlikte yedeğe alınır.

Sembolik Linkleri Yönetmek

Sembolik linkler, sistem yöneticilerinin sıkça karşılaştığı ve cp ile birlikte en çok baş ağrıtan konulardan biri. Varsayılan davranışı anlamamak, linkin kendisini değil hedef dosyayı kopyalamanıza neden olur.

Önce durumu somutlaştıralım:

# Bir sembolik link oluşturalım
ln -s /etc/nginx/nginx.conf /home/admin/nginx.conf

# Şimdi bu linki kopyalamaya çalışalım
ls -la /home/admin/nginx.conf
# lrwxrwxrwx 1 admin admin 22 Ara 15 10:30 nginx.conf -> /etc/nginx/nginx.conf

Eğer bu linki sıradan cp ile kopyalarsanız:

cp /home/admin/nginx.conf /tmp/nginx_kopi.conf
# Bu komut, linkin gösterdiği /etc/nginx/nginx.conf dosyasının içeriğini kopyalar
# Sembolik linki değil!

Ama biz linkin kendisini korumak istiyorsak:

# -d parametresi ile linki kopyala (hedefi değil)
cp -d /home/admin/nginx.conf /tmp/nginx_kopi.conf

# -P parametresi de aynı işi yapar (büyük P)
cp -P /home/admin/nginx.conf /tmp/nginx_kopi.conf

# Kontrol edelim
ls -la /tmp/nginx_kopi.conf
# lrwxrwxrwx 1 root root 22 Ara 15 10:35 nginx_kopi.conf -> /etc/nginx/nginx.conf

-a parametresi de sembolik linklerin kendisini kopyalar, hedeflerini takip etmez. Bu yüzden dizin kopyalamalarında -a kullanmak genellikle doğru seçimdir.

Sembolik Link İçeren Dizinleri Kopyalamak

Bir uygulamanın konfigürasyon dizininde sembolik linkler varsa ve siz bu dizini arşivliyorsanız:

# Örnek dizin yapısı
# /app/config/
#   ├── database.conf (gerçek dosya)
#   ├── redis.conf -> /etc/redis/redis.conf (sembolik link)
#   └── ssl/ -> /etc/ssl/app/ (dizin linki)

# -a ile kopyalama: linkler korunur
cp -av /app/config /backup/config_backup

# -rL ile kopyalama: linkler takip edilir, içerikler kopyalanır
cp -rLv /app/config /backup/config_backup_full

# Hangisini seçeceğiniz use case'e göre değişir

-L parametresi, kopyalama sırasında tüm sembolik linkleri takip eder ve hedeflerin gerçek içeriğini kopyalar. Bu, dağıtık bir sisteme taşıma yaparken ve karşı tarafta aynı link yapısının bulunmadığını bildiğinizde işe yarar.

Hard Linkler ve -l Parametresi

Hard linkler, sembolik linklerden farklı olarak aynı inode’u paylaşan dosya isimleridir. cp -l komutu, kopyalama yerine hard link oluşturur.

# Hard link oluşturarak "kopyalama"
cp -l orijinal.txt hardlink_kopya.txt

# İnce farkı görmek için
ls -lai orijinal.txt hardlink_kopya.txt
# Her ikisi de aynı inode numarasını gösterir

Peki bu ne işe yarar? Disk alanı tasarrufu konusunda harika bir yöntemdir. Özellikle incremental backup sistemlerinde çok kullanılır. Rsync’in --link-dest özelliği de bu prensibi kullanır.

# Incremental backup benzeri senaryo
# Önceki backup ile değişmeyen dosyalar hard link olarak bağlanır
cp -al /backup/gun1/ /backup/gun2/
# Şimdi gun2'yi güncelle, değişen dosyalar kopyalanır, değişmeyenler hard link olarak kalır

Bu yaklaşımın dezavantajı: Hard linkler partition sınırlarını geçemez. /home ve /backup farklı partition’larda ise hard link oluşturamazsınız.

–preserve=links: Hard Link İlişkilerini Korumak

Bu parametre, çoğu sysadmin’in hiç duymadığı ama çok işe yarayan bir özellik. Bir dizinde birden fazla dosya aynı inode’u (yani hard link) paylaşıyorsa, bu ilişkiyi hedef dizinde de korumak ister misiniz?

# Örnek oluşturalım
mkdir /tmp/test_hardlinks
echo "ortak icerik" > /tmp/test_hardlinks/dosya1.txt
ln /tmp/test_hardlinks/dosya1.txt /tmp/test_hardlinks/dosya2.txt

# İkisi aynı inode'u paylaşıyor
ls -lai /tmp/test_hardlinks/

# --preserve=links ile kopyalama
cp -a --preserve=links /tmp/test_hardlinks /tmp/test_hardlinks_kopya

# Hedefte de hard link ilişkisi korunmuş olmalı
ls -lai /tmp/test_hardlinks_kopya/

Bu özellik özellikle sistem yedeklerinde kritik önem taşır. Bazı uygulamalar hard link yapısına dayanır ve bu yapı bozulursa uygulama hatalı çalışabilir.

Gerçek Dünya Senaryoları

Senaryo 1: Web Sunucusu Dizini Yedekleme

Production’da bir değişiklik yapmadan önce tam bir backup almak istiyorsunuz:

#!/bin/bash

APP_DIR="/var/www/myapp"
BACKUP_BASE="/backup/myapp"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="$BACKUP_BASE/$TIMESTAMP"

# Backup dizini oluştur
mkdir -p "$BACKUP_DIR"

# Arşiv modunda kopyala, verbose çıktıyı logla
cp -av "$APP_DIR" "$BACKUP_DIR" 2>&1 | tee "/var/log/backup_$TIMESTAMP.log"

# Backup başarılı mı kontrol et
if [ $? -eq 0 ]; then
    echo "Backup basariyla tamamlandi: $BACKUP_DIR"
    # Son 5 backup'ı tut, eskilerini sil
    ls -dt "$BACKUP_BASE"/*/ | tail -n +6 | xargs rm -rf
else
    echo "HATA: Backup basarisiz!" >&2
    exit 1
fi

Senaryo 2: Konfigürasyon Dosyalarını Farklı Sunucuya Taşıma

Yeni bir sunucu kuruyorsunuz ve mevcut sunucudaki nginx konfigürasyonunu taşımanız gerekiyor:

# Kaynak sunucuda: konfigürasyonu hazırla
cp -a /etc/nginx /tmp/nginx_transfer

# tar ile paketle (ssh üzerinden taşımak için)
tar czf /tmp/nginx_config.tar.gz -C /tmp nginx_transfer

# Hedef sunucuya gönder
scp /tmp/nginx_config.tar.gz hedef_sunucu:/tmp/

# Hedef sunucuda:
cd /tmp
tar xzf nginx_config.tar.gz
cp -a /tmp/nginx_transfer/* /etc/nginx/

# İzinleri kontrol et
ls -la /etc/nginx/

Senaryo 3: Kullanıcı Home Dizinlerini Yedekleme

Birden fazla kullanıcının home dizinini yedeklemek:

#!/bin/bash

BACKUP_DIR="/backup/homes/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

for user_dir in /home/*/; do
    username=$(basename "$user_dir")
    echo "Yedekleniyor: $username"
    
    # Kullanıcı dizinini arşiv modunda yedekle
    cp -a "$user_dir" "$BACKUP_DIR/$username"
    
    if [ $? -eq 0 ]; then
        echo "$username: OK"
    else
        echo "$username: HATA" >&2
    fi
done

echo "Tum home dizinleri yedeklendi: $BACKUP_DIR"

Senaryo 4: SELinux Context’ini Koruma

SELinux kullanan sistemlerde (RHEL, CentOS, Fedora) dosya context’ini korumak önemlidir:

# SELinux context dahil her şeyi koru
cp --preserve=all /etc/httpd/conf/httpd.conf /backup/httpd.conf

# Context'i kontrol et
ls -lZ /backup/httpd.conf
ls -lZ /etc/httpd/conf/httpd.conf

# Eğer context kaybolmuşsa, restorecon ile düzelt
restorecon -v /backup/httpd.conf

cp ile Güvenli Kopyalama Teknikleri

-i ve -n Parametreleri

Üzerine yazma konusunda dikkatli olmak gerekir:

# Her üzerine yazma için onay iste
cp -i kaynak.conf /etc/uygulama.conf

# Hiçbir zaman üzerine yazma
cp -n kaynak.conf /etc/uygulama.conf

# -i ve -n birlikte kullanılamaz, -n öncelik alır

Kısmi Kopyalama ve -u Parametresi

Büyük dizinlerde sadece yeni veya değişmiş dosyaları kopyalamak:

# Sadece kaynak daha yeniyse kopyala
cp -u /kaynak/* /hedef/

# Büyük dizinler için
cp -rau /var/log/app /backup/log_backup

# Bu özellik incremental backup mantığı için kullanışlı
# ama rsync kadar gelişmiş değil

Dikkat Edilmesi Gereken Noktalar

cp komutunun bazı davranışları başlangıçta sürpriz yapabilir:

Trailing slash (sondaki /) farkı: Bash’te dizin kopyalarken sondaki slash önemlidir.

# /kaynak dizinini /hedef altına kopyalar -> /hedef/kaynak
cp -a /kaynak /hedef

# /kaynak içeriğini /hedef içine kopyalar
cp -a /kaynak/ /hedef/
# ya da
cp -a /kaynak/. /hedef/

Root olmadan sahiplik koruma: Normal kullanıcı olarak başka bir kullanıcıya ait dosyaları kopyalamaya çalışırsanız, sahiplik korunamaz:

# Root değilseniz bu uyarı alırsınız:
# cp: failed to preserve ownership for 'hedef.txt': Operation not permitted
# Ama kopyalama yine de tamamlanır, sadece ownership korunamaz
sudo cp -a /root/dosya /tmp/kopya  # sudo ile sorun çözülür

Ext4 ve xattr desteği: Bazı dosya sistemleri extended attributes desteklemeyebilir. NFS üzerinde xattr korumak sorunlu olabilir.

# xattr desteğini kontrol et
cp --preserve=xattr kaynak hedef 2>&1
# Eğer dosya sistemi desteklemiyorsa hata verir ama kopyalama devam eder

cp Yerine Ne Zaman Başka Araçlar Kullanmalı?

cp güçlü ama her iş için en iyi araç değil:

  • rsync: Ağ üzerinden kopyalama, incremental backup, bant genişliği kontrolü gerektiğinde
  • tar: Büyük dizin ağaçlarını bir bütün olarak taşırken, özellikle izin/ownership korunması kritikse
  • dd: Disk veya partition imajı almak gerektiğinde
  • install: Dosyaları belirli izin ve sahiplikle yerleştirmek gerektiğinde

Özellikle ağ üzerinden veri aktarırken şu yaklaşım daha güvenilirdir:

# tar + ssh kombinasyonu: cp -a'nın ağ versiyonu
tar czf - -C /kaynak . | ssh hedef_sunucu "tar xzf - -C /hedef"

# rsync: daha akıllı ve incremental
rsync -avz --preserve-permissions /kaynak/ hedef_sunucu:/hedef/

Hızlı Referans: Yaygın Kullanım Kalıpları

Sık karşılaşılan durumlar için hazır komutlar:

# Tek dosyayı izinleriyle kopyala
cp -p kaynak.conf hedef.conf

# Dizini tüm özellikleriyle yedekle
cp -a /uygulama /backup/uygulama_$(date +%Y%m%d)

# Sembolik linkleri koruyarak kopyala
cp -d semlink hedef_dizin/

# Üzerine yazmadan kopyala
cp -rn /kaynak /hedef

# Sadece yeni dosyaları kopyala
cp -ru /kaynak/* /hedef/

# Her şeyi koru (SELinux dahil)
sudo cp --preserve=all kaynak hedef

# Verbose ile dizin kopyala
cp -av /etc/apache2 /backup/apache2_backup

Sonuç

cp komutu, görünürde basit ama derinlemesine incelendiğinde son derece güçlü bir araç. Günlük kullanımda çoğumuz cp -r ile geçiştirip geçiyoruz, ama bir production olayında yanlış parametreyle alınan bir backup, geri dönüşü çok zor sorunlara yol açabilir.

Özellikle şu üç noktayı aklınızda tutun: Arşiv modunda yedekleme yaparken -a parametresi neredeyse her zaman doğru seçimdir. Sembolik linklerin hedeflerini değil kendilerini korumak istiyorsanız -d veya -P kullanın. Sahiplik koruma işlemlerini root yetkisiyle yapın, aksi takdirde sessizce başarısız olabilir ve yanlış sahiplikli dosyalarla karşılaşabilirsiniz.

Temel komutları iyi bilmek, karmaşık senaryolarda doğru kararlar vermenizi sağlar. rsync ve tar gibi araçlar daha gelişmiş backup ihtiyaçları için tercih edilebilir, ama yerel kopyalama ve anlık yedekleme senaryolarında cp hızlı, güvenilir ve her Linux sistemde hazır olarak bulunur.

Yorum yapın