Esempio n. 1
0
func (g *GraphTool) tarCp(srcName string, tw *tar.Writer) (int64, error) {
	var (
		src *os.File
		err error
	)

	if src, err = os.Open(srcName); err != nil {
		return 0, err
	}
	defer src.Close()

	srcStat, err := src.Stat()
	if err != nil {
		g.logger.Error(err.Error())
	} else if err := unix.Fadvise(int(src.Fd()), 0, srcStat.Size(), unix.MADV_SEQUENTIAL); err != nil {
		g.logger.Error(err.Error())
	}

	if n, err := io.Copy(tw, src); err != nil {
		g.logger.Error(err.Error())
	} else {
		return n, nil
	}

	return 0, nil
}
Esempio n. 2
0
// ClearCache syncs and then removes the file's content from the OS cache.
func ClearCache(file File) error {
	f, ok := file.(*os.File)
	if !ok {
		panic("ClearCache called for file not *os.File")
	}

	err := f.Sync()
	if err != nil {
		return err
	}

	return unix.Fadvise(int(f.Fd()), 0, 0, _POSIX_FADV_DONTNEED)
}
Esempio n. 3
0
func (f *nonCachingFile) Read(p []byte) (int, error) {
	n, err := f.File.Read(p)

	if n > 0 {
		ferr := unix.Fadvise(int(f.File.Fd()), f.readOffset, int64(n), _POSIX_FADV_DONTNEED)

		f.readOffset += int64(n)

		if err == nil {
			err = ferr
		}
	}

	return n, err
}
Esempio n. 4
0
func main() {
	var ok int // return status

	outStat, err := os.Stdout.Stat()
	if err != nil {
		fatal.Fatalln(err)
	}
	outReg := outStat.Mode().IsRegular()
	outBsize := bsize(outStat)

	// catch (./cat) < /etc/group
	args := flag.Args()
	if flag.NArg() == 0 {
		args = []string{"-"}
	}

	var file *os.File
	for _, arg := range args {
		file = os.Stdin
		if arg != "-" {
			file, err = os.Open(arg)
			if err != nil {
				fatal.Fatalln(err)
			}
		}

		inStat, err := file.Stat()
		if err != nil {
			fatal.Fatalln(err)
		}
		if inStat.IsDir() {
			fatal.Printf("%s: is a directory\n", file.Name())
		}
		inBsize := bsize(inStat)

		// prefetch! prefetch! prefetch!
		unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)

		// Make sure we're not catting a file to itself,
		// provided it's a regular file. Catting a non-reg
		// file to itself is cool.
		// e.g. cat file > file
		if outReg && os.SameFile(outStat, inStat) {
			if n, _ := file.Seek(0, os.SEEK_CUR); n < inStat.Size() {
				fatal.Fatalf("%s: input file is output file\n", file.Name())
			}
		}

		pageSize := os.Getpagesize()
		if simple {
			// Select larger block size
			size := max(inBsize, outBsize)
			outBuf := bufio.NewWriterSize(os.Stdout, size+pageSize-1)
			ok ^= simpleCat(file, outBuf)

			// Flush because we don't have a chance to in
			// simpleCat() because we use io.Copy()
			outBuf.Flush()
		} else {
			// If you want to know why, exactly, I chose
			// outBsize -1 + inBsize*4 + 20, read GNU's cat
			// source code. The tl;dr is the 20 is the counter
			// buffer, inBsize*4 is from potentially prepending
			// the control characters (M-^), and outBsize is
			// due to new tests for newlines.
			size := outBsize - 1 + inBsize*4 + 20
			outBuf := bufio.NewWriterSize(os.Stdout, size)
			inBuf := make([]byte, inBsize+pageSize-1)
			ok ^= cat(file, inBuf, outBuf)
		}

		file.Close()
	}

	os.Exit(ok)
}
Esempio n. 5
0
func wc(file *os.File, cur int64, status fstatus) int {
	// Our temp number of lines, words, chars, and bytes
	var (
		lines      int64
		words      int64
		chars      int64
		numBytes   int64
		lineLength int64

		buffer [bufferSize]byte

		// Return value.
		ok = 0
	)

	countComplicated := *printWords || *printLineLength

	if !*printBytes || *printChars || *printLines || countComplicated {
		unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)
	}

	// If we simply want the bytes we can ignore the overhead of
	// counting lines, chars, and words
	if *printBytes && !*printChars && !*printLines && !countComplicated {

		if status.failed != nil {
			status.stat, status.failed = file.Stat()
		}

		// For sized files, seek a block from EOF.
		// From GNU's source:
		//
		// "This works better for files in proc-like file systems where
		// the size is only approximate."
		if status.failed == nil &&
			// Regular file but not stdin.
			((status.stat.Mode().IsRegular() &&
				status.stat.Mode()&os.ModeCharDevice != 0) ||
				status.stat.Mode()&os.ModeSymlink != 0) &&
			0 < status.stat.Size() {

			numBytes = status.stat.Size()
			end := numBytes
			high := end - end%(blockSize+1)
			if cur < 0 {
				cur, _ = file.Seek(0, os.SEEK_CUR)
			}
			if 0 <= cur && cur < high {
				if n, _ := file.Seek(high, os.SEEK_CUR); 0 <= n {
					numBytes = high - cur
				}
			}
		}

		unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)
		for {
			n, err := file.Read(buffer[:])
			if err != nil {
				if err != io.EOF {
					ok = 1
				}
				break
			}
			numBytes += int64(n)
		}

		// Use a different loop to lower overhead if we're *only* counting
		// lines (or lines and bytes)
	} else if !*printChars && !countComplicated {
		for {
			n, err := file.Read(buffer[:])
			if err != nil {
				if err != io.EOF {
					ok = 1
				}
				break
			}

			// Go doesn't inline this sooo...
			for i := 0; i < n; i++ {
				if buffer[i] != '\n' {
					o := bytes.IndexByte(buffer[i:n], '\n')
					if o < 0 {
						break
					}
					i += o
				}
				lines++
			}
			numBytes += int64(n)
		}
	} else {
		var (
			inWord  int64
			linePos int64
		)
		for {
			n, err := file.Read(buffer[:])
			if err != nil {
				if err != io.EOF {
					ok = 1
				}
				break
			}

			numBytes += int64(n)

			for bp := 0; bp < n; {
				r, s := utf8.DecodeRune(buffer[bp:])

				switch r {
				case '\n':
					lines++
					fallthrough
				case '\r':
					fallthrough
				case '\f':
					if linePos > lineLength {
						lineLength = linePos
					}
					linePos = 0
					words += inWord
					inWord = 0
				case '\t':
					linePos += *tabWidth - (linePos % *tabWidth)
					words += inWord
					inWord = 0
				case ' ':
					linePos++
					fallthrough
				case '\v':
					words += inWord
					inWord = 0
				default:
					if unicode.IsPrint(r) {
						linePos++
						if unicode.IsSpace(r) {
							words += inWord
							inWord = 0
						}
						inWord = 1
					}
				}

				chars++
				bp += s
			}
		}
		if linePos > lineLength {
			lineLength = linePos
		}

		words += inWord
	}

	writeCounts(lines, words, chars, numBytes, lineLength, file.Name())

	totalBytes += numBytes
	totalChars += chars
	totalLines += lines
	totalWords += words

	if lineLength > maxLineLength {
		maxLineLength = lineLength
	}

	return ok
}
Esempio n. 6
0
func wc(file *os.File, cur int64, status *fstatus) int {
	// Our temp number of lines, words, chars, and bytes
	var (
		lines      int64
		words      int64
		chars      int64
		numBytes   int64
		lineLength int64
		linePos    int64
		inWord     int64

		buffer = make([]byte, BufferSize+1)

		// Return value.
		ok = 0
	)

	countComplicated := *printWords || *printLineLength

	if !*printBytes || *printChars || *printLines || countComplicated {
		unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)
	}

	// If we simply want the bytes we can ignore the overhead of
	// counting lines, chars, and words
	if *printBytes && !*printChars && !*printLines && !countComplicated {

		// Manually count bytes if Stat() failed or if we're reading from
		// piped input (e.g. cat file.csv | wc -c -)
		if status.stat == nil || status.stat.Mode()&os.ModeNamedPipe != 0 {

			unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)
			for {
				n, err := file.Read(buffer)
				if err != nil && err != io.EOF {
					ok = 1
					break
				}

				numBytes += int64(n)

				if err == io.EOF {
					break
				}
			}
		} else {
			numBytes = status.stat.Size()
			end := numBytes
			high := end - end%BufferSize
			if cur <= 0 {
				cur, _ = file.Seek(0, os.SEEK_CUR)
			}
			if 0 <= cur && cur < high {
				if n, _ := file.Seek(high, os.SEEK_CUR); 0 <= n {
					numBytes = high - cur
				}
			}
		}

		// Use a different loop to lower overhead if we're *only* counting
		// lines (or lines and bytes)
	} else if !*printChars && !countComplicated {
		for {
			n, err := file.Read(buffer)
			if err != nil && err != io.EOF {
				ok = 1
				break
			}

			lines += count(buffer[:n], NewLineByte)
			numBytes += int64(n)

			if err == io.EOF {
				break
			}
		}
	} else {
		for {
			n, err := file.Read(buffer)
			numBytes += int64(n)

			b := buffer[:n]

			for len(b) > 0 {
				r, s := utf8.DecodeRune(b)

				switch r {
				case NewLine:
					lines++
					fallthrough
				case Return:
					fallthrough
				case FormFeed:
					if linePos > lineLength {
						lineLength = linePos
					}
					linePos = 0
					words += inWord
					inWord = 0
				case HorizTab:
					linePos += *tabWidth - (linePos % *tabWidth)
					words += inWord
					inWord = 0
				case Space:
					linePos++
					fallthrough
				case VertTab:
					words += inWord
					inWord = 0
				default:
					if unicode.IsPrint(r) {
						linePos++
						inWord = 1
					}
				}

				chars++
				b = b[s:]
			}

			if err == io.EOF {
				break
			} else if err != nil {
				ok = 1
				break
			}
		}
		if linePos > lineLength {
			lineLength = linePos
		}

		words += inWord
	}

	writeCounts(lines, words, chars, numBytes, lineLength, file.Name())

	totalBytes += numBytes
	totalChars += chars
	totalLines += lines
	totalWords += words

	if lineLength > maxLineLength {
		maxLineLength = lineLength
	}

	return ok
}
Esempio n. 7
0
func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "%s", Help)
		os.Exit(1)
	}
	flag.Parse()

	if *version {
		fmt.Fprintf(os.Stdout, "%s", Version)
		os.Exit(0)
	}

	var (
		ok     int  // return status
		simple bool // no non-printing
	)

	// -vET
	if *all {
		*nonPrint = true
		*npTabs = true
		*npEnds = true
	}
	if *npEnds {
		*ends = true
	}
	if *blank {
		*number = true
	}
	if *npTabs {
		*tabs = true
	}
	if *all || *npEnds || *npTabs || *nonPrint {
		showNonPrinting = true
	}

	outStat, err := os.Stdout.Stat()
	if err != nil {
		fatal.Fatalln(err)
	}
	outReg := outStat.Mode().IsRegular()
	outBsize := int(outStat.Sys().(*syscall.Stat_t).Blksize)

	// catch (./cat) < /etc/group
	var args []string
	if flag.NArg() == 0 {
		args = []string{"-"}
	} else {
		args = flag.Args()
	}

	// the main loop
	var file *os.File
	for _, arg := range args {

		if arg == "-" {
			file = os.Stdin
		} else {
			file, err = os.Open(arg)
			if err != nil {
				fatal.Fatalln(err)
			}
		}

		inStat, err := file.Stat()
		if err != nil {
			fatal.Fatalln(err)
		}
		if inStat.IsDir() {
			fatal.Printf("%s: Is a directory\n", file.Name())
		}
		inBsize := int(inStat.Sys().(*syscall.Stat_t).Blksize)

		// prefetch! prefetch! prefetch!
		unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)

		// Make sure we're not catting a file to itself,
		// provided it's a regular file. Catting a non-reg
		// file to itself is cool.
		// e.g. cat file > file
		if outReg && os.SameFile(outStat, inStat) {
			if n, _ := file.Seek(0, os.SEEK_CUR); n < inStat.Size() {
				fatal.Fatalf("%s: input file is output file\n", file.Name())
			}
		}

		if simple {
			// Select larger block size
			size := max(inBsize, outBsize)
			outBuf := bufio.NewWriterSize(os.Stdout, size)
			ok ^= simpleCat(file, outBuf)

			// Flush because we don't have a chance to in
			// simpleCat() because we use io.Copy()
			outBuf.Flush()
		} else {
			// If you want to know why, exactly, I chose
			// outBsize -1 + inBsize*4 + 20, read GNU's cat
			// source code. The tl;dr is the 20 is the counter
			// buffer, inBsize*4 is from potentially prepending
			// the control characters (M-^), and outBsize is
			// due to new tests for newlines.
			size := outBsize - 1 + inBsize*4 + 20
			outBuf := bufio.NewWriterSize(os.Stdout, size)
			inBuf := make([]byte, inBsize+1)
			ok ^= cat(file, inBuf, outBuf)
		}

		file.Close()
	}

	os.Exit(ok)
}
Esempio n. 8
0
func wc(file *os.File, cur int64, status fstatus) int {
	// Our temp number of lines, words, chars, and bytes
	var (
		lines      int64
		words      int64
		chars      int64
		numBytes   int64
		lineLength int64

		buffer [BufferSize + 1]byte

		// Return value.
		ok = 0
	)

	countComplicated := *printWords || *printLineLength

	if !*printBytes || *printChars || *printLines || countComplicated {
		unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)
	}

	// If we simply want the bytes we can ignore the overhead of
	// counting lines, chars, and words
	if *printBytes && !*printChars && !*printLines && !countComplicated {

		// Manually count bytes if Stat() failed or if we're reading from
		// piped input (e.g. cat file.csv | wc -c -)
		if status.stat == nil || status.stat.Mode()&os.ModeNamedPipe != 0 {

			unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)
			for {
				n, err := file.Read(buffer[:])
				if err != nil {
					if err != io.EOF {
						ok = 1
					}
					break
				}
				numBytes += int64(n)
			}
		} else {
			numBytes = status.stat.Size()
			end := numBytes
			high := end - end%BufferSize
			if cur < 0 {
				cur, _ = file.Seek(0, os.SEEK_CUR)
			}
			if 0 <= cur && cur < high {
				if n, _ := file.Seek(high, os.SEEK_CUR); 0 <= n {
					numBytes = high - cur
				}
			}
		}

		// Use a different loop to lower overhead if we're *only* counting
		// lines (or lines and bytes)
	} else if !*printChars && !countComplicated {
		for {
			n, err := file.Read(buffer[:])
			if err != nil {
				if err != io.EOF {
					ok = 1
				}
				break
			}

			// Go doesn't inline this sooo...
			for i := 0; i < n; i++ {
				if buffer[i] != '\n' {
					o := bytes.IndexByte(buffer[i:n], '\n')
					if o < 0 {
						break
					}
					i += o
				}
				lines++
			}
			numBytes += int64(n)
		}
	} else {
		var (
			inWord  int64
			linePos int64
		)
		for {
			n, err := file.Read(buffer[:])
			if err != nil {
				if err != io.EOF {
					ok = 1
				}
				break
			}

			numBytes += int64(n)

			for bp := 0; bp < n; {
				r, s := utf8.DecodeRune(buffer[bp:])

				switch r {
				case '\n':
					lines++
					fallthrough
				case '\r':
					fallthrough
				case '\f':
					if linePos > lineLength {
						lineLength = linePos
					}
					linePos = 0
					words += inWord
					inWord = 0
				case '\t':
					linePos += *tabWidth - (linePos % *tabWidth)
					words += inWord
					inWord = 0
				case ' ':
					linePos++
					fallthrough
				case '\v':
					words += inWord
					inWord = 0
				default:
					if unicode.IsPrint(r) {
						linePos++
						if unicode.IsSpace(r) {
							words += inWord
							inWord = 0
						}
						inWord = 1
					}
				}

				chars++
				bp += s
			}
		}
		if linePos > lineLength {
			lineLength = linePos
		}

		words += inWord
	}

	writeCounts(lines, words, chars, numBytes, lineLength, file.Name())

	totalBytes += numBytes
	totalChars += chars
	totalLines += lines
	totalWords += words

	if lineLength > maxLineLength {
		maxLineLength = lineLength
	}

	return ok
}
Esempio n. 9
0
func tsort(rw io.ReadWriter) int {

	var (
		root = newItem("")

		j *item
		k *item

		ok int
	)

	scanner := bufio.NewScanner(rw)
	scanner.Split(bufio.ScanWords)

	// https://talks.golang.org/2015/tricks.slide#16
	if file, ok := rw.(interface {
		Fd() uintptr
	}); ok {
		unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)
	}

	for scanner.Scan() {
		k = root.searchItem(scanner.Text())

		if j != nil {
			recordRelation(j, k)
			k = nil
		}

		j = k
	}

	if k != nil {
		fatal.Fatalln("input contains an odd number of tokens")
	}

	root.walkTree(countItems)

	for numStrings > 0 {

		root.walkTree(scanZeros)

		for head != nil {
			p := head.top

			fmt.Fprintln(rw, head.str)

			head.str = ""
			numStrings--

			for p != nil {
				p.suc.count--
				if p.suc.count == 0 {
					zeros.qlink = p.suc
					zeros = p.suc
				}

				p = p.next
			}

			head = head.qlink
		}

		if numStrings > 0 {
			fatal.Print("tsort: input contains a loop:")
			ok = 1

			for {
				root.walkTree(detectLoop)

				if loop == nil {
					break
				}
			}
		}
	}

	return ok
}
Esempio n. 10
0
func tsort(file *os.File) int {
	root := newItem("")

	var (
		j *item = nil
		k *item = nil
	)

	ok := 0

	reader := bufio.NewReader(file)
	scanner := bufio.NewScanner(reader)
	scanner.Split(bufio.ScanWords)

	unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL)

	for scanner.Scan() {
		k = root.searchItem(scanner.Text())

		if j != nil {
			recordRelation(j, k)
			k = nil
		}

		j = k
	}

	if k != nil {
		fatal.Fatalln("input contains an odd number of tokens")
	}

	root.walkTree(countItems)

	for numStrings > 0 {

		root.walkTree(scanZeros)

		for head != nil {
			p := head.top

			fmt.Println(head.str)

			head.str = ""
			numStrings--

			for p != nil {
				p.suc.count--
				if p.suc.count == 0 {
					zeros.qlink = p.suc
					zeros = p.suc
				}

				p = p.next
			}

			head = head.qlink
		}

		if numStrings > 0 {
			fatal.Print("input contains a loop:")
			ok = 1

			for {
				root.walkTree(detectLoop)

				if loop == nil {
					break
				}
			}
		}
	}

	return ok
}