int our_link(char *oldpath, char *newpath) { #ifdef _WINDOWS assert(0); /* link not used in Windows */ return(-1); #else /* UNIX */ char *p, *pold; size_t len; int ret = -1; p = fname_to_locale(oldpath); if(p){ len = strlen(p); pold = (char *) fs_get((len+1) * sizeof(char)); strncpy(pold, p, len+1); pold[len] = '\0'; ret = link(pold, fname_to_locale(newpath)); fs_give((void **) &pold); } return ret; #endif /* UNIX */ }
int our_truncate(char *path, off_t size) { int ret = -1; #if defined(_WINDOWS) || !defined(HAVE_TRUNCATE) int fdes; #endif #ifdef _WINDOWS if((fdes = our_open(path, O_RDWR | O_CREAT | S_IREAD | S_IWRITE | _O_U8TEXT, 0600)) != -1){ if(chsize(fdes, size) == 0) ret = 0; close(fdes); } #else /* UNIX */ #ifdef HAVE_TRUNCATE ret = truncate(fname_to_locale(path), size); #else /* !HAVE_TRUNCATE */ if((fdes = our_open(path, O_RDWR, 0600)) != -1){ ret = chsize(fdes, size) ; if(close(fdes)) ret = -1; } #endif /* !HAVE_TRUNCATE */ #endif /* UNIX */ return ret; }
int our_open(char *path, int flags, mode_t mode) { #ifdef _WINDOWS LPTSTR p = NULL; int ret = -1; /* * Setting the _O_WTEXT flag when opening a file for reading * will cause us to read the first few bytes to check for * a BOM and to translate from that encoding if we find it. * This only works with stream I/O, not low-level read/write. * * When opening for writing the flag _O_U8TEXT will cause * us to put a UTF-8 BOM at the start of the file. * * O_TEXT will cause LF -> CRLF on output, opposite on input * O_BINARY suppresses that. * _O_U8TEXT implies O_TEXT. */ p = utf8_to_lptstr((LPSTR) path); if(p){ ret = _topen(p, flags, mode); fs_give((void **) &p); } return ret; #else /* UNIX */ return(open(fname_to_locale(path), flags, mode)); #endif /* UNIX */ }
int our_stat(char *filename, struct stat *sbuf) { #ifdef _WINDOWS LPTSTR f = NULL; int ret = -1; struct _stat s; f = utf8_to_lptstr((LPSTR) filename); if(f){ ret = _tstat(f, &s); sbuf->st_dev = s.st_dev; sbuf->st_ino = s.st_ino; sbuf->st_mode = s.st_mode; sbuf->st_nlink = s.st_nlink; sbuf->st_uid = s.st_uid; sbuf->st_gid = s.st_gid; sbuf->st_rdev = s.st_rdev; sbuf->st_size = s.st_size; sbuf->st_atime = (time_t) s.st_atime; sbuf->st_mtime = (time_t) s.st_mtime; sbuf->st_ctime = (time_t) s.st_ctime; fs_give((void **) &f); } return ret; #else /* UNIX */ return(stat(fname_to_locale(filename), sbuf)); #endif /* UNIX */ }
int our_chown(char *path, uid_t owner, gid_t group) { #ifdef _WINDOWS return 0; #else /* UNIX */ return(chown(fname_to_locale(path), owner, group)); #endif /* UNIX */ }
int our_lstat(char *filename, struct stat *sbuf) { #ifdef _WINDOWS assert(0); /* lstat not used in Windows */ return(-1); #else /* UNIX */ return(lstat(fname_to_locale(filename), sbuf)); #endif /* UNIX */ }
int our_rename(char *oldpath, char *newpath) { #ifdef _WINDOWS LPTSTR pold = NULL, pnew = NULL; int ret = -1; pold = utf8_to_lptstr((LPSTR) oldpath); pnew = utf8_to_lptstr((LPSTR) newpath); if(pold && pnew) ret = _trename(pold, pnew); if(pold) fs_give((void **) &pold); if(pnew) fs_give((void **) &pnew); return ret; #else /* UNIX */ char *p, *pold; size_t len; int ret = -1; p = fname_to_locale(oldpath); if(p){ len = strlen(p); pold = (char *) fs_get((len+1) * sizeof(char)); strncpy(pold, p, len+1); pold[len] = '\0'; ret = rename(pold, fname_to_locale(newpath)); fs_give((void **) &pold); } return ret; #endif /* UNIX */ }
int our_access(char *path, int mode) { #ifdef _WINDOWS LPTSTR p = NULL; int ret = -1; p = utf8_to_lptstr((LPSTR) path); if(p){ ret = _taccess(p, mode); fs_give((void **) &p); } return ret; #else /* UNIX */ return(access(fname_to_locale(path), mode)); #endif /* UNIX */ }
int our_utime(char *path, struct utimbuf *buf) { #ifdef _WINDOWS LPTSTR p = NULL; int ret = -1; p = utf8_to_lptstr((LPSTR) path); if(p){ ret = _tutime(p, buf); fs_give((void **) &p); } return ret; #else /* UNIX */ return(utime(fname_to_locale(path), buf)); #endif /* UNIX */ }
int our_unlink(char *path) { #ifdef _WINDOWS LPTSTR p = NULL; int ret = -1; p = utf8_to_lptstr((LPSTR) path); if(p){ ret = _tunlink(p); fs_give((void **) &p); } return ret; #else /* UNIX */ return(unlink(fname_to_locale(path))); #endif /* UNIX */ }
int our_mkdir(char *path, mode_t mode) { #ifdef _WINDOWS /* mode is a noop for _WINDOWS */ LPTSTR p = NULL; int ret = -1; p = utf8_to_lptstr((LPSTR) path); if(p){ ret = _tmkdir(p); fs_give((void **) &p); } return ret; #else /* UNIX */ return(mkdir(fname_to_locale(path), mode)); #endif /* UNIX */ }
FILE * our_fopen(char *path, char *mode) { #ifdef _WINDOWS LPTSTR p = NULL, m = NULL; FILE *ret = NULL; char *mode_with_ccs = NULL; char buf[500]; size_t len; if(mode && (*mode == 'r' || *mode == 'a')){ char *force_bom_check = ", ccs=UNICODE"; if(strchr(mode, 'b')) mode_with_ccs = mode; else{ /* * The docs seem to say that we don't need the ccs parameter and * if the file has a BOM at the beginning it will notice that and * use it. However, we're not seeing that. Instead, what we see is * that giving a parameter of UNICODE causes the desired behavior. * This causes it to check for a BOM and if it finds one it uses it. * If it doesn't find one, it treats the file as ANSI, which is what * we want. */ if((len = strlen(mode) + strlen(force_bom_check)) < sizeof(buf)){ len = sizeof(buf)-1; mode_with_ccs = buf; } else mode_with_ccs = (char *) MemAlloc((len+1) * sizeof(char)); if(mode_with_ccs) snprintf(mode_with_ccs, len+1, "%s%s", mode, force_bom_check); else mode_with_ccs = mode; /* can't happen */ } } else if(mode && (*mode == 'w')){ char *force_utf8 = ", ccs=UTF-8"; if(strchr(mode, 'b')) mode_with_ccs = mode; else{ if((len = strlen(mode) + strlen(force_utf8)) < sizeof(buf)){ len = sizeof(buf)-1; mode_with_ccs = buf; } else mode_with_ccs = (char *) MemAlloc((len+1) * sizeof(char)); if(mode_with_ccs) snprintf(mode_with_ccs, len+1, "%s%s", mode, force_utf8); else mode_with_ccs = mode; /* can't happen */ } } p = utf8_to_lptstr((LPSTR) path); if(p){ m = utf8_to_lptstr((LPSTR) mode_with_ccs); if(m){ ret = _tfopen(p, m); MemFree((void *) m); } fs_give((void **) &p); } if(mode_with_ccs && mode_with_ccs != buf && mode_with_ccs != mode) MemFree((void *) mode_with_ccs); return ret; #else /* UNIX */ return(fopen(fname_to_locale(path), mode)); #endif /* UNIX */ }
/*---------------------------------------------------------------------- Spawn a child process and optionally connect read/write pipes to it Args: command -- string to hand the shell outfile -- address of pointer containing file to receive output errfile -- address of pointer containing file to receive error output mode -- mode for type of shell, signal protection etc... Returns: pointer to alloc'd PIPE_S on success, NULL otherwise The outfile is either NULL, a pointer to a NULL value, or a pointer to the requested name for the output file. In the pointer-to-NULL case the caller doesn't care about the name, but wants to see the pipe's results so we make one up. It's up to the caller to make sure the free storage containing the name is cleaned up. Mode bits serve several purposes. PIPE_WRITE tells us we need to open a pipe to write the child's stdin. PIPE_READ tells us we need to open a pipe to read from the child's stdout/stderr. *NOTE* Having neither of the above set means we're not setting up any pipes, just forking the child and exec'ing the command. Also, this takes precedence over any named outfile. PIPE_STDERR means we're to tie the childs stderr to the same place stdout is going. *NOTE* This only makes sense then if PIPE_READ or an outfile is provided. Also, this takes precedence over any named errfile. PIPE_RESET means we reset the terminal mode to what it was before we started pine and then exec the command. In PC-Pine, _RESET was a shortcut for just executing a command. We'll try to pay attention to the above flags to make sure we do the right thing. PIPE_PROT means to protect the child from the usual nasty signals that might cause premature death. Otherwise, the default signals are set so the child can deal with the nasty signals in its own way. NOT USED UNDER WINDOWS PIPE_NOSHELL means we're to exec the command without the aid of a system shell. *NOTE* This negates the affect of PIPE_USER. NOT USED UNDER WINDOWS PIPE_USER means we're to try executing the command in the user's shell. Right now we only look in the environment, but that may get more sophisticated later. NOT USED UNDER WINDOWS PIPE_RUNNOW was added for WINDOWS for the case pipe is called to run a shell program (like for url viewing). This is the only option where we don't wait for child termination, and is only obeyed if PIPE_WRITE and PIPE_READ aren't set ----*/ PIPE_S * open_system_pipe(char *command, char **outfile, char **errfile, int mode, int timeout, void (*pipecb_f)(PIPE_S *, int, void *), void (*piperr_f)(char *)) { PIPE_S *syspipe = NULL; #ifdef _WINDOWS int exit_code = 0; char cmdbuf[1024]; unsigned flags = 0; #else char shellpath[MAXPATH+1], *shell; int p[2], oparentd = -1, ochildd = -1, iparentd = -1, ichildd = -1; #endif #ifdef _WINDOWS if(mode & PIPE_STDERR) flags |= MSWIN_EAW_CAPT_STDERR; /* * It'll be a lot more difficult to support READing and WRITing. * This was never supported, and there don't look to be any cases * that set both of these flags anymore for win32. * * errfile could probably be supported pretty easily */ if(errfile){ if(piperr_f) (*piperr_f)("Pipe arg not yet supported: Error File"); return(NULL); } if((mode & PIPE_RUNNOW) && !(mode & (PIPE_WRITE | PIPE_READ | PIPE_STDERR))){ if(mswin_shell_exec(command, NULL) == 0 && (syspipe = (PIPE_S *) malloc(sizeof(PIPE_S))) != NULL){ memset(syspipe, 0, sizeof(PIPE_S)); return(syspipe); } return(NULL); } strncpy(cmdbuf, command, sizeof(cmdbuf)); cmdbuf[sizeof(cmdbuf)-1] = '\0'; if((syspipe = (PIPE_S *) malloc(sizeof(PIPE_S))) == NULL) return(NULL); memset(syspipe, 0, sizeof(PIPE_S)); syspipe->mode = mode; if(!outfile){ syspipe->deloutfile = 1; if(mode & PIPE_READ){ syspipe->outfile = temp_nam(NULL, "po"); our_unlink(syspipe->outfile); } } else{ if(!*outfile) /* asked for, but not named? */ *outfile = temp_nam(NULL, "po"); our_unlink(*outfile); syspipe->outfile = (char *) malloc((strlen(*outfile)+1)*sizeof(char)); snprintf(syspipe->outfile, strlen(*outfile)+1, "%s", *outfile); } if(mode & PIPE_WRITE){ /* * Create tmp file to write, spawn child in close_pipe * after tmp file's written... */ syspipe->infile = temp_nam(NULL, "pw"); syspipe->out.f = our_fopen(syspipe->infile, "wb"); syspipe->command = (char *) malloc((strlen(cmdbuf)+1)*sizeof(char)); snprintf(syspipe->command, strlen(cmdbuf)+1, "%s", cmdbuf); dprint((1, "pipe write: %s", cmdbuf)); } else if(mode & PIPE_READ){ /* * Create a tmp file for command result, exec the command * here into temp file, and return file pointer to it... */ syspipe->command = (char *) malloc((strlen(cmdbuf)+1)*sizeof(char)); snprintf(syspipe->command, strlen(cmdbuf)+1, "%s", cmdbuf); dprint((1, "pipe read: %s", cmdbuf)); if(pipe_mswin_exec_wrapper("pipe command", syspipe, flags, pipecb_f, piperr_f)){ if(syspipe->outfile){ free((void *) syspipe->outfile); syspipe->outfile = NULL; } zot_pipe(&syspipe); } else{ syspipe->in.f = our_fopen(syspipe->outfile, "rb"); syspipe->exit_code = exit_code; } } else{ /* we just run the command taking outfile into account */ syspipe->command = (char *) malloc((strlen(cmdbuf)+1)*sizeof(char)); snprintf(syspipe->command, strlen(cmdbuf)+1, "%s", cmdbuf); if(pipe_mswin_exec_wrapper("pipe command", syspipe, flags, pipecb_f, piperr_f)){ if(syspipe->outfile){ free((void *) syspipe->outfile); syspipe->outfile = NULL; } zot_pipe(&syspipe); } else syspipe->exit_code = exit_code; } #else /* !_WINDOWS */ if((syspipe = (PIPE_S *) malloc(sizeof(PIPE_S))) == NULL) return(NULL); memset(syspipe, 0, sizeof(PIPE_S)); syspipe->mode = mode; /* * If we're not using the shell's command parsing smarts, build * argv by hand... */ if(mode & PIPE_NOSHELL){ char **ap, *p; size_t n; /* parse the arguments into argv */ for(p = command; *p && isspace((unsigned char)(*p)); p++) ; /* swallow leading ws */ if(*p){ int l = strlen(p); if((syspipe->args = (char *) malloc((l + 1) * sizeof(char))) != NULL){ strncpy(syspipe->args, p, l); syspipe->args[l] = '\0'; } else{ if(piperr_f) (*piperr_f)(pipe_error_msg("<null>", "execute", "Can't allocate command string")); zot_pipe(&syspipe); return(NULL); } } else{ if(piperr_f) (*piperr_f)(pipe_error_msg("<null>", "execute", "No command name found")); zot_pipe(&syspipe); return(NULL); } for(p = syspipe->args, n = 2; *p; p++) /* count the args */ if(isspace((unsigned char)(*p)) && *(p+1) && !isspace((unsigned char)(*(p+1)))) n++; if ((syspipe->argv = ap = (char **)malloc(n * sizeof(char *))) == NULL){ zot_pipe(&syspipe); return(NULL); } memset(syspipe->argv, 0, n * sizeof(char *)); for(p = syspipe->args; *p; ){ /* collect args */ while(*p && isspace((unsigned char)(*p))) *p++ = '\0'; *ap++ = (*p) ? p : NULL; while(*p && !isspace((unsigned char)(*p))) p++; } /* make sure argv[0] exists in $PATH */ if(can_access_in_path(getenv("PATH"), syspipe->argv[0], EXECUTE_ACCESS) < 0){ if(piperr_f) (*piperr_f)(pipe_error_msg(syspipe->argv[0], "access", error_description(errno))); zot_pipe(&syspipe); return(NULL); } } /* fill in any output filenames */ if(!(mode & PIPE_READ)){ if(outfile && !*outfile) *outfile = temp_nam(NULL, "pine_p"); /* asked for, but not named? */ if(errfile && !*errfile) *errfile = temp_nam(NULL, "pine_p"); /* ditto */ } /* create pipes */ if(mode & (PIPE_WRITE | PIPE_READ)){ if(mode & PIPE_WRITE){ pipe(p); /* alloc pipe to write child */ oparentd = p[STDOUT_FILENO]; ichildd = p[STDIN_FILENO]; } if(mode & PIPE_READ){ pipe(p); /* alloc pipe to read child */ iparentd = p[STDIN_FILENO]; ochildd = p[STDOUT_FILENO]; } } if(pipecb_f) /* let caller prep display */ (*pipecb_f)(syspipe, OSB_PRE_OPEN, NULL); if((syspipe->pid = vfork()) == 0){ /* reset child's handlers in requested fashion... */ (void)signal(SIGINT, (mode & PIPE_PROT) ? SIG_IGN : SIG_DFL); (void)signal(SIGQUIT, (mode & PIPE_PROT) ? SIG_IGN : SIG_DFL); (void)signal(SIGHUP, (mode & PIPE_PROT) ? SIG_IGN : SIG_DFL); #ifdef SIGCHLD (void) signal(SIGCHLD, SIG_DFL); #endif /* if parent isn't reading, and we have a filename to write */ if(!(mode & PIPE_READ) && outfile){ /* connect output to file */ int output = our_creat(*outfile, 0600); dup2(output, STDOUT_FILENO); if(mode & PIPE_STDERR) dup2(output, STDERR_FILENO); else if(errfile) dup2(our_creat(*errfile, 0600), STDERR_FILENO); } if(mode & PIPE_WRITE){ /* connect process input */ close(oparentd); dup2(ichildd, STDIN_FILENO); /* tie stdin to pipe */ close(ichildd); } if(mode & PIPE_READ){ /* connect process output */ close(iparentd); dup2(ochildd, STDOUT_FILENO); /* tie std{out,err} to pipe */ if(mode & PIPE_STDERR) dup2(ochildd, STDERR_FILENO); else if(errfile) dup2(our_creat(*errfile, 0600), STDERR_FILENO); close(ochildd); } if(mode & PIPE_NOSHELL){ execvp(syspipe->argv[0], syspipe->argv); } else{ if(mode & PIPE_USER){ char *env, *sh; if((env = getenv("SHELL")) && (sh = strrchr(env, '/'))){ shell = sh + 1; strncpy(shellpath, env, sizeof(shellpath)-1); shellpath[sizeof(shellpath)-1] = '\0'; } else{ shell = "csh"; strncpy(shellpath, "/bin/csh", sizeof(shellpath)-1); shellpath[sizeof(shellpath)-1] = '\0'; } } else{ shell = "sh"; strncpy(shellpath, "/bin/sh", sizeof(shellpath)-1); shellpath[sizeof(shellpath)-1] = '\0'; } execl(shellpath, shell, command ? "-c" : (char *)NULL, fname_to_locale(command), (char *)NULL); } fprintf(stderr, "Can't exec %s\nReason: %s", command, error_description(errno)); _exit(-1); } if((child_pid = syspipe->pid) > 0){ syspipe->isig = signal(SIGINT, SIG_IGN); /* Reset handlers to make */ syspipe->qsig = signal(SIGQUIT, SIG_IGN); /* sure we don't come to */ syspipe->hsig = signal(SIGHUP, SIG_IGN); /* a premature end... */ if((syspipe->timeout = timeout) != 0){ syspipe->alrm = signal(SIGALRM, pipe_alarm); syspipe->old_timeo = alarm(timeout); } if(mode & PIPE_WRITE){ close(ichildd); if(mode & PIPE_DESC) syspipe->out.d = oparentd; else syspipe->out.f = fdopen(oparentd, "w"); } if(mode & PIPE_READ){ close(ochildd); if(mode & PIPE_DESC) syspipe->in.d = iparentd; else syspipe->in.f = fdopen(iparentd, "r"); } } else{ if(mode & (PIPE_WRITE | PIPE_READ)){ if(mode & PIPE_WRITE){ close(oparentd); close(ichildd); } if(mode & PIPE_READ){ close(iparentd); close(ochildd); } } if(pipecb_f) /* let caller fixup display */ (*pipecb_f)(syspipe, OSB_POST_OPEN, NULL); if(outfile && *outfile){ our_unlink(*outfile); free((void *) *outfile); *outfile = NULL; } if(errfile && *errfile){ our_unlink(*errfile); free((void *) *errfile); *errfile = NULL; } if(piperr_f) (*piperr_f)(pipe_error_msg(command, "fork", error_description(errno))); zot_pipe(&syspipe); } #endif /* UNIX */ return(syspipe); }