1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 // streaming file system (virtual)
17 {$INCLUDE ../shared/a_modes.inc}
18 {.$R+}
19 {.$DEFINE SFS_VOLDEBUG}
22 interface
24 uses
28 type
34 public
36 fPath: AnsiString; // ðàçäåëèòåëè êàòàëîãîâ -- "/"; êîðåíü íèêàê íå îáîçíà÷åí, åñëè íå ïóñòîå, îáÿçàíî çàâåðøàòüñÿ "/"
49 // âèðòóàëüíàÿ ôàéëîâàÿ ñèñòåìà. ÒÎËÜÊÎ ÄËß ×ÒÅÍÈß!
50 // òîì ÍÅ ÄÎËÆÅÍ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè ôàáðèêè!
52 protected
57 // ïðèøèáèòü âñå ñòðóêòóðû.
58 // íå äîëæíà ïàäàòü, åñëè å¸ âûçûâàþò íåñêîëüêî ðàç.
61 // âûçûâàåòñÿ èç DoDirectoryRead() äëÿ çàïîëíåíèÿ ñïèñêà ôàéëîâ.
62 // ñ÷èòàåòñÿ, ÷òî âñå ìàãèêè óæå ïðîâåðåíû è ôàéë òî÷íî íàø.
63 // fFileName, fFileStream óæå óñòàíîâëåíû, fFiles ñîçäàí,
64 // â í¸ì, ñêîðåå âñåãî, íèêîãî íåò.
65 // ïîçèöèÿ ïîòîêà -- òà, ÷òî îñòàâèëà ôàáðèêà.
66 // ïðè îøèáêàõ êèäàòü èñêëþ÷åíèå, òîãäà òîì áóäåò ïðèáèò ôàáðèêîé.
67 // ðàçäåëèòåëè ïóòåé äîëæíû áûòü òîëüêî "/", êîðíåâîé "/" äîëæåí
68 // áûòü îïóùåí, ïóòè (åñëè íå ïóñòûå) äîëæíû çàâåðøàòüñÿ "/"!
69 // fName äîëæíî ñîäåðæàòü òîëüêî èìÿ, fPath -- òîëüêî ïóòü.
70 // â ïðèíöèïå, îá ýòîì ïîçàáîòèòñÿ DoDirectoryRead(), íî çà÷åì
71 // äàâàòü åìó ëèøíþþ ðàáîòó?
74 // íàéòè ôàéë, âåðíóòü åãî èíäåêñ â fFiles.
75 // ýòà ïðîöåäóðà ìîæåò ìåíÿòü fFiles!
76 // fPath -- â ïðàâèëüíîé ôîðìå, ñ "/", êîðíåâîé "/" óáèò, ôèíàëüíûé äîáàâëåí.
77 // åñëè ôàéë íå íàéäåí, âåðíóòü -1.
80 // âîçâðàùàåò êîëè÷åñòâî ôàéëîâ â fFiles
83 // âîçâðàùàåò ôàéë ñ èíäåêñîì index.
84 // ìîæåò âîçâðàùàòü NIL.
85 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
88 public
89 // pSt íå îáÿçàòåëüíî çàïîìèíàòü, åñëè îí íå íóæåí.
91 // fFileStream óíè÷òîæàòü íåëüçÿ, åñëè îí ðàâåí ïàðàìåòðó pSt êîíñòðóêòîðà.
94 // âûçûâàåò ReadDirectory().
95 // ýòà ïðîöåäóðà ñàìà ðàçáåð¸òñÿ ñ äóáëèêàòàìè èì¸í: ïîäîáàâëÿåò â
96 // êîíåö èì¸í-äóáëèêàòîâ ïîä÷¸ðêèâàíèå è äåñÿòè÷íûé íîìåð.
97 // òàêæå îíà íîðìàëèçóåò âèä èì¸í.
100 // ïðè îøèáêàõ êèäàòüñÿ èñêëþ÷åíèÿìè.
103 // åñëè íå ñìîãëî îòêóïîðèòü ôàéëî (èëè åù¸ ãäå îøèáëîñü), çàøâûðí¸ò èñêëþ÷åíèå.
107 // ìîæåò âîçâðàùàòü NIL.
108 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
112 // ôàáðèêà òîìîâ. âñå SFS ïðè ñòàðòå äîáàâëÿþò ñâîè ôàáðèêè.
113 // áëàãîäàðÿ ýòîìó ìîæíî ñîçäàâàòü ðàçíûå âñÿêèå SFS ñòàíäàðòíûì
114 // âûçîâîì ñòàíäàðòíîé ïðîöåäóðû.
115 // ôàáðèêà ÍÅ ÄÎËÆÍÀ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè âûçîâà
116 // SFSUnregisterVolumeFactory()! ýòî ãàðàíòèðóåò, ÷òî äâèæîê
117 // ïåðåä ðàññòðåëîì îòäàñò åé âñå å¸ òîìà.
119 public
120 // åñëè äîáàâëÿåì ôàéë äàííûõ ôàéë ñ èìåíåì òèïà "zip:....", òî
121 // SFS èçâëå÷¸ò ýòî "zip" è ïåðåäàñò â ñèþ ôóíêöèþ.
122 // åæåëè ôóíêöèÿ âåðí¸ò ïðàâäó, òî SFS âûçîâåò Produce äëÿ äàííîãî
123 // ôàéëà. åñëè íè îäíà ôàáðèêà ïðåôèêñ íå ïðèçíàåò, òî ôàéë íå îòêðîþò.
124 // èñïîëüçóåòñÿ äëÿ ñêèïàíèÿ àâòîäåòåêòà.
125 // SFS ÍÅ Ñ×ÈÒÀÅÒ ÏÐÅÔÈÊÑÎÌ ÑÒÐÎÊÓ ÊÎÐÎ×Å ÒÐ¨Õ ÑÈÌÂÎËÎÂ!
127 // ïðîâåðÿåò, ìîæåò ëè ôàáðèêà ñäåëàòü òîì äëÿ äàííîãî ôàéëà.
128 // st -- îòêðûòûé äëÿ ÷òåíèÿ ôàéëîâé ïîòîê. óêàçàòåëü ÷òåíèÿ ñòîèò â íà÷àëå.
129 // ýòîò ïîòîê íåëüçÿ çàêðûâàòü!
130 // prefix: òî, ÷òî áûëî ïåðåäàíî â IsMyVolumePrefix() èëè ''.
131 // èñêëþ÷åíèå ñ÷èòàåòñÿ îøèáêîé, âîçâðàò NIL ñ÷èòàåòñÿ îøèáêîé.
132 function Produce (const prefix, fileName: AnsiString; st: TStream): TSFSVolume; virtual; abstract;
133 // êîãäà òîì áîëüøå íå íóæåí, îí áóäåò îòäàí ôàáðèêå íà ïåðåðàáîòêó.
134 // äàëåå äâèæîê íå áóäåò þçàòü ñåé òîì.
138 // "èòåðàòîð", âîçâðàùàåìûé SFSFileList()
140 protected
146 public
152 // ïðè íåïðàâèëüíîì èíäåêñå ìîë÷à âåðí¸ò NIL.
153 // ïðè ïðàâèëüíîì òîæå ìîæåò âåðíóòü NIL!
154 // î÷åíü íå ñîâåòóþ ìåíÿòü ñîäåðæèìîå ïîëó÷åííîãî êëàññà.
155 // êîíå÷íî, ÿ ìîã áû âîçâðàùàòü íîâóþ ñòðóêòóðó èëè íå÷òî ïîõîæåå,
156 // íî áëèí, åñëè òû èäèîò è íå óìååøü äàæå êîììåíòû ÷èòàòü, òî
157 // êàêîãî òû âîîáùå â ïðîãðàììèíã ïîëåç?
163 // ýòà ôóíêöèÿ àâòîìàòè÷åñêè ïðèáü¸ò factory.
166 // äîáàâèòü ñáîðíèê â ïîñòîÿííûé ñïèñîê.
167 // åñëè ñáîðíèê ñ òàêèì èìåíåì óæå îòêðûò, òî íå îòêðûâàåò åãî ïîâòîðíî.
168 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
169 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
170 // âåðí¸ò ëîæü ïðè îøèáêå.
171 // ñïîñîáíî îòêðûâàòü ñáîðíèêè â ñáîðíèêàõ ïðè ïîìîùè êðóòûõ èì¸í a-la:
172 // "zip:pack0::pack:pack1::wad2:pack2".
173 // â äàëüíåéøåì ñëåäóåò îáðàùàòüñÿ ê ñáîðíèêó êàê "pack2::xxx".
174 // èëè ìîæíî íàïèñàòü:
175 // "zip:pack0::pack:pack1::wad2:pack2|datafile".
176 // è îáðàùàòüñÿ êàê "datafile::xxx".
177 // "||" ïðåîáðàçóþòñÿ â ïðîñòîé "|" è ðàçäåëèòåëåì íå ñ÷èòàþòñÿ.
178 // ïðèíèìàåòñÿ âî âíèìàíèå òîëüêî ïîñëåäíÿÿ òðóáà.
181 // äîáàâèòü ñáîðíèê âðåìåííî
184 // äîáàâèòü â ïîñòîÿííûé ñïèñîê ñáîðíèê èç ïîòîêà ds.
185 // åñëè âîçâðàùàåò èñòèíó, òî SFS ñòàíîâèòñÿ âëÿäåëüöåì ïîòîêà ds è ñàìà
186 // óãðîáèò ñåé ïîòîê ïî íåîáõîäèìîñòè.
187 // virtualName ñòàíîâèòñÿ èìåíåì ñáîðíèêà äëÿ îïåðàöèè îòêðûòèÿ ôàéëà òèïà
188 // "packfile:file.ext".
189 // åñëè êàêîé-íèáóäü ñáîðíèê ñ èìåíåì virtualName óæå îòêðûò, âåðí¸ò false.
190 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
191 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
192 // âåðí¸ò ëîæü ïðè îøèáêå.
193 // îòêðûâàåò ñáîðíèê èç ïîòîêà. dataFileName -- ÂÈÐÒÓÀËÜÍÎÅ èìÿ.
194 // ò.å. íà ñàìîì äåëå òàêîãî ôàéëà ìîæåò è íå áûòü íà äèñêå.
195 function SFSAddSubDataFile (const virtualName: AnsiString; ds: TStream; top: Boolean=false): Boolean;
197 // øâûðÿåòñÿ èñêëþ÷åíèÿìè.
198 // åñëè fName íå èìååò óêàçàíèÿ íà ôàéë äàííûõ (ýòî òî, ÷òî îòäåëåíî îò
199 // îñòàëüíîãî èìåíè äâîåòî÷èåì), òî èùåì ñíà÷àëà ïî âñåì çàðåãèñòðèðîâàííûì
200 // ôàéëàì äàííûõ, ïîòîì â òåêóùåì êàòàëîãå, ïîòîì â êàòàëîãå, îòêóäà ñòàðòîâàëè.
201 // åñëè íè÷åãî íå íàøëè, êèäàåì èñêëþ÷åíèå.
204 // ïðè îøèáêå -- NIL, è íèêàêèõ èñêëþ÷åíèé.
207 // âîçâðàùàåò NIL ïðè îøèáêå.
208 // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-)
211 // çàïðåòèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
214 // ðàçðåøèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
217 // for completeness sake
222 // ðàçîáðàòü òîëñòîå èìÿ ôàéëà, âåðíóòü âèðòóàëüíîå èìÿ ïîñëåäíåãî ñïèñêà
223 // èëè ïóñòóþ ñòîðîêó, åñëè ñïèñêîâ íå áûëî.
226 // Wildcard matching
227 // this code is meant to allow wildcard pattern matches. tt is VERY useful
228 // for matching filename wildcard patterns. tt allows unix grep-like pattern
229 // comparisons, for instance:
230 //
231 // ? Matches any single characer
232 // + Matches any single characer or nothing
233 // * Matches any number of contiguous characters
234 // [abc] Matches a or b or c at that position
235 // [!abc] Matches anything but a or b or c at that position
236 // [a-e] Matches a through e at that position
237 //
238 // 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
239 // 'this [e-n]s a [!zy]est' -Would match 'this is a test', but would
240 // not match 'this as a yest'
241 //
247 var
248 // ïðàâäà: ðàçðåøåíî èñêàòü ôàéëî íå òîëüêî â ôàéëàõ äàííûõ, íî è íà äèñêå.
250 // ïðàâäà: åñëè ôàéë íå ïðåôèêñîâàí, òî ñíà÷àëà èùåì ôàéëî íà äèñêå,
251 // ïîòîì â ôàéëàõ äàííûõ.
253 // ïðàâäà: äàæå äëÿ ïðåôèêñîâàíûõ ôàéëîâ ñíà÷àëà ïðîñìîòðèì äèñê
254 // (åñëè óñòàíîâëåí ôëàæîê sfsDiskFirst è sfsDiskEnabled).
256 // ñïèñîê äèñêîâûõ êàòàëîãîâ äëÿ ïîèñêà ôàéëà. åñëè ïóñò -- èùåì òîëüêî â
257 // òåêóùåì. êàòàëîãè ðàçäåëÿþòñÿ òðóáîé ("|").
258 // <currentdir> çàìåíÿåòñÿ íà òåêóùèé êàòàëîã (ñ çàâåðøàþùèì "/"),
259 // <exedir> çàìåíÿåòñÿ íà êàòàëîã, ãäå ñèäèò .EXE (ñ çàâåðøàþùèì "/").
263 implementation
265 uses
269 const
270 // character defines
282 begin
283 result :=
291 function MatchMask (const pattern: AnsiString; p, pend: Integer; const text: AnsiString; t, tend: Integer): Boolean;
292 var
296 begin
297 // sanity checks
303 begin
305 begin
306 // no more text. check if there's no more chars in pattern (except "*" & "+")
311 exit;
314 WILD_CHAR_SINGLE: ;
315 WILD_CHAR_ESCAPE:
316 begin
321 WILD_CHAR_RANGE_OPEN:
322 begin
330 repeat
336 begin
340 begin
342 end
344 end
349 // skip the rest or the range
353 WILD_CHAR_SINGLE_OR_NONE:
354 begin
358 exit;
360 WILD_CHAR_MULTI:
361 begin
365 begin
369 exit;
380 begin
387 var
389 begin
395 begin
397 begin
399 begin
406 begin
416 type
418 public
423 fPermanent: Boolean; // èñòèíà -- íå áóäåò óãðîáëåíà, åñëè íå îñòàíåòñÿ íè îäíîãî îòêðûòîãî òîìà
424 // èñòèíà -- ýòîò òîì áûë ñîçäàí èç ïîòîêà è íå èìååò äèñêîâîãî ôàéëà, ïîòîìó ôàáðèêå áóäåò ïåðåäàíî íå èìÿ ñáîðíèêà, à ïóñòàÿ ñòðîêà
432 protected
435 public
441 var
448 var
452 begin
453 // collect garbage
456 begin
460 begin
461 // this volume probably can be removed
465 begin
467 begin
475 begin
476 {$IFDEF SFS_VOLDEBUG}writeln('000: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
480 continue;
488 begin
493 begin
496 begin
503 // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
504 // ñîáñòâåííî èìÿ ôàéëà
505 // èìÿ âûãëÿäèò êàê:
506 // (("sfspfx:")?"datafile::")*"filename"
508 var
510 begin
513 begin
518 else
519 begin
525 // ñàéäýôôåêò: âûðåçàåò âèðòóàëüíîå èìÿ èç dataFile.
527 var
529 begin
532 begin
535 begin
537 else
538 begin
541 break;
548 // ðàçáèòü èìÿ ñáîðíèêà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
549 // âèðòóàëüíîå èìÿ. åñëè âèðòóàëüíîãî èìåíè íå äàíî, îíî áóäåò ðàâíî dataFile.
550 // èìÿ âûãëÿäèò êàê:
551 // [sfspfx:]datafile[|virtname]
552 // åñëè ïåðåä äâîåòî÷èåì ìåíüøå òð¸õ áóêâ, òî ýòî ñ÷èòàåòñÿ íå ïðåôèêñîì,
553 // à èìåíåì äèñêà.
555 var
557 begin
560 else
561 begin
568 // íàéòè ïðîèçâîäèòåëÿ äëÿ ýòîãî ôàéëà (åñëè ôàéë óæå îòêðûò).
569 // onlyPerm: òîëüêî "ïîñòîÿííûå" ïðîèçâîäèòåëè.
571 var
574 begin
577 begin
579 begin
582 begin
584 begin
586 exit;
595 // íàéòè èíôó äëÿ ýòîãî òîìà.
596 // õîðîøåå èìÿ, ïðàâäà? %-)
598 begin
601 begin
603 begin
611 // adds '/' too
613 var
615 begin
619 begin
621 begin
623 continue;
626 begin
628 end
629 else
630 begin
639 var
641 begin
644 begin
646 begin
647 // avoid unnecessary string changes
654 var
657 begin
659 repeat
667 { TVolumeInfo }
669 var
672 begin
679 // òèïà ìóñîðîñáîðíèê: åñëè íàø ïîòîê áîëåå íèêåì íå þçàåòñÿ, òî óãðîáèòü åãî íàôèã
681 begin
685 begin
687 begin
690 begin
703 { TOwnedPartialStream }
706 begin
713 var
715 begin
718 begin
721 begin
724 begin
725 {$IFDEF SFS_VOLDEBUG}writeln('001: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
733 { TSFSFileInfo }
735 begin
746 begin
752 { TSFSVolume }
754 begin
762 var
766 begin
773 begin
775 // normalize name & path
782 begin
783 // split path and name
795 begin
802 begin
807 begin
809 else
810 begin
813 begin
816 begin
826 begin
831 begin
833 else
834 begin
841 var
844 begin
846 // normalize name, find split position
850 begin
863 { TSFSFileList }
865 var
867 begin
877 var
879 begin
883 // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî
884 if (gcdisabled = 0) and not TVolumeInfo(volumes[f]).fPermanent and (TVolumeInfo(volumes[f]).fOpenedFilesCount < 1) then
885 begin
886 {$IFDEF SFS_VOLDEBUG}writeln('002: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
893 begin
898 begin
905 var
907 begin
916 var
919 begin
924 begin
932 function SFSAddDataFileEx (dataFileName: AnsiString; ds: TStream; top, permanent: Integer): Integer;
933 // dataFileName ìîæåò èìåòü ïðåôèêñ òèïà "zip:" (ñì. âûøå: IsMyPrefix).
934 // ìîæåò âûêèíóòü èñêëþ÷åíèå!
935 // top:
936 // <0: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
937 // =0: íå ìåíÿòü.
938 // >0: äîáàâèòü â êîíåö ñïèñêà ïîèñêà.
939 // permanent:
940 // <0: ñîçäàòü "âðåìåííûé" òîì.
941 // =0: íå ìåíÿòü ôëàæîê ïîñòîÿíñòâà.
942 // >0: ñîçäàòü "ïîñòîÿííûé" òîì.
943 // åñëè ds <> nil, òî ñîçäà¸ò ñáîðíèê èç ïîòîêà. åñëè ñáîðíèê ñ èìåíåì
944 // dataFileName óæå çàðåãèñòðèðîâàí, òî ïàäàåò íàôèã.
945 // âîçâðàùàåò èíäåêñ â volumes.
946 // óìååò äåëàòü ðåêóðñèþ.
947 var
955 begin
958 begin
959 // ðåêóðñèâíîå îòêðûòèå.
960 // ðàçîáü¸ì dataFileName íà èìÿ ñáîðíèêà è îñòàòîê.
961 // pfx áóäåò èìåíåì ñáîðíèêà, dataFileName -- îñòàòêîì.
963 // ñíà÷àëà îòêðîåì ïåðâûé ñïèñîê...
965 // ...òåïåðü ïðîäîëæèì ñ îñòàòêîì.
966 // óçíàåì, êàêîå ôàéëî îòêðûâàòü.
967 // âûêîâûðÿåì ïåðâûé "::" ïðåôèêñ (ýòî áóäåò èìÿ ôàéëà).
970 // dataFileName õðàíèò îñòàòîê.
971 // èçâëå÷¸ì èìÿ ôàéëà:
973 // îòêðîåì ýòîò ôàéë
975 try
978 except
980 // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì.
981 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[result] := nil;
984 // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå.
986 try
989 except
993 exit;
996 // îáûêíîâåííîå íåðåêóðñèâíîå îòêðûòèå.
1001 begin
1008 exit;
1018 try
1020 begin
1025 try
1028 except
1034 except
1040 try
1042 begin
1045 end
1047 except
1063 function SFSAddSubDataFile (const virtualName: AnsiString; ds: TStream; top: Boolean=false): Boolean;
1064 var
1066 begin
1068 try
1072 except
1078 var
1080 begin
1081 try
1085 except
1091 var
1093 begin
1094 try
1098 except
1106 var
1109 begin
1112 begin
1123 begin
1128 end
1134 var
1142 // ïðîâåðèì, åñòü ëè ôàëî fn ãäå-òî íà äèñêàõ.
1143 var
1146 begin
1153 begin
1159 try
1161 exit;
1162 except
1167 begin
1174 begin
1175 // ïðåôèêñîâàíûé ôàéë
1177 begin
1185 try
1188 except
1190 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1193 exit;
1195 //Inc(vi.fOpenedFilesCount);
1197 exit;
1200 // íåïðåôèêñîâàíûé ôàéë
1202 begin
1206 // èùåì ïî âñåì ïåðìàíåíòíûì ïðåôèêñàì
1209 begin
1212 begin
1214 begin
1217 begin
1218 try
1221 //Inc(vi.fOpenedFilesCount);
1222 except
1236 begin
1237 try
1239 except
1245 var
1248 begin
1252 try
1254 except
1255 exit;
1259 try
1261 except
1262 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1267 initialization
1270 //finalization
1271 //volumes.Free(); // it fails for some reason... Runtime 217 (^C hit). wtf?!
1272 //factories.Free(); // not need to be done actually...