19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <ip.h>
51269a55eSDavid du Colombier #include <mp.h>
61269a55eSDavid du Colombier #include <libsec.h>
79a747e4fSDavid du Colombier #include <auth.h>
89a747e4fSDavid du Colombier #include <fcall.h>
99a747e4fSDavid du Colombier #include <ctype.h>
109a747e4fSDavid du Colombier #include <String.h>
119a747e4fSDavid du Colombier #include "ftpfs.h"
129a747e4fSDavid du Colombier
139a747e4fSDavid du Colombier enum
149a747e4fSDavid du Colombier {
159a747e4fSDavid du Colombier /* return codes */
169a747e4fSDavid du Colombier Extra= 1,
179a747e4fSDavid du Colombier Success= 2,
189a747e4fSDavid du Colombier Incomplete= 3,
199a747e4fSDavid du Colombier TempFail= 4,
209a747e4fSDavid du Colombier PermFail= 5,
219a747e4fSDavid du Colombier Impossible= 6,
229a747e4fSDavid du Colombier };
239a747e4fSDavid du Colombier
249a747e4fSDavid du Colombier Node *remdir; /* current directory on remote machine */
259a747e4fSDavid du Colombier Node *remroot; /* root directory on remote machine */
269a747e4fSDavid du Colombier
279a747e4fSDavid du Colombier int ctlfd; /* fd for control connection */
289a747e4fSDavid du Colombier Biobuf ctlin; /* input buffer for control connection */
299a747e4fSDavid du Colombier Biobuf stdin; /* input buffer for standard input */
309a747e4fSDavid du Colombier Biobuf dbuf; /* buffer for data connection */
319a747e4fSDavid du Colombier char msg[512]; /* buffer for replies */
329a747e4fSDavid du Colombier char net[Maxpath]; /* network for connections */
339a747e4fSDavid du Colombier int listenfd; /* fd to listen on for connections */
349a747e4fSDavid du Colombier char netdir[Maxpath];
359a747e4fSDavid du Colombier int os, defos;
369a747e4fSDavid du Colombier char topsdir[64]; /* name of listed directory for TOPS */
379a747e4fSDavid du Colombier String *remrootpath; /* path on remote side to remote root */
389a747e4fSDavid du Colombier char *user;
399a747e4fSDavid du Colombier int nopassive;
409a747e4fSDavid du Colombier long lastsend;
411269a55eSDavid du Colombier extern int usetls;
429a747e4fSDavid du Colombier
439a747e4fSDavid du Colombier static void sendrequest(char*, char*);
449a747e4fSDavid du Colombier static int getreply(Biobuf*, char*, int, int);
459a747e4fSDavid du Colombier static int active(int, Biobuf**, char*, char*);
469a747e4fSDavid du Colombier static int passive(int, Biobuf**, char*, char*);
479a747e4fSDavid du Colombier static int data(int, Biobuf**, char*, char*);
489a747e4fSDavid du Colombier static int port(void);
499a747e4fSDavid du Colombier static void ascii(void);
509a747e4fSDavid du Colombier static void image(void);
519a747e4fSDavid du Colombier static void unixpath(Node*, String*);
529a747e4fSDavid du Colombier static void vmspath(Node*, String*);
539a747e4fSDavid du Colombier static void mvspath(Node*, String*);
549a747e4fSDavid du Colombier static Node* vmsdir(char*);
559a747e4fSDavid du Colombier static int getpassword(char*, char*);
56ecc2a59cSDavid du Colombier static int nw_mode(char dirlet, char *s);
579a747e4fSDavid du Colombier
589a747e4fSDavid du Colombier /*
599a747e4fSDavid du Colombier * connect to remote server, default network is "tcp/ip"
609a747e4fSDavid du Colombier */
619a747e4fSDavid du Colombier void
hello(char * dest)629a747e4fSDavid du Colombier hello(char *dest)
639a747e4fSDavid du Colombier {
649a747e4fSDavid du Colombier char *p;
659a747e4fSDavid du Colombier char dir[Maxpath];
661269a55eSDavid du Colombier TLSconn conn;
679a747e4fSDavid du Colombier
689a747e4fSDavid du Colombier Binit(&stdin, 0, OREAD); /* init for later use */
699a747e4fSDavid du Colombier
709a747e4fSDavid du Colombier ctlfd = dial(netmkaddr(dest, "tcp", "ftp"), 0, dir, 0);
719a747e4fSDavid du Colombier if(ctlfd < 0){
729a747e4fSDavid du Colombier fprint(2, "can't dial %s: %r\n", dest);
739a747e4fSDavid du Colombier exits("dialing");
749a747e4fSDavid du Colombier }
751269a55eSDavid du Colombier
769a747e4fSDavid du Colombier Binit(&ctlin, ctlfd, OREAD);
779a747e4fSDavid du Colombier
789a747e4fSDavid du Colombier /* remember network for the data connections */
799a747e4fSDavid du Colombier p = strrchr(dir+1, '/');
809a747e4fSDavid du Colombier if(p == 0)
819a747e4fSDavid du Colombier fatal("wrong dial(2) linked with ftp");
829a747e4fSDavid du Colombier *p = 0;
839a747e4fSDavid du Colombier safecpy(net, dir, sizeof(net));
849a747e4fSDavid du Colombier
859a747e4fSDavid du Colombier /* wait for hello from other side */
869a747e4fSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)
879a747e4fSDavid du Colombier fatal("bad hello");
88d9306527SDavid du Colombier if(strstr(msg, "Plan 9"))
89d9306527SDavid du Colombier os = Plan9;
901269a55eSDavid du Colombier
911269a55eSDavid du Colombier if(usetls){
921269a55eSDavid du Colombier sendrequest("AUTH", "TLS");
931269a55eSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)
941269a55eSDavid du Colombier fatal("bad auth tls");
951269a55eSDavid du Colombier
961269a55eSDavid du Colombier ctlfd = tlsClient(ctlfd, &conn);
971269a55eSDavid du Colombier if(ctlfd < 0)
981269a55eSDavid du Colombier fatal("starting tls: %r");
991269a55eSDavid du Colombier free(conn.cert);
1001269a55eSDavid du Colombier
1011269a55eSDavid du Colombier Binit(&ctlin, ctlfd, OREAD);
1021269a55eSDavid du Colombier
1031269a55eSDavid du Colombier sendrequest("PBSZ", "0");
1041269a55eSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)
1051269a55eSDavid du Colombier fatal("bad pbsz 0");
1061269a55eSDavid du Colombier sendrequest("PROT", "P");
1071269a55eSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)
1081269a55eSDavid du Colombier fatal("bad prot p");
1091269a55eSDavid du Colombier }
1109a747e4fSDavid du Colombier }
1119a747e4fSDavid du Colombier
1129a747e4fSDavid du Colombier /*
1139a747e4fSDavid du Colombier * login to remote system
1149a747e4fSDavid du Colombier */
1159a747e4fSDavid du Colombier void
rlogin(char * rsys,char * keyspec)116eaa278a2SDavid du Colombier rlogin(char *rsys, char *keyspec)
1179a747e4fSDavid du Colombier {
1189a747e4fSDavid du Colombier char *line;
1199a747e4fSDavid du Colombier char pass[128];
120d9306527SDavid du Colombier UserPasswd *up;
1219a747e4fSDavid du Colombier
122d9306527SDavid du Colombier up = nil;
1239a747e4fSDavid du Colombier for(;;){
124d9306527SDavid du Colombier if(up == nil && os != Plan9)
125eaa278a2SDavid du Colombier up = auth_getuserpasswd(auth_getkey, "proto=pass server=%s service=ftp %s", rsys, keyspec);
126d9306527SDavid du Colombier if(up != nil){
127d9306527SDavid du Colombier sendrequest("USER", up->user);
128d9306527SDavid du Colombier } else {
1299a747e4fSDavid du Colombier print("User[default = %s]: ", user);
1309a747e4fSDavid du Colombier line = Brdline(&stdin, '\n');
1319a747e4fSDavid du Colombier if(line == 0)
1329a747e4fSDavid du Colombier exits(0);
1339a747e4fSDavid du Colombier line[Blinelen(&stdin)-1] = 0;
1349a747e4fSDavid du Colombier if(*line){
1359a747e4fSDavid du Colombier free(user);
1369a747e4fSDavid du Colombier user = strdup(line);
1379a747e4fSDavid du Colombier }
1389a747e4fSDavid du Colombier sendrequest("USER", user);
139d9306527SDavid du Colombier }
1409a747e4fSDavid du Colombier switch(getreply(&ctlin, msg, sizeof(msg), 1)){
1419a747e4fSDavid du Colombier case Success:
142d9306527SDavid du Colombier goto out;
1439a747e4fSDavid du Colombier case Incomplete:
1449a747e4fSDavid du Colombier break;
1459a747e4fSDavid du Colombier case TempFail:
1469a747e4fSDavid du Colombier case PermFail:
1479a747e4fSDavid du Colombier continue;
1489a747e4fSDavid du Colombier }
1499a747e4fSDavid du Colombier
150d9306527SDavid du Colombier if(up != nil){
151d9306527SDavid du Colombier sendrequest("PASS", up->passwd);
152d9306527SDavid du Colombier } else {
1539a747e4fSDavid du Colombier if(getpassword(pass, pass+sizeof(pass)) < 0)
1549a747e4fSDavid du Colombier exits(0);
1559a747e4fSDavid du Colombier sendrequest("PASS", pass);
156d9306527SDavid du Colombier }
1579a747e4fSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 1) == Success){
1589a747e4fSDavid du Colombier if(strstr(msg, "Sess#"))
1599a747e4fSDavid du Colombier defos = MVS;
160d9306527SDavid du Colombier break;
1619a747e4fSDavid du Colombier }
1629a747e4fSDavid du Colombier }
163d9306527SDavid du Colombier out:
164d9306527SDavid du Colombier if(up != nil){
165d9306527SDavid du Colombier memset(up, 0, sizeof(*up));
166d9306527SDavid du Colombier free(up);
167d9306527SDavid du Colombier }
1689a747e4fSDavid du Colombier }
1699a747e4fSDavid du Colombier
1709a747e4fSDavid du Colombier /*
1719a747e4fSDavid du Colombier * login to remote system with given user name and password.
1729a747e4fSDavid du Colombier */
1739a747e4fSDavid du Colombier void
clogin(char * cuser,char * cpassword)1749a747e4fSDavid du Colombier clogin(char *cuser, char *cpassword)
1759a747e4fSDavid du Colombier {
1769a747e4fSDavid du Colombier free(user);
1779a747e4fSDavid du Colombier user = strdup(cuser);
1789a747e4fSDavid du Colombier if (strcmp(user, "anonymous") != 0 &&
1799a747e4fSDavid du Colombier strcmp(user, "ftp") != 0)
1809a747e4fSDavid du Colombier fatal("User must be 'anonymous' or 'ftp'");
1819a747e4fSDavid du Colombier sendrequest("USER", user);
1829a747e4fSDavid du Colombier switch(getreply(&ctlin, msg, sizeof(msg), 1)){
1839a747e4fSDavid du Colombier case Success:
1849a747e4fSDavid du Colombier return;
1859a747e4fSDavid du Colombier case Incomplete:
1869a747e4fSDavid du Colombier break;
1879a747e4fSDavid du Colombier case TempFail:
1889a747e4fSDavid du Colombier case PermFail:
1899a747e4fSDavid du Colombier fatal("login failed");
1909a747e4fSDavid du Colombier }
1919a747e4fSDavid du Colombier if (cpassword == 0)
1929a747e4fSDavid du Colombier fatal("password needed");
1939a747e4fSDavid du Colombier sendrequest("PASS", cpassword);
1949a747e4fSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)
1959a747e4fSDavid du Colombier fatal("password failed");
1969a747e4fSDavid du Colombier if(strstr(msg, "Sess#"))
1979a747e4fSDavid du Colombier defos = MVS;
1989a747e4fSDavid du Colombier return;
1999a747e4fSDavid du Colombier }
2009a747e4fSDavid du Colombier
2019a747e4fSDavid du Colombier /*
2029a747e4fSDavid du Colombier * find out about the other side. go to it's root if requested. set
2039a747e4fSDavid du Colombier * image mode if a Plan9 system.
2049a747e4fSDavid du Colombier */
2059a747e4fSDavid du Colombier void
preamble(char * mountroot)2069a747e4fSDavid du Colombier preamble(char *mountroot)
2079a747e4fSDavid du Colombier {
2089a747e4fSDavid du Colombier char *p, *ep;
2099a747e4fSDavid du Colombier int rv;
2109a747e4fSDavid du Colombier OS *o;
2119a747e4fSDavid du Colombier
2129a747e4fSDavid du Colombier /*
2139a747e4fSDavid du Colombier * create a root directory mirror
2149a747e4fSDavid du Colombier */
2159a747e4fSDavid du Colombier remroot = newnode(0, s_copy("/"));
2169a747e4fSDavid du Colombier remroot->d->qid.type = QTDIR;
2179a747e4fSDavid du Colombier remroot->d->mode = DMDIR|0777;
2189a747e4fSDavid du Colombier remdir = remroot;
2199a747e4fSDavid du Colombier
2209a747e4fSDavid du Colombier /*
2219a747e4fSDavid du Colombier * get system type
2229a747e4fSDavid du Colombier */
2239a747e4fSDavid du Colombier sendrequest("SYST", nil);
2249a747e4fSDavid du Colombier switch(getreply(&ctlin, msg, sizeof(msg), 1)){
2259a747e4fSDavid du Colombier case Success:
2269a747e4fSDavid du Colombier for(o = oslist; o->os != Unknown; o++)
2279a747e4fSDavid du Colombier if(strncmp(msg+4, o->name, strlen(o->name)) == 0)
2289a747e4fSDavid du Colombier break;
2299a747e4fSDavid du Colombier os = o->os;
2309a747e4fSDavid du Colombier if(os == NT)
2319a747e4fSDavid du Colombier os = Unix;
2329a747e4fSDavid du Colombier break;
2339a747e4fSDavid du Colombier default:
2349a747e4fSDavid du Colombier os = defos;
2359a747e4fSDavid du Colombier break;
2369a747e4fSDavid du Colombier }
2379a747e4fSDavid du Colombier if(os == Unknown)
2389a747e4fSDavid du Colombier os = defos;
2399a747e4fSDavid du Colombier
2409a747e4fSDavid du Colombier remrootpath = s_reset(remrootpath);
2419a747e4fSDavid du Colombier switch(os){
2426b6b9ac8SDavid du Colombier case NetWare:
2436b6b9ac8SDavid du Colombier /*
2446b6b9ac8SDavid du Colombier * Request long, rather than 8.3 filenames,
2456b6b9ac8SDavid du Colombier * where the Servers & Volume support them.
2466b6b9ac8SDavid du Colombier */
2476b6b9ac8SDavid du Colombier sendrequest("SITE LONG", nil);
2486b6b9ac8SDavid du Colombier getreply(&ctlin, msg, sizeof(msg), 0);
2496b6b9ac8SDavid du Colombier /* FALL THRU */
2509a747e4fSDavid du Colombier case Unix:
2519a747e4fSDavid du Colombier case Plan9:
2529a747e4fSDavid du Colombier /*
2539a747e4fSDavid du Colombier * go to the remote root, if asked
2549a747e4fSDavid du Colombier */
2559a747e4fSDavid du Colombier if(mountroot){
2569a747e4fSDavid du Colombier sendrequest("CWD", mountroot);
2579a747e4fSDavid du Colombier getreply(&ctlin, msg, sizeof(msg), 0);
2589a747e4fSDavid du Colombier } else {
2599a747e4fSDavid du Colombier s_append(remrootpath, "/usr/");
2609a747e4fSDavid du Colombier s_append(remrootpath, user);
2619a747e4fSDavid du Colombier }
2629a747e4fSDavid du Colombier
2639a747e4fSDavid du Colombier /*
2649a747e4fSDavid du Colombier * get the root directory
2659a747e4fSDavid du Colombier */
2669a747e4fSDavid du Colombier sendrequest("PWD", nil);
2679a747e4fSDavid du Colombier rv = getreply(&ctlin, msg, sizeof(msg), 1);
2689a747e4fSDavid du Colombier if(rv == PermFail){
2699a747e4fSDavid du Colombier sendrequest("XPWD", nil);
2709a747e4fSDavid du Colombier rv = getreply(&ctlin, msg, sizeof(msg), 1);
2719a747e4fSDavid du Colombier }
2729a747e4fSDavid du Colombier if(rv == Success){
2739a747e4fSDavid du Colombier p = strchr(msg, '"');
2749a747e4fSDavid du Colombier if(p){
2759a747e4fSDavid du Colombier p++;
2769a747e4fSDavid du Colombier ep = strchr(p, '"');
2779a747e4fSDavid du Colombier if(ep){
2789a747e4fSDavid du Colombier *ep = 0;
2799a747e4fSDavid du Colombier s_append(s_reset(remrootpath), p);
2809a747e4fSDavid du Colombier }
2819a747e4fSDavid du Colombier }
2829a747e4fSDavid du Colombier }
2839a747e4fSDavid du Colombier
2849a747e4fSDavid du Colombier break;
2859a747e4fSDavid du Colombier case Tops:
2869a747e4fSDavid du Colombier case VM:
2879a747e4fSDavid du Colombier /*
2889a747e4fSDavid du Colombier * top directory is a figment of our imagination.
2899a747e4fSDavid du Colombier * make it permanently cached & valid.
2909a747e4fSDavid du Colombier */
2919a747e4fSDavid du Colombier CACHED(remroot);
2929a747e4fSDavid du Colombier VALID(remroot);
2939a747e4fSDavid du Colombier remroot->d->atime = time(0) + 100000;
2949a747e4fSDavid du Colombier
2959a747e4fSDavid du Colombier /*
2969a747e4fSDavid du Colombier * no initial directory. We are in the
2979a747e4fSDavid du Colombier * imaginary root.
2989a747e4fSDavid du Colombier */
2999a747e4fSDavid du Colombier remdir = newtopsdir("???");
3009a747e4fSDavid du Colombier topsdir[0] = 0;
3019a747e4fSDavid du Colombier if(os == Tops && readdir(remdir) >= 0){
3029a747e4fSDavid du Colombier CACHED(remdir);
3039a747e4fSDavid du Colombier if(*topsdir)
3049a747e4fSDavid du Colombier remdir->remname = s_copy(topsdir);
3059a747e4fSDavid du Colombier VALID(remdir);
3069a747e4fSDavid du Colombier }
3079a747e4fSDavid du Colombier break;
3089a747e4fSDavid du Colombier case VMS:
3099a747e4fSDavid du Colombier /*
3109a747e4fSDavid du Colombier * top directory is a figment of our imagination.
3119a747e4fSDavid du Colombier * make it permanently cached & valid.
3129a747e4fSDavid du Colombier */
3139a747e4fSDavid du Colombier CACHED(remroot);
3149a747e4fSDavid du Colombier VALID(remroot);
3159a747e4fSDavid du Colombier remroot->d->atime = time(0) + 100000;
3169a747e4fSDavid du Colombier
3179a747e4fSDavid du Colombier /*
3189a747e4fSDavid du Colombier * get current directory
3199a747e4fSDavid du Colombier */
3209a747e4fSDavid du Colombier sendrequest("PWD", nil);
3219a747e4fSDavid du Colombier rv = getreply(&ctlin, msg, sizeof(msg), 1);
3229a747e4fSDavid du Colombier if(rv == PermFail){
3239a747e4fSDavid du Colombier sendrequest("XPWD", nil);
3249a747e4fSDavid du Colombier rv = getreply(&ctlin, msg, sizeof(msg), 1);
3259a747e4fSDavid du Colombier }
3269a747e4fSDavid du Colombier if(rv == Success){
3279a747e4fSDavid du Colombier p = strchr(msg, '"');
3289a747e4fSDavid du Colombier if(p){
3299a747e4fSDavid du Colombier p++;
3309a747e4fSDavid du Colombier ep = strchr(p, '"');
3319a747e4fSDavid du Colombier if(ep){
3329a747e4fSDavid du Colombier *ep = 0;
3339a747e4fSDavid du Colombier remroot = remdir = vmsdir(p);
3349a747e4fSDavid du Colombier }
3359a747e4fSDavid du Colombier }
3369a747e4fSDavid du Colombier }
3379a747e4fSDavid du Colombier break;
3389a747e4fSDavid du Colombier case MVS:
3399a747e4fSDavid du Colombier usenlst = 1;
3409a747e4fSDavid du Colombier break;
3419a747e4fSDavid du Colombier }
3429a747e4fSDavid du Colombier
3439a747e4fSDavid du Colombier if(os == Plan9)
3449a747e4fSDavid du Colombier image();
3459a747e4fSDavid du Colombier }
3469a747e4fSDavid du Colombier
3479a747e4fSDavid du Colombier static void
ascii(void)3489a747e4fSDavid du Colombier ascii(void)
3499a747e4fSDavid du Colombier {
3509a747e4fSDavid du Colombier sendrequest("TYPE A", nil);
3519a747e4fSDavid du Colombier switch(getreply(&ctlin, msg, sizeof(msg), 0)){
3529a747e4fSDavid du Colombier case Success:
3539a747e4fSDavid du Colombier break;
3549a747e4fSDavid du Colombier default:
3559a747e4fSDavid du Colombier fatal("can't set type to ascii");
3569a747e4fSDavid du Colombier }
3579a747e4fSDavid du Colombier }
3589a747e4fSDavid du Colombier
3599a747e4fSDavid du Colombier static void
image(void)3609a747e4fSDavid du Colombier image(void)
3619a747e4fSDavid du Colombier {
3629a747e4fSDavid du Colombier sendrequest("TYPE I", nil);
3639a747e4fSDavid du Colombier switch(getreply(&ctlin, msg, sizeof(msg), 0)){
3649a747e4fSDavid du Colombier case Success:
3659a747e4fSDavid du Colombier break;
3669a747e4fSDavid du Colombier default:
3679a747e4fSDavid du Colombier fatal("can't set type to image/binary");
3689a747e4fSDavid du Colombier }
3699a747e4fSDavid du Colombier }
3709a747e4fSDavid du Colombier
3719a747e4fSDavid du Colombier /*
3729a747e4fSDavid du Colombier * decode the time fields, return seconds since epoch began
3739a747e4fSDavid du Colombier */
3749a747e4fSDavid du Colombier char *monthchars = "janfebmaraprmayjunjulaugsepoctnovdec";
3759a747e4fSDavid du Colombier static Tm now;
3769a747e4fSDavid du Colombier
3779a747e4fSDavid du Colombier static ulong
cracktime(char * month,char * day,char * yr,char * hms)3789a747e4fSDavid du Colombier cracktime(char *month, char *day, char *yr, char *hms)
3799a747e4fSDavid du Colombier {
3809a747e4fSDavid du Colombier Tm tm;
3819a747e4fSDavid du Colombier int i;
3829a747e4fSDavid du Colombier char *p;
3839a747e4fSDavid du Colombier
3846b6b9ac8SDavid du Colombier
3859a747e4fSDavid du Colombier /* default time */
3869a747e4fSDavid du Colombier if(now.year == 0)
3879a747e4fSDavid du Colombier now = *localtime(time(0));
3889a747e4fSDavid du Colombier tm = now;
3896b6b9ac8SDavid du Colombier tm.yday = 0;
3909a747e4fSDavid du Colombier
3919a747e4fSDavid du Colombier /* convert ascii month to a number twixt 1 and 12 */
3929a747e4fSDavid du Colombier if(*month >= '0' && *month <= '9'){
3939a747e4fSDavid du Colombier tm.mon = atoi(month) - 1;
3949a747e4fSDavid du Colombier if(tm.mon < 0 || tm.mon > 11)
3959a747e4fSDavid du Colombier tm.mon = 5;
3969a747e4fSDavid du Colombier } else {
3979a747e4fSDavid du Colombier for(p = month; *p; p++)
3989a747e4fSDavid du Colombier *p = tolower(*p);
3999a747e4fSDavid du Colombier for(i = 0; i < 12; i++)
4009a747e4fSDavid du Colombier if(strncmp(&monthchars[i*3], month, 3) == 0){
4019a747e4fSDavid du Colombier tm.mon = i;
4029a747e4fSDavid du Colombier break;
4039a747e4fSDavid du Colombier }
4049a747e4fSDavid du Colombier }
4059a747e4fSDavid du Colombier
4069a747e4fSDavid du Colombier tm.mday = atoi(day);
4079a747e4fSDavid du Colombier
4089a747e4fSDavid du Colombier if(hms){
4099a747e4fSDavid du Colombier tm.hour = strtol(hms, &p, 0);
4109a747e4fSDavid du Colombier if(*p == ':'){
4119a747e4fSDavid du Colombier tm.min = strtol(p+1, &p, 0);
4129a747e4fSDavid du Colombier if(*p == ':')
4139a747e4fSDavid du Colombier tm.sec = strtol(p+1, &p, 0);
4149a747e4fSDavid du Colombier }
4159a747e4fSDavid du Colombier if(tolower(*p) == 'p')
4169a747e4fSDavid du Colombier tm.hour += 12;
4179a747e4fSDavid du Colombier }
4189a747e4fSDavid du Colombier
4199a747e4fSDavid du Colombier if(yr){
4209a747e4fSDavid du Colombier tm.year = atoi(yr);
4219a747e4fSDavid du Colombier if(tm.year >= 1900)
4229a747e4fSDavid du Colombier tm.year -= 1900;
4239a747e4fSDavid du Colombier } else {
4249a747e4fSDavid du Colombier if(tm.mon > now.mon || (tm.mon == now.mon && tm.mday > now.mday+1))
4259a747e4fSDavid du Colombier tm.year--;
4269a747e4fSDavid du Colombier }
4279a747e4fSDavid du Colombier
4289a747e4fSDavid du Colombier /* convert to epoch seconds */
4299a747e4fSDavid du Colombier return tm2sec(&tm);
4309a747e4fSDavid du Colombier }
4319a747e4fSDavid du Colombier
4329a747e4fSDavid du Colombier /*
4339a747e4fSDavid du Colombier * decode a Unix or Plan 9 file mode
4349a747e4fSDavid du Colombier */
4359a747e4fSDavid du Colombier static ulong
crackmode(char * p)4369a747e4fSDavid du Colombier crackmode(char *p)
4379a747e4fSDavid du Colombier {
4389a747e4fSDavid du Colombier ulong flags;
4399a747e4fSDavid du Colombier ulong mode;
4409a747e4fSDavid du Colombier int i;
4419a747e4fSDavid du Colombier
4429a747e4fSDavid du Colombier flags = 0;
4439a747e4fSDavid du Colombier switch(strlen(p)){
4449a747e4fSDavid du Colombier case 10: /* unix and new style plan 9 */
4459a747e4fSDavid du Colombier switch(*p){
4469a747e4fSDavid du Colombier case 'l':
4479a747e4fSDavid du Colombier return DMSYML|0777;
4489a747e4fSDavid du Colombier case 'd':
4499a747e4fSDavid du Colombier flags |= DMDIR;
4509a747e4fSDavid du Colombier case 'a':
4519a747e4fSDavid du Colombier flags |= DMAPPEND;
4529a747e4fSDavid du Colombier }
4539a747e4fSDavid du Colombier p++;
4549a747e4fSDavid du Colombier if(p[2] == 'l')
4559a747e4fSDavid du Colombier flags |= DMEXCL;
4569a747e4fSDavid du Colombier break;
4579a747e4fSDavid du Colombier case 11: /* old style plan 9 */
4589a747e4fSDavid du Colombier switch(*p++){
4599a747e4fSDavid du Colombier case 'd':
4609a747e4fSDavid du Colombier flags |= DMDIR;
4619a747e4fSDavid du Colombier break;
4629a747e4fSDavid du Colombier case 'a':
4639a747e4fSDavid du Colombier flags |= DMAPPEND;
4649a747e4fSDavid du Colombier break;
4659a747e4fSDavid du Colombier }
4669a747e4fSDavid du Colombier if(*p++ == 'l')
4679a747e4fSDavid du Colombier flags |= DMEXCL;
4689a747e4fSDavid du Colombier break;
4699a747e4fSDavid du Colombier default:
4709a747e4fSDavid du Colombier return DMDIR|0777;
4719a747e4fSDavid du Colombier }
4729a747e4fSDavid du Colombier mode = 0;
4739a747e4fSDavid du Colombier for(i = 0; i < 3; i++){
4749a747e4fSDavid du Colombier mode <<= 3;
4759a747e4fSDavid du Colombier if(*p++ == 'r')
4769a747e4fSDavid du Colombier mode |= DMREAD;
4779a747e4fSDavid du Colombier if(*p++ == 'w')
4789a747e4fSDavid du Colombier mode |= DMWRITE;
4799a747e4fSDavid du Colombier if(*p == 'x' || *p == 's' || *p == 'S')
4809a747e4fSDavid du Colombier mode |= DMEXEC;
4819a747e4fSDavid du Colombier p++;
4829a747e4fSDavid du Colombier }
4839a747e4fSDavid du Colombier return mode | flags;
4849a747e4fSDavid du Colombier }
4859a747e4fSDavid du Colombier
4869a747e4fSDavid du Colombier /*
4879a747e4fSDavid du Colombier * find first punctuation
4889a747e4fSDavid du Colombier */
4899a747e4fSDavid du Colombier char*
strpunct(char * p)4909a747e4fSDavid du Colombier strpunct(char *p)
4919a747e4fSDavid du Colombier {
4929a747e4fSDavid du Colombier int c;
4939a747e4fSDavid du Colombier
4949a747e4fSDavid du Colombier for(;c = *p; p++){
4959a747e4fSDavid du Colombier if(ispunct(c))
4969a747e4fSDavid du Colombier return p;
4979a747e4fSDavid du Colombier }
4989a747e4fSDavid du Colombier return 0;
4999a747e4fSDavid du Colombier }
5009a747e4fSDavid du Colombier
5019a747e4fSDavid du Colombier /*
5029a747e4fSDavid du Colombier * decode a Unix or Plan 9 directory listing
5039a747e4fSDavid du Colombier */
5049a747e4fSDavid du Colombier static Dir*
crackdir(char * p,String ** remname)5059a747e4fSDavid du Colombier crackdir(char *p, String **remname)
5069a747e4fSDavid du Colombier {
5079a747e4fSDavid du Colombier char *field[15];
5089a747e4fSDavid du Colombier char *dfield[4];
5099a747e4fSDavid du Colombier char *cp;
5109a747e4fSDavid du Colombier String *s;
5119a747e4fSDavid du Colombier int dn, n;
5129a747e4fSDavid du Colombier Dir d, *dp;
5139a747e4fSDavid du Colombier
5149a747e4fSDavid du Colombier memset(&d, 0, sizeof(d));
5159a747e4fSDavid du Colombier
5169a747e4fSDavid du Colombier n = getfields(p, field, 15, 1, " \t");
5179a747e4fSDavid du Colombier if(n > 2 && strcmp(field[n-2], "->") == 0)
5189a747e4fSDavid du Colombier n -= 2;
5199a747e4fSDavid du Colombier switch(os){
5209a747e4fSDavid du Colombier case TSO:
5219a747e4fSDavid du Colombier cp = strchr(field[0], '.');
5229a747e4fSDavid du Colombier if(cp){
5239a747e4fSDavid du Colombier *cp++ = 0;
5249a747e4fSDavid du Colombier s = s_copy(cp);
5259a747e4fSDavid du Colombier d.uid = field[0];
5269a747e4fSDavid du Colombier } else {
5279a747e4fSDavid du Colombier s = s_copy(field[0]);
5289a747e4fSDavid du Colombier d.uid = "TSO";
5299a747e4fSDavid du Colombier }
5309a747e4fSDavid du Colombier d.gid = "TSO";
5319a747e4fSDavid du Colombier d.mode = 0666;
5329a747e4fSDavid du Colombier d.length = 0;
5339a747e4fSDavid du Colombier d.atime = 0;
5349a747e4fSDavid du Colombier break;
5359a747e4fSDavid du Colombier case OS½:
5369a747e4fSDavid du Colombier s = s_copy(field[n-1]);
5379a747e4fSDavid du Colombier d.uid = "OS½";
5389a747e4fSDavid du Colombier d.gid = d.uid;
5399a747e4fSDavid du Colombier d.mode = 0666;
5409a747e4fSDavid du Colombier switch(n){
5419a747e4fSDavid du Colombier case 5:
5429a747e4fSDavid du Colombier if(strcmp(field[1], "DIR") == 0)
5439a747e4fSDavid du Colombier d.mode |= DMDIR;
544*63eaa10dSDavid du Colombier d.length = atoll(field[0]);
5459a747e4fSDavid du Colombier dn = getfields(field[2], dfield, 4, 1, "-");
5469a747e4fSDavid du Colombier if(dn == 3)
5479a747e4fSDavid du Colombier d.atime = cracktime(dfield[0], dfield[1], dfield[2], field[3]);
5489a747e4fSDavid du Colombier break;
5499a747e4fSDavid du Colombier }
5509a747e4fSDavid du Colombier break;
5519a747e4fSDavid du Colombier case Tops:
5529a747e4fSDavid du Colombier if(n != 4){ /* tops directory name */
5539a747e4fSDavid du Colombier safecpy(topsdir, field[0], sizeof(topsdir));
5549a747e4fSDavid du Colombier return 0;
5559a747e4fSDavid du Colombier }
5569a747e4fSDavid du Colombier s = s_copy(field[3]);
557*63eaa10dSDavid du Colombier d.length = atoll(field[0]);
5589a747e4fSDavid du Colombier d.mode = 0666;
5599a747e4fSDavid du Colombier d.uid = "Tops";
5609a747e4fSDavid du Colombier d.gid = d.uid;
5619a747e4fSDavid du Colombier dn = getfields(field[1], dfield, 4, 1, "-");
5629a747e4fSDavid du Colombier if(dn == 3)
5639a747e4fSDavid du Colombier d.atime = cracktime(dfield[1], dfield[0], dfield[2], field[2]);
5649a747e4fSDavid du Colombier else
5659a747e4fSDavid du Colombier d.atime = time(0);
5669a747e4fSDavid du Colombier break;
5679a747e4fSDavid du Colombier case VM:
5689a747e4fSDavid du Colombier switch(n){
5699a747e4fSDavid du Colombier case 9:
5709a747e4fSDavid du Colombier s = s_copy(field[0]);
5719a747e4fSDavid du Colombier s_append(s, ".");
5729a747e4fSDavid du Colombier s_append(s, field[1]);
573*63eaa10dSDavid du Colombier d.length = atoll(field[3]) * atoll(field[4]);
5749a747e4fSDavid du Colombier if(*field[2] == 'F')
5759a747e4fSDavid du Colombier d.mode = 0666;
5769a747e4fSDavid du Colombier else
5779a747e4fSDavid du Colombier d.mode = 0777;
5789a747e4fSDavid du Colombier d.uid = "VM";
5799a747e4fSDavid du Colombier d.gid = d.uid;
5809a747e4fSDavid du Colombier dn = getfields(field[6], dfield, 4, 1, "/-");
5819a747e4fSDavid du Colombier if(dn == 3)
5829a747e4fSDavid du Colombier d.atime = cracktime(dfield[0], dfield[1], dfield[2], field[7]);
5839a747e4fSDavid du Colombier else
5849a747e4fSDavid du Colombier d.atime = time(0);
5859a747e4fSDavid du Colombier break;
5869a747e4fSDavid du Colombier case 1:
5879a747e4fSDavid du Colombier s = s_copy(field[0]);
5889a747e4fSDavid du Colombier d.uid = "VM";
5899a747e4fSDavid du Colombier d.gid = d.uid;
5909a747e4fSDavid du Colombier d.mode = 0777;
5919a747e4fSDavid du Colombier d.atime = 0;
5929a747e4fSDavid du Colombier break;
5939a747e4fSDavid du Colombier default:
5949a747e4fSDavid du Colombier return nil;
5959a747e4fSDavid du Colombier }
5969a747e4fSDavid du Colombier break;
5979a747e4fSDavid du Colombier case VMS:
5989a747e4fSDavid du Colombier switch(n){
5999a747e4fSDavid du Colombier case 6:
6009a747e4fSDavid du Colombier for(cp = field[0]; *cp; cp++)
6019a747e4fSDavid du Colombier *cp = tolower(*cp);
6029a747e4fSDavid du Colombier cp = strchr(field[0], ';');
6039a747e4fSDavid du Colombier if(cp)
6049a747e4fSDavid du Colombier *cp = 0;
6059a747e4fSDavid du Colombier d.mode = 0666;
6069a747e4fSDavid du Colombier cp = field[0] + strlen(field[0]) - 4;
6079a747e4fSDavid du Colombier if(strcmp(cp, ".dir") == 0){
6089a747e4fSDavid du Colombier d.mode |= DMDIR;
6099a747e4fSDavid du Colombier *cp = 0;
6109a747e4fSDavid du Colombier }
6119a747e4fSDavid du Colombier s = s_copy(field[0]);
612*63eaa10dSDavid du Colombier d.length = atoll(field[1]) * 512;
6139a747e4fSDavid du Colombier field[4][strlen(field[4])-1] = 0;
6149a747e4fSDavid du Colombier d.uid = field[4]+1;
6159a747e4fSDavid du Colombier d.gid = d.uid;
6169a747e4fSDavid du Colombier dn = getfields(field[2], dfield, 4, 1, "/-");
6179a747e4fSDavid du Colombier if(dn == 3)
6189a747e4fSDavid du Colombier d.atime = cracktime(dfield[1], dfield[0], dfield[2], field[3]);
6199a747e4fSDavid du Colombier else
6209a747e4fSDavid du Colombier d.atime = time(0);
6219a747e4fSDavid du Colombier break;
6229a747e4fSDavid du Colombier default:
6239a747e4fSDavid du Colombier return nil;
6249a747e4fSDavid du Colombier }
6259a747e4fSDavid du Colombier break;
6269a747e4fSDavid du Colombier case NetWare:
6279a747e4fSDavid du Colombier switch(n){
628ecc2a59cSDavid du Colombier case 8: /* New style */
629ecc2a59cSDavid du Colombier s = s_copy(field[7]);
630ecc2a59cSDavid du Colombier d.uid = field[2];
631ecc2a59cSDavid du Colombier d.gid = d.uid;
632ecc2a59cSDavid du Colombier d.mode = nw_mode(field[0][0], field[1]);
633*63eaa10dSDavid du Colombier d.length = atoll(field[3]);
634ecc2a59cSDavid du Colombier if(strchr(field[6], ':'))
635ecc2a59cSDavid du Colombier d.atime = cracktime(field[4], field[5], nil, field[6]);
636ecc2a59cSDavid du Colombier else
637ecc2a59cSDavid du Colombier d.atime = cracktime(field[4], field[5], field[6], nil);
638ecc2a59cSDavid du Colombier break;
6399a747e4fSDavid du Colombier case 9:
6409a747e4fSDavid du Colombier s = s_copy(field[8]);
6419a747e4fSDavid du Colombier d.uid = field[2];
6429a747e4fSDavid du Colombier d.gid = d.uid;
6439a747e4fSDavid du Colombier d.mode = 0666;
6449a747e4fSDavid du Colombier if(*field[0] == 'd')
6459a747e4fSDavid du Colombier d.mode |= DMDIR;
646*63eaa10dSDavid du Colombier d.length = atoll(field[3]);
6479a747e4fSDavid du Colombier d.atime = cracktime(field[4], field[5], field[6], field[7]);
6489a747e4fSDavid du Colombier break;
6499a747e4fSDavid du Colombier case 1:
6509a747e4fSDavid du Colombier s = s_copy(field[0]);
6519a747e4fSDavid du Colombier d.uid = "none";
6529a747e4fSDavid du Colombier d.gid = d.uid;
6539a747e4fSDavid du Colombier d.mode = 0777;
6549a747e4fSDavid du Colombier d.atime = 0;
6559a747e4fSDavid du Colombier break;
6569a747e4fSDavid du Colombier default:
6579a747e4fSDavid du Colombier return nil;
6589a747e4fSDavid du Colombier }
6599a747e4fSDavid du Colombier break;
6609a747e4fSDavid du Colombier case Unix:
6619a747e4fSDavid du Colombier case Plan9:
6629a747e4fSDavid du Colombier default:
6639a747e4fSDavid du Colombier switch(n){
6649a747e4fSDavid du Colombier case 8: /* ls -l */
6659a747e4fSDavid du Colombier s = s_copy(field[7]);
6669a747e4fSDavid du Colombier d.uid = field[2];
6679a747e4fSDavid du Colombier d.gid = d.uid;
6689a747e4fSDavid du Colombier d.mode = crackmode(field[0]);
669*63eaa10dSDavid du Colombier d.length = atoll(field[3]);
6709a747e4fSDavid du Colombier if(strchr(field[6], ':'))
6719a747e4fSDavid du Colombier d.atime = cracktime(field[4], field[5], 0, field[6]);
6729a747e4fSDavid du Colombier else
6739a747e4fSDavid du Colombier d.atime = cracktime(field[4], field[5], field[6], 0);
6749a747e4fSDavid du Colombier break;
6759a747e4fSDavid du Colombier case 9: /* ls -lg */
6769a747e4fSDavid du Colombier s = s_copy(field[8]);
6779a747e4fSDavid du Colombier d.uid = field[2];
6789a747e4fSDavid du Colombier d.gid = field[3];
6799a747e4fSDavid du Colombier d.mode = crackmode(field[0]);
680*63eaa10dSDavid du Colombier d.length = atoll(field[4]);
6819a747e4fSDavid du Colombier if(strchr(field[7], ':'))
6829a747e4fSDavid du Colombier d.atime = cracktime(field[5], field[6], 0, field[7]);
6839a747e4fSDavid du Colombier else
6849a747e4fSDavid du Colombier d.atime = cracktime(field[5], field[6], field[7], 0);
6859a747e4fSDavid du Colombier break;
6869a747e4fSDavid du Colombier case 10: /* plan 9 */
6879a747e4fSDavid du Colombier s = s_copy(field[9]);
6889a747e4fSDavid du Colombier d.uid = field[3];
6899a747e4fSDavid du Colombier d.gid = field[4];
6909a747e4fSDavid du Colombier d.mode = crackmode(field[0]);
691*63eaa10dSDavid du Colombier d.length = atoll(field[5]);
6929a747e4fSDavid du Colombier if(strchr(field[8], ':'))
6939a747e4fSDavid du Colombier d.atime = cracktime(field[6], field[7], 0, field[8]);
6949a747e4fSDavid du Colombier else
6959a747e4fSDavid du Colombier d.atime = cracktime(field[6], field[7], field[8], 0);
6969a747e4fSDavid du Colombier break;
6979a747e4fSDavid du Colombier case 4: /* a Windows_NT version */
6989a747e4fSDavid du Colombier s = s_copy(field[3]);
6999a747e4fSDavid du Colombier d.uid = "NT";
7009a747e4fSDavid du Colombier d.gid = d.uid;
7019a747e4fSDavid du Colombier if(strcmp("<DIR>", field[2]) == 0){
7029a747e4fSDavid du Colombier d.length = 0;
7039a747e4fSDavid du Colombier d.mode = DMDIR|0777;
7049a747e4fSDavid du Colombier } else {
7059a747e4fSDavid du Colombier d.mode = 0666;
706*63eaa10dSDavid du Colombier d.length = atoll(field[2]);
7079a747e4fSDavid du Colombier }
7089a747e4fSDavid du Colombier dn = getfields(field[0], dfield, 4, 1, "/-");
7099a747e4fSDavid du Colombier if(dn == 3)
7109a747e4fSDavid du Colombier d.atime = cracktime(dfield[0], dfield[1], dfield[2], field[1]);
7119a747e4fSDavid du Colombier break;
7129a747e4fSDavid du Colombier case 1:
7139a747e4fSDavid du Colombier s = s_copy(field[0]);
7149a747e4fSDavid du Colombier d.uid = "none";
7159a747e4fSDavid du Colombier d.gid = d.uid;
7169a747e4fSDavid du Colombier d.mode = 0777;
7179a747e4fSDavid du Colombier d.atime = 0;
7189a747e4fSDavid du Colombier break;
7199a747e4fSDavid du Colombier default:
7209a747e4fSDavid du Colombier return nil;
7219a747e4fSDavid du Colombier }
7229a747e4fSDavid du Colombier }
7239a747e4fSDavid du Colombier d.muid = d.uid;
7249a747e4fSDavid du Colombier d.qid.type = (d.mode & DMDIR) ? QTDIR : QTFILE;
7259a747e4fSDavid du Colombier d.mtime = d.atime;
7269a747e4fSDavid du Colombier if(ext && (d.qid.type & QTDIR) == 0)
7279a747e4fSDavid du Colombier s_append(s, ext);
7289a747e4fSDavid du Colombier d.name = s_to_c(s);
7299a747e4fSDavid du Colombier
7309a747e4fSDavid du Colombier /* allocate a freeable dir structure */
7319a747e4fSDavid du Colombier dp = reallocdir(&d, 0);
7329a747e4fSDavid du Colombier *remname = s;
7339a747e4fSDavid du Colombier
7349a747e4fSDavid du Colombier return dp;
7359a747e4fSDavid du Colombier }
7369a747e4fSDavid du Colombier
7379a747e4fSDavid du Colombier /*
7389a747e4fSDavid du Colombier * probe files in a directory to see if they are directories
7399a747e4fSDavid du Colombier */
7409a747e4fSDavid du Colombier /*
7419a747e4fSDavid du Colombier * read a remote directory
7429a747e4fSDavid du Colombier */
7439a747e4fSDavid du Colombier int
readdir(Node * node)7449a747e4fSDavid du Colombier readdir(Node *node)
7459a747e4fSDavid du Colombier {
7469a747e4fSDavid du Colombier Biobuf *bp;
7479a747e4fSDavid du Colombier char *line;
7489a747e4fSDavid du Colombier Node *np;
7499a747e4fSDavid du Colombier Dir *d;
7509a747e4fSDavid du Colombier long n;
7519a747e4fSDavid du Colombier int tries, x, files;
7529a747e4fSDavid du Colombier static int uselist;
7539a747e4fSDavid du Colombier int usenlist;
7549a747e4fSDavid du Colombier String *remname;
7559a747e4fSDavid du Colombier
7569a747e4fSDavid du Colombier if(changedir(node) < 0)
7579a747e4fSDavid du Colombier return -1;
7589a747e4fSDavid du Colombier
7599a747e4fSDavid du Colombier usenlist = 0;
7609a747e4fSDavid du Colombier for(tries = 0; tries < 3; tries++){
7619a747e4fSDavid du Colombier if(usenlist || usenlst)
7629a747e4fSDavid du Colombier x = data(OREAD, &bp, "NLST", nil);
7639a747e4fSDavid du Colombier else if(os == Unix && !uselist)
7649a747e4fSDavid du Colombier x = data(OREAD, &bp, "LIST -l", nil);
7659a747e4fSDavid du Colombier else
7669a747e4fSDavid du Colombier x = data(OREAD, &bp, "LIST", nil);
7679a747e4fSDavid du Colombier switch(x){
7689a747e4fSDavid du Colombier case Extra:
7699a747e4fSDavid du Colombier break;
7709a747e4fSDavid du Colombier /* case TempFail:
7719a747e4fSDavid du Colombier continue;
7729a747e4fSDavid du Colombier */
7739a747e4fSDavid du Colombier default:
7749a747e4fSDavid du Colombier if(os == Unix && uselist == 0){
7759a747e4fSDavid du Colombier uselist = 1;
7769a747e4fSDavid du Colombier continue;
7779a747e4fSDavid du Colombier }
7789a747e4fSDavid du Colombier return seterr(nosuchfile);
7799a747e4fSDavid du Colombier }
7809a747e4fSDavid du Colombier files = 0;
7819a747e4fSDavid du Colombier while(line = Brdline(bp, '\n')){
7829a747e4fSDavid du Colombier n = Blinelen(bp);
7839a747e4fSDavid du Colombier if(debug)
7849a747e4fSDavid du Colombier write(2, line, n);
7859a747e4fSDavid du Colombier if(n > 1 && line[n-2] == '\r')
7869a747e4fSDavid du Colombier n--;
7879a747e4fSDavid du Colombier line[n - 1] = 0;
7889a747e4fSDavid du Colombier
7899a747e4fSDavid du Colombier d = crackdir(line, &remname);
7909a747e4fSDavid du Colombier if(d == nil)
7919a747e4fSDavid du Colombier continue;
7929a747e4fSDavid du Colombier files++;
7939a747e4fSDavid du Colombier np = extendpath(node, remname);
7949a747e4fSDavid du Colombier d->qid.path = np->d->qid.path;
7959a747e4fSDavid du Colombier d->qid.vers = np->d->qid.vers;
7969a747e4fSDavid du Colombier d->type = np->d->type;
7979a747e4fSDavid du Colombier d->dev = 1; /* mark node as valid */
7989a747e4fSDavid du Colombier if(os == MVS && node == remroot){
7999a747e4fSDavid du Colombier d->qid.type = QTDIR;
8009a747e4fSDavid du Colombier d->mode |= DMDIR;
8019a747e4fSDavid du Colombier }
8029a747e4fSDavid du Colombier free(np->d);
8039a747e4fSDavid du Colombier np->d = d;
8049a747e4fSDavid du Colombier }
8059a747e4fSDavid du Colombier close(Bfildes(bp));
8069a747e4fSDavid du Colombier
8079a747e4fSDavid du Colombier switch(getreply(&ctlin, msg, sizeof(msg), 0)){
8089a747e4fSDavid du Colombier case Success:
8099a747e4fSDavid du Colombier if(files == 0 && !usenlst && !usenlist){
8109a747e4fSDavid du Colombier usenlist = 1;
8119a747e4fSDavid du Colombier continue;
8129a747e4fSDavid du Colombier }
8139a747e4fSDavid du Colombier if(files && usenlist)
8149a747e4fSDavid du Colombier usenlst = 1;
8159a747e4fSDavid du Colombier if(usenlst)
8169a747e4fSDavid du Colombier node->chdirunknown = 1;
8179a747e4fSDavid du Colombier return 0;
8189a747e4fSDavid du Colombier case TempFail:
8199a747e4fSDavid du Colombier break;
8209a747e4fSDavid du Colombier default:
8219a747e4fSDavid du Colombier return seterr(nosuchfile);
8229a747e4fSDavid du Colombier }
8239a747e4fSDavid du Colombier }
8249a747e4fSDavid du Colombier return seterr(nosuchfile);
8259a747e4fSDavid du Colombier }
8269a747e4fSDavid du Colombier
8279a747e4fSDavid du Colombier /*
8289a747e4fSDavid du Colombier * create a remote directory
8299a747e4fSDavid du Colombier */
8309a747e4fSDavid du Colombier int
createdir(Node * node)8319a747e4fSDavid du Colombier createdir(Node *node)
8329a747e4fSDavid du Colombier {
8339a747e4fSDavid du Colombier if(changedir(node->parent) < 0)
8349a747e4fSDavid du Colombier return -1;
8359a747e4fSDavid du Colombier
8369a747e4fSDavid du Colombier sendrequest("MKD", node->d->name);
8379a747e4fSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
8389a747e4fSDavid du Colombier return -1;
8399a747e4fSDavid du Colombier return 0;
8409a747e4fSDavid du Colombier }
8419a747e4fSDavid du Colombier
8429a747e4fSDavid du Colombier /*
8439a747e4fSDavid du Colombier * change to a remote directory.
8449a747e4fSDavid du Colombier */
8459a747e4fSDavid du Colombier int
changedir(Node * node)8469a747e4fSDavid du Colombier changedir(Node *node)
8479a747e4fSDavid du Colombier {
8489a747e4fSDavid du Colombier Node *to;
8499a747e4fSDavid du Colombier String *cdpath;
8509a747e4fSDavid du Colombier
8519a747e4fSDavid du Colombier to = node;
8529a747e4fSDavid du Colombier if(to == remdir)
8539a747e4fSDavid du Colombier return 0;
8549a747e4fSDavid du Colombier
8559a747e4fSDavid du Colombier /* build an absolute path */
8569a747e4fSDavid du Colombier switch(os){
8579a747e4fSDavid du Colombier case Tops:
8589a747e4fSDavid du Colombier case VM:
8599a747e4fSDavid du Colombier switch(node->depth){
8609a747e4fSDavid du Colombier case 0:
8619a747e4fSDavid du Colombier remdir = node;
8629a747e4fSDavid du Colombier return 0;
8639a747e4fSDavid du Colombier case 1:
8649a747e4fSDavid du Colombier cdpath = s_clone(node->remname);
8659a747e4fSDavid du Colombier break;
8669a747e4fSDavid du Colombier default:
8679a747e4fSDavid du Colombier return seterr(nosuchfile);
8689a747e4fSDavid du Colombier }
8699a747e4fSDavid du Colombier break;
8709a747e4fSDavid du Colombier case VMS:
8719a747e4fSDavid du Colombier switch(node->depth){
8729a747e4fSDavid du Colombier case 0:
8739a747e4fSDavid du Colombier remdir = node;
8749a747e4fSDavid du Colombier return 0;
8759a747e4fSDavid du Colombier default:
8769a747e4fSDavid du Colombier cdpath = s_new();
8779a747e4fSDavid du Colombier vmspath(node, cdpath);
8789a747e4fSDavid du Colombier }
8799a747e4fSDavid du Colombier break;
8809a747e4fSDavid du Colombier case MVS:
8819a747e4fSDavid du Colombier if(node->depth == 0)
8829a747e4fSDavid du Colombier cdpath = s_clone(remrootpath);
8839a747e4fSDavid du Colombier else{
8849a747e4fSDavid du Colombier cdpath = s_new();
8859a747e4fSDavid du Colombier mvspath(node, cdpath);
8869a747e4fSDavid du Colombier }
8879a747e4fSDavid du Colombier break;
8889a747e4fSDavid du Colombier default:
8899a747e4fSDavid du Colombier if(node->depth == 0)
8909a747e4fSDavid du Colombier cdpath = s_clone(remrootpath);
8919a747e4fSDavid du Colombier else{
8929a747e4fSDavid du Colombier cdpath = s_new();
8939a747e4fSDavid du Colombier unixpath(node, cdpath);
8949a747e4fSDavid du Colombier }
8959a747e4fSDavid du Colombier break;
8969a747e4fSDavid du Colombier }
8979a747e4fSDavid du Colombier
8989a747e4fSDavid du Colombier uncachedir(remdir, 0);
8999a747e4fSDavid du Colombier
9009a747e4fSDavid du Colombier /*
9019a747e4fSDavid du Colombier * connect, if we need a password (Incomplete)
9029a747e4fSDavid du Colombier * act like it worked (best we can do).
9039a747e4fSDavid du Colombier */
9049a747e4fSDavid du Colombier sendrequest("CWD", s_to_c(cdpath));
9059a747e4fSDavid du Colombier s_free(cdpath);
9069a747e4fSDavid du Colombier switch(getreply(&ctlin, msg, sizeof(msg), 0)){
9079a747e4fSDavid du Colombier case Success:
9089a747e4fSDavid du Colombier case Incomplete:
9099a747e4fSDavid du Colombier remdir = node;
9109a747e4fSDavid du Colombier return 0;
9119a747e4fSDavid du Colombier default:
9129a747e4fSDavid du Colombier return seterr(nosuchfile);
9139a747e4fSDavid du Colombier }
9149a747e4fSDavid du Colombier }
9159a747e4fSDavid du Colombier
9169a747e4fSDavid du Colombier /*
9179a747e4fSDavid du Colombier * read a remote file
9189a747e4fSDavid du Colombier */
9199a747e4fSDavid du Colombier int
readfile1(Node * node)9209a747e4fSDavid du Colombier readfile1(Node *node)
9219a747e4fSDavid du Colombier {
9229a747e4fSDavid du Colombier Biobuf *bp;
9239a747e4fSDavid du Colombier char buf[4*1024];
9249a747e4fSDavid du Colombier long off;
9259a747e4fSDavid du Colombier int n;
9269a747e4fSDavid du Colombier int tries;
9279a747e4fSDavid du Colombier
9289a747e4fSDavid du Colombier if(changedir(node->parent) < 0)
9299a747e4fSDavid du Colombier return -1;
9309a747e4fSDavid du Colombier
9319a747e4fSDavid du Colombier for(tries = 0; tries < 4; tries++){
9329a747e4fSDavid du Colombier switch(data(OREAD, &bp, "RETR", s_to_c(node->remname))){
9339a747e4fSDavid du Colombier case Extra:
9349a747e4fSDavid du Colombier break;
9359a747e4fSDavid du Colombier case TempFail:
9369a747e4fSDavid du Colombier continue;
9379a747e4fSDavid du Colombier default:
9389a747e4fSDavid du Colombier return seterr(nosuchfile);
9399a747e4fSDavid du Colombier }
9409a747e4fSDavid du Colombier off = 0;
9419a747e4fSDavid du Colombier while((n = read(Bfildes(bp), buf, sizeof buf)) > 0){
9429a747e4fSDavid du Colombier if(filewrite(node, buf, off, n) != n){
9439a747e4fSDavid du Colombier off = -1;
9449a747e4fSDavid du Colombier break;
9459a747e4fSDavid du Colombier }
9469a747e4fSDavid du Colombier off += n;
9479a747e4fSDavid du Colombier }
9489a747e4fSDavid du Colombier if(off < 0)
9499a747e4fSDavid du Colombier return -1;
9509a747e4fSDavid du Colombier
9519a747e4fSDavid du Colombier /* make sure a file gets created even for a zero length file */
9529a747e4fSDavid du Colombier if(off == 0)
9539a747e4fSDavid du Colombier filewrite(node, buf, 0, 0);
9549a747e4fSDavid du Colombier
9559a747e4fSDavid du Colombier close(Bfildes(bp));
9569a747e4fSDavid du Colombier switch(getreply(&ctlin, msg, sizeof(msg), 0)){
9579a747e4fSDavid du Colombier case Success:
9589a747e4fSDavid du Colombier return off;
9599a747e4fSDavid du Colombier case TempFail:
9609a747e4fSDavid du Colombier continue;
9619a747e4fSDavid du Colombier default:
9629a747e4fSDavid du Colombier return seterr(nosuchfile);
9639a747e4fSDavid du Colombier }
9649a747e4fSDavid du Colombier }
9659a747e4fSDavid du Colombier return seterr(nosuchfile);
9669a747e4fSDavid du Colombier }
9679a747e4fSDavid du Colombier
9689a747e4fSDavid du Colombier int
readfile(Node * node)9699a747e4fSDavid du Colombier readfile(Node *node)
9709a747e4fSDavid du Colombier {
9719a747e4fSDavid du Colombier int rv, inimage;
9729a747e4fSDavid du Colombier
9739a747e4fSDavid du Colombier switch(os){
9749a747e4fSDavid du Colombier case MVS:
9759a747e4fSDavid du Colombier case Plan9:
9769a747e4fSDavid du Colombier case Tops:
9779a747e4fSDavid du Colombier case TSO:
9789a747e4fSDavid du Colombier inimage = 0;
9799a747e4fSDavid du Colombier break;
9809a747e4fSDavid du Colombier default:
9819a747e4fSDavid du Colombier inimage = 1;
9829a747e4fSDavid du Colombier image();
9839a747e4fSDavid du Colombier break;
9849a747e4fSDavid du Colombier }
9859a747e4fSDavid du Colombier
9869a747e4fSDavid du Colombier rv = readfile1(node);
9879a747e4fSDavid du Colombier
9889a747e4fSDavid du Colombier if(inimage)
9899a747e4fSDavid du Colombier ascii();
9909a747e4fSDavid du Colombier return rv;
9919a747e4fSDavid du Colombier }
9929a747e4fSDavid du Colombier
9939a747e4fSDavid du Colombier /*
9949a747e4fSDavid du Colombier * write back a file
9959a747e4fSDavid du Colombier */
9969a747e4fSDavid du Colombier int
createfile1(Node * node)9979a747e4fSDavid du Colombier createfile1(Node *node)
9989a747e4fSDavid du Colombier {
9999a747e4fSDavid du Colombier Biobuf *bp;
10009a747e4fSDavid du Colombier char buf[4*1024];
10019a747e4fSDavid du Colombier long off;
10029a747e4fSDavid du Colombier int n;
10039a747e4fSDavid du Colombier
10049a747e4fSDavid du Colombier if(changedir(node->parent) < 0)
10059a747e4fSDavid du Colombier return -1;
10069a747e4fSDavid du Colombier
10079a747e4fSDavid du Colombier if(data(OWRITE, &bp, "STOR", s_to_c(node->remname)) != Extra)
10089a747e4fSDavid du Colombier return -1;
10099a747e4fSDavid du Colombier for(off = 0; ; off += n){
10109a747e4fSDavid du Colombier n = fileread(node, buf, off, sizeof(buf));
10119a747e4fSDavid du Colombier if(n <= 0)
10129a747e4fSDavid du Colombier break;
10139a747e4fSDavid du Colombier write(Bfildes(bp), buf, n);
10149a747e4fSDavid du Colombier }
10159a747e4fSDavid du Colombier close(Bfildes(bp));
101605a04ac5SDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
101705a04ac5SDavid du Colombier return -1;
10189a747e4fSDavid du Colombier return off;
10199a747e4fSDavid du Colombier }
10209a747e4fSDavid du Colombier
10219a747e4fSDavid du Colombier int
createfile(Node * node)10229a747e4fSDavid du Colombier createfile(Node *node)
10239a747e4fSDavid du Colombier {
10249a747e4fSDavid du Colombier int rv;
10259a747e4fSDavid du Colombier
10269a747e4fSDavid du Colombier switch(os){
10279a747e4fSDavid du Colombier case Plan9:
10289a747e4fSDavid du Colombier case Tops:
10299a747e4fSDavid du Colombier break;
10309a747e4fSDavid du Colombier default:
10319a747e4fSDavid du Colombier image();
10329a747e4fSDavid du Colombier break;
10339a747e4fSDavid du Colombier }
10349a747e4fSDavid du Colombier rv = createfile1(node);
10359a747e4fSDavid du Colombier switch(os){
10369a747e4fSDavid du Colombier case Plan9:
10379a747e4fSDavid du Colombier case Tops:
10389a747e4fSDavid du Colombier break;
10399a747e4fSDavid du Colombier default:
10409a747e4fSDavid du Colombier ascii();
10419a747e4fSDavid du Colombier break;
10429a747e4fSDavid du Colombier }
10439a747e4fSDavid du Colombier return rv;
10449a747e4fSDavid du Colombier }
10459a747e4fSDavid du Colombier
10469a747e4fSDavid du Colombier /*
10479a747e4fSDavid du Colombier * remove a remote file
10489a747e4fSDavid du Colombier */
10499a747e4fSDavid du Colombier int
removefile(Node * node)10509a747e4fSDavid du Colombier removefile(Node *node)
10519a747e4fSDavid du Colombier {
10529a747e4fSDavid du Colombier if(changedir(node->parent) < 0)
10539a747e4fSDavid du Colombier return -1;
10549a747e4fSDavid du Colombier
10559a747e4fSDavid du Colombier sendrequest("DELE", s_to_c(node->remname));
10569a747e4fSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
10579a747e4fSDavid du Colombier return -1;
10589a747e4fSDavid du Colombier return 0;
10599a747e4fSDavid du Colombier }
10609a747e4fSDavid du Colombier
10619a747e4fSDavid du Colombier /*
10629a747e4fSDavid du Colombier * remove a remote directory
10639a747e4fSDavid du Colombier */
10649a747e4fSDavid du Colombier int
removedir(Node * node)10659a747e4fSDavid du Colombier removedir(Node *node)
10669a747e4fSDavid du Colombier {
10679a747e4fSDavid du Colombier if(changedir(node->parent) < 0)
10689a747e4fSDavid du Colombier return -1;
10699a747e4fSDavid du Colombier
10709a747e4fSDavid du Colombier sendrequest("RMD", s_to_c(node->remname));
10719a747e4fSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
10729a747e4fSDavid du Colombier return -1;
10739a747e4fSDavid du Colombier return 0;
10749a747e4fSDavid du Colombier }
10759a747e4fSDavid du Colombier
10769a747e4fSDavid du Colombier /*
10779a747e4fSDavid du Colombier * tell remote that we're exiting and then do it
10789a747e4fSDavid du Colombier */
10799a747e4fSDavid du Colombier void
quit(void)10809a747e4fSDavid du Colombier quit(void)
10819a747e4fSDavid du Colombier {
10829a747e4fSDavid du Colombier sendrequest("QUIT", nil);
10839a747e4fSDavid du Colombier getreply(&ctlin, msg, sizeof(msg), 0);
10849a747e4fSDavid du Colombier exits(0);
10859a747e4fSDavid du Colombier }
10869a747e4fSDavid du Colombier
10879a747e4fSDavid du Colombier /*
10889a747e4fSDavid du Colombier * send a request
10899a747e4fSDavid du Colombier */
10909a747e4fSDavid du Colombier static void
sendrequest(char * a,char * b)10919a747e4fSDavid du Colombier sendrequest(char *a, char *b)
10929a747e4fSDavid du Colombier {
10939a747e4fSDavid du Colombier char buf[2*1024];
10949a747e4fSDavid du Colombier int n;
10959a747e4fSDavid du Colombier
10969a747e4fSDavid du Colombier n = strlen(a)+2+1;
10979a747e4fSDavid du Colombier if(b != nil)
10989a747e4fSDavid du Colombier n += strlen(b)+1;
10999a747e4fSDavid du Colombier if(n >= sizeof(buf))
11009a747e4fSDavid du Colombier fatal("proto request too long");
11019a747e4fSDavid du Colombier strcpy(buf, a);
11029a747e4fSDavid du Colombier if(b != nil){
11039a747e4fSDavid du Colombier strcat(buf, " ");
11049a747e4fSDavid du Colombier strcat(buf, b);
11059a747e4fSDavid du Colombier }
11069a747e4fSDavid du Colombier strcat(buf, "\r\n");
11079a747e4fSDavid du Colombier n = strlen(buf);
11089a747e4fSDavid du Colombier if(write(ctlfd, buf, n) != n)
11099a747e4fSDavid du Colombier fatal("remote side hung up");
11109a747e4fSDavid du Colombier if(debug)
11119a747e4fSDavid du Colombier write(2, buf, n);
11129a747e4fSDavid du Colombier lastsend = time(0);
11139a747e4fSDavid du Colombier }
11149a747e4fSDavid du Colombier
11159a747e4fSDavid du Colombier /*
11169a747e4fSDavid du Colombier * replies codes are in the range [100, 999] and may contain multiple lines of
11179a747e4fSDavid du Colombier * continuation.
11189a747e4fSDavid du Colombier */
11199a747e4fSDavid du Colombier static int
getreply(Biobuf * bp,char * msg,int len,int printreply)11209a747e4fSDavid du Colombier getreply(Biobuf *bp, char *msg, int len, int printreply)
11219a747e4fSDavid du Colombier {
11229a747e4fSDavid du Colombier char *line;
1123d9306527SDavid du Colombier char *p;
11249a747e4fSDavid du Colombier int rv;
11259a747e4fSDavid du Colombier int i, n;
11269a747e4fSDavid du Colombier
11279a747e4fSDavid du Colombier while(line = Brdline(bp, '\n')){
11289a747e4fSDavid du Colombier /* add line to message buffer, strip off \r */
11299a747e4fSDavid du Colombier n = Blinelen(bp);
11309a747e4fSDavid du Colombier if(n > 1 && line[n-2] == '\r'){
11319a747e4fSDavid du Colombier n--;
11329a747e4fSDavid du Colombier line[n-1] = '\n';
11339a747e4fSDavid du Colombier }
11349a747e4fSDavid du Colombier if(printreply && !quiet)
11359a747e4fSDavid du Colombier write(1, line, n);
11369a747e4fSDavid du Colombier else if(debug)
11379a747e4fSDavid du Colombier write(2, line, n);
11389a747e4fSDavid du Colombier if(n > len - 1)
11399a747e4fSDavid du Colombier i = len - 1;
11409a747e4fSDavid du Colombier else
11419a747e4fSDavid du Colombier i = n;
11429a747e4fSDavid du Colombier if(i > 0){
11439a747e4fSDavid du Colombier memmove(msg, line, i);
11449a747e4fSDavid du Colombier msg += i;
11459a747e4fSDavid du Colombier len -= i;
11469a747e4fSDavid du Colombier *msg = 0;
11479a747e4fSDavid du Colombier }
11489a747e4fSDavid du Colombier
11499a747e4fSDavid du Colombier /* stop if not a continuation */
1150d9306527SDavid du Colombier rv = strtol(line, &p, 10);
1151d9306527SDavid du Colombier if(rv >= 100 && rv < 600 && p==line+3 && *p != '-')
11529a747e4fSDavid du Colombier return rv/100;
11539a747e4fSDavid du Colombier
11549a747e4fSDavid du Colombier /* tell user about continuations */
11559a747e4fSDavid du Colombier if(!debug && !quiet && !printreply)
11569a747e4fSDavid du Colombier write(2, line, n);
11579a747e4fSDavid du Colombier }
11589a747e4fSDavid du Colombier
11599a747e4fSDavid du Colombier fatal("remote side closed connection");
11609a747e4fSDavid du Colombier return 0;
11619a747e4fSDavid du Colombier }
11629a747e4fSDavid du Colombier
11639a747e4fSDavid du Colombier /*
11649a747e4fSDavid du Colombier * Announce on a local port and tell its address to the the remote side
11659a747e4fSDavid du Colombier */
11669a747e4fSDavid du Colombier static int
port(void)11679a747e4fSDavid du Colombier port(void)
11689a747e4fSDavid du Colombier {
11699a747e4fSDavid du Colombier char buf[256];
11709a747e4fSDavid du Colombier int n, fd;
11719a747e4fSDavid du Colombier char *ptr;
11729a747e4fSDavid du Colombier uchar ipaddr[IPaddrlen];
11739a747e4fSDavid du Colombier int port;
11749a747e4fSDavid du Colombier
11759a747e4fSDavid du Colombier /* get a channel to listen on, let kernel pick the port number */
11769a747e4fSDavid du Colombier sprint(buf, "%s!*!0", net);
11779a747e4fSDavid du Colombier listenfd = announce(buf, netdir);
11789a747e4fSDavid du Colombier if(listenfd < 0)
11799a747e4fSDavid du Colombier return seterr("can't announce");
11809a747e4fSDavid du Colombier
11819a747e4fSDavid du Colombier /* get the local address and port number */
11829a747e4fSDavid du Colombier sprint(buf, "%s/local", netdir);
11839a747e4fSDavid du Colombier fd = open(buf, OREAD);
11849a747e4fSDavid du Colombier if(fd < 0)
11859a747e4fSDavid du Colombier return seterr("opening %s: %r", buf);
11869a747e4fSDavid du Colombier n = read(fd, buf, sizeof(buf)-1);
11879a747e4fSDavid du Colombier close(fd);
11889a747e4fSDavid du Colombier if(n <= 0)
11899a747e4fSDavid du Colombier return seterr("opening %s/local: %r", netdir);
11909a747e4fSDavid du Colombier buf[n] = 0;
11919a747e4fSDavid du Colombier ptr = strchr(buf, ' ');
11929a747e4fSDavid du Colombier if(ptr)
11939a747e4fSDavid du Colombier *ptr = 0;
11949a747e4fSDavid du Colombier ptr = strchr(buf, '!')+1;
11959a747e4fSDavid du Colombier port = atoi(ptr);
11969a747e4fSDavid du Colombier
11976d0d1481SDavid du Colombier memset(ipaddr, 0, IPaddrlen);
11986d0d1481SDavid du Colombier if (*net){
11996d0d1481SDavid du Colombier strcpy(buf, net);
12006d0d1481SDavid du Colombier ptr = strchr(buf +1, '/');
12016d0d1481SDavid du Colombier if (ptr)
12026d0d1481SDavid du Colombier *ptr = 0;
12036d0d1481SDavid du Colombier myipaddr(ipaddr, buf);
12046d0d1481SDavid du Colombier }
12056d0d1481SDavid du Colombier
12069a747e4fSDavid du Colombier /* tell remote side */
12079a747e4fSDavid du Colombier sprint(buf, "PORT %d,%d,%d,%d,%d,%d", ipaddr[IPv4off+0], ipaddr[IPv4off+1],
12089a747e4fSDavid du Colombier ipaddr[IPv4off+2], ipaddr[IPv4off+3], port>>8, port&0xff);
12099a747e4fSDavid du Colombier sendrequest(buf, nil);
12109a747e4fSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)
12119a747e4fSDavid du Colombier return seterr(msg);
12129a747e4fSDavid du Colombier return 0;
12139a747e4fSDavid du Colombier }
12149a747e4fSDavid du Colombier
12159a747e4fSDavid du Colombier /*
12169a747e4fSDavid du Colombier * have server call back for a data connection
12179a747e4fSDavid du Colombier */
12189a747e4fSDavid du Colombier static int
active(int mode,Biobuf ** bpp,char * cmda,char * cmdb)12199a747e4fSDavid du Colombier active(int mode, Biobuf **bpp, char *cmda, char *cmdb)
12209a747e4fSDavid du Colombier {
12219a747e4fSDavid du Colombier int cfd, dfd, rv;
12229a747e4fSDavid du Colombier char newdir[Maxpath];
12239a747e4fSDavid du Colombier char datafile[Maxpath + 6];
12241269a55eSDavid du Colombier TLSconn conn;
12259a747e4fSDavid du Colombier
12269a747e4fSDavid du Colombier if(port() < 0)
12279a747e4fSDavid du Colombier return TempFail;
12289a747e4fSDavid du Colombier
12299a747e4fSDavid du Colombier sendrequest(cmda, cmdb);
12309a747e4fSDavid du Colombier
12319a747e4fSDavid du Colombier rv = getreply(&ctlin, msg, sizeof(msg), 0);
12329a747e4fSDavid du Colombier if(rv != Extra){
12339a747e4fSDavid du Colombier close(listenfd);
12349a747e4fSDavid du Colombier return rv;
12359a747e4fSDavid du Colombier }
12369a747e4fSDavid du Colombier
12379a747e4fSDavid du Colombier /* wait for a new call */
12389a747e4fSDavid du Colombier cfd = listen(netdir, newdir);
12399a747e4fSDavid du Colombier if(cfd < 0)
12409a747e4fSDavid du Colombier fatal("waiting for data connection");
12419a747e4fSDavid du Colombier close(listenfd);
12429a747e4fSDavid du Colombier
12439a747e4fSDavid du Colombier /* open it's data connection and close the control connection */
12449a747e4fSDavid du Colombier sprint(datafile, "%s/data", newdir);
12459a747e4fSDavid du Colombier dfd = open(datafile, ORDWR);
12469a747e4fSDavid du Colombier close(cfd);
12479a747e4fSDavid du Colombier if(dfd < 0)
12489a747e4fSDavid du Colombier fatal("opening data connection");
12491269a55eSDavid du Colombier
12501269a55eSDavid du Colombier if(usetls){
12511269a55eSDavid du Colombier memset(&conn, 0, sizeof(conn));
12521269a55eSDavid du Colombier dfd = tlsClient(dfd, &conn);
12531269a55eSDavid du Colombier if(dfd < 0)
12541269a55eSDavid du Colombier fatal("starting tls: %r");
12551269a55eSDavid du Colombier free(conn.cert);
12561269a55eSDavid du Colombier }
12571269a55eSDavid du Colombier
12589a747e4fSDavid du Colombier Binit(&dbuf, dfd, mode);
12599a747e4fSDavid du Colombier *bpp = &dbuf;
12609a747e4fSDavid du Colombier return Extra;
12619a747e4fSDavid du Colombier }
12629a747e4fSDavid du Colombier
12639a747e4fSDavid du Colombier /*
12649a747e4fSDavid du Colombier * call out for a data connection
12659a747e4fSDavid du Colombier */
12669a747e4fSDavid du Colombier static int
passive(int mode,Biobuf ** bpp,char * cmda,char * cmdb)12679a747e4fSDavid du Colombier passive(int mode, Biobuf **bpp, char *cmda, char *cmdb)
12689a747e4fSDavid du Colombier {
12699a747e4fSDavid du Colombier char msg[1024];
12709a747e4fSDavid du Colombier char ds[1024];
12719a747e4fSDavid du Colombier char *f[6];
12729a747e4fSDavid du Colombier char *p;
12739a747e4fSDavid du Colombier int x, fd;
12741269a55eSDavid du Colombier TLSconn conn;
12759a747e4fSDavid du Colombier
12769a747e4fSDavid du Colombier if(nopassive)
12779a747e4fSDavid du Colombier return Impossible;
12789a747e4fSDavid du Colombier
12799a747e4fSDavid du Colombier sendrequest("PASV", nil);
12809a747e4fSDavid du Colombier if(getreply(&ctlin, msg, sizeof(msg), 0) != Success){
12819a747e4fSDavid du Colombier nopassive = 1;
12829a747e4fSDavid du Colombier return Impossible;
12839a747e4fSDavid du Colombier }
12849a747e4fSDavid du Colombier
12859a747e4fSDavid du Colombier /* get address and port number from reply, this is AI */
12869a747e4fSDavid du Colombier p = strchr(msg, '(');
12879a747e4fSDavid du Colombier if(p == 0){
12889a747e4fSDavid du Colombier for(p = msg+3; *p; p++)
12899a747e4fSDavid du Colombier if(isdigit(*p))
12909a747e4fSDavid du Colombier break;
12919a747e4fSDavid du Colombier } else
12929a747e4fSDavid du Colombier p++;
12939a747e4fSDavid du Colombier if(getfields(p, f, 6, 0, ",") < 6){
12949a747e4fSDavid du Colombier if(debug)
12959a747e4fSDavid du Colombier fprint(2, "passive mode protocol botch: %s\n", msg);
12969a747e4fSDavid du Colombier werrstr("ftp protocol botch");
12979a747e4fSDavid du Colombier nopassive = 1;
12989a747e4fSDavid du Colombier return Impossible;
12999a747e4fSDavid du Colombier }
13009a747e4fSDavid du Colombier snprint(ds, sizeof(ds), "%s!%s.%s.%s.%s!%d", net,
13019a747e4fSDavid du Colombier f[0], f[1], f[2], f[3],
13029a747e4fSDavid du Colombier ((atoi(f[4])&0xff)<<8) + (atoi(f[5])&0xff));
13039a747e4fSDavid du Colombier
13049a747e4fSDavid du Colombier /* open data connection */
13059a747e4fSDavid du Colombier fd = dial(ds, 0, 0, 0);
13069a747e4fSDavid du Colombier if(fd < 0){
13079a747e4fSDavid du Colombier if(debug)
13089a747e4fSDavid du Colombier fprint(2, "passive mode connect to %s failed: %r\n", ds);
13099a747e4fSDavid du Colombier nopassive = 1;
13109a747e4fSDavid du Colombier return TempFail;
13119a747e4fSDavid du Colombier }
13129a747e4fSDavid du Colombier
13139a747e4fSDavid du Colombier /* tell remote to send a file */
13149a747e4fSDavid du Colombier sendrequest(cmda, cmdb);
13159a747e4fSDavid du Colombier x = getreply(&ctlin, msg, sizeof(msg), 0);
13169a747e4fSDavid du Colombier if(x != Extra){
13179a747e4fSDavid du Colombier close(fd);
13189a747e4fSDavid du Colombier if(debug)
13199a747e4fSDavid du Colombier fprint(2, "passive mode retrieve failed: %s\n", msg);
13209a747e4fSDavid du Colombier werrstr(msg);
13219a747e4fSDavid du Colombier return x;
13229a747e4fSDavid du Colombier }
13239a747e4fSDavid du Colombier
13241269a55eSDavid du Colombier if(usetls){
13251269a55eSDavid du Colombier memset(&conn, 0, sizeof(conn));
13261269a55eSDavid du Colombier fd = tlsClient(fd, &conn);
13271269a55eSDavid du Colombier if(fd < 0)
13281269a55eSDavid du Colombier fatal("starting tls: %r");
13291269a55eSDavid du Colombier free(conn.cert);
13301269a55eSDavid du Colombier }
13319a747e4fSDavid du Colombier Binit(&dbuf, fd, mode);
13321269a55eSDavid du Colombier
13339a747e4fSDavid du Colombier *bpp = &dbuf;
13349a747e4fSDavid du Colombier return Extra;
13359a747e4fSDavid du Colombier }
13369a747e4fSDavid du Colombier
13379a747e4fSDavid du Colombier static int
data(int mode,Biobuf ** bpp,char * cmda,char * cmdb)13389a747e4fSDavid du Colombier data(int mode, Biobuf **bpp, char* cmda, char *cmdb)
13399a747e4fSDavid du Colombier {
13409a747e4fSDavid du Colombier int x;
13419a747e4fSDavid du Colombier
13429a747e4fSDavid du Colombier x = passive(mode, bpp, cmda, cmdb);
13439a747e4fSDavid du Colombier if(x != Impossible)
13449a747e4fSDavid du Colombier return x;
13459a747e4fSDavid du Colombier return active(mode, bpp, cmda, cmdb);
13469a747e4fSDavid du Colombier }
13479a747e4fSDavid du Colombier
13489a747e4fSDavid du Colombier /*
13499a747e4fSDavid du Colombier * used for keep alives
13509a747e4fSDavid du Colombier */
13519a747e4fSDavid du Colombier void
nop(void)13529a747e4fSDavid du Colombier nop(void)
13539a747e4fSDavid du Colombier {
13549a747e4fSDavid du Colombier if(lastsend - time(0) < 15)
13559a747e4fSDavid du Colombier return;
13569a747e4fSDavid du Colombier sendrequest("PWD", nil);
13579a747e4fSDavid du Colombier getreply(&ctlin, msg, sizeof(msg), 0);
13589a747e4fSDavid du Colombier }
13599a747e4fSDavid du Colombier
13609a747e4fSDavid du Colombier /*
13619a747e4fSDavid du Colombier * turn a vms spec into a path
13629a747e4fSDavid du Colombier */
13639a747e4fSDavid du Colombier static Node*
vmsextendpath(Node * np,char * name)13649a747e4fSDavid du Colombier vmsextendpath(Node *np, char *name)
13659a747e4fSDavid du Colombier {
13669a747e4fSDavid du Colombier np = extendpath(np, s_copy(name));
13679a747e4fSDavid du Colombier if(!ISVALID(np)){
13689a747e4fSDavid du Colombier np->d->qid.type = QTDIR;
13699a747e4fSDavid du Colombier np->d->atime = time(0);
13709a747e4fSDavid du Colombier np->d->mtime = np->d->atime;
13719a747e4fSDavid du Colombier strcpy(np->d->uid, "who");
13729a747e4fSDavid du Colombier strcpy(np->d->gid, "cares");
13739a747e4fSDavid du Colombier np->d->mode = DMDIR|0777;
13749a747e4fSDavid du Colombier np->d->length = 0;
13759a747e4fSDavid du Colombier if(changedir(np) >= 0)
13769a747e4fSDavid du Colombier VALID(np);
13779a747e4fSDavid du Colombier }
13789a747e4fSDavid du Colombier return np;
13799a747e4fSDavid du Colombier }
13809a747e4fSDavid du Colombier static Node*
vmsdir(char * name)13819a747e4fSDavid du Colombier vmsdir(char *name)
13829a747e4fSDavid du Colombier {
13839a747e4fSDavid du Colombier char *cp;
13849a747e4fSDavid du Colombier Node *np;
13859a747e4fSDavid du Colombier char *oname;
13869a747e4fSDavid du Colombier
13879a747e4fSDavid du Colombier np = remroot;
13889a747e4fSDavid du Colombier cp = strchr(name, '[');
13899a747e4fSDavid du Colombier if(cp)
13909a747e4fSDavid du Colombier strcpy(cp, cp+1);
13919a747e4fSDavid du Colombier cp = strchr(name, ']');
13929a747e4fSDavid du Colombier if(cp)
13939a747e4fSDavid du Colombier *cp = 0;
13949a747e4fSDavid du Colombier oname = name = strdup(name);
13959a747e4fSDavid du Colombier if(name == 0)
13969a747e4fSDavid du Colombier return 0;
13979a747e4fSDavid du Colombier
13989a747e4fSDavid du Colombier while(cp = strchr(name, '.')){
13999a747e4fSDavid du Colombier *cp = 0;
14009a747e4fSDavid du Colombier np = vmsextendpath(np, name);
14019a747e4fSDavid du Colombier name = cp+1;
14029a747e4fSDavid du Colombier }
14039a747e4fSDavid du Colombier np = vmsextendpath(np, name);
14049a747e4fSDavid du Colombier
14059a747e4fSDavid du Colombier /*
14069a747e4fSDavid du Colombier * walk back to first accessible directory
14079a747e4fSDavid du Colombier */
14089a747e4fSDavid du Colombier for(; np->parent != np; np = np->parent)
14099a747e4fSDavid du Colombier if(ISVALID(np)){
14109a747e4fSDavid du Colombier CACHED(np->parent);
14119a747e4fSDavid du Colombier break;
14129a747e4fSDavid du Colombier }
14139a747e4fSDavid du Colombier
14149a747e4fSDavid du Colombier free(oname);
14159a747e4fSDavid du Colombier return np;
14169a747e4fSDavid du Colombier }
14179a747e4fSDavid du Colombier
14189a747e4fSDavid du Colombier /*
14199a747e4fSDavid du Colombier * walk up the tree building a VMS style path
14209a747e4fSDavid du Colombier */
14219a747e4fSDavid du Colombier static void
vmspath(Node * node,String * path)14229a747e4fSDavid du Colombier vmspath(Node *node, String *path)
14239a747e4fSDavid du Colombier {
14249a747e4fSDavid du Colombier char *p;
14259a747e4fSDavid du Colombier int n;
14269a747e4fSDavid du Colombier
14279a747e4fSDavid du Colombier if(node->depth == 1){
14289a747e4fSDavid du Colombier p = strchr(s_to_c(node->remname), ':');
14299a747e4fSDavid du Colombier if(p){
14309a747e4fSDavid du Colombier n = p - s_to_c(node->remname) + 1;
14319a747e4fSDavid du Colombier s_nappend(path, s_to_c(node->remname), n);
14329a747e4fSDavid du Colombier s_append(path, "[");
14339a747e4fSDavid du Colombier s_append(path, p+1);
14349a747e4fSDavid du Colombier } else {
14359a747e4fSDavid du Colombier s_append(path, "[");
14369a747e4fSDavid du Colombier s_append(path, s_to_c(node->remname));
14379a747e4fSDavid du Colombier }
14389a747e4fSDavid du Colombier s_append(path, "]");
14399a747e4fSDavid du Colombier return;
14409a747e4fSDavid du Colombier }
14419a747e4fSDavid du Colombier vmspath(node->parent, path);
14429a747e4fSDavid du Colombier s_append(path, ".");
14439a747e4fSDavid du Colombier s_append(path, s_to_c(node->remname));
14449a747e4fSDavid du Colombier }
14459a747e4fSDavid du Colombier
14469a747e4fSDavid du Colombier /*
14479a747e4fSDavid du Colombier * walk up the tree building a Unix style path
14489a747e4fSDavid du Colombier */
14499a747e4fSDavid du Colombier static void
unixpath(Node * node,String * path)14509a747e4fSDavid du Colombier unixpath(Node *node, String *path)
14519a747e4fSDavid du Colombier {
14529a747e4fSDavid du Colombier if(node == node->parent){
14539a747e4fSDavid du Colombier s_append(path, s_to_c(remrootpath));
14549a747e4fSDavid du Colombier return;
14559a747e4fSDavid du Colombier }
14569a747e4fSDavid du Colombier unixpath(node->parent, path);
1457ecc2a59cSDavid du Colombier if(s_len(path) > 0 && strcmp(s_to_c(path), "/") != 0)
14589a747e4fSDavid du Colombier s_append(path, "/");
14599a747e4fSDavid du Colombier s_append(path, s_to_c(node->remname));
14609a747e4fSDavid du Colombier }
14619a747e4fSDavid du Colombier
14629a747e4fSDavid du Colombier /*
14639a747e4fSDavid du Colombier * walk up the tree building a MVS style path
14649a747e4fSDavid du Colombier */
14659a747e4fSDavid du Colombier static void
mvspath(Node * node,String * path)14669a747e4fSDavid du Colombier mvspath(Node *node, String *path)
14679a747e4fSDavid du Colombier {
14689a747e4fSDavid du Colombier if(node == node->parent){
14699a747e4fSDavid du Colombier s_append(path, s_to_c(remrootpath));
14709a747e4fSDavid du Colombier return;
14719a747e4fSDavid du Colombier }
14729a747e4fSDavid du Colombier mvspath(node->parent, path);
14739a747e4fSDavid du Colombier if(s_len(path) > 0)
14749a747e4fSDavid du Colombier s_append(path, ".");
14759a747e4fSDavid du Colombier s_append(path, s_to_c(node->remname));
14769a747e4fSDavid du Colombier }
14779a747e4fSDavid du Colombier
14789a747e4fSDavid du Colombier static int
getpassword(char * buf,char * e)14799a747e4fSDavid du Colombier getpassword(char *buf, char *e)
14809a747e4fSDavid du Colombier {
14819a747e4fSDavid du Colombier char *p;
14829a747e4fSDavid du Colombier int c;
14839a747e4fSDavid du Colombier int consctl, rv = 0;
14849a747e4fSDavid du Colombier
14859a747e4fSDavid du Colombier consctl = open("/dev/consctl", OWRITE);
14869a747e4fSDavid du Colombier if(consctl >= 0)
14879a747e4fSDavid du Colombier write(consctl, "rawon", 5);
14889a747e4fSDavid du Colombier print("Password: ");
14899a747e4fSDavid du Colombier e--;
14909a747e4fSDavid du Colombier for(p = buf; p <= e; p++){
14919a747e4fSDavid du Colombier c = Bgetc(&stdin);
14929a747e4fSDavid du Colombier if(c < 0){
14939a747e4fSDavid du Colombier rv = -1;
14949a747e4fSDavid du Colombier goto out;
14959a747e4fSDavid du Colombier }
14969a747e4fSDavid du Colombier if(c == '\n' || c == '\r')
14979a747e4fSDavid du Colombier break;
14989a747e4fSDavid du Colombier *p = c;
14999a747e4fSDavid du Colombier }
15009a747e4fSDavid du Colombier *p = 0;
15019a747e4fSDavid du Colombier print("\n");
15029a747e4fSDavid du Colombier
15039a747e4fSDavid du Colombier out:
15049a747e4fSDavid du Colombier if(consctl >= 0)
15059a747e4fSDavid du Colombier close(consctl);
15069a747e4fSDavid du Colombier return rv;
15079a747e4fSDavid du Colombier }
15089a747e4fSDavid du Colombier
15099a747e4fSDavid du Colombier /*
15109a747e4fSDavid du Colombier * convert from latin1 to utf
15119a747e4fSDavid du Colombier */
15129a747e4fSDavid du Colombier static char*
fromlatin1(char * from)15139a747e4fSDavid du Colombier fromlatin1(char *from)
15149a747e4fSDavid du Colombier {
15159a747e4fSDavid du Colombier char *p, *to;
15169a747e4fSDavid du Colombier Rune r;
15179a747e4fSDavid du Colombier
15189a747e4fSDavid du Colombier if(os == Plan9)
15199a747e4fSDavid du Colombier return nil;
15209a747e4fSDavid du Colombier
15219a747e4fSDavid du Colombier /* don't convert if we don't have to */
15229a747e4fSDavid du Colombier for(p = from; *p; p++)
15239a747e4fSDavid du Colombier if(*p & 0x80)
15249a747e4fSDavid du Colombier break;
15259a747e4fSDavid du Colombier if(*p == 0)
15269a747e4fSDavid du Colombier return nil;
15279a747e4fSDavid du Colombier
15289a747e4fSDavid du Colombier to = malloc(3*strlen(from)+2);
15299a747e4fSDavid du Colombier if(to == nil)
15309a747e4fSDavid du Colombier return nil;
15319a747e4fSDavid du Colombier for(p = to; *from; from++){
15329a747e4fSDavid du Colombier r = (*from) & 0xff;
15339a747e4fSDavid du Colombier p += runetochar(p, &r);
15349a747e4fSDavid du Colombier }
15359a747e4fSDavid du Colombier *p = 0;
15369a747e4fSDavid du Colombier return to;
15379a747e4fSDavid du Colombier }
15389a747e4fSDavid du Colombier
15399a747e4fSDavid du Colombier Dir*
reallocdir(Dir * d,int dofree)15409a747e4fSDavid du Colombier reallocdir(Dir *d, int dofree)
15419a747e4fSDavid du Colombier {
15429a747e4fSDavid du Colombier Dir *dp;
15439a747e4fSDavid du Colombier char *p;
15449a747e4fSDavid du Colombier int nn, ng, nu, nm;
15459a747e4fSDavid du Colombier char *utf;
15469a747e4fSDavid du Colombier
15479a747e4fSDavid du Colombier if(d->name == nil)
15489a747e4fSDavid du Colombier d->name = "?name?";
15499a747e4fSDavid du Colombier if(d->uid == nil)
15509a747e4fSDavid du Colombier d->uid = "?uid?";
15519a747e4fSDavid du Colombier if(d->gid == nil)
15529a747e4fSDavid du Colombier d->gid = d->uid;
15539a747e4fSDavid du Colombier if(d->muid == nil)
15549a747e4fSDavid du Colombier d->muid = d->uid;
15559a747e4fSDavid du Colombier
15569a747e4fSDavid du Colombier utf = fromlatin1(d->name);
15579a747e4fSDavid du Colombier if(utf != nil)
15589a747e4fSDavid du Colombier d->name = utf;
15599a747e4fSDavid du Colombier
15609a747e4fSDavid du Colombier nn = strlen(d->name)+1;
15619a747e4fSDavid du Colombier nu = strlen(d->uid)+1;
15629a747e4fSDavid du Colombier ng = strlen(d->gid)+1;
15639a747e4fSDavid du Colombier nm = strlen(d->muid)+1;
15649a747e4fSDavid du Colombier dp = malloc(sizeof(Dir)+nn+nu+ng+nm);
15659a747e4fSDavid du Colombier if(dp == nil){
15669a747e4fSDavid du Colombier if(dofree)
15679a747e4fSDavid du Colombier free(d);
15689a747e4fSDavid du Colombier if(utf != nil)
15699a747e4fSDavid du Colombier free(utf);
15709a747e4fSDavid du Colombier return nil;
15719a747e4fSDavid du Colombier }
15729a747e4fSDavid du Colombier *dp = *d;
15739a747e4fSDavid du Colombier p = (char*)&dp[1];
15749a747e4fSDavid du Colombier strcpy(p, d->name);
15759a747e4fSDavid du Colombier dp->name = p;
15769a747e4fSDavid du Colombier p += nn;
15779a747e4fSDavid du Colombier strcpy(p, d->uid);
15789a747e4fSDavid du Colombier dp->uid = p;
15799a747e4fSDavid du Colombier p += nu;
15809a747e4fSDavid du Colombier strcpy(p, d->gid);
15819a747e4fSDavid du Colombier dp->gid = p;
15829a747e4fSDavid du Colombier p += ng;
15839a747e4fSDavid du Colombier strcpy(p, d->muid);
15849a747e4fSDavid du Colombier dp->muid = p;
15859a747e4fSDavid du Colombier if(dofree)
15869a747e4fSDavid du Colombier free(d);
15879a747e4fSDavid du Colombier if(utf != nil)
15889a747e4fSDavid du Colombier free(utf);
15899a747e4fSDavid du Colombier return dp;
15909a747e4fSDavid du Colombier }
15919a747e4fSDavid du Colombier
15929a747e4fSDavid du Colombier Dir*
dir_change_name(Dir * d,char * name)15939a747e4fSDavid du Colombier dir_change_name(Dir *d, char *name)
15949a747e4fSDavid du Colombier {
15959a747e4fSDavid du Colombier if(d->name && strlen(d->name) >= strlen(name)){
15969a747e4fSDavid du Colombier strcpy(d->name, name);
15979a747e4fSDavid du Colombier return d;
15989a747e4fSDavid du Colombier }
15999a747e4fSDavid du Colombier d->name = name;
16009a747e4fSDavid du Colombier return reallocdir(d, 1);
16019a747e4fSDavid du Colombier }
16029a747e4fSDavid du Colombier
16039a747e4fSDavid du Colombier Dir*
dir_change_uid(Dir * d,char * name)16049a747e4fSDavid du Colombier dir_change_uid(Dir *d, char *name)
16059a747e4fSDavid du Colombier {
16069a747e4fSDavid du Colombier if(d->uid && strlen(d->uid) >= strlen(name)){
16079a747e4fSDavid du Colombier strcpy(d->name, name);
16089a747e4fSDavid du Colombier return d;
16099a747e4fSDavid du Colombier }
16109a747e4fSDavid du Colombier d->uid = name;
16119a747e4fSDavid du Colombier return reallocdir(d, 1);
16129a747e4fSDavid du Colombier }
16139a747e4fSDavid du Colombier
16149a747e4fSDavid du Colombier Dir*
dir_change_gid(Dir * d,char * name)16159a747e4fSDavid du Colombier dir_change_gid(Dir *d, char *name)
16169a747e4fSDavid du Colombier {
16179a747e4fSDavid du Colombier if(d->gid && strlen(d->gid) >= strlen(name)){
16189a747e4fSDavid du Colombier strcpy(d->name, name);
16199a747e4fSDavid du Colombier return d;
16209a747e4fSDavid du Colombier }
16219a747e4fSDavid du Colombier d->gid = name;
16229a747e4fSDavid du Colombier return reallocdir(d, 1);
16239a747e4fSDavid du Colombier }
16249a747e4fSDavid du Colombier
16259a747e4fSDavid du Colombier Dir*
dir_change_muid(Dir * d,char * name)16269a747e4fSDavid du Colombier dir_change_muid(Dir *d, char *name)
16279a747e4fSDavid du Colombier {
16289a747e4fSDavid du Colombier if(d->muid && strlen(d->muid) >= strlen(name)){
16299a747e4fSDavid du Colombier strcpy(d->name, name);
16309a747e4fSDavid du Colombier return d;
16319a747e4fSDavid du Colombier }
16329a747e4fSDavid du Colombier d->muid = name;
16339a747e4fSDavid du Colombier return reallocdir(d, 1);
16349a747e4fSDavid du Colombier }
1635ecc2a59cSDavid du Colombier
1636ecc2a59cSDavid du Colombier static int
nw_mode(char dirlet,char * s)1637ecc2a59cSDavid du Colombier nw_mode(char dirlet, char *s) /* NetWare file mode mapping */
1638ecc2a59cSDavid du Colombier {
1639ecc2a59cSDavid du Colombier int mode = 0777;
1640ecc2a59cSDavid du Colombier
1641ecc2a59cSDavid du Colombier if(dirlet == 'd')
1642ecc2a59cSDavid du Colombier mode |= DMDIR;
1643ecc2a59cSDavid du Colombier
1644ecc2a59cSDavid du Colombier if (strlen(s) >= 10 && s[0] != '[' || s[9] != ']')
1645ecc2a59cSDavid du Colombier return(mode);
1646ecc2a59cSDavid du Colombier
1647ecc2a59cSDavid du Colombier if (s[1] == '-') /* can't read file */
1648ecc2a59cSDavid du Colombier mode &= ~0444;
1649ecc2a59cSDavid du Colombier if (dirlet == 'd' && s[6] == '-') /* cannot scan dir */
1650ecc2a59cSDavid du Colombier mode &= ~0444;
1651ecc2a59cSDavid du Colombier if (s[2] == '-') /* can't write file */
1652ecc2a59cSDavid du Colombier mode &= ~0222;
1653ecc2a59cSDavid du Colombier if (dirlet == 'd' && s[7] == '-' && s[3] == '-') /* cannot create in, or modify dir */
1654ecc2a59cSDavid du Colombier mode &= ~0222;
1655ecc2a59cSDavid du Colombier
1656ecc2a59cSDavid du Colombier return(mode);
1657ecc2a59cSDavid du Colombier }
1658