30 Mayıs 2011 Pazartesi

LDAP ve Apache - Kullanıcı Doğrulaması Pratikleri

LDAP (Lightweight Directory Access Protocol), dizin servislerine (directory services) erişimi sağlayan bir iletişim protokolünü ifade etmektedir. Dizin sunucusu (directory server) adı verilen bir tür veritabanının sunduğu veri erişim servisine dizin servisi adı verilmektedir. Dizin sunucuları, verinin merkezi olarak tutulduğu ve çoğunlukla gezinme, arama ve okuma işlevlerine yazma işlevinden daha fazla gereksinim duyulan durumlarda ön plana çıkan sunuculardır. Verinin hiyerarşik şekilde tutulduğu ve standart arayüzler üzerinden erişim imkanı sunan bu sunucuların kullanıcı veritabanı olmak ve kullanıcı doğrulaması sağlamak gibi işlevlere yönelik olarak geniş bir kullanım alanı bulması doğaldır.

Bu yazıda LDAP protokolü ve sunucularını anlatmaktan çok Apache (http://httpd.apache.org/) Web sunucusu üzerinden verilen bir takım servislerin LDAP üzerinden kullanıcı doğrulaması yapacak şekilde nasıl ayarlanabileceklerine değinilmiştir.

Debian kullanıyorsanız, paket yöneticisi ile yüklediğiniz Apache 2.2 sunucunuz aynı zamanda mod_ldap ve mod_authnz_ldap modülleri ile birlikte gelecektir. Bu modüller etkinleştirilirse, Web sunucusu belirlenen URL alanları için LDAP doğrulaması yapar hale getirilebilmektedir.

Debian dağıtımı ile gelen Apache ayar dizini içindeki mods-enabled dizini içinden, mods-available dizini içindeki ldap.load, ldap.conf ve authnz_ldap.load dosyalarına referans verecek şekilde soft-linkler oluşturulmalıdır. Böylece mod_ldap.so ve mod_authnz_ldap.so dinamik kütüphaneleri Apache açılışında yüklenir hale getirilir.

Aşağıdaki Apache konfigürasyon ifadeleri ile kullanıcı doğrulaması bağlamında yapılabileceklere yönelik pratik örnekler verilmiştir.

Belirli bir URL dizinine erişimin LDAP üzerinden kullanıcı doğrulaması yapmaya zorlanması aşağıda örneklenmiştir:
<Location "/internal">
  AuthType Basic
  AuthName "Kullanicilara Yonelik Bolge"
  AuthBasicProvider ldap
  AuthLDAPURL "ldap://127.0.0.1/uid=user1,ou=Users,dc=x,dc=y,dc=z?uid?sub?(objectClass=inetOrgPerson)"
  Require valid-user
</location>
Apache Web sunucusu üzerinden verilen bir SVN (Subversion) servisi aşağıdaki gibi LDAP üzerinden kullanıcı doğrulaması yapmaya zorlanabilir. (Bu örnekten önce Subversion (SVN) Servislerinin HTTPS Üzerinden Sunulması başlıklı yazıya göz atabilirsiniz.)
<Location /svn/project1>
  DAV svn
  SVNPath /disk/svn/project1
  AuthzSVNAccessFile /disk/svn/project1/conf/authz
  Require valid-user
  AuthType Basic
  AuthName "Project1 - SVN Repository"
  AuthBasicProvider ldap
  AuthLDAPURL "ldap://127.0.0.1/ou=Users,dc=x,dc=y,dc=z?uid?sub?(|(objectClass=inetOrgPerson)(objectClass=simpleSecurityObject))"
</Location>
Aşağıda ise bir Trac (http://trac.edgewall.org/) servisinin LDAP ile kullanıcı doğrulaması yapar hale getirilmesini örneklemektedir. (Bu örnekten önce Debian Üzerine Trac Kurulumu başlıklı yazıya göz atabilirsiniz.)
<Location /trac/project1>
  SetHandler mod_python
  PythonHandler trac.web.modpython_frontend
  PythonInterpreter main
  PythonOption TracEnv /disk/trac/project1
  PythonOption TracUriRoot /trac/project1
  SetEnv PYTHON_EGG_CACHE /tmp
</Location>

<Location "/trac/project1/login">
  AuthType Basic
  AuthName "Project 1 - Trac Interface"
  AuthBasicProvider ldap
  AuthLDAPURL "ldap://127.0.0.1/ou=Users,dc=x,dc=y,dc=z?uid?sub?(objectClass=inetOrgPerson)"
  Require valid-user
</location>
Örneklediğimiz ortamda Apache Web sunucusu ve LDAP sunucularının aynı makinada olacağı düşünülmüştür. Dolayısıyla ayarlarda görüleceği üzere LDAP URL içinde 127.0.0.1 IP adresine erişim söz konusudur. Apache ve LDAP sunucularının ayrı makinalarda olması durumunda güvenli LDAP bağlantısı (LDAPS) kullanılması önerilmektedir.

Burada yapılan işlem sadece kullanıcı doğrulaması (authentication) yapılarak erişilmek istenen servise erişimin ilk aşamasının yapılmasıdır. Servis özelindeki erişim yetkilerinin (authorization) ele alınması ile ilgili sorumluluk ilgili servise (dolayısıyla sunucusuna) bırakılmıştır.

Linkler:

20 Mayıs 2011 Cuma

Eclipse RCP Uygulamalarında Açılışta Login Ekranı Gösterimi

Eclipse RCP uygulamalarında açılışta gösterilen splash ekranı, aynı zamanda kullanıcı doğrulaması için login parametrelerinin sorulduğu bir dialog ekranına dönüştürülebilmektedir.

Splash ekranı gösterecek şekilde ayarlanmış bir Eclipse RCP uygulamamız varsa, önce plugin.xml dosyasına aşağıdaki extension eklemesini yapmakla işe başlayabiliriz. Eclipse uygulamamızda Product ID, "x.y.z.product" olarak tanımlanmıştır.
<extension point="org.eclipse.ui.splashHandlers">
  <splashHandler
    class="x.y.z.SplashHandler"
       id="x.y.z.splashHandler">
  </splashHandler>
  <splashHandlerProductBinding
    productId="x.y.z.product"
     splashId="x.y.z.splashHandler">
  </splashHandlerProductBinding>
</extension>
Şimdi bu extension tanımı ile eklenmek istenen fonksiyonalite aşağıdaki sınıf içinde gerçekleştirilir.
package x.y.z;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.splash.AbstractSplashHandler;

public class SplashHandler extends AbstractSplashHandler {

  private boolean authenticated = false;

  @Override
  public void init(final Shell splash) {
    super.init(splash);

    splash.setLayout(new FillLayout());
    splash.setBackgroundMode(SWT.INHERIT_DEFAULT);

    Composite composite = new Composite(splash, SWT.BORDER);
    composite.setLayout(new GridLayout(2, false));

    Label lblUserName = new Label(composite, SWT.NONE);
    lblUserName.setText("&User Name :");
    final Text txtUserName = new Text(composite, SWT.BORDER);

    Label lblPassword = new Label(composite, SWT.NONE);
    lblPassword.setText("&Password :");
    final Text txtPassword = new Text(composite, SWT.BORDER);

    Button btnOK = new Button(composite, SWT.PUSH);
    btnOK.setText("OK");
    btnOK.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        String userName = txtUserName.getText();
        String password = txtPassword.getText();
        if (userName.length() > 0 && password.length() > 0) {
          if (userName.equals("user1") && password.equals("secret")) {
            authenticated = true;
          }
        } else {
          MessageDialog.openError(splash, "Authentication Failed", "Username and password must be specified.");
        }
      }
    });

    Button btnCancel = new Button(composite, SWT.PUSH);
    btnCancel.setText("Cancel");
    btnCancel.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        splash.getDisplay().close();
        System.exit(0);
      }
    });

    splash.layout(true);

    while (authenticated == false) {
      if (splash.getDisplay().readAndDispatch() == false) {
        splash.getDisplay().sleep();
      }
    }
  }
}
Burada işleyişin bir bütün halinde anlaşılması amacıyla oldukça sadeleştirilmiş bir kod örneği sunulmuştur. Daha kullanışlı bir login uygulaması için aşağıdaki bağlantıya göz atılabilir:
http://tomsondev.bestsolution.at/2007/06/12/splash-screen-and-threads/

