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