Move code to the "src" subdirectory
This commit is contained in:
67
src/crc.c
Normal file
67
src/crc.c
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned long _crcTable[256];
|
||||
int _crcTableInitialized = 0;
|
||||
|
||||
#define CRC32_POLYNOMIAL 0xEDB88320L
|
||||
|
||||
void CRCTable_Init() {
|
||||
int i;
|
||||
int j;
|
||||
unsigned long crc;
|
||||
|
||||
if (_crcTableInitialized) {
|
||||
return;
|
||||
}
|
||||
_crcTableInitialized = 1;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
crc = i;
|
||||
for (j = 8; j > 0; j--) {
|
||||
if (crc & 1)
|
||||
crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
|
||||
else
|
||||
crc >>= 1;
|
||||
}
|
||||
_crcTable[i] = crc;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long CRC_BufferInternal(unsigned char *buffer, int len,
|
||||
unsigned long crc) {
|
||||
unsigned char *p;
|
||||
|
||||
// Calcular CRC del buffer
|
||||
p = (unsigned char*) buffer;
|
||||
while (len-- != 0) {
|
||||
unsigned long termA = (crc >> 8) & 0x00FFFFFFL;
|
||||
unsigned long termB = _crcTable[((int) crc ^ *p++) & 0xff];
|
||||
crc = termA ^ termB;
|
||||
}
|
||||
|
||||
return (crc);
|
||||
}
|
||||
|
||||
unsigned long CRC_Buffer(unsigned char *buffer, int len, unsigned long crc) {
|
||||
CRCTable_Init();
|
||||
return (CRC_BufferInternal(buffer, len, crc));
|
||||
}
|
||||
|
||||
unsigned long CRC_File(FILE *file) {
|
||||
unsigned long crc;
|
||||
unsigned char buffer[512];
|
||||
|
||||
CRCTable_Init();
|
||||
|
||||
crc = 0xFFFFFFFFL;
|
||||
for (;;) {
|
||||
// Llenar el buffer
|
||||
int count = fread(buffer, 1, 512, file);
|
||||
if (count == 0)
|
||||
break;
|
||||
|
||||
// Calcular CRC del buffer
|
||||
crc = CRC_BufferInternal(buffer, count, crc);
|
||||
}
|
||||
return (crc ^= 0xFFFFFFFFL);
|
||||
}
|
||||
9
src/crc.h
Normal file
9
src/crc.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef _CRC_
|
||||
#define _CRC_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned long CRC_Buffer(unsigned char *buffer, int len, unsigned long crc);
|
||||
unsigned long CRC_File(FILE *file);
|
||||
|
||||
#endif
|
||||
510
src/filenode.c
Normal file
510
src/filenode.c
Normal file
@@ -0,0 +1,510 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "crc.h"
|
||||
#include "fileutil.h"
|
||||
#include "filenode.h"
|
||||
|
||||
FileNode *_free_filenode = NULL;
|
||||
int _n_filenode = 0;
|
||||
#define FileNode_Block 1024
|
||||
FileNode *FileNode_Create() {
|
||||
FileNode *fileNode;
|
||||
|
||||
if (_free_filenode == NULL ) {
|
||||
FileNode *nodos;
|
||||
int i;
|
||||
// Reservar un tocho
|
||||
nodos = malloc(sizeof(FileNode) * FileNode_Block);
|
||||
for (i = 0; i < FileNode_Block - 1; i++) {
|
||||
nodos[i].next = &nodos[i + 1];
|
||||
}
|
||||
nodos[FileNode_Block - 1].next = NULL;
|
||||
_free_filenode = &nodos[0];
|
||||
}
|
||||
|
||||
// Obtener el primero libre
|
||||
fileNode = _free_filenode;
|
||||
_free_filenode = fileNode->next;
|
||||
_n_filenode++;
|
||||
|
||||
// Iniciar
|
||||
fileNode->name[0] = 0;
|
||||
fileNode->flags = 0;
|
||||
fileNode->estado = FileStatus_None;
|
||||
fileNode->size = 0;
|
||||
fileNode->crc = 0;
|
||||
fileNode->fileTime = 0;
|
||||
fileNode->child = NULL;
|
||||
fileNode->childCount = 0;
|
||||
fileNode->next = NULL;
|
||||
fileNode->parent = NULL;
|
||||
|
||||
return (fileNode);
|
||||
}
|
||||
|
||||
void FileNode_Delete(FileNode *fn) {
|
||||
fn->next = _free_filenode;
|
||||
_free_filenode = fn;
|
||||
_n_filenode--;
|
||||
}
|
||||
|
||||
void FileNode_AddChild(FileNode *fileNode, FileNode *file2) {
|
||||
if (!file2 || !fileNode)
|
||||
return;
|
||||
file2->next = fileNode->child;
|
||||
fileNode->child = file2;
|
||||
fileNode->childCount++;
|
||||
file2->parent = fileNode;
|
||||
}
|
||||
|
||||
void FileNode_SetEstadoRec(FileNode *fileNode, FileStatus estado) {
|
||||
FileNode *fn_child;
|
||||
fileNode->estado = estado;
|
||||
fn_child = fileNode->child;
|
||||
while (fn_child != NULL ) {
|
||||
FileNode_SetEstadoRec(fn_child, estado);
|
||||
fn_child = fn_child->next;
|
||||
}
|
||||
}
|
||||
|
||||
void FileNode_GetPath_Rec(FileNode *fileNode, char **pathnode) {
|
||||
if (fileNode->parent) {
|
||||
pathnode[0] = fileNode->parent->name;
|
||||
FileNode_GetPath_Rec(fileNode->parent, pathnode + 1);
|
||||
} else {
|
||||
pathnode[0] = NULL;
|
||||
}
|
||||
}
|
||||
char temppath[MaxPath];
|
||||
char *FileNode_GetPath(FileNode *fileNode, char *path) {
|
||||
char *pathnodes[128];
|
||||
int levels, i;
|
||||
char *pathptr = temppath;
|
||||
if (path)
|
||||
pathptr = path;
|
||||
|
||||
FileNode_GetPath_Rec(fileNode, pathnodes);
|
||||
levels = 0;
|
||||
while (pathnodes[levels]) {
|
||||
levels++;
|
||||
}
|
||||
strcpy(pathptr, "");
|
||||
for (i = levels - 1; i >= 0; i--) {
|
||||
strcat(pathptr, pathnodes[i]);
|
||||
strcat(pathptr, "/");
|
||||
}
|
||||
strcat(pathptr, fileNode->name);
|
||||
return temppath;
|
||||
}
|
||||
char *FileNode_GetFullPath(FileNode *fileNode, char *basePath, char *path) {
|
||||
char *pathnodes[128];
|
||||
int levels, i;
|
||||
char *pathptr = temppath;
|
||||
if (path)
|
||||
pathptr = path;
|
||||
|
||||
FileNode_GetPath_Rec(fileNode, pathnodes);
|
||||
levels = 0;
|
||||
while (pathnodes[levels]) {
|
||||
levels++;
|
||||
}
|
||||
strcpy(pathptr, basePath);
|
||||
strcat(pathptr, "/");
|
||||
for (i = levels - 2; i >= 0; i--) {
|
||||
strcat(pathptr, pathnodes[i]);
|
||||
strcat(pathptr, "/");
|
||||
}
|
||||
strcat(pathptr, fileNode->name);
|
||||
return temppath;
|
||||
}
|
||||
|
||||
void FileNode_GetSize(FileNode *fileNode, char *filePath) {
|
||||
fileNode->flags |= FileFlag_HasSize;
|
||||
fileNode->size = File_GetSize(filePath);
|
||||
}
|
||||
|
||||
void FileNode_GetFecha(FileNode *fileNode, char *filePath) {
|
||||
fileNode->flags |= FileFlag_HastTime;
|
||||
fileNode->fileTime = FileTime_Get(filePath);
|
||||
}
|
||||
|
||||
void FileNode_GetCRC(FileNode *fileNode, char *filePath) {
|
||||
FILE *file;
|
||||
file = fopen(filePath, "rb");
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
fileNode->flags |= FileFlag_HasCRC;
|
||||
fileNode->crc = CRC_File(file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void FileNode_SaveNode(FileNode *fileNode, FILE *file) {
|
||||
short name_len;
|
||||
|
||||
// Escribir nombre
|
||||
name_len = strlen(fileNode->name);
|
||||
fwrite((void *) &name_len, sizeof(name_len), 1, file);
|
||||
fputs(fileNode->name, file);
|
||||
|
||||
// Escribir flags
|
||||
fwrite((void *) &fileNode->flags, sizeof(fileNode->flags), 1, file);
|
||||
|
||||
// Escribir estado
|
||||
fputc((char) fileNode->estado, file);
|
||||
|
||||
// Escribir tamanho
|
||||
if (fileNode->flags & FileFlag_HasSize) {
|
||||
fwrite((void *) &fileNode->size, sizeof(fileNode->size), 1, file);
|
||||
}
|
||||
|
||||
// Escribir fecha
|
||||
if (fileNode->flags & FileFlag_HastTime) {
|
||||
fwrite((void *) &fileNode->fileTime, sizeof(fileNode->fileTime), 1, file);
|
||||
}
|
||||
|
||||
// Escribir CRC
|
||||
if (fileNode->flags & FileFlag_HasCRC) {
|
||||
fwrite((void *) &fileNode->crc, sizeof(fileNode->crc), 1, file);
|
||||
}
|
||||
|
||||
// Escribir ficheros del directorio
|
||||
if (fileNode->flags & FileFlag_Directory) {
|
||||
FileNode *fileNodeChild;
|
||||
fwrite((void *) &fileNode->childCount, sizeof(fileNode->childCount), 1, file);
|
||||
fileNodeChild = fileNode->child;
|
||||
while (fileNodeChild) {
|
||||
FileNode_SaveNode(fileNodeChild, file);
|
||||
fileNodeChild = fileNodeChild->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileNode_Save(FileNode *fileNode, char *filePath) {
|
||||
FILE *file;
|
||||
char marca[5];
|
||||
int version;
|
||||
|
||||
if (!fileNode)
|
||||
return;
|
||||
file = fopen(filePath, "wb+");
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
// Escribir marca y version
|
||||
strcpy(marca, "sYnC");
|
||||
fwrite((void *) marca, sizeof(char), 4, file);
|
||||
version = FileNode_Version;
|
||||
fwrite((void *) &version, sizeof(int), 1, file);
|
||||
|
||||
FileNode_SaveNode(fileNode, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
FileNode *FileNode_LoadNode(FILE *file) {
|
||||
short nameLen;
|
||||
FileNode *fileNode;
|
||||
int i;
|
||||
|
||||
fileNode = FileNode_Create();
|
||||
|
||||
// Leer el nombre
|
||||
fread((void *) &nameLen, sizeof(nameLen), 1, file);
|
||||
fread((void *) fileNode->name, sizeof(char), nameLen, file);
|
||||
fileNode->name[nameLen] = 0;
|
||||
|
||||
// Leer vanderas
|
||||
fread((void *) &fileNode->flags, sizeof(fileNode->flags), 1, file);
|
||||
|
||||
// Leer estado
|
||||
fileNode->estado = fgetc(file);
|
||||
|
||||
// Leer tamanho
|
||||
if (fileNode->flags & FileFlag_HasSize) {
|
||||
fread((void *) &fileNode->size, sizeof(fileNode->size), 1, file);
|
||||
}
|
||||
|
||||
// Leer fecha
|
||||
if (fileNode->flags & FileFlag_HastTime) {
|
||||
fread((void *) &fileNode->fileTime, sizeof(fileNode->fileTime), 1, file);
|
||||
}
|
||||
|
||||
// Leer CRC
|
||||
if (fileNode->flags & FileFlag_HasCRC) {
|
||||
fread((void *) &fileNode->crc, sizeof(fileNode->crc), 1, file);
|
||||
}
|
||||
|
||||
// Leer ficheros del directorio
|
||||
if (fileNode->flags & FileFlag_Directory) {
|
||||
FileNode *fileNodeChildAux = NULL, *fileNodeChild;
|
||||
fread((void *) &fileNode->childCount, sizeof(fileNode->childCount), 1, file);
|
||||
for (i = 0; i < fileNode->childCount; i++) {
|
||||
fileNodeChild = FileNode_LoadNode(file);
|
||||
fileNodeChild->parent = fileNode;
|
||||
if (!fileNodeChildAux) {
|
||||
fileNode->child = fileNodeChild;
|
||||
} else {
|
||||
fileNodeChildAux->next = fileNodeChild;
|
||||
}
|
||||
fileNodeChildAux = fileNodeChild;
|
||||
}
|
||||
}
|
||||
|
||||
return (fileNode);
|
||||
}
|
||||
|
||||
FileNode *FileNode_Load(char *filePath) {
|
||||
FILE *file;
|
||||
FileNode *fileNode;
|
||||
char mark[5];
|
||||
int version;
|
||||
|
||||
file = fopen(filePath, "rb");
|
||||
if (!file)
|
||||
return (NULL );
|
||||
|
||||
// Leer marca y version
|
||||
fread((void *) mark, sizeof(char), 4, file);
|
||||
mark[4] = 0;
|
||||
if (strcmp(mark, "sYnC")) {
|
||||
// Marca incorrecta
|
||||
fclose(file);
|
||||
return (NULL );
|
||||
}
|
||||
fread((void *) &version, sizeof(int), 1, file);
|
||||
if (version != FileNode_Version) {
|
||||
// Version incorrecta
|
||||
fclose(file);
|
||||
return (NULL );
|
||||
}
|
||||
|
||||
fileNode = FileNode_LoadNode(file);
|
||||
fclose(file);
|
||||
|
||||
return (fileNode);
|
||||
}
|
||||
|
||||
void FileNode_PrintNode(FileNode *fileNode) {
|
||||
printf(FileNode_GetPath(fileNode, NULL ));
|
||||
if (fileNode->flags & FileFlag_Normal) {
|
||||
printf(" File");
|
||||
} else {
|
||||
printf(" Dir");
|
||||
}
|
||||
printf(" %d", fileNode->estado);
|
||||
if (fileNode->estado == FileStatus_New) {
|
||||
printf(" Nuevo");
|
||||
}
|
||||
if (fileNode->estado == FileStatus_Modified) {
|
||||
printf(" Modificado");
|
||||
}
|
||||
if (fileNode->estado == FileStatus_Deleted) {
|
||||
printf(" Borrado!!!");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/*
|
||||
// Tamanho
|
||||
if(fn->flags&FileFlag_TieneTamanho){
|
||||
printf("\\-Tamanho: %lld\n",fn->size);
|
||||
}
|
||||
|
||||
// Fecha
|
||||
if(fn->flags&FileFlag_TieneFecha){
|
||||
printf("\\-Fecha : ");FileTime_Print(fn->ft);printf("\n");
|
||||
}
|
||||
|
||||
// CRC
|
||||
if(fn->flags&FileFlag_TieneCRC){
|
||||
printf("\\-CRC : [%08X]\n",fn->crc);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void FileNode_Print(FileNode *fileNode) {
|
||||
FileNode *fileNodeAux = fileNode;
|
||||
int end = 0;
|
||||
|
||||
while (fileNodeAux != NULL && !end) {
|
||||
|
||||
if (fileNodeAux->parent != NULL ) {
|
||||
FileNode_PrintNode(fileNodeAux);
|
||||
}
|
||||
|
||||
if (fileNodeAux->child) {
|
||||
fileNodeAux = fileNodeAux->child;
|
||||
} else {
|
||||
while (fileNodeAux->next == NULL ) {
|
||||
fileNodeAux = fileNodeAux->parent;
|
||||
if (fileNodeAux == fileNode || fileNodeAux == NULL ) {
|
||||
printf("End\n");
|
||||
end = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!end) {
|
||||
fileNodeAux = fileNodeAux->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FileNode_Build_Iterate(char *path, char *name, void *d);
|
||||
|
||||
FileNode *FileNode_Build(char *path) {
|
||||
FileNode *fileNode;
|
||||
|
||||
if (!File_ExistsPath(path))
|
||||
return (NULL );
|
||||
|
||||
// Crear el nodo
|
||||
fileNode = FileNode_Create();
|
||||
File_GetName(path, fileNode->name);
|
||||
|
||||
// Determinar si es un fichero o directorio
|
||||
if (File_IsDirectory(path)) {
|
||||
// Obtener datos para los directorios
|
||||
fileNode->flags |= FileFlag_Directory;
|
||||
FileNode_GetFecha(fileNode, path);
|
||||
File_IterateDir(path, FileNode_Build_Iterate, fileNode);
|
||||
} else {
|
||||
// Obtener datos para los ficheros
|
||||
fileNode->flags |= FileFlag_Normal;
|
||||
FileNode_GetSize(fileNode, path);
|
||||
FileNode_GetFecha(fileNode, path);
|
||||
}
|
||||
|
||||
return (fileNode);
|
||||
}
|
||||
|
||||
int FileNode_Build_Iterate(char *path, char *name, void *d) {
|
||||
FileNode *fileNode, *fileNodeParent = d;
|
||||
;
|
||||
|
||||
if (!strcmp(name, FileNode_Filename)) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
fileNode = FileNode_Build(path);
|
||||
FileNode_AddChild(fileNodeParent, fileNode);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int FileNode_Refresh_Iterate(char *path, char *name, void *d);
|
||||
|
||||
FileNode *FileNode_Refresh(FileNode *fileNode, char *filePath) {
|
||||
if (!File_ExistsPath(filePath)) {
|
||||
// El fichero/directorio ha sido borrado
|
||||
if (!fileNode) {
|
||||
fileNode = FileNode_Create();
|
||||
File_GetName(filePath, fileNode->name);
|
||||
}
|
||||
FileNode_SetEstadoRec(fileNode, FileStatus_Deleted);
|
||||
return (fileNode);
|
||||
}
|
||||
if (!fileNode) {
|
||||
// El fichero ha sido creado
|
||||
fileNode = FileNode_Build(filePath);
|
||||
FileNode_SetEstadoRec(fileNode, FileStatus_New);
|
||||
} else {
|
||||
// Comprobar si ha sido modificado
|
||||
FileTime fileTime;
|
||||
long long size;
|
||||
int crc;
|
||||
|
||||
// Marcar normal
|
||||
fileNode->estado = FileStatus_None;
|
||||
fileNode->flags &= ~FileFlag_MarkerForReview;
|
||||
|
||||
// Determinar si es un fichero o directorio
|
||||
if (File_IsDirectory(filePath)) {
|
||||
FileNode *fileNodeChild;
|
||||
|
||||
// Comparar datos de los directorios
|
||||
if (!(fileNode->flags & FileFlag_Directory)) {
|
||||
fileNode->estado = FileStatus_Modified;
|
||||
fileNode->flags |= FileFlag_Directory;
|
||||
fileNode->flags &= ~FileFlag_Normal;
|
||||
}
|
||||
fileTime = FileTime_Get(filePath);
|
||||
if (fileTime != fileNode->fileTime) {
|
||||
fileNode->estado = FileStatus_Modified;
|
||||
fileNode->fileTime = fileTime;
|
||||
}
|
||||
|
||||
// Marcar hijos para determinar cual es actualizado
|
||||
fileNodeChild = fileNode->child;
|
||||
while (fileNodeChild) {
|
||||
fileNodeChild->flags |= FileFlag_MarkerForReview;
|
||||
fileNodeChild = fileNodeChild->next;
|
||||
}
|
||||
|
||||
// Escanear subdirectorios
|
||||
File_IterateDir(filePath, FileNode_Refresh_Iterate, fileNode);
|
||||
|
||||
// Buscar que sigan marcados (borrados)
|
||||
fileNodeChild = fileNode->child;
|
||||
while (fileNodeChild) {
|
||||
if (fileNodeChild->flags & FileFlag_MarkerForReview) {
|
||||
fileNodeChild->flags &= ~FileFlag_MarkerForReview;
|
||||
FileNode_SetEstadoRec(fileNodeChild, FileStatus_Deleted);
|
||||
}
|
||||
fileNodeChild = fileNodeChild->next;
|
||||
}
|
||||
} else {
|
||||
// Comprar datos de los ficheros
|
||||
if (!(fileNode->flags & FileFlag_Normal)) {
|
||||
fileNode->estado = FileStatus_Modified;
|
||||
fileNode->flags |= FileFlag_Normal;
|
||||
fileNode->flags &= ~FileFlag_Directory;
|
||||
}
|
||||
size = File_GetSize(filePath);
|
||||
if (size != fileNode->size) {
|
||||
fileNode->estado = FileStatus_Modified;
|
||||
fileNode->size = size;
|
||||
}
|
||||
fileTime = FileTime_Get(filePath);
|
||||
if (fileTime != fileNode->fileTime) {
|
||||
fileNode->estado = FileStatus_Modified;
|
||||
fileNode->fileTime = fileTime;
|
||||
}
|
||||
if (fileNode->estado == FileStatus_Modified) {
|
||||
fileNode->flags &= ~FileFlag_HasCRC;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (fileNode);
|
||||
}
|
||||
|
||||
int FileNode_Refresh_Iterate(char *path, char *name, void *d) {
|
||||
FileNode *fileNode = d;
|
||||
FileNode *fileNodeChild;
|
||||
|
||||
if (!strcmp(name, FileNode_Filename)) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Buscar el fichero entre los del arbol
|
||||
fileNodeChild = fileNode->child;
|
||||
while (fileNodeChild) {
|
||||
if (!strcmp(fileNodeChild->name, name)) {
|
||||
break;
|
||||
}
|
||||
fileNodeChild = fileNodeChild->next;
|
||||
}
|
||||
if (fileNodeChild) {
|
||||
// Existe, refrescar
|
||||
FileNode_Refresh(fileNodeChild, path);
|
||||
} else {
|
||||
// Nuevo, construir
|
||||
fileNodeChild = FileNode_Refresh(NULL, path);
|
||||
FileNode_AddChild(fileNode, fileNodeChild);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
59
src/filenode.h
Normal file
59
src/filenode.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef _FILENODE_H_
|
||||
#define _FILENODE_H_
|
||||
|
||||
#define FileNode_Filename "nodesFile.fs"
|
||||
|
||||
#define FileNode_Version 4
|
||||
|
||||
#define FileFlag_Root 1
|
||||
#define FileFlag_Normal 2
|
||||
#define FileFlag_Directory 4
|
||||
#define FileFlag_HasSize 8
|
||||
#define FileFlag_HastTime 16
|
||||
#define FileFlag_HasCRC 32
|
||||
#define FileFlag_MarkerForReview 1024
|
||||
|
||||
typedef enum {
|
||||
FileStatus_None,
|
||||
FileStatus_New,
|
||||
FileStatus_Modified,
|
||||
FileStatus_Deleted
|
||||
} FileStatus;
|
||||
|
||||
typedef struct SFileNode {
|
||||
char name[MaxFilename];
|
||||
int flags;
|
||||
FileStatus estado;
|
||||
|
||||
long long size;
|
||||
unsigned long crc;
|
||||
FileTime fileTime;
|
||||
|
||||
struct SFileNode *child;
|
||||
int childCount;
|
||||
|
||||
struct SFileNode *next;
|
||||
struct SFileNode *parent;
|
||||
} FileNode;
|
||||
|
||||
FileNode *FileNode_Create();
|
||||
void FileNode_Delete(FileNode *fileNode);
|
||||
void FileNode_AddChild(FileNode *file, FileNode *file2);
|
||||
|
||||
char *FileNode_GetFullPath(FileNode *fileNode, char *basePath, char *path);
|
||||
|
||||
void FileNode_GetSize(FileNode *fileNode, char *file);
|
||||
void FileNode_GetFecha(FileNode *fileNode, char *file);
|
||||
void FileNode_GetCRC(FileNode *fileNode, char *file);
|
||||
|
||||
void FileNode_Save(FileNode *fileNode, char *fichero);
|
||||
FileNode *FileNode_Load(char *fichero);
|
||||
|
||||
void FileNode_PrintNode(FileNode *fileNode);
|
||||
void FileNode_Print(FileNode *fileNode);
|
||||
|
||||
FileNode *FileNode_Build(char *path);
|
||||
|
||||
FileNode *FileNode_Refresh(FileNode *file, char *path);
|
||||
|
||||
#endif
|
||||
665
src/filenodecmp.c
Normal file
665
src/filenodecmp.c
Normal file
@@ -0,0 +1,665 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "crc.h"
|
||||
#include "fileutil.h"
|
||||
#include "filenode.h"
|
||||
#include "filenodecmp.h"
|
||||
|
||||
int maxDeltaTime=4000;
|
||||
|
||||
#define QueueNode(queue,node) (queue)->next = node; (queue) = node;
|
||||
|
||||
AccionFileNode *_actionFileNodeFree = NULL;
|
||||
#define AccionFileNode_Tocho 1024
|
||||
AccionFileNode *AccionFileNode_Create() {
|
||||
AccionFileNode *actionFileNode;
|
||||
|
||||
if (_actionFileNodeFree == NULL ) {
|
||||
AccionFileNode *actionFileNodeFreeAux;
|
||||
int i;
|
||||
// Reservar un tocho
|
||||
actionFileNodeFreeAux = malloc(
|
||||
sizeof(AccionFileNode) * AccionFileNode_Tocho);
|
||||
for (i = 0; i < AccionFileNode_Tocho - 1; i++) {
|
||||
actionFileNodeFreeAux[i].next = &actionFileNodeFreeAux[i + 1];
|
||||
}
|
||||
actionFileNodeFreeAux[AccionFileNode_Tocho - 1].next = NULL;
|
||||
_actionFileNodeFree = &actionFileNodeFreeAux[0];
|
||||
}
|
||||
|
||||
// Obtener el primero libre
|
||||
actionFileNode = _actionFileNodeFree;
|
||||
_actionFileNodeFree = actionFileNode->next;
|
||||
|
||||
// Iniciar
|
||||
actionFileNode->action = AccionFileCmp_Nothing;
|
||||
actionFileNode->left = NULL;
|
||||
actionFileNode->right = NULL;
|
||||
actionFileNode->next = NULL;
|
||||
|
||||
return (actionFileNode);
|
||||
}
|
||||
|
||||
void AccionFileNode_Destroy(AccionFileNode *actionFileNode) {
|
||||
actionFileNode->next = _actionFileNodeFree;
|
||||
_actionFileNodeFree = actionFileNode;
|
||||
}
|
||||
|
||||
AccionFileNode *AccionFileNode_CreateNormal(FileNode *fileNodeLeft,
|
||||
FileNode *fileNodeRight) {
|
||||
AccionFileNode *actionFileNode;
|
||||
actionFileNode = AccionFileNode_Create();
|
||||
actionFileNode->action = AccionFileCmp_Nothing;
|
||||
actionFileNode->left = fileNodeLeft;
|
||||
actionFileNode->right = fileNodeRight;
|
||||
return actionFileNode;
|
||||
}
|
||||
|
||||
void AccionFileNode_CompareChilds(AccionFileNode *actionFileNodeRoot,
|
||||
AccionFileNode **actionFileNodeQueue,
|
||||
void (*CheckPair)(FileNode *fileNodeLeft, FileNode *fileNodeRight,
|
||||
AccionFileNode **actionFileNodeQueue)) {
|
||||
FileNode *fileNodeLeft, *fileNodeRight;
|
||||
AccionFileNode *actionFileNodeQueueStart = (*actionFileNodeQueue);
|
||||
|
||||
// Comprobar si hay algo que comparar
|
||||
if (!actionFileNodeRoot->left && !actionFileNodeRoot->right) {
|
||||
// Nada que hacer
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterar todos los nodos de la izquierda
|
||||
if (actionFileNodeRoot->left) {
|
||||
fileNodeLeft = actionFileNodeRoot->left->child;
|
||||
while (fileNodeLeft) {
|
||||
if (actionFileNodeRoot->right) {
|
||||
fileNodeRight = actionFileNodeRoot->right->child;
|
||||
while (fileNodeRight) {
|
||||
if (!strcmp(fileNodeLeft->name, fileNodeRight->name)) {
|
||||
break;
|
||||
} else {
|
||||
fileNodeRight = fileNodeRight->next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fileNodeRight = NULL;
|
||||
}
|
||||
|
||||
CheckPair(fileNodeLeft, fileNodeRight, actionFileNodeQueue);
|
||||
|
||||
fileNodeLeft = fileNodeLeft->next;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterar todos los nodos de la derecha,
|
||||
// ignorando las comparaciones ya realizadas
|
||||
if (actionFileNodeRoot->right) {
|
||||
fileNodeRight = actionFileNodeRoot->right->child;
|
||||
while (fileNodeRight) {
|
||||
int doCheck = 1;
|
||||
if (actionFileNodeRoot->left) {
|
||||
fileNodeLeft = actionFileNodeRoot->left->child;
|
||||
while (fileNodeLeft) {
|
||||
AccionFileNode *afnCheck = actionFileNodeQueueStart;
|
||||
while (afnCheck) {
|
||||
if (afnCheck->left == fileNodeLeft
|
||||
&& afnCheck->right == fileNodeRight) {
|
||||
break;
|
||||
} else {
|
||||
afnCheck = afnCheck->next;
|
||||
}
|
||||
}
|
||||
if (afnCheck) {
|
||||
doCheck = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!strcmp(fileNodeLeft->name, fileNodeRight->name)) {
|
||||
break;
|
||||
} else {
|
||||
fileNodeLeft = fileNodeLeft->next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fileNodeLeft = NULL;
|
||||
}
|
||||
|
||||
if (doCheck) {
|
||||
CheckPair(fileNodeLeft, fileNodeRight, actionFileNodeQueue);
|
||||
}
|
||||
|
||||
fileNodeRight = fileNodeRight->next;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AccionFileNode_DeletePair(FileNode *fileNodeLeft, FileNode *fileNodeRight,
|
||||
AccionFileNode **actionFileNodeQueue) {
|
||||
AccionFileNode *actionFileNodeNew = AccionFileNode_CreateNormal(
|
||||
fileNodeLeft, fileNodeRight);
|
||||
|
||||
if (!fileNodeLeft && !fileNodeRight) {
|
||||
AccionFileNode_Destroy(actionFileNodeNew);
|
||||
return;
|
||||
}
|
||||
if (!fileNodeLeft && fileNodeRight) {
|
||||
if (fileNodeRight->flags & FileFlag_Directory) {
|
||||
// Iterar hijos para borrarlos
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew, actionFileNodeQueue,
|
||||
AccionFileNode_DeletePair);
|
||||
}
|
||||
|
||||
if (fileNodeRight->estado != FileStatus_Deleted) {
|
||||
// Accion de borrado para el nodo
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteRight;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
} else {
|
||||
AccionFileNode_Destroy(actionFileNodeNew);
|
||||
}
|
||||
}
|
||||
if (fileNodeLeft && !fileNodeRight) {
|
||||
if (fileNodeLeft->flags & FileFlag_Directory) {
|
||||
// Iterar hijos para borrarlos
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew, actionFileNodeQueue,
|
||||
AccionFileNode_DeletePair);
|
||||
}
|
||||
|
||||
if (fileNodeLeft->estado != FileStatus_Deleted) {
|
||||
// Accion de borrado para el nodo
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteLeft;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
} else {
|
||||
AccionFileNode_Destroy(actionFileNodeNew);
|
||||
}
|
||||
}
|
||||
if (fileNodeLeft && fileNodeRight) {
|
||||
if ((fileNodeLeft->flags & FileFlag_Directory)
|
||||
|| (fileNodeRight->flags & FileFlag_Directory)) {
|
||||
// Alguno es directorio
|
||||
|
||||
// Iterar hijos para borrarlos
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew, actionFileNodeQueue,
|
||||
AccionFileNode_DeletePair);
|
||||
}
|
||||
|
||||
if (fileNodeLeft->estado != FileStatus_Deleted) {
|
||||
// Accion de borrado para el nodo izquierdo
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteLeft;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
actionFileNodeNew = NULL;
|
||||
}
|
||||
if (fileNodeRight->estado != FileStatus_Deleted) {
|
||||
if (!actionFileNodeNew) {
|
||||
actionFileNodeNew = AccionFileNode_CreateNormal(fileNodeLeft,
|
||||
fileNodeRight);
|
||||
}
|
||||
// Accion de borrado para el nodo derecho
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteRight;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
actionFileNodeNew = NULL;
|
||||
}
|
||||
if (actionFileNodeNew) {
|
||||
AccionFileNode_Destroy(actionFileNodeNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AccionFileNode_CheckPair(FileNode *fileNodeLeft, FileNode *fileNodeRight,
|
||||
AccionFileNode **actionFileNodeQueue) {
|
||||
AccionFileNode *actionFileNodeNew = AccionFileNode_CreateNormal(
|
||||
fileNodeLeft, fileNodeRight);
|
||||
|
||||
if (!fileNodeLeft && !fileNodeRight) {
|
||||
AccionFileNode_Destroy(actionFileNodeNew);
|
||||
return;
|
||||
}
|
||||
if (!fileNodeLeft && fileNodeRight) {
|
||||
if (fileNodeRight->flags & FileFlag_Directory) {
|
||||
// Directory
|
||||
if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_MakeLeftDirectory;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
|
||||
// Iterar hijos
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew,
|
||||
actionFileNodeQueue, AccionFileNode_CheckPair);
|
||||
|
||||
// Crear nueva accion para copiar la fecha
|
||||
actionFileNodeNew = AccionFileNode_CreateNormal(fileNodeLeft,
|
||||
fileNodeRight);
|
||||
actionFileNodeNew->action = AccionFileCmp_DateRightToLeft;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
}
|
||||
} else {
|
||||
// File
|
||||
if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_RightToLeft;
|
||||
}
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
}
|
||||
}
|
||||
if (fileNodeLeft && !fileNodeRight) {
|
||||
if (fileNodeLeft->flags & FileFlag_Directory) {
|
||||
// Directory
|
||||
if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_MakeRightDirectory;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
|
||||
// Iterar hijos
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew,
|
||||
actionFileNodeQueue, AccionFileNode_CheckPair);
|
||||
|
||||
// Crear nueva accion para copiar la fecha
|
||||
actionFileNodeNew = AccionFileNode_CreateNormal(fileNodeLeft,
|
||||
fileNodeRight);
|
||||
actionFileNodeNew->action = AccionFileCmp_DateLeftToRight;
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
}
|
||||
} else {
|
||||
// File
|
||||
if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_LeftToRight;
|
||||
}
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
}
|
||||
}
|
||||
if (fileNodeLeft && fileNodeRight) {
|
||||
if ((fileNodeLeft->flags & FileFlag_Directory)
|
||||
&& (fileNodeRight->flags & FileFlag_Directory)) {
|
||||
// Directorios
|
||||
|
||||
// Preparar accion para el par de directorios
|
||||
if (abs(fileNodeLeft->fileTime - fileNodeRight->fileTime) <= maxDeltaTime) { // appoximadamente iguales
|
||||
if (fileNodeRight->estado == FileStatus_Deleted
|
||||
&& fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
} else if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteLeft;
|
||||
if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
} else if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteRight;
|
||||
if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
} else if (fileNodeLeft->fileTime < fileNodeRight->fileTime) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DateRightToLeft;
|
||||
if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteLeft;
|
||||
if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
}
|
||||
} else if (fileNodeLeft->fileTime > fileNodeRight->fileTime) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DateLeftToRight;
|
||||
if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteRight;
|
||||
if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Procesar nodos hijos
|
||||
if (actionFileNodeNew->action == AccionFileCmp_DeleteRight
|
||||
|| actionFileNodeNew->action == AccionFileCmp_DeleteLeft
|
||||
|| (fileNodeLeft->estado == FileStatus_Deleted
|
||||
&& fileNodeRight->estado == FileStatus_Deleted)) {
|
||||
// Iterar nodos hijos para borrarlos
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew,
|
||||
actionFileNodeQueue, AccionFileNode_DeletePair);
|
||||
} else {
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew,
|
||||
actionFileNodeQueue, AccionFileNode_CheckPair);
|
||||
}
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
} else if ((fileNodeLeft->flags & FileFlag_Normal)
|
||||
&& (fileNodeRight->flags & FileFlag_Normal)) {
|
||||
// Ficheros
|
||||
|
||||
// Preparar accion para el par de ficheros
|
||||
if (abs(fileNodeLeft->fileTime - fileNodeRight->fileTime) <= maxDeltaTime) { // appoximadamente iguales
|
||||
if (fileNodeRight->estado == FileStatus_Deleted
|
||||
&& fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
} else if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteLeft;
|
||||
if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
} else if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteRight;
|
||||
if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
} else if (fileNodeLeft->fileTime < fileNodeRight->fileTime) {
|
||||
// FIXME: Check size to determine y further checks are necessary
|
||||
actionFileNodeNew->action = AccionFileCmp_RightToLeft;
|
||||
if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteLeft;
|
||||
if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
}
|
||||
} else if (fileNodeLeft->fileTime > fileNodeRight->fileTime) {
|
||||
// FIXME: Check size to determine y further checks are necessary
|
||||
actionFileNodeNew->action = AccionFileCmp_LeftToRight;
|
||||
if (fileNodeLeft->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteRight;
|
||||
if (fileNodeRight->estado == FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
} else {
|
||||
// FIXME: !!!!!
|
||||
// Directory vs File
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AccionFileNode *AccionFileNode_BuildSync(FileNode *izquierda, FileNode *derecha) {
|
||||
AccionFileNode *actionFileNodeRoot = AccionFileNode_CreateNormal(izquierda,
|
||||
derecha);
|
||||
AccionFileNode *actionFileNodeQueue = actionFileNodeRoot;
|
||||
AccionFileNode_CompareChilds(actionFileNodeRoot, &actionFileNodeQueue,
|
||||
AccionFileNode_CheckPair);
|
||||
return actionFileNodeRoot;
|
||||
}
|
||||
|
||||
void AccionFileNode_Copy(FileNode *fileNodeLeft, FileNode *fileNodeRight,
|
||||
AccionFileNode **actionFileNodeQueue) {
|
||||
AccionFileNode *actionFileNodeNew = AccionFileNode_CreateNormal(
|
||||
fileNodeLeft, fileNodeRight);
|
||||
|
||||
if (!fileNodeLeft && !fileNodeRight) {
|
||||
AccionFileNode_Destroy(actionFileNodeNew);
|
||||
return;
|
||||
}
|
||||
if (!fileNodeLeft && fileNodeRight) {
|
||||
if (fileNodeRight->flags & FileFlag_Directory) {
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew, actionFileNodeQueue,
|
||||
AccionFileNode_DeletePair);
|
||||
}
|
||||
|
||||
if (fileNodeRight->estado != FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteRight;
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
}
|
||||
if (fileNodeLeft && !fileNodeRight) {
|
||||
if (fileNodeLeft->estado != FileStatus_Deleted) {
|
||||
if (fileNodeLeft->flags & FileFlag_Directory) {
|
||||
actionFileNodeNew->action = AccionFileCmp_MakeRightDirectory;
|
||||
(*actionFileNodeQueue)->next = actionFileNodeNew;
|
||||
(*actionFileNodeQueue) = actionFileNodeNew;
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew,
|
||||
actionFileNodeQueue, AccionFileNode_Copy);
|
||||
actionFileNodeNew = AccionFileNode_CreateNormal(fileNodeLeft,
|
||||
fileNodeRight);
|
||||
actionFileNodeNew->action = AccionFileCmp_DateLeftToRight;
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_LeftToRight;
|
||||
}
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
}
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
}
|
||||
if (fileNodeLeft && fileNodeRight) {
|
||||
if ((fileNodeLeft->flags & FileFlag_Directory)
|
||||
|| (fileNodeRight->flags & FileFlag_Directory)) {
|
||||
if (fileNodeLeft->estado != FileStatus_Deleted) {
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew,
|
||||
actionFileNodeQueue, AccionFileNode_Copy);
|
||||
if (abs(fileNodeLeft->fileTime - fileNodeRight->fileTime)
|
||||
<= maxDeltaTime) { // appox. equal
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_DateLeftToRight;
|
||||
}
|
||||
} else {
|
||||
AccionFileNode_CompareChilds(actionFileNodeNew,
|
||||
actionFileNodeQueue, AccionFileNode_DeletePair);
|
||||
if (fileNodeRight->estado != FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteRight;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fileNodeLeft->estado != FileStatus_Deleted) {
|
||||
if (abs(fileNodeLeft->fileTime - fileNodeRight->fileTime)
|
||||
<= maxDeltaTime) { // appox. equal
|
||||
actionFileNodeNew->action = AccionFileCmp_Nothing;
|
||||
} else {
|
||||
actionFileNodeNew->action = AccionFileCmp_LeftToRight;
|
||||
}
|
||||
} else {
|
||||
if (fileNodeRight->estado != FileStatus_Deleted) {
|
||||
actionFileNodeNew->action = AccionFileCmp_DeleteRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
QueueNode(*actionFileNodeQueue, actionFileNodeNew);
|
||||
}
|
||||
}
|
||||
|
||||
AccionFileNode *AccionFileNode_BuildCopy(FileNode *fileNodeLeft,
|
||||
FileNode *fileNodeRight) {
|
||||
AccionFileNode *actionFileNodeRoot = AccionFileNode_CreateNormal(
|
||||
fileNodeLeft, fileNodeRight);
|
||||
AccionFileNode *actionFileNodeQueue = actionFileNodeRoot;
|
||||
AccionFileNode_CompareChilds(actionFileNodeRoot, &actionFileNodeQueue,
|
||||
AccionFileNode_Copy);
|
||||
return actionFileNodeRoot;
|
||||
}
|
||||
|
||||
void AccionFileNode_Statistics(AccionFileNode *actionFileNode,
|
||||
ActionQueueStatistics *statistics) {
|
||||
statistics->readLeft = 0;
|
||||
statistics->writeLeft = 0;
|
||||
statistics->readRight = 0;
|
||||
statistics->writeRight = 0;
|
||||
statistics->fullCopyCount = 0;
|
||||
statistics->dateCopyCount = 0;
|
||||
statistics->directoryCount = 0;
|
||||
statistics->deleteCount = 0;
|
||||
statistics->deleteLeft = 0;
|
||||
statistics->deleteRight = 0;
|
||||
|
||||
while (actionFileNode != NULL ) {
|
||||
|
||||
switch (actionFileNode->action) {
|
||||
case AccionFileCmp_Nothing:
|
||||
break;
|
||||
case AccionFileCmp_LeftToRight:
|
||||
statistics->fullCopyCount++;
|
||||
statistics->readLeft += actionFileNode->left->size;
|
||||
statistics->writeRight += actionFileNode->left->size;
|
||||
break;
|
||||
case AccionFileCmp_RightToLeft:
|
||||
statistics->fullCopyCount++;
|
||||
statistics->writeLeft += actionFileNode->right->size;
|
||||
statistics->readRight += actionFileNode->right->size;
|
||||
break;
|
||||
case AccionFileCmp_DeleteLeft:
|
||||
statistics->deleteCount++;
|
||||
statistics->deleteLeft += actionFileNode->left->size;
|
||||
break;
|
||||
case AccionFileCmp_DeleteRight:
|
||||
statistics->deleteCount++;
|
||||
statistics->deleteRight += actionFileNode->right->size;
|
||||
break;
|
||||
case AccionFileCmp_DateLeftToRight:
|
||||
statistics->dateCopyCount++;
|
||||
break;
|
||||
case AccionFileCmp_DateRightToLeft:
|
||||
statistics->dateCopyCount++;
|
||||
break;
|
||||
case AccionFileCmp_MakeRightDirectory:
|
||||
statistics->directoryCount++;
|
||||
break;
|
||||
case AccionFileCmp_MakeLeftDirectory:
|
||||
statistics->directoryCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
actionFileNode = actionFileNode->next;
|
||||
}
|
||||
}
|
||||
|
||||
void AccionFileNode_Print(AccionFileNode *actionFileNode) {
|
||||
char showPath[MaxPath];
|
||||
while (actionFileNode != NULL ) {
|
||||
if (actionFileNode->left) {
|
||||
FileNode_GetFullPath(actionFileNode->left, "", showPath);
|
||||
} else {
|
||||
FileNode_GetFullPath(actionFileNode->right, "", showPath);
|
||||
}
|
||||
|
||||
switch (actionFileNode->action) {
|
||||
case AccionFileCmp_Nothing:
|
||||
//printf("%s == %s\n",pathIzq,pathDer);
|
||||
break;
|
||||
case AccionFileCmp_LeftToRight:
|
||||
printf(" => %s\n", showPath);
|
||||
break;
|
||||
case AccionFileCmp_RightToLeft:
|
||||
printf(" <= %s\n", showPath);
|
||||
break;
|
||||
case AccionFileCmp_DeleteLeft:
|
||||
printf(" *- %s\n", showPath);
|
||||
break;
|
||||
case AccionFileCmp_DeleteRight:
|
||||
printf(" -* %s\n", showPath);
|
||||
break;
|
||||
case AccionFileCmp_DateLeftToRight:
|
||||
printf(" -> %s\n", showPath);
|
||||
break;
|
||||
case AccionFileCmp_DateRightToLeft:
|
||||
printf(" <- %s\n", showPath);
|
||||
break;
|
||||
case AccionFileCmp_MakeRightDirectory:
|
||||
printf(" -D %s\n", showPath);
|
||||
break;
|
||||
case AccionFileCmp_MakeLeftDirectory:
|
||||
printf(" D- %s\n", showPath);
|
||||
break;
|
||||
}
|
||||
|
||||
actionFileNode = actionFileNode->next;
|
||||
}
|
||||
printf("End\n");
|
||||
}
|
||||
|
||||
void AccionFileNodeAux_CopyDate(char *pathOrig, char *pathDest) {
|
||||
FileTime ft = FileTime_Get(pathOrig);
|
||||
FileTime_Set(pathDest, ft);
|
||||
}
|
||||
|
||||
void AccionFileNodeAux_Copy(char *pathOrig, char *pathDest) {
|
||||
if (File_Copy(pathOrig, pathDest)) {
|
||||
AccionFileNodeAux_CopyDate(pathOrig, pathDest);
|
||||
} else {
|
||||
File_Delete(pathDest);
|
||||
}
|
||||
}
|
||||
void AccionFileNodeAux_Delete(char *pathOrig, char *pathDest) {
|
||||
if (File_IsDirectory(pathDest)) {
|
||||
File_DeleteDirectory(pathDest);
|
||||
} else {
|
||||
File_Delete(pathDest);
|
||||
}
|
||||
}
|
||||
void AccionFileNodeAux_MakeDir(char *pathOrig, char *pathDest) {
|
||||
File_MakeDirectory(pathDest);
|
||||
}
|
||||
|
||||
void AccionFileNode_RunList(AccionFileNode *actionFileNode, char *pathLeft,
|
||||
char *pathRight) {
|
||||
char fullPathLeft[MaxPath], fullPathRight[MaxPath], showPath[MaxPath];
|
||||
while (actionFileNode != NULL ) {
|
||||
if (actionFileNode->left) {
|
||||
FileNode_GetFullPath(actionFileNode->left, pathLeft, fullPathLeft);
|
||||
} else {
|
||||
FileNode_GetFullPath(actionFileNode->right, pathLeft, fullPathLeft);
|
||||
}
|
||||
if (actionFileNode->right) {
|
||||
FileNode_GetFullPath(actionFileNode->right, pathRight,
|
||||
fullPathRight);
|
||||
} else {
|
||||
FileNode_GetFullPath(actionFileNode->left, pathRight,
|
||||
fullPathRight);
|
||||
}
|
||||
if (actionFileNode->left) {
|
||||
FileNode_GetFullPath(actionFileNode->left, "", showPath);
|
||||
} else {
|
||||
FileNode_GetFullPath(actionFileNode->right, "", showPath);
|
||||
}
|
||||
|
||||
switch (actionFileNode->action) {
|
||||
case AccionFileCmp_Nothing:
|
||||
//printf("%s == %s\n",pathIzq,pathDer);
|
||||
break;
|
||||
case AccionFileCmp_LeftToRight:
|
||||
printf(" => %s\n", showPath);
|
||||
AccionFileNodeAux_Copy(fullPathLeft, fullPathRight);
|
||||
break;
|
||||
case AccionFileCmp_RightToLeft:
|
||||
printf(" <= %s\n", showPath);
|
||||
AccionFileNodeAux_Copy(fullPathRight, fullPathLeft);
|
||||
break;
|
||||
case AccionFileCmp_DeleteLeft:
|
||||
printf(" *- %s\n", showPath);
|
||||
AccionFileNodeAux_Delete(fullPathRight, fullPathLeft);
|
||||
break;
|
||||
case AccionFileCmp_DeleteRight:
|
||||
printf(" -* %s\n", showPath);
|
||||
AccionFileNodeAux_Delete(fullPathLeft, fullPathRight);
|
||||
break;
|
||||
case AccionFileCmp_DateLeftToRight:
|
||||
printf(" -> %s\n", showPath);
|
||||
AccionFileNodeAux_CopyDate(fullPathLeft, fullPathRight);
|
||||
break;
|
||||
case AccionFileCmp_DateRightToLeft:
|
||||
printf(" <- %s\n", showPath);
|
||||
AccionFileNodeAux_CopyDate(fullPathRight, fullPathLeft);
|
||||
break;
|
||||
case AccionFileCmp_MakeRightDirectory:
|
||||
printf(" -D %s\n", showPath);
|
||||
AccionFileNodeAux_MakeDir(fullPathLeft, fullPathRight);
|
||||
break;
|
||||
case AccionFileCmp_MakeLeftDirectory:
|
||||
printf(" D- %s\n", showPath);
|
||||
AccionFileNodeAux_MakeDir(fullPathRight, fullPathLeft);
|
||||
break;
|
||||
}
|
||||
|
||||
actionFileNode = actionFileNode->next;
|
||||
}
|
||||
printf("End\n");
|
||||
}
|
||||
56
src/filenodecmp.h
Normal file
56
src/filenodecmp.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef _FILENODECMP_H_
|
||||
#define _FILENODECMP_H_
|
||||
|
||||
#include "filenode.h"
|
||||
|
||||
typedef enum {
|
||||
AccionFileCmp_Nothing,
|
||||
AccionFileCmp_LeftToRight,
|
||||
AccionFileCmp_RightToLeft,
|
||||
AccionFileCmp_DeleteLeft,
|
||||
AccionFileCmp_DeleteRight,
|
||||
AccionFileCmp_DateLeftToRight,
|
||||
AccionFileCmp_DateRightToLeft,
|
||||
AccionFileCmp_MakeRightDirectory,
|
||||
AccionFileCmp_MakeLeftDirectory
|
||||
} AccionFileCmp;
|
||||
|
||||
typedef struct SAccionFileNode {
|
||||
AccionFileCmp action;
|
||||
FileNode *left;
|
||||
FileNode *right;
|
||||
struct SAccionFileNode *next;
|
||||
} AccionFileNode;
|
||||
|
||||
AccionFileNode *AccionFileNode_Create();
|
||||
void AccionFileNode_Destroy(AccionFileNode *actionFileNode);
|
||||
AccionFileNode *AccionFileNode_CreateNormal(FileNode *fileNodeLeft,
|
||||
FileNode *fileNodeRight);
|
||||
|
||||
AccionFileNode *AccionFileNode_BuildSync(FileNode *fileNodeLeft,
|
||||
FileNode *fileNodeRight);
|
||||
AccionFileNode *AccionFileNode_BuildCopy(FileNode *fileNodeLeft,
|
||||
FileNode *fileNodeRight);
|
||||
|
||||
typedef struct SActionQueueStatistics {
|
||||
long long readLeft;
|
||||
long long writeLeft;
|
||||
long long readRight;
|
||||
long long writeRight;
|
||||
int fullCopyCount;
|
||||
int dateCopyCount;
|
||||
int directoryCount;
|
||||
int deleteCount;
|
||||
long long deleteLeft;
|
||||
long long deleteRight;
|
||||
} ActionQueueStatistics;
|
||||
|
||||
void AccionFileNode_Statistics(AccionFileNode *actionFileNode,
|
||||
ActionQueueStatistics *statistics);
|
||||
|
||||
void AccionFileNode_Print(AccionFileNode *actionFileNode);
|
||||
|
||||
void AccionFileNode_RunList(AccionFileNode *actionFileNode, char *pathLeft,
|
||||
char *pathRight);
|
||||
|
||||
#endif
|
||||
326
src/fileutil.c
Normal file
326
src/fileutil.c
Normal file
@@ -0,0 +1,326 @@
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#include <time.h>
|
||||
#ifdef WIN32
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#include <signal.h>
|
||||
#include <windows.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "fileutil.h"
|
||||
|
||||
#ifdef WIN32
|
||||
long long FileTime_to_POSIX(FILETIME fileTime) {
|
||||
LARGE_INTEGER date, adjust;
|
||||
|
||||
// takes the last modified date
|
||||
date.HighPart = fileTime.dwHighDateTime;
|
||||
date.LowPart = fileTime.dwLowDateTime;
|
||||
|
||||
// 100-nanoseconds = milliseconds * 10000
|
||||
adjust.QuadPart = 11644473600000ll * 10000;
|
||||
|
||||
// removes the diff between 1970 and 1601
|
||||
date.QuadPart -= adjust.QuadPart;
|
||||
|
||||
// converts back from 100-nanoseconds to seconds
|
||||
return date.QuadPart / 10000000ll;
|
||||
}
|
||||
|
||||
FILETIME POSIX_to_FileTime(FileTime fileTime) {
|
||||
LARGE_INTEGER date, adjust;
|
||||
FILETIME fileTimeOut;
|
||||
|
||||
// converts to 100-nanoseconds from seconds
|
||||
date.QuadPart = fileTime * 10000000ll;
|
||||
|
||||
// 100-nanoseconds = milliseconds * 10000
|
||||
adjust.QuadPart = 11644473600000ll * 10000ll;
|
||||
|
||||
// removes the diff between 1970 and 1601
|
||||
date.QuadPart += adjust.QuadPart;
|
||||
|
||||
// asigns to filetime
|
||||
fileTimeOut.dwHighDateTime = date.HighPart;
|
||||
fileTimeOut.dwLowDateTime = date.LowPart;
|
||||
return fileTimeOut;
|
||||
}
|
||||
|
||||
FileTime FileTime_Get(char *fileName) {
|
||||
HANDLE hFile;
|
||||
FILETIME ftCreate, ftAccess, ftWrite;
|
||||
hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
|
||||
GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite);
|
||||
CloseHandle(hFile);
|
||||
return (FileTime_to_POSIX(ftWrite));
|
||||
}
|
||||
|
||||
void FileTime_Set(char *fileName, FileTime fileTime) {
|
||||
HANDLE hFile;
|
||||
FILETIME ftWrite;
|
||||
hFile = CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
|
||||
ftWrite = POSIX_to_FileTime(fileTime);
|
||||
SetFileTime(hFile, NULL, NULL, &ftWrite);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
FileTime FileTime_Get(char *filename) {
|
||||
struct stat fs;
|
||||
lstat(filename, &fs);
|
||||
return (fs.st_mtime);
|
||||
}
|
||||
|
||||
void FileTime_Set(char *filename, FileTime t) {
|
||||
struct utimbuf utb;
|
||||
|
||||
utb.actime = t;
|
||||
utb.modtime = t;
|
||||
utime(filename, &utb);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void FileTime_Print(FileTime fileTime) {
|
||||
struct tm *tms;
|
||||
|
||||
tms = localtime((time_t *) &fileTime);
|
||||
printf("%04d-%02d-%02d %02d:%02d:%02d", tms->tm_year + 1900,
|
||||
tms->tm_mon + 1, tms->tm_mday, tms->tm_hour, tms->tm_min,
|
||||
tms->tm_sec);
|
||||
}
|
||||
|
||||
void File_GetName(char *path, char *name) {
|
||||
int i, j;
|
||||
|
||||
i = strlen(path) - 1;
|
||||
while (i >= 0) {
|
||||
if (path[i] == '/' || path[i] == '\\') {
|
||||
i++;
|
||||
break;
|
||||
} else {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (i < 0)
|
||||
i++;
|
||||
|
||||
j = 0;
|
||||
while (path[i]) {
|
||||
name[j] = path[i];
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
name[j] = 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
int File_ExistsPath(char *path) {
|
||||
unsigned rc;
|
||||
rc = GetFileAttributes(path);
|
||||
|
||||
if (rc == INVALID_FILE_ATTRIBUTES ) {
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
int File_IsDirectory(char *dir) {
|
||||
unsigned rc;
|
||||
rc = GetFileAttributes(dir);
|
||||
|
||||
if (rc == INVALID_FILE_ATTRIBUTES ) {
|
||||
return (0);
|
||||
}
|
||||
if (rc & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
int File_IsFile(char *fichero) {
|
||||
unsigned rc;
|
||||
rc = GetFileAttributes(fichero);
|
||||
|
||||
if (rc == INVALID_FILE_ATTRIBUTES ) {
|
||||
return (0);
|
||||
}
|
||||
if (rc & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
#else
|
||||
int File_ExistsPath(char *path) {
|
||||
struct stat info;
|
||||
|
||||
if (lstat(path, &info) == -1) {
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
int File_IsDirectory(char *dir) {
|
||||
struct stat info;
|
||||
|
||||
if (lstat(dir, &info) == -1) {
|
||||
return (0);
|
||||
}
|
||||
if (S_ISDIR(info.st_mode)) {
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
int File_IsFile(char *fichero) {
|
||||
struct stat info;
|
||||
|
||||
if (lstat(fichero, &info) == -1) {
|
||||
return (0);
|
||||
}
|
||||
if (S_ISDIR(info.st_mode)) {
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
long long File_GetSize(char *file) {
|
||||
FILE *f;
|
||||
long long tamanho;
|
||||
|
||||
f = fopen(file, "rb");
|
||||
if (!f)
|
||||
return (-1);
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
tamanho = ftell(f);
|
||||
fclose(f);
|
||||
return (tamanho);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
int File_MakeDirectory(char *path) {
|
||||
return (_mkdir(path));
|
||||
}
|
||||
#else
|
||||
int File_MakeDirectory(char *path) {
|
||||
return (mkdir(path, 0777));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
void File_IterateDir(char *path,
|
||||
int (*func)(char *path, char *name, void *data), void *data) {
|
||||
int handle;
|
||||
struct _finddata_t fileinfo;
|
||||
char f_path[MaxPath];
|
||||
int fin = 0;
|
||||
int findnext_rc;
|
||||
char path_aux[MaxPath];
|
||||
char *ptr;
|
||||
|
||||
snprintf(path_aux, MaxPath, "%s/*", path);
|
||||
handle = _findfirst(path_aux, &fileinfo);
|
||||
if (handle == -1)
|
||||
return;
|
||||
|
||||
// Recorrer el directorio
|
||||
do {
|
||||
if (strcmp(fileinfo.name, ".") && strcmp(fileinfo.name, "..")) {
|
||||
// A partir de aqui hay un fichero
|
||||
// (o directorio)
|
||||
snprintf(f_path, 512, "%s/%s", path, fileinfo.name);
|
||||
fin = func(f_path, fileinfo.name, data);
|
||||
}
|
||||
findnext_rc = _findnext(handle, &fileinfo);
|
||||
} while (findnext_rc != -1 && !fin);
|
||||
_findclose(handle);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void File_IterateDir(char *path,
|
||||
int (*func)(char *path, char *name, void *data), void *data) {
|
||||
DIR *directorio;
|
||||
struct dirent *entidad_dir;
|
||||
char f_path[MaxPath];
|
||||
int fin = 0;
|
||||
char *ptr;
|
||||
|
||||
directorio = opendir(path);
|
||||
if (directorio == NULL )
|
||||
return;
|
||||
|
||||
// Recorrer el directorio
|
||||
do {
|
||||
entidad_dir = readdir(directorio);
|
||||
if (entidad_dir != NULL ) {
|
||||
if (strcmp(entidad_dir->d_name, ".")
|
||||
&& strcmp(entidad_dir->d_name, "..")) {
|
||||
// A partir de aqui hay un fichero
|
||||
// (o directorio)
|
||||
snprintf(f_path, MaxPath, "%s/%s", path, entidad_dir->d_name);
|
||||
fin = func(f_path, entidad_dir->d_name, data);
|
||||
}
|
||||
}
|
||||
}while (entidad_dir != NULL && !fin);
|
||||
closedir(directorio);
|
||||
}
|
||||
#endif
|
||||
|
||||
void File_Delete(char *path) {
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
void File_DeleteDirectory(char *path) {
|
||||
rmdir(path);
|
||||
}
|
||||
|
||||
#define MaxBuffer 16384
|
||||
int File_Copy(const char *pathOrig, const char *pathDest) {
|
||||
FILE *fOrig, *fDest;
|
||||
char buffer[MaxBuffer];
|
||||
int readLen = 0;
|
||||
int writeLen = 0;
|
||||
int ok = 0;
|
||||
|
||||
if ((fOrig = fopen(pathOrig, "rb")) == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
if ((fDest = fopen(pathDest, "wb")) == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
readLen = fread(&buffer, 1, MaxBuffer, fOrig);
|
||||
if (readLen > 0) {
|
||||
writeLen = fwrite(&buffer, 1, readLen, fDest);
|
||||
if (writeLen != readLen) {
|
||||
// Error
|
||||
fclose(fOrig);
|
||||
fclose(fDest);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while (readLen == MaxBuffer);
|
||||
|
||||
if (feof(fOrig)) {
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
fclose(fOrig);
|
||||
fclose(fDest);
|
||||
return ok;
|
||||
}
|
||||
38
src/fileutil.h
Normal file
38
src/fileutil.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef _FILEUTIL_
|
||||
#define _FILEUTIL_
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// FileTime
|
||||
|
||||
typedef long long FileTime;
|
||||
|
||||
FileTime FileTime_Get(char *filename);
|
||||
void FileTime_Set(char *filename, FileTime t);
|
||||
void FileTime_Print(FileTime t);
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// File
|
||||
#define MaxPath 4096
|
||||
#define MaxFilename 512
|
||||
|
||||
void File_GetName(char *path, char *name);
|
||||
|
||||
int File_ExistsPath(char *path);
|
||||
|
||||
int File_IsDirectory(char *path);
|
||||
|
||||
int File_IsFile(char *path);
|
||||
|
||||
long long File_GetSize(char *ficheros);
|
||||
|
||||
int File_MakeDirectory(char *path);
|
||||
|
||||
void File_IterateDir(char *path,
|
||||
int (*func)(char *path, char *name, void *data), void *data);
|
||||
|
||||
void File_Delete(char *path);
|
||||
void File_DeleteDirectory(char *path);
|
||||
|
||||
int File_Copy(const char *pathOrig, const char *pathDest);
|
||||
|
||||
#endif
|
||||
237
src/main.c
Normal file
237
src/main.c
Normal file
@@ -0,0 +1,237 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "crc.h"
|
||||
#include "fileutil.h"
|
||||
#include "filenode.h"
|
||||
#include "filenodecmp.h"
|
||||
|
||||
void Help(char *exe) {
|
||||
char exeFilename[MaxPath];
|
||||
File_GetName(exe, exeFilename);
|
||||
printf("Usage:\n");
|
||||
printf(" %s info [file] {[file] {..}}\n", exeFilename);
|
||||
printf(" %s scan [dir] [tree] \n", exeFilename);
|
||||
printf(" %s rescan [dir] [tree] \n", exeFilename);
|
||||
printf(" %s read [file] [tree]\n", exeFilename);
|
||||
printf(" %s dir [dir]\n", exeFilename);
|
||||
printf("\n");
|
||||
printf(" %s sync [dirIzquierda] [dirDerecha]\n", exeFilename);
|
||||
printf(" %s resync [dirIzquierda] [dirDerecha]\n", exeFilename);
|
||||
printf(" %s synctest [dirIzquierda] [dirDerecha]\n", exeFilename);
|
||||
printf(" %s resynctest [dirIzquierda] [dirDerecha]\n", exeFilename);
|
||||
printf("\n");
|
||||
printf(" %s copy [dirIzquierda] [dirDerecha]\n", exeFilename);
|
||||
printf(" %s recopy [dirIzquierda] [dirDerecha]\n", exeFilename);
|
||||
printf(" %s copytest [dirIzquierda] [dirDerecha]\n", exeFilename);
|
||||
printf(" %s recopytest [dirIzquierda] [dirDerecha]\n", exeFilename);
|
||||
}
|
||||
|
||||
FileNode *CheckDir(char *path, int recheck);
|
||||
int Sync(char *pathLeft, char *pathRight, int recheck, int dryRun);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FILE *file;
|
||||
unsigned long crc = 0;
|
||||
FileTime fileTime;
|
||||
int i;
|
||||
|
||||
if (argc < 2) {
|
||||
Help(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "info") && argc >= 3) {
|
||||
// Informacion de ficheros
|
||||
for (i = 2; i < argc; i++) {
|
||||
if (File_ExistsPath(argv[i])) {
|
||||
file = fopen(argv[i], "rb");
|
||||
if (file) {
|
||||
crc = CRC_File(file);
|
||||
fclose(file);
|
||||
}
|
||||
fileTime = FileTime_Get(argv[i]);
|
||||
printf("%s:\t[%08X]\t", argv[i], crc);
|
||||
FileTime_Print(fileTime);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(argv[1], "scan") && argc == 4) {
|
||||
// Scanear informacion de directorio y guardar arbol
|
||||
FileNode *fileNode;
|
||||
printf("Building FileNode..\n");
|
||||
fileNode = FileNode_Build(argv[2]);
|
||||
FileNode_Save(fileNode, argv[3]);
|
||||
} else if (!strcmp(argv[1], "rescan") && argc == 4) {
|
||||
// Scanear informacion de directorio y guardar arbol
|
||||
FileNode *fileNode;
|
||||
printf("Loading FileNode..\n");
|
||||
fileNode = FileNode_Load(argv[3]);
|
||||
if (fileNode) {
|
||||
printf("Rebuilding FileNode..\n");
|
||||
fileNode = FileNode_Refresh(fileNode, argv[2]);
|
||||
FileNode_Save(fileNode, argv[3]);
|
||||
}
|
||||
} else if (!strcmp(argv[1], "read") && argc == 3) {
|
||||
// Leer informacion de arbol
|
||||
FileNode *fileNode;
|
||||
fileNode = FileNode_Load(argv[2]);
|
||||
if (fileNode)
|
||||
FileNode_Print(fileNode);
|
||||
} else if (!strcmp(argv[1], "dir") && argc == 3) {
|
||||
// Leer informacion de dir
|
||||
char *path = argv[2];
|
||||
char dirNodesFile[MaxPath];
|
||||
FileNode *fileNode;
|
||||
|
||||
fileNode = CheckDir(path, 1);
|
||||
if (fileNode) {
|
||||
FileNode_Print(fileNode);
|
||||
}
|
||||
} else if (argc == 4) {
|
||||
char *cmd = argv[1];
|
||||
char *pathLeft = argv[2];
|
||||
char *pathRight = argv[3];
|
||||
if (!strcmp(cmd, "sync")) {
|
||||
Sync(pathLeft, pathRight, 1, 0);
|
||||
} else if (!strcmp(cmd, "resync")) {
|
||||
Sync(pathLeft, pathRight, 0, 0);
|
||||
} else if (!strcmp(cmd, "synctest")) {
|
||||
Sync(pathLeft, pathRight, 1, 1);
|
||||
} else if (!strcmp(cmd, "resynctest")) {
|
||||
Sync(pathLeft, pathRight, 0, 1);
|
||||
} else if (!strcmp(cmd, "copy")) {
|
||||
Copy(pathLeft, pathRight, 1, 0);
|
||||
} else if (!strcmp(cmd, "recopy")) {
|
||||
Copy(pathLeft, pathRight, 0, 0);
|
||||
} else if (!strcmp(cmd, "copytest")) {
|
||||
Copy(pathLeft, pathRight, 1, 1);
|
||||
} else if (!strcmp(cmd, "recopytest")) {
|
||||
Copy(pathLeft, pathRight, 0, 1);
|
||||
}
|
||||
} else {
|
||||
Help(argv[0]);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
FileNode *CheckDir(char *path, int recheck) {
|
||||
char dirNodesFile[MaxPath];
|
||||
FileNode *fileNode;
|
||||
|
||||
// Comprobar directorio
|
||||
snprintf(dirNodesFile, MaxPath, "%s/"FileNode_Filename, path);
|
||||
if (recheck) {
|
||||
printf("Checking Directory.. %s\n", path);
|
||||
fileNode = FileNode_Load(dirNodesFile);
|
||||
if (fileNode) {
|
||||
fileNode = FileNode_Refresh(fileNode, path);
|
||||
} else {
|
||||
fileNode = FileNode_Build(path);
|
||||
}
|
||||
FileNode_Save(fileNode, dirNodesFile);
|
||||
} else {
|
||||
printf("Loading Directory.. %s\n", path);
|
||||
fileNode = FileNode_Load(dirNodesFile);
|
||||
if (!fileNode) {
|
||||
printf("Error, no nodesFile.fs\n");
|
||||
return NULL ;
|
||||
}
|
||||
}
|
||||
return fileNode;
|
||||
}
|
||||
|
||||
void PrintStatistics(AccionFileNode *actionFileNode) {
|
||||
ActionQueueStatistics statistics;
|
||||
AccionFileNode_Statistics(actionFileNode, &statistics);
|
||||
printf("Statistics\n");
|
||||
printf(" % 12s % 12s % 12s\n", "Read", "Write", "Delete");
|
||||
printf("Left : % 12lld % 12lld % 12lld\n", statistics.readLeft,
|
||||
statistics.writeLeft, statistics.deleteLeft);
|
||||
printf("Right: % 12lld % 12lld % 12lld\n", statistics.readRight,
|
||||
statistics.writeRight, statistics.deleteRight);
|
||||
printf("\n");
|
||||
printf("Copy count : % 10d\n", statistics.fullCopyCount);
|
||||
printf("Date copy count: % 10d\n", statistics.dateCopyCount);
|
||||
printf("Directory count: % 10d\n", statistics.directoryCount);
|
||||
printf("Delete count : % 10d\n", statistics.deleteCount);
|
||||
}
|
||||
|
||||
int Sync(char *pathLeft, char *pathRight, int recheck, int dryRun) {
|
||||
FileNode *fileNodeLeft, *fileNodeRight;
|
||||
|
||||
// Comprobar y cargar directorios
|
||||
if (!File_ExistsPath(pathLeft) || !File_IsDirectory(pathLeft)) {
|
||||
printf("Error, directory does not exist: %s\n", pathLeft);
|
||||
return 0;
|
||||
}
|
||||
if (!File_ExistsPath(pathRight) || !File_IsDirectory(pathRight)) {
|
||||
printf("Error, directory does not exist: %s\n", pathRight);
|
||||
return 0;
|
||||
}
|
||||
fileNodeLeft = CheckDir(pathLeft, recheck);
|
||||
if (!fileNodeLeft) {
|
||||
return 0;
|
||||
}
|
||||
fileNodeRight = CheckDir(pathRight, recheck);
|
||||
if (!fileNodeRight) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Construir acciones
|
||||
printf("Building action list.. \n");
|
||||
AccionFileNode *actionFileNode = NULL;
|
||||
actionFileNode = AccionFileNode_BuildSync(fileNodeLeft, fileNodeRight);
|
||||
|
||||
if (dryRun) {
|
||||
// Mostrar lista de acciones
|
||||
AccionFileNode_Print(actionFileNode);
|
||||
PrintStatistics(actionFileNode);
|
||||
} else {
|
||||
// Ejecutar lista de acciones
|
||||
AccionFileNode_RunList(actionFileNode, pathLeft, pathRight);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
int Copy(char *pathLeft, char *pathRight, int reCheck, int dryRun) {
|
||||
FileNode *fileNodeLeft, *fileNodeRight;
|
||||
|
||||
// Comprobar y cargar directorios
|
||||
if (!File_ExistsPath(pathLeft) || !File_IsDirectory(pathLeft)) {
|
||||
printf("Error, directory does not exist: %s\n", pathLeft);
|
||||
return 0;
|
||||
}
|
||||
if (!File_ExistsPath(pathRight) || !File_IsDirectory(pathRight)) {
|
||||
printf("Error, directory does not exist: %s\n", pathRight);
|
||||
return 0;
|
||||
}
|
||||
fileNodeLeft = CheckDir(pathLeft, reCheck);
|
||||
if (!fileNodeLeft) {
|
||||
return 0;
|
||||
}
|
||||
fileNodeRight = CheckDir(pathRight, reCheck);
|
||||
if (!fileNodeRight) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Construir acciones
|
||||
printf("Building action list.. \n");
|
||||
AccionFileNode *actionFileNode = NULL;
|
||||
actionFileNode = AccionFileNode_BuildCopy(fileNodeLeft, fileNodeRight);
|
||||
|
||||
if (dryRun) {
|
||||
// Mostrar lista de acciones
|
||||
AccionFileNode_Print(actionFileNode);
|
||||
PrintStatistics(actionFileNode);
|
||||
} else {
|
||||
// Ejecutar lista de acciones
|
||||
AccionFileNode_RunList(actionFileNode, pathLeft, pathRight);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
15
src/util.c
Normal file
15
src/util.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
char *String_Copy(char *str) {
|
||||
char *strnew;
|
||||
int len;
|
||||
len = strlen(str);
|
||||
strnew = malloc(len + 1);
|
||||
strcpy(strnew, str);
|
||||
return (strnew);
|
||||
}
|
||||
|
||||
6
src/util.h
Normal file
6
src/util.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef _UTIL_
|
||||
#define _UTIL_
|
||||
|
||||
char *String_Copy(char *str);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user