func (fe *fileExistsIn) goServe(lc *longCall, wsData *webserverData) { var err error var exists, isdir bool if exists, err = ssutil.FileOrDirExists(fe.File); err == nil { isdir, err = ssutil.IsDir(fe.File) } if err != nil { lc.Response <- jsonResponseError("error: " + err.Error()) } else { lc.Response <- jsonResponse{"state": "done", "exists": exists && !isdir} } }
func (fr *fileRemoveIn) goServe(lc *longCall, wsData *webserverData) { var isdir bool var err error if isdir, err = ssutil.IsDir(fr.File); err != nil { lc.Response <- jsonResponseError("error: " + err.Error()) } if isdir { lc.Response <- jsonResponseError("error: file.remove() cannot remove a directory") } else { err = os.Remove(fr.File) if err != nil { lc.Response <- jsonResponseError("error: " + err.Error()) } else { lc.Response <- jsonResponse{"state": "done"} } } }
func mustBeARawSelfServingSourceFile(filespec string) (exeFileData []byte, err error) { var fileOrDirExists, isDir bool if fileOrDirExists, err = ssutil.FileOrDirExists(filespec); err != nil { return exeFileData, err } if isDir, err = ssutil.IsDir(filespec); err != nil { return exeFileData, err } if !fileOrDirExists || isDir { return exeFileData, errors.New("compile-from file \"" + filespec + "\" does not look valid") } // read binary file - if amIAlreadyCompiled is not in there this this isn't right if exeFileData, err = ioutil.ReadFile(filespec); err != nil { return exeFileData, err } if !bytes.Contains(exeFileData, []byte(secret_offset_of_appended_data)) { return exeFileData, errors.New("compile-from file \"" + filespec + "\" is not valid slfsrv executable") } return }
func main() { var precompiled int = compiler.OffsetOfAppendedData() var err error = nil var bundleOut, compile, compileFrom, patharg, fullpatharg, initPathUrl, initQuery, storeFilespec, configFile string var helpWanted, compileReplaceOK, verbose, isdir bool var port int var cwd string var args []string var zipReader *zip.Reader rand.Seed(time.Now().Unix()) var myselfExecutable string myselfExecutable, err = osext.Executable() if err != nil { fmt.Fprintf(os.Stderr, "could not determine location of self-server executable\n") return } if precompiled != 0 { helpWanted = false bundleOut = "" compile = "" compileFrom = "" configFile = "" fullpatharg = "" patharg = "" compileReplaceOK = false isdir = false args = []string{} port, verbose, err = parse_compiled_command_line() if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) return } zipReader, initPathUrl, err = bundle.Reader(myselfExecutable, precompiled) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) return } storeFilespec = myselfExecutable + ".slfsrv-data" } else { // parse command-line inputs helpWanted, bundleOut, compile, compileFrom, compileReplaceOK, port, verbose, configFile, args, err = parse_command_line() if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) helpWanted = true } if helpWanted { usage() return } // figure out the initial path and root file to serve from if cwd, err = os.Getwd(); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } cwd = filepath.ToSlash(cwd) config.ParseConfigFile(configFile) settings := config.GetSettings() fmt.Printf("config: %+v\n", *settings) if settings.Port != 0 { port = settings.Port } if len(args) < 2 { initPathUrl = "" } else { initPathUrl = args[1] } if len(args) == 0 { patharg = cwd } else { patharg = filepath.ToSlash(path.Clean(args[0])) } var queryIdx int = strings.Index(initPathUrl, "?") if queryIdx == -1 { initQuery = "" } else { initQuery = initPathUrl[queryIdx+1:] initPathUrl = initPathUrl[:queryIdx] } if initPathUrl == "" { // figure out if path arg is just a path (in which case add index.htm or index.html) or a full file if isdir, err = ssutil.IsDir(patharg); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } if !isdir { patharg, initPathUrl = path.Split(patharg) } } fullpatharg = path.Clean(patharg) // if patharg is a subfolder of cwd then skip the cwd part so it is prettier patharg = ssutil.CleanPathRelativeToCwd(fullpatharg, cwd) // if initPathUrl not specified then guess at "index.htm" or "index.html" if initPathUrl == "" { var exists bool initPathUrl = "index.htm" if exists, _ = ssutil.FileOrDirExists(filepath.FromSlash(fullpatharg + "/" + initPathUrl)); !exists { initPathUrl = "index.html" } } storeFilespec = filepath.FromSlash(path.Join(fullpatharg, initPathUrl+".slfsrv-data")) } if bundleOut != "" { // BUNDLE into a standalone zip file if verbose { fmt.Printf("create compiled version from %s\n", filepath.FromSlash(patharg)) } bundleOut = ssutil.CleanPathRelativeToCwd(bundleOut, cwd) err = bundle.Bundle(bundleOut, compileReplaceOK, patharg, initPathUrl, verbose) if err == nil { if verbose { fmt.Println("bundle SUCCESS! Created:", bundleOut) } } if err != nil { fmt.Fprintf(os.Stderr, "ERROR: %s\n", err) } } else if compile != "" { // COMPILE if compileFrom == "" { compileFrom = myselfExecutable } compileFrom = ssutil.CleanPathRelativeToCwd(compileFrom, cwd) if verbose { fmt.Printf("create compiled version from %s executable\n", compileFrom) fmt.Printf("with source files from %s/%s\n", filepath.FromSlash(patharg), initPathUrl) } compile = ssutil.CleanPathRelativeToCwd(compile, cwd) err = compiler.Compile(compile, compileReplaceOK, compileFrom, patharg, initPathUrl, verbose) if err == nil { if verbose { fmt.Println("compilation SUCCESS! Created:", compile) } } if err != nil { fmt.Fprintf(os.Stderr, "ERROR: %s\n", err) } } else { // SERVE exitChan := make(chan int) // we may be reading from a pre-bundled file, determine now if that is the case if (precompiled == 0) && !isdir { var zip_initPathUrl string zipReader, zip_initPathUrl, err = bundle.Reader(path.Join(patharg, initPathUrl), 0) if err == nil { storeFilespec = filepath.FromSlash(path.Join(fullpatharg, initPathUrl) + ".slfsrv-data") initPathUrl = zip_initPathUrl } else { zipReader = nil } } var secretKey string var keepAliveSeconds int64 settings := config.GetSettings() if settings.SecretKey != "" { secretKey = settings.SecretKey } else { secretKey = generate_secret_key() } if settings.KeepAliveSeconds != 0 { keepAliveSeconds = settings.KeepAliveSeconds } else { keepAliveSeconds = 2 } port = webserver.ListenAndServe(port, secretKey, keepAliveSeconds, zipReader, patharg, fullpatharg, initPathUrl, verbose, exitChan, myselfExecutable, storeFilespec) browser.LaunchDefaultBrowser(port, secretKey, initPathUrl, initQuery, verbose) <-exitChan tempdir.Cleanup(verbose) } }
func Tempdir(prefix string, zipReader *zip.Reader, /*null if reading from raw files*/ rootPath string /*used if zipRead is nul*/, verbose bool) (tempdir string, err error) { tempdirMutex.Lock() defer tempdirMutex.Unlock() var foundInMap bool if tempdir, foundInMap = tempdirs[prefix]; foundInMap { // this prefix is already mapped, so nothing to do but return the existing mapping return } if tempdir, err = ioutil.TempDir("", "slfsrv-tmp-"+prefix); err != nil { return } if verbose { fmt.Println("Tempdir \"" + tempdir + "\" created for prefix \"" + prefix + "\"") } tempdirs[prefix] = tempdir if len(prefix) != 0 { // copy all the local files in our prefix directory to the temp dir if zipReader != nil { // read from the zip file var startsWith string = prefix + "/" // if if windows we store this slash type var startsWithLength int = len(startsWith) var f *zip.File for _, f = range zipReader.File { if strings.HasPrefix(f.Name, startsWith) { var rc io.ReadCloser if rc, err = f.Open(); err != nil { return } err = writeToTempDir(rc, tempdir, filepath.FromSlash(f.Name[startsWithLength:]), 0777 /*f.Mode()*/) if err != nil { rc.Close() } else { err = rc.Close() } } } } else { // read from the raw file system var isDir bool var copyFromDir string = filepath.Join(rootPath, prefix) if isDir, err = ssutil.IsDir(copyFromDir); (err == nil) && isDir { // prefix is a directory, so copy everything from it to tempdir var skipLen int = len(copyFromDir) + 1 walkFunc := func(path string, info os.FileInfo, err error) error { if err == nil { if !info.IsDir() { var relativePath string = path[skipLen:] var f *os.File if f, err = os.Open(path); err == nil { err = writeToTempDir(f, tempdir, relativePath, info.Mode()) if err != nil { f.Close() } else { err = f.Close() } } } } return err } if err = filepath.Walk(copyFromDir, walkFunc); err != nil { return } } } } return }
func Compile(exeOutPath string, replaceOK bool, exeInPath string, rootPath string, initialUrl string, verbose bool) (err error) { var exeFileData []byte // verify that exeInPath exists and is a file if _, err = mustBeARawSelfServingSourceFile(exeInPath); err != nil { return err } // output must be file name, not a directory var isDir bool if isDir, err = ssutil.IsDir(exeOutPath); err != nil { return err } if isDir { return errors.New("compile file \"" + exeOutPath + "\" must not be a directory") } // verify that there is not already an output file, or it's OK to create that file if !replaceOK { var fileOrDirExists bool if fileOrDirExists, err = ssutil.FileOrDirExists(exeOutPath); err != nil { return err } if fileOrDirExists { return errors.New("compile file \"" + exeOutPath + "\" already exists; cannot overwrite without -replace flag") } } // copy source file to destination (to make sure we get all attribute) switch runtime.GOOS { case "darwin", "linux": var cmd *exec.Cmd = exec.Command("cp", exeInPath, exeOutPath) if err = cmd.Run(); err != nil { return err } case "windows": var cmd *exec.Cmd = exec.Command("cmd.exe", "/C", "copy", exeInPath, exeOutPath) if err = cmd.Run(); err != nil { return err } default: return errors.New("Sorry, don't know how to copy file for OS " + runtime.GOOS) } // verify that exeInPath exists and is a file if exeFileData, err = mustBeARawSelfServingSourceFile(exeInPath); err != nil { return errors.New("error copying file \"" + exeInPath + "\" to " + "\"" + exeOutPath + "\"") } exeFileData = hardcode_startup_data_into_output_file(exeFileData) // zip all file data var zipContents *bytes.Buffer if zipContents, err = bundle.BundleDirectory(rootPath, initialUrl); err != nil { return err } // append zipContents to buffer var exeFileBuf *bytes.Buffer = bytes.NewBuffer(exeFileData) if _, err = exeFileBuf.Write(zipContents.Bytes()); err != nil { return err } err = saveAlteredOutputFile(exeOutPath, exeFileBuf.Bytes()) return }