Source file
src/os/removeall_at.go
1
2
3
4
5
6
7 package os
8
9 import (
10 "io"
11 "syscall"
12 )
13
14 func removeAll(path string) error {
15 if path == "" {
16
17
18 return nil
19 }
20
21
22
23 if endsWithDot(path) {
24 return &PathError{Op: "RemoveAll", Path: path, Err: syscall.EINVAL}
25 }
26
27
28 err := Remove(path)
29 if err == nil || IsNotExist(err) {
30 return nil
31 }
32
33
34
35 parentDir, base := splitPath(path)
36
37 parent, err := Open(parentDir)
38 if IsNotExist(err) {
39
40 return nil
41 }
42 if err != nil {
43 return err
44 }
45 defer parent.Close()
46
47 if err := removeAllFrom(parent, base); err != nil {
48 if pathErr, ok := err.(*PathError); ok {
49 pathErr.Path = parentDir + string(PathSeparator) + pathErr.Path
50 err = pathErr
51 }
52 return err
53 }
54 return nil
55 }
56
57 func removeAllFrom(parent *File, base string) error {
58 parentFd := sysfdType(parent.Fd())
59
60
61 err := removefileat(parentFd, base)
62 if err == nil || IsNotExist(err) {
63 return nil
64 }
65
66
67
68
69
70
71
72 if err != syscall.EISDIR && err != syscall.EPERM && err != syscall.EACCES {
73 return &PathError{Op: "unlinkat", Path: base, Err: err}
74 }
75 uErr := err
76
77
78 var recurseErr error
79 for {
80 const reqSize = 1024
81 var respSize int
82
83
84 file, err := openDirAt(parentFd, base)
85 if err != nil {
86 if IsNotExist(err) {
87 return nil
88 }
89 if err == syscall.ENOTDIR || isErrNoFollow(err) {
90
91 return &PathError{Op: "unlinkat", Path: base, Err: uErr}
92 }
93 recurseErr = &PathError{Op: "openfdat", Path: base, Err: err}
94 break
95 }
96
97 for {
98 numErr := 0
99
100 names, readErr := file.Readdirnames(reqSize)
101
102 if readErr != nil && readErr != io.EOF {
103 file.Close()
104 if IsNotExist(readErr) {
105 return nil
106 }
107 return &PathError{Op: "readdirnames", Path: base, Err: readErr}
108 }
109
110 respSize = len(names)
111 for _, name := range names {
112 err := removeAllFrom(file, name)
113 if err != nil {
114 if pathErr, ok := err.(*PathError); ok {
115 pathErr.Path = base + string(PathSeparator) + pathErr.Path
116 }
117 numErr++
118 if recurseErr == nil {
119 recurseErr = err
120 }
121 }
122 }
123
124
125
126 if numErr != reqSize {
127 break
128 }
129 }
130
131
132
133
134
135
136 file.Close()
137
138
139 if respSize < reqSize {
140 break
141 }
142 }
143
144
145 unlinkError := removedirat(parentFd, base)
146 if unlinkError == nil || IsNotExist(unlinkError) {
147 return nil
148 }
149
150 if recurseErr != nil {
151 return recurseErr
152 }
153 return &PathError{Op: "unlinkat", Path: base, Err: unlinkError}
154 }
155
156
157
158
159
160
161
162
163
164 func openDirAt(dirfd sysfdType, name string) (*File, error) {
165 fd, err := rootOpenDir(dirfd, name)
166 if err != nil {
167 return nil, err
168 }
169 return newDirFile(fd, name)
170 }
171
View as plain text