1 // streaming file system (virtual)
2 {$MODE DELPHI}
3 {$R+}
4 {.$DEFINE SFS_VOLDEBUG}
7 interface
9 uses
13 type
19 public
21 fPath: AnsiString; // ðàçäåëèòåëè êàòàëîãîâ -- "/"; êîðåíü íèêàê íå îáîçíà÷åí, åñëè íå ïóñòîå, îáÿçàíî çàâåðøàòüñÿ "/"
34 // âèðòóàëüíàÿ ôàéëîâàÿ ñèñòåìà. ÒÎËÜÊÎ ÄËß ×ÒÅÍÈß!
35 // òîì ÍÅ ÄÎËÆÅÍ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè ôàáðèêè!
37 protected
42 // ïðèøèáèòü âñå ñòðóêòóðû.
43 // íå äîëæíà ïàäàòü, åñëè å¸ âûçûâàþò íåñêîëüêî ðàç.
46 // âûçûâàåòñÿ èç DoDirectoryRead() äëÿ çàïîëíåíèÿ ñïèñêà ôàéëîâ.
47 // ñ÷èòàåòñÿ, ÷òî âñå ìàãèêè óæå ïðîâåðåíû è ôàéë òî÷íî íàø.
48 // fFileName, fFileStream óæå óñòàíîâëåíû, fFiles ñîçäàí,
49 // â í¸ì, ñêîðåå âñåãî, íèêîãî íåò.
50 // ïîçèöèÿ ïîòîêà -- òà, ÷òî îñòàâèëà ôàáðèêà.
51 // ïðè îøèáêàõ êèäàòü èñêëþ÷åíèå, òîãäà òîì áóäåò ïðèáèò ôàáðèêîé.
52 // ðàçäåëèòåëè ïóòåé äîëæíû áûòü òîëüêî "/", êîðíåâîé "/" äîëæåí
53 // áûòü îïóùåí, ïóòè (åñëè íå ïóñòûå) äîëæíû çàâåðøàòüñÿ "/"!
54 // fName äîëæíî ñîäåðæàòü òîëüêî èìÿ, fPath -- òîëüêî ïóòü.
55 // â ïðèíöèïå, îá ýòîì ïîçàáîòèòñÿ DoDirectoryRead(), íî çà÷åì
56 // äàâàòü åìó ëèøíþþ ðàáîòó?
59 // íàéòè ôàéë, âåðíóòü åãî èíäåêñ â fFiles.
60 // ýòà ïðîöåäóðà ìîæåò ìåíÿòü fFiles!
61 // fPath -- â ïðàâèëüíîé ôîðìå, ñ "/", êîðíåâîé "/" óáèò, ôèíàëüíûé äîáàâëåí.
62 // åñëè ôàéë íå íàéäåí, âåðíóòü -1.
65 // âîçâðàùàåò êîëè÷åñòâî ôàéëîâ â fFiles
68 // âîçâðàùàåò ôàéë ñ èíäåêñîì index.
69 // ìîæåò âîçâðàùàòü NIL.
70 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
75 public
76 // pSt íå îáÿçàòåëüíî çàïîìèíàòü, åñëè îí íå íóæåí.
78 // fFileStream óíè÷òîæàòü íåëüçÿ, åñëè îí ðàâåí ïàðàìåòðó pSt êîíñòðóêòîðà.
81 // âûçûâàåò ReadDirectory().
82 // ýòà ïðîöåäóðà ñàìà ðàçáåð¸òñÿ ñ äóáëèêàòàìè èì¸í: ïîäîáàâëÿåò â
83 // êîíåö èì¸í-äóáëèêàòîâ ïîä÷¸ðêèâàíèå è äåñÿòè÷íûé íîìåð.
84 // òàêæå îíà íîðìàëèçóåò âèä èì¸í.
87 // ïðè îøèáêàõ êèäàòüñÿ èñêëþ÷åíèÿìè.
90 // åñëè íå ñìîãëî îòêóïîðèòü ôàéëî (èëè åù¸ ãäå îøèáëîñü), çàøâûðí¸ò èñêëþ÷åíèå.
94 // ìîæåò âîçâðàùàòü NIL.
95 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
99 // ôàáðèêà òîìîâ. âñå SFS ïðè ñòàðòå äîáàâëÿþò ñâîè ôàáðèêè.
100 // áëàãîäàðÿ ýòîìó ìîæíî ñîçäàâàòü ðàçíûå âñÿêèå SFS ñòàíäàðòíûì
101 // âûçîâîì ñòàíäàðòíîé ïðîöåäóðû.
102 // ôàáðèêà ÍÅ ÄÎËÆÍÀ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè âûçîâà
103 // SFSUnregisterVolumeFactory()! ýòî ãàðàíòèðóåò, ÷òî äâèæîê
104 // ïåðåä ðàññòðåëîì îòäàñò åé âñå å¸ òîìà.
106 public
107 // åñëè äîáàâëÿåì ôàéë äàííûõ ôàéë ñ èìåíåì òèïà "zip:....", òî
108 // SFS èçâëå÷¸ò ýòî "zip" è ïåðåäàñò â ñèþ ôóíêöèþ.
109 // åæåëè ôóíêöèÿ âåðí¸ò ïðàâäó, òî SFS âûçîâåò Produce äëÿ äàííîãî
110 // ôàéëà. åñëè íè îäíà ôàáðèêà ïðåôèêñ íå ïðèçíàåò, òî ôàéë íå îòêðîþò.
111 // èñïîëüçóåòñÿ äëÿ ñêèïàíèÿ àâòîäåòåêòà.
112 // SFS ÍÅ Ñ×ÈÒÀÅÒ ÏÐÅÔÈÊÑÎÌ ÑÒÐÎÊÓ ÊÎÐÎ×Å ÒÐ¨Õ ÑÈÌÂÎËÎÂ!
114 // ïðîâåðÿåò, ìîæåò ëè ôàáðèêà ñäåëàòü òîì äëÿ äàííîãî ôàéëà.
115 // st -- îòêðûòûé äëÿ ÷òåíèÿ ôàéëîâé ïîòîê. óêàçàòåëü ÷òåíèÿ ñòîèò â íà÷àëå.
116 // ýòîò ïîòîê íåëüçÿ çàêðûâàòü!
117 // prefix: òî, ÷òî áûëî ïåðåäàíî â IsMyVolumePrefix() èëè ''.
118 // èñêëþ÷åíèå ñ÷èòàåòñÿ îøèáêîé, âîçâðàò NIL ñ÷èòàåòñÿ îøèáêîé.
119 function Produce (const prefix, fileName: AnsiString; st: TStream): TSFSVolume; virtual; abstract;
120 // êîãäà òîì áîëüøå íå íóæåí, îí áóäåò îòäàí ôàáðèêå íà ïåðåðàáîòêó.
121 // äàëåå äâèæîê íå áóäåò þçàòü ñåé òîì.
125 // "èòåðàòîð", âîçâðàùàåìûé SFSFileList()
127 protected
133 public
139 // ïðè íåïðàâèëüíîì èíäåêñå ìîë÷à âåðí¸ò NIL.
140 // ïðè ïðàâèëüíîì òîæå ìîæåò âåðíóòü NIL!
141 // î÷åíü íå ñîâåòóþ ìåíÿòü ñîäåðæèìîå ïîëó÷åííîãî êëàññà.
142 // êîíå÷íî, ÿ ìîã áû âîçâðàùàòü íîâóþ ñòðóêòóðó èëè íå÷òî ïîõîæåå,
143 // íî áëèí, åñëè òû èäèîò è íå óìååøü äàæå êîììåíòû ÷èòàòü, òî
144 // êàêîãî òû âîîáùå â ïðîãðàììèíã ïîëåç?
150 // ýòà ôóíêöèÿ àâòîìàòè÷åñêè ïðèáü¸ò factory.
153 // äîáàâèòü ñáîðíèê â ïîñòîÿííûé ñïèñîê.
154 // åñëè ñáîðíèê ñ òàêèì èìåíåì óæå îòêðûò, òî íå îòêðûâàåò åãî ïîâòîðíî.
155 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
156 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
157 // âåðí¸ò ëîæü ïðè îøèáêå.
158 // ñïîñîáíî îòêðûâàòü ñáîðíèêè â ñáîðíèêàõ ïðè ïîìîùè êðóòûõ èì¸í a-la:
159 // "zip:pack0::pack:pack1::wad2:pack2".
160 // â äàëüíåéøåì ñëåäóåò îáðàùàòüñÿ ê ñáîðíèêó êàê "pack2::xxx".
161 // èëè ìîæíî íàïèñàòü:
162 // "zip:pack0::pack:pack1::wad2:pack2|datafile".
163 // è îáðàùàòüñÿ êàê "datafile::xxx".
164 // "||" ïðåîáðàçóþòñÿ â ïðîñòîé "|" è ðàçäåëèòåëåì íå ñ÷èòàþòñÿ.
165 // ïðèíèìàåòñÿ âî âíèìàíèå òîëüêî ïîñëåäíÿÿ òðóáà.
168 // äîáàâèòü ñáîðíèê âðåìåííî
171 // äîáàâèòü â ïîñòîÿííûé ñïèñîê ñáîðíèê èç ïîòîêà ds.
172 // åñëè âîçâðàùàåò èñòèíó, òî SFS ñòàíîâèòñÿ âëÿäåëüöåì ïîòîêà ds è ñàìà
173 // óãðîáèò ñåé ïîòîê ïî íåîáõîäèìîñòè.
174 // virtualName ñòàíîâèòñÿ èìåíåì ñáîðíèêà äëÿ îïåðàöèè îòêðûòèÿ ôàéëà òèïà
175 // "packfile:file.ext".
176 // åñëè êàêîé-íèáóäü ñáîðíèê ñ èìåíåì virtualName óæå îòêðûò, âåðí¸ò false.
177 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
178 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
179 // âåðí¸ò ëîæü ïðè îøèáêå.
180 // îòêðûâàåò ñáîðíèê èç ïîòîêà. dataFileName -- ÂÈÐÒÓÀËÜÍÎÅ èìÿ.
181 // ò.å. íà ñàìîì äåëå òàêîãî ôàéëà ìîæåò è íå áûòü íà äèñêå.
182 function SFSAddSubDataFile (const virtualName: AnsiString; ds: TStream; top: Boolean=false): Boolean;
184 // øâûðÿåòñÿ èñêëþ÷åíèÿìè.
185 // åñëè fName íå èìååò óêàçàíèÿ íà ôàéë äàííûõ (ýòî òî, ÷òî îòäåëåíî îò
186 // îñòàëüíîãî èìåíè äâîåòî÷èåì), òî èùåì ñíà÷àëà ïî âñåì çàðåãèñòðèðîâàííûì
187 // ôàéëàì äàííûõ, ïîòîì â òåêóùåì êàòàëîãå, ïîòîì â êàòàëîãå, îòêóäà ñòàðòîâàëè.
188 // åñëè íè÷åãî íå íàøëè, êèäàåì èñêëþ÷åíèå.
191 // ïðè îøèáêå -- NIL, è íèêàêèõ èñêëþ÷åíèé.
194 // âîçâðàùàåò NIL ïðè îøèáêå.
195 // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-)
198 // çàïðåòèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
201 // ðàçðåøèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
204 // for completeness sake
209 // ðàçîáðàòü òîëñòîå èìÿ ôàéëà, âåðíóòü âèðòóàëüíîå èìÿ ïîñëåäíåãî ñïèñêà
210 // èëè ïóñòóþ ñòîðîêó, åñëè ñïèñêîâ íå áûëî.
213 // Wildcard matching
214 // this code is meant to allow wildcard pattern matches. tt is VERY useful
215 // for matching filename wildcard patterns. tt allows unix grep-like pattern
216 // comparisons, for instance:
217 //
218 // ? Matches any single characer
219 // + Matches any single characer or nothing
220 // * Matches any number of contiguous characters
221 // [abc] Matches a or b or c at that position
222 // [!abc] Matches anything but a or b or c at that position
223 // [a-e] Matches a through e at that position
224 //
225 // 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
226 // 'this [e-n]s a [!zy]est' -Would match 'this is a test', but would
227 // not match 'this as a yest'
228 //
234 var
235 // ïðàâäà: ðàçðåøåíî èñêàòü ôàéëî íå òîëüêî â ôàéëàõ äàííûõ, íî è íà äèñêå.
237 // ïðàâäà: åñëè ôàéë íå ïðåôèêñîâàí, òî ñíà÷àëà èùåì ôàéëî íà äèñêå,
238 // ïîòîì â ôàéëàõ äàííûõ.
240 // ïðàâäà: äàæå äëÿ ïðåôèêñîâàíûõ ôàéëîâ ñíà÷àëà ïðîñìîòðèì äèñê
241 // (åñëè óñòàíîâëåí ôëàæîê sfsDiskFirst è sfsDiskEnabled).
243 // ñïèñîê äèñêîâûõ êàòàëîãîâ äëÿ ïîèñêà ôàéëà. åñëè ïóñò -- èùåì òîëüêî â
244 // òåêóùåì. êàòàëîãè ðàçäåëÿþòñÿ òðóáîé ("|").
245 // <currentdir> çàìåíÿåòñÿ íà òåêóùèé êàòàëîã (ñ çàâåðøàþùèì "/"),
246 // <exedir> çàìåíÿåòñÿ íà êàòàëîã, ãäå ñèäèò .EXE (ñ çàâåðøàþùèì "/").
250 implementation
252 uses
256 const
257 // character defines
269 begin
270 result :=
278 function MatchMask (const pattern: AnsiString; p, pend: Integer; const text: AnsiString; t, tend: Integer): Boolean;
279 var
283 begin
284 // sanity checks
290 begin
292 begin
293 // no more text. check if there's no more chars in pattern (except "*" & "+")
298 exit;
301 WILD_CHAR_SINGLE: ;
302 WILD_CHAR_ESCAPE:
303 begin
308 WILD_CHAR_RANGE_OPEN:
309 begin
317 repeat
323 begin
327 begin
329 end
331 end
336 // skip the rest or the range
340 WILD_CHAR_SINGLE_OR_NONE:
341 begin
345 exit;
347 WILD_CHAR_MULTI:
348 begin
352 begin
356 exit;
367 begin
374 var
376 begin
382 begin
384 begin
386 begin
393 begin
403 type
409 fPermanent: Boolean; // èñòèíà -- íå áóäåò óãðîáëåíà, åñëè íå îñòàíåòñÿ íè îäíîãî îòêðûòîãî òîìà
410 // èñòèíà -- ýòîò òîì áûë ñîçäàí èç ïîòîêà è íå èìååò äèñêîâîãî ôàéëà, ïîòîìó ôàáðèêå áóäåò ïåðåäàíî íå èìÿ ñáîðíèêà, à ïóñòàÿ ñòðîêà
418 protected
421 public
427 var
434 var
438 begin
439 // collect garbage
442 begin
446 begin
447 // this volume probably can be removed
451 begin
453 begin
461 begin
462 {$IFDEF SFS_VOLDEBUG}writeln('000: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
466 continue;
474 begin
479 begin
482 begin
489 // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
490 // ñîáñòâåííî èìÿ ôàéëà
491 // èìÿ âûãëÿäèò êàê:
492 // (("sfspfx:")?"datafile::")*"filename"
494 var
496 begin
499 begin
504 else
505 begin
511 // ñàéäýôôåêò: âûðåçàåò âèðòóàëüíîå èìÿ èç dataFile.
513 var
515 begin
518 begin
521 begin
523 else
524 begin
527 break;
534 // ðàçáèòü èìÿ ñáîðíèêà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
535 // âèðòóàëüíîå èìÿ. åñëè âèðòóàëüíîãî èìåíè íå äàíî, îíî áóäåò ðàâíî dataFile.
536 // èìÿ âûãëÿäèò êàê:
537 // [sfspfx:]datafile[|virtname]
538 // åñëè ïåðåä äâîåòî÷èåì ìåíüøå òð¸õ áóêâ, òî ýòî ñ÷èòàåòñÿ íå ïðåôèêñîì,
539 // à èìåíåì äèñêà.
541 var
543 begin
546 else
547 begin
554 // íàéòè ïðîèçâîäèòåëÿ äëÿ ýòîãî ôàéëà (åñëè ôàéë óæå îòêðûò).
555 // onlyPerm: òîëüêî "ïîñòîÿííûå" ïðîèçâîäèòåëè.
557 var
560 begin
563 begin
565 begin
568 begin
570 begin
572 exit;
581 // íàéòè èíôó äëÿ ýòîãî òîìà.
582 // õîðîøåå èìÿ, ïðàâäà? %-)
584 begin
587 begin
589 begin
597 // adds '/' too
599 var
601 begin
605 begin
607 begin
609 continue;
612 begin
614 end
615 else
616 begin
625 var
627 begin
630 begin
632 begin
633 // avoid unnecessary string changes
640 var
643 begin
645 repeat
653 { TVolumeInfo }
655 var
658 begin
665 // òèïà ìóñîðîñáîðíèê: åñëè íàø ïîòîê áîëåå íèêåì íå þçàåòñÿ, òî óãðîáèòü åãî íàôèã
667 begin
671 begin
673 begin
676 begin
689 { TOwnedPartialStream }
692 begin
699 var
701 begin
704 begin
707 begin
710 begin
711 {$IFDEF SFS_VOLDEBUG}writeln('001: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
719 { TSFSFileInfo }
721 begin
732 begin
738 { TSFSVolume }
740 begin
748 begin
752 var
756 begin
763 begin
765 // normalize name & path
772 begin
773 // split path and name
786 begin
793 begin
798 begin
800 else
801 begin
804 begin
807 begin
817 begin
822 begin
824 else
825 begin
832 var
835 begin
837 // normalize name, find split position
841 begin
854 { TSFSFileList }
856 var
858 begin
868 var
870 begin
874 // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî
875 if (gcdisabled = 0) and not TVolumeInfo(volumes[f]).fPermanent and (TVolumeInfo(volumes[f]).fOpenedFilesCount < 1) then
876 begin
877 {$IFDEF SFS_VOLDEBUG}writeln('002: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
884 begin
889 begin
896 var
898 begin
907 var
910 begin
915 begin
923 function SFSAddDataFileEx (dataFileName: AnsiString; ds: TStream; top, permanent: Integer): Integer;
924 // dataFileName ìîæåò èìåòü ïðåôèêñ òèïà "zip:" (ñì. âûøå: IsMyPrefix).
925 // ìîæåò âûêèíóòü èñêëþ÷åíèå!
926 // top:
927 // <0: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
928 // =0: íå ìåíÿòü.
929 // >0: äîáàâèòü â êîíåö ñïèñêà ïîèñêà.
930 // permanent:
931 // <0: ñîçäàòü "âðåìåííûé" òîì.
932 // =0: íå ìåíÿòü ôëàæîê ïîñòîÿíñòâà.
933 // >0: ñîçäàòü "ïîñòîÿííûé" òîì.
934 // åñëè ds <> nil, òî ñîçäà¸ò ñáîðíèê èç ïîòîêà. åñëè ñáîðíèê ñ èìåíåì
935 // dataFileName óæå çàðåãèñòðèðîâàí, òî ïàäàåò íàôèã.
936 // âîçâðàùàåò èíäåêñ â volumes.
937 // óìååò äåëàòü ðåêóðñèþ.
938 var
946 begin
949 begin
950 // ðåêóðñèâíîå îòêðûòèå.
951 // ðàçîáü¸ì dataFileName íà èìÿ ñáîðíèêà è îñòàòîê.
952 // pfx áóäåò èìåíåì ñáîðíèêà, dataFileName -- îñòàòêîì.
954 // ñíà÷àëà îòêðîåì ïåðâûé ñïèñîê...
956 // ...òåïåðü ïðîäîëæèì ñ îñòàòêîì.
957 // óçíàåì, êàêîå ôàéëî îòêðûâàòü.
958 // âûêîâûðÿåì ïåðâûé "::" ïðåôèêñ (ýòî áóäåò èìÿ ôàéëà).
961 // dataFileName õðàíèò îñòàòîê.
962 // èçâëå÷¸ì èìÿ ôàéëà:
964 // îòêðîåì ýòîò ôàéë
966 try
969 except
971 // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì.
972 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[result] := nil;
975 // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå.
977 try
980 except
984 exit;
987 // îáûêíîâåííîå íåðåêóðñèâíîå îòêðûòèå.
992 begin
999 exit;
1009 try
1011 begin
1016 try
1019 except
1025 except
1031 try
1033 begin
1036 end
1038 except
1054 function SFSAddSubDataFile (const virtualName: AnsiString; ds: TStream; top: Boolean=false): Boolean;
1055 var
1057 begin
1059 try
1063 except
1069 var
1071 begin
1072 try
1076 except
1082 var
1084 begin
1085 try
1089 except
1097 var
1100 begin
1103 begin
1114 begin
1119 end
1125 var
1133 // ïðîâåðèì, åñòü ëè ôàëî fn ãäå-òî íà äèñêàõ.
1134 var
1137 begin
1144 begin
1150 try
1152 exit;
1153 except
1158 begin
1165 begin
1166 // ïðåôèêñîâàíûé ôàéë
1168 begin
1176 try
1179 except
1181 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1184 exit;
1186 //Inc(vi.fOpenedFilesCount);
1188 exit;
1191 // íåïðåôèêñîâàíûé ôàéë
1193 begin
1197 // èùåì ïî âñåì ïåðìàíåíòíûì ïðåôèêñàì
1200 begin
1203 begin
1205 begin
1208 begin
1209 try
1212 //Inc(vi.fOpenedFilesCount);
1213 except
1227 begin
1228 try
1230 except
1236 var
1239 begin
1243 try
1245 except
1246 exit;
1250 try
1252 except
1253 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1258 initialization
1261 //finalization
1262 //volumes.Free(); // it fails for some reason... Runtime 217 (^C hit). wtf?!
1263 //factories.Free(); // not need to be done actually...