home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
ARCHIVERS
/
lha205.lzh
/
ln.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-14
|
17KB
|
550 lines
/* Ln: create a hard link to a file (os9/68k)
* by Robert A. Larson (blarson@skat.usc.edu)
* This is placed in the public domain for all to enjoy.
*
****** USE AT YOUR OWN RISK *****
*
* 01/14/89 Version 1.0
*
* Warning: this does potentialy dangerous writing to directories
* and to the raw disk. Although some attempt is made to lock out
* other users from interfearing, I'm not sure the locking works.
* Moving or links to directories should be used with EXTREME caution
* if at all. Note that moving a directory can make a directory tree
* inaccessable, and 'deldir'ing a linked directory will delete its
* contents and change the remaining links to normal files.
*/
/*
* Version 1.1
*
* Modified by Mike Haaland
*
* December 8, 1992 Tuesday 9:55:17 am - MSH
*
* o added sector size checking for OSK 2.4
* o added closing path to raw disk after successful link
* o Added FROM_DISK || FROM_DRIVER as methods of checking sector size
* o Added TESTING define for debuggin info
*
*/
#include <stdio.h>
#include <ctype.h>
#include <modes.h>
#include <direct.h>
#include <errno.h>
#include <sgstat.h>
struct sgbuf sgopts;
extern char *rindex();
extern int open();
extern int close();
extern int read();
extern int write();
extern int lseek();
extern int access();
extern int getuid();
extern int strcmp();
extern char *strcpy();
extern char *strcat();
extern char *_prgname();
extern int _gs_devn();
extern int _ss_lock();
extern long _gs_pos();
static int dncmp(); /* directory name comparison */
static int do_link(); /* does all the real work */
/* keys for the do_link subroutine */
#define DO_LINK 0
#define DO_RENAME 1
#define TO_DIR 128 /* orred with one of the above */
/*
* Define one of the following ONLY
*
* FROM_DISK - will read LSN0 for the sector size info, byte 0x68
* works on ALL OSK systems that I've encountered.
* FROM_DRIVER - uses the path descriptor sg_ssize field
* BEWARE: some OSK 2.3 drivers LIE and say 512 bytes
* when the disk actually uses 256 byte sectors!!!
* MSH
*/
#define FROM_DISK
/* Get sector size info from driver - Hazelwoods HD Driver lies on the TC70
#define FROM_DRIVER
*/
#ifndef LINK
main(argc, argv)
int argc;
char **argv;
{
register int i;
char *todir = NULL;
int skip, what;
for(i = 1; i < argc; i++) {
if(argv[i][0]=='-') {
switch(argv[i][1]) {
case '?':
usage();
exit(0);
case 'w':
if(todir==NULL && argv[i][2]=='=') {
todir = &argv[i][3];
skip = i;
continue;
}
/*FALLTHROUGH*/
default:
usage();
exit(1);
}
}
}
what = strcmp(argv[0],"ln")==0 ? DO_LINK : DO_RENAME;
if(todir==NULL) {
if(argc != 3) {
usage();
exit(1);
}
exit(do_link(argv[1], argv[2], what) < 0);
}
what |= TO_DIR;
for(i=1; i < argc; i++) {
if(i!=skip) {
if(do_link(argv[i], todir, what) < 0) exit(1);
}
}
exit(0);
}
usage() {
register char *prg = _prgname();
fprintf(stderr,"Usage: %s -?\n",prg);
fprintf(stderr," %s <from> <to>\n",prg);
fprintf(stderr," %s -w=<todir> <from> [<from>]...\n", prg);
}
#define problem(x) fprintf x
#else
#define problem(x) /* ignore */
link(old, new)
register char *old, *new;
{
return do_link(old, new, DO_LINK);
}
rename(old, new)
register char *old, *new;
{
return do_link(old, new, DO_RENAME);
}
#endif
static int do_link(old, new, action)
char *old, *new;
int action;
{
char *olddir, *oldname, *newdir, *newname;
int olddirp, newdirp;
char olddevn[32], newdevn[32+2];
struct dirent de;
unsigned char fdl;
int disk;
long empty_slot;
long newdir_addr;
long entrydir_addr;
long fdladdr;
int same;
int i;
int sector_size;
long old_slot;
char namebuf[256];
char nn[128];
char ssz;
int uid;
if((oldname = rindex(old, '/')) == NULL) {
olddir = ".";
oldname = old;
}
else {
olddir = namebuf;
strncpy(namebuf, old, oldname - old);
namebuf[oldname - old] = '\0';
oldname++;
}
if(action & TO_DIR) {
newdir = new;
newname = oldname;
action &= ~TO_DIR;
}
else {
if((newname = rindex(new, '/')) == NULL) {
newdir = ".";
newname = new;
}
else {
newdir = namebuf;
if(olddir==namebuf) newdir += oldname - old;
strncpy(newdir, new, newname - new);
newdir[newname - new] = '\0';
newname++;
}
}
if(_prsnam(newname) <= 0) {
problem((stderr, "%s: Invalid file name \"%s\"\n", _prgname(), newname));
return -1;
}
if((olddirp = open(olddir, S_IREAD | S_IWRITE | S_IFDIR)) < 0) {
problem((stderr, "%s: Can't open old directory \"%s\"\n", _prgname(),
olddir));
return -1;
}
if((newdirp = open(newdir, S_IREAD | S_IWRITE | S_IFDIR)) < 0) {
problem((stderr, "%s: Can't open new directory \"%s\"\n", _prgname(),
newdir));
close(olddirp);
return -1;
}
_gs_devn(olddirp, olddevn);
_gs_devn(newdirp, newdevn);
if(strcmp(olddevn, newdevn) != 0) {
problem((stderr, "%s: Not on same device \"%s\" \"%s\"\n",
_prgname(), olddir, newdir));
errno = E_DIFFER;
close(olddirp);
close(newdirp);
return -1;
}
if((lseek(newdirp, (long)sizeof de, 0) < 0) /* skip .. */
|| (read(newdirp, (char *)&de, sizeof de) != sizeof de)) { /* read . */
problem((stderr, "%s: Problem reading \"%s\"\n", _prgname(), newdir));
close(olddirp);
close(newdirp);
return -1;
}
newdir_addr = de.dir_addr;
if((lseek(olddirp, (long)sizeof de, 0) < 0) /* skip .. */
|| (read(olddirp, (char *)&de, sizeof de) != sizeof de)) { /* read . */
problem((stderr, "%s: Problem reading \"%s\"\n", _prgname(), olddir));
close(olddirp);
close(newdirp);
return -1;
}
if((same = (de.dir_addr == newdir_addr)) != 0) {
/* link to same directory, scan only once */
close(olddirp);
olddirp = newdirp;
/* rename to same name allowed, but not link */
if(action == DO_LINK && dncmp(oldname, newname) == 0) {
problem((stderr, "%s: Can't link to same name \"%s\" \"%s\"\n",
_prgname(), oldname, newname));
errno = E_CEF;
close(newdirp);
return -1;
}
if(_ss_lock(newdirp, 0xfffffffff) < 0) {
problem((stderr, "%s: Could not lock directory \"%s\"\n",
_prgname(), newdir));
close(newdirp);
return -1;
}
}
empty_slot = 0;
for(;;) {
if(read(olddirp, (char *)&de, sizeof de) != sizeof de) {
problem((stderr, "%s: Could not find \"%s\" in \"%s\"\n",
_prgname(), oldname, olddir));
errno = E_PNNF;
if(!same) close(olddirp);
close(newdirp);
return -1;
}
if(dncmp(de.dir_name, oldname) == 0) break; /* found it */
if(same) {
if(dncmp(de.dir_name, newname) == 0) {
problem((stderr, "%s: Already exists \"%s/%s\"\n",
_prgname(), newdir, newname));
errno = E_CEF;
close(newdirp);
return -1;
}
if(empty_slot == 0 && de.dir_name[0] == '\0')
empty_slot = _gs_pos(olddirp);
}
}
if(action != DO_LINK) old_slot = _gs_pos(olddirp);
entrydir_addr = de.dir_addr;
if(!same) {
if(_ss_lock(newdirp, 0xffffffff) < 0) {
problem((stderr, "%s: Can't lock directory \"%s\"\n", _prgname(),
newdir));
close(olddirp);
close(newdirp);
return -1;
}
}
if(action != DO_LINK && same) empty_slot = old_slot;
while(read(newdirp, (char *)&de, sizeof de) == sizeof de) {
if(dncmp(de.dir_name, newname) == 0) {
problem((stderr, "%s: Already exists \"%s/%s\"\n", _prgname(),
newdir, newname));
errno = E_CEF;
if(!same) close(olddirp);
close(newdirp);
return -1;
}
if(empty_slot == 0 && de.dir_name[0] == '\0') {
empty_slot = _gs_pos(newdirp);
}
}
strcpy(de.dir_name, newname);
i = strlen(de.dir_name);
de.dir_name[i-1] |= 0x80;
while(i < sizeof de.dir_name) de.dir_name[i++] = '\0';
de.dir_addr = entrydir_addr;
if(empty_slot != 0) {
if(lseek(newdirp, empty_slot - sizeof de, 0) < 0) {
problem((stderr, "%s: Can't position in \"%s\"\n", _prgname(),
newdir));
close(disk);
if(!same) close(olddirp);
close(newdirp);
return -1;
}
}
if(action == DO_LINK) { /* link: increase the link count */
/* Sector size info for OSK 2.4 added 12/07/1992 by MSH */
#ifdef FROM_DRIVER
if (_gs_opt(newdirp,&sgopts) == -1) {
problem((stderr, "%s: Can't get device sector size info.\n",
_prgname()));
close(olddirp);
close(newdirp);
return -1;
}
sector_size = sgopts.sg_ssize;
if (sector_size == 0)
sector_size = 256;
#endif
uid = getuid();
if (uid)
setuid(0);
newdevn[0] = '/'; /* form /<device>@ string */
strcat(strcpy(newdevn+1, olddevn), "@");
#ifdef TESTING
fprintf(stderr,"Opening '%s' for link\n",newdevn);
#endif
if((disk = open(newdevn, S_IREAD | S_IWRITE)) < 0) {
problem((stderr, "%s: Can't open \"%s\"\n", _prgname(), newdevn));
if(!same) close(olddirp);
close(newdirp);
setuid(uid);
return -1;
}
#ifdef FROM_MEDIA
/* Sector size info for OSK 2.4 added 12/07/1992 by MSH */
/* seek to byte 0x68 - LSNSize - media logical sector size */
if (lseek(disk,0x68,0) != 0x68) {
problem((stderr,"%s: Can't seek to LSN0 on \"%s\"\n",_prgname(),newdevn));
if(!same) close(olddirp);
close(newdirp);
setuid(uid);
return -1;
}
/* Read LSNSize byte */
if(read(disk, &ssz, sizeof ssz) != sizeof ssz) {
problem((stderr, "%s: Can't get sector size of \"%s\"\n", _prgname(), newdevn));
close(disk);
if(!same) close(olddirp);
setuid(uid);
close(newdirp);
return -1;
}
/* If it's 0 sector size is 256 bytes - Pre-OSK 2.4 */
if (ssz == 0)
ssz = 1;
/* value * 256 == sector size in bytes */
sector_size = ssz * 256;
#endif /* FROM_MEDIA */
#ifdef TESTING
fprintf(stderr,"Media sector size %d bytes\n",sector_size);
#endif
if((fdladdr = lseek(disk, (entrydir_addr * sector_size) +
((char *)(&(((struct fildes *)0)->fd_link)) - (char *)0),
0)) < 0) {
problem((stderr, "%s: Can't seek to sector 0x%x on \"%s\"\n",
_prgname(), entrydir_addr, newdevn));
close(disk);
if(!same) close(olddirp);
setuid(uid);
close(newdirp);
return -1;
}
#ifdef TESTING
fprintf(stderr,"Linkbyte addr (%d) for file '%s'\n",fdladdr,old);
#endif
if(read(disk, (char *)&fdl, sizeof fdl) != sizeof fdl) {
problem((stderr, "%s: Can't read \"%s\"\n", _prgname(), newdevn));
close(disk);
if(!same) close(olddirp);
setuid(uid);
close(newdirp);
return -1;
}
#ifdef TESTING
fprintf(stderr,"Linkbyte = (%d) for file '%s'\n",fdl,old);
#endif
if(fdl == 0) {
problem((stderr, "%s: Bad file descriptor \"%s/%s\"\n", _prgname(),
olddir, oldname));
errno = E_BMHP; /* no appropriate error number */
close(disk);
if(!same) close(olddirp);
setuid(uid);
close(newdirp);
return -1;
}
if(++fdl == 0) {
problem((stderr, "%s: Too many links \"%s/%s\"\n", _prgname(),
olddir, oldname));
errno = E_BMHP; /* no appropriate error number */
close(disk);
if(!same) close(olddirp);
setuid(uid);
close(newdirp);
return -1;
}
#ifdef TESTING
fprintf(stderr,"Inc. Linkbyte = (%d) to link '%s'\n",fdl,new);
#endif
if(lseek(disk, fdladdr, 0) != fdladdr) {
problem((stderr, "%s: Can't lseek on \"%s\"\n", _prgname(),
newdevn));
close(disk);
if(!same) close(olddirp);
setuid(uid);
close(newdirp);
return -1;
}
#ifdef TESTING
fprintf(stderr,"ReSeek to (%d) to link '%s'\n",fdladdr,new);
#endif
if(write(disk, &fdl, sizeof fdl) < 0) {
problem((stderr, "%s: Can't write to \"%s\"\n", _prgname(),
newdevn));
close(disk);
if(!same) close(olddirp);
setuid(uid);
close(newdirp);
return -1;
}
/* This wasn't here!!! - might have been my link problem, yes? */
close(disk);
#ifdef TESTING
fprintf(stderr,"Success %s linked to %s - (%d) links\n",old,new,fdl);
#endif
setuid(uid);
}
else {
strcpy(nn, newdir);
strcat(nn, "/");
strcat(nn, newname);
/* Don't let non-superuser move directories, it is dangerous!
* (artificial restriction)
*/
if(!same && access(nn, 0) != 0 && getuid() != 0) {
problem((stderr, "%s: Directory moving can only be done by superuser\n",
_prgname()));
errno = E_FNA;
close(olddirp);
close(newdirp);
return -1;
}
}
if(write(newdirp, (char *)&de, sizeof de) < 0) {
problem((stderr, "%s: Can't write to \"%s\"\n", _prgname(), newdir));
if(action==DO_LINK) close(disk);
if(!same) close(olddirp);
close(newdirp);
return -1;
}
if(action != DO_LINK && !same) { /* rename: delete old name */
if((disk = open(nn, S_IREAD | S_IWRITE | S_IFDIR)) >= 0) {
/* change .. when moving directory */
if(lseek(disk, (long)sizeof de.dir_name, 0) < 0) {
problem((stderr, "%s: can't position in \"%s\"\n",
_prgname(), nn));
close(disk);
close(olddirp);
close(newdirp);
return -1;
}
if(write(disk, (char *)&newdir_addr, sizeof newdir_addr) < 0) {
problem((stderr, "%s: Can't write to \"%s\"\n",
_prgname(), nn));
close(disk);
close(olddirp);
close(newdirp);
return -1;
}
close(disk);
}
fdl = '\0';
if(lseek(olddirp, old_slot - sizeof de, 0) < 0) {
problem((stderr, "%s: can't position in \"%s\"\n", _prgname(),
olddir));
close(olddirp);
close(newdirp);
return -1;
}
if(write(olddirp, (char *)&fdl, sizeof fdl) < 0) {
problem((stderr, "%s: can't write to \"%s\"\n", _prgname(),
olddir));
close(olddirp);
close(newdirp);
return -1;
}
}
if(action == DO_LINK) close(disk);
if(!same) close(olddirp);
close(newdirp);
return 0;
}
/* Compares two os9 file names, case independant.
* The first argument may be terminated by setting the msb of
* the last character or NUL terminated, the second must be NUL
* termintated. Returns zero on same, non-zero on different.
*/
static int dncmp(cp1, cp2)
register char *cp1, *cp2;
{
register int c1, c2;
while((c1 = *cp1++) != 0) {
if(c1 & 0x80) {
c1 &= 0x7f;
return ((c1 != (c2 = *cp2++)) &&
(isupper(c1) ? (tolower(c1) != c2) :
(!isupper(c2) || (tolower(c2) != c1)))) || *cp2;
}
if((c1 != (c2 = *cp2++)) && (isupper(c1) ? (tolower(c1) != c2) :
(!isupper(c2) || (tolower(c2) != c1)))) return 1;
}
return *cp2;
}