mirror of
				https://github.com/rclone/rclone.git
				synced 2025-10-30 23:17:59 +02:00 
			
		
		
		
	vfs: make sure all 96 combinations of flags for Open work
This commit is contained in:
		
							
								
								
									
										228
									
								
								vfs/make_open_tests.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								vfs/make_open_tests.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | ||||
| // This makes the open test suite | ||||
| // | ||||
| // Run with go run make_open_tests.go | gofmt > open_test.go | ||||
| // | ||||
| //+build none | ||||
|  | ||||
| // FIXME include read too? | ||||
|  | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // Interprets err into a vfs error | ||||
| func whichError(err error) string { | ||||
| 	switch err { | ||||
| 	case nil: | ||||
| 		return "nil" | ||||
| 	case io.EOF: | ||||
| 		return "io.EOF" | ||||
| 	} | ||||
| 	s := err.Error() | ||||
| 	switch { | ||||
| 	case strings.Contains(s, "no such file or directory"): | ||||
| 		return "ENOENT" | ||||
| 	case strings.Contains(s, "bad file descriptor"): | ||||
| 		return "EBADF" | ||||
| 	case strings.Contains(s, "file exists"): | ||||
| 		return "EEXIST" | ||||
| 	} | ||||
| 	log.Fatalf("Unknown error: %v", err) | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| // test Opening, reading and writing the file handle with the flags given | ||||
| func test(fileName string, flags int, mode string) { | ||||
| 	// first try with file not existing | ||||
| 	_, err := os.Stat(fileName) | ||||
| 	if !os.IsNotExist(err) { | ||||
| 		log.Fatalf("File must not exist") | ||||
| 	} | ||||
| 	f, openNonExistentErr := os.OpenFile(fileName, flags, 0666) | ||||
|  | ||||
| 	var readNonExistentErr error | ||||
| 	var writeNonExistentErr error | ||||
| 	if openNonExistentErr == nil { | ||||
| 		// read some bytes | ||||
| 		buf := []byte{0, 0} | ||||
| 		_, readNonExistentErr = f.Read(buf) | ||||
|  | ||||
| 		// write some bytes | ||||
| 		_, writeNonExistentErr = f.Write([]byte("hello")) | ||||
|  | ||||
| 		// close | ||||
| 		err = f.Close() | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("failed to close: %v", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// write the file | ||||
| 	f, err = os.Create(fileName) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("failed to create: %v", err) | ||||
| 	} | ||||
| 	n, err := f.Write([]byte("hello")) | ||||
| 	if n != 5 || err != nil { | ||||
| 		log.Fatalf("failed to write n=%d: %v", n, err) | ||||
| 	} | ||||
| 	// close | ||||
| 	err = f.Close() | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("failed to close: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// then open file and try with file existing | ||||
|  | ||||
| 	f, openExistingErr := os.OpenFile(fileName, flags, 0666) | ||||
| 	var readExistingErr error | ||||
| 	var writeExistingErr error | ||||
| 	if openExistingErr == nil { | ||||
| 		// read some bytes | ||||
| 		buf := []byte{0, 0} | ||||
| 		_, readExistingErr = f.Read(buf) | ||||
|  | ||||
| 		// write some bytes | ||||
| 		n, writeExistingErr = f.Write([]byte("HEL")) | ||||
|  | ||||
| 		// close | ||||
| 		err = f.Close() | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("failed to close: %v", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// read the file | ||||
| 	f, err = os.Open(fileName) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("failed to open: %v", err) | ||||
| 	} | ||||
| 	var buf = make([]byte, 64) | ||||
| 	n, err = f.Read(buf) | ||||
| 	if err != nil && err != io.EOF { | ||||
| 		log.Fatalf("failed to read n=%d: %v", n, err) | ||||
| 	} | ||||
| 	err = f.Close() | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("failed to close: %v", err) | ||||
| 	} | ||||
| 	contents := string(buf[:n]) | ||||
|  | ||||
| 	// remove file | ||||
| 	err = os.Remove(fileName) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("failed to remove: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// output the struct | ||||
| 	fmt.Printf(`{ | ||||
| 	flags: %s, | ||||
| 	what: %q, | ||||
| 	openNonExistentErr: %s, | ||||
| 	readNonExistentErr: %s, | ||||
| 	writeNonExistentErr: %s, | ||||
| 	openExistingErr: %s, | ||||
| 	readExistingErr: %s, | ||||
| 	writeExistingErr: %s, | ||||
| 	contents: %q, | ||||
| },`, | ||||
| 		mode, | ||||
| 		mode, | ||||
| 		whichError(openNonExistentErr), | ||||
| 		whichError(readNonExistentErr), | ||||
| 		whichError(writeNonExistentErr), | ||||
| 		whichError(openExistingErr), | ||||
| 		whichError(readExistingErr), | ||||
| 		whichError(writeExistingErr), | ||||
| 		contents) | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	fmt.Printf(`// data generated by go run make_open_tests.go | gofmt > open_test.go | ||||
|  | ||||
| package vfs | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| // openTest describes a test of OpenFile | ||||
| type openTest struct{ | ||||
| 	flags int | ||||
| 	what string | ||||
| 	openNonExistentErr error | ||||
| 	readNonExistentErr error | ||||
| 	writeNonExistentErr error | ||||
| 	openExistingErr error | ||||
| 	readExistingErr error | ||||
| 	writeExistingErr error | ||||
| 	contents string | ||||
| } | ||||
|  | ||||
| // openTests is a suite of tests for OpenFile with all possible | ||||
| // combination of flags.  This obeys Unix semantics even on Windows. | ||||
| var openTests = []openTest{ | ||||
| `) | ||||
| 	f, err := ioutil.TempFile("", "open-test") | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	fileName := f.Name() | ||||
| 	_ = f.Close() | ||||
| 	err = os.Remove(fileName) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("failed to remove: %v", err) | ||||
| 	} | ||||
| 	for _, rwMode := range []int{os.O_RDONLY, os.O_WRONLY, os.O_RDWR} { | ||||
| 		flags0 := rwMode | ||||
| 		parts0 := []string{"os.O_RDONLY", "os.O_WRONLY", "os.O_RDWR"}[rwMode : rwMode+1] | ||||
| 		for _, appendMode := range []int{0, os.O_APPEND} { | ||||
| 			flags1 := flags0 | appendMode | ||||
| 			parts1 := parts0 | ||||
| 			if appendMode != 0 { | ||||
| 				parts1 = append(parts1, "os.O_APPEND") | ||||
| 			} | ||||
| 			for _, createMode := range []int{0, os.O_CREATE} { | ||||
| 				flags2 := flags1 | createMode | ||||
| 				parts2 := parts1 | ||||
| 				if createMode != 0 { | ||||
| 					parts2 = append(parts2, "os.O_CREATE") | ||||
| 				} | ||||
| 				for _, exclMode := range []int{0, os.O_EXCL} { | ||||
| 					flags3 := flags2 | exclMode | ||||
| 					parts3 := parts2 | ||||
| 					if exclMode != 0 { | ||||
| 						parts3 = append(parts2, "os.O_EXCL") | ||||
| 					} | ||||
| 					for _, syncMode := range []int{0, os.O_SYNC} { | ||||
| 						flags4 := flags3 | syncMode | ||||
| 						parts4 := parts3 | ||||
| 						if syncMode != 0 { | ||||
| 							parts4 = append(parts4, "os.O_SYNC") | ||||
| 						} | ||||
| 						for _, truncMode := range []int{0, os.O_TRUNC} { | ||||
| 							flags5 := flags4 | truncMode | ||||
| 							parts5 := parts4 | ||||
| 							if truncMode != 0 { | ||||
| 								parts5 = append(parts5, "os.O_TRUNC") | ||||
| 							} | ||||
| 							textMode := strings.Join(parts5, "|") | ||||
| 							flags := flags5 | ||||
|  | ||||
| 							test(fileName, flags, textMode) | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	fmt.Printf("\n}\n") | ||||
| } | ||||
							
								
								
									
										987
									
								
								vfs/open_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										987
									
								
								vfs/open_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,987 @@ | ||||
| // data generated by go run make_open_tests.go | gofmt > open_test.go | ||||
|  | ||||
| package vfs | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| // openTest describes a test of OpenFile | ||||
| type openTest struct { | ||||
| 	flags               int | ||||
| 	what                string | ||||
| 	openNonExistentErr  error | ||||
| 	readNonExistentErr  error | ||||
| 	writeNonExistentErr error | ||||
| 	openExistingErr     error | ||||
| 	readExistingErr     error | ||||
| 	writeExistingErr    error | ||||
| 	contents            string | ||||
| } | ||||
|  | ||||
| // openTests is a suite of tests for OpenFile with all possible | ||||
| // combination of flags.  This obeys Unix semantics even on Windows. | ||||
| var openTests = []openTest{ | ||||
| 	{ | ||||
| 		flags:               os.O_RDONLY, | ||||
| 		what:                "os.O_RDONLY", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_SYNC, | ||||
| 		what:                "os.O_RDONLY|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_EXCL, | ||||
| 		what:                "os.O_RDONLY|os.O_EXCL", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_RDONLY|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_CREATE, | ||||
| 		what:                "os.O_RDONLY|os.O_CREATE", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_CREATE | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_CREATE|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_CREATE | os.O_SYNC, | ||||
| 		what:                "os.O_RDONLY|os.O_CREATE|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_CREATE | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_CREATE | os.O_EXCL, | ||||
| 		what:                "os.O_RDONLY|os.O_CREATE|os.O_EXCL", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_CREATE | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_CREATE|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_CREATE | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_RDONLY|os.O_CREATE|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_CREATE | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_SYNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_EXCL, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_EXCL", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_CREATE, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_CREATE", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_SYNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    EBADF, | ||||
| 		contents:            "", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: EBADF, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY, | ||||
| 		what:                "os.O_WRONLY", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HELlo", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_SYNC, | ||||
| 		what:                "os.O_WRONLY|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HELlo", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_EXCL, | ||||
| 		what:                "os.O_WRONLY|os.O_EXCL", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HELlo", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_WRONLY|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HELlo", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_CREATE, | ||||
| 		what:                "os.O_WRONLY|os.O_CREATE", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HELlo", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_CREATE | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_CREATE|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_CREATE | os.O_SYNC, | ||||
| 		what:                "os.O_WRONLY|os.O_CREATE|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HELlo", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_CREATE | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_CREATE | os.O_EXCL, | ||||
| 		what:                "os.O_WRONLY|os.O_CREATE|os.O_EXCL", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_CREATE | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_CREATE|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_CREATE | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_WRONLY|os.O_CREATE|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_CREATE | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_SYNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_EXCL, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_EXCL", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_CREATE, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_CREATE", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_SYNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     EBADF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  EBADF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR, | ||||
| 		what:                "os.O_RDWR", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "heHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_SYNC, | ||||
| 		what:                "os.O_RDWR|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "heHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_EXCL, | ||||
| 		what:                "os.O_RDWR|os.O_EXCL", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "heHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_RDWR|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "heHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_CREATE, | ||||
| 		what:                "os.O_RDWR|os.O_CREATE", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "heHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_CREATE | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_CREATE|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_CREATE | os.O_SYNC, | ||||
| 		what:                "os.O_RDWR|os.O_CREATE|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "heHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_CREATE | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_CREATE|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_CREATE | os.O_EXCL, | ||||
| 		what:                "os.O_RDWR|os.O_CREATE|os.O_EXCL", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_CREATE | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_CREATE | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_CREATE | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_SYNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_EXCL, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_EXCL", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  ENOENT, | ||||
| 		readNonExistentErr:  nil, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_CREATE, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_CREATE", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_SYNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "helloHEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     nil, | ||||
| 		readExistingErr:     io.EOF, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "HEL", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_EXCL, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_EXCL", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_SYNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_SYNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, { | ||||
| 		flags:               os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_SYNC | os.O_TRUNC, | ||||
| 		what:                "os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC", | ||||
| 		openNonExistentErr:  nil, | ||||
| 		readNonExistentErr:  io.EOF, | ||||
| 		writeNonExistentErr: nil, | ||||
| 		openExistingErr:     EEXIST, | ||||
| 		readExistingErr:     nil, | ||||
| 		writeExistingErr:    nil, | ||||
| 		contents:            "hello", | ||||
| 	}, | ||||
| } | ||||
| @@ -3,6 +3,7 @@ package vfs | ||||
| import ( | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"runtime" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/ncw/rclone/fs" | ||||
| @@ -44,6 +45,11 @@ func newRWFileHandle(d *Dir, f *File, remote string, flags int) (fh *RWFileHandl | ||||
| 		return nil, errors.Wrap(err, "open RW handle failed to make cache directory") | ||||
| 	} | ||||
|  | ||||
| 	// if O_CREATE and O_EXCL are set and if path already exists, then return EEXIST | ||||
| 	if flags&(os.O_CREATE|os.O_EXCL) == os.O_CREATE|os.O_EXCL && f.exists() { | ||||
| 		return nil, EEXIST | ||||
| 	} | ||||
|  | ||||
| 	fh = &RWFileHandle{ | ||||
| 		o:      f.o, | ||||
| 		file:   f, | ||||
| @@ -69,6 +75,8 @@ func (fh *RWFileHandle) openPending(truncate bool) (err error) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	cacheFileOpenFlags := fh.flags | ||||
|  | ||||
| 	// if not truncating the file, need to read it first | ||||
| 	if fh.flags&os.O_TRUNC == 0 && !truncate { | ||||
| 		// Fetch the file if it hasn't changed | ||||
| @@ -92,12 +100,30 @@ func (fh *RWFileHandle) openPending(truncate bool) (err error) { | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		// Set the size to 0 since we are truncating | ||||
| 		// Set the size to 0 since we are truncating and flag we need to write it back | ||||
| 		fh.file.setSize(0) | ||||
| 		fh.writeCalled = true | ||||
| 		if fh.flags&os.O_CREATE != 0 && fh.file.exists() { | ||||
| 			// create and empty file if it exists on the source | ||||
| 			cacheFileOpenFlags |= os.O_CREATE | ||||
| 		} | ||||
| 		// Windows doesn't seem to deal well with O_TRUNC and | ||||
| 		// certain access modes so so truncate the file if it | ||||
| 		// exists in these cases. | ||||
| 		if runtime.GOOS == "windows" && (fh.flags&accessModeMask == os.O_RDONLY || fh.flags|os.O_APPEND != 0) { | ||||
| 			cacheFileOpenFlags &^= os.O_TRUNC | ||||
| 			_, err = os.Stat(fh.osPath) | ||||
| 			if err == nil { | ||||
| 				err = os.Truncate(fh.osPath, 0) | ||||
| 				if err != nil { | ||||
| 					return errors.Wrap(err, "cache open failed to truncate") | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	fs.Debugf(fh.remote, "Opening cached copy with flags=%s", decodeOpenFlags(fh.flags)) | ||||
| 	fd, err := os.OpenFile(fh.osPath, fh.flags|os.O_CREATE, 0600) | ||||
| 	fd, err := os.OpenFile(fh.osPath, cacheFileOpenFlags, 0600) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "cache open file failed") | ||||
| 	} | ||||
| @@ -180,8 +206,8 @@ func (fh *RWFileHandle) close() (err error) { | ||||
|  | ||||
| 	// FIXME measure whether we actually did any writes or not - | ||||
| 	// no writes means no transfer? | ||||
| 	if rdwrMode == os.O_RDONLY { | ||||
| 		fs.Debugf(fh.remote, "read only so not transferring") | ||||
| 	if rdwrMode == os.O_RDONLY && fh.flags&os.O_TRUNC == 0 { | ||||
| 		fs.Debugf(fh.remote, "read only and not truncating so not transferring") | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| @@ -302,30 +328,35 @@ func (fh *RWFileHandle) Stat() (os.FileInfo, error) { | ||||
| 	return fh.file, nil | ||||
| } | ||||
|  | ||||
| // Read bytes from the file | ||||
| func (fh *RWFileHandle) Read(b []byte) (n int, err error) { | ||||
| // readFn is a general purpose read function - pass in a closure to do | ||||
| // the actual read | ||||
| func (fh *RWFileHandle) readFn(read func() (int, error)) (n int, err error) { | ||||
| 	fh.mu.Lock() | ||||
| 	defer fh.mu.Unlock() | ||||
| 	if fh.closed { | ||||
| 		return 0, ECLOSED | ||||
| 	} | ||||
| 	if fh.flags&accessModeMask == os.O_WRONLY { | ||||
| 		return 0, EBADF | ||||
| 	} | ||||
| 	if err = fh.openPending(false); err != nil { | ||||
| 		return n, err | ||||
| 	} | ||||
| 	return fh.File.Read(b) | ||||
| 	return read() | ||||
| } | ||||
|  | ||||
| // Read bytes from the file | ||||
| func (fh *RWFileHandle) Read(b []byte) (n int, err error) { | ||||
| 	return fh.readFn(func() (int, error) { | ||||
| 		return fh.File.Read(b) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // ReadAt bytes from the file at off | ||||
| func (fh *RWFileHandle) ReadAt(b []byte, off int64) (n int, err error) { | ||||
| 	fh.mu.Lock() | ||||
| 	defer fh.mu.Unlock() | ||||
| 	if fh.closed { | ||||
| 		return 0, ECLOSED | ||||
| 	} | ||||
| 	if err = fh.openPending(false); err != nil { | ||||
| 		return n, err | ||||
| 	} | ||||
| 	return fh.File.ReadAt(b, off) | ||||
| 	return fh.readFn(func() (int, error) { | ||||
| 		return fh.File.ReadAt(b, off) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Seek to new file position | ||||
| @@ -350,6 +381,9 @@ func (fh *RWFileHandle) writeFn(write func() error) (err error) { | ||||
| 	if fh.closed { | ||||
| 		return ECLOSED | ||||
| 	} | ||||
| 	if fh.flags&accessModeMask == os.O_RDONLY { | ||||
| 		return EBADF | ||||
| 	} | ||||
| 	if err = fh.openPending(false); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -421,5 +455,8 @@ func (fh *RWFileHandle) Sync() error { | ||||
| 	if !fh.opened { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if fh.flags&accessModeMask == os.O_RDONLY { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fh.File.Sync() | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package vfs | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| @@ -286,6 +287,10 @@ func TestRWFileHandleMethodsWrite(t *testing.T) { | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, 7, n) | ||||
|  | ||||
| 	// Sync | ||||
| 	err = fh.Sync() | ||||
| 	assert.NoError(t, err) | ||||
|  | ||||
| 	// Stat | ||||
| 	var fi os.FileInfo | ||||
| 	fi, err = fh.Stat() | ||||
| @@ -434,3 +439,87 @@ func TestRWFileHandleReleaseWrite(t *testing.T) { | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.True(t, fh.closed) | ||||
| } | ||||
|  | ||||
| func testRWFileHandleOpenTest(t *testing.T, vfs *VFS, test *openTest) { | ||||
| 	fileName := "open-test-file" | ||||
|  | ||||
| 	// first try with file not existing | ||||
| 	_, err := vfs.Stat(fileName) | ||||
| 	require.True(t, os.IsNotExist(err), test.what) | ||||
|  | ||||
| 	f, openNonExistentErr := vfs.OpenFile(fileName, test.flags, 0666) | ||||
|  | ||||
| 	var readNonExistentErr error | ||||
| 	var writeNonExistentErr error | ||||
| 	if openNonExistentErr == nil { | ||||
| 		// read some bytes | ||||
| 		buf := []byte{0, 0} | ||||
| 		_, readNonExistentErr = f.Read(buf) | ||||
|  | ||||
| 		// write some bytes | ||||
| 		_, writeNonExistentErr = f.Write([]byte("hello")) | ||||
|  | ||||
| 		// close | ||||
| 		err = f.Close() | ||||
| 		require.NoError(t, err, test.what) | ||||
| 	} | ||||
|  | ||||
| 	// write the file | ||||
| 	f, err = vfs.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0777) | ||||
| 	require.NoError(t, err, test.what) | ||||
| 	_, err = f.Write([]byte("hello")) | ||||
| 	require.NoError(t, err, test.what) | ||||
| 	err = f.Close() | ||||
| 	require.NoError(t, err, test.what) | ||||
|  | ||||
| 	// then open file and try with file existing | ||||
|  | ||||
| 	f, openExistingErr := vfs.OpenFile(fileName, test.flags, 0666) | ||||
| 	var readExistingErr error | ||||
| 	var writeExistingErr error | ||||
| 	if openExistingErr == nil { | ||||
| 		// read some bytes | ||||
| 		buf := []byte{0, 0} | ||||
| 		_, readExistingErr = f.Read(buf) | ||||
|  | ||||
| 		// write some bytes | ||||
| 		_, writeExistingErr = f.Write([]byte("HEL")) | ||||
|  | ||||
| 		// close | ||||
| 		err = f.Close() | ||||
| 		require.NoError(t, err, test.what) | ||||
| 	} | ||||
|  | ||||
| 	// read the file | ||||
| 	f, err = vfs.OpenFile(fileName, os.O_RDONLY, 0) | ||||
| 	require.NoError(t, err, test.what) | ||||
| 	buf, err := ioutil.ReadAll(f) | ||||
| 	require.NoError(t, err, test.what) | ||||
| 	err = f.Close() | ||||
| 	require.NoError(t, err, test.what) | ||||
| 	contents := string(buf) | ||||
|  | ||||
| 	// remove file | ||||
| 	node, err := vfs.Stat(fileName) | ||||
| 	require.NoError(t, err, test.what) | ||||
| 	err = node.Remove() | ||||
| 	require.NoError(t, err, test.what) | ||||
|  | ||||
| 	// check | ||||
| 	assert.Equal(t, test.readNonExistentErr, readNonExistentErr, "readNonExistentErr: %s: want=%v, got=%v", test.what, test.readNonExistentErr, readNonExistentErr) | ||||
| 	assert.Equal(t, test.writeNonExistentErr, writeNonExistentErr, "writeNonExistentErr: %s: want=%v, got=%v", test.what, test.writeNonExistentErr, writeNonExistentErr) | ||||
| 	assert.Equal(t, test.readExistingErr, readExistingErr, "readExistingErr: %s: want=%v, got=%v", test.what, test.readExistingErr, readExistingErr) | ||||
| 	assert.Equal(t, test.writeExistingErr, writeExistingErr, "writeExistingErr: %s: want=%v, got=%v", test.what, test.writeExistingErr, writeExistingErr) | ||||
| 	assert.Equal(t, test.contents, contents, test.what) | ||||
| } | ||||
|  | ||||
| func TestRWFileHandleOpenTests(t *testing.T) { | ||||
| 	r := fstest.NewRun(t) | ||||
| 	defer r.Finalise() | ||||
|  | ||||
| 	vfs := New(r.Fremote, nil) | ||||
| 	vfs.Opt.CacheMode = CacheModeFull | ||||
| 	for _, test := range openTests { | ||||
| 		testRWFileHandleOpenTest(t, vfs, &test) | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user