Повреждения в Календаре: дубликаты. Как проанализировать их причину и устранить?

1

Я использую Calendarна Mac под управлением MacOS X Mountain Lion (10.8.5).

Этот Mac вручную регулярно синхронизируется с iPhone под управлением iOS 7.1.2.

Здесь Calendarхранятся 15 лет мероприятий, организованных в рамках 9 «календарей». Поскольку часть этой информации является высокочувствительной, профессиональной или частной, я не синхронизирую ее ни в какой форме календаря общедоступного магазина ( iCloud, Google Calendar...). С другой стороны, у меня есть много Time Machineрезервных копий и полных резервных копий.

Недавно я неожиданно обнаружил, что с лета 2001 года я дублировал события полного дня Calendarна моем Mac. Я смог увидеть их быстро, так как их двойная природа видна непосредственно. Это не общий случай: большинство моих событий на весь день не дублируются. Но все мои 9 "календарей" пострадали от этой коррупции . Я считаю, что у меня есть несколько сотен событий в этом случае. Я вижу то же самое искажение на моем iPhone.


Я экспортировал один из моих календарей и извлек одну из дублированных записей. Вот вывод diff на 2 .icsвыдержки:

••My_Mac••$ diff duplicate.[12].ics
2c2
< UID:74FC7CC1-016C-4A74-9E02-7ECDD82C8129
---
> UID:9B6BC4CD-5859-4DC2-8DEA-9158CB8F9B0D
10,11c10,11
< X-WR-ALARMUID:D0FE4A14-981C-4409-84C1-B11107F7EC31
< UID:D0FE4A14-981C-4409-84C1-B11107F7EC31
---
> X-WR-ALARMUID:48141767-C3C6-4131-9984-0DD080833D9F
> UID:48141767-C3C6-4131-9984-0DD080833D9F
••My_Mac••$

Обозначение: ••имя строки ••означает, что «имя» было отредактировано.

Вот что я нашел внутри /var/log/system.logи что может быть связано:

13 сентября 10:08:32 •• My_Mac •• SyncServer [93677]: [0x7fbe60c0bdd0] | SyncServer | Предупреждение | Обновление сторожевого таймера из-за предупреждения о смене времени календаря.
13 сентября 16:09:10 •• My_Mac •• SyncServer [94189]: [0x7fd25a40bdd0] | SyncServer | Предупреждение | Обновление сторожевого таймера из-за предупреждения о смене времени календаря.
14 сентября 03:21:15 •• My_Mac •• SyncServer [94351]: [0x7f9e1ac0bdd0] | SyncServer | Предупреждение | Обновление сторожевого таймера из-за предупреждения о смене времени календаря.
14 сентября 08:56:41 •• My_Mac •• SyncServer [94351]: [0x7f9e1ac0bdd0] | SyncServer | Предупреждение | Обновление сторожевого таймера из-за предупреждения о смене времени календаря.
15 сентября 14:11:39 •• My_Mac •• SyncServer [94351]: [0x7f9e1ac0bdd0] | SyncServer | Предупреждение | Обновление сторожевого таймера из-за предупреждения о смене времени календаря.
16 сентября 00:25:17 •• My_Mac •• SyncServer [95764]: [0x7faf92c0bdd0] | SyncServer | Предупреждение | Обновление сторожевого таймера из-за предупреждения о смене времени календаря.
16 сентября 13:36:27 •• My_Mac •• SyncServer [96213]: [0x7f9470c0bdd0] | SyncServer | Предупреждение | Обновление сторожевого таймера из-за предупреждения о смене времени календаря.
16 сентября 13:51:33 •• My_Mac •• CalendarAgent [90827]: недопустимый символ _ для PropertyName в строке 7
16 сентября, 13:51:33 •• My_Mac •• CalendarAgent [90827]: неожиданный EOF, возвращающий последний токен как запасной


Как я могу проанализировать, откуда происходят эти дубликаты событий?

Как я могу найти дату и время, когда событие могло начать искажать мои планы? Без даты начала повреждения мои резервные копии мало помогают. Более того, они будут означать полное восстановление правильных событий, которые произошли после повреждения .

Как я могу получить правильное видение этого искажения всех моих «календарей»?

И кроме того, как я могу исправить это огромное и явно случайное повреждение данных ?

Дан
источник

Ответы:

0

У меня пока нет правильного объяснения этих искажений, но, по крайней мере, я написал решение, чтобы иметь четкое представление о степени ущерба и исправить его.

Вот Perl-скрипт duplicate.pl:

$ cat <<'eof' >duplicate.pl
#!/usr/bin/perl
use strict ;
use warnings ;

# program reading on its standard input a file under
# ics format exported by iCal or Calendar
# Both only export one calendar at a time

# file = name of created file for a given calendar

my %file = () ;

# filedesc = file descriptor of the created calendar file

my %filedesc = () ;

# hash of all unduplicated events local_event_id
my %events = () ;

# current event storage
my @event = () ;
my $dtstart = '' ;
my $dtend = '' ;

# number of events analysed
my $num_event = 0 ;
my $duplicate = 0 ;
my $calendar = '' ;

# state booleans
my $in_header = 1 ;
my $in_event = 0 ;
my $in_summary = 0 ;
my $line = '' ;
my $summary = '' ;

# local event identifier :      summary;dtstart;dtend
# because ';' is never used within a name
my $local_event_id = '' ;

while (<STDIN>) {
        $line = $_ ;

# header :      BEGIN:VCALENDAR
#               ...
#               BEGIN:VEVENT

        if ( $in_summary ) {

#               continuation line of summary

                if ( $line =~ /^ (.+)\r\n$/ ) {
                        $summary .= $1 ;
                } else {

#                       end of summary continuation lines analysis

                        $in_summary = 0 ;
                }
        }
        if ( $line =~ /^SUMMARY[^:]*:(.+)\r\n$/ ) {
                $summary = $1 ;
                $in_summary = 1 ;
        } elsif ( $line =~ /^BEGIN:VEVENT/) {
                if ( $in_header ) {
                        $in_header = 0 ;

#                       print every lines of event or header

                        foreach $line (@event) {
                                printf {$filedesc{$calendar}} "%s", $line ;
                        }
                }
                $in_event = 1 ;
                @event = () ;
        } elsif ( $line =~ /^X-WR-CALNAME:(.+)\r\n$/) {
                $calendar = $1 ;

#               create .ics file

                if ( ! defined $file{$calendar} ) {
                        $file{$calendar} = $calendar . ".ics" ;
                        if ( -e $file{$calendar} ) {
                                die "$file{$calendar} already exists\n" ;
                        }
                        open ($filedesc{$calendar}, ">", $file{$calendar}) ;

#                       print every lines of header

                        foreach $line (@event) {
                                printf {$filedesc{$calendar}} "%s", $line ;
                        }
                        @event = () ;
                        $in_event = 0 ;
                }
#               printf STDOUT "calendar = %s\n", $calendar ;
#               printf STDOUT "file = %s\n", $file{$calendar} ;
#               printf STDOUT "fh = %d\n", $filedesc{$calendar} ;

        } elsif ( $line =~ /^DTSTART[^:]*:(.*)\r\n$/ ) {
                $dtstart = $1 ;

#               printf STDOUT "DTSTART = %32s\n", $dtstart ;

        } elsif ( $line =~ /^DTEND[^:]*:(.*)\r\n$/ ) {
                $dtend = $1 ;

#               printf STDOUT "DTEND = %32s\n", $dtend ;

        } elsif ( $line =~ /^END:VEVENT/ ) {

# it's only on closing an event definition that we have
# a complete local event identifier

                $local_event_id = "$summary" . ";" . "$dtstart" . ";" . "$dtend" ;


                if ( defined ( $events{"$local_event_id"} )) {

#                       duplicate event

                        printf STDOUT "\n\tduplicate\t%s\n", $local_event_id ;

#                       free event storage

                        @event = () ;
                        $in_event = 0 ;
                        $duplicate++ ;
                } else {

#                       new event
                        $events{$local_event_id} = 1;

                        if ($in_event) {

#                               print every lines of stored event

                                foreach $line (@event) {
                                        printf {$filedesc{$calendar}} "%s", $line ;
                                }
                                @event = () ;
                                $in_event = 0 ;
                                $num_event++ ;
                                $in_header = 1 ;

#                               show progress
                                if (($num_event % 100) == 0) {
                                        printf STDOUT "\n%8d", $num_event ;
                                } else {
                                        print STDOUT "." ;
                                }
                        }
                }
        } elsif ( $in_event == 0 ) {
                $in_header = 1 ;
        }

#       store every line of event or header

        if ($in_event || $in_header) {
                push (@event, $line) ;
        }

}

printf STDOUT "\nevents:%12d\n", $num_event ;
printf STDOUT "duplicates:%8d\n", $duplicate ;

#                       print every lines of ending

                        foreach $line (@event) {
                                printf {$filedesc{$calendar}} "%s", $line ;
                        }

close ($filedesc{$calendar}) ;
exit 0 ;
eof
$ chmod u+x duplicate.pl

И вот как я это использовал:

  1. Из Calendar, экспортируйте данный календарь через:

    File > Export > Export...

    скажем так: Documents/Calendar/2015/professionnal.ics

    NB .: это будет резервной копией в случае возникновения проблемы, и гораздо более практичным, чем любые манипуляции с файлами с помощью Time Machine

  2. Установите приведенный выше скрипт как:

    ~/Documents/Calendar/src/duplicate.pl
    
  3. Перейдите в каталог, чтобы проверить исправленную версию, например:

    mkdir ~/Documents/Calendar/2015.fixed
    cd ~/Documents/Calendar/2015.fixed
    
  4. Выполнить duplicate.pl:

    ../src/duplicate.pl <../2015/professionnal.ics
    

    который отобразит количество прочитанных событий и количество найденных дубликатов и создаст здесь фиксированную версию календаря:

    ~/Documents/Calendar/2015.fixed/professionnal.ics
    
  5. Сравните результат с исходной поврежденной версией, чтобы убедиться, что все в порядке:

     diff ../2015/professionnal.ics .
    
  6. Внутри Calendarвыберите календарь professionnalи удалите его через:

    Edit > Delete

  7. Импортируйте фиксированный через:

    File > Import > Import...

Дан
источник