(parent *os.Root, name, displayPath string)
| 399 | } |
| 400 | |
| 401 | func (r *Root) openVerifiedEntry(parent *os.Root, name, displayPath string) (*os.File, error) { |
| 402 | before, err := parent.Lstat(name) |
| 403 | if err != nil { |
| 404 | return nil, err |
| 405 | } |
| 406 | redirect, err := isPathRedirect(r, parent, name, before) |
| 407 | if err != nil { |
| 408 | return nil, err |
| 409 | } |
| 410 | if redirect { |
| 411 | return nil, SymlinkTraversalError{Path: displayPath} |
| 412 | } |
| 413 | if before.Mode()&os.ModeNamedPipe != 0 { |
| 414 | return nil, namedPipeWriteError(displayPath) |
| 415 | } |
| 416 | |
| 417 | openFlag := os.O_WRONLY | nonBlockingOpenFlag() |
| 418 | file, err := r.openFile(parent, name, openFlag, 0) |
| 419 | if err != nil { |
| 420 | return nil, err |
| 421 | } |
| 422 | opened, err := file.Stat() |
| 423 | if err != nil { |
| 424 | _ = file.Close() |
| 425 | return nil, err |
| 426 | } |
| 427 | after, err := parent.Lstat(name) |
| 428 | if err != nil { |
| 429 | _ = file.Close() |
| 430 | return nil, err |
| 431 | } |
| 432 | redirect, err = isPathRedirect(r, parent, name, after) |
| 433 | if err != nil { |
| 434 | _ = file.Close() |
| 435 | return nil, err |
| 436 | } |
| 437 | if redirect { |
| 438 | _ = file.Close() |
| 439 | return nil, SymlinkTraversalError{Path: displayPath} |
| 440 | } |
| 441 | if !os.SameFile(before, opened) || !os.SameFile(before, after) { |
| 442 | _ = file.Close() |
| 443 | return nil, fmt.Errorf("file %q changed while opening", displayPath) |
| 444 | } |
| 445 | if openFlag != os.O_WRONLY { |
| 446 | if err := clearNonblocking(file); err != nil { |
| 447 | _ = file.Close() |
| 448 | return nil, err |
| 449 | } |
| 450 | } |
| 451 | return file, nil |
| 452 | } |
| 453 | |
| 454 | func (r *Root) redirectTargetIsDir(parent *os.Root, name string) (bool, error) { |
| 455 | info, err := r.stat(parent, name) |
no test coverage detected