1 // streaming file system (virtual)
2 {$MODE DELPHI}
3 {.$R-}
6 interface
8 uses
12 type
21 public
23 fPath: TSFSString; // ðàçäåëèòåëè êàòàëîãîâ -- "/"; êîðåíü íèêàê íå îáîçíà÷åí, åñëè íå ïóñòîå, îáÿçàíî çàâåðøàåòñÿ "/"
36 // âèðòóàëüíàÿ ôàéëîâàÿ ñèñòåìà. ÒÎËÜÊÎ ÄËß ×ÒÅÍÈß!
37 // òîì ÍÅ ÄÎËÆÅÍ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè ôàáðèêè!
39 protected
44 // ïðèøèáèòü âñå ñòðóêòóðû.
45 // íå äîëæíà ïàäàòü, åñëè å¸ âûçûâàþò íåñêîëüêî ðàç.
48 // âûçûâàåòñÿ èç DoDirectoryRead() äëÿ çàïîëíåíèÿ ñïèñêà ôàéëîâ.
49 // ñ÷èòàåòñÿ, ÷òî âñå ìàãèêè óæå ïðîâåðåíû è ôàéë òî÷íî íàø.
50 // fFileName, fFileStream óæå óñòàíîâëåíû, fFiles ñîçäàí,
51 // â í¸ì, ñêîðåå âñåãî, íèêîãî íåò.
52 // ïîçèöèÿ ïîòîêà -- òà, ÷òî îñòàâèëà ôàáðèêà.
53 // ïðè îøèáêàõ êèäàòü èñêëþ÷åíèå, òîãäà òîì áóäåò ïðèáèò ôàáðèêîé.
54 // ðàçäåëèòåëè ïóòåé äîëæíû áûòü òîëüêî "/", êîðíåâîé "/" äîëæåí
55 // áûòü îïóùåí, ïóòè (åñëè íå ïóñòûå) äîëæíû çàâåðøàòüñÿ "/"!
56 // fName äîëæíî ñîäåðæàòü òîëüêî èìÿ, fPath -- òîëüêî ïóòü.
57 // â ïðèíöèïå, îá ýòîì ïîçàáîòèòñÿ DoDirectoryRead(), íî çà÷åì
58 // äàâàòü åìó ëèøíþþ ðàáîòó?
61 // íàéòè ôàéë, âåðíóòü åãî èíäåêñ â fFiles.
62 // ýòà ïðîöåäóðà ìîæåò ìåíÿòü fFiles!
63 // fPath -- â ïðàâèëüíîé ôîðìå, ñ "/", êîðíåâîé "/" óáèò, ôèíàëüíûé äîáàâëåí.
64 // åñëè ôàéë íå íàéäåí, âåðíóòü -1.
67 // ïðè îøèáêàõ êèäàòüñÿ èñêëþ÷åíèÿìè.
70 // âîçâðàùàåò êîëè÷åñòâî ôàéëîâ â fFiles
73 // âîçâðàùàåò ôàéë ñ èíäåêñîì index.
74 // ìîæåò âîçâðàùàòü NIL.
75 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
78 public
79 // pSt íå îáÿçàòåëüíî çàïîìèíàòü, åñëè îí íå íóæåí.
81 // fFileStream óíè÷òîæàòü íåëüçÿ, åñëè îí ðàâåí ïàðàìåòðó pSt êîíñòðóêòîðà.
84 // âûçûâàåò ReadDirectory().
85 // ýòà ïðîöåäóðà ñàìà ðàçáåð¸òñÿ ñ äóáëèêàòàìè èì¸í: ïîäîáàâëÿåò â
86 // êîíåö èì¸í-äóáëèêàòîâ ïîä÷¸ðêèâàíèå è äåñÿòè÷íûé íîìåð.
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: TSFSString; st: TStream): TSFSVolume; virtual; abstract;
120 // êîãäà òîì áîëüøå íå íóæåí, îí áóäåò îòäàí ôàáðèêå íà ïåðåðàáîòêó.
121 // äàëåå äâèæîê íå áóäåò þçàòü ñåé òîì.
125 // "èòåðàòîð", âîçâðàùàåìûé SFSFileList()
127 protected
133 public
138 // ïðè íåïðàâèëüíîì èíäåêñå ìîë÷à âåðí¸ò NIL.
139 // ïðè ïðàâèëüíîì òîæå ìîæåò âåðíóòü NIL!
140 // î÷åíü íå ñîâåòóþ ìåíÿòü ñîäåðæèìîå ïîëó÷åííîãî êëàññà.
141 // êîíå÷íî, ÿ ìîã áû âîçâðàùàòü íîâóþ ñòðóêòóðó èëè íå÷òî ïîõîæåå,
142 // íî áëèí, åñëè òû èäèîò è íå óìååøü äàæå êîììåíòû ÷èòàòü, òî
143 // êàêîãî òû âîîáùå â ïðîãðàììèíã ïîëåç?
149 // ýòà ôóíêöèÿ àâòîìàòè÷åñêè ïðèáü¸ò factory.
152 // äîáàâèòü ñáîðíèê â ïîñòîÿííûé ñïèñîê.
153 // åñëè ñáîðíèê ñ òàêèì èìåíåì óæå îòêðûò, òî íå îòêðûâàåò åãî ïîâòîðíî.
154 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
155 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
156 // âåðí¸ò ëîæü ïðè îøèáêå.
157 // ñïîñîáíî îòêðûâàòü ñáîðíèêè â ñáîðíèêàõ ïðè ïîìîùè êðóòûõ èì¸í a-la:
158 // "zip:pack0::pack:pack1::wad2:pack2".
159 // â äàëüíåéøåì ñëåäóåò îáðàùàòüñÿ ê ñáîðíèêó êàê "pack2::xxx".
160 // èëè ìîæíî íàïèñàòü:
161 // "zip:pack0::pack:pack1::wad2:pack2|datafile".
162 // è îáðàùàòüñÿ êàê "datafile::xxx".
163 // "||" ïðåîáðàçóþòñÿ â ïðîñòîé "|" è ðàçäåëèòåëåì íå ñ÷èòàþòñÿ.
164 // ïðèíèìàåòñÿ âî âíèìàíèå òîëüêî ïîñëåäíÿÿ òðóáà.
167 // äîáàâèòü â ïîñòîÿííûé ñïèñîê ñáîðíèê èç ïîòîêà ds.
168 // åñëè âîçâðàùàåò èñòèíó, òî SFS ñòàíîâèòñÿ âëÿäåëüöåì ïîòîêà ds è ñàìà
169 // óãðîáèò ñåé ïîòîê ïî íåîáõîäèìîñòè.
170 // virtualName ñòàíîâèòñÿ èìåíåì ñáîðíèêà äëÿ îïåðàöèè îòêðûòèÿ ôàéëà òèïà
171 // "packfile:file.ext".
172 // åñëè êàêîé-íèáóäü ñáîðíèê ñ èìåíåì virtualName óæå îòêðûò, âåðí¸ò false.
173 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
174 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
175 // âåðí¸ò ëîæü ïðè îøèáêå.
176 // îòêðûâàåò ñáîðíèê èç ïîòîêà. dataFileName -- ÂÈÐÒÓÀËÜÍÎÅ èìÿ.
177 // ò.å. íà ñàìîì äåëå òàêîãî ôàéëà ìîæåò è íå áûòü íà äèñêå.
178 function SFSAddSubDataFile (const virtualName: TSFSString; ds: TStream; top: Boolean=false): Boolean;
180 // øâûðÿåòñÿ èñêëþ÷åíèÿìè.
181 // åñëè fName íå èìååò óêàçàíèÿ íà ôàéë äàííûõ (ýòî òî, ÷òî îòäåëåíî îò
182 // îñòàëüíîãî èìåíè äâîåòî÷èåì), òî èùåì ñíà÷àëà ïî âñåì çàðåãèñòðèðîâàííûì
183 // ôàéëàì äàííûõ, ïîòîì â òåêóùåì êàòàëîãå, ïîòîì â êàòàëîãå, îòêóäà ñòàðòîâàëè.
184 // åñëè íè÷åãî íå íàøëè, êèäàåì èñêëþ÷åíèå.
187 // ïðè îøèáêå -- NIL, è íèêàêèõ èñêëþ÷åíèé.
190 // âîçâðàùàåò NIL ïðè îøèáêå.
191 // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-)
195 // èãíîðèðóåò ðåãèñòð ñèìâîëîâ
196 // <0: s0 < s1
197 // =0: s0 = s1
198 // >0: s0 > s1
201 // ðàçîáðàòü òîëñòîå èìÿ ôàéëà, âåðíóòü âèðòóàëüíîå èìÿ ïîñëåäíåãî ñïèñêà
202 // èëè ïóñòóþ ñòîðîêó, åñëè ñïèñêîâ íå áûëî.
205 // ïðåîáðàçîâàòü ÷èñëî â ñòðîêó, êðàñèâî ðàçáàâëÿÿ çàïÿòûìè
208 // Wildcard matching
209 // this code is meant to allow wildcard pattern matches. tt is VERY useful
210 // for matching filename wildcard patterns. tt allows unix grep-like pattern
211 // comparisons, for instance:
212 //
213 // ? Matches any single characer
214 // + Matches any single characer or nothing
215 // * Matches any number of contiguous characters
216 // [abc] Matches a or b or c at that position
217 // [!abc] Matches anything but a or b or c at that position
218 // [a-e] Matches a through e at that position
219 //
220 // 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
221 // 'this [e-n]s a [!zy]est' -Would match 'this is a test', but would
222 // not match 'this as a yest'
223 //
229 var
230 // ïðàâäà: ðàçðåøåíî èñêàòü ôàéëî íå òîëüêî â ôàéëàõ äàííûõ, íî è íà äèñêå.
232 // ïðàâäà: åñëè ôàéë íå ïðåôèêñîâàí, òî ñíà÷àëà èùåì ôàéëî íà äèñêå,
233 // ïîòîì â ôàéëàõ äàííûõ.
235 // ïðàâäà: äàæå äëÿ ïðåôèêñîâàíûõ ôàéëîâ ñíà÷àëà ïðîñìîòðèì äèñê
236 // (åñëè óñòàíîâëåí ôëàæîê sfsDiskFirst è sfsDiskEnabled).
238 // ñïèñîê äèñêîâûõ êàòàëîãîâ äëÿ ïîèñêà ôàéëà. åñëè ïóñò -- èùåì òîëüêî â
239 // òåêóùåì. êàòàëîãè ðàçäåëÿþòñÿ òðóáîé ("|").
240 // <currentdir> çàìåíÿåòñÿ íà òåêóùèé êàòàëîã (ñ çàâåðøàþùèì "/"),
241 // <exedir> çàìåíÿåòñÿ íà êàòàëîã, ãäå ñèäèò .EXE (ñ çàâåðøàþùèì "/").
245 implementation
247 uses
248 xstreams;
252 var
254 begin
258 begin
264 const
265 // character defines
277 begin
278 result :=
286 function MatchMask (const pattern: TSFSString; p, pend: Integer; const text: TSFSString; t, tend: Integer): Boolean;
287 var
291 begin
292 // sanity checks
298 begin
300 begin
301 // no more text. check if there's no more chars in pattern (except "*" & "+")
306 exit;
309 WILD_CHAR_SINGLE: ;
310 WILD_CHAR_ESCAPE:
311 begin
316 WILD_CHAR_RANGE_OPEN:
317 begin
325 repeat
331 begin
335 begin
337 end
339 end
344 // skip the rest or the range
348 WILD_CHAR_SINGLE_OR_NONE:
349 begin
353 exit;
355 WILD_CHAR_MULTI:
356 begin
360 begin
364 exit;
375 begin
382 var
384 begin
390 begin
392 begin
394 begin
401 begin
411 type
417 fPermanent: Boolean; // èñòèíà -- íå áóäåò óãðîáëåíà, åñëè íå îñòàíåòñÿ íè îäíîãî îòêðûòîãî òîìà
418 // èñòèíà -- ýòîò òîì áûë ñîçäàí èç ïîòîêà è íå èìååò äèñêîâîãî ôàéëà, ïîòîìó ôàáðèêå áóäåò ïåðåäàíî íå èìÿ ñáîðíèêà, à ïóñòàÿ ñòðîêà
426 protected
429 public
435 var
440 // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
441 // ñîáñòâåííî èìÿ ôàéëà
442 // èìÿ âûãëÿäèò êàê:
443 // (("sfspfx:")?"datafile::")*"filename"
445 var
447 begin
450 begin
455 else
456 begin
462 // ñàéäýôôåêò: âûðåçàåò âèðòóàëüíîå èìÿ èç dataFile.
464 var
466 begin
469 begin
472 begin
474 else
475 begin
478 break;
485 // ðàçáèòü èìÿ ñáîðíèêà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
486 // âèðòóàëüíîå èìÿ. åñëè âèðòóàëüíîãî èìåíè íå äàíî, îíî áóäåò ðàâíî dataFile.
487 // èìÿ âûãëÿäèò êàê:
488 // [sfspfx:]datafile[|virtname]
489 // åñëè ïåðåä äâîåòî÷èåì ìåíüøå òð¸õ áóêâ, òî ýòî ñ÷èòàåòñÿ íå ïðåôèêñîì,
490 // à èìåíåì äèñêà.
492 var
494 begin
497 else
498 begin
505 // íàéòè ïðîèçâîäèòåëÿ äëÿ ýòîãî ôàéëà (åñëè ôàéë óæå îòêðûò).
506 // onlyPerm: òîëüêî "ïîñòîÿííûå" ïðîèçâîäèòåëè.
508 var
511 begin
514 begin
516 begin
519 begin
521 begin
523 exit;
532 // íàéòè èíôó äëÿ ýòîãî òîìà.
533 // õîðîøåå èìÿ, ïðàâäà? %-)
535 begin
538 begin
540 begin
547 // <0: s0 < s1
548 // =0: s0 = s1
549 // >0: s0 > s1
551 begin
556 var
558 begin
561 begin
563 begin
564 // avoid unnecessary string changes
571 var
574 begin
576 repeat
584 { TVolumeInfo }
586 var
589 begin
593 // òèïà ìóñîðîñáîðíèê: åñëè íàø ïîòîê áîëåå íèêåì íå þçàåòñÿ,
594 // òî óãðîáèòü åãî íàôèã.
599 begin
601 begin
613 { TOwnedPartialStream }
616 begin
623 var
625 begin
628 begin
631 begin
639 { TSFSFileInfo }
641 begin
650 begin
656 { TSFSVolume }
658 begin
666 var
671 begin
674 try
678 // check for duplicate file names
681 begin
684 // normalize name & path
691 begin
692 // split path and name
699 // check for duplicates
701 begin
706 repeat
716 except
723 begin
730 begin
735 begin
737 else
738 begin
741 begin
744 begin
754 begin
759 begin
761 else
762 begin
769 var
772 begin
774 // normalize name, find split position
778 begin
791 { TSFSFileList }
793 var
795 begin
805 var
807 begin
811 // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî
818 begin
823 begin
830 var
832 begin
841 var
844 begin
849 begin
859 // dataFileName ìîæåò èìåòü ïðåôèêñ òèïà "zip:" (ñì. âûøå: IsMyPrefix).
860 // ìîæåò âûêèíóòü èñêëþ÷åíèå!
861 // top:
862 // <0: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
863 // =0: íå ìåíÿòü.
864 // >0: äîáàâèòü â êîíåö ñïèñêà ïîèñêà.
865 // permanent:
866 // <0: ñîçäàòü "âðåìåííûé" òîì.
867 // =0: íå ìåíÿòü ôëàæîê ïîñòîÿíñòâà.
868 // >0: ñîçäàòü "ïîñòîÿííûé" òîì.
869 // åñëè ds <> nil, òî ñîçäà¸ò ñáîðíèê èç ïîòîêà. åñëè ñáîðíèê ñ èìåíåì
870 // dataFileName óæå çàðåãèñòðèðîâàí, òî ïàäàåò íàôèã.
871 // âîçâðàùàåò èíäåêñ â volumes.
872 // óìååò äåëàòü ðåêóðñèþ.
873 var
881 begin
884 begin
885 // ðåêóðñèâíîå îòêðûòèå.
886 // ðàçîáü¸ì dataFileName íà èìÿ ñáîðíèêà è îñòàòîê.
887 // pfx áóäåò èìåíåì ñáîðíèêà, dataFileName -- îñòàòêîì.
889 // ñíà÷àëà îòêðîåì ïåðâûé ñïèñîê...
891 // ...òåïåðü ïðîäîëæèì ñ îñòàòêîì.
892 // óçíàåì, êàêîå ôàéëî îòêðûâàòü.
893 // âûêîâûðÿåì ïåðâûé "::" ïðåôèêñ (ýòî áóäåò èìÿ ôàéëà).
896 // dataFileName õðàíèò îñòàòîê.
897 // èçâëå÷¸ì èìÿ ôàéëà:
899 // îòêðîåì ýòîò ôàéë
901 try
904 except
906 // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì.
910 // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå.
912 try
915 except
919 exit;
922 // îáûêíîâåííîå íåðåêóðñèâíîå îòêðûòèå.
927 begin
934 exit;
944 try
946 begin
951 try
954 except
960 except
966 try
968 begin
971 end
973 except
991 var
993 begin
995 try
999 except
1005 var
1007 begin
1008 try
1012 except
1019 var
1022 begin
1025 begin
1036 begin
1041 end
1047 var
1055 // ïðîâåðèì, åñòü ëè ôàëî fn ãäå-òî íà äèñêàõ.
1056 var
1059 begin
1066 begin
1072 try
1074 exit;
1075 except
1080 begin
1087 begin
1088 // ïðåôèêñîâàíûé ôàéë
1090 begin
1098 try
1101 except
1106 exit;
1108 //Inc(vi.fOpenedFilesCount);
1110 exit;
1113 // íåïðåôèêñîâàíûé ôàéë
1115 begin
1119 // èùåì ïî âñåì ïåðìàíåíòíûì ïðåôèêñàì
1122 begin
1125 begin
1127 begin
1130 begin
1131 try
1134 //Inc(vi.fOpenedFilesCount);
1135 except
1149 begin
1150 try
1152 except
1158 var
1161 begin
1165 try
1167 except
1168 exit;
1172 try
1174 except
1180 initialization
1183 finalization
1184 //volumes.Free(); // it fails for some reason... Runtime 217 (^C hit). wtf?!
1185 //factories.Free(); // not need to be done actually...