Add proper per-file copyright notices/licenses and top-level license.
[bluesky.git] / TBBT / trace_init / hier.pl
1 #\r
2 # Copyright (c) 2002-2003\r
3 #      The President and Fellows of Harvard College.\r
4 #\r
5 # Redistribution and use in source and binary forms, with or without\r
6 # modification, are permitted provided that the following conditions\r
7 # are met:\r
8 # 1. Redistributions of source code must retain the above copyright\r
9 #    notice, this list of conditions and the following disclaimer.\r
10 # 2. Redistributions in binary form must reproduce the above copyright\r
11 #    notice, this list of conditions and the following disclaimer in the\r
12 #    documentation and/or other materials provided with the distribution.\r
13 # 3. Neither the name of the University nor the names of its contributors\r
14 #    may be used to endorse or promote products derived from this software\r
15 #    without specific prior written permission.\r
16 #\r
17 # THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND\r
18 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
20 # ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE\r
21 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
22 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
23 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
24 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
26 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
27 # SUCH DAMAGE.\r
28 #\r
29 # $Id: hier.pl,v 1.14 2003/07/26 20:52:03 ellard Exp $\r
30 #\r
31 # hier.pl - Tools to map out the file system hierarchy.  This is\r
32 # accomplished by snooping out the lookup calls.\r
33 #\r
34 # This is expensive because the hierarchy can require a LOT of space\r
35 # to store for a large system with lots of files (especially if files\r
36 # come and go).  Don't construct the hierarchy unless you want it --\r
37 # and be prepared to prune it from time to time.\r
38 \r
39 package hier;\r
40 \r
41 # Tables used by the outside world:\r
42 \r
43 %fh2Parent              = ();\r
44 %fh2Name                = ();\r
45 %fh2Attr                = ();\r
46 %fh2AttrOrig            = ();\r
47 %parent2fh              = ();\r
48 \r
49 #RFS: init FS\r
50 %rootsName              = ();\r
51 %discardFHs = ();\r
52 %rootsFHs = ();\r
53 #RFS: dependency table\r
54 %fhCreate = ();\r
55 \r
56 %rfsAllFHs = ();\r
57 %fhType = (); # we use %fhIsDir instead\r
58 $rfsLineNum = 0;\r
59 \r
60 \r
61 \r
62 \r
63 \r
64 \r
65 # Library-private tables and variables.\r
66 \r
67 %pendingCallsXIDnow     = ();\r
68 %pendingCallsXIDfh      = ();\r
69 %pendingCallsXIDname    = ();\r
70 \r
71 $nextPruneTime          = -1;\r
72 $PRUNE_INTERVAL         = 5 * 60;       # Five minutes.\r
73 \r
74 sub processLine {\r
75         my ($line, $proto, $op, $xid, $client, $now, $response, $fh_type) = @_;\r
76 \r
77         &addRfsAllFHs($line, $proto, $op, $uxid,\r
78                                 $now, $response, $fh_type);\r
79 \r
80         if ($now > $nextPruneTime) {\r
81                 &prunePending ($now - $PRUNE_INTERVAL);\r
82                 $nextPruneTime = $now + $PRUNE_INTERVAL;\r
83         }\r
84 \r
85         my $uxid = "$client-$xid";\r
86 \r
87         # 'lookup', 'create', 'rename', 'delete',\r
88         # 'getattr', 'setattr'\r
89 \r
90         #RFS: add mkdir/rmdir/symlink\r
91         if ( $op eq 'lookup' || $op eq 'create' || $op eq 'mkdir' || \r
92              ($op eq 'symlink' && ($proto eq 'C3' || $proto eq 'R3' ) ) ) {\r
93                 return (&doLookup ($line, $proto, $op, $uxid,\r
94                                 $now, $response, $fh_type));\r
95         }\r
96         elsif ($op eq 'rename') {\r
97         }\r
98         elsif ($op eq 'remove' || $op eq 'rmdir') {\r
99                 # RFS: why remove these entries? Just let them exist since \r
100                 # there is generation number available to distinguish btw removed dir/file \r
101                 # and new dir/file with the same inode number.\r
102                 #return (&doRemove ($line, $proto, $op, $uxid,\r
103                 #               $now, $response, $fh_type));\r
104         }\r
105         elsif ($op eq 'getattr' || $op eq 'read' || $op eq 'write'  ||\r
106                  ($op eq 'readlink' && ($proto eq 'C3' || $proto eq 'R3' ) ) ) {\r
107                 return (&doGetAttr ($line, $proto, $op, $uxid,\r
108                                 $now, $response, $fh_type));\r
109         }\r
110         elsif ($op eq 'setattr') {\r
111         }\r
112 }\r
113 \r
114 \r
115 # get time stamp\r
116 \r
117 sub getTimeStamp{\r
118         my ($line) = @_;\r
119 \r
120         if (! ($line =~ /^[0-9]/)) {\r
121                 print "getTimeStamp return undef\n";\r
122                 return undef;\r
123         }\r
124         else {\r
125                 my @l = split (' ', $line, 2);\r
126                 return $l[0];\r
127         }\r
128 }\r
129 \r
130 sub addRfsAllFHs {\r
131         my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
132 \r
133         my $fh = undef;\r
134         \r
135         my $checkfh = undef;\r
136         $checkfh = nfsd::nfsDumpParseLineField ($line, 'fh');\r
137         if (defined $checkfh) {\r
138                 $fh = nfsd::nfsDumpCompressFH ($fh_type, $checkfh);\r
139         }\r
140         \r
141         my $fh2 = undef;\r
142 \r
143         if ($op eq 'rename' || $op eq 'link') {\r
144                 $checkfh = nfsd::nfsDumpParseLineField ($line, 'fh2');\r
145                 if (defined $checkfh) {\r
146                         $fh2 = nfsd::nfsDumpCompressFH ($fh_type, $checkfh);\r
147                 }       \r
148         }\r
149 \r
150         if (defined $fh) {\r
151                 # record the first appearance of the fh\r
152                 if ( !exists  $rfsAllFHs{$fh} )  {\r
153                         $rfsAllFHs{$fh} = $rfsLineNum ;\r
154                 }\r
155         }\r
156 \r
157         if (defined $fh2) {\r
158                 if ( !exists  $rfsAllFHs{$fh2} ) {\r
159                         $rfsAllFHs{$fh2} = $rfsLineNum;\r
160                 }\r
161         }\r
162 \r
163         return ;\r
164 }\r
165 \r
166 \r
167 sub doLookup {\r
168         my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
169 \r
170         if ($proto eq 'C3' || $proto eq 'C2') {\r
171                 my $tag = ($proto eq 'C3') ? 'name' : 'fn';\r
172                 my $name = nfsd::nfsDumpParseLineField ($line, $tag);\r
173 \r
174                 # All directories have (at least) three names:  the\r
175                 # given name, and "." and "..".  We're only interested\r
176                 # in the given name.\r
177 \r
178                 if ($name eq '"."' || $name eq '".."') {\r
179                         return ;\r
180                 }\r
181 \r
182                 my $fh = nfsd::nfsDumpCompressFH ($fh_type,\r
183                         nfsd::nfsDumpParseLineField ($line, 'fh'));\r
184 \r
185                 $pendingCallsXIDnow{$uxid} = $now;\r
186                 $pendingCallsXIDfh{$uxid} = $fh;\r
187                 $pendingCallsXIDname{$uxid} = $name;\r
188         }\r
189         elsif ($proto eq 'R3' || $proto eq 'R2') {\r
190                 if (! exists $pendingCallsXIDnow{$uxid}) {\r
191                         return ;\r
192                 }\r
193 \r
194                 my $pfh = $pendingCallsXIDfh{$uxid};\r
195                 my $name = $pendingCallsXIDname{$uxid};\r
196 \r
197                 delete $pendingCallsXIDnow{$uxid};\r
198                 delete $pendingCallsXIDfh{$uxid};\r
199                 delete $pendingCallsXIDname{$uxid};\r
200 \r
201                 if ($response eq 'OK') {\r
202                         my $cfh = nfsd::nfsDumpCompressFH ($fh_type,\r
203                                         nfsd::nfsDumpParseLineField ($line, 'fh'));\r
204 \r
205                         my $type = nfsd::nfsDumpParseLineField ($line, 'ftype');\r
206 \r
207                         #if ($type == 2) \r
208                         {\r
209                                 $fhIsDir{$cfh} = $type;\r
210                         }\r
211 \r
212                         # Original code\r
213                         # $fh2Parent{$cfh} = $pfh;\r
214                         # $fh2Name{$cfh} = $name;\r
215                         # $parent2fh{"$pfh,$name"} = $cfh;\r
216                         # RFS code: in case of the rename, we will record the name of the old name\r
217                         $fh2Parent{$cfh} = $pfh;\r
218                         if (! exists   $fh2Name{$cfh}) {\r
219                                 $fh2Name{$cfh} = $name;\r
220                                 $parent2fh{"$pfh,$name"} = $cfh;\r
221                         } else {\r
222                                 # keep the old name in the fh2Name{$cfh}\r
223                                 # and we also add the newname and pfh mapping\r
224                                 #$fh2Name{$cfh} = $name;\r
225                                 $parent2fh{"$pfh,$name"} = $cfh;\r
226                         }\r
227 \r
228                         my ($size, $mode, $atime, $mtime, $ctime, $nlink) =\r
229                                         nfsd::nfsDumpParseLineFields ($line,\r
230                                         'size', 'mode',\r
231                                         'atime', 'mtime', 'ctime', 'nlink');\r
232                         my $ts = getTimeStamp($line);\r
233 \r
234                         # RFS: modify here to get/maintain more file attributes\r
235                         # we can just check the ctime and compare it with trace-start-time\r
236                         # to decide whether to create a file/diretory.\r
237                         # atime - last access time of the file\r
238                         # mtime - last modification time of the file\r
239                         # ctime - last file status change time\r
240                         \r
241                         #$fh2Attr{$cfh} = "$size $mode $atime $mtime $ctime";\r
242                         if  (! exists $fh2AttrOrig{$cfh} ) {\r
243                                 $fh2AttrOrig{$cfh} = "$size $mode $op $atime $mtime $ctime $nlink $ts";\r
244                         }\r
245                         $fh2Attr{$cfh} = "$size $mode $op $atime $mtime $ctime $nlink $ts";\r
246                 }\r
247 \r
248         }\r
249 \r
250         return ;\r
251 }\r
252 \r
253 sub doRemove {\r
254         my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
255 \r
256         if ($proto eq 'C3' || $proto eq 'C2') {\r
257                 my $tag = ($proto eq 'C3') ? 'name' : 'fn';\r
258                 my $name = nfsd::nfsDumpParseLineField ($line, $tag);\r
259 \r
260                 # All directories have (at least) three names:  the\r
261                 # given name, and "." and "..".  We're only interested\r
262                 # in the given name.\r
263 \r
264                 if ($name eq '"."' || $name eq '".."') {\r
265                         return ;\r
266                 }\r
267 \r
268                 my $pfh = nfsd::nfsDumpCompressFH ($fh_type,\r
269                         nfsd::nfsDumpParseLineField ($line, 'fh'));\r
270 \r
271                 if (! exists $parent2fh{"$pfh,$name"}) {\r
272                         return ;\r
273                 }\r
274 \r
275                 $pendingCallsXIDnow{$uxid} = $now;\r
276                 $pendingCallsXIDfh{$uxid} = $pfh;\r
277                 $pendingCallsXIDname{$uxid} = $name;\r
278         }\r
279         elsif ($proto eq 'R3' || $proto eq 'R2') {\r
280                 if (! exists $pendingCallsXIDnow{$uxid}) {\r
281                         return ;\r
282                 }\r
283 \r
284                 my $pfh = $pendingCallsXIDfh{$uxid};\r
285                 my $name = $pendingCallsXIDname{$uxid};\r
286 \r
287                 delete $pendingCallsXIDfh{$uxid};\r
288                 delete $pendingCallsXIDname{$uxid};\r
289                 delete $pendingCallsXIDnow{$uxid};\r
290 \r
291                 if (! exists $parent2fh{"$pfh,$name"}) {\r
292                         return ;\r
293                 }\r
294 \r
295                 my $cfh = $parent2fh{"$pfh,$name"};\r
296 \r
297                 if ($response eq 'OK') {\r
298                         if ($op eq 'remove') {\r
299                                 printFileInfo ($cfh, 'D');\r
300 \r
301                                 delete $fh2Parent{$cfh};\r
302                                 delete $fh2Name{$cfh};\r
303                                 delete $fh2Attr{$cfh};\r
304                                 delete $fhs2AttrOrig{$cfg};\r
305                                 delete $parent2fh{"$pfh,$name"};\r
306                         }\r
307                 }\r
308         }\r
309 \r
310         return ;\r
311 }\r
312 \r
313 sub doGetAttr {\r
314         my ($line, $proto, $op, $uxid, $now, $response, $fh_type) = @_;\r
315 \r
316         if ($proto eq 'C3' || $proto eq 'C2') {\r
317                 my $fh = nfsd::nfsDumpCompressFH ($fh_type,\r
318                         nfsd::nfsDumpParseLineField ($line, 'fh'));\r
319 \r
320                 #if (nfsd::nfsDumpParseLineField ($line, 'fh')\r
321                 #               eq '00018961-57570100-d2440000-61890100') {\r
322                 #       printf STDERR "Seen it ($op)\n";\r
323                 #}\r
324 \r
325                 if (! defined $fh) {\r
326                         return ;\r
327                 }\r
328 \r
329                 $pendingCallsXIDnow{$uxid} = $now;\r
330                 $pendingCallsXIDfh{$uxid} = $fh;\r
331 # RFS debug code\r
332 #my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
333 #if ($fh eq $wantfh) {\r
334 #       print "JIAWU: doGetAttr call $wantfh\n";\r
335 #}\r
336         }\r
337         else {\r
338                 if (! exists $pendingCallsXIDnow{$uxid}) {\r
339                         return ;\r
340                 }\r
341 \r
342                 my $fh = $pendingCallsXIDfh{$uxid};\r
343                 delete $pendingCallsXIDfh{$uxid};\r
344                 delete $pendingCallsXIDnow{$uxid};\r
345 # RFS debug code\r
346 #my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
347 #if ($fh eq $wantfh) {\r
348 #       print "JIAWU: doGetAttr response $wantfh\n";\r
349 #}\r
350 \r
351                 if ($response ne 'OK') {\r
352                         return ;\r
353                 }\r
354 \r
355                 my ($ftype) = nfsd::nfsDumpParseLineFields ($line, 'ftype');\r
356                 if (!defined $ftype) {\r
357                         print STDERR "BAD $line";\r
358                         return ;\r
359                 }\r
360 \r
361                 #if ($ftype == 2) \r
362                 {\r
363                         $fhIsDir{$fh} = $ftype;\r
364                 }\r
365 \r
366                 #RFS comment: here if fh is a directory, then it will not be add \r
367                 # in the two hash table %fh2Attr(%fh2AttrOrig) and %fh2Name\r
368                 # if ($ftype != 1) {\r
369                 #       return ;\r
370                 #}\r
371                 if ($ftype != 1) {\r
372                         #return ;\r
373                 }\r
374 \r
375 \r
376                 my ($mode, $size, $atime, $mtime, $ctime, $nlink) =\r
377                                 nfsd::nfsDumpParseLineFields ($line,\r
378                                 'mode', 'size', 'atime', 'mtime', 'ctime', 'nlink');\r
379                 my $ts = getTimeStamp($line);\r
380 \r
381                         # RFS: modify here to get/maintain more file attributes\r
382                         # we can just check the ctime and compare it with trace-start-time\r
383                         # to decide whether to create a file/diretory.\r
384                         # atime - last access time of the file\r
385                         # mtime - last modification time of the file\r
386                         # ctime - last file status change time\r
387 \r
388                         # $fh2Attr{$fh} = "$size $mode $atime $mtime $ctime";\r
389 \r
390                         if  (! exists $fh2AttrOrig{$fh} ) {\r
391                                 $fh2AttrOrig{$fh} = "$size $mode $op $atime $mtime $ctime $nlink $ts";\r
392                         }\r
393                         $fh2Attr{$fh} = "$size $mode $op $atime $mtime $ctime $nlink $ts";\r
394         }\r
395 }\r
396 \r
397 # Purge all the pending XID records dated earlier than $when (which is\r
398 # typically at least $PRUNE_INTERVAL seconds ago).  This is important\r
399 # because otherwise missing XID records can pile up, eating a lot of\r
400 # memory. \r
401   \r
402 sub prunePending {\r
403         my ($when) = @_;\r
404 \r
405         foreach my $uxid ( keys %pendingCallsXIDnow ) {\r
406                 if ($pendingCallsXIDnow{$uxid} < $when) {\r
407 # RFS debug code\r
408 my $fh = $pendingCallsXIDfh{$uxid};\r
409 my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
410 if ($fh eq $wantfh) {\r
411         print "JIAWU: prunePending $wantfh\n";\r
412 }\r
413 #enf RFS\r
414                         delete $pendingCallsXIDnow{$uxid};\r
415                 }\r
416         }\r
417 \r
418         return ;\r
419 }\r
420 \r
421 # Return as much of the path for the given fh as possible.  It may or\r
422 # may not reach the root (or the mount point of the file system), but\r
423 # right now we don't check.  Usually on busy systems the data is\r
424 # complete enough so that most paths are complete back to the mount\r
425 # point.\r
426 \r
427 sub findPath {\r
428         my ($fh) = @_;\r
429         my $isdir = 0;\r
430         my $cnt = 0;\r
431         my $MaxPathLen = 40;\r
432 \r
433         if (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) {\r
434                 $isdir = 1;\r
435         }\r
436 \r
437         my @path = ();\r
438         while ($fh && exists $fh2Name{$fh}) {\r
439                 unshift (@path, $fh2Name{$fh});\r
440 \r
441                 if ( ($fh2Name{$fh} ne '"RFSNN0"' ) ) {\r
442                         if (! exists $fh2Parent{$fh}) {\r
443                                 print STDERR "$fh2Name{$fh} ";\r
444                                 if ( ($fh2Name{$fh} eq '"RFSNN0"' ) ) {\r
445                                         print STDERR "eq RFSNN0\n";\r
446                                 } else {\r
447                                         print STDERR "NOT eq RFSNN0\n";\r
448                                 }\r
449                         }\r
450                         if ($fh eq $fh2Parent{$fh}) {\r
451                                 unshift (@path, '(LOOP)');\r
452                                 last;\r
453                         }\r
454                 }\r
455 \r
456                 if ($cnt++ > $MaxPathLen) {\r
457                         print STDERR "findPath: path too long (> $MaxPathLen)\n";\r
458                         unshift (@path, '(TOO-LONG)');\r
459                         last;\r
460                 }\r
461 \r
462                 $fh = $fh2Parent{$fh};\r
463         }\r
464 \r
465         # RFS: append the ~user (fh and !exists $fh2Name{$fh} and type is Directory)\r
466         if ($fh && !exists $fh2Name{$fh} && (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) ) {\r
467                 if (exists $rootsName{$fh}) {\r
468                         #print "JIAWU: $rootsName{$fh}\n";\r
469                         unshift(@path, $rootsName{$fh});\r
470                 } else {\r
471                         print "JIAWU: WARNING! No rootsName for this fh: $fh\n";\r
472                         unshift(@path, $fh);\r
473                 }\r
474         } else {\r
475                 if ($fh && !exists $fh2Name{$fh} && (!exists $fhIsDir{$fh} || (exists $fhIsDir{$fh} && $fhIsDir{$fh}!=2)) ) {\r
476                         if (exists $discardFHs{$fh}) {\r
477                                 open NOATTRDIR, ">>noattrdirdiscard" || die "open noattrdirdiscard failed\n";\r
478                                 print NOATTRDIR "$fh DISCARD\n";\r
479                                 close NOATTRDIR;\r
480                         } else {\r
481                                 # RFS: if a possible fh without attr and name, then regard it as a special root ~/RFSNN0\r
482                                 unshift(@path, '"RFSNN0"');\r
483                                 $fhIsDir{$fh}=2;\r
484                                 $fh2Name{$fh} = '"RFSNN0"';\r
485                                 $rootsName{$fh} = '"RFSNN0"';\r
486                                 open NOATTRDIR, ">>noattrdir-root";\r
487                                 print NOATTRDIR "$fh /RFSNN0/\n";\r
488                                 close NOATTRDIR;\r
489                         }\r
490                 }\r
491         }\r
492 \r
493         \r
494         my $str = '';\r
495         $cnt = 0;\r
496         foreach my $p ( @path ) {\r
497                 $p =~ s/^.//;\r
498                 $p =~ s/.$//;\r
499                 $str .= "/$p";\r
500                 $cnt++;\r
501         }\r
502 \r
503         if ($isdir) {\r
504                 $str .= '/';\r
505         }\r
506 \r
507         if ($cnt == 0) {\r
508                 $str = '.';\r
509         }\r
510 \r
511         return ($str, $cnt);\r
512 }\r
513 \r
514 \r
515 $total_unknown_fh = 0;\r
516 $total_known_fh = 0;\r
517 \r
518 sub printAll {\r
519         my ($start_time, $out) = @_;\r
520 \r
521         my %allfh = ();\r
522         my $fh;\r
523         my $u = 0;\r
524         my $k = 0;\r
525 \r
526         # RFS print more information here\r
527         open (OUT_RFS, ">rfsinfo") ||\r
528                 die "Can't create $OutFileBaseName.rfs.";\r
529                 \r
530         foreach $fh ( keys %fh2Attr ) {\r
531                 $allfh{$fh} = 1; \r
532         }\r
533         foreach $fh ( keys %fh2Name ) {\r
534                 $allfh{$fh} = 1; \r
535         }\r
536 \r
537         #RFS: before printFileInfo, name those roots' name\r
538 \r
539         #RFS there are three kind of fh\r
540         # 1. fh/name paired (fh/attr must)\r
541         # 2. fh/attr but no fh/name: type file (discard related operations)\r
542         # 3. fh/attr but no fh/name: type dir (keep as persuedo root)\r
543         $u = $k = 0;\r
544         my $sn=1;\r
545         foreach $fh ( keys %allfh ) {\r
546                 if (exists $fh2Parent{$fh} ) {\r
547                         $k++;\r
548                 }\r
549                 else {\r
550                         $u++;\r
551                         my $type = (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) ? 'D' : 'F';\r
552                         if ($type eq 'D') {\r
553                                 $rootsName{$fh} = sprintf("\"RFSNN%d\"", $sn++);\r
554                                 $rootsFHs{$fh} = 2;\r
555                         }\r
556                         else {\r
557                                 $discardFHs{$fh} = 1;\r
558                         }\r
559                 }\r
560         }\r
561         print OUT_RFS "#stat: fh with parent = $k, fh without parent = $u\n";\r
562         $u = keys %rootsFHs;\r
563         print OUT_RFS "#RFS: root fh list($u)\n";\r
564         foreach $fh (keys %rootsName) {\r
565                 print OUT_RFS "#RFS: $rootsName{$fh} $fh\n";\r
566         }\r
567         $u = keys %discardFHs;\r
568         print OUT_RFS "#RFS: discard fh list($u)\n";\r
569         print OUT_RFS join("\n", keys %discardFHs, "");\r
570         \r
571 \r
572         print $out "#F type state fh path pathcount attrOrig(size,mode,op,atime,mt,ct) attrLast(size,mode,op,at,mt,ct)\n";\r
573 \r
574         print $out "#T starttime = $start_time\n";\r
575         foreach $fh ( keys %allfh ) {\r
576                 printFileInfoOutputFile ($fh, 'A', $out);\r
577         }\r
578         \r
579         my $numfh2Name = keys %fh2Name;\r
580         my $numfh2Attr = keys %fh2Attr;\r
581         print OUT_RFS "fh2name has $numfh2Name, fh2Attr has $numfh2Attr\n";\r
582 \r
583         \r
584         $u = $k = 0;\r
585         foreach $fh ( keys %allfh ) {\r
586                 if ( exists $fh2Name{$fh} ) {$k++;}\r
587                 else {$u++;}\r
588         }\r
589         print OUT_RFS "#stat: total fh with name = $k, without name = $u\n";\r
590 \r
591         print OUT_RFS "#stat: finally, total known fh = $total_known_fh, unknown = $total_unknown_fh\n";\r
592 \r
593 # Note: fh with name (8303), fh without name (103)\r
594 #          root fh list: 18\r
595 #          discard fh list: 85\r
596 #          known fh (8321): ( fh with name(8303) + root fh list (18) = 8321)\r
597 #          unknown fh (85)\r
598 #\r
599 # All fh from the those data structures: 8321 + 85 = 8303+103\r
600 # Or, in keys %allfh\r
601 #\r
602\r
603         print OUT_RFS "#RFS\n";\r
604         close OUT_RFS;  \r
605 \r
606         open (MISSED, ">missdiscardfh") ||\r
607                         die "Can't create missdiscardfh.";\r
608         foreach $fh (keys %rfsAllFHs) {\r
609                 if ( !exists $allfh{$fh} && \r
610                      ( (defined $fh2Name{$fh}) && ($fh2Name{$fh} ne '"RFSNN0"')) ) {\r
611                         print MISSED "$fh LN: $rfsAllFHs{$fh}\n"\r
612                 }\r
613         }\r
614         close MISSED;\r
615 \r
616 # check for a special fh\r
617 #my $wantfh = "6189010057570100200000000000862077ed3800d24400006189010057570100";\r
618 #if ($allfh{$wantfh} == 1) {\r
619 #       print OUT_RFS "JIAWU: found $wantfh\n";\r
620 #} else {\r
621 #       print OUT_RFS "JIAWU: NOT found $wantfh\n";\r
622 #}\r
623 #foreach $fh ( keys %allfh ) {\r
624 #       if ( $fh eq $wantfh ) {\r
625 #               print OUT_RFS "JIAWU: found $wantfh\n";\r
626 #               printFileInfoOutputFile ($fh, 'JIAWU', *OUT_RFS);\r
627 #               last;\r
628 #       }\r
629 #}\r
630 #print OUT_RFS "JIAWU: after \n";\r
631 \r
632 \r
633 }\r
634 \r
635 sub printFileInfoOutputFile {\r
636         my ($fh, $state, $out) = @_;\r
637 \r
638         my ($p, $c) = findPath ($fh);\r
639         \r
640         if ($c == 0) {$total_unknown_fh++;}\r
641         else {$total_known_fh++;}\r
642         \r
643         #my $type = (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) ? 'D' : 'F';\r
644         my $type = $fhIsDir{$fh};\r
645         if (!defined $type) \r
646         {\r
647                 print STDERR "unknown ftype(U) for fh: $fh\n"; \r
648                 $type = 'U';\r
649         }\r
650         my $attr = (exists $fh2Attr{$fh}) ?\r
651                         $fh2Attr{$fh} : "-1 -1 -1 -1 -1 -1 -1 -1";\r
652         my $attrOrig = (exists $fh2AttrOrig{$fh}) ?\r
653                         $fh2AttrOrig{$fh} : "-1 -1 -1 -1 -1 -1 -1 -1";\r
654 \r
655         print $out "F $type $state $fh $p $c $attrOrig $attr\n";\r
656 }\r
657 \r
658 sub printFileInfo {\r
659         my ($fh, $state) = @_;\r
660 \r
661         my ($p, $c) = findPath ($fh);\r
662         \r
663         if ($c == 0) {$total_unknown_fh++;}\r
664         else {$total_known_fh++;}\r
665         \r
666         my $type = (exists $fhIsDir{$fh} && $fhIsDir{$fh}==2) ? 'D' : 'F';\r
667         my $attr = (exists $fh2Attr{$fh}) ?\r
668                         $fh2Attr{$fh} : "-1 -1 -1 -1 -1 -1 -1 -1";\r
669         my $attrOrig = (exists $fh2AttrOrig{$fh}) ?\r
670                         $fh2AttrOrig{$fh} : "-1 -1 -1 -1 -1 -1 -1 -1";\r
671 \r
672         print "F $type $state $fh $p $c $attrOrig $attr\n";\r
673 }\r
674 \r
675 #\r
676 # The flow to create the dependency table\r
677\r
678 # create(dirfh, name, attr) -->newfh, new attr\r
679 # mkdir(dirfh, name, attr) -> newfh, new attr\r
680 #\r
681 # remove(dirfh, name) --> status\r
682 # rmdir(dirfh, name) --> status\r
683 # rename(dirfh, name, todirfh, toname) --> status\r
684 #\r
685 # link(newdirfh, newname, dirfh, name) --> status (newdir/newname=>dir/name)\r
686 # syslink(newdirfh, newname, string) --> status (newdir/newname=>"string")\r
687 # readlink(fh) --> string\r
688 # lookup(dirfh, name) --> fh, attr\r
689 # getattr(fh) --> attr\r
690 # setattr(fh, attr) --> attr\r
691 # read(fh, offset, count) -> attr, data\r
692 # write(fh, offset, count, data) --> attr\r
693 # readdir(dirfh, cookie, count) --> entries\r
694 # statfs(fh) --> status\r
695 #\r
696 #\r
697 #\r
698 #\r
699 # for each line the trace file: \r
700 #       if (op == R2 or R3) continue; #skip the response line\r
701 #       switch (the op)\r
702 #       {\r
703 #       # CREATION OPs:\r
704 #       case create:\r
705 #       case remove:\r
706 #       # DELETE OPs:\r
707 #       case mkdir:\r
708 #       case rmdir:\r
709 #       # other OPs\r
710 #\r
711 #\r
712 #\r
713 #\r
714 #\r
715 1;\r