#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;
}