package bookfile import ( "os" "path/filepath" "strings" ) // OpenReaderAt opens a book file and returns a ReaderAt + size. // Consolidates the 3 places that open a book file + stat + get ReaderAt. func OpenReaderAt(root, rel string) (*os.File, int64, error) { abs := filepath.Join(root, filepath.FromSlash(rel)) f, err := os.Open(abs) if err != nil { return nil, 0, err } st, err := f.Stat() if err != nil { f.Close() return nil, 0, err } return f, st.Size(), nil } // Contains reports whether child is inside parent using EvalSymlinks semantics. // Falls back to Clean if EvalSymlinks fails (e.g., path doesn't exist yet). func Contains(parent, child string) bool { p, err := filepath.EvalSymlinks(parent) if err != nil { p = filepath.Clean(parent) } c, err := filepath.EvalSymlinks(child) if err != nil { c = filepath.Clean(child) } return c == p || strings.HasPrefix(c, p+string(os.PathSeparator)) }