proto.c
来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 1,658 行 · 第 1/2 页
C
1,658 行
intcreatedir(Node *node){ if(changedir(node->parent) < 0) return -1; sendrequest("MKD", node->d->name); if(getreply(&ctlin, msg, sizeof(msg), 0) != Success) return -1; return 0;}/* * change to a remote directory. */intchangedir(Node *node){ Node *to; String *cdpath; to = node; if(to == remdir) return 0; /* build an absolute path */ switch(os){ case Tops: case VM: switch(node->depth){ case 0: remdir = node; return 0; case 1: cdpath = s_clone(node->remname); break; default: return seterr(nosuchfile); } break; case VMS: switch(node->depth){ case 0: remdir = node; return 0; default: cdpath = s_new(); vmspath(node, cdpath); } break; case MVS: if(node->depth == 0) cdpath = s_clone(remrootpath); else{ cdpath = s_new(); mvspath(node, cdpath); } break; default: if(node->depth == 0) cdpath = s_clone(remrootpath); else{ cdpath = s_new(); unixpath(node, cdpath); } break; } uncachedir(remdir, 0); /* * connect, if we need a password (Incomplete) * act like it worked (best we can do). */ sendrequest("CWD", s_to_c(cdpath)); s_free(cdpath); switch(getreply(&ctlin, msg, sizeof(msg), 0)){ case Success: case Incomplete: remdir = node; return 0; default: return seterr(nosuchfile); }}/* * read a remote file */intreadfile1(Node *node){ Biobuf *bp; char buf[4*1024]; long off; int n; int tries; if(changedir(node->parent) < 0) return -1; for(tries = 0; tries < 4; tries++){ switch(data(OREAD, &bp, "RETR", s_to_c(node->remname))){ case Extra: break; case TempFail: continue; default: return seterr(nosuchfile); } off = 0; while((n = read(Bfildes(bp), buf, sizeof buf)) > 0){ if(filewrite(node, buf, off, n) != n){ off = -1; break; } off += n; } if(off < 0) return -1; /* make sure a file gets created even for a zero length file */ if(off == 0) filewrite(node, buf, 0, 0); close(Bfildes(bp)); switch(getreply(&ctlin, msg, sizeof(msg), 0)){ case Success: return off; case TempFail: continue; default: return seterr(nosuchfile); } } return seterr(nosuchfile);}intreadfile(Node *node){ int rv, inimage; switch(os){ case MVS: case Plan9: case Tops: case TSO: inimage = 0; break; default: inimage = 1; image(); break; } rv = readfile1(node); if(inimage) ascii(); return rv;}/* * write back a file */intcreatefile1(Node *node){ Biobuf *bp; char buf[4*1024]; long off; int n; if(changedir(node->parent) < 0) return -1; if(data(OWRITE, &bp, "STOR", s_to_c(node->remname)) != Extra) return -1; for(off = 0; ; off += n){ n = fileread(node, buf, off, sizeof(buf)); if(n <= 0) break; write(Bfildes(bp), buf, n); } close(Bfildes(bp)); if(getreply(&ctlin, msg, sizeof(msg), 0) != Success) return -1; return off;}intcreatefile(Node *node){ int rv; switch(os){ case Plan9: case Tops: break; default: image(); break; } rv = createfile1(node); switch(os){ case Plan9: case Tops: break; default: ascii(); break; } return rv;}/* * remove a remote file */intremovefile(Node *node){ if(changedir(node->parent) < 0) return -1; sendrequest("DELE", s_to_c(node->remname)); if(getreply(&ctlin, msg, sizeof(msg), 0) != Success) return -1; return 0;}/* * remove a remote directory */intremovedir(Node *node){ if(changedir(node->parent) < 0) return -1; sendrequest("RMD", s_to_c(node->remname)); if(getreply(&ctlin, msg, sizeof(msg), 0) != Success) return -1; return 0;}/* * tell remote that we're exiting and then do it */voidquit(void){ sendrequest("QUIT", nil); getreply(&ctlin, msg, sizeof(msg), 0); exits(0);}/* * send a request */static voidsendrequest(char *a, char *b){ char buf[2*1024]; int n; n = strlen(a)+2+1; if(b != nil) n += strlen(b)+1; if(n >= sizeof(buf)) fatal("proto request too long"); strcpy(buf, a); if(b != nil){ strcat(buf, " "); strcat(buf, b); } strcat(buf, "\r\n"); n = strlen(buf); if(write(ctlfd, buf, n) != n) fatal("remote side hung up"); if(debug) write(2, buf, n); lastsend = time(0);}/* * replies codes are in the range [100, 999] and may contain multiple lines of * continuation. */static intgetreply(Biobuf *bp, char *msg, int len, int printreply){ char *line; char *p; int rv; int i, n; while(line = Brdline(bp, '\n')){ /* add line to message buffer, strip off \r */ n = Blinelen(bp); if(n > 1 && line[n-2] == '\r'){ n--; line[n-1] = '\n'; } if(printreply && !quiet) write(1, line, n); else if(debug) write(2, line, n); if(n > len - 1) i = len - 1; else i = n; if(i > 0){ memmove(msg, line, i); msg += i; len -= i; *msg = 0; } /* stop if not a continuation */ rv = strtol(line, &p, 10); if(rv >= 100 && rv < 600 && p==line+3 && *p != '-') return rv/100; /* tell user about continuations */ if(!debug && !quiet && !printreply) write(2, line, n); } fatal("remote side closed connection"); return 0;}/* * Announce on a local port and tell its address to the the remote side */static intport(void){ char buf[256]; int n, fd; char *ptr; uchar ipaddr[IPaddrlen]; int port; /* get a channel to listen on, let kernel pick the port number */ sprint(buf, "%s!*!0", net); listenfd = announce(buf, netdir); if(listenfd < 0) return seterr("can't announce"); /* get the local address and port number */ sprint(buf, "%s/local", netdir); fd = open(buf, OREAD); if(fd < 0) return seterr("opening %s: %r", buf); n = read(fd, buf, sizeof(buf)-1); close(fd); if(n <= 0) return seterr("opening %s/local: %r", netdir); buf[n] = 0; ptr = strchr(buf, ' '); if(ptr) *ptr = 0; ptr = strchr(buf, '!')+1; port = atoi(ptr); memset(ipaddr, 0, IPaddrlen); if (*net){ strcpy(buf, net); ptr = strchr(buf +1, '/'); if (ptr) *ptr = 0; myipaddr(ipaddr, buf); } /* tell remote side */ sprint(buf, "PORT %d,%d,%d,%d,%d,%d", ipaddr[IPv4off+0], ipaddr[IPv4off+1], ipaddr[IPv4off+2], ipaddr[IPv4off+3], port>>8, port&0xff); sendrequest(buf, nil); if(getreply(&ctlin, msg, sizeof(msg), 0) != Success) return seterr(msg); return 0;}/* * have server call back for a data connection */static intactive(int mode, Biobuf **bpp, char *cmda, char *cmdb){ int cfd, dfd, rv; char newdir[Maxpath]; char datafile[Maxpath + 6]; TLSconn conn; if(port() < 0) return TempFail; sendrequest(cmda, cmdb); rv = getreply(&ctlin, msg, sizeof(msg), 0); if(rv != Extra){ close(listenfd); return rv; } /* wait for a new call */ cfd = listen(netdir, newdir); if(cfd < 0) fatal("waiting for data connection"); close(listenfd); /* open it's data connection and close the control connection */ sprint(datafile, "%s/data", newdir); dfd = open(datafile, ORDWR); close(cfd); if(dfd < 0) fatal("opening data connection"); if(usetls){ memset(&conn, 0, sizeof(conn)); dfd = tlsClient(dfd, &conn); if(dfd < 0) fatal("starting tls: %r"); free(conn.cert); } Binit(&dbuf, dfd, mode); *bpp = &dbuf; return Extra;}/* * call out for a data connection */static intpassive(int mode, Biobuf **bpp, char *cmda, char *cmdb){ char msg[1024]; char ds[1024]; char *f[6]; char *p; int x, fd; TLSconn conn; if(nopassive) return Impossible; sendrequest("PASV", nil); if(getreply(&ctlin, msg, sizeof(msg), 0) != Success){ nopassive = 1; return Impossible; } /* get address and port number from reply, this is AI */ p = strchr(msg, '('); if(p == 0){ for(p = msg+3; *p; p++) if(isdigit(*p)) break; } else p++; if(getfields(p, f, 6, 0, ",") < 6){ if(debug) fprint(2, "passive mode protocol botch: %s\n", msg); werrstr("ftp protocol botch"); nopassive = 1; return Impossible; } snprint(ds, sizeof(ds), "%s!%s.%s.%s.%s!%d", net, f[0], f[1], f[2], f[3], ((atoi(f[4])&0xff)<<8) + (atoi(f[5])&0xff)); /* open data connection */ fd = dial(ds, 0, 0, 0); if(fd < 0){ if(debug) fprint(2, "passive mode connect to %s failed: %r\n", ds); nopassive = 1; return TempFail; } /* tell remote to send a file */ sendrequest(cmda, cmdb); x = getreply(&ctlin, msg, sizeof(msg), 0); if(x != Extra){ close(fd); if(debug) fprint(2, "passive mode retrieve failed: %s\n", msg); werrstr(msg); return x; } if(usetls){ memset(&conn, 0, sizeof(conn)); fd = tlsClient(fd, &conn); if(fd < 0) fatal("starting tls: %r"); free(conn.cert); } Binit(&dbuf, fd, mode); *bpp = &dbuf; return Extra;}static intdata(int mode, Biobuf **bpp, char* cmda, char *cmdb){ int x; x = passive(mode, bpp, cmda, cmdb); if(x != Impossible) return x; return active(mode, bpp, cmda, cmdb);}/* * used for keep alives */voidnop(void){ if(lastsend - time(0) < 15) return; sendrequest("PWD", nil); getreply(&ctlin, msg, sizeof(msg), 0);}/* * turn a vms spec into a path */static Node*vmsextendpath(Node *np, char *name){ np = extendpath(np, s_copy(name)); if(!ISVALID(np)){ np->d->qid.type = QTDIR; np->d->atime = time(0); np->d->mtime = np->d->atime; strcpy(np->d->uid, "who"); strcpy(np->d->gid, "cares"); np->d->mode = DMDIR|0777; np->d->length = 0; if(changedir(np) >= 0) VALID(np); } return np;}static Node*vmsdir(char *name){ char *cp; Node *np; char *oname; np = remroot; cp = strchr(name, '['); if(cp) strcpy(cp, cp+1); cp = strchr(name, ']'); if(cp) *cp = 0; oname = name = strdup(name); if(name == 0) return 0; while(cp = strchr(name, '.')){ *cp = 0; np = vmsextendpath(np, name); name = cp+1; } np = vmsextendpath(np, name); /* * walk back to first accessible directory */ for(; np->parent != np; np = np->parent) if(ISVALID(np)){ CACHED(np->parent); break; } free(oname); return np;}/* * walk up the tree building a VMS style path */static voidvmspath(Node *node, String *path){ char *p; int n; if(node->depth == 1){ p = strchr(s_to_c(node->remname), ':'); if(p){ n = p - s_to_c(node->remname) + 1; s_nappend(path, s_to_c(node->remname), n); s_append(path, "["); s_append(path, p+1); } else { s_append(path, "["); s_append(path, s_to_c(node->remname)); } s_append(path, "]"); return; } vmspath(node->parent, path); s_append(path, "."); s_append(path, s_to_c(node->remname));}/* * walk up the tree building a Unix style path */static voidunixpath(Node *node, String *path){ if(node == node->parent){ s_append(path, s_to_c(remrootpath)); return; } unixpath(node->parent, path); if(s_len(path) > 0 && strcmp(s_to_c(path), "/") != 0) s_append(path, "/"); s_append(path, s_to_c(node->remname));}/* * walk up the tree building a MVS style path */static voidmvspath(Node *node, String *path){ if(node == node->parent){ s_append(path, s_to_c(remrootpath)); return; } mvspath(node->parent, path); if(s_len(path) > 0) s_append(path, "."); s_append(path, s_to_c(node->remname));}static intgetpassword(char *buf, char *e){ char *p; int c; int consctl, rv = 0; consctl = open("/dev/consctl", OWRITE); if(consctl >= 0) write(consctl, "rawon", 5); print("Password: "); e--; for(p = buf; p <= e; p++){ c = Bgetc(&stdin); if(c < 0){ rv = -1; goto out; } if(c == '\n' || c == '\r') break; *p = c; } *p = 0; print("\n");out: if(consctl >= 0) close(consctl); return rv;}/* * convert from latin1 to utf */static char*fromlatin1(char *from){ char *p, *to; Rune r; if(os == Plan9) return nil; /* don't convert if we don't have to */ for(p = from; *p; p++) if(*p & 0x80) break; if(*p == 0) return nil; to = malloc(3*strlen(from)+2); if(to == nil) return nil; for(p = to; *from; from++){ r = (*from) & 0xff; p += runetochar(p, &r); } *p = 0; return to;}Dir*reallocdir(Dir *d, int dofree){ Dir *dp; char *p; int nn, ng, nu, nm; char *utf; if(d->name == nil) d->name = "?name?"; if(d->uid == nil) d->uid = "?uid?"; if(d->gid == nil) d->gid = d->uid; if(d->muid == nil) d->muid = d->uid; utf = fromlatin1(d->name); if(utf != nil) d->name = utf; nn = strlen(d->name)+1; nu = strlen(d->uid)+1; ng = strlen(d->gid)+1; nm = strlen(d->muid)+1; dp = malloc(sizeof(Dir)+nn+nu+ng+nm); if(dp == nil){ if(dofree) free(d); if(utf != nil) free(utf); return nil; } *dp = *d; p = (char*)&dp[1]; strcpy(p, d->name); dp->name = p; p += nn; strcpy(p, d->uid); dp->uid = p; p += nu; strcpy(p, d->gid); dp->gid = p; p += ng; strcpy(p, d->muid); dp->muid = p; if(dofree) free(d); if(utf != nil) free(utf); return dp;}Dir*dir_change_name(Dir *d, char *name){ if(d->name && strlen(d->name) >= strlen(name)){ strcpy(d->name, name); return d; } d->name = name; return reallocdir(d, 1);}Dir*dir_change_uid(Dir *d, char *name){ if(d->uid && strlen(d->uid) >= strlen(name)){ strcpy(d->name, name); return d; } d->uid = name; return reallocdir(d, 1);}Dir*dir_change_gid(Dir *d, char *name){ if(d->gid && strlen(d->gid) >= strlen(name)){ strcpy(d->name, name); return d; } d->gid = name; return reallocdir(d, 1);}Dir*dir_change_muid(Dir *d, char *name){ if(d->muid && strlen(d->muid) >= strlen(name)){ strcpy(d->name, name); return d; } d->muid = name; return reallocdir(d, 1);}static intnw_mode(char dirlet, char *s) /* NetWare file mode mapping */{ int mode = 0777; if(dirlet == 'd') mode |= DMDIR; if (strlen(s) >= 10 && s[0] != '[' || s[9] != ']') return(mode); if (s[1] == '-') /* can't read file */ mode &= ~0444; if (dirlet == 'd' && s[6] == '-') /* cannot scan dir */ mode &= ~0444; if (s[2] == '-') /* can't write file */ mode &= ~0222; if (dirlet == 'd' && s[7] == '-' && s[3] == '-') /* cannot create in, or modify dir */ mode &= ~0222; return(mode);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?