0)i}tSrSSKrSSKrSSKrSSKrSSKJrJr SSKJr SSK r SSK J r SSK r "SS5r g)z Backup Engine - TimeMachineBackup Incremental backup system with hard-link deduplication Extracted from BackupSystem for integration with Scheduler N)datetime timedelta)Path)loggerc\rSrSrSrSrS\4SjrS\4SjrS\4Sjr S \4S jr S r S r S r S\S\4SjrSrSrSSjrSrSrSSjrSSjrSSjrSrS SjrSrSrg)!TimeMachineBackupc[U[5(a [U5n[RR [RR [U555n[U5UlURRSSS9 URS- Ul URS- Ul URS- Ul URRSSS9 UR5 g)NTparentsexist_okzbackup_metadata.jsonz .backup.lockstore) isinstancerstrospath expandvars expanduser backup_rootmkdir metadata_file lock_file store_dir load_metadata)selfrs 3C:\PYTHON\Scheduler\modules\backup\backup_engine.py__init__TimeMachineBackup.__init__s k4 ( (k*Kgg((););C DM t}} ,*,DMM, ' -ED C,.r B  Cs.BBB BBBB.-B.rc >[RS:wag[U5R=(d [ U5nSSKnSSKJn URRRnURURURURUR5URUR5URUR5URUR/UlUR5nUR5nUR5nURS5n U"USSUR!U5UR!U5UR!U5U S5n U (aU R"=(d S$g![$a gf=f)zKRitorna il tipo di filesystem (es. 'NTFS', 'exFAT') su Windows oppure None.ntNr)wintypes)rnameranchorrctypesr2windllkernel32GetVolumeInformationWLPCWSTRLPWSTRDWORDPOINTERargtypescreate_unicode_bufferbyrefvaluer-) rrrootr6r2r9sermclflags fsname_bufoks r_windows_fs_type"TimeMachineBackup._windows_fs_type.sR ww$:$$1D D  '$*MM$:$:$P$P !  x~~.x~~.x~~. . ! *.."C.."CNN$E55c:J&tT1fll36GVYIZ\b\h\hin\oq{~ABB!''/4/  sFE5F FFc[RS:Xa.URU5nU(aUR5S:HU4$gg![a gf=f)z^Prova a capire se il FS supporta hard links. Ritorna (supports: bool|None, fsname: str|None). r1NTFSNN)rr4rHupperr-)rrfsnames rfs_supports_hardlinks'TimeMachineBackup.fs_supports_hardlinksMsS ww$..t4"LLNf4f==#  sAA AA source_pathc#P# SSKn1Skn[R"[U5SSS9GHupVn/n[ U5Hn [ U5U - n U R 5(aURU 5 M9X;aURU 5 MQU(dMZ[[ U5U - RU55RSS5n U n UHCn URX5(dURX5(dM1URU 5 M M UHn URU 5 M UHn[ U5U- nUR 5(aM)U(a{[URU55RSS5nURn SnUH4n URUU 5(dURX5(dM2Sn O U(aMUv M GM g![a Mf=f![a Mf=f![a gf=f7f) a>Itera i file di una sorgente con pruning veloce delle directory inutili. - Usa os.walk(topdown=True) per poter modificare `dirs` in-place ed evitare di scendere in alberi enormi come .git, node_modules, venv, ecc. - Applica i pattern di exclude sia alle directory (per il pruning) sia ai file. - Non segue symlink. rN>tmpTempvenv __pycache__ node_modules.git.venv.cacheTF)topdown followlinks\/)fnmatchrwalkrlistr is_symlinkappend relative_toreplaceremove ValueErrorr4r-)rrQexclude_fnmprune_dirnamesrBdirsfilesprunedddpathrel_dirr4patr.fpathrel_fileskips riter_source_files#TimeMachineBackup.iter_source_files\s4  "nN%'WWS-=tY^%_!EdA JNE'')) a( * a( w"%tDzA~&B&B;&O"P"X"XY]_b"c #*C#||G99T\\$=T=T & a 0 %$+$" A A A JNE! ++--$"'*5+<+<[+I'J'R'RSWY\']H#(::D#(D'.#'<<##>#>$,,tBYBY+/D$)(/ $ (# !7&`.&*%! !   sH&BHA'HH$G45H H"H$A/H H$H&H* H3H&4 H>HHH HHHH H# H&"H##H& relative_pathc[RS:wag1SknURH=nURSS5SR 5R 5nXB;dM;Us $ g![ a gf=f)zRitorna il segmento riservato di Windows trovato nel percorso relativo, altrimenti None. Su Windows non sono permessi nomi di dispositivo come: CON, PRN, AUX, NUL, COM1..COM9, LPT1..LPT9. Sono vietati anche con estensione (es. NUL.txt). r1N>AUXCONNULPRNCOM1COM2COM3COM4COM5COM6COM7COM8COM9LPT1LPT2LPT3LPT4LPT5LPT6LPT7LPT8LPT9.r)rr4partssplitstriprMr-)rrwreservedpartbases r_windows_reserved_segment+TimeMachineBackup._windows_reserved_segmentsw  ww$H &++zz#q)!,224::<#K ,   s#A)AA)"A)&A)) A65A6cSn[R"SS[UR5S9up![R "USSS9n[ R"URUSS S 9 SSS5 [R"XR5 U(a=[RRU5(a[R"U5 ggg!,(df  Ns=f![a gf=f!U(aM[RRU5(a([R"U5 f![a ff=fff=f) zSalva i metadatiN metadata_z.json)prefixsuffixdirwr"r#F)indent ensure_ascii)tempfilemkstemprrrfdopenr*dumpr,rerrr(rfOSError)rrSfdr.s r save_metadataTimeMachineBackup.save_metadatas &&k'sSWScScOdeGB2sW5 $--15I6 JJs.. /rww~~c**IIcN+s 65rww~~c**IIcN+ssZAC5"C'(C5;C% C"C5% C21C25,E "D98E 9 EE EE c US- nURSS5URSS5-nURSS5nURSS5nURSS5nURSS5nURSS5n URS /5n Sn Sn URS 5HNn U R5(dMU RS:wdM,XR 5R - n U S - n MP S nXv:aS nOUS:aSnUS:aUS-U-OSn[USSS9nURS5 URS5 URS5 URSU S35 URSURS35 URSUS35 URS5 URS5 URS5 URSUSS35 URSUSS US!35 URS"USS SU- S!35 URS#USS35 URS5 URS$5 URS5 URS%U S&S'U S(- S(- S)S*35 URS+US&S'US(- S(- S)S*35 U S:a,US:a&X:a!SUS-U - - nURS,US-S.35 URS5 URS5 URS/5 URS5 [U S 5HunnURUS0US35 M URS5 Xv:aURS5 URS15 URS5 URS25 URS35 URS45 URS55 URS65 URS75 URS85 URS5 S9S9S95 g9![ [4a GMf=f!,(df  g9=f![a#n[R"S:U35 S9nAg9S9nAff=f);z5Crea un file di log leggibile per il backup corrente.zBACKUP_INFO.txt files_linkedr files_copiedfiles_in_store total_size timestamp source_dirs*ru✓ OK - Hard links funzionantiuJ⚠ ATTENZIONE - Troppi file copiati (filesystem non supporta hard links?)u3⚠ PARZIALE - Alcuni file copiati invece di linkeddrr"r#zG====================================================================== z RIEPILOGO BACKUP zH====================================================================== z Data e ora:  z Nome backup: zStato: z zG---------------------------------------------------------------------- zSTATISTICHE FILE z File totali nella snapshot: z>10u" • Hard links (risparmiati): z (z%) u" • Copie fisiche: z Nuovi file nel content store: zOCCUPAZIONE SPAZIO z Dimensione apparente snapshot: z>15,z bytes (iz>8.1fz MB) z Nuovi dati nel content store: z Risparmio spazio (hard links): z>14.1fz% zDIRECTORY SORGENTI z. u⚠ AVVISO IMPORTANTE u2Questo backup contiene più COPIE che HARD LINKS! u,Stai occupando PIÙ SPAZIO del necessario. zCausa probabile: u9 • Filesystem non supporta hard links (FAT32, exFAT) z Soluzione: u; • Formatta il disco come NTFS (Windows) o ext4 (Linux) u3 • Esegui un nuovo backup dopo la formattazione Nz Impossibile creare file di log: )getrglobis_filer4statst_sizerPermissionErrorr)write enumerater-rwarning)r backup_path backup_infolog_file total_filesrrrrrsources apparent_size file_countitemstatushardlink_percentager.savingsisrces rcreate_backup_log_file(TimeMachineBackup.create_backup_log_files`!22P C%//.!<{~_`?aaK(__-=qAN&??>1=L&??>1=L$q9J# R8I!oomR8GMJ#))#.<<>>dii3D&D%)<)<< "a /7F*e!NJUWX<##5#D^_ hg6!(78)*,yk45- (8(8'9<='&./(,-(:;s:K2NO<\##:NdST(./(:=:NiXefjXjkoXopuWvv|}~::d:K9U_`dUdeiUijoTppvwx 1$a!1"%c)9M)I"J"B76BRRU VW (./('3FAsGGqcC5O,4 .GGO,GG67GGO,GGQRGGLMGG01GGYZGGN+GGZ[GGRSGGO,_76$_576b C NN=aSA B B CsaB>Rc^[R"5n[US5m[U4SjS5HnUR U5 M SSS5 UR 5$!,(df  N=f![ [4a gf=f)z!Calcola l'hash SHA-256 di un filerbc&>TRS5$)Ni)read)r.sr7TimeMachineBackup.calculate_file_hash..s!&&*=rrN)hashlibsha256r)iterupdate hexdigestrr)r file_pathhasherchunkr.s @rcalculate_file_hash%TimeMachineBackup.calculate_file_hashsv! i&!!"=sCEMM%(D'##% %'&)  s( A6)A% A6% A3/A66B B  file_hashreturncDUSSUSSp2URS- U- U- U- $)z,Percorso nel content store per un dato hash.Nrr)r)rrabs rhash_to_store_path$TimeMachineBackup.hash_to_store_path!s5!}i!n1')A-1I==rc[R"UR[R[R-[R -5n[R "USSS9nUR[R"[R"5[R"5R5S.55 SSS5 g!,(df  g=f![a [S5 gf=f) z2Evita sovrapposizione backup (lock file semplice).rr"r#)pidtimeNTz5Un altro backup sembra in esecuzione (lock presente).F)rr)rO_CREATO_EXCLO_WRONLYrrr*dumpsgetpidrnow isoformatFileExistsErrorprint)rrr.s r acquire_lockTimeMachineBackup.acquire_lock&s bii)?"++)MNB2sW5 299; @X@X@Z#[\]665  I J s1A'C )ACC  CC C C87C8cURR5(aURR5 gg![a gf=fN)rr(unlinkr)rs r release_lockTimeMachineBackup.release_lock1sA ~~$$&&%%''   s9= A  A Nc Uc'S[R"5RS53nURU- nUR SS9 [ R "SU35 [R"5R5/SSSSS.nSnU(auU(anUH\n [U 5n U R5(d[ R"S U S 35 M?URX5Hn US - nM M^ U"S US .5 Sn Sn UGH9n [U 5n U R5(d[ R"S U S 35 M@[ R "SU 35 XjR- nUR SS9 U S - n SnU(aU"S[U 5U S.5 URX5HLnURUXX5 U S - n US - nU(dM)U"SU U[U5[U 5U US.5 MN USR![U 55 U(dGM"U"S[U 5U US.5 GM< XpR"SU'UR%5 UR'Xg5 USUS-n[ R "SUSUSSUSSUSS3 5 USUS:a[ R"S 5 [ R"S!5 [ R"S"5 [ R"S#5 [ R"S$5 [ R"S 5 gg![a GNLf=f![a GNf=f![a GMf=f![a GM{f=f)%u]Crea un nuovo backup. - Se `progress` è None (CLI senza barra), niente pre‑scansione. - Se `progress` è fornito: * con `progress_precount=True` (default, usato dalla GUI): conta rapida per inizializzare il totale. * con `progress_precount=False` (CLI): evita la pre‑scansione, mostrando comunque avanzamento incrementale. Nzbackup-z%Y-%m-%d-%H%M%STr zCreando backup: r)rrrrrrzAvviso: z non esisterstart)phasetotalz Backup di: source_start)rsource source_indexprogress)r processedrfilerrsource_processedr source_end)rrrrr%rrzBackup completato: z file totali ( hard links, z copie), rz nuovi file nel content storezF======================================================================u.⚠️ ATTENZIONE: Più copie che hard links!u:⚠️ Il backup sta OCCUPANDO PIÙ SPAZIO del necessariouI⚠️ Causa probabile: Filesystem non supporta hard links (FAT32/exFAT)uG⚠️ Soluzione: Formatta il disco come NTFS (Windows) o ext4 (Linux))rrstrftimerrrinforrr(rrur-r4rprocess_file_v2rcr,rr)rr backup_namerhrprogress_precountrrr source_dirrQ_r source_idxdest_dirrrrs r create_backupTimeMachineBackup.create_backup8s  #HLLN$;$;x!-"%k"2(2,< W&j1< i -  ##K=".1K4OO  !+/N+,M+n:U9VV_+,--J L  ~ &^)D D NN8 $ NNK L NNW X NNf g NNd e NN8 $ EU  0!&%!sH? M M%"M+3M= MM M('M(+ M:9M:= N  N cURU5nX%- nURRSSS9 URU5nUcgUR 5R nXpR S;a[UR SU5n U R5(a]UR5(aUR5 [R"[U 5[U55 US==S- ss'g[R"X5 US==S- ss'US==U- ss'[U5UR SU'g![a NXf=f![ an [#S US U 35 Sn A gSn A ff=f) z1Processa un singolo file (copia o crea hard link)Tr Nr&rrrrErrore processando : )rdparentrrrrr,rr(rrlinkrrshutilcopy2r-r) rrrr source_rootrw dest_filer file_size existing_filers r process_fileTimeMachineBackup.process_filesl$ :%11+>M 0I    " "4$ " ?00;I !(00IMM-88 $T]]=%A)%L M  '')) ''))!((*M 2C NC#N3q83 LL .  '1 , '  % 2 %7:)nDMM- ( 3# : ' {"QC8 9 9 :sDAEBE6E ?A E EEEE F%E;;Fc |URS(d [S5 g[S5 URSR5Hup[R"US5R S5n[SUSU35 S U;azUR S S 5UR S S 5-n[S USUR S S 5SUR S S 5S35 [SUR S S 535 M[SUR S S 5SUR S S 5S35 M g)z Lista tutti i backup disponibilir%zNessun backup trovatoNzBackup disponibili:rz%Y-%m-%d %H:%M:%Sz z - rrrrz File totali: z (rz copie)z Nuovi nel content store: z File: z copiati, z collegamenti)r,ritemsr fromisoformatrr)rr4r daters r list_backupsTimeMachineBackup.list_backupss2}}Y' ) *  #$-- 288:JD))${*;<EEFYZD BtfCv& ' 4'3dhh~q6QQ)%488NA3N2O}.!45W>?5dhh?OQR6S5TUV 488NA#>"?z.!45]DE;rcnXRS;a[SUS35 gURU- nUR5(d[SUS35 gUc[R "5S- n[ U5nUR SS 9 [S US U35 UR5HwnUR5(a%X$R- n[R"XESS 9 M=UR5(dMT[R"XBUR- 5 My [S U35 g)zRipristina un backupr%zBackup z non trovatoNzCartella backup z non trovatarestored_backupTrzRipristinando backup z in  dirs_exist_okzRipristino completato in )r,rrr(rhomeriterdiris_dirr4rcopytreerr)rr  restore_pathrrrs rrestore_backup TimeMachineBackup.restore_backups  mmI6 6 GK= 5 6 &&4 !!## $[M> ?   99;)::LL) D) %k]$|nEF '')D{{}}'))3dC T$))#;< * ),89rchURU- nXB- nUR5(d[SUSU35 gUc,[R"5[U5R - nO [U5nUR RSSS9 [R"XS5 [SU35 g)zRipristina un file specificozFile z non trovato nel backup NTr zFile ripristinato: ) rr(rrcwdr4rrrr)rr r restore_tor source_files r restore_fileTimeMachineBackup.restore_file s&&4 !- !!## E)$<[MJ K   d9o&:&::Jj)Jt< [- #J<01rc~URU- nXB- nUR5(aUR5(d[SUSU35 gUc#[R "5UR - nO [ U5nURRSSS9 [R"XSSS9 [SU35 g)uRipristina una directory specifica dal backup. directory_path è relativo alla radice del backup (es: 'Documents' o 'Documents/Progetti').z Directory z non trovata nel backup NTr r(zDirectory ripristinata in: ) rr(r,rrr2r4rrrr-)rr directory_pathr3rr s rrestore_directory#TimeMachineBackup.restore_directorys&&4  1   ""**;*;*=*= J~..F{mT U   joo5Jj)Jt< dC +J<89rc  UR5(a[R"SU35 gURU5nX&- nURR SSS9 UR U5nU(a[R"SUSUS35 g[R"SUS U35 U(ah[U5RS S 5n URn UH;n [R"X5(d[R"X5(dM; g UR5n [U5n URRS 05RU 5nU(aPURS 5U R:Xa1URS5U R :XaURS5nOLUR#U5nUcgU RU R US.URR%S 05U 'U R nUR'U5nSnUR)5(dURR SSS9 [*R,"S[UR5S9unn[.R0"U5 [2R4"UU5 [.R"UU5 [.R6R)U5(a[.R8"U5 OSnUR%SS5 US==S- ss'US==U- ss'UR)5(aUR=5 [.R>"[U5[U55 US==S- ss'[U5URR%S!05U'UR%S"/5 XS";aUS"RMU5 gg![:a Nf=f![.R6R)U5(a([.R8"U5 f![:a ff=ff=f![:Ga+n[AUSS5nUS:waURS5(dSUS'[R"SU35 URCURD5unnUSLa[[GURD5RH=(d URD5nO%![Ja [URD5nOf=f[R"SUSUS35 [2R4"X5 US ==S- ss'U(d US==U- ss'SnAGNSnAff=f![JaZn[RN"S#US WS$U35 SnAg![Ja# [RN"S#US$U35 SnAgf=fSnAff=f)%z/Nuova versione: usa content store e cache path.zSalto symlink: NTr z,Salto elemento con nome riservato Windows: 'z' nel percorso ''z Analizzo: z -> r]r^r'mtime_nssizehash)r=r>r?Fobj_)rrrrrrrwinerrorivhardlink_failedz"Hard link fallito (usando copia): zIl volume di backup u è 'z7' e non supporta hard links: verranno effettuate copie.rr&hashesrr)(rbrrrdrrrdebugrrer4r_rr,r st_mtime_nsrr setdefaultrr(rrrcloserrrrfrrrgetattrrOrrr5r-rcerror)rrrrrrhrwrbadrel_strr4rqstabs_pathcachedrr store_path newly_storedtmp_fdtmp_pathrwinerrsupportsrNvols rr !TimeMachineBackup.process_file_v21s1m E##%% <=%11+>M 0I    " "4$ " ?00?CB3%GWXeWffgh LL:i[YK@ Am,44T3? ~~"Cw448R8R# !B9~H]]&&|R8<+//:K*L*L59K 12NN%Gs#KL'+'A'A$BRBR'S$Hf5(8"%d4+;+;&<&C&C&WtGWGW"XC(8"%d&6&6"7C8)=cU%xPG(HI Y2N+q0+# -:-) ;8 E E 29+T)BqcRSS E 29+RsCDD E  Es.VA$VBVVB3VCV.O7$V-O'AV6QAV' O41V3O44V7%QP43Q4 Q>QQQV U>A*U9>;S:9U9:TU9TAU93V9U>>V W% V00&WW WW  W%c^ URRS05nU(d [S5 gSm [UR 5U 4SjS9n/nUbD[ R "5[US9- nUVVs/sHupxT "U5U:dMUPM nnnOAUb2US:aSn[U5U:aUSU*VV s/sHupyUPM nnn O [S 5 gUH^nURU- n U R5(a[R"U 5 URUS5 [S U35 M` UR5 gs snnfs sn nf![an [S US U 35 Sn A MSn A ff=f) u+Rimuove vecchi backup per conteggio o età.r%zNessun backup da rimuovereNc[R"URS55$![a [Rs$f=f)Nr)rr"rr-min)r s rparse_dt1TimeMachineBackup.prune_backups..parse_dts: $--dhh{.CDD $||# $s$'AAc>T"US5$)Nr)kvrZs rr1TimeMachineBackup.prune_backups..s "Q%r)key)daysrzSpecifica --keep o --older-thanzRimosso backup zImpossibile rimuovere r)r,rrsortedr!rrrlenrr(rrmtreepopr-r) rkeepolder_than_daysr%ordered to_deletecutoffr4r rrrrZs @r prune_backupsTimeMachineBackup.prune_backupssf--##Ir2 . /  $ .HI  &\\^i_&EEF07S*$8D>F;RISI  ax7|d"184%AgdT A 3 4 D##d*D <;;==MM$' D$'v./  %T B <.tfBqc:;; > " "%'WWT^^%<!E"E( $T U 2!!LLN#qLG #&= "7)+DEF )! !s>D++ D98D9)rrr,rr)NNNTrrL)__name__ __module__ __qualname____firstlineno__rrrrHrOrurrrrrrrrrrr$r/r5r9r rkrs__static_attributes__r]rrrrs  -T>  $  <T<|t. TCl >C>D> w%r&:PE,::2$:&oEb!FGrr)__doc__rrrr*rrpathlibrrlogururr_rr]rrr}s5   (K GK Gr