/* @(SH) Funzioni per la gestione dei file a record. @(M$) PRIVATE CalcPos(Rec,Len,Base) : Calcola la posizione del record nel file @(C$) PRIVATE LOCKSEM : 'locksem' ; nome del semaforo utilizzato per il lock @(VG$) PRIVATE ld : struttura su disco che contien i dati per i lock sui file sizeld : numero di byte occupati dalla struttura ld semres : flag per l'ok delle operazioni sui semafori ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- */ #include "ccustio.h" #include "checks.h" #ifdef DOS #include #endif #include #ifndef DOS #include #include #include #else #include #include #include #include #include "modaut.h" #endif #define CalcPos(Rec, Len, Base) (((Rec) - 1) * ((RecNoType) (Len)) + ((RecNoType) (Base))) #define LOCK_OFF 1200000000L #ifndef DOS #define LOCKSEM "locksem" /* extern long lseek(int, long, int);*/ extern int chsize(int, long); extern int lockf(int, int, long); #endif unsigned setlock(unsigned); int seeklk(SecDef *, long, unsigned, unsigned, long); #ifndef DOS int semtran(char *); static void semcall(int, int); void PS(int); void VS(int); #endif BOOLEAN test_share() { #ifdef DOS static BOOLEAN share_active = 2; if (share_active == 2) { share_active = CGetAut(MUAUT); if (share_active) { int f = open("net.ini", O_RDONLY, SH_DENYNO, S_IREAD); share_active = f != -1; if (f != -1) close(f); } } return share_active; #else return TRUE; #endif } /* @($) setlock CUSTIO @(ID) Trasforma il modo di lock utente in modo lock XENIX. @(FD) @(ISV) Nella versione XENIX : lm = numero lock xenix. @(FSV) @(IN) Restituisce il comando XENIX. @(FN) */ unsigned setlock(LockMode) unsigned LockMode; /* Tipo di lock */ { int lm; LockMode &= RecLockTypes ; #ifdef DOS if (LockMode == ShareLock) lm = _LK_NBRLCK ; else if (LockMode == Lock) lm = _LK_NBRLCK ; else lm = _LK_UNLCK ; #else if (LockMode == ShareLock) lm = F_TLOCK ; else if (LockMode == Lock) lm = F_TLOCK ; else lm = F_ULOCK ; #endif return(lm) ; } /* @($) seeklk CUSTIO @(ID) Effettua una seek. @(FD) @(ISV) junk = variabile di lavoro. lock = variabile per eseguire comandi di lock. @(FSV) */ int seeklk(S, pos, lm, LockMode, rec) SecDef *S ; /* Descrittore file */ long pos ; /* posizione all'interno del file */ unsigned lm ; /* comando di lock per XENIX */ unsigned LockMode; /* comando di lock utente */ long rec; /* n.ro di record */ { if (LockMode != NoLock && S->LockMode != ExclLock) { #ifdef DOS if (test_share()) { if (_lseek(S->F, LOCK_OFF + rec, SEEK_SET) == -1L) if ((S->IOR = CIOResult()) != NoErr) return(-1) ; if ( _locking(S->F,lm, 1L) == -1) { S->IOR = CIOResult(); if (S->IOR == EACCES) S->IOR = EAGAIN; if (LockMode == UnLock) S->IOR = NoErr; if (S->IOR != NoErr) return(-1); } } #else if (lseek(S->F, LOCK_OFF + rec, SEEK_SET) == -1L) if ((S->IOR = CIOResult()) != NoErr) return(-1) ; if (lockf(S->F,lm, 1L) == -1) if ((S->IOR = CIOResult()) != NoErr) return(-1) ; #endif } #ifdef DOS if (_lseek(S->F, pos, SEEK_SET) == -1L) #else if (lseek(S->F, pos, SEEK_SET) == -1L) #endif if ((S->IOR = CIOResult()) != NoErr) return(-1) ; return(0) ; } /* @(#) CLockRec CUSTIO @(ID) Esegue un comando lock sul record nro. "rec" del file descritto da "s". @(FD) @(ISV) Solo versione XENIX. @(FSV) */ void CLockRec(s, rec, lockmode) SecDef *s ; /* descrittore del file */ RecNoType rec ; /* numero record su cui effettuare il lock */ unsigned lockmode;/* operazione lock da effettuare */ { seeklk(s, CalcPos(rec, s->LenRec, s->BaseFil), setlock(lockmode), lockmode, rec); } /* @(#) CVerify CUSTIO @(ID) Verifica che il file "name" esista. @(FD) @(ISV) junk = variabile di lavoro. @(FSV) */ void CVerify(S, Name) SecDef *S; /* descrittore File */ FileName Name; /* nome file */ { int junk ; S->IOR = NoErr; #ifdef DOS if ((S->F = sopen(Name, O_RDONLY | O_BINARY, SH_DENYNO, S_IREAD | S_IWRITE)) == -1) #else if ((S->F = open(Name, O_RDONLY, 0666)) == -1) #endif S->IOR = CIOResult(); else if (close(S->F) == -1) { junk = CIOResult(); if (!S->IOR) S->IOR = junk; } } /* @(#) COpen CUSTIO @(ID) Apre un file di record. @(FD) @(ISV) junk = variabile di lavoro. @(FSV) */ void COpen(S, Name, Len, Base, LockMode) SecDef *S; /* descrittore file */ FileName Name; /* nome del file */ unsigned Len; /* lunghezza record */ unsigned Base; /* offset dall'inizio del file fisico; e' sempre 0 per i file dati */ unsigned LockMode;/* lock di apertura del file */ { int junk; S->IOR = NoErr; #ifdef DOS if ((S->F = sopen(Name, O_RDWR|O_BINARY, test_share() && LockMode == ExclLock ? SH_DENYRW : SH_DENYNO, S_IREAD|S_IWRITE)) == -1) #else if ((S->F = open(Name, O_RDWR , 0666)) == -1) #endif if ((S->IOR = CIOResult()) != NoErr) return ; S->LenRec = Len; S->BaseFil = Base * BlockLenIO ; S->LockMode = LockMode ; S->lpos = -1; strcpy(S->name, Name); if (lseek(S->F, 0L, SEEK_SET) == -1L) if ((S->IOR = CIOResult()) != NoErr) return ; if (excllock(Name, (S->LockMode == ExclLock)) == -1) { S->IOR = CIOResult(); if (close(S->F) == -1) junk = CIOResult(); } } /* @(#) CCreate CUSTIO @(ID) Crea un nuovo file di record. @(FD) @(ISV) junk = variabile di lavoro. @(FSV) */ void CCreate(S, Name, Len, Base, MaxSec) SecDef *S; /* descrittore del file */ FileName Name; /* nome del file */ unsigned Len; /* lunghezza del record */ unsigned Base; /* offset dall'inizio del file fisico */ RecNoType MaxSec; /* Numero di blocchi di disco da allocare */ { int junk; S->IOR = NoErr; #ifdef DOS if ((S->F = sopen(Name, O_RDWR | O_CREAT, SH_DENYNO, S_IREAD | S_IWRITE)) == -1) #else if ((S->F = open(Name, O_RDWR | O_CREAT, 0666)) == -1) #endif if ((S->IOR = CIOResult()) != NoErr) return ; if (chsize(S->F, ((RecNoType) MaxSec)*BlockLenIO) == -1) S->IOR = CIOResult(); if (close(S->F) == -1) { junk = CIOResult(); if (!S->IOR) S->IOR = junk; } } /* @(#) CChsize CUSTIO @(ID) Cambia la dimensione di un file di record. @(FD) @(ISV) junk = variabile di lavoro. @(FSV) */ void CChsize(S, Name, Len, Base, MaxSec) SecDef *S; /* descrittore del file */ FileName Name; /* nome del file */ unsigned Len; /* lunghezza del record */ unsigned Base; /* offset dall'inizio del file fisico */ RecNoType MaxSec; /* numero di blocchi del file modificati */ { int junk; S->IOR = NoErr; #ifdef DOS if ((S->F = sopen(Name, O_RDWR | O_BINARY, SH_DENYNO, S_IREAD | S_IWRITE)) == -1) #else if ((S->F = open(Name, O_RDWR, 0666)) == -1) #endif if ((S->IOR = CIOResult()) != NoErr) return ; if (chsize(S->F, ((RecNoType) MaxSec)*BlockLenIO) == -1) S->IOR = CIOResult(); if (close(S->F) == -1) { junk = CIOResult(); if (!S->IOR) S->IOR = junk; } } /* @(#) CClose CUSTIO @(ID) Chiude un file di record. @(FD) */ void CClose(S) SecDef *S; /* descrittore del file da chiudere */ { S->IOR = NoErr; #ifdef DOS if (close(S->F) == -1) S->IOR = CIOResult(); #else if (S->LockMode == AutoLock) { if (S->lpos != -1) { if (lseek(S->F, S->lpos, SEEK_SET) == -1L) if ((S->IOR = CIOResult()) != NoErr) return ; if (lockf(S->F,F_ULOCK,(long) S->LenRec) == -1) if ((S->IOR = CIOResult()) != NoErr) return ; } } if (close(S->F) == -1) S->IOR = CIOResult(); if (exclunlock(S->name, (S->LockMode == ExclLock)) == -1) S->IOR = CIOResult(); #endif } /* @(#) CDelete CUSTIO @(ID) Cancella un file di record. @(FD) */ void CDelete(S, Name) SecDef *S; /* descrittore del file */ FileName Name; /* Nome del file */ { if (unlink(Name) == -1) S->IOR = CIOResult(); else S->IOR = NoErr; } /* @(#) CRead CUSTIO @(ID) Legge un record del file. @(FD) @(ISV) junk = variabile di lavoro. fpos = contiene la posizione del record all'interno del file. @(FSV) @(IN) Lo spazio necessario a contenere il record letto deve essere stato allocato in precedenza. @(FN) */ void CRead(S, RecBuf, Rec, LockMode) SecDef *S; /* descrittore del file */ RecType RecBuf; /* spazio per contenere il record */ RecNoType Rec; /* Record da leggere */ unsigned LockMode; /* lock sul record */ { int junk; register RecNoType fpos; if (Rec) { S->IOR = NoErr; fpos = CalcPos(Rec, S->LenRec, S->BaseFil); #ifndef DOS if (S->LockMode == AutoLock) { if (S->lpos != -1) if (seeklk(S, S->lpos, F_ULOCK, LockMode, (S->lpos - S->BaseFil) / S->LenRec) == -1) return ; if (seeklk(S, fpos, F_TLOCK, LockMode, Rec) == -1) return ; S->lpos = fpos ; } else #endif if (seeklk(S, fpos, setlock(LockMode), LockMode, Rec) == -1) return ; if (read(S->F, RecBuf, (unsigned) S->LenRec) == -1) { S->IOR = CIOResult(); junk = seeklk(S, fpos, setlock(UnLock), LockMode, Rec) == -1; } } else S->IOR = 3; } /* @(#) CWrite CUSTIO @(ID) Scrive un record nel file. @(FD) @(ISV) junk = variabile di lavoro. fpos = contiene la posizione del record all'interno del file. @(FSV) @(IN) Lo spazio necessario a contenere il record letto deve essere stato allocato in precedenza. @(FN) */ void CWrite(S, RecBuf, Rec, LockMode) SecDef *S; /* descrittore del file */ RecType RecBuf; /* spazio che contiene il record da scrivere */ RecNoType Rec; /* numero del record da scrivere */ unsigned LockMode; /* lock sul record */ { int junk; register RecNoType fpos; if (Rec) { S->IOR = NoErr; fpos = CalcPos(Rec, S->LenRec, S->BaseFil); #ifndef DOS if (S->LockMode == AutoLock) { if (S->lpos != -1) if (seeklk(S, S->lpos, F_ULOCK, LockMode, (S->lpos - S->BaseFil) / S->LenRec) == -1) return ; if (seeklk(S, fpos, F_TLOCK, LockMode, Rec) == -1) return ; S->lpos = fpos ; } else #endif if (seeklk(S, fpos, setlock(LockMode), LockMode, Rec) == -1) return ; if (write(S->F, RecBuf, (unsigned) S->LenRec) == -1) { S->IOR = CIOResult(); junk = seeklk(S, fpos, setlock(UnLock), LockMode, Rec) == -1; } } else S->IOR = 3; } /* @(#) IDeleteRec CUSTIO @(ID) Cancellazione logica di un record. @(FD) */ void IDeleteRec(RecBuf) RecType RecBuf; /* record da cancellare */ { RecBuf[0] = Deleted; } /* @(#) IRecallRec CUSTIO @(ID) Recupero logico di un record. @(FD) */ void IRecallRec(RecBuf) RecType RecBuf; /* record da recuperare logicamente */ { RecBuf[0] = Valid; } /* @(#) IRecIsDeleted CUSTIO @(ID) Controlla se il record in "RecBuf" e' cancellato oppure no. @(FD) */ BOOLEAN IRecIsDeleted(RecBuf) RecType RecBuf; /* record da controllare */ { return (RecBuf[0] == Deleted); } /* @(#) ITestLock CUSTIO @(ID) Controlla se l'errore "err" e' dovuto ad un lock. @(FD) @(ISV) Versione DOS e XENIX. @(FSV) */ BOOLEAN ITestLock(err) int err; /* codice di errore */ { return(TESTLOCK(err)) ; } #ifndef DOS struct lockdata { int users; int excl; } ld; int sizeld = sizeof(struct lockdata); /* @($) lockpath CUSTIO @(ID) Restituisce il nome del file di lock per il file "name". @(FD) @(ISV) path = percorso per il file (/usr/tmp/....). s1,s,s2 = stringhe di lavoro (nomi file). Solo versione XENIX. @(FSV) */ char *lockpath(name) char *name; /* stringa nome file */ { static char path[200]; char *s1 = name, *s = name, *s2 = name; while ((s1 = strchr(s, DIRSEP)) != NULL) { s2 = s; s = s1 + 1; } sprintf(path, "/usr/tmp/%s", s2); return(path); } /* @($) dirname CUSTIO @(ID) Estrae dal path il nome del direttorio. @(FD) @(ISV) path = percorso per il file . s = stringa di lavoro. Solo versione XENIX. @(FSV) */ char *dirname(name) char *name; /* stringa contenente il path */ { static char path[200]; char *s; strcpy(path,name); if ((s = strrchr(path, DIRSEP)) == NULL) strcpy(path, "."); else *s = '\0'; return(path); } static int semres = 0; /* @($) semtran CUSTIO @(ID) Trasforma il nome di un semaforo in un identificatore poi lo crea o lo apre. @(FD) @(ISV) key = chiave corrispondente al nome semaforo. id = identificatore del semaforo. Solo versione XENIX. La semget fa una open sul semaforo; se non lo trova lo crea e poi lo libera. @(FSV) */ int semtran(s) char *s; /* stringa nome del semaforo */ { register int key = 0, sid; semres = 0 ; while (*s) key += *s++; if ((sid = semget((key_t) key, 1, 0666)) == -1) { if ((sid = semget((key_t) key, 1, 0666 | IPC_CREAT)) == -1) semres = -1; VS(sid); } return(sid); } /* @($) semcall CUSTIO @(ID) Chiama il semaforo "sid" e su di esso svolge "op". @(FD) @(ISV) sb = struttura necessaria per la chiamata a "semop". Solo versione XENIX. @(FSV) @(IN) se op = -1 il semaforo viene occupato. se op = +1 il semaforo viene liberato. @(FN) */ static void semcall(sid, op) int sid; /* identificatore semaforo */ int op; /* operazione da effettuare sul semaforo: libero/occupato */ { struct sembuf sb; semres = 0 ; sb.sem_num = 0; sb.sem_op = op; sb.sem_flg = 0; if (semop(sid, &sb, 1) == -1) semres = -1; } /* @($) PS CUSTIO @(ID) Acquisisce il semaforo "sid". @(FD) @(ISV) Solo versione XENIX. @(FSV) */ void PS(sid) int sid; /* identificatore semaforo */ { semcall(sid, -1); } /* @($) VS CUSTIO @(ID) Rilascia il semaforo "sid". @(FD) @(ISV) Solo versione XENIX. @(FSV) */ void VS(sid) int sid; { semcall(sid, 1); } #endif /* @(#) excllock CUSTIO @(ID) Funzione per la gestione di un lock esclusivo su tutto il file. @(FD) @(ISV) Nella versione XENIX: path = contiene il file di lock. dir = contiene la directory. fd = identificatore restituito dalla "open". junk = variabile di lavoro. sid = identificatore del semaforo su locksem. errno = numero errore. sb = struttura che contiene informazioni sullo stato del file (vedi "stat"). @(FSV) */ int excllock(name,excl) char *name; /* nome del file */ BOOLEAN excl; /* se true deve fare il lock ex. altrimenti no */ { #ifndef DOS char path[200], dir[200]; int fd, junk, sid; extern int errno; struct stat sb; strcpy(path, lockpath(name)); strcpy(dir, dirname(path)); sid = semtran(LOCKSEM); if (semres == -1) return(-1); PS(sid); if (semres == -1) return(-1); if ((stat(dir, &sb) == -1) && (errno == ENOENT)) CMkDir(dir); if (((fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666)) == -1) && errno == EEXIST) { errno = 0; if ((fd = open(path, O_RDWR, 0666)) == -1) { VS(sid); return(-1); } if ((read(fd, &ld, sizeld) <= 0) || (lseek(fd, 0L, SEEK_SET) == -1L)) { junk = close(fd); VS(sid); return(-1) ; } if (((ld.excl) && (ld.excl != getpid())) || excl) { junk = close(fd); errno = EACCES ; VS(sid); return(-1); } ld.users++; } else { if (fd == -1) { VS(sid); return(-1); } errno = 0; ld.users = 1; if (excl) ld.excl = getpid(); else ld.excl = 0; } if (write(fd, &ld, sizeld) == -1) { junk = close(fd); VS(sid); return(-1); } if (close(fd) == -1) { VS(sid); return(-1); } VS(sid); if (semres == -1) return(-1); #endif return(0); } /* @(#) exclunlock CUSTIO @(ID) Gestisce un unlock esclusivo su tutto il file. @(FD) @(ISV) Nella versione XENIX: path = contiene il file di lock. fd = identificatore restituito dalla "open". junk = variabile di lavoro. sid = identificatore del semaforo su locksem. @(FSV) */ int exclunlock(name,excl) char *name; /* nome file */ BOOLEAN excl; /* se true esegue un unlock sul file */ { #ifndef DOS int fd, junk, sid; char path[200]; strcpy(path, lockpath(name)); sid = semtran(LOCKSEM); if (semres == -1) return(-1); PS(sid); if (semres == -1) return(-1); if (((fd = open(path, O_RDWR , 0666)) == -1) || (read(fd, &ld, sizeld) <= 0) || (lseek(fd, 0L, SEEK_SET) == -1L)) { junk = close(fd); VS(sid); return(-1); } if (excl) ld.excl = 0; if (--ld.users == 0) { if ((close(fd) == -1) || (unlink(path) == -1)) { VS(sid); return(-1); } VS(sid); if (semres == -1) return(-1); return(0); } if (write(fd, &ld, sizeld) == -1) { junk = close(fd); VS(sid); return(-1); } if (close(fd) == -1) { VS(sid); return(-1); } VS(sid); if (semres == -1) return(-1); #endif return(0); }