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 || isErrNoFollow(err) {
97
98 return &PathError{Op: "unlinkat", Path: base, Err: uErr}
99 }
100 recurseErr = &PathError{Op: "openfdat", Path: base, Err: err}
101 break
102 }
103
104 for {
105 numErr := 0
106
107 names, readErr := file.Readdirnames(reqSize)
108
109 if readErr != nil && readErr != io.EOF {
110 file.Close()
111 if IsNotExist(readErr) {
112 return nil
113 }
114 return &PathError{Op: "readdirnames", Path: base, Err: readErr}
115 }
116
117 respSize = len(names)
118 for _, name := range names {
119 err := removeAllFrom(sysfdType(file.Fd()), name)
120 if err != nil {
121 if pathErr, ok := err.(*PathError); ok {
122 pathErr.Path = base + string(PathSeparator) + pathErr.Path
123 }
124 numErr++
125 if recurseErr == nil {
126 recurseErr = err
127 }
128 }
129 }
130
131
132
133 if numErr != reqSize {
134 break
135 }
136 }
137
138
139
140
141
142
143 file.Close()
144
145
146 if respSize < reqSize {
147 break
148 }
149 }
150
151
152 unlinkError := removedirat(parentFd, base)
153 if unlinkError == nil || IsNotExist(unlinkError) {
154 return nil
155 }
156
157 if recurseErr != nil {
158 return recurseErr
159 }
160 return &PathError{Op: "unlinkat", Path: base, Err: unlinkError}
161 }
162
163
164
165
166
167
168
169
170
171 func openDirAt(dirfd sysfdType, name string) (*File, error) {
172 fd, err := rootOpenDir(dirfd, name)
173 if err != nil {
174 return nil, err
175 }
176 return newDirFile(fd, name)
177 }
178
View as plain text