ProvaPratica 2013.09.13

From Sistemi Operativi
Revision as of 00:58, 5 March 2014 by Edu san (talk | contribs) (Created page with "[C esercizio 1 e 2] <syntaxhighlight lang="C"> /*********************************************************************** * Prova Pratica di Laboratorio di Sistemi Operativi ...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

[C esercizio 1 e 2]

 /***********************************************************************
 * Prova Pratica di Laboratorio di Sistemi Operativi			*
 * 13 settembre 2013							*
 * Esercizio 1+2							*
 * 									*
 * URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.09.13.pdf 	*
 * Autore: Eduardo Santarelli						*
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>

/* An entry in the hash table. */
typedef struct fileEntry{

	const char *filename;
	struct fileEntry *next;

} fileEntry;


/* Global variables */
fileEntry **table = NULL;
int table_size;

/* Hash function. Calculates XOR of 8-bytes blocks		*
 * (actually, sizeof(long int)) read from the input file	*/
unsigned int hash(const char *fname){

	FILE *f;
	unsigned long int hash_val = 0;
	unsigned long int tmp = 0;

	f = fopen(fname, "r");
	fread(&hash_val, sizeof(unsigned long int), 1, f);

	while((fread(&tmp, sizeof(unsigned long int), 1, f) == 1))
		hash_val = hash_val^tmp;

	fclose(f);
	return hash_val;

}


/* Creates a table of struct fileEntry elements, based on the hash values of the files	*
 * detected by scandir. If a collision is detected, the new entry is pointed by the	*
 * 'next' field of the current last element*/
void populate_table(struct dirent *dir_list[], int n){

	int i;
	
	table_size = 2*n;	
	table = (fileEntry**)calloc(table_size, sizeof(fileEntry));
	if(!table) abort();

	for(i=0; i<n; i++){
		unsigned int index;
		fileEntry *entry = NULL;

		entry = (fileEntry*)malloc(sizeof(fileEntry));
		if(!entry) abort();

		index = hash(dir_list[i]->d_name)%table_size;
		if(table[index] == NULL){
			entry->filename = dir_list[i]->d_name;
			entry->next = NULL;
			table[index] = entry;
		}
		else{
			entry->filename = dir_list[i]->d_name;
			entry->next = table[index];
			table[index] = entry;
		}
	}


}


/* Compares two files */
int fcompare(const char *f1, const char *f2){

	FILE *f, *g;
	int file1, file2;	

	f = fopen(f1, "r");
	g = fopen(f2, "r");

	while(fread(&file1, sizeof(int), 1, f) && fread(&file2, sizeof(int), 1, g)){
		if(file1!=file2){
			fclose(f);
			fclose(g);
			return 0;
 		}
	}
	fclose(f);
	fclose(g);
	return 1;

}
		

/* This function scans the file table. If an entry contains more than one file,	*
 * it compares all them. If a duplicate is found, the first file is removed,  	*
 * and a hard link is created with the deleted file's name, pointing to the	*
 * second, identical, file.							*/
void deduplicate(){

	int i;

	for(i=0; i<table_size; i++){
		while(table[i] != NULL && table[i]->next != NULL){

			fileEntry *file1, *file2;
			file1 = table[i];
			file2 = table[i]->next;
			while(file2 != NULL){
				if(fcompare(file1->filename, file2->filename)){
					unlink(file1->filename);
					link(file2->filename, file1->filename);
					printf("%s -> %s\n", file1->filename, file2->filename);
					break;
				}
				file2 = file2->next;
			}
			table[i] = table[i]->next;
		}
	}
}


/*selector function for scandir() */
int exclude(const struct dirent *dir){

	if(dir->d_type != DT_REG)
		return 0;
	else
		return 1;

}


int main(int argc, char *argv[]){

	struct dirent **entries = NULL;
	int num_files;

	num_files = scandir(".", &entries, exclude, alphasort);

	populate_table(entries, num_files);
	deduplicate();

	return EXIT_SUCCESS;

}