From dc56be66c70079c82f86651477ca5982459271f1 Mon Sep 17 00:00:00 2001 From: Natalia Serrano Date: Fri, 8 Nov 2024 13:48:50 +0100 Subject: [PATCH] refs #1101 add ogUcastSyntax() and its dependencies --- client/lib/engine/bin/ImageLib.py | 275 ++++++++++++++++++++++++++ client/lib/engine/bin/ProtocolLib.py | 276 +++++++++++++++++++++++++++ 2 files changed, 551 insertions(+) create mode 100644 client/lib/engine/bin/ImageLib.py create mode 100644 client/lib/engine/bin/ProtocolLib.py diff --git a/client/lib/engine/bin/ImageLib.py b/client/lib/engine/bin/ImageLib.py new file mode 100644 index 0000000..b9bef13 --- /dev/null +++ b/client/lib/engine/bin/ImageLib.py @@ -0,0 +1,275 @@ +#!/usr/bin/python3 + +import shutil +import subprocess +import os +import os.path +import re +from pathlib import Path + +import DiskLib +import FileSystemLib +import SystemLib +import ogGlobals + +## ProtocolLib.ogUcastSyntax() calls ogCreateImageSyntax() +## in ogCreateImageSyntax(), param2 may contain a pipe or may be empty +## if param2 is empty, then ogUcastSyntax(): +## - does a .split() +## - accesses the third element of the resulting array (ie. does "parts[2]") +## - promptly gets an IndexError exception +## +## param2 in ogCreateImageSyntax() only contains a pipe if 'mbuffer' is installed +## therefore, a hard dependency on mbuffer is created +## +## raise an Exception at import time if mbuffer is not present +if not shutil.which ('mbuffer'): + raise FileNotFoundError ('"mbuffer" utility must be present') + +#/** +#@file ImageLib.py +#@brief Librería o clase Image +#@class Image +#@brief Funciones para creación, restauración y clonación de imágenes de sistemas. +#@warning License: GNU GPLv3+ +#*/ + + +#/** +# ogCreateImageSyntax path_device path_filename [str_tool] [str_compressionlevel] +#@brief Genera una cadena de texto con la instrucción para crear un fichero imagen +#@param path_device dispositivo Linux del sistema de archivos +#@param path_fileneme path absoluto del fichero imagen +#@param [opcional] str_tool herrmaienta de clonacion [partimage, partclone, ntfsclone] +#@param [opcional] str_compressionlevel nivel de compresion. [0 -none-, 1-lzop-, 2-gzip] +#@return str_command - cadena con el comando que se debe ejecutar. +#@warning Salida nula si se producen errores. +#@TODO introducir las herramientas fsarchiver, dd +#*/ ## +#ogCreateImageSyntax /dev/sda1 /opt/opengnsys/images/prueba.img partclone lzop +#ogCreateImageSyntax /dev/sda1 /opt/opengnsys/images/prueba.img +def ogCreateImageSyntax (dev, imgfile, tool='partclone', level='gzip'): + + if 'ntfsclone' == tool: + param1 = f'ntfsclone --force --save-image -O - {dev}' + elif 'partimage' == tool or 'default' == tool: + param1 = f'partimage -M -f3 -o -d -B gui=no -c -z0 --volume=0 save {dev} stdout' + elif 'partclone' == tool: + disk, part = DiskLib.ogDevToDisk (dev).split() + fs = FileSystemLib.ogGetFsType (disk, part) + param1 = { + 'EXT2': 'partclone.extfs', + 'EXT3': 'partclone.extfs', + 'EXT4': 'partclone.extfs', + 'BTRFS': 'partclone.btrfs', + 'REISERFS': 'partclone.reiserfs', + 'REISER4': 'partclone.reiser4', + 'JFS': 'partclone.jfs', + 'XFS': 'partclone.xfs', + 'F2FS': 'partclone.f2fs', + 'NILFS2': 'partclone.nilfs2', + 'NTFS': 'partclone.ntfs', + 'EXFAT': 'partclone.exfat', + 'FAT16': 'partclone.fat', + 'FAT32': 'partclone.fat', + 'HFS': 'partclone.hfsp', + 'HFSPLUS': 'partclone.hfsp', + 'UFS': 'partclone.ufs', + 'VMFS': 'partclone.vmfs', + }.get (fs, 'partclone.imager') + dash_c = '-c' + if not shutil.which (param1): + param1 = 'partclone.dd' + # Algunas versiones de partclone.dd no tienen opción "-c". + out = subprocess.run (['partclone.dd', '--help'], capture_output=True, text=True).stdout + if ' -c' not in out: dash_c = '' + param1=f'{param1} -d0 -F {dash_c} -s {dev}' + else: + raise Exception (f'unknown tool "{tool}"') + + param2 = '| mbuffer -q -m 40M ' if shutil.which ('mbuffer') else ' ' + + param3 = { + 0: ' > ', + 'none': ' > ', + 1: ' | lzop > ', + 'lzop': ' | lzop > ', + 2: ' | gzip -c > ', + 'gzip': ' | gzip -c > ', + 3: ' | bzip -c > ', + 'bzip': ' | bzip -c > ', + }.get (level, ' > ') + + print (f'param1 ({param1}) param2 ({param2}) param3 ({param3}) imgfile ({imgfile})') + if param1: return f'{param1} {param2} {param3} {imgfile}' + + +#/** +# ogRestoreImageSyntax path_filename path_device [str_tools] [str_compressionlevel] +#@brief Genera una cadena de texto con la instrucción para crear un fichero imagen +#@param path_device dispositivo Linux del sistema de archivos +#@param path_fileneme path absoluto del fichero imagen +#@param [opcional] str_tools herrmaienta de clonacion [partimage, partclone, ntfsclone] +#@param [opcional] str_compressionlevel nivel de compresion. [0 -none-, 1-lzop-, 2-gzip] +#@return cadena con el comando que se debe ejecutar. +#@exception OG_ERR_FORMAT formato incorrecto. +#@warning En pruebas iniciales +#@TODO introducir las herramientas fsarchiver, dd +#@TODO introducir el nivel de compresion gzip +#*/ ## +#ogRestoreImageSyntax /opt/opengnsys/images/prueba.img /dev/sda1 [partclone] [lzop] +def ogRestoreImageSyntax (imgfile, part, tool=None, level=None): + if not os.path.exists (imgfile): + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, imgfile) + ## original bash code is broken: 'return' is never called + #return + + if tool is None or level is None: + infoimg = ogGetImageInfo (imgfile) + if not infoimg: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'no image {imgfile}') + ## original bash code is broken: 'return' is never called + #return + try: + tool, level = infoimg.split (':')[0:2] + except: + tool, level = '', '' + return ogRestoreImageSyntax (imgfile, part, tool, level) + + tool = tool.lower() + level = level.lower() + compressor = { + 0: ' ', + 'none': ' ', + 1: ' lzop -dc ', + 'lzop': ' lzop -dc ', + 2: ' gzip -dc ', + 'gzip': ' gzip -dc ', + 3: ' bzip -dc ', + 'bzip': ' bzip -dc ', + }.get (level, '') + print (f'tool ({tool}) level ({level}) compressor ({compressor})') + if compressor is '': + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'Compressor no valid {level}') + ## original bash code is broken: 'return' is never called + #return + + mbuffer = '| mbuffer -q -m 40M ' if shutil.which ('mbuffer') else ' ' + print (f'mbuffer ({mbuffer})') + if 'ntfsclone' == tool: + tool = f'| ntfsclone --restore-image --overwrite {part} -' + elif 'partimage' == tool: + tool = f'| partimage -f3 -B gui=no restore {part} stdin' + elif 'partclone' in tool: + # -C para que no compruebe tamaños + tool = f'| partclone.restore -d0 -C -I -o {part}' + elif 'dd' == tool: + tool = f'| pv | dd conv=sync,noerror bs=1M of={part}' + else: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'Tools imaging no valid {tool}') + ## original bash code is broken: 'return' is never called + #return + print (f'tool ({tool})') + + return f'{compressor} {imgfile} {mbuffer} {tool}'.strip() + + +#/** +# ogGetImageInfo filename +#@brief muestra información sobre la imagen monolitica. +#@param 1 filename path absoluto del fichero imagen +#@return cadena compuesta por clonacion:compresor:sistemaarchivos:tamañoKB +#@exception OG_ERR_FORMAT formato incorrecto. +#@exception OG_ERR_NOTFOUND fichero no encontrado. +#@exception OG_ERR_IMAGE "Image format is not valid $IMGFILE" +#@warning En pruebas iniciales +#@TODO Definir sintaxis de salida (herramienta y compresor en minuscula) +#@TODO Arreglar loop para ntfsclone +#@TODO insertar parametros entrada tipo OG +#*/ ## +#ogGetImageInfo /opt/opengnsys/images/prueba.img ==> PARTCLONE:LZOP:NTFS:5642158" +def ogGetImageInfo (imgfile): + if not os.path.exists (imgfile): + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, imgfile) + return + + imgdetect = False + filehead = f'/tmp/{os.path.basename (imgfile)}.infohead' + compressor = subprocess.run (['file', imgfile], capture_output=True, text=True).stdout.split()[1] + if compressor not in ['gzip', 'lzop']: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_IMAGE, f'Image format is not valid {imgfile}') + return + + ## original bash idiom is: $($COMPRESSOR -dc $IMGFILE 2>/dev/null | head -n 40 > $FILEHEAD) || ogRaiseError + ## the purpose of which I can't fully comprehend + print (f'shelling out "{compressor} -dc {imgfile} |head -n 40 > {filehead}"') + if subprocess.run (f'{compressor} -dc {imgfile} |head -n 40 > {filehead}', shell=True).returncode: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_IMAGE, f'Image format is not valid {imgfile}') + return + + tools = fs = size = None + + if False == imgdetect: + lc_all = os.getenv ('LC_ALL') + os.environ['LC_ALL'] = 'C' + partclone_info = subprocess.run (['partclone.info', filehead], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True).stdout + if lc_all is not None: + os.environ["LC_ALL"] = lc_all + else: + del os.environ["LC_ALL"] + if 'size' in partclone_info: + tools = 'PARTCLONE' + sizefactor = 1000000 if 'GB' in partclone_info else 1024 + fs_lines = list (filter (lambda l: 'File system' in l, partclone_info.splitlines())) + fs = fs_lines[0].split (':')[1].strip() + if fs in ['HFS', 'HFSPLUS', 'FAT32']: + ## TODO + #FSPLUS=$(echo $PARTCLONEINFO | awk '{gsub(/\: /,"\n"); print toupper($9);}') + #echo $PARTCLONEINFO | grep GB > /dev/null && SIZEFACTOR=1000000 || SIZEFACTOR=1024 + fsplus = 'PLUS' + if fsplus: + fs += fsplus + size = 42 + else: + size = 42 + ## /TODO + size = int (size * sizefactor) + else: + m = re.search (r'Device size *: *(\S+)', partclone_info) + size = float (m.group(1)) if m else 0 + size = int (size * sizefactor) + imgdetect = True + + if False == imgdetect and not os.path.exists ('/dev/loop2'): + filehead_contents = Path (filehead).read_bytes() + if b'ntfsclone-image' in filehead_contents: + print (f'shelling out "cat {filenead} | ntfsclone --restore --overwrite /dev/loop2 - 2>&1"') + ntfscloneinfo = subprocess.run (f'cat {filenead} | ntfsclone --restore --overwrite /dev/loop2 - 2>&1', shell=True, capture_output=True, text=True).stdout + if 'ntfsclone' in ntfscloneinfo: + tools = 'NTFSCLONE' + size_lines = list (filter (lambda l: '__TODO__' in l, ntfscloneinfo.splitlines())) ## TODO + size = 42 #int (size_lines[0].split (':')[1].strip()) ## TODO + fs = 'NTFS' + imgdetect = True + + if False == imgdetect: + partimageinfo = subprocess.run (['partimage', '-B', 'gui=no', 'imginfo', filehead], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True).stdout + if 'Partition' in partimageinfo: + tools = 'TOOLS=PARTIMAGE' + fs_lines = list (filter (lambda l: '__TODO__' in l, partimageinfo.splitlines())) ## TODO + fs = 'EXTFS' #fs_lines[0].split (':')[1].strip() ## TODO + size_lines = list (filter (lambda l: '__TODO__' in l, partimageinfo.splitlines())) ## TODO + size = 42 #int (size_lines[0].split (':')[1].strip()) ## TODO + imgdetect = True + if 'boot sector' in subprocess.run (['file', filehead], capture_output=True, text=True).stdout: + tools = 'partclone.dd' + fs = '' + size = 0 + imgdetect = True + + if not tools or not compressor or False == imgdetect: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_IMAGE, f'Image format is not valid {imgfile}') + return + + compressor = compressor.lower() + return ':'.join ([tools, compressor, fs, str (size)]) diff --git a/client/lib/engine/bin/ProtocolLib.py b/client/lib/engine/bin/ProtocolLib.py new file mode 100644 index 0000000..a9b94bf --- /dev/null +++ b/client/lib/engine/bin/ProtocolLib.py @@ -0,0 +1,276 @@ +#!/usr/bin/python3 + +import ogGlobals +import SystemLib +import ImageLib + +#/** +#@file ProtocolLib.py +#@brief Librería o clase Protocol +#@class Protocol +#@brief Funciones para transmisión de datos +#@warning License: GNU GPLv3+ +#*/ + + +##################### FUNCIONES UNICAST ################ + +#/** +# ogUcastSyntax +#@brief Función para generar la instrucción de transferencia de datos unicast +#@param 1 Tipo de operación [ SENDPARTITION RECEIVERPARTITION SENDFILE RECEIVERFILE ] +#@param 2 Sesion Unicast +#@param 3 Dispositivo (opción PARTITION) o fichero(opción FILE) que será enviado. +#@param 4 Tools de clonación (opcion PARTITION) +#@param 5 Tools de compresion (opcion PARTITION) +#@return instrucción para ser ejecutada. +#@exception OG_ERR_FORMAT formato incorrecto. +#@exception OG_ERR_UCASTSYNTAXT formato de la sesion unicast incorrecta. +#@note Requisitos: mbuffer +#@todo: controlar que mbuffer esta disponible para los clientes. +#*/ ## + +#ogUcastSyntax SENDPARTITION 8000:172.17.36.11:172.17.36.12 device tool level +#ogUcastSyntax RECEIVERPARTITION 8000:172.17.36.249 device tool level + +#ogUcastSyntax SENDFILE 8000:172.17.36.11:172.17.36.12 file +#ogUcastSyntax RECEIVERFILE 8000:172.17.36.249 file + +def ogUcastSyntax (op, sess, file=None, device=None, tool=None, level=None): + if 'SENDPARTITION' == op or 'RECEIVERPARTITION' == op: + if device is None: + raise TypeError ('missing required argument: "device"') + if tool is None: + raise TypeError ('missing required argument: "tool"') + if tool not in ['partclone', 'PARTCLONE', 'partimage', 'PARTIMAGE', 'ntfsclone', 'NTFSCLONE']: + raise TypeError (f'argument "tool" has unsupported value "{tool}"') + if level is None: + raise TypeError ('missing required argument: "level"') + if level not in ['lzop', 'gzip', 'LZOP', 'GZIP', '0', '1']: + raise TypeError (f'argument "level" has unsupported value "{level}"') + elif 'SENDFILE' == op or 'RECEIVERFILE' == op: + if file is None: + raise TypeError ('missing required argument: "file"') + else: + raise TypeError ('first parameter should match (SEND|RECEIVER)(PARTITION|FILE), eg. "SENDFILE"') + + if 'SEND' in op: mode = 'server' + else: mode = 'client' + + session = sess.split (':') + + portbase = int (session[0]) + if portbase not in range (8000, 8006): + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'McastSession portbase {portbase}') ## || PERROR=3 + return + + if 'SERVER' == mode: + address = '' + for i in range (1, len (session)): + address += f'-O {session[i]}:{portbase}' + else: + address = f'{session[1]}:{portbase}' + print (f'nati mode ({mode}) address ({address})') + + if 'SENDPARTITION' == op: + syn = ImageLib.ogCreateImageSyntax (device, ' ', tool, level) + ## REQUIRES package mbuffer to be installed!! + ## otherwise, param2 in ImageLib.ogCreateImageSyntax() is not '| mbuffer' but empty + ## and then parts[2] is out of range + parts = syn.split ('|') + print (f'syn ({syn}) parts ({parts})') + prog1 = f'{parts[0]}|{parts[2]}'.strip() + prog1 = prog1.replace ('>', '').strip() + return f'{prog1} | mbuffer {address}' + elif 'RECEIVERPARTITION' == op: + syn = ImageLib.ogRestoreImageSyntax (' ', device, tool, level) + parts = syn.split ('|') + compressor = parts[0].strip() + tools = parts[-1].strip() + return f'mbuffer -I {address} | {compressor} | {tools}' + elif 'SENDFILE' == op: + return f'mbuffer {address} -i {file}' + elif 'RECEIVERFILE' == op: + return f'mbuffer -I {address} -i {file}' + else: + pass ## shouldn't happen + + +#/** +# ogUcastSendPartition +#@brief Función para enviar el contenido de una partición a multiples particiones remotas usando UNICAST. +#@param 1 disk +#@param 2 partition +#@param 3 sesionUcast +#@param 4 tool image +#@param 5 tool compresor +#@return +#@exception $OG_ERR_FORMAT +#@exception $OG_ERR_UCASTSENDPARTITION +#@note +#@todo: ogIsLocked siempre devuelve 1 +#*/ ## + + +#/** +# ogUcastReceiverPartition +#@brief Función para recibir directamente en la partición el contenido de un fichero imagen remoto enviado por UNICAST. +#@param 1 disk +#@param 2 partition +#@param 3 session unicast +#@return +#@exception OG_ERR_FORMAT +#@exception OG_ERR_UCASTRECEIVERPARTITION +#@note +#@todo: +#*/ ## + + +#/** +# ogUcastSendFile [ str_repo | int_ndisk int_npart ] /Relative_path_file sessionMulticast +#@brief Envía un fichero por unicast ORIGEN(fichero) DESTINO(sessionmulticast) +#@param (2 parámetros) $1 path_aboluto_fichero $2 sesionMcast +#@param (3 parámetros) $1 Contenedor REPO|CACHE $2 path_absoluto_fichero $3 sesionMulticast +#@param (4 parámetros) $1 disk $2 particion $3 path_absoluto_fichero $4 sesionMulticast +#@return +#@exception OG_ERR_FORMAT formato incorrecto. +#@exception $OG_ERR_NOTFOUND +#@exception OG_ERR_UCASTSENDFILE +#@note Requisitos: +#*/ ## +# + + +#/** +# ogMcastSyntax +#@brief Función para generar la instrucción de ejucción la transferencia de datos multicast +#@param 1 Tipo de operación [ SENDPARTITION RECEIVERPARTITION SENDFILE RECEIVERFILE ] +#@param 2 Sesión Mulicast +#@param 3 Dispositivo (opción PARTITION) o fichero(opción FILE) que será enviado. +#@param 4 Tools de clonación (opcion PARTITION) +#@param 5 Tools de compresion (opcion PARTITION) +#@return instrucción para ser ejecutada. +#@exception OG_ERR_FORMAT formato incorrecto. +#@exception OG_ERR_NOTEXEC +#@exception OG_ERR_MCASTSYNTAXT +#@note Requisitos: upd-cast 2009 o superior +#@todo localvar check versionudp +#*/ ## +# + + + + +#/** +# ogMcastSendFile [ str_repo | int_ndisk int_npart ] /Relative_path_file sessionMulticast +#@brief Envía un fichero por multicast ORIGEN(fichero) DESTINO(sessionmulticast) +#@param (2 parámetros) $1 path_aboluto_fichero $2 sesionMcast +#@param (3 parámetros) $1 Contenedor REPO|CACHE $2 path_absoluto_fichero $3 sesionMulticast +#@param (4 parámetros) $1 disk $2 particion $3 path_absoluto_fichero $4 sesionMulticast +#@return +#@exception OG_ERR_FORMAT formato incorrecto. +#@exception $OG_ERR_NOTFOUND +#@exception OG_ERR_MCASTSENDFILE +#*/ ## +# + + + + +#/** +# ogMcastReceiverFile sesion Multicast [ str_repo | int_ndisk int_npart ] /Relative_path_file +#@brief Recibe un fichero multicast ORIGEN(sesionmulticast) DESTINO(fichero) +#@param (2 parámetros) $1 sesionMcastCLIENT $2 path_aboluto_fichero_destino +#@param (3 parámetros) $1 sesionMcastCLIENT $2 Contenedor REPO|CACHE $3 path_absoluto_fichero_destino +#@param (4 parámetros) $1 sesionMcastCLIENT $2 disk $3 particion $4 path_absoluto_fichero_destino +#@return +#@exception OG_ERR_FORMAT formato incorrecto. +#@exception $OG_ERR_MCASTRECEIVERFILE +#@note Requisitos: +#*/ ## +# + + + +#/** +# ogMcastSendPartition +#@brief Función para enviar el contenido de una partición a multiples particiones remotas. +#@param 1 disk +#@param 2 partition +#@param 3 session multicast +#@param 4 tool clone +#@param 5 tool compressor +#@return +#@exception OG_ERR_FORMAT +#@exception OG_ERR_MCASTSENDPARTITION +#@note +#@todo: ogIsLocked siempre devuelve 1. crear ticket +#*/ ## + + +#/** +# ogMcastReceiverPartition +#@brief Función para recibir directamente en la partición el contenido de un fichero imagen remoto enviado por multicast. +#@param 1 disk +#@param 2 partition +#@param 3 session multicast +#@param 4 tool clone +#@param 5 tool compressor +#@return +#@exception $OG_ERR_FORMAT +#*/ ## + + +#/** +# ogMcastRequest +#@brief Función temporal para solicitar al ogRepoAux el envio de un fichero por multicast +#@param 1 Fichero a enviar ubicado en el REPO. puede ser ruta absoluta o relatica a /opt/opengnsys/images +#@param 2 PROTOOPT opciones protocolo multicast +#@return +#@exception +#*/ ## + + +########################################## +############## funciones torrent +#/** +# ogTorrentStart [ str_repo | int_ndisk int_npart ] Relative_path_file.torrent | SessionProtocol +#@brief Función iniciar P2P - requiere un tracker para todos los modos, y un seeder para los modos peer y leecher y los ficheros .torrent. +#@param str_pathDirectory str_Relative_path_file +#@param int_disk int_partition str_Relative_path_file +#@param str_REPOSITORY(CACHE - LOCAL) str_Relative_path_file +#@param (2 parámetros) $1 path_aboluto_fichero_torrent $2 Parametros_Session_Torrent +#@param (3 parámetros) $1 Contenedor CACHE $2 path_absoluto_fichero_Torrent $3 Parametros_Session_Torrent +#@param (4 parámetros) $1 disk $2 particion $3 path_absoluto_fichero_Torrent 4$ Parametros_Session_Torrent +#@return +#@note protocoloTORRENT=mode:time mode=seeder -> Dejar el equipo seedeando hasta que transcurra el tiempo indicado o un kill desde consola, mode=peer -> seedear mientras descarga mode=leecher -> NO seedear mientras descarga time tiempo que una vez descargada la imagen queremos dejar al cliente como seeder. +#*/ ## + +#/** +# ogCreateTorrent [ str_repo | int_ndisk int_npart ] Relative_path_file +#@brief Función para crear el fichero torrent. +#@param str_pathDirectory str_Relative_path_file +#@param int_disk int_partition str_Relative_path_file +#@param str_REPOSITORY(CACHE - LOCAL) str_Relative_path_file +#@return +#@exception OG_ERR_FORMAT Formato incorrecto. +#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo. +#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar. +#@exception OG_ERR_NOTOS La partición no tiene instalado un sistema operativo. +#*/ ## + + + +#/** +# ogUpdateCacheIsNecesary [ str_repo ] Relative_path_file_OGIMG_with_/ +#@brief Comprueba que el fichero que se desea almacenar en la cache del cliente, no esta. +#@param 1 str_REPO +#@param 2 str_Relative_path_file_OGIMG_with_/ +#@param 3 md5 to check: use full to check download image torrent +#@return 0 (true) cache sin imagen, SI es necesario actualizar el fichero. +#@return 1 (false) imagen en la cache, NO es necesario actualizar el fichero +#@return >1 (false) error de sintaxis (TODO) +#@note +#@todo: Proceso en el caso de que el fichero tenga el mismo nombre, pero su contenido sea distinto. +#@todo: Se dejan mensajes mientras se confirma su funcionamiento. +#*/ ##