示例#1
0
// Change the working directory of the process, and verify that we can open a
// file using the relative path.
func TestChdir(test *testing.T) {
	fs, proc := OpenMinixImage(test)

	// Change into /var and then try to open run/syslogd.pid
	if err := proc.Chdir("/var"); err != nil {
		testutils.FatalHere(test, "Failed to change directory: %s", err)
	}
	if proc.workdir.Inum != 543 {
		testutils.FatalHere(test, "Got wrong inode expected %d, got %d", 543, proc.workdir.Inum)
	}

	// Fetch something with a relative path
	rip, err := fs.eatPath(proc, "run/syslogd.pid")
	if err != nil {
		testutils.FatalHere(test, "Could not open relative file: %s", err)
	}
	if rip.Inum != 481 {
		testutils.FatalHere(test, "Got wrong inode expected %d, got %d", 481, rip.Inum)
	}

	fs.itable.PutInode(rip)

	err = fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed when shutting down filesystem: %s", err)
	}
}
示例#2
0
// Ensure that an open process prevents clean shutdown
func TestSpawnNoExit(test *testing.T) {
	fs, proc := OpenMinixImage(test)

	_, err := proc.Fork()
	if err != nil {
		testutils.FatalHere(test, "Failed when spawning new process: %s", err)
	}

	err = fs.Shutdown()
	if err != common.EBUSY {
		testutils.FatalHere(test, "Expected EBUSY error, got: %v", err)
	}
}
示例#3
0
// Create a new file on the file system, ensure that it is given the
// appropriate inode number and created successfully. Then unlink the file
// so the file system remains in the same state it began in.
func TestCreateThenUnlink(test *testing.T) {
	fs, proc := OpenMinixImage(test)
	alloc := proc.rootdir.Devinfo.AllocTbl

	// Check the state of the bitmap before creating this file
	inum, err := alloc.AllocInode()
	if err != nil {
		testutils.FatalHere(test, "Error pre-allocating an inode: %s", err)
	}
	alloc.FreeInode(inum)

	// Get block 13 and print it before we make any changes
	//bp := fs.bcache.GetBlock(ROOT_DEVICE, 13, INODE_BLOCK, NORMAL)
	//debug.PrintBlock(bp, fs.devinfo[ROOT_DEVICE])

	// Create a new file and check allocation tables, etc.
	file, err := fs.Open(proc, "/tmp/created_file", common.O_CREAT, 0666)
	if err != nil {
		testutils.FatalHere(test, "Failed when creating new file: %s", err)
	}
	filp := file.(*filp)
	if filp.inode.Inum != inum {
		testutils.ErrorHere(test, "Inum mismatch expected %d, got %d", inum, filp.inode.Inum)
	}

	// Close and unlink the new file
	err = fs.Close(proc, file)
	if err != nil {
		testutils.ErrorHere(test, "Failed when closing new file: %s", err)
	}
	err = fs.Unlink(proc, "/tmp/created_file")
	if err != nil {
		testutils.ErrorHere(test, "Failed when unlinking new file: %s", err)
	}

	// The bit we just freed should be our next
	inum2, err := alloc.AllocInode()
	if err != nil {
		testutils.FatalHere(test, "Failed when checking inode allocation: %s", err)
	}
	if inum != inum2 {
		testutils.FatalHere(test, "Inode mismatch expected %d, got %d", inum, inum2)
	}
	alloc.FreeInode(inum2)

	fs.Exit(proc)
	err = fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed when shutting down filesystem: %s", err)
	}
}
示例#4
0
// Ensure cleanup happens properly with fork/exit
func TestForkWithExit(test *testing.T) {
	fs, proc := OpenMinixImage(test)

	child, err := proc.Fork()
	if err != nil {
		testutils.FatalHere(test, "Failed when spawning new process: %s", err)
	}

	child.Exit()
	err = fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed when shutting down filesystem: %s", err)
	}
}
示例#5
0
func TestShutdownNoRootProcExit(test *testing.T) {
	fs, _ := OpenMinixImage(test)
	err := fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed shutting down: %s", err)
	}
}
示例#6
0
func OpenEuroparl(test *testing.T) *os.File {
	filename := getExtraFilename("europarl-en.txt")
	file, err := os.OpenFile(filename, os.O_RDONLY, 0666)
	if err != nil {
		testutils.FatalHere(test, "Could not open Europarl reference: %s", err)
	}
	return file
}
示例#7
0
func OpenMinixImage(test *testing.T) (*FileSystem, *Process) {
	imageFilename := getExtraFilename("minix3root.img")
	fs, proc, err := OpenFileSystemFile(imageFilename)
	if err != nil {
		testutils.FatalHere(test, "Failed opening file system: %s", err)
	}
	return fs, proc
}
示例#8
0
// Test read functionality by reading the same file from the guest/host
// operating systems and comparing the results of sucessive read calls. The
// number of bytes read per call is set to (4/3) of the block size of the file
// system to ensure that we hit all codepaths.
func TestRead(test *testing.T) {
	fs, proc := OpenMinixImage(test)
	file, err := fs.Open(proc, "/sample/europarl-en.txt", common.O_RDONLY, 0666)
	if err != nil {
		testutils.FatalHere(test, "Failed when opening file: %s", err)
	}

	ofile := OpenEuroparl(test)

	// Read and compare the two files
	blocksize := fs.devinfo[common.ROOT_DEVICE].Blocksize
	numbytes := blocksize + (blocksize / 3)

	data := make([]byte, numbytes)
	odata := make([]byte, numbytes)
	offset := 0

	for {
		n, err := file.Read(data)
		od, oerr := ofile.Read(odata)

		if n != od {
			testutils.FatalHere(test, "Bytes read mismatch at offset %d: expected %d, got %d", offset, od, n)
		}
		if err != oerr {
			testutils.FatalHere(test, "Error mismatch at offset %d: expected '%s', got '%s'", offset, oerr, err)
		}
		if bytes.Compare(data, odata) != 0 {
			testutils.FatalHere(test, "Data mismatch at offset %d\n==Expected\n%s\n==Got\n%s", offset, odata, data)
		}

		if err == io.EOF && oerr == io.EOF {
			break
		}

		offset += n
	}

	fs.Exit(proc)
	err = fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed when shutting down filesystem: %s", err)
	}
}
示例#9
0
// Test that we can open and close a file
func TestOpenClose(test *testing.T) {
	fs, proc := OpenMinixImage(test)

	file, err := proc.Open("/sample/europarl-en.txt", common.O_RDONLY, 0666)
	if err != nil {
		testutils.FatalHere(test, "Failed opening file: %s", err)
	}

	found, count := checkFileAndCount(proc, file)

	if !found {
		testutils.FatalHere(test, "Did not find open file in proc.files")
	}
	if count != 1 {
		testutils.FatalHere(test, "Open file count incorrect got %d, expected %d", count, 1)
	}

	// Now close the file and make sure things are cleaned up
	err = proc.Close(file)

	found, count = checkFileAndCount(proc, file)

	if found {
		testutils.FatalHere(test, "Found file in process table, should not have")
	}
	if count != 0 {
		testutils.FatalHere(test, "Open file count mismatch got %d, expected %d", count, 0)
	}

	// How many goroutines are open right now?
	numgoros := runtime.NumGoroutine()
	stacknow := make([]byte, 4096)
	runtime.Stack(stacknow, true)

	fs.Exit(proc)
	err = fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed when shutting down filesystem: %s", err)
	}

	// We expect shutdown to have killed the following goroutines
	//  * device
	//  * block cache
	//  * inode cache
	//  * allocation table
	//  * file server

	// This test is fragile, so be careful with it!
	expected := numgoros - 5
	if runtime.NumGoroutine() != expected {
		test.Logf("Original stack:\n%s\n", stacknow)
		newstack := make([]byte, 4096)
		runtime.Stack(newstack, true)
		test.Logf("Current stack:\n%s\n", newstack)
		testutils.FatalHere(test, "Goroutine count mismatch got %d, expected %d", expected, runtime.NumGoroutine())
	}
}
示例#10
0
// Test changin the position within an open file using the same technique as
// TestRead, by comparing to the POSIX API provided by the Go standard
// libraries corresponding calls.
func TestSeek(test *testing.T) {
	fs, proc := OpenMinixImage(test)

	file, err := fs.Open(proc, "/sample/europarl-en.txt", common.O_RDONLY, 0666)
	if err != nil {
		testutils.FatalHere(test, "Failed when opening file: %s", err)
	}

	ofile := OpenEuroparl(test)

	type seekData struct {
		whence int
		pos    int
	}

	seekOps := []seekData{
		{0, 0},
		{0, 31337},
		{1, 3333},
	}

	// Read and compare several blocks of the file, seeking between each read.
	// This ensures that our seek behaviour is the same as POSIX.
	blocksize := fs.devinfo[common.ROOT_DEVICE].Blocksize
	numbytes := blocksize + (blocksize / 3)

	data := make([]byte, numbytes)
	odata := make([]byte, numbytes)

	for idx, testData := range seekOps {
		pos, err := file.Seek(testData.pos, testData.whence)
		opos, err := ofile.Seek(int64(testData.pos), testData.whence)

		if int64(pos) != opos {
			testutils.FatalHere(test, "Seek position mismatch in test %d: exected %d, got %d", idx, opos, pos)
		}

		n, err := file.Read(data)
		od, oerr := ofile.Read(odata)

		if n != od {
			testutils.FatalHere(test, "Bytes read mismatch at offset %d: expected %d, got %d", idx, od, n)
		}
		if err != oerr {
			testutils.FatalHere(test, "Error mismatch at offset %d: expected '%s', got '%s'", idx, oerr, err)
		}
		if bytes.Compare(data, odata) != 0 {
			testutils.FatalHere(test, "Data mismatch at offset %d\n==Expected\n%s\n==Got\n%s", idx, odata, data)
		}
	}

	fs.Exit(proc)
	err = fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed when shutting down filesystem: %s", err)
	}
}
示例#11
0
// Make a new directory on the file system, ensure that it is given the
// appropriate number/contents, then rmdir the file and check that the file
// system is returned to its initial state.
func TestMkdir(test *testing.T) {
	fs, proc := OpenMinixImage(test)
	bitmap := proc.rootdir.Devinfo.AllocTbl

	// Check the state of the bitmaps before creating this file
	inum, err := bitmap.AllocInode()
	if err != nil {
		testutils.FatalHere(test, "Error pre-allocating an inode: %s", err)
	}
	bitmap.FreeInode(inum)

	znum, err := bitmap.AllocZone(common.NO_ZONE)
	if err != nil {
		testutils.FatalHere(test, "Error pre-allocating a zone: %s", err)
	}
	bitmap.FreeZone(znum)

	// Create a new file and check allocation tables, etc.
	err = fs.Mkdir(proc, "/tmp/new_directory", 0666)
	if err != nil {
		testutils.FatalHere(test, "Failed when creating new directory: %s", err)
	}

	dirp, err := fs.eatPath(proc, "/tmp/new_directory")
	if err != nil {
		testutils.FatalHere(test, "Failed when looking up new directory: %s", err)
	}
	if dirp.Inum != inum {
		testutils.ErrorHere(test, "Inum mismatch expected %d, got %d", inum, dirp.Inum)
	}
	ok, devnum, inum := Lookup(dirp, ".")
	if !ok {
		testutils.ErrorHere(test, "Current directory . lookup failed")
	}
	if devnum != dirp.Devinfo.Devnum {
		testutils.ErrorHere(test, "Current directory . devnum mismatch expected %d, got %d", dirp.Devinfo.Devnum, devnum)
	}
	if inum != dirp.Inum {
		testutils.ErrorHere(test, "Current directory . inum mismatch expected %d, got %d", dirp.Inum, inum)
	}
	if !dirp.IsDirectory() {
		testutils.ErrorHere(test, "New directory is not a directory")
	}
	if dirp.Nlinks != 2 {
		testutils.ErrorHere(test, "Links mismatch expected %d, got %d", 2, dirp.Nlinks)
	}
	if dirp.Size != 128 {
		testutils.ErrorHere(test, "Directory size mismatch expected %d, got %d", 128, dirp.Size)
	}
	fs.itable.PutInode(dirp)

	// Remove the new directory
	err = fs.Rmdir(proc, "/tmp/new_directory")
	if err != nil {
		testutils.ErrorHere(test, "Failed when unlinking new directory: %s", err)
	}

	// The bit we just freed should be our next
	inum2, err := bitmap.AllocInode()
	if err != nil {
		testutils.ErrorHere(test, "Failed when checking inode allocation: %s", err)
	}
	if inum != inum2 {
		testutils.ErrorHere(test, "Inode mismatch expected %d, got %d", inum, inum2)
	}
	bitmap.FreeInode(inum2)

	fs.Exit(proc)
	err = fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed when shutting down filesystem: %s", err)
	}
}
示例#12
0
// Test write functionality by taking the data from the host system and
// writing it to the guest system along with the host system (at the same
// time) and comparing the returns from these functions. Then compare the
// written data to the original data to make sure it was written correctly.
func TestWrite(test *testing.T) {
	fs, proc := OpenMinixImage(test)
	ofile := OpenEuroparl(test)

	// Read the data for the entire file
	filesize := 4489799 // known
	filedata, err := ioutil.ReadAll(ofile)
	if err != nil {
		testutils.FatalHere(test, "Failed when reading from original file: %s", err)
	}
	if filesize != len(filedata) {
		testutils.FatalHere(test, "File content sizes differ: %v != %v", len(filedata), filesize)
	}
	if ofile.Close() != nil {
		testutils.FatalHere(test, "Failed when closing original file: %s", err)
	}

	// Open the two files that will be written to
	gfile, err := fs.Open(proc, "/tmp/europarl-en.txt", common.O_CREAT|common.O_TRUNC|common.O_RDWR, 0666)
	if err != nil || gfile == nil {
		testutils.FatalHere(test, "Could not open file on guest: %s", err)
	}
	hfile, err := os.OpenFile("/tmp/europarl-en.txt", os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666)
	if err != nil || hfile == nil {
		testutils.FatalHere(test, "Could not open file on host: %s", err)
	}

	// Write the data to a file on the host/guest operating systems in sync
	blocksize := fs.devinfo[common.ROOT_DEVICE].Blocksize
	numbytes := blocksize + (blocksize / 3)
	pos := 0

	for pos < filesize {
		// Write the next numbytes bytes to the file
		endpos := pos + numbytes
		if endpos > filesize {
			endpos = filesize
		}
		data := filedata[pos:endpos]

		gn, gerr := gfile.Write(data)
		hn, herr := hfile.Write(data)

		if gn != hn {
			testutils.ErrorHere(test, "Bytes read mismatch at offset %d: expected %d, got %d", pos, hn, gn)
		}
		if gerr != herr {
			testutils.ErrorHere(test, "Error mismatch at offset %d: expected '%s', got '%s'", pos, herr, gerr)
		}

		rip, err := fs.eatPath(proc, "/tmp/europarl-en.txt")
		if err != nil {
			testutils.FatalHere(test, "After write at position %d: could not locate newly created file: %s", pos, err)
		} else {
			fs.itable.PutInode(rip)
		}

		pos += gn
	}

	if hfile.Close() != nil {
		testutils.ErrorHere(test, "Failed when closing host file")
	}

	// Seek to beginning of file
	gfile.Seek(0, 0)
	written := make([]byte, filesize)
	n, err := gfile.Read(written)
	if n != filesize {
		testutils.ErrorHere(test, "Verify count mismatch expected %d, got %d", filesize, n)
	}
	if err != nil {
		testutils.ErrorHere(test, "Error when reading to verify: %s", err)
	}

	compare := bytes.Compare(filedata, written)
	if compare != 0 {
		testutils.ErrorHere(test, "Error comparing written data expected %d, got %d", 0, compare)
	}

	if fs.Close(proc, gfile) != nil {
		testutils.ErrorHere(test, "Error when closing out the written file: %s", err)
	}

	err = fs.Unlink(proc, "/tmp/europarl-en.txt")
	if err != nil {
		testutils.ErrorHere(test, "Failed when unlinking written file: %s", err)
	}

	fs.Exit(proc)
	err = fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed when shutting down filesystem: %s", err)
	}
}
示例#13
0
// Test that path lookups function properly
func TestEatPath(test *testing.T) {
	fs, proc := OpenMinixImage(test)

	// Fetch some additional inodes to ensure path lookup is functioning
	// properly.
	//
	//  inode permission link   size name
	//      1 drwxr-xr-x  14    1088 /
	//      2 drwxr-xr-x   2     128 /usr
	//    541 drwxr-xr-x   2     192 /sample
	//    542 -rw-r--r--   1 4489799 /sample/europarl-en.txt
	//     35 -rw-------   2 2705920 /boot/image/3.1.8
	//    540 -rw-r--r--   1     395 /root/.ssh/known_hosts
	//    481 -rw-------   1       5 /var/run/syslogd.pid

	type inodeTest struct {
		path  string
		inum  int
		links int
		size  int
		zones []int
	}

	inodeTests := []inodeTest{
		{"/", 1, 14, 1088, nil},
		{"/usr", 2, 2, 128, nil},
		{"/sample", 541, 2, 192, nil},
		{"/sample/europarl-en.txt", 542, 1, 4489799, nil},
		{"/boot/image/3.1.8", 35, 2, 2705920, nil},
		{"/root/.ssh/known_hosts", 540, 1, 395, nil},
		{"/var/run/syslogd.pid", 481, 1, 5, nil},
	}

	for _, itest := range inodeTests {
		rip, err := fs.eatPath(proc, itest.path)
		if err != nil {
			testutils.FatalHere(test, "Failed when fetching inode for %s: %s", itest.path, err)
		}
		if itest.inum != -1 && rip.Inum != itest.inum {
			testutils.ErrorHere(test, "[%s] mismatch for inum got %d, expected %d", itest.path, rip.Inum, itest.inum)
		}
		if itest.links != -1 && rip.Nlinks != uint16(itest.links) {
			testutils.ErrorHere(test, "[%s] mismatch for links got %d, expected %d", itest.path, rip.Nlinks, itest.links)
		}
		if itest.size != -1 && rip.Size != int32(itest.size) {
			testutils.ErrorHere(test, "[%s] mismatch for size got %d, expected %d", itest.path, rip.Size, itest.size)
		}
		for i := 0; i < 10; i++ {
			if i < len(itest.zones) && rip.Zone[i] != uint32(itest.zones[i]) {
				testutils.ErrorHere(test, "[%s] mismatch for zone[%d] got %d, expected %d", i, itest.path, rip.Zone[i], itest.zones[i])
			}
		}

		// Convert the test to use a relative path and then compare the inodes
		if len(itest.path) > 1 {
			relpath := itest.path[1:]
			relrip, err := fs.eatPath(proc, relpath)
			if err != nil {
				testutils.ErrorHere(test, "Failed fetching relative path %s", relpath)
			}
			if relrip != rip {
				testutils.ErrorHere(test, "Relative inode does not match absolute inode for path %s", itest.path)
			}
			fs.itable.PutInode(relrip)
		}

		fs.itable.PutInode(rip)
	}

	fs.Exit(proc)
	err := fs.Shutdown()
	if err != nil {
		testutils.FatalHere(test, "Failed when shutting down filesystem: %s", err)
	}
}