@@ -402,7 +402,7 @@ func (r *RusticBackup) Path() string {
402402 return fmt .Sprintf ("%s/snapshot-%s" , r .repositoryPath , r .snapshotID )
403403}
404404
405- // Size returns the size of the backup
405+ // Size returns the size of the backup accounting for deduplication
406406func (r * RusticBackup ) Size () (int64 , error ) {
407407 if r .snapshotID == "" {
408408 return 0 , errors .New ("rustic: no snapshot ID available" )
@@ -417,6 +417,19 @@ func (r *RusticBackup) Size() (int64, error) {
417417 defer cancel ()
418418 defer r .cleanup ()
419419
420+ // Get the proportional size based on repository deduplication
421+ size , err := r .calculateProportionalSize (ctx )
422+ if err != nil {
423+ // Fallback to DataAdded if proportional calculation fails
424+ r .log ().WithError (err ).Debug ("failed to calculate proportional size, falling back to DataAdded" )
425+ return r .getSnapshotDataAdded (ctx )
426+ }
427+
428+ return size , nil
429+ }
430+
431+ // getSnapshotDataAdded returns the raw DataAdded value for backward compatibility
432+ func (r * RusticBackup ) getSnapshotDataAdded (ctx context.Context ) (int64 , error ) {
420433 cmd := r .buildRusticCommandWithContext (ctx , "snapshots" , "--json" , r .snapshotID )
421434 output , err := cmd .Output ()
422435 if err != nil {
@@ -442,6 +455,66 @@ func (r *RusticBackup) Size() (int64, error) {
442455 return 0 , errors .New ("rustic: snapshot not found or size unavailable" )
443456}
444457
458+ // calculateProportionalSize calculates the proportional size of this backup based on repository deduplication
459+ func (r * RusticBackup ) calculateProportionalSize (ctx context.Context ) (int64 , error ) {
460+ if r .serverUuid == "" {
461+ return 0 , errors .New ("rustic: server UUID required for proportional size calculation" )
462+ }
463+
464+ // Get repository information
465+ repoInfo , err := r .getRepositoryInfo (ctx )
466+ if err != nil {
467+ return 0 , errors .Wrap (err , "failed to get repository information for size calculation" )
468+ }
469+
470+ // Get all snapshots for this server
471+ snapshots , err := r .getAllServerSnapshots (ctx )
472+ if err != nil {
473+ return 0 , errors .Wrap (err , "failed to get all server snapshots for size calculation" )
474+ }
475+
476+ if len (snapshots ) == 0 {
477+ return 0 , errors .New ("no snapshots found for proportional size calculation" )
478+ }
479+
480+ // Find our snapshot and calculate proportional size
481+ var ourSnapshot * RusticSnapshotInfo
482+ var totalDataAdded int64
483+
484+ for _ , snapshot := range snapshots {
485+ if snapshot .Summary != nil && snapshot .Summary .DataAdded > 0 {
486+ totalDataAdded += snapshot .Summary .DataAdded
487+ }
488+
489+ // Check if this is our snapshot
490+ if snapshot .ID == r .snapshotID ||
491+ (len (r .snapshotID ) == 8 && strings .HasPrefix (snapshot .ID , r .snapshotID )) {
492+ ourSnapshot = & snapshot
493+ }
494+ }
495+
496+ if ourSnapshot == nil {
497+ return 0 , errors .New ("current snapshot not found in server snapshots" )
498+ }
499+
500+ if ourSnapshot .Summary == nil || ourSnapshot .Summary .DataAdded == 0 {
501+ return 1024 , nil // Return minimum size for empty snapshots
502+ }
503+
504+ totalRepoDataSize := repoInfo .GetTotalDataSize ()
505+ if totalDataAdded == 0 || totalRepoDataSize == 0 {
506+ return ourSnapshot .Summary .DataAdded , nil // Fallback to original size
507+ }
508+
509+ // Calculate proportional size: (this snapshot's original contribution / total original) * actual repository size
510+ proportionalSize := int64 (float64 (ourSnapshot .Summary .DataAdded ) / float64 (totalDataAdded ) * float64 (totalRepoDataSize ))
511+
512+ // Ensure minimum size (avoid zero-sized backups)
513+ proportionalSize = max (proportionalSize , 1024 ) // 1KB minimum
514+
515+ return proportionalSize , nil
516+ }
517+
445518// Checksum returns a checksum for the backup
446519func (r * RusticBackup ) Checksum () ([]byte , error ) {
447520 if r .snapshotID == "" {
0 commit comments