14 Mayıs 2011 Cumartesi

SQLJet ile Dosya Tabanlı Veritabanı Kullanımı

SQLite (http://sqlite.org/) dosya tabanlı, sunucusuz, ek kütüphane ve konfigürasyon gerektirmeyen, transaction desteği veren bir veritabanı kütüphanesidir. Bir tür gömülü veritabanı yönetim sistemi olarak nitelendirilebilir.

SQLJet (http://sqljet.com/) ise Java programlama dili içinden SQLite veritabanı oluşturma ve kullanma imkanı sunan, tamamen Java ile yazılmış, JDBC sürücüsü gerektirmeyen bir kütüphanedir.

Bu yazıda SQLJet ile ufak bir veritabanı uygulamasının nasıl çalışacağı aşağıda göreceğiniz JUnit test sınıfı içinde örneklenmiştir. Bu örnekte, log kayıtlarını veritabanında tutacak ve bu kayıtlara zaman bazlı hızlı erişim sunacak bir sistemin SQLJet ile gerçekleştirimi basit bir şekilde test edilmektedir.
package x.y.z.test;

import java.io.File;
import java.util.Date;

import org.junit.Test;
import org.tmatesoft.sqljet.core.SqlJetException;
import org.tmatesoft.sqljet.core.SqlJetTransactionMode;
import org.tmatesoft.sqljet.core.table.ISqlJetCursor;
import org.tmatesoft.sqljet.core.table.ISqlJetTable;
import org.tmatesoft.sqljet.core.table.SqlJetDb;

public class SQLJetTester {

  private static final String DB_FILE_NAME = "/log-sqljet.db";
  private static final String TABLE_LOG = "log";
  private static final String TABLE_LOG_COL_TIMESTAMP = "timestamp";
  private static final String TABLE_LOG_COL_MESSAGE = "message";

  private Date startOfPeriod = null;
  private Date endOfPeriod = null;

  public SQLJetTester() {
  }

  @Test
  public void queryTest() {
    try {
      SqlJetDb db = initDatabase();
      if (db != null) {
        db.beginTransaction(SqlJetTransactionMode.READ_ONLY);
        ISqlJetTable table = db.getTable(TABLE_LOG);
        ISqlJetCursor cursor = table.scope(table.getPrimaryKeyIndexName(), new Object[] { startOfPeriod.getTime() }, new Object[] { endOfPeriod.getTime() });
        try {
          System.out.printf("\nQuery results:\n");
          while (!cursor.eof()) {
            long timestamp = cursor.getInteger(TABLE_LOG_COL_TIMESTAMP);
            String message = cursor.getString(TABLE_LOG_COL_MESSAGE);
            System.out.printf("%s, %s\n", new Date(timestamp), message);
            cursor.next();
          }
        } finally {
          cursor.close();
          db.commit();
        }
      }
    } catch (SqlJetException e) {
      e.printStackTrace();
    }
  }

  @Test
  public void cleanTest() {
    try {
      SqlJetDb db = initDatabase();
      if (db != null) {
        db.beginTransaction(SqlJetTransactionMode.WRITE);
        ISqlJetTable table = db.getTable(TABLE_LOG);
        ISqlJetCursor deleteCursor = table.scope(table.getPrimaryKeyIndexName(), new Object[] { Long.MIN_VALUE }, new Object[] { startOfPeriod.getTime() });
        while (!deleteCursor.eof()) {
          deleteCursor.delete();
        }
        deleteCursor.close();
        db.commit();

        db.beginTransaction(SqlJetTransactionMode.READ_ONLY);
        ISqlJetCursor cursor = table.order(table.getPrimaryKeyIndexName());
        try {
          System.out.printf("\nQuery result after clean:\n");
          while (!cursor.eof()) {
            long timestamp = cursor.getInteger(TABLE_LOG_COL_TIMESTAMP);
            String message = cursor.getString(TABLE_LOG_COL_MESSAGE);
            System.out.printf("%s, %s\n", new Date(timestamp), message);
            cursor.next();
          }
        } finally {
          cursor.close();
          db.commit();
        }
      }
    } catch (SqlJetException e) {
      e.printStackTrace();
    }
  }

  // ---

  private SqlJetDb initDatabase() {
    File dbFile = new File(DB_FILE_NAME);
    dbFile.delete();
    try {
      SqlJetDb db = SqlJetDb.open(dbFile, true);
      db.beginTransaction(SqlJetTransactionMode.WRITE);
      try {
        String query = String.format("CREATE TABLE IF NOT EXISTS %s (%s INTEGER NOT NULL PRIMARY KEY, %s TEXT)", TABLE_LOG, TABLE_LOG_COL_TIMESTAMP, TABLE_LOG_COL_MESSAGE);
        db.createTable(query);
      } finally {
        db.commit();
      }

      db.beginTransaction(SqlJetTransactionMode.WRITE);
      try {
        ISqlJetTable table = db.getTable(TABLE_LOG);
        System.out.printf("\nInserting rows:\n");
        for (int i = 0; i < 10; i++) {
          Date date = new Date();
          String message = "message-" + i;
          System.out.printf("%s-%s\n", date.getTime(), message);
          table.insert(date.getTime(), message);
          if (i == 2) {
            startOfPeriod = date;
          } else if (i == 6) {
            endOfPeriod = date;
          }

          try {
            Thread.sleep(100);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      } finally {
        db.commit();
      }

      return db;
    } catch (SqlJetException e) {
      e.printStackTrace();
    }

    return null;
  }
}
Bu test kodu içinde önce veritabanı yaratılmakta (varsa silinerek), sonra timestamp ve message kolonları içeren bir tablo yaratılmakta ve örnek kayıtlar eklenmektedir. Sonrasında iki test metodu, ilklenen bu veritabanı üzerinde şu işlemleri yapmaktadır:
  • queryTest metodu iki tarih aralığı içindeki log mesajlarını getirir.
  • queryClean metodu belirli bir tarihten önceki verilerin silinmesi işlevini test eder.
Bu test kodu çalıştırılınca aşağıdaki çıktı elde edilecektir:
Inserting rows:
1305355900765-message-0
1305355900875-message-1
1305355900984-message-2
1305355901078-message-3
1305355901171-message-4
1305355901281-message-5
1305355901375-message-6
1305355901484-message-7
1305355901578-message-8
1305355901687-message-9

Query results:
Sat May 14 09:51:40 EEST 2011, message-2
Sat May 14 09:51:41 EEST 2011, message-3
Sat May 14 09:51:41 EEST 2011, message-4
Sat May 14 09:51:41 EEST 2011, message-5
Sat May 14 09:51:41 EEST 2011, message-6

Inserting rows:
1305355901906-message-0
1305355902000-message-1
1305355902109-message-2
1305355902203-message-3
1305355902312-message-4
1305355902406-message-5
1305355902515-message-6
1305355902609-message-7
1305355902718-message-8
1305355902812-message-9

Query result after clean:
Sat May 14 09:51:42 EEST 2011, message-3
Sat May 14 09:51:42 EEST 2011, message-4
Sat May 14 09:51:42 EEST 2011, message-5
Sat May 14 09:51:42 EEST 2011, message-6
Sat May 14 09:51:42 EEST 2011, message-7
Sat May 14 09:51:42 EEST 2011, message-8
Sat May 14 09:51:42 EEST 2011, message-9
Linkler:

13 Mayıs 2011 Cuma

XStream ile XML Serileştirme (XML Serialization)

Java'daki serileştirme (serialization) desteğine alternatif olarak kullanılabilecek bir yöntem XML serileştirme (XML serialization) yöntemidir. Bu metod ile Java işletim ortamınızdaki nesne örneklerini (instance) XML formuna çevirebilir veya tam tersini (XML formundan tekrar işletim ortamına nesne örneği olarak yükleme) yapabiliriz. XStream (http://xstream.codehaus.org/) bu işi kolayca yapabilmemizi sağlayan bir kütüphane.

Aşağıda XStream kullanımı örneklenmiştir.
package x.y.z;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class XStreamTester {

  public static class Person {
    private String name;
    private Date birthDate = new Date();

    public Person(String name) {
      this.name = name;
    }

    @Override
    public String toString() {
      return String.format("%s,%s", name, birthDate);
    }
  }

  public static class Author extends Person {
    private List<Book> books = new ArrayList<Book>();

    public Author(String name) {
      super(name);
    }

    public List<Book> getBooks() {
      return books;
    }

    @Override
    public String toString() {
      return String.format("%s,%s", super.toString(), books);
    }
  }

  public static class Book {
    private String name;
    private Author author;

    public Book(String name, Author author) {
      this.name = name;
      this.author = author;
    }

    @Override
    public String toString() {
      return String.format("%s", name);
    }
  }

  public static void main(String[] args) {
    Author author1 = new Author("author1");
    author1.getBooks().add(new Book("book1", author1));
    author1.getBooks().add(new Book("book2", author1));
    author1.getBooks().add(new Book("book3", author1));

    XStream xstream = new XStream(new DomDriver());
    xstream.alias("Book", Book.class);            // XML icinde sinifi tanimlayan etiket olarak verdigimiz isim kullanilir
    xstream.omitField(Person.class, "birthDate"); // Verilen alan serilestirmeye sokulmaz

    String xml = xstream.toXML(author1);
    System.out.printf("%s\n\n", xml);

    System.out.printf("before : %s\n", author1);

    Object object = xstream.fromXML(xml);
    System.out.printf("after  : %s\n", object);
  }
}
Bu kod çalışınca aşağıdaki çıktı alınacaktır:
<x.y.z.XStreamTester_-Author>
  <name>author1</name>
  <books>
    <Book>
      <name>book1</name>
      <author reference="../../.."/>
    </Book>
    <Book>
      <name>book2</name>
      <author reference="../../.."/>
    </Book>
    <Book>
      <name>book3</name>
      <author reference="../../.."/>
    </Book>
  </books>
</x.y.z.XStreamTester_-Author>

before : author1,Fri May 13 22:14:19 EEST 2011,[book1, book2, book3]
after  : author1,null,[book1, book2, book3]
Linkler:

8 Mayıs 2011 Pazar

Clonezilla ile Disk Bölümü Klonlama

Yeni bir sabit disk aldınız ve hali hazırda kullanmakta olduğunuz işletim sistemini aynı şekilde yeni diske aktarmak istiyorsunuz. Bir başka senaryoda da zaman harcayıp çeşitli programlar kurduğunuz, türlü türlü ayarlamlar yapıp kendiniz için özelleştirdiğiniz bir işletim sisteminiz var ve oluşabilecek bir sorun nedeniyle bu sistemi kullanamaz hale geldiğinizde tekrar yükleyip kullanabilmek istiyorsunuz. Bu tür durumlar için disk klonlama araçları imdada yetişiyor.

Eski sabit diskinizin tümünü veya bir bölümünü (partititon), taşıma (migration) yapacağınız başka bir depolama aygıtına (storage device) bir klonlama yazılımı kullanarak olduğu gibi aktarmak, etkin bir çözümdür. Aynı şekilde, kurulu bir bilgisayarin sabit diskinin tümünün veya sadece belirli bir bölümünün (özellikle işletim sistemi dosyalarının bulunduğu kesim) yeniden yüklenebilir imajını almak ve daha sonra çalışma ortamında kullanılacak depolama aygıtına bu imajdan tekrar yükleme yapmak, iyi bir yedekleme/kurtarma stratejisi olacaktır.

Bir süreden beri disk klonlama ile ilgili konularda Clonezilla kullanmaktayım. Ağ üzerinden çoklu makina klonlama gibi gelişmiş özellikleri olmasına rağmen ben şu ana kadar sadece tek makina üzerinde bölüm klonlama işlevini kullandım ve işimi fazlasıyla gördü diyebilirim.

Disk klonlama gibi işlere girişildiği zaman çoğunlukla bilgisayarın durdurulması ve bir boot CD/flash ortamından ile boot etmek suretiyle çalışılması sözkonusudur. Böyle bir çalışma ortamında elinizin altında her türlü olumsuzluğa cevap verebilecek türlü araçları içeren bir yazılım en büyük ihtiyaçtır. Clonezilla'nın tam olarak bu tanıma uyduğunu düşünüyorum.

Clonezilla Live, linux dağıtımı (debian live) üzerine inşa edilmiş ve depolama aygıtları üzerinde yapılacak işler için uygun araçları içeren bir linux dağıtımı olarak düşünülebilir. Bu dağıtım açılırken depolama aygıtlarına yönelik yazılım araçları için ön yüz (front end) görevi gören bir yazılımı yükler ve kullanıcı, bu yazılımın menüleri üzerinden yapmak istediği işe uygun operasyonları başlatır.

Bu yazının devamında NTFS dosya sistemi kullanan Windows XP kurulu bir disk bölümünün yeni bir depolama aygıtına (bir SSD) taşınması sürecinde yapılanlar anlatılmıştır. Bu taşıma sürecinin başlangıcında, Windows kurulu olan kaynak disk bölümünün büyüklüğünün (source partition size, 60 GB), yeni depolama aygıtında kullanılması düşünülen hedef bölüm büyüklüğünden (target partition size, 40 GB) daha fazla olması bir sorun olarak görülmekteydi.
  • Öncelikle Clonezilla sitesinden (http://clonezilla.org/) kullanılan donanım platformuna uygun bir Clonezilla live ISO imajı indirilir. Intel Core 2 Duo işlemcisi kullanan donanım platformumuz için i686 uzantılı ISO imajı seçildi. Normalde Core 2 Duo işlemcili makinalar için AMD64 uyumlu kernel sürümü seçilmesine rağmen Clonezilla'da bu sürümle sorun yaşadık. i686 sürümü ise başarılı oldu.
  • Boot aygıtı olarak USB flash bellek kullanmayı tercih ettik. ISO imajını USB belleğine yazmak için de http://clonezilla.org/liveusb.php, adresindeki öneriye uyarak Tuxboot yazılımını (http://tuxboot.org/) kullandık.
  • Bilgisayarı kapatıp yeni diskimizi (SSD) ana kartta boştaki bir SATA portuna taktık.
  • Bilgisayarı USB flash bellek üzerinden boot ettik. USB flash belleğini çalışma esnasında rahatça çıkarabilmek için açılışta Clonezilla imajını RAM'e yükleme seçeneği seçildi. Clonezilla ayağa kalkmıştı.
  • Hedef disk yeni alınmış olup henüz bölünmemişti.
  • Clonezilla'nın diğer bir konsol penceresine geçildi (ALT + F2). Artık Linux konsolundaydık. Root olarak login olmak gerekiyordu:
    sudo su -
  • Hedef diskin aygıt tanımlayıcısı "/dev/sdb" olarak tespit edildi. Bölümleme için komut satırından fdisk kullanıldı. İlk bölüm, tipi 7 (NTFS), bootable ve büyüklüğü +40G şeklinde girilerek oluşturuldu. Şart olmamasına rağmen bu bölüm üzerinde NTFS dosya sistemi oluşturuldu:
    mkfs.ntfs /dev/sdb1 -f
  • Kaynak bölüm (/dev/sda1) büyüklüğünün hedefinkinden fazla olması nedeniyle (kaynak bölümde kullanılan alan, hedef bölümden küçük olmasına rağmen) Clonezilla'nın standart arayüz menüsü üzerinden yapılan ilk klonlama girişimi (doğal olarak) başarısız oldu. Clonezilla, kaynak bölümün hedef bölümden küçük veya hedef bölüme eşit olmasını istemekteydi.
  • Hemen pes edilmedi. Clonezilla menüsünden konsol penceresine geçilerek root olarak login olundu. Kaynak diskin hedef diskten küçük hale getirilmesi gerekiyordu. Önce bölüm içinde kullanılan alan dikkate alınarak en fazla ne kadar küçültme yapılabileceği öğrenildi:
    ntfsresize -i /dev/sda1
    Kullanılan alan 40GB'ın altında olduğundan bu değere kadar küçültme yapmak mümkündü. Volüm, 40GB büyüklüğüne indirildi:
    ntfsresize -s 40G /dev/sda1
  • Bu işlemin bölüm büyüklüğüne yansıması için kaynak disk üzerinde komut satırından fdisk uygulaması yapıldı. Bunun için fdisk içinden önce /dev/sda1 silindi. Sonra bölüm, tipi 7 (NTFS), bootable ve büyüklüğü +40G şeklinde girilerek tekrar oluşturuldu. Böylece bölüm büyüklüğü de 40GB düzeyine çekilmiş oldu. DİKKAT! Burada fdisk ile seçilen yeni bölüm büyüklüğünün, ntfsresize ile verilen değerden küçük olmaması gerekiyor (büyük olabilir), aksi taktirde kaynak bölümü tüm verisi ile kaybedilir.
  • Bilgisayar tekrar eski disk üzerinden boot edildi. Windows içinden aşağıdaki komut çalıştırılarak bir sonraki açılışta Windows, disk taraması yapmaya zorlanmış oldu.
    chkdsk c: /F
  • Windows reboot edilerek açılışta otomatik disk taraması yaptırıldı.
  • Herşey yolunda olunca makina tekrar kapatıldı. Eski disk anakartta bağlı olduğu SATA portundan çıkararak başka bir SATA portuna takıldı. Yeni disk (SSD) ise eski diskin daha önce takılı olduğu SATA portuna takıldı.
  • Bilgisayar tekrar USB flash bellek üzerinden boot edilerek Clonezilla çalıştırıldı. Kaynak disk bölümünden hedef disk bölümüne klonlama yapıldı.
  • Klonlama bittikten sonra bilgisayar kapatıldı. Eski disk çıkarıldı ve açılış yeni disk üzerinden yapıldı.
Burada eski disk bölümünün ntfsresize ve fdisk ikilisi ile boyutunun azaltılması işlemi dikkatli yapılması gereken bir işlem. fdisk ile verilen bölüm büyüklüğünün ntfsresize ile verilenden küçük olmaması gerekiyor. Hata yapılırsa bölümü tüm verisiyle kaybedebilirsiniz.

Linkler: