UNSAFE MODULE DirOp_ux EXPORTS DirOp; (***************************************************************************) (* Copyright (C) Olivetti 1989 *) (* All Rights reserved *) (* *) (* Use and copy of this software and preparation of derivative works based *) (* upon this software are permitted to any person, provided this same *) (* copyright notice and the following Olivetti warranty disclaimer are *) (* included in any copy of the software or any modification thereof or *) (* derivative work therefrom made by any person. *) (* *) (* This software is made available AS IS and Olivetti disclaims all *) (* warranties with respect to this software, whether expressed or implied *) (* under any law, including all implied warranties of merchantibility and *) (* fitness for any purpose. In no event shall Olivetti be liable for any *) (* damages whatsoever resulting from loss of use, data or profits or *) (* otherwise arising out of or in connection with the use or performance *) (* of this software. *) (***************************************************************************) IMPORT Text, Thread; IMPORT Ustat, Unix, UnixMutex, Uerror, Udir, Utypes, Ctypes, M3toC; IMPORT TimeDate, FileStamp, PathName, OSError, FileOp; IMPORT OSError_ux, PathName_ux, FileOp_priv; EXCEPTION BadUse; REVEAL T = BRANDED OBJECT mutex: Thread.Mutex; name: Text.T; closed: BOOLEAN := FALSE; first, last: Iterator := NIL; END; Entry = FileOp.Info BRANDED OBJECT dir: T; next: Iterator := NIL; statDone := FALSE; entryName: Text.T := NIL; dirINode: Utypes.ino_t; accessible := TRUE; OVERRIDES name := EntryFullName; isFile := IsFile; access := Access; lastModified := LastModified; length := Length; stat := Stat; inode := INode; END; Iterator = Entry BRANDED OBJECT END; PROCEDURE AddEntry(t: T; e: Udir.direct_star) RAISES {}= VAR new := NEW(Iterator, dir := t, dirINode := e.d_ino, entryName := M3toC.CopyStoT(ADR(e.d_name))); BEGIN new.nameText := PathName.Concat(t.name, new.entryName); IF t.first = NIL THEN t.first := new ELSE t.last.next := new END; t.last := new; END AddEntry; <*INLINE*> PROCEDURE UnixName(name: Text.T): Ctypes.char_star RAISES {}= VAR realName: Text.T; BEGIN IF Text.Length(name) = 0 THEN realName := PathName_ux.CurrentDirText; ELSE realName := name; END; RETURN M3toC.TtoS(realName); END UnixName; PROCEDURE Open(name: Text.T; mustExist := TRUE): T RAISES {OSError.E} = VAR d: Udir.DIR_star; BEGIN LOCK UnixMutex.errno DO d := Udir.opendir(UnixName(name)); IF d = NIL THEN IF NOT mustExist AND Uerror.errno = Uerror.ENOENT THEN RETURN NIL END; OSError_ux.Raise(); END; END; VAR t := NEW(T, mutex := NEW(MUTEX), name := name); BEGIN LOOP WITH e = Udir.readdir(d) DO IF e # NIL THEN AddEntry(t, e); ELSE EVAL Udir.closedir(d); RETURN t; END; END; END; END; END Open; PROCEDURE Name(t: T): Text.T RAISES {}= BEGIN LOCK t.mutex DO IF t.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; RETURN t.name; END; END Name; PROCEDURE Close(VAR t: T) RAISES {} = BEGIN LOCK t.mutex DO t.closed := TRUE END; t := NIL; END Close; PROCEDURE Find(t: T; name: Text.T; VAR e: Entry): BOOLEAN RAISES {}= BEGIN LOCK t.mutex DO IF t.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; VAR search := t.first; BEGIN WHILE search # NIL DO IF Text.Equal(search.entryName, name) THEN e := search; RETURN TRUE; ELSE search := search.next END; END; END; END; e := NIL; RETURN FALSE; END Find; PROCEDURE Next(t: T; VAR i: Iterator; VAR e: Entry): BOOLEAN RAISES {}= BEGIN LOCK t.mutex DO IF t.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; IF i = NIL THEN i := t.first; ELSE IF t # i.dir THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; i := i.next; END; END; e := i; RETURN e # NIL; END Next; PROCEDURE DoStat(e: Entry) RAISES {}= BEGIN IF NOT e.accessible THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; LOCK UnixMutex.errno DO IF Ustat.stat(M3toC.TtoS(e.nameText), ADR(e.statBuf)) < 0 THEN e.accessible := FALSE; RETURN; END; END; e.statDone := TRUE; FileOp_priv.InfoFromStatBuf(e.statBuf, e.info); END DoStat; PROCEDURE AccessibleEntry(e: Entry): BOOLEAN RAISES {}= BEGIN LOCK e.dir.mutex DO IF e.dir.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; IF e.accessible AND NOT e.statDone THEN DoStat(e) END; RETURN e.accessible; END; END AccessibleEntry; PROCEDURE EntryName(e: Entry): Text.T RAISES {}= BEGIN LOCK e.dir.mutex DO IF e.dir.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; RETURN e.entryName; END; END EntryName; PROCEDURE EntryFullName(e: Entry): Text.T RAISES {}= BEGIN LOCK e.dir.mutex DO IF e.dir.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; RETURN e.nameText; END; END EntryFullName; PROCEDURE IsFile(e: Entry): BOOLEAN RAISES {}= BEGIN LOCK e.dir.mutex DO IF e.dir.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; IF NOT e.statDone THEN DoStat(e) END; RETURN e.info.isFile; END; (* lock *) END IsFile; PROCEDURE Access(e: Entry): FileOp.Access RAISES {}= BEGIN LOCK e.dir.mutex DO IF e.dir.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; IF NOT e.statDone THEN DoStat(e) END; RETURN e.info.access; END; (* lock *) END Access; PROCEDURE LastModified(e: Entry): TimeDate.Stamp RAISES {}= BEGIN LOCK e.dir.mutex DO IF e.dir.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; IF NOT e.statDone THEN DoStat(e) END; RETURN FileStamp.Copy(e.info.lastModified); END; (* lock *) END LastModified; PROCEDURE Length(e: Entry): CARDINAL RAISES {}= BEGIN LOCK e.dir.mutex DO IF e.dir.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; IF NOT e.statDone THEN DoStat(e) END; RETURN e.statBuf.st_size; END; (* lock *) END Length; PROCEDURE Stat(e: Entry): Ustat.struct_stat RAISES {}= BEGIN LOCK e.dir.mutex DO IF e.dir.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; IF NOT e.statDone THEN DoStat(e) END; RETURN e.statBuf; END; (* lock *) END Stat; PROCEDURE INode(e: Entry): Utypes.ino_t RAISES {}= BEGIN LOCK e.dir.mutex DO IF e.dir.closed THEN <* FATAL BadUse *> BEGIN RAISE BadUse END; END; RETURN e.dirINode; END; (* lock *) END INode; <*INLINE*> PROCEDURE Accessible(name: Text.T): BOOLEAN RAISES {}= BEGIN RETURN FileOp.Accessible(name); END Accessible; PROCEDURE Create(name: Text.T) RAISES {OSError.E}= CONST (* Default access is rwxrwxr-x *) RWXRWXR_X = Ustat.S_IREAD + Ustat.S_IWRITE + Ustat.S_IEXEC + Ustat.S_GREAD + Ustat.S_GWRITE + Ustat.S_GEXEC + Ustat.S_OREAD + Ustat.S_OEXEC; BEGIN LOCK UnixMutex.errno DO IF Unix.mkdir(UnixName(name), RWXRWXR_X) < 0 THEN OSError_ux.Raise(); END; END; END Create; PROCEDURE Remove(name: Text.T; mustExist := TRUE) RAISES {OSError.E}= BEGIN LOCK UnixMutex.errno DO IF Unix.rmdir(UnixName(name)) < 0 THEN IF NOT mustExist AND Uerror.errno = Uerror.ENOENT THEN RETURN END; OSError_ux.Raise(); END; END; END Remove; PROCEDURE Rename(from, to: Text.T) RAISES {OSError.E}= BEGIN (* Same as 'FileOp.Remove' under Unix *) FileOp.Rename(from, to); END Rename; BEGIN END DirOp_ux.