9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* [9fans] trfs
@ 2002-07-11  8:53 Fco.J.Ballesteros
  0 siblings, 0 replies; 2+ messages in thread
From: Fco.J.Ballesteros @ 2002-07-11  8:53 UTC (permalink / raw)
  To: 9fans

[-- Attachment #1: Type: text/plain, Size: 227 bytes --]

This is what I'm using to rename files. All I do is
	trfs -n tcp!foreign
	mount -c /srv/tcp!foreign /n/remote

BTW, It's also useful to debug 9p connections just by giving
the -v option.

Manual page included.

enjoy

[-- Attachment #2: trfs --]
[-- Type: text/plain, Size: 1789 bytes --]

.TH TRFS 4
.SH NAME
trfs  \-  translate spaces in file names file system
.SH SYNOPSIS
.B trfs
[
.B -Dv
]
[
.B -\fIRune\fP
]
[
.B -s
.I srvfile
]
[
.B -n
.I addr
]
.I servename
.SH DESCRIPTION
.I Trfs
translates 9P requests exchanged between a client and a file
server. The translation replaces spaces seen in remote file names 
to a different rune.
.PP
By default
.I trfs
translates spaces within file names to open box runes (0x2423)
"␣". A different rune can be selected by specifying it as an option.
.PP
.I Trfs
reaches the server through the
.I servename
file or through a network connection to the 
.I addr
address given to the
.B -n
option. 
The client mounts the file posted by
.I trfs
in
.IR srv (4).
The file posted is named
.B /srv/trfs
by default, but it can be 
.B /srv/\fIsrvfile\fP 
when the option
.B -s
is used, and also
.B /srv/\fIaddr\fP when the option
.B -n
is given.
.PP
Option
.B -v
instructs
.I trfs
to print to standard error a human readable copy of messages exchanged. This
makes
.I trfs
useful to debug file servers. The
.B -D
option enables debug messages.
.SH EXAMPLE
These examples dial a foreign system, start
.IR trfs ,
and mount it at
.B /n/remote.
Names like
.B "/n/remote/music/alan parsons" 
that contaning blanks
would be renamed to names like
.B "/n/remote/music/alan␣parsons."
.PP
.EX
	srv tcp!foreign
	trfs -s foreign.tr /srv/tcp!foreign
	mount -c /srv/foreign.tr /n/remote

	trfs -n tcp!foreign
	mount -c /srv/tcp!foreign /n/remote
.EE
.SH SOURCE
.B /sys/src/cmd/trfs.c
.SH BUGS
Spaces in remote file names are not caught when found inside file
names or other media. The rune used instead of space might be used
in remote file names leading to confussion.

[-- Attachment #3: trfs.c --]
[-- Type: text/plain, Size: 6838 bytes --]

#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>


enum {
	Maxmsglen	= IOHDRSZ + 8 * 1024,	// Max message size
	Nnames		= 128,			// Max # of names in a message
	OBRune		= L'␣',			// translate spc into this
};

#define dprint	if(debug)print

Rune	altspc = OBRune;
int	debug;
int	verbose;

uchar	rxbuf[Maxmsglen];
uchar	txbuf[Maxmsglen];
char	statbuf[Maxmsglen];
char	dirbuf[2*Maxmsglen];

Fidpool*fidpool;


static void
usage(void)
{
	fprint(2, "usage: %s [-Dv] [-RUNE] [-s srvfile] [-n addr] servename\n", argv0);
	exits("usage");
}


static ulong
getaux(Fid* fp)
{
	assert(sizeof(ulong) <= sizeof(fp->aux));
	return (ulong)fp->aux;
}

static void
setaux(Fid* fp, ulong aux)
{
	assert(sizeof(ulong) <= sizeof(fp->aux));
	fp->aux = (void*) aux;
}

static char*
emalloc(int l)
{
	char* r;
	r = malloc(l);
	if (r == nil)
		sysfatal("not enough memory");
	return r;
}

int	nnames;
char*	names[Nnames];

void
cleannames(void)
{
	int i;

	for (i = 0; i < nnames; i++)
		free(names[i]);
	nnames = 0;
}

/* From Plan 9 to Unix */
char*
exportname(char* name)
{
	Rune r;
	int   nr;
	char *uxname;
	char *up;

	if (name == 0 || utfrune(name, altspc) == 0)
		return name;
	up = uxname = emalloc(strlen(name) + 1);
	names[nnames++] = uxname;
	while(*name != 0){
		nr = chartorune(&r, name);
		if (r == altspc)
			r = ' ';
		up += runetochar(up, &r);
		name += nr;
	}
	*up = 0;
	return uxname;
}

/* From Unix to Plan 9 */
char*
importname(char* name)
{
	Rune r;
	int  nr;
	char *up;
	char *p9name;

	if (name == 0 || strchr(name, ' ') == 0)
		return name;
	p9name = emalloc(strlen(name) * 3 + 1);	// worst case: all blanks + 0
	up = p9name;
	names[nnames++] = p9name;
	while (*name != 0){
		nr = chartorune(&r, name);
		if (r == ' ')
			r = altspc;
		up += runetochar(up, &r);
		name += nr;
	}
	*up = 0;
	return p9name;
}

static int
isfdir(Fcall* f, Fid **fpp)
{
	Fid*	fp;
	int	r;
	fp = lookupfid(fidpool, f->fid);
	if (fp == nil)
		return 0;
	r = (fp->qid.type&QTDIR);
	if (r)
		*fpp = fp;
	else
		closefid(fp);
	return r;
}

static int
getfcall(int fd, Fcall* f)
{
	int r;

	r = read9pmsg(fd, rxbuf, sizeof(rxbuf));
	if (r <= 0)
		return 0;
	if (convM2S(rxbuf, sizeof(rxbuf), f) == 0)
		return -1;
	return 1;
}

static int
putfcall(int fd, Fcall* f)
{
	int n;

	n = convS2M(f, txbuf, sizeof(txbuf));
	if (n == 0)
		return -1;
	if (write(fd, txbuf, n) != n)
		return -1;
}

static void
twalk(Fcall* f)
{
	int	i;

	cleannames();
	for (i = 0; i < f->nwname; i++)
		f->wname[i] = exportname(f->wname[i]);
}

static void
tcreate(Fcall* f)
{
	cleannames();
	f->name = exportname(f->name);
}


// Dir read is tricky.
// We have to change the user supplied offset to match the sizes
// seen by the server. Sizes seen by client are greater than those
// seen by server since the change from ' ' to '␣' adds 2 bytes.
static void
tread(Fcall* f)
{
	Fid*	fp;

	fp = nil;
	if (!isfdir(f, &fp))
		return;
	f->count /= 3;	// sizes will grow upon return.
	if (fp == nil)
		sysfatal("can't find fid\n");
	if (f->offset == 0)
		setaux(fp, 0);
	f->offset -= getaux(fp);	// cumulative size delta
	closefid(fp);
}

static void
rread(Fcall* f)
{
	ulong	n, rn, nn, delta;
	Dir	d;
	Fid*	fp;

	if (!isfdir(f, &fp))
		return;
	if (f->count == 0)
		goto done;
	cleannames();
	for (n = nn = 0; n < f->count; n += rn){
		rn = convM2D((uchar*)f->data + n, f->count - n, &d, statbuf);
		if (rn <= BIT16SZ)
			break;
		d.name = importname(d.name);
		//dprint("⇒ %D\n", &d);
		nn += convD2M(&d, (uchar*)dirbuf + nn, sizeof(dirbuf) - nn);
	}
	delta = nn - n;
	setaux(fp, getaux(fp) + delta);
	f->count = nn;
	f->data = dirbuf;
done:
	closefid(fp);
}

static void
twstat(Fcall* f)
{
	Dir	d;

	cleannames();
	if (convM2D(f->stat, f->nstat, &d, statbuf) <= BIT16SZ)
		return;
	d.name = exportname(d.name);
	f->nstat = convD2M(&d, (uchar*)dirbuf, sizeof(dirbuf));
	f->stat = (uchar*)dirbuf;
	if (statcheck(f->stat, f->nstat) < 0)
		dprint("stat fails\n");
}

static void
rstat(Fcall* f)
{
	Dir	d;

	cleannames();
	convM2D(f->stat, f->nstat, &d, statbuf);
	d.name = importname(d.name);
	f->nstat = convD2M(&d, (uchar*)dirbuf, sizeof(dirbuf));
	f->stat = (uchar*)dirbuf;
	if (statcheck(f->stat, f->nstat) < 0)
		dprint("stat fails\n");
}

void
nop(Fid*)
{
}


static void
service(int cfd, int sfd, int dfd)
{
	Fcall	f;
	int	r;
	Fid*	fp;

	fidpool = allocfidpool(nop);
	for(;;){
		fp = nil;
		r = getfcall(cfd, &f);
		if (r <= 0)
			break;
		if(verbose)
			fprint(dfd , "c→s %F\n", &f);
		switch(f.type){
		case Tclunk:
		case Tremove:
			// BUG in lib9p? removefid leaks fid.
			// is that what it should do?
			fp = lookupfid(fidpool, f.fid);
			if (fp != nil){
				removefid(fidpool, f.fid);
				closefid(fp);
				closefid(fp);
				fp = nil;
			}
			break;
		case Tcreate:
			tcreate(&f);
			// and also...
		case Topen:
			fp = allocfid(fidpool, f.fid);
			fp->aux = 0;
			break;
		case Tread:
			tread(&f);
			break;
		case Twalk:
			twalk(&f);
			break;
		case Twstat:
			twstat(&f);
			break;
		}
		if(verbose && debug)
			fprint(dfd , "c→s %F\n", &f);
		putfcall(sfd, &f);

		r = getfcall(sfd, &f);
		if (r <= 0)
			break;
		if (verbose)
			fprint(dfd, "c←s %F\n", &f);
		switch(f.type){
		case Ropen:
		case Rcreate:
			fp->qid = f.qid;
			break;
		case Rread:
			rread(&f);
			break;
		case Rstat:
			rstat(&f);
			break;
		}
		if(verbose && debug)
			fprint(dfd , "c←s %F\n", &f);
		putfcall(cfd, &f);
		if (fp != nil)
			closefid(fp);
	}
}

void
main(int argc, char* argv[])
{
	char*	srv = nil;
	char*	sname = nil;
	char*	addr = nil;
	int	fd;
	int	p[2];

	ARGBEGIN{
	case 'D':
		debug = 1;
		break;
	case 'n':
		addr = EARGF(usage());
		break;
	case 'v':
		verbose = 1;
		break;
	case 's':
		sname = EARGF(usage());
		break;
	default:
		altspc = ARGC();
	}ARGEND;
	if (addr == nil){
		if (argc < 1)
			usage();
		srv = *argv;
		argc--;
	}
	if (argc > 0)
		usage();
	if (sname == nil)
		sname = (addr != nil) ? addr : "trfs";
	fmtinstall('D', dirfmt);
	fmtinstall('M', dirmodefmt);
	fmtinstall('F', fcallfmt);

	if (addr == nil)
		fd = open(srv, ORDWR);
	else
		fd = dial(netmkaddr(addr, "net", "9fs"), 0, 0, 0);
	if (fd < 0 || pipe(p) < 0)
		sysfatal("can't connect to  server %s: %r\n", (addr?addr:srv));
	if (postfd(sname, p[0]) < 0)
		sysfatal("can't post srv: %r\n");
	close(p[0]);
	switch(rfork(RFPROC)){
	case 0:
		service(p[1], fd, 2);
		break;
	case -1:
		sysfatal("can't fork server: %r\n");
		break;
	}
	exits(nil);	
}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [9fans] trfs
@ 2002-07-12  2:55 okamoto
  0 siblings, 0 replies; 2+ messages in thread
From: okamoto @ 2002-07-12  2:55 UTC (permalink / raw)
  To: 9fans

>translates spaces within file names to open box runes (0x2423)
>"␣". A different rune can be selected by specifying it as an option.

:-)

Kenji  - I don't reject your efforts, of course



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2002-07-12  2:55 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-07-11  8:53 [9fans] trfs Fco.J.Ballesteros
2002-07-12  2:55 okamoto

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).