Mocka: the stat error

While doing some tests with Mocka, I found out that the stat function cannot be used anymore, due to a change in the C sources in /sys/stat.h, probably due to the changeover to libc several years ago. In the table below you will find the old and the new definitions.

Field Type Offset Old stat Offset New stat
stDev devT 00 SHORTCARD 00 ARRAY [0..1] OF CARDINAL
pad1 SHORTCARD 02 SHORTCARD 08 SHORTCARD
stIno inoT 04 LONGCARD 0A LONGCARD
stMode umodeT 08 SHORTCARD 0E LONGCARD
stNlink nlinkT 0A SHORTCARD 12 LONGCARD
stUid uidT 0C SHORTCARD 16 LONGCARD
stGid gidT 0E SHORTCARD 1A LONGCARD
stRdev devT 10 SHORTCARD 1E ARRAY [0..1] OF CARDINAL
pad2 SHORTCARD 12 SHORTCARD 26 SHORTCARD
stSize offT 14 LONGINT 28 LONGINT
stBlksize LONGCARD 18 LONGCARD 2C LONGCARD
stBlocks LONGCARD 1C LONGCARD 30 LONGCARD
stAtime timeT 20 LONGINT 34 LONGINT
unused1 LONGCARD 24 LONGCARD 38 LONGCARD
stMtime timeT 28 LONGINT 3C LONGINT
unused2 LONGCARD 2C LONGCARD 40 LONGCARD
stCtime timeT 30 LONGINT 44 LONGINT
unused3 LONGCARD 34 LONGCARD 48 LONGCARD
unused4 LONGCARD 38 LONGCARD 4C LONGCARD
unused5 LONGCARD 3C LONGCARD 50 LONGCARD

This makes the record, supplied by the 'stat' function considerably larger than what our Mocka stat still expects... The old stat record is 64 bytes, the new one is 84 bytes. Sounds like another buffer overrun to me...

The workaround

I posted the problem to the Mocka mailinglist and to rubino at ipd dot info dot uni-karlsruhe dot de (if you cut and paste these letters into the Kmail address field, you're in for a surprise. Try it!). Still, I wanted to see if I could determine the filesize in another way. So I came up with a follow-up of the 'System command' topic which I published some months ago.

The general idea was to have the command 'ls -l filename' issued and then the letters should be caught by stdin via InOut.Read commands. But that failed. The letters just seem to get lost, when they march from the System command towards stdin. If I recall well, /dev/null is also on their road and they might have gotten curious.
So, if the pipe is broken, another mechanism was used: the temporary file. See it in the sourcecode below:

MODULE fs;

FROM   SYSTEM		IMPORT	ADR;
FROM   SysLib		IMPORT	system;

IMPORT TextIO;
IMPORT InOut;
IMPORT ASCII;

VAR   fd		: TextIO.File;
      ch		: CHAR;
      ok		: BOOLEAN;
      str		: ARRAY [0..31] OF CHAR;


PROCEDURE SystemCommand (VAR  command : ARRAY OF CHAR) : BOOLEAN;

BEGIN
   IF  system (ADR (command) ) = 0  THEN
      RETURN TRUE
   ELSE
      RETURN FALSE
   END
END SystemCommand;


BEGIN
   IF  SystemCommand ("ls -l fs.mod >.tmp.tmp") = TRUE  THEN
      TextIO.OpenInput (fd, ".tmp.tmp");
      IF  NOT TextIO.Done ()  THEN  
         InOut.WriteString ("Opening of .tmp.tmp failed");	InOut.WriteLn;
	 HALT
      END;
      TextIO.GetString (fd, str);
      TextIO.GetString (fd, str);
      TextIO.GetString (fd, str);
      TextIO.GetString (fd, str);
      TextIO.GetString (fd, str);
      InOut.WriteString ("Filesize is ");
      InOut.WriteString (str);
      InOut.WriteLn;
      TextIO.Close (fd);
      TextIO.Erase (".tmp.tmp", ok);
      IF  NOT ok  THEN  InOut.WriteString ("Final error...")  END
   ELSE
      InOut.WriteString ("ls failed");		InOut.WriteLn;
      HALT
   END
END fs.
   
I issue an 'ls' command and have the letters disappear in a file called '.tmp.tmp'. Then I open the file, read five strings from it (the first four are garbage) and extract the filesize from the fifth string.
   jan@beryllium:~/modula/test$ ls -l fs.mod
   -rw-r--r--  1 jan users 1122 2007-02-25 01:42 fs.mod
   
When done, I erase the file. It works. To be usefull, the fifth 'TextIO.GetString (fd, str);' should of course be replaced by a 'TextIO.GetCard (fd, num);' command.

When I have an answer from Karlsruhe howmto tackle this problem, I will let you know via this same page.

Page created 25 February 2007,