/* file.c */ /* file permissions etc. are maintained in data structures & code here */ #include <sys/types.h> #include <sys/stat.h> #include "config.h" #include "object.h" #include "file.h" #include "globals.h" #include "interp.h" #include "construct.h" int SYSTEM_mkdir(char *filename) { if (mkdir(filename,493)) return 1; else return 0; } int SYSTEM_rmdir(char *filename) { if (rmdir(filename)) return 1; else return 0; } char *make_path(struct file_entry *entry) { char *buf,*buf2; struct file_entry *curr; unsigned int len; len=strlen(mudlib_path); curr=entry; while (curr!=root_dir) { len=len+strlen(curr->filename)+1; curr=curr->parent; } len++; buf=MALLOC(len); buf2=MALLOC(len); *buf='\0'; *buf2='\0'; curr=entry; while (curr!=root_dir) { strcpy(buf2,buf); strcpy(buf,"/"); strcat(buf,curr->filename); strcat(buf,buf2); curr=curr->parent; } strcpy(buf2,buf); strcpy(buf,mudlib_path); strcat(buf,buf2); FREE(buf2); return buf; } struct file_entry *find_entry(char *filename) { struct file_entry *curr; char *currname,*currptr; if (*filename!='/') return NULL; if (filename[1]=='\0') return root_dir; curr=root_dir; currname=MALLOC(strlen(filename)+1); while (*filename=='/') { currptr=currname; filename++; while (*filename!='/' && *filename!='\0') *(currptr++)=*(filename++); *currptr='\0'; curr=curr->contents; while (curr) { if (!strcmp(curr->filename,currname)) break; curr=curr->next_file; } if (!curr) { FREE(currname); return NULL; } } FREE(currname); return curr; } int can_read(struct file_entry *fe, struct object *uid) { if (!uid) return 1; if (!fe) return 1; if (uid->flags & PRIV) return 1; if (fe==root_dir) return 1; while (fe!=root_dir) { if (uid->refno!=fe->owner && !(fe->flags & READ_OK)) return 0; fe=fe->parent; } return 1; } struct file_entry *split_dir(char *filename, char **f) { char *buf1,*buf2; struct file_entry *fe; int count,maxcount,x; if (*filename!='/') return NULL; count=0; maxcount=0; while (filename[count]) { if (filename[count]=='/') maxcount=count; count++; } buf1=MALLOC(maxcount+2); buf2=MALLOC(count-maxcount); x=0; while (x<maxcount) { buf1[x]=filename[x]; x++; } buf1[x]='\0'; while (x<count) { x++; buf2[x-maxcount-1]=filename[x]; } if (!maxcount) { buf1[0]='/'; buf1[1]='\0'; } fe=find_entry(buf1); FREE(buf1); if (!fe) { FREE(buf2); return NULL; } if (f) *f=buf2; else FREE(buf2); return fe; } struct file_entry *make_entry(struct file_entry *dir, char *name, struct object *uid) { struct file_entry *fe,*curr,*prev; int x; if (!is_legal(name)) return NULL; curr=dir->contents; prev=NULL; while (curr) { x=strcmp(name,curr->filename); if (!x) return curr; if (x<0) { fe=MALLOC(sizeof(struct file_entry)); fe->filename=copy_string(name); fe->flags=0; if (uid) fe->owner=uid->refno; else fe->owner=0; fe->contents=NULL; fe->parent=dir; fe->prev_file=prev; fe->next_file=curr; curr->prev_file=fe; if (prev) prev->next_file=fe; else dir->contents=fe; break; } prev=curr; curr=curr->next_file; } if (!curr) { fe=MALLOC(sizeof(struct file_entry)); fe->filename=name; fe->flags=0; if (uid) fe->owner=uid->refno; else fe->owner=0; fe->contents=NULL; fe->parent=dir; fe->prev_file=prev; fe->next_file=NULL; if (prev) prev->next_file=fe; else dir->contents=fe; } return fe; } int remove_entry(struct file_entry *fe) { if (fe==root_dir) return 1; if (fe->contents) return 1; if (fe->parent->contents==fe) fe->parent->contents=fe->next_file; if (fe->next_file) fe->next_file->prev_file=fe->prev_file; if (fe->prev_file) fe->prev_file->next_file=fe->next_file; FREE(fe->filename); FREE(fe); return 0; } int ls_dir(char *filename, struct object *uid, struct object *player) { struct file_entry *fe; struct fns *listen_func; char *buf; struct var_stack *rts; struct var tmp; struct object *rcv; if (!uid) return 1; rcv=player; if (!player) rcv=uid; fe=find_entry(filename); if (!fe) return 1; if (!can_read(fe,uid)) return 1; if (!(fe->flags & DIRECTORY)) return 1; listen_func=find_fns("listen",rcv); if (!listen_func) return 0; fe=fe->contents; while (fe) { buf=MALLOC((2*ITOA_BUFSIZ)+4+strlen(fe->filename)); sprintf(buf,"%ld %ld %s\n",(long) fe->owner,(long) fe->flags,fe->filename); rts=NULL; tmp.type=STRING; tmp.value.string=buf; push(&tmp,&rts); FREE(buf); tmp.type=NUM_ARGS; tmp.value.integer=1; push(&tmp,&rts); interp(uid,rcv,player,&rts,listen_func); free_stack(&rts); fe=fe->next_file; } return 0; } FILE *open_file(char *filename, char *mode, struct object *uid) { struct file_entry *fe,*homefe; char *buf,*newbuf; FILE *f; fe=find_entry(filename); if (!fe) { if (*mode=='r') return NULL; if (!uid) return NULL; homefe=split_dir(filename,&newbuf); if (!homefe) return NULL; if (!can_read(homefe,uid)) { FREE(newbuf); return NULL; } if (!(homefe->owner==uid->refno || (uid->flags & PRIV) || (homefe->flags & WRITE_OK))) { FREE(newbuf); return NULL; } fe=make_entry(homefe,newbuf,uid); if (!fe) { FREE(newbuf); return NULL; } } if (fe->flags & DIRECTORY) return NULL; if (!can_read(fe->parent,uid)) return NULL; buf=make_path(fe); if (!uid && *mode=='r') { f=fopen(buf,mode); FREE(buf); return f; } if (!uid) { FREE(buf); return NULL; } if (uid->refno==fe->owner || (uid->flags & PRIV)) { f=fopen(buf,mode); FREE(buf); return f; } if (*mode=='r' && (fe->flags & READ_OK)) { f=fopen(buf,mode); FREE(buf); return f; } if ((*mode=='a' || *mode=='w') && (fe->flags & WRITE_OK)) { f=fopen(buf,mode); FREE(buf); return f; } FREE(buf); return NULL; } int remove_file(char *filename, struct object *uid) { struct file_entry *fe; char *buf; if (!uid) return 1; fe=find_entry(filename); if (!fe) return 1; if (fe->flags & DIRECTORY) return 1; if (!can_read(fe->parent,uid)) return 1; if (fe->parent->owner!=uid->refno && !(fe->parent->flags & WRITE_OK) && !(uid && (uid->flags & PRIV))) return 1; buf=make_path(fe); if (remove(buf)) { FREE(buf); return 1; } remove_entry(fe); FREE(buf); return 0; } int copy_file(char *src, char *dest, struct object *uid) { FILE *srcf,*destf; int c; if (!uid) return 1; srcf=open_file(src,"r",uid); if (!srcf) return 1; destf=open_file(dest,"w",uid); if (!destf) { close_file(srcf); return 1; } c=fgetc(srcf); while (c!=EOF) { fputc(c,destf); c=fgetc(srcf); } close_file(srcf); close_file(destf); return 0; } int move_file(char *src, char *dest, struct object *uid) { struct file_entry *homefe,*srcf,*destf; char *buf; FILE *f1,*f2; int c; if (!uid) return 1; if (!strcmp(src,dest)) return 1; srcf=find_entry(src); if (!srcf) return 1; if (srcf->flags & DIRECTORY) return 1; destf=find_entry(dest); if (!destf) { homefe=split_dir(dest,&buf); if (!homefe) return 1; if (!can_read(homefe,uid)) { FREE(buf); return 1; } if (!(homefe->owner==uid->refno || (uid->flags & PRIV) || (homefe->flags & WRITE_OK))) { FREE(buf); return 1; } destf=make_entry(homefe,buf,uid); if (!destf) { FREE(buf); return 1; } } if (destf->flags & DIRECTORY) return 1; if (!can_read(srcf,uid)) return 1; if (!(srcf->parent->owner==uid->refno || (uid->flags & PRIV) || (srcf->parent->flags & WRITE_OK))) return 1; if (!can_read(destf->parent,uid)) return 1; if (!(destf->owner==uid->refno || (uid->flags & PRIV) || (destf->flags & WRITE_OK))) return 1; f1=open_file(src,"r",uid); if (!f1) return 1; f2=open_file(dest,"w",uid); if (!f2) { close_file(f1); return 1; } c=fgetc(f1); while (c!=EOF) { fputc(c,f2); c=fgetc(f1); } close_file(f1); close_file(f2); buf=make_path(srcf); if (remove(buf)) { FREE(buf); return 1; } FREE(buf); remove_entry(srcf); return 0; } int make_dir(char *filename, struct object *uid) { struct file_entry *fe,*homefe; char *buf; if (!uid) return 1; fe=find_entry(filename); if (fe) return 1; homefe=split_dir(filename,&buf); if (!homefe) return 1; if (!(homefe->owner==uid->refno || (uid->flags & PRIV) || (homefe->flags & WRITE_OK))) { FREE(buf); return 1; } if (!(fe=make_entry(homefe,buf,uid))) { FREE(buf); return 1; } fe->flags=DIRECTORY; buf=make_path(fe); if (SYSTEM_mkdir(buf)) { FREE(buf); remove_entry(fe); return 1; } FREE(buf); return 0; } int remove_dir(char *filename, struct object *uid) { struct file_entry *fe; char *buf; if (!uid) return 1; fe=find_entry(filename); if (!(fe->flags & DIRECTORY)) return 1; if (fe->contents) return 1; if (fe==root_dir) return 1; if (!(fe->parent->owner==uid->refno || (uid->flags & PRIV) || (fe->parent->flags & WRITE_OK))) return 1; buf=make_path(fe); if (SYSTEM_rmdir(buf)) { FREE(buf); return 1; } FREE(buf); remove_entry(fe); return 0; } int hide(char *filename) { struct file_entry *fe; fe=find_entry(filename); if (!fe) return 1; return remove_entry(fe); } int unhide(char *filename, struct object *uid, int flags) { struct file_entry *fe,*homefe; char *buf; fe=find_entry(filename); if (fe) return 1; homefe=split_dir(filename,&buf); if (!homefe) return 1; if (!(fe=make_entry(homefe,buf,uid))) { FREE(buf); return 1; } fe->flags=flags; return 0; } int db_add_entry(char *filename, signed long uid, int flags) { struct file_entry *fe,*homefe; char *buf; fe=find_entry(filename); if (fe) return 1; homefe=split_dir(filename,&buf); if (!homefe) return 1; if (!(fe=make_entry(homefe,buf,NULL))) { FREE(buf); return 1; } fe->flags=flags; fe->owner=uid; return 0; } int chown_file(char *filename, struct object *uid, struct object *new_owner) { struct file_entry *fe; fe=find_entry(filename); if (!uid) return 1; if (!new_owner) return 1; if (!fe) return 1; if (fe!=root_dir) if (!can_read(fe->parent,uid)) return 1; if (!(fe->owner==uid->refno || (uid->flags & PRIV))) return 1; fe->owner=new_owner->refno; return 0; } int chmod_file(char *filename, struct object *uid, int flags) { struct file_entry *fe; fe=find_entry(filename); if (!fe) return 1; if (!uid) return 1; if (fe!=root_dir) if (!can_read(fe->parent,uid)) return 1; if (!(fe->owner==uid->refno || (uid->flags & PRIV))) return 1; if (fe==root_dir && (!(flags & READ_OK))) return 1; flags&=(WRITE_OK | READ_OK); fe->flags&=DIRECTORY; fe->flags|=flags; return 0; } void log_sysmsg(char *msg) { char timebuf[20]; time_t now_time; FILE *logfile; struct tm *time_s; now_time=time(NULL); time_s=localtime(&now_time); sprintf(timebuf,"%2d/%02d/%2d %2d:%02d %s",(int) (time_s->tm_mon+1), (int) time_s->tm_mday, (int) time_s->tm_year, (int) (((time_s->tm_hour)%12) ? ((time_s->tm_hour)%12):12), (int) time_s->tm_min, ((time_s->tm_hour<12) ? "AM":"PM")); if (noisy) fprintf(stderr,"%s %s\n",timebuf,msg); logfile=fopen(syslog_path,"a"); if (!logfile) { fprintf(stderr,"%s system: couldn't open system log %s\n",timebuf, syslog_path); return; } fprintf(logfile,"%s %s\n",timebuf,msg); fclose(logfile); }