storage: fileStorage.GetManifest() should returns error with type of ErrCorrupted if corruption detected (fixes #121)
diff --git a/leveldb/errors/errors.go b/leveldb/errors/errors.go
index 84b5d6b..dacbf13 100644
--- a/leveldb/errors/errors.go
+++ b/leveldb/errors/errors.go
@@ -52,12 +52,14 @@
 	switch err.(type) {
 	case *ErrCorrupted:
 		return true
+	case *storage.ErrCorrupted:
+		return true
 	}
 	return false
 }
 
 // ErrMissingFiles is the type that indicating a corruption due to missing
-// files.
+// files. ErrMissingFiles always wrapped with ErrCorrupted.
 type ErrMissingFiles struct {
 	Files []*storage.FileInfo
 }
diff --git a/leveldb/storage/file_storage.go b/leveldb/storage/file_storage.go
index 46cc9d0..f671b2e 100644
--- a/leveldb/storage/file_storage.go
+++ b/leveldb/storage/file_storage.go
@@ -243,7 +243,10 @@
 					rem = append(rem, fn)
 				}
 				if !pend1 || cerr == nil {
-					cerr = fmt.Errorf("leveldb/storage: corrupted or incomplete %s file", fn)
+					cerr = &ErrCorrupted{
+						File: fsParseName(filepath.Base(fn)),
+						Err:  errors.New("leveldb/storage: corrupted or incomplete manifest file"),
+					}
 				}
 			} else if f != nil && f1.Num() < f.Num() {
 				fs.log(fmt.Sprintf("skipping %s: obsolete", fn))
@@ -505,30 +508,37 @@
 	return filepath.Join(f.fs.path, f.name())
 }
 
-func (f *file) parse(name string) bool {
-	var num uint64
+func fsParseName(name string) *FileInfo {
+	fi := &FileInfo{}
 	var tail string
-	_, err := fmt.Sscanf(name, "%d.%s", &num, &tail)
+	_, err := fmt.Sscanf(name, "%d.%s", &fi.Num, &tail)
 	if err == nil {
 		switch tail {
 		case "log":
-			f.t = TypeJournal
+			fi.Type = TypeJournal
 		case "ldb", "sst":
-			f.t = TypeTable
+			fi.Type = TypeTable
 		case "tmp":
-			f.t = TypeTemp
+			fi.Type = TypeTemp
 		default:
-			return false
+			return nil
 		}
-		f.num = num
-		return true
+		return fi
 	}
-	n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &num, &tail)
+	n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &fi.Num, &tail)
 	if n == 1 {
-		f.t = TypeManifest
-		f.num = num
-		return true
+		fi.Type = TypeManifest
+		return fi
 	}
+	return nil
+}
 
-	return false
+func (f *file) parse(name string) bool {
+	fi := fsParseName(name)
+	if fi == nil {
+		return false
+	}
+	f.t = fi.Type
+	f.num = fi.Num
+	return true
 }
diff --git a/leveldb/storage/storage.go b/leveldb/storage/storage.go
index 85dd70b..a4e037c 100644
--- a/leveldb/storage/storage.go
+++ b/leveldb/storage/storage.go
@@ -46,6 +46,22 @@
 	ErrClosed      = errors.New("leveldb/storage: closed")
 )
 
+// ErrCorrupted is the type that wraps errors that indicate corruption of
+// a file. Package storage has its own type instead of using
+// errors.ErrCorrupted to prevent circular import.
+type ErrCorrupted struct {
+	File *FileInfo
+	Err  error
+}
+
+func (e *ErrCorrupted) Error() string {
+	if e.File != nil {
+		return fmt.Sprintf("%v [file=%v]", e.Err, e.File)
+	} else {
+		return e.Err.Error()
+	}
+}
+
 // Syncer is the interface that wraps basic Sync method.
 type Syncer interface {
 	// Sync commits the current contents of the file to stable storage.