/*********************************************************************\ * Copyright (c) 1991 by Wen-King Su (wen-king@vlsi.cs.caltech.edu) * * * * You may copy or modify this file in any manner you wish, provided * * that this notice is always included, and that you hold the author * * harmless for any loss or damage resulting from the installation or * * use of this software. * \*********************************************************************/ #include "tweak.h" #include "client_def.h" #include "c_extern.h" #ifdef STDC_HEADERS #include #endif #include "my-string.h" static int env_dir_malloced = 0; const char *env_dir = "/"; const char *env_passwd = "\0"; const char *env_myport; const char *env_host; const char *env_port; const char *env_local_dir; const char *env_listen_on; unsigned int env_timeout; unsigned short client_buf_len; unsigned short client_net_len; int statworks=1; #define TWOGIGS 0x7fffffffUL #define FOURGIGS 0xffffffffUL /* returns mallocated abs. path merged from s2 and env.dir */ #define APPEND_PASSWORD if(have_password) \ { \ strcat(path,"\n"); \ strcat(path,env_passwd); \ } char *util_abs_path (const char * s2) { char *path, *s, *d, *t; int have_password = 0; if(!env_dir) env_dir = ""; if(!s2) s2 = ""; if(strlen(env_passwd)>0) have_password=1; if(*s2 == '/') { path = malloc(strlen(s2)+2+strlen(env_passwd)+1); sprintf(path,"/%s",s2); if(have_password) util_junk_password(path); } else { path = malloc(strlen(env_dir)+strlen(s2)+3+strlen(env_passwd)+1); sprintf(path,"/%s/%s",env_dir,s2); if(have_password) util_junk_password(path); } for(t = path; *t; ) { if(t[0] == '/') { while(t[1] == '/') for(d = t, (s = t+1); (*d++ = *s++); ); if(t != path && t[1] == 0) { t[0] = 0; return(path); } } if(t[0] == '.' && t[1] == '.') { if(t-1 == path && t[2] == 0 ) { *t = 0; APPEND_PASSWORD; return(path); } if(t-1 == path && t[2] == '/') { for(d = t, s = t + 3; (*d++ = *s++); ); continue; } if(t[-1] == '/' && (t[2] == '/' || t[2] == 0)) { s = t + 2; /* point to either slash or nul */ t -= 2; /* guaranteed that t >= path here */ while(t > path && t[0] != '/') t--; if(t != path || *s == '/') for(d = t; (*d++ = *s++); ); else { t[1] = 0; APPEND_PASSWORD; return(path); } continue; } } if(t[0] == '.') { if(t-1 == path && t[1] == 0 ) { *t = 0; APPEND_PASSWORD; return(path); } if(t-1 == path && t[1] == '/') { for(d = t, s = t + 2; (*d++ = *s++); ); continue; } if(t[-1] == '/' && (t[1] == '/' || t[1] == 0)) { s = t + 1; /* point to either slash or nul */ for(d = t-1; (*d++ = *s++); ); t--; continue; } } t++; } APPEND_PASSWORD; return(path); } static int util_split_path (char * path, char ** p1, char ** p2, char ** p3) { char *s; static char junk; *p1 = "/"; if(*path == '/') { *p2 = path; *p3 = path+1; } else { *p2 = &junk; *p3 = path; } for(s = *p3; *s; s++) { if(*s == '/') { *p1 = path; *p2 = s; *p3 = s+1; } } if (**p3 == '\0') *p3 = "."; return(1); } /* return current working directory (from environment) */ char *util_getwd (char * p) { if(p) strcpy(p,env_dir); return(p); } static RDIRENT **get_dir_blk (char * path) { RDIRENT **dp; char *p1, *p2, *fpath, buf[NBSIZE]; unsigned long pos; int cnt, k, len, rem, acc, at_eof, rlen; unsigned short dirblocksize; UBUF *ub; fpath = util_abs_path(path); dirblocksize = 0; for(pos = 0, at_eof = acc = cnt = 0; ; ) { while((acc < UBUF_MAXSPACE) && !at_eof) { ub = client_interact(CC_GET_DIR,pos, strlen(fpath), (unsigned char *)fpath+1, 2, (unsigned char *)&client_net_len); if(ub->cmd == CC_ERR) { fprintf(stderr,"%s: %s\n",path, ub->buf); free(fpath); errno = EACCES; return((RDIRENT **) 0); } rlen = BB_READ2(ub->bb_len); if(dirblocksize == 0 ) dirblocksize = rlen; else if (rlen < dirblocksize) at_eof = 1; /* if(rlen < RDHSIZE) at_eof = 1; */ for(p1 = ub->buf, p2 = buf + acc, k = rlen; k--; ) *p2++ = *p1++; acc += rlen; pos += rlen; } if(acc >= UBUF_MAXSPACE) len = UBUF_MAXSPACE; else len = acc; for(p2 = buf, rem = len, k = 0; ; k++) { if(rem < RDHSIZE) break; if(((RDIRENT *) p2)->type == RDTYPE_SKIP) break; if(((RDIRENT *) p2)->type == RDTYPE_END ) { k++; break; } p2 += RDHSIZE; rem -= (RDHSIZE+1); while(*p2++) rem--; while((p2 - buf) & 3) { p2++; rem--; } } p1 = malloc(p2-buf); if(cnt) dp = (RDIRENT **) realloc(dp,(cnt+k+1)*sizeof(RDIRENT *)); else dp = (RDIRENT **) malloc((cnt+k+1)*sizeof(RDIRENT *)); if(!p1 || !dp) { fputs("directory reading out of memory\n",stderr); free(fpath); return((RDIRENT **) 0); } for(p2 = buf, rem = len; ; cnt++) { if(rem < RDHSIZE) break; if(((RDIRENT *) p2)->type == RDTYPE_SKIP) break; if(((RDIRENT *) p2)->type == RDTYPE_END) { dp[cnt] = 0; free(fpath); return(dp); } dp[cnt] = (RDIRENT *) p1; for(k = RDHSIZE, rem -= (RDHSIZE+1); k--; *p1++ = *p2++); while( (*p1++ = *p2++) ) rem--; while((p2 - buf) & 3) { p2++; p1++; rem--; } } if(acc < UBUF_MAXSPACE) { dp[cnt] = 0; free(fpath); return(dp); } for(p1 = buf + UBUF_MAXSPACE, p2 = buf, k = (acc -= UBUF_MAXSPACE); k--;) *p2++ = *p1++; } free(fpath); } static int util_download_main (char * path, char * fpath, FILE * fp, unsigned long start_from, int cmd) { unsigned long pos, started_from = start_from, downloaded; unsigned tmax, wrote, sent_time, rlen; UBUF *ub; time_t t = time(NULL); for(tmax = 1, pos = start_from, sent_time = 0; ;) { ub = client_interact(cmd,pos,strlen(fpath),(unsigned char *)fpath+1, 2, (unsigned char *)&client_net_len); if(client_trace && (udp_sent_time != sent_time)) { sent_time = udp_sent_time; if(client_buf_len >= UBUF_SPACE) fprintf(stderr,"\r%luk ",1+(pos>>10)); else fprintf(stderr,"\r%lu ", pos); fflush(stderr); } if(ub->cmd == CC_ERR) { fprintf(stderr,"downloading %s: %s\n",path,ub->buf); return(-1); } rlen = BB_READ2(ub->bb_len); wrote = fwrite(ub->buf,1,rlen,fp); /* check for long integer pos overflow */ #if SIZEOF_LONG > 4 if(pos+wrote>FOURGIGS) break; #else if(pos+wrote>10), path, downloaded/t); fflush(stderr); } return(0); } int util_download (char * path, FILE * fp, unsigned long start_from) { int code, len; char *fpath; fpath = util_abs_path(path); if(*env_passwd) { strcat(fpath, "\n"); strcat(fpath, env_passwd); len = strlen(fpath); } code = util_download_main(path, fpath, fp, start_from, CC_GET_FILE); free(fpath); return(code); } int util_grab_file (char * path, FILE * fp, unsigned long start_from) { int code, len; char *fpath; UBUF *ub; fpath = util_abs_path(path); if(*env_passwd) { strcat(fpath, "\n"); strcat(fpath, env_passwd); len = strlen(fpath); } code = util_download_main(path, fpath, fp, start_from, CC_GRAB_FILE); if(code) { free(fpath); return(code); } ub = client_interact(CC_GRAB_DONE, 0L, len, (unsigned char *)fpath+1, 0, (unsigned char *)NULLP); if(ub->cmd == CC_ERR) { fprintf(stderr,"Warning, unexpected grab error: %s\n",ub->buf); } free(fpath); return(code); } int util_upload (char * path, FILE * fp, time_t stamp) { unsigned long pos; unsigned bytes, first, tmax, sent_time; char *fpath, buf[UBUF_MAXSPACE]; UBUF *ub; time_t t = time(NULL); char *dpath,*p1,*p2; unsigned char flags; struct stat sb; fpath = util_abs_path(path); util_split_path(fpath,&dpath,&p1,&p2); *p1='\0'; /* check if we have enough rights to create file */ ub = client_interact(CC_GET_PRO,0, strlen(dpath), (unsigned char *)dpath+1, 0, (unsigned char *)NULLP); free(fpath); fpath = util_abs_path(path); if(ub->cmd == CC_ERR) { fprintf(stderr,"uploading %s: %s\n",path,ub->buf); free(fpath); return(1); } /* extract flags from server reply */ bytes = BB_READ2(ub->bb_len); pos = BB_READ4(ub->bb_pos); if(pos) { /* flags are in the reply */ flags = *(ub->buf+bytes); /* check for required flags */ if(! (flags & DIR_OWNER)) { if( ! (flags & DIR_ADD)) { fprintf(stderr,"No permission for adding files.\n"); free(fpath); return(1); } } else { /* owner of directory */ flags|=DIR_DEL|DIR_ADD; } /* check if we can overwrite an existing file */ if(! (flags & DIR_DEL)) { if(util_stat(fpath,&sb)==0) { fprintf(stderr,"No permission for overwriting: %s\n",fpath); free(fpath); return(1); } } } for(tmax = 1, sent_time = 0, pos = 0, first = 1; ; first = 0) { if((bytes = fread(buf,1,client_buf_len,fp)) || first) { ub = client_interact(CC_UP_LOAD,pos, bytes, (unsigned char *)buf, 0, (unsigned char *)NULLP); if(client_trace && (udp_sent_time != sent_time)) { sent_time = udp_sent_time; if(client_buf_len >= UBUF_SPACE) fprintf(stderr,"\r%luk ",1+(pos>>10)); else fprintf(stderr,"\r%lu ", pos ); fflush(stderr); } } else { BB_WRITE4(buf,stamp); ub = client_interact(CC_INSTALL,stamp==0?0:4,strlen(fpath), (unsigned char *)fpath+1, stamp==0?0:4, (unsigned char *)buf); } if(ub->cmd == CC_ERR) { fprintf(stderr,"uploading %s: %s\n",path,ub->buf); free(fpath); return(1); } if(!bytes && !first) break; #if SIZEOF_LONG > 4 if(pos+bytes>FOURGIGS) break; #else if(pos+bytes>10), path, pos/t); fflush(stderr); } free(fpath); return(0); } static void util_get_env (void) { char *p; if(!(env_host = getenv("FSP_HOST"))) { fputs("No FSP_HOST specified.\n",stderr); exit(1); } if(!(env_port = getenv("FSP_PORT"))) { fputs("No FSP_PORT specified.\n",stderr); exit(1); } if(!(env_dir = getenv("FSP_DIR"))) { env_dir = "/"; env_dir_malloced = 0; } if(!(env_myport = getenv("FSP_LOCALPORT"))) env_myport = "0"; if(!(env_listen_on = getenv("FSP_LOCALIP"))) env_listen_on = NULL; if(!(env_passwd = getenv("FSP_PASSWORD"))) env_passwd = "\0"; client_trace = !!getenv("FSP_TRACE"); if( (p = getenv("FSP_BUF_SIZE")) ) client_buf_len = atoi(p); else client_buf_len = UBUF_SPACE; if(client_buf_len > UBUF_MAXSPACE) client_buf_len = UBUF_MAXSPACE; client_net_len = htons(client_buf_len); if( (p = getenv("FSP_DELAY")) ) target_delay = atol(p); if(target_delay < MIN_DELAY) target_delay = MIN_DELAY; if(target_delay > MAX_DELAY) target_delay = MAX_DELAY; if( (p = getenv("FSP_MAXDELAY")) ) target_maxdelay = atol(p); if(target_maxdelay < target_delay) target_maxdelay = target_delay; if(target_maxdelay > MAX_DELAY) target_maxdelay = MAX_DELAY; if(!(env_local_dir = getenv("FSP_LOCAL_DIR"))) env_local_dir="."; if(!(p = getenv("FSP_TIMEOUT"))) env_timeout = DEFAULT_TIMEOUT; else env_timeout = atol(p); } void env_client (void) { util_get_env(); init_client(env_host,atoi(env_port),atoi(env_myport)); } static DDLIST *ddroot = 0; RDIR *util_opendir (char * path) { char *fpath; RDIRENT **dep; DDLIST *ddp; RDIR *rdirp; fpath = util_abs_path(path); for(ddp = ddroot; ddp; ddp = ddp->next) if(!strcmp(ddp->path,fpath)) break; if(!ddp) { if(!(dep = get_dir_blk(fpath))) { free(fpath); return((RDIR *) 0); } ddp = (DDLIST *) malloc(sizeof(DDLIST)); ddp->dep_root = dep; ddp->path = fpath; ddp->ref_cnt = 0; ddp->next = ddroot; ddroot = ddp; } else free(fpath); ddp->ref_cnt++; rdirp = (RDIR *) malloc(sizeof(RDIR)); rdirp->ddp = ddp; rdirp->dep = ddp->dep_root; return(rdirp); } void util_closedir (RDIR * rdirp) { rdirp->ddp->ref_cnt--; free(rdirp); } rdirent *util_readdir (RDIR * rdirp) { static rdirent rde; RDIRENT **dep; dep = rdirp->dep; if(!*dep) return((rdirent *) 0); rde.d_fileno = 10; rde.d_rcdlen = 10; rde.d_namlen = strlen((*dep)->name); rde.d_name = (*dep)->name; rdirp->dep = dep+1; return(&rde); } /* Removes \npassword from input */ void util_junk_password(char *path) { char *pos; pos=strchr(path,'\n'); if(pos != NULL) /* terminate them! */ *pos='\0'; } int util_stat (char * path, struct stat * sbuf) { RDIR *drp; RDIRENT **dep; DDLIST *ddp; UBUF *ub; char *fpath,*fpath2, *ppath, *p1, *pfile; int cached=0; fpath = util_abs_path(path); fpath2 = strdup(fpath); if(!strcmp(fpath,env_dir)) { ppath = fpath; pfile = "."; } else { util_split_path(fpath,&ppath,&p1,&pfile); *p1='\0'; } /* printf("ppath `%s` pfile '%s'\n",ppath,pfile); */ /* check if we have ppath cached */ /* printf("Finding `%s` in cache.\n",ppath); */ for(ddp = ddroot; ddp; ddp = ddp->next) { /* printf(" we have %s in cache.\n",ddp->path); */ if(!strcmp(ddp->path,ppath)) { cached=1; break; } } /* if(cached) printf("Record found in cache.\n",ppath); */ if(statworks && !cached) { /* send a new FSP_STAT command to server */ ub = client_interact(CC_STAT,0L, strlen(fpath2), (unsigned char *) fpath2+1, 0, 0); if(ub->cmd == CC_STAT) { sbuf->st_uid = 0; sbuf->st_gid = 0; sbuf->st_atime = sbuf->st_mtime = sbuf->st_ctime = BB_READ4((ub->buf)); sbuf->st_size = BB_READ4((ub->buf+4)); if((ub->buf[8]) == RDTYPE_DIR) { sbuf->st_mode = 0777 | S_IFDIR; sbuf->st_nlink = 2; } else { sbuf->st_mode = 0666 | S_IFREG; sbuf->st_nlink = 1; } free(fpath); free(fpath2); if(ub->buf[8]==0) { errno = ENOENT; return -1; } return 0; } else { statworks=0; } } /* CC_STAT */ if( (drp = util_opendir(ppath)) ) { for(dep = drp->dep; *dep; dep++) { if(!strcmp((*dep)->name,pfile)) { if((*dep)->type == RDTYPE_DIR) sbuf->st_mode = 0777 | S_IFDIR; else sbuf->st_mode = 0666 | S_IFREG; if((*dep)->type == RDTYPE_DIR) sbuf->st_nlink = 2; else sbuf->st_nlink = 1; sbuf->st_uid = 0; sbuf->st_gid = 0; sbuf->st_size = BB_READ4((*dep)->bb_size); sbuf->st_atime = sbuf->st_mtime = sbuf->st_ctime = BB_READ4((*dep)->bb_time); util_closedir(drp); free(fpath); free(fpath2); return(0); } } util_closedir(drp); } free(fpath); free(fpath2); errno = ENOENT; return(-1); } int util_cd (char * p) { char *fpath; UBUF *ub; DDLIST *ddp; fpath = util_abs_path(p); for(ddp = ddroot; ddp; ddp = ddp->next) if(!strcmp(ddp->path,fpath)) break; if(!ddp && strcmp(p,".") && strcmp(p,"..")) { ub = client_interact(CC_GET_DIR,0L, strlen(fpath), (unsigned char *) fpath+1, 2, (unsigned char *)&client_net_len); if(ub->cmd == CC_ERR) { free(fpath); fprintf(stderr,"%s: %s\n",p, ub->buf); errno = EACCES; return(-1); } } if(env_dir_malloced) free(env_dir); env_dir_malloced = 1; env_dir = fpath; return(0); } /* Perform a cd, but don't verify path. Assume the path has been * pre-verified */ int util_cd2 (char * p) { char *fpath; fpath = util_abs_path(p); if(env_dir_malloced) free(env_dir); env_dir_malloced = 1; env_dir = fpath; return(0); } void util_process_file(char *path, int mode, void (*process_file)(char *,struct stat *, int, int), int (*process_start_dir)(char *,struct stat *,u_long *), void (*process_end_dir)(char *,int,u_long,int), int level) { struct stat sbuf; RDIR *rdir; struct rdirent *rde; int pathlen; char *newname; u_long sum; if (util_stat(path, &sbuf) < 0) { perror(path); return; } if (S_ISREG(sbuf.st_mode)) { if(process_file) (*process_file)(path, &sbuf, mode, level); } else if (S_ISDIR(sbuf.st_mode)) { sum = mode; if (process_start_dir && (*process_start_dir)(path, &sbuf, &sum) < 0) fprintf(stderr, "skipping remote directory `%s'\n", path); else { if ((rdir = util_opendir(path))) { pathlen = strlen(path); while ((rde = util_readdir(rdir))) { /* skip over "." and ".." */ if (rde->d_name[0] == '.' && (rde->d_name[1] == '\0' || (rde->d_name[1] == '.' && rde->d_name[2] == '\0'))) continue; newname = malloc(pathlen + rde->d_namlen + 2); strcpy(newname, path); if(newname[pathlen-1] != '/') newname[pathlen] = '/'; else pathlen--; strcpy(newname + pathlen + 1, rde->d_name); util_process_file(newname, mode, process_file, process_start_dir, process_end_dir, level + 1); free(newname); } util_closedir(rdir); } if(process_end_dir) (*process_end_dir)(path, mode, sum, level); } } else fprintf(stderr, "remote file `%s' is not a file or directory!\n",path); /* free(path); */ }