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