I was working today on a similar task - making copies of files, however under Linux version of BlackBox.
First, I tried to do it the 'native' way: looked up stackoverflow and other sources on 'how to copy files under linux"; ended with using libc function sendfile; found an example in c++ and adopted it to my BB env; after 2.5 hrs of work, I finally got it to work... only to discover that whatever I do, sendfile always copies 0 bytes for me. Always. And, I could find nothing about it on stackoverflow or in the wide big google.
Well, 'to hell with nativity', I thought, and wrote a BB platform-independent procedure. Took me 20 minutes.
Code: Select all
IMPORT Libc := LinLibc, HostFiles, Utf, Files, AprLibc;
PROCEDURE CopyFile (from, to: Files.Locator; IN name: Files.Name);
CONST buflen = 1024*1024;
VAR rd: Files.Reader; wr: Files.Writer; buf: POINTER TO ARRAY buflen OF BYTE;
VAR chunk, length, beg: INTEGER; f, g: Files.File;
BEGIN NEW(buf);
f := Files.dir.Old(from, name, Files.shared); length := f.Length();
IF f # NIL THEN rd := f.NewReader(rd);
g := Files.dir.New(to, Files.dontAsk); wr := g.NewWriter(wr);
beg := 0;
REPEAT chunk := MIN(buflen, length); DEC(length, chunk); INC(beg, chunk);
rd.ReadBytes(buf, beg, chunk); wr.WriteBytes(buf, beg, chunk)
UNTIL length = 0;
g.Register(name, '', Files.dontAsk, to.res);
f.Close
END
END CopyFile;
Then I faced the timestamp issue; after another hour of googling and pronouncing magical spells, all to no avail, I had to look up touch.c on gnu coreutils site - the source of touch utility used to change timestamps of files from command line. That led me to discover utimensat(), which I was then able to get to work.
I made an interface module:
Code: Select all
MODULE AprLibc ["libc.so.6"];
IMPORT Libc := LinLibc;
TYPE TVP* = RECORD [untagged] access*, modification*: Libc.timespec_t END;
PROCEDURE [ccall] utimensat* (fd: INTEGER; file: Libc.PtrSTR; VAR tvp: TVP; flags: SET): INTEGER;
END AprLibc.
and a BB procedure:
Code: Select all
PROCEDURE CopyTimestamps* (from, to: Files.Locator; IN name: Files.Name);
VAR src, dst: INTEGER; buf: ARRAY 512 OF SHORTCHAR; offset, res: INTEGER;
stat: Libc.stat_t; tvp: AprLibc.TVP;
BEGIN
Utf.StringToUtf8(from(HostFiles.Locator).path + "/" + name, buf, res);
IF res = 0 THEN src := Libc.open(buf, Libc.O_RDONLY, {});
IF src >= 0 THEN
res := Libc.__xstat(Libc._STAT_VER_LINUX, buf, stat);
IF res = 0 THEN
Utf.StringToUtf8(to(HostFiles.Locator).path + "/" + name, buf, res);
IF res = 0 THEN
tvp.access := stat.st_atim; tvp.modification := stat.st_mtim;
res := AprLibc.utimensat(0, buf, tvp, {});
IF res # 0 THEN to.res := eTimestamps END
ELSE to.res := eUtf
END
ELSE from.res := eOpen
END;
res := Libc.close(src)
ELSE from.res := eStat
END
ELSE from.res := eUtf
END
END CopyTimestamps;
This code works in BlackBox Cross-Platform 1.8 (which is in development phase yet) under Linux. Utf.StringToUtf8 might be the only call you'd have to adapt to your BB version.