沈夜把乙册介质的目录结构彻底打开以后,屏幕上出现的是几百行表格数据。他让林小雪举着手电,自己一行一行往下扫。表格的每一行对应一个孩子,字段不多,姓名,编号,补课批次,出生日期。
他先按老周的提示,没有看第一行,而是从最后一行开始往前翻。名单的末尾部分已经没有姓名,只剩几行残缺的记录,像是数据写入时被截断过。他把滚动条拖回顶部,才明白老周为什么要让他先看最后一行。
这份名单的第一行,不是孩子,是一段登记说明。上面写着,本册收录历年补课记录,借阅人不得增删页数,如有遗失,按名录补录。
沈夜说,借阅须知第四条,归还时须原样放回,不得增删页数。老周怕我按规矩从头看起,把时间都耗在这些说明上。
他把第一行说明略过,开始逐行比对出生日期。几百行的数据,光靠肉眼对不齐。他让林小雪拿手机录屏,自己把窗口放大,按批次把孩子们分成组。
林小雪说,几百个孩子,要是有人真把东西做进某个日期里,做的人得怎么保证你能找到。
沈夜说,他不会让我找。他说,老周做这种事向来会留一个能让人一眼抓住的破绽,只是破绽藏在规则的漏洞里,要顺着规则读才看得见。
他说着,放慢滚动速度,把注意力放在每一条字段对齐异常的行上。名单里大多数行的字段都排得整整齐齐,只有少数几行缺了半个字段,像是删改时留下的尾巴。
他数了数,这几行记录,全部集中在名单的中后段。
林小雪在旁边看了一会儿,说,这些出生日期,看着没什么规律。
沈夜没有答话。他盯着屏幕,手指在检修台上无意识地敲着。忽然,他停住了,说,有规律。他说,你注意看,每三个孩子一组,出生日期的末两位是依次递增的。
林小雪顺着他的手指看过去。三行数据排在一起,出生日期分别是十七日,十八日,十九日,果然是连着走的。她继续往后看,下一组又是如此,二十三日,二十四日,二十五日。
她说,是连着。可名单这么长,孩子又不是按出生日期排队的,怎么会这么整齐。
沈夜说,所以它不是孩子的出生日期。它是一串编号,套着出生日期的壳。
他说,在老周的年代,能往档案里写这种编号的人,一定很熟悉这份名单的字段结构。编号按组递增,说明写它的人在用一种近乎程序化的方式管理这些孩子,不是把他们当成名字,而是当成一串需要排好序的记录。
林小雪说,把活人排成编号,这听起来比鬼故事还冷。
沈夜说,是冷。他说,但老周留下来的提示也正因为这样才管用。他混在这一套编号系统里待了那么久,才会在关键位置留下一个空缺,而不是直接写一句碎片在这里。
林小雪说,直接写,会被人顺着查到。
沈夜说,对。他说,老周要防的,不是翻档案的管理员,而是那些看得懂名字、看不懂编号的人。他赌的就是,只有真正按编号逻辑来找东西的人,才会发现那个空缺。
林小雪说,而你就是那个会按编号逻辑找东西的人。
沈夜没有否认。他盯着那组残缺的单元格标记,说,也可能是老周从一开始就算好了,总有一天会有一个写程序的人,走到这份名单面前。
他拖动滚动条,快速翻过中间几百行,专门看每一组的末尾。大部分组的递增都正常,可翻到名单中后段时,他忽然停住。有一组数据,第三个孩子的出生日期之后,本该接上第四个孩子的日期,可那里是空的,整行被删除,只留下一个残缺的单元格标记。
林小雪说,缺了一行。
沈夜说,老周那句话说的是,碎片在出生日期里。可他没说,是在哪一行出生日期里。现在看来,碎片不在任何一行现有的出生日期里,而在这个空缺里。
他调出那组数据,把前后两组末两位的递增值算出来。空缺的位置,对应的正好是一组完整序列里缺失的那一个日期。他把那个日期在纸上写下来,盯着看了很久,说,这个日期,跟我自己的生日,差了一位。
林小雪说,差在哪一位。
沈夜说,月份相同,日期不同。名单里缺的这个日期,是把我的出生日期改了一个数字以后的样子,像是一个故意做出来的变体。
林小雪说,如果它是你出生日期的变体,那它指向的,就不该是一个具体的人,而是一串数据。
沈夜点头。他说,第五份碎片不在乙册现有的数据里。它藏在乙册的底层,藏在一条被删掉的行注释里。
他打开介质的底层维护模式,这个操作他在老东家机房干了三年,闭着眼都能做。屏幕上弹出十六进制数据流,他沿着名单文件的末尾,找到了那段被标记删除的区域。
删除标记是好的,完全符合规范。如果换成别人,看到这段区域只会把它当成正常清理过的垃圾数据,直接跳过。可沈夜知道,在程序里,被标记删除不等于消失。只要没人覆盖,那段数据就还躺在原地。