Herşeyden önce Soma'daki kömür madeni kazasından ötürü herkese baş sağlığı dileyerek başlıyorum.
Birşeyler
yazmayalı ve yayınlamayalı çok uzun zaman olmuştu. Bu zaman zarfında,
bilgisayarı yenileyince başta Euro Truck Simulator gibi her erkeğin
hayali olan saçma sapan oyunlar yada eski bilgisayarımda çalışmayan ve
uzun zamandır oynamak istediğim oyunlardan dolayı hemen hiçbirşey
yapmadığım gibi yazmaya da zaman ayırmadım. O nedenle neredeyse
üzerinden bir yıl geçecek olan yazı dizisine hiçbirşey olmamış gibi
devam ediyorum. Bir de 4-5 hafta sonrasına yazılması gereken bir rapor
var, onu yazmamak için blog yazayım dedim.
Önce
seri sürümünün kodunu açıklayacağım. Daha önceki yazılarda da söyledim,
benim yazdığım seri sürümden çok daha iyi (ve hızlı) sürümler
internette de bulunabilir. Benim yaptığım tek yenilik sözlük dosyasını
bilgisayarlar arasında bölüp işlemi paralelleştirmek oldu.
Kodla
ilgili açıklamaları yine kodun içerisinde açıklama satırlarında yaptım.
Bölük pörçük olmaması için kodu bölen başka bir açıklama girmeyeceğim.
Uzun yorum satırları bölünmesin diye karakter boyutunu küçülttüm.
İnceleyecek olan zaten kodu Notepad++ yada gedit gibi bir programda
inceleyebilirse daha iyi olur.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// unrar kutuphanesine ait header dosyalari
#include<raros.hpp>
#include<dll.hpp>
void DosyaCoz(char *arsiv, int sira) {
// dosya adlari acik, dosya sifreliyse cozme islemi
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi; // RAR dosyayla ilgili veriler
struct RARHeaderData *Baslik; // RAR icerisindeki dosyalarla ilgili veriler
char sozluk[] = "sozluk.txt"; // sozluk.txt denenecek kelimelerin oldugu dosya
char kelime[256];
FILE *hDosya;
int status, k1, k2 = 0;
hDosya = fopen(sozluk, "r");
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
while(!feof(hDosya)) {
// sozlukten bir kelime oku
fscanf(hDosya, "%s", kelime);
// RAR kutuphanesinin dosya acmak icin kullandigi yapi
AcmaVerisi->ArcName = arsiv;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
// RAR dosyasini ac.
hArsiv = RAROpenArchive(AcmaVerisi);
Baslik->CmtBuf = NULL;
for(k1 = 0; k1 < (sira - 1); k1++) {
// ilk sifreli dosyaya kadar oku, yalnizca bazi dosyalar sifrelenmis
// olabilir.
RARReadHeader(hArsiv, Baslik);
RARProcessFile(hArsiv, RAR_SKIP, NULL, NULL);
}
// ilk sifreli dosyayi oku
RARReadHeader(hArsiv, Baslik);
RARSetPassword(hArsiv, kelime);
// sifreyle birlikte dosyayi test et. eger sifir dondururse sifre dogrudur.
status = RARProcessFile(hArsiv, RAR_TEST, NULL, NULL);
fprintf(stdout, "%8d", ++k2);
fflush(stdout);
if(status == 0) break; // dogru sifre bulunduysa donguyu sonlandir.
RARCloseArchive(hArsiv);
}
// sozluk.txt'nin sonuna gelinmemisse (break ile cikildiysa) sifre bulunmustur
if(!feof(hDosya))
// sifre bulunduysa ekrana yaz
printf("Sifre: %s\n", kelime);
else
printf("Sifre bulunamadi.\n\n");
fclose(hDosya);
return;
}
void ArsivCoz(char *arsiv) {
// dosya adlari sifrelenmisse cozme altprogrami
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi; // RAR dosyayla ilgili veriler
struct RARHeaderData *Baslik; // RAR icerisindeki dosyalarla ilgili veriler
char sozluk[] = "sozluk.txt"; // sozluk.txt denenecek kelimelerin oldugu dosya
char kelime[256];
FILE *hDosya;
int status;
hDosya = fopen(sozluk, "r");
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
while(!feof(hDosya)) {
// sozlukten bir kelime oku
fscanf(hDosya, "%s", kelime);
// RAR kutuphanesinin dosya acmak icin kullandigi yapiyi doldur:
AcmaVerisi->ArcName = arsiv;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
// doldurulan verilerle RAR dosyayi ac
hArsiv = RAROpenArchive(AcmaVerisi);
Baslik->CmtBuf = NULL;
RARSetPassword(hArsiv, kelime);
// sifreyi belirttikten sonra RAR dosya basligini oku
status = RARReadHeader(hArsiv, Baslik);
// eger baslik okuma isi basariyla sonlanmissa status'da sifir degeri
// doner. yani sifre bulunmus olur. bu durumda donguyu sonlandir.
if(status == 0) break;
RARCloseArchive(hArsiv);
}
// sozluk.txt'nin sonuna gelinmemisse (break ile cikildiysa) sifre bulunmustur
if(!feof(hDosya))
// sifre bulunduysa ekrana yaz
printf("Sifre: %s\n", kelime);
else
printf("Sifre bulunamadi.\n\n");
fclose(hDosya);
return;
}
int main(int argc, char *argv[]) {
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi;
struct RARHeaderData *Baslik;
char dosyaadi[] = "deneme1.rar";
// programa parametre olarak herhangi bir dosya adi belirtilmezse bu dosya
// adindaki RAR dosyayi acmaya calisir.
int status, k1 = 0, k2 = 1;
// RAR dosyanin acma verisi icin bellek ayir. malloc'un sonucunu kontrol
// ettirmedim, ancak istenirse bu kontrol eklenebilir.
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
// programa bir arguman dosya adi verildiyse bu dosya adini ac.
if(argc > 1) strcpy(dosyaadi, argv[1]);
AcmaVerisi->ArcName = dosyaadi;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
if((hArsiv = RAROpenArchive(AcmaVerisi)) == NULL) {
// dosyayi bulamazsa
printf("Arsivi acma basarisiz oldu.\n");
return 1;
}
// RAR dosyayi ac, baslik icin gereken yapilari bellekte ayir.
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
Baslik->CmtBuf = NULL; // RAR dosyadaki yorumlar okunmayacak
while(1) {
// RAR dosya icerisindeki dosya bilgilerini oku
status = RARReadHeader(hArsiv, Baslik);
// eger RAR dosyanin sonuna gelindiyse while'i sonlandir.
if(status == ERAR_END_ARCHIVE) break;
// dosya adlari sifrelenmisse ArsivCoz fonksiyonu cagirilacak
if(status == ERAR_MISSING_PASSWORD) {
printf("Dosya adlari sifrelenmis.\n");
ArsivCoz(dosyaadi);
break;
}
k1 = k1 + k2; // ilk adimda k1 = 0, k2 = 1. eger bir tane sifrelenmis
// dosya varsa k2 = 0 olacak, sayma islemi sonlandirilacak.
printf("Arsivdeki dosyanin adi: %s", Baslik->ArcName);
if(Baslik->Flags & 0x04) { // flags'da 3. bitin set edilmesi dosyanin
printf("*\n"); // sifrelendigini gosterir. sifrelenmis
k2 = 0; // dosyayi yaninda * ile ekrana yazip dosya
} // sayimini sonlandir.
else printf("\n"); // dosya sifrelenmemisse * koyma
status = RARProcessFile(hArsiv, RAR_SKIP, NULL, NULL); // bir sonraki dosyaya gec
if(status != 0) printf("Dosyalari islerken birseyler oldu (%d).\n", status);
}
RARCloseArchive(hArsiv);
// k1'de ilk sifreli dosyanin numarasi var.
if(status != ERAR_MISSING_PASSWORD)
// eger MISSING_PASSWORD varsa zaten tum dosya sifrelidir.
// tek bir dosya sifreliyse DosyaCoz fonksiyonunu cagir.
DosyaCoz(dosyaadi, k1);
return 0;
}
#include<stdlib.h>
#include<string.h>
// unrar kutuphanesine ait header dosyalari
#include<raros.hpp>
#include<dll.hpp>
void DosyaCoz(char *arsiv, int sira) {
// dosya adlari acik, dosya sifreliyse cozme islemi
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi; // RAR dosyayla ilgili veriler
struct RARHeaderData *Baslik; // RAR icerisindeki dosyalarla ilgili veriler
char sozluk[] = "sozluk.txt"; // sozluk.txt denenecek kelimelerin oldugu dosya
char kelime[256];
FILE *hDosya;
int status, k1, k2 = 0;
hDosya = fopen(sozluk, "r");
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
while(!feof(hDosya)) {
// sozlukten bir kelime oku
fscanf(hDosya, "%s", kelime);
// RAR kutuphanesinin dosya acmak icin kullandigi yapi
AcmaVerisi->ArcName = arsiv;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
// RAR dosyasini ac.
hArsiv = RAROpenArchive(AcmaVerisi);
Baslik->CmtBuf = NULL;
for(k1 = 0; k1 < (sira - 1); k1++) {
// ilk sifreli dosyaya kadar oku, yalnizca bazi dosyalar sifrelenmis
// olabilir.
RARReadHeader(hArsiv, Baslik);
RARProcessFile(hArsiv, RAR_SKIP, NULL, NULL);
}
// ilk sifreli dosyayi oku
RARReadHeader(hArsiv, Baslik);
RARSetPassword(hArsiv, kelime);
// sifreyle birlikte dosyayi test et. eger sifir dondururse sifre dogrudur.
status = RARProcessFile(hArsiv, RAR_TEST, NULL, NULL);
fprintf(stdout, "%8d", ++k2);
fflush(stdout);
if(status == 0) break; // dogru sifre bulunduysa donguyu sonlandir.
RARCloseArchive(hArsiv);
}
// sozluk.txt'nin sonuna gelinmemisse (break ile cikildiysa) sifre bulunmustur
if(!feof(hDosya))
// sifre bulunduysa ekrana yaz
printf("Sifre: %s\n", kelime);
else
printf("Sifre bulunamadi.\n\n");
fclose(hDosya);
return;
}
void ArsivCoz(char *arsiv) {
// dosya adlari sifrelenmisse cozme altprogrami
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi; // RAR dosyayla ilgili veriler
struct RARHeaderData *Baslik; // RAR icerisindeki dosyalarla ilgili veriler
char sozluk[] = "sozluk.txt"; // sozluk.txt denenecek kelimelerin oldugu dosya
char kelime[256];
FILE *hDosya;
int status;
hDosya = fopen(sozluk, "r");
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
while(!feof(hDosya)) {
// sozlukten bir kelime oku
fscanf(hDosya, "%s", kelime);
// RAR kutuphanesinin dosya acmak icin kullandigi yapiyi doldur:
AcmaVerisi->ArcName = arsiv;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
// doldurulan verilerle RAR dosyayi ac
hArsiv = RAROpenArchive(AcmaVerisi);
Baslik->CmtBuf = NULL;
RARSetPassword(hArsiv, kelime);
// sifreyi belirttikten sonra RAR dosya basligini oku
status = RARReadHeader(hArsiv, Baslik);
// eger baslik okuma isi basariyla sonlanmissa status'da sifir degeri
// doner. yani sifre bulunmus olur. bu durumda donguyu sonlandir.
if(status == 0) break;
RARCloseArchive(hArsiv);
}
// sozluk.txt'nin sonuna gelinmemisse (break ile cikildiysa) sifre bulunmustur
if(!feof(hDosya))
// sifre bulunduysa ekrana yaz
printf("Sifre: %s\n", kelime);
else
printf("Sifre bulunamadi.\n\n");
fclose(hDosya);
return;
}
int main(int argc, char *argv[]) {
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi;
struct RARHeaderData *Baslik;
char dosyaadi[] = "deneme1.rar";
// programa parametre olarak herhangi bir dosya adi belirtilmezse bu dosya
// adindaki RAR dosyayi acmaya calisir.
int status, k1 = 0, k2 = 1;
// RAR dosyanin acma verisi icin bellek ayir. malloc'un sonucunu kontrol
// ettirmedim, ancak istenirse bu kontrol eklenebilir.
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
// programa bir arguman dosya adi verildiyse bu dosya adini ac.
if(argc > 1) strcpy(dosyaadi, argv[1]);
AcmaVerisi->ArcName = dosyaadi;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
if((hArsiv = RAROpenArchive(AcmaVerisi)) == NULL) {
// dosyayi bulamazsa
printf("Arsivi acma basarisiz oldu.\n");
return 1;
}
// RAR dosyayi ac, baslik icin gereken yapilari bellekte ayir.
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
Baslik->CmtBuf = NULL; // RAR dosyadaki yorumlar okunmayacak
while(1) {
// RAR dosya icerisindeki dosya bilgilerini oku
status = RARReadHeader(hArsiv, Baslik);
// eger RAR dosyanin sonuna gelindiyse while'i sonlandir.
if(status == ERAR_END_ARCHIVE) break;
// dosya adlari sifrelenmisse ArsivCoz fonksiyonu cagirilacak
if(status == ERAR_MISSING_PASSWORD) {
printf("Dosya adlari sifrelenmis.\n");
ArsivCoz(dosyaadi);
break;
}
k1 = k1 + k2; // ilk adimda k1 = 0, k2 = 1. eger bir tane sifrelenmis
// dosya varsa k2 = 0 olacak, sayma islemi sonlandirilacak.
printf("Arsivdeki dosyanin adi: %s", Baslik->ArcName);
if(Baslik->Flags & 0x04) { // flags'da 3. bitin set edilmesi dosyanin
printf("*\n"); // sifrelendigini gosterir. sifrelenmis
k2 = 0; // dosyayi yaninda * ile ekrana yazip dosya
} // sayimini sonlandir.
else printf("\n"); // dosya sifrelenmemisse * koyma
status = RARProcessFile(hArsiv, RAR_SKIP, NULL, NULL); // bir sonraki dosyaya gec
if(status != 0) printf("Dosyalari islerken birseyler oldu (%d).\n", status);
}
RARCloseArchive(hArsiv);
// k1'de ilk sifreli dosyanin numarasi var.
if(status != ERAR_MISSING_PASSWORD)
// eger MISSING_PASSWORD varsa zaten tum dosya sifrelidir.
// tek bir dosya sifreliyse DosyaCoz fonksiyonunu cagir.
DosyaCoz(dosyaadi, k1);
return 0;
}
Bu arada program kodunu vim'de yazıp Notepad++'ya aktardım. Vim'de tabstop 8, Notepad++'da 4 karakter. Bu nedenle de kodun bazı yerlerinde hizalama (indentation) kaydı. Beni suçlamak yerine alıcılarınızın ayarlarıyla oynayın lütfen.
Gelelim bilgisayarına MPI kuracaklar veya hesaplama kümesi erişimi olanlar için asıl olay paralel koda:
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<mpi.h>
// unrar kutuphanesine ait header dosyalari
#include<raros.hpp>
#include<dll.hpp>
#define MAX_PASS_LENGTH 16
#define MAX_NAME_LENGTH 256 // olabilecek en uzun dosya adi.
#define CALL_ArsivCoz 0x04
#define CALL_DosyaCoz 0x08
#define TAG 0x10
void DosyaCoz(char *arsiv, char *sozluk, int blksiz, int ofset, int sira) {
/*
DosyaCoz(...): Dosya adlari acik, dosya sifreliyse cozme islemi
arsiv: RAR dosyanin adini tutan string.
sozluk: Sifrelerin listelendigi sozluk dosyasinin adini tutan string
blksiz: her bir islemciye sozluk dosyasindan dusen kelime sayisi
ofset: her islemcinin sozluk dosyasinin hangi satirini okuyacagi
sira: sifresi cozulecek dosyanin arsiv dosyasindaki sirasi
*/
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi; // RAR dosyayla ilgili veriler
struct RARHeaderData *Baslik; // RAR icerisindeki dosyalarla ilgili veriler
char kelime[MAX_PASS_LENGTH];
FILE *hDosya;
int status, k1, k2, rank;
double sure;
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // MPI uzayinda kacinci islemciyim?
sure = MPI_Wtime(); // sure olcumunu baslat
#ifdef DEBUG
printf("(%d): blok buyuklugu: %d, ofset: %d\n", rank, blksiz, ofset);
#endif
hDosya = fopen(sozluk, "r");
for(k2 = 0; k2 < ofset; k2++)
fgets(kelime, MAX_PASS_LENGTH, hDosya);
// her islemci kendi okuyacagi yere kadar gelsin
// RAR dosya ve icindeki verileri acmak icin gerekli yapilari bellekte ayir
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
// burada malloc'un dondurdugu degerlerin test edilmesi eksik
k2 = 0;
while(k2 < blksiz) {
// sozlukten bir kelime oku
fscanf(hDosya, "%s", kelime);
#ifdef DEBUG
printf("(%d): (sayac %d) denenen kelime: %s\n", rank, k2, kelime);
fflush(stdout);
#endif
// RAR kutuphanesinin dosya acmak icin kullandigi yapi
AcmaVerisi->ArcName = arsiv;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
// RAR dosyasini ac
hArsiv = RAROpenArchive(AcmaVerisi);
Baslik->CmtBuf = NULL;
for(k1 = 0; k1 < (sira - 1); k1++) {
// ilk sifreli dosyaya kadar oku, yalnizca bazi dosyalar sifrelenmis
// olabilir.
RARReadHeader(hArsiv, Baslik);
RARProcessFile(hArsiv, RAR_SKIP, NULL, NULL);
}
// ilk sifreli dosyayi oku
RARReadHeader(hArsiv, Baslik);
RARSetPassword(hArsiv, kelime);
// sifreyle birlikte dosyayi test et. eger sifir dondururse sifre dogrudur.
status = RARProcessFile(hArsiv, RAR_TEST, NULL, NULL);
if(status == 0) break; // dogru sifre bulunduysa donguyu sonlandir
RARCloseArchive(hArsiv);
k2++;
}
if(k2 < blksiz) { // dongu bitiminde islemci kendisine dusen blogun
// sonuna gelmemisse arada bir yerde sifreyi buldu demektir.
printf("Sifre: %s\n", kelime);
MPI_Abort(MPI_COMM_WORLD, 8);
}
else
printf("Sifre bulunamadi.\n\n");
printf("Islemci %d icin calisma suresi %f saniye.\n", rank, MPI_Wtime() - sure);
fclose(hDosya);
return;
}
void ArsivCoz(char *arsiv, char *sozluk, int blksiz, int ofset) {
/*
ArsivCoz(...): Dosya adlari sifrelenmisse cozme algoritmasi
arsiv: RAR dosyanin adini tutan string.
sozluk: Sifrelerin listelendigi sozluk dosyasinin adini tutan string
blksiz: her bir islemciye sozluk dosyasindan dusen kelime sayisi
ofset: her islemcinin sozluk dosyasinin hangi satirini okuyacagi
*/
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi; // RAR dosyasiyla ilgili veriler
struct RARHeaderData *Baslik; // RAR icerisindeki dosyalarla ilgili veriler
char kelime[MAX_PASS_LENGTH];
FILE *hDosya;
int status, k1, rank;
double sure;
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // MPI uzayinda kacinci islemciyim?
sure = MPI_Wtime(); // sure olcumunu baslat..
#ifdef DEBUG
printf("(%d): blok buyuklugu: %d, ofset: %d\n", rank, blksiz, ofset);
#endif
hDosya = fopen(sozluk, "r");
for(k1 = 0; k1 < ofset; k1++)
fgets(kelime, MAX_PASS_LENGTH, hDosya);
// herkes sozluk dosyasinda kendi okuyacagi yere kadar gelsin
// RAR dosya ve icindeki verileri acmak icin gerekli yapilari bellekte ayir
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
// burada malloc'un dondurdugu degerlerin test edilmesi eksik
k1 = 0;
while(k1 < blksiz) {
// sozlukten bir kelime oku
fgets(kelime, MAX_PASS_LENGTH, hDosya);
#ifdef DEBUG
printf("(%d): (sayac %d) denenen kelime: %s\n", rank, k1, kelime);
fflush(stdout);
#endif
// RAR kutuphanesinin dosya acmak icin kullandigi yapiyi doldur
AcmaVerisi->ArcName = arsiv;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
// doldurulan verilerle RAR dosyayi ac
hArsiv = RAROpenArchive(AcmaVerisi);
// CommentBuffer = NULL : Comment'leri okuma
Baslik->CmtBuf = NULL;
RARSetPassword(hArsiv, kelime);
// sifreyi belirttikten sonra RAR dosya basligini oku
status = RARReadHeader(hArsiv, Baslik);
// eger baslik okuma isi basariyla sonlanmissa status'da sifir degeri
// doner yani sifre bulunmus olur. bu durumda donguyu sonlandir.
if(status == 0) break;
RARCloseArchive(hArsiv);
k1++;
}
if(k1 < blksiz) { // dongu bitiminde islemci kendisine dusen blogun
// sonuna gelmemisse arada bir yerde sifreyi buldu demektir.
printf("Sifre: %s\n", kelime);
MPI_Abort(MPI_COMM_WORLD, 9);
}
else
printf("Sifre bulunamadi.\n\n");
printf("Islemci %d icin calisma suresi %f saniye.\n", rank, MPI_Wtime() - sure);
fclose(hDosya);
return;
}
int main(int argc, char *argv[]) {
FILE *hSozluk;
int size, rank, nsatir, krkt, mesaj, blksiz, ofset, status;
int k1 = 0, k2 = 1;
HANDLE PASCAL *hArsiv;
struct RAROpenArchiveData *AcmaVerisi;
struct RARHeaderData *Baslik;
char dosyaadi[MAX_NAME_LENGTH];
char sozluk[MAX_NAME_LENGTH] = "sozluk.txt";
char tmp[MAX_PASS_LENGTH];
double sure;
MPI_Init(&argc, &argv);
// MPI'i initle, islemci sayisini ve sira sayilarini al.
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
sure = MPI_Wtime();
if(argc > 1) {
// RAR dosyanin adi programa arguman olarak verilir.
strcpy(dosyaadi, argv[1]);
// eger birden fazla arguman verilmisse ikinci arguman sozluk dosyasidir
if(argc > 2) strcpy(sozluk, argv[2]);
}
else {
if(rank == 0) printf("Kullanim: rarsolve <dosyaadi.rar> [sozluk.txt]\n");
MPI_Abort(MPI_COMM_WORLD, 1);
return 1;
}
if(rank == 0) {
// sifirinci islemci sozlugun satir sayisini belirler
hSozluk = fopen(sozluk, "r");
nsatir = 0;
do {
krkt = fgetc(hSozluk);
if(krkt == '\n') nsatir++;
} while(krkt != EOF);
fclose(hSozluk);
}
// satir sayisini butun islemcilere bildir.
MPI_Bcast(&nsatir, 1, MPI_INT, 0, MPI_COMM_WORLD);
blksiz = nsatir / size;
ofset = rank * blksiz;
// herkes kendine dusen sozluk blogunu ve ilk kelimesini bulsun
if((nsatir % size) && (rank == (size - 1)))
blksiz = nsatir - (blksiz * size - blksiz);
// tamsayi duzenlemeleri
if(rank == 0) {
// RAR dosyanin acma verisi icin bellekte yer ayir.
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
AcmaVerisi->ArcName = dosyaadi;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
if((hArsiv = RAROpenArchive(AcmaVerisi)) == NULL) {
// dosyayi bulamazsa
printf("Arsivi acma basarisiz oldu.\n");
MPI_Abort(MPI_COMM_WORLD, 2);
return 2;
}
// RAR dosyayi ac, baslik icin gereken yapilari bellekte ayir.
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
Baslik->CmtBuf = NULL; // RAR dosyadaki yorumlar okunmayacak
while(1) {
// RAR arsivi icerisindeki dosya bilgilerini oku.
status = RARReadHeader(hArsiv, Baslik);
// eger RAR dosyanin sonuna gelindiyse while'i sonlandir.
if(status == ERAR_END_ARCHIVE) break;
// dosya adlari sifrelenmisse ArsivCoz fonksiyonu cagirilacak.
if(status == ERAR_MISSING_PASSWORD) {
printf("Dosya adlari sifrelenmis.\n");
mesaj = CALL_ArsivCoz;
for(krkt = 1; krkt < size; krkt++)
// sifirinci butun islemcilere ArsivCoz fonksiyonunun
// cagirilacagini mesajla bildiriyor.
MPI_Send(&mesaj, 1, MPI_INT, krkt, TAG, MPI_COMM_WORLD);
// sifirinci islemcinin kendisi de ArsivCoz'u cagiriyor.
ArsivCoz(dosyaadi, sozluk, blksiz, ofset);
break;
}
k1 = k1 + k2; // ilk adimda k1 = 0, k2 = 1. eger bir tane sifrelenmis dosya varsa
// k2 = 0 olacak, sayma islemi sonlandirilacak.
printf("Arsiv adi: %s", Baslik->ArcName);
if(Baslik->Flags & 0x04) { // flags'da 3. bitin set edilmesi
printf("*\n"); // dosyanin sifrelendigini gosterir.
k2 = 0; // sifrelenmis dosyayi yaninda * ile yaz
}
else printf("\n");
status = RARProcessFile(hArsiv, RAR_SKIP, NULL, NULL); // bir sonraki dosyaya gec
if(status != 0) printf("Dosyalari islerken birseyler oldu (%d).\n", status);
}
RARCloseArchive(hArsiv);
// k1'de ilk sifreli dosyanin numarasi var.
if(status != ERAR_MISSING_PASSWORD) {
// eger MISSING_PASSWORD varsa zaten tum dosya sifrelidir.
mesaj = CALL_DosyaCoz;
// sifirinci islemci diger islemcilere DosyaCoz fonksiyonunun
// cagirilacagini mesajla bildiriyor
for(krkt = 1; krkt < size; krkt++)
MPI_Send(&mesaj, 1, MPI_INT, krkt, TAG, MPI_COMM_WORLD);
// sifirinci islemcinin kendisi de ArsivCoz'u cagiriyor.
DosyaCoz(dosyaadi, sozluk, blksiz, ofset, k1);
}
}
else {
// sifirinci islemci haricindeki islemciler sifirincidan mesaj bekliyor
MPI_Recv(&mesaj, 1, MPI_INT, 0, TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
if(mesaj == CALL_ArsivCoz)
ArsivCoz(dosyaadi, sozluk, blksiz, ofset);
else if(mesaj == CALL_DosyaCoz)
DosyaCoz(dosyaadi, sozluk, blksiz, ofset, k1);
}
if(rank == 0)
printf("Toplam %f saniyede %d kelime denendi.\n", MPI_Wtime() - sure, nsatir);
MPI_Finalize();
return 0;
}
#include<string.h>
#include<stdio.h>
#include<mpi.h>
// unrar kutuphanesine ait header dosyalari
#include<raros.hpp>
#include<dll.hpp>
#define MAX_PASS_LENGTH 16
#define MAX_NAME_LENGTH 256 // olabilecek en uzun dosya adi.
#define CALL_ArsivCoz 0x04
#define CALL_DosyaCoz 0x08
#define TAG 0x10
void DosyaCoz(char *arsiv, char *sozluk, int blksiz, int ofset, int sira) {
/*
DosyaCoz(...): Dosya adlari acik, dosya sifreliyse cozme islemi
arsiv: RAR dosyanin adini tutan string.
sozluk: Sifrelerin listelendigi sozluk dosyasinin adini tutan string
blksiz: her bir islemciye sozluk dosyasindan dusen kelime sayisi
ofset: her islemcinin sozluk dosyasinin hangi satirini okuyacagi
sira: sifresi cozulecek dosyanin arsiv dosyasindaki sirasi
*/
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi; // RAR dosyayla ilgili veriler
struct RARHeaderData *Baslik; // RAR icerisindeki dosyalarla ilgili veriler
char kelime[MAX_PASS_LENGTH];
FILE *hDosya;
int status, k1, k2, rank;
double sure;
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // MPI uzayinda kacinci islemciyim?
sure = MPI_Wtime(); // sure olcumunu baslat
#ifdef DEBUG
printf("(%d): blok buyuklugu: %d, ofset: %d\n", rank, blksiz, ofset);
#endif
hDosya = fopen(sozluk, "r");
for(k2 = 0; k2 < ofset; k2++)
fgets(kelime, MAX_PASS_LENGTH, hDosya);
// her islemci kendi okuyacagi yere kadar gelsin
// RAR dosya ve icindeki verileri acmak icin gerekli yapilari bellekte ayir
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
// burada malloc'un dondurdugu degerlerin test edilmesi eksik
k2 = 0;
while(k2 < blksiz) {
// sozlukten bir kelime oku
fscanf(hDosya, "%s", kelime);
#ifdef DEBUG
printf("(%d): (sayac %d) denenen kelime: %s\n", rank, k2, kelime);
fflush(stdout);
#endif
// RAR kutuphanesinin dosya acmak icin kullandigi yapi
AcmaVerisi->ArcName = arsiv;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
// RAR dosyasini ac
hArsiv = RAROpenArchive(AcmaVerisi);
Baslik->CmtBuf = NULL;
for(k1 = 0; k1 < (sira - 1); k1++) {
// ilk sifreli dosyaya kadar oku, yalnizca bazi dosyalar sifrelenmis
// olabilir.
RARReadHeader(hArsiv, Baslik);
RARProcessFile(hArsiv, RAR_SKIP, NULL, NULL);
}
// ilk sifreli dosyayi oku
RARReadHeader(hArsiv, Baslik);
RARSetPassword(hArsiv, kelime);
// sifreyle birlikte dosyayi test et. eger sifir dondururse sifre dogrudur.
status = RARProcessFile(hArsiv, RAR_TEST, NULL, NULL);
if(status == 0) break; // dogru sifre bulunduysa donguyu sonlandir
RARCloseArchive(hArsiv);
k2++;
}
if(k2 < blksiz) { // dongu bitiminde islemci kendisine dusen blogun
// sonuna gelmemisse arada bir yerde sifreyi buldu demektir.
printf("Sifre: %s\n", kelime);
MPI_Abort(MPI_COMM_WORLD, 8);
}
else
printf("Sifre bulunamadi.\n\n");
printf("Islemci %d icin calisma suresi %f saniye.\n", rank, MPI_Wtime() - sure);
fclose(hDosya);
return;
}
void ArsivCoz(char *arsiv, char *sozluk, int blksiz, int ofset) {
/*
ArsivCoz(...): Dosya adlari sifrelenmisse cozme algoritmasi
arsiv: RAR dosyanin adini tutan string.
sozluk: Sifrelerin listelendigi sozluk dosyasinin adini tutan string
blksiz: her bir islemciye sozluk dosyasindan dusen kelime sayisi
ofset: her islemcinin sozluk dosyasinin hangi satirini okuyacagi
*/
HANDLE PASCAL hArsiv;
struct RAROpenArchiveData *AcmaVerisi; // RAR dosyasiyla ilgili veriler
struct RARHeaderData *Baslik; // RAR icerisindeki dosyalarla ilgili veriler
char kelime[MAX_PASS_LENGTH];
FILE *hDosya;
int status, k1, rank;
double sure;
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // MPI uzayinda kacinci islemciyim?
sure = MPI_Wtime(); // sure olcumunu baslat..
#ifdef DEBUG
printf("(%d): blok buyuklugu: %d, ofset: %d\n", rank, blksiz, ofset);
#endif
hDosya = fopen(sozluk, "r");
for(k1 = 0; k1 < ofset; k1++)
fgets(kelime, MAX_PASS_LENGTH, hDosya);
// herkes sozluk dosyasinda kendi okuyacagi yere kadar gelsin
// RAR dosya ve icindeki verileri acmak icin gerekli yapilari bellekte ayir
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
// burada malloc'un dondurdugu degerlerin test edilmesi eksik
k1 = 0;
while(k1 < blksiz) {
// sozlukten bir kelime oku
fgets(kelime, MAX_PASS_LENGTH, hDosya);
#ifdef DEBUG
printf("(%d): (sayac %d) denenen kelime: %s\n", rank, k1, kelime);
fflush(stdout);
#endif
// RAR kutuphanesinin dosya acmak icin kullandigi yapiyi doldur
AcmaVerisi->ArcName = arsiv;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
// doldurulan verilerle RAR dosyayi ac
hArsiv = RAROpenArchive(AcmaVerisi);
// CommentBuffer = NULL : Comment'leri okuma
Baslik->CmtBuf = NULL;
RARSetPassword(hArsiv, kelime);
// sifreyi belirttikten sonra RAR dosya basligini oku
status = RARReadHeader(hArsiv, Baslik);
// eger baslik okuma isi basariyla sonlanmissa status'da sifir degeri
// doner yani sifre bulunmus olur. bu durumda donguyu sonlandir.
if(status == 0) break;
RARCloseArchive(hArsiv);
k1++;
}
if(k1 < blksiz) { // dongu bitiminde islemci kendisine dusen blogun
// sonuna gelmemisse arada bir yerde sifreyi buldu demektir.
printf("Sifre: %s\n", kelime);
MPI_Abort(MPI_COMM_WORLD, 9);
}
else
printf("Sifre bulunamadi.\n\n");
printf("Islemci %d icin calisma suresi %f saniye.\n", rank, MPI_Wtime() - sure);
fclose(hDosya);
return;
}
int main(int argc, char *argv[]) {
FILE *hSozluk;
int size, rank, nsatir, krkt, mesaj, blksiz, ofset, status;
int k1 = 0, k2 = 1;
HANDLE PASCAL *hArsiv;
struct RAROpenArchiveData *AcmaVerisi;
struct RARHeaderData *Baslik;
char dosyaadi[MAX_NAME_LENGTH];
char sozluk[MAX_NAME_LENGTH] = "sozluk.txt";
char tmp[MAX_PASS_LENGTH];
double sure;
MPI_Init(&argc, &argv);
// MPI'i initle, islemci sayisini ve sira sayilarini al.
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
sure = MPI_Wtime();
if(argc > 1) {
// RAR dosyanin adi programa arguman olarak verilir.
strcpy(dosyaadi, argv[1]);
// eger birden fazla arguman verilmisse ikinci arguman sozluk dosyasidir
if(argc > 2) strcpy(sozluk, argv[2]);
}
else {
if(rank == 0) printf("Kullanim: rarsolve <dosyaadi.rar> [sozluk.txt]\n");
MPI_Abort(MPI_COMM_WORLD, 1);
return 1;
}
if(rank == 0) {
// sifirinci islemci sozlugun satir sayisini belirler
hSozluk = fopen(sozluk, "r");
nsatir = 0;
do {
krkt = fgetc(hSozluk);
if(krkt == '\n') nsatir++;
} while(krkt != EOF);
fclose(hSozluk);
}
// satir sayisini butun islemcilere bildir.
MPI_Bcast(&nsatir, 1, MPI_INT, 0, MPI_COMM_WORLD);
blksiz = nsatir / size;
ofset = rank * blksiz;
// herkes kendine dusen sozluk blogunu ve ilk kelimesini bulsun
if((nsatir % size) && (rank == (size - 1)))
blksiz = nsatir - (blksiz * size - blksiz);
// tamsayi duzenlemeleri
if(rank == 0) {
// RAR dosyanin acma verisi icin bellekte yer ayir.
AcmaVerisi = (struct RAROpenArchiveData *)malloc(sizeof(struct RAROpenArchiveData));
AcmaVerisi->ArcName = dosyaadi;
AcmaVerisi->OpenMode = RAR_OM_EXTRACT;
AcmaVerisi->CmtBuf = NULL;
AcmaVerisi->CmtBufSize = 0;
if((hArsiv = RAROpenArchive(AcmaVerisi)) == NULL) {
// dosyayi bulamazsa
printf("Arsivi acma basarisiz oldu.\n");
MPI_Abort(MPI_COMM_WORLD, 2);
return 2;
}
// RAR dosyayi ac, baslik icin gereken yapilari bellekte ayir.
Baslik = (struct RARHeaderData *)malloc(sizeof(struct RARHeaderData));
Baslik->CmtBuf = NULL; // RAR dosyadaki yorumlar okunmayacak
while(1) {
// RAR arsivi icerisindeki dosya bilgilerini oku.
status = RARReadHeader(hArsiv, Baslik);
// eger RAR dosyanin sonuna gelindiyse while'i sonlandir.
if(status == ERAR_END_ARCHIVE) break;
// dosya adlari sifrelenmisse ArsivCoz fonksiyonu cagirilacak.
if(status == ERAR_MISSING_PASSWORD) {
printf("Dosya adlari sifrelenmis.\n");
mesaj = CALL_ArsivCoz;
for(krkt = 1; krkt < size; krkt++)
// sifirinci butun islemcilere ArsivCoz fonksiyonunun
// cagirilacagini mesajla bildiriyor.
MPI_Send(&mesaj, 1, MPI_INT, krkt, TAG, MPI_COMM_WORLD);
// sifirinci islemcinin kendisi de ArsivCoz'u cagiriyor.
ArsivCoz(dosyaadi, sozluk, blksiz, ofset);
break;
}
k1 = k1 + k2; // ilk adimda k1 = 0, k2 = 1. eger bir tane sifrelenmis dosya varsa
// k2 = 0 olacak, sayma islemi sonlandirilacak.
printf("Arsiv adi: %s", Baslik->ArcName);
if(Baslik->Flags & 0x04) { // flags'da 3. bitin set edilmesi
printf("*\n"); // dosyanin sifrelendigini gosterir.
k2 = 0; // sifrelenmis dosyayi yaninda * ile yaz
}
else printf("\n");
status = RARProcessFile(hArsiv, RAR_SKIP, NULL, NULL); // bir sonraki dosyaya gec
if(status != 0) printf("Dosyalari islerken birseyler oldu (%d).\n", status);
}
RARCloseArchive(hArsiv);
// k1'de ilk sifreli dosyanin numarasi var.
if(status != ERAR_MISSING_PASSWORD) {
// eger MISSING_PASSWORD varsa zaten tum dosya sifrelidir.
mesaj = CALL_DosyaCoz;
// sifirinci islemci diger islemcilere DosyaCoz fonksiyonunun
// cagirilacagini mesajla bildiriyor
for(krkt = 1; krkt < size; krkt++)
MPI_Send(&mesaj, 1, MPI_INT, krkt, TAG, MPI_COMM_WORLD);
// sifirinci islemcinin kendisi de ArsivCoz'u cagiriyor.
DosyaCoz(dosyaadi, sozluk, blksiz, ofset, k1);
}
}
else {
// sifirinci islemci haricindeki islemciler sifirincidan mesaj bekliyor
MPI_Recv(&mesaj, 1, MPI_INT, 0, TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
if(mesaj == CALL_ArsivCoz)
ArsivCoz(dosyaadi, sozluk, blksiz, ofset);
else if(mesaj == CALL_DosyaCoz)
DosyaCoz(dosyaadi, sozluk, blksiz, ofset, k1);
}
if(rank == 0)
printf("Toplam %f saniyede %d kelime denendi.\n", MPI_Wtime() - sure, nsatir);
MPI_Finalize();
return 0;
}
Son
olarak herşey tamamsa son bir soru kalıyor: "Sözlük dosyaları nasıl
oluşturulacak?" Onun için de basit bir MATLAB kodu yazdım. Yaptığı tek
şey belirli kriterlere göre 5 ile 10 karakter arası rastgele kelimeler
üretip bunları sozluk.txt dosyasina yazıyor. Aslında bunun için daha
amaca daha yönelik araçlar yazılabilir. Örneğin sozluk.txt olarak imla
kılavuzunu alıp imla kılavuzundaki kelimelerin başına yada sonuna
sayılar eklemek gibi. Matlab kodu görece basit olduğundan pek açıklama
yazmayacağım ancak onunla ilgili tek söyleyebileceğim 33 ve 36.
satırlardaki iki for döngüsü yüzünden bir hayli yavaş çalıştığı.
kucuk_harfler = true;
buyuk_harfler = false;
sayilar = true;
karakterler = false;
kel_sayi = 200000; % 200bin kelime uret
kHavuz = [ ];
bharf_tablo = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
kharf_tablo = 'abcdefghijklmnopqrstuvwxyz';
sayi_tablo = '0123456789';
karak_tablo = '!#$%&()*+,-./:;<=>?@_';
if(kucuk_harfler)
kHavuz = strcat(kHavuz, kharf_tablo);
end
if(buyuk_harfler)
kHavuz = strcat(kHavuz, bharf_tablo);
end
if(sayilar)
kHavuz = strcat(kHavuz, sayi_tablo);
end
if(karakterler)
kHavuz = strcat(kHavuz, karak_tablo);
end
lHavuz = length(kHavuz);
hSozluk = fopen('sozluk.txt', 'w');
for k1 = 1:kel_sayi
kelime = [ ];
uzunluk = floor(rand * 5 + 5); % kelime uzunluklari rastgele
for k2 = 1:uzunluk
Havuz_ptr = floor(rand * lHavuz + 1);
kelime = strcat(kelime, kHavuz(Havuz_ptr));
end
fprintf(hSozluk, '%s\n', kelime);
end
fclose(hSozluk);
buyuk_harfler = false;
sayilar = true;
karakterler = false;
kel_sayi = 200000; % 200bin kelime uret
kHavuz = [ ];
bharf_tablo = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
kharf_tablo = 'abcdefghijklmnopqrstuvwxyz';
sayi_tablo = '0123456789';
karak_tablo = '!#$%&()*+,-./:;<=>?@_';
if(kucuk_harfler)
kHavuz = strcat(kHavuz, kharf_tablo);
end
if(buyuk_harfler)
kHavuz = strcat(kHavuz, bharf_tablo);
end
if(sayilar)
kHavuz = strcat(kHavuz, sayi_tablo);
end
if(karakterler)
kHavuz = strcat(kHavuz, karak_tablo);
end
lHavuz = length(kHavuz);
hSozluk = fopen('sozluk.txt', 'w');
for k1 = 1:kel_sayi
kelime = [ ];
uzunluk = floor(rand * 5 + 5); % kelime uzunluklari rastgele
for k2 = 1:uzunluk
Havuz_ptr = floor(rand * lHavuz + 1);
kelime = strcat(kelime, kHavuz(Havuz_ptr));
end
fprintf(hSozluk, '%s\n', kelime);
end
fclose(hSozluk);
Buraya
kadar kodlardan ötürü bir hayli uzunca bir yazı oldu. Bu ara tekrar
yazmak için zaman bulabilirsem gerçekten ne kadar gereksiz işlerle
uğraştığımı anlatan bir yazı daha yayınlayabilirim.
Hiç yorum yok:
Yorum Gönder