@@ -14,6 +14,7 @@ import (
14
14
"io"
15
15
"os"
16
16
"path/filepath"
17
+ "sort"
17
18
"strconv"
18
19
"strings"
19
20
@@ -152,14 +153,10 @@ type dirWalkClosure struct {
152
153
//
153
154
// Other than the `vendor` and VCS directories mentioned above, the calculated
154
155
// hash includes the pathname to every discovered file system node, whether it
155
- // is an empty directory, a non-empty directory, empty file, non-empty file, or
156
- // symbolic link. If a symbolic link, the referent name is included. If a
157
- // non-empty file, the file's contents are included. If a non-empty directory,
158
- // the contents of the directory are included.
156
+ // is an empty directory, a non-empty directory, an empty file, or a non-empty file.
159
157
//
160
- // While filepath.Walk could have been used, that standard library function
161
- // skips symbolic links, and for now, we want the hash to include the symbolic
162
- // link referents.
158
+ // Symbolic links are excluded, as they are not considered valid elements in the
159
+ // definition of a Go module.
163
160
func DigestFromDirectory (osDirname string ) (VersionedDigest , error ) {
164
161
osDirname = filepath .Clean (osDirname )
165
162
@@ -173,9 +170,14 @@ func DigestFromDirectory(osDirname string) (VersionedDigest, error) {
173
170
someHash : sha256 .New (),
174
171
}
175
172
176
- err := DirWalk (osDirname , func (osPathname string , info os.FileInfo , err error ) error {
173
+ err := filepath . Walk (osDirname , func (osPathname string , info os.FileInfo , err error ) error {
177
174
if err != nil {
178
- return err // DirWalk received an error during initial Lstat
175
+ return err
176
+ }
177
+
178
+ // Completely ignore symlinks.
179
+ if info .Mode ()& os .ModeSymlink != 0 {
180
+ return nil
179
181
}
180
182
181
183
var osRelative string
@@ -207,11 +209,9 @@ func DigestFromDirectory(osDirname string) (VersionedDigest, error) {
207
209
switch {
208
210
case modeType & os .ModeDir > 0 :
209
211
mt = os .ModeDir
210
- // DirWalkFunc itself does not need to enumerate children, because
211
- // DirWalk will do that for us.
212
+ // This func does not need to enumerate children, because
213
+ // filepath.Walk will do that for us.
212
214
shouldSkip = true
213
- case modeType & os .ModeSymlink > 0 :
214
- mt = os .ModeSymlink
215
215
case modeType & os .ModeNamedPipe > 0 :
216
216
mt = os .ModeNamedPipe
217
217
shouldSkip = true
@@ -225,9 +225,8 @@ func DigestFromDirectory(osDirname string) (VersionedDigest, error) {
225
225
226
226
// Write the relative pathname to hash because the hash is a function of
227
227
// the node names, node types, and node contents. Added benefit is that
228
- // empty directories, named pipes, sockets, devices, and symbolic links
229
- // will also affect final hash value. Use `filepath.ToSlash` to ensure
230
- // relative pathname is os-agnostic.
228
+ // empty directories, named pipes, sockets, and devices. Use
229
+ // `filepath.ToSlash` to ensure relative pathname is os-agnostic.
231
230
writeBytesWithNull (closure .someHash , []byte (filepath .ToSlash (osRelative )))
232
231
233
232
binary .LittleEndian .PutUint32 (closure .someModeBytes , uint32 (mt )) // encode the type of mode
@@ -237,15 +236,6 @@ func DigestFromDirectory(osDirname string) (VersionedDigest, error) {
237
236
return nil // nothing more to do for some of the node types
238
237
}
239
238
240
- if mt == os .ModeSymlink { // okay to check for equivalence because we set to this value
241
- osRelative , err = os .Readlink (osPathname ) // read the symlink referent
242
- if err != nil {
243
- return errors .Wrap (err , "cannot Readlink" )
244
- }
245
- writeBytesWithNull (closure .someHash , []byte (filepath .ToSlash (osRelative ))) // write referent to hash
246
- return nil // proceed to next node in queue
247
- }
248
-
249
239
// If we get here, node is a regular file.
250
240
fh , err := os .Open (osPathname )
251
241
if err != nil {
@@ -541,3 +531,25 @@ func CheckDepTree(osDirname string, wantDigests map[string]VersionedDigest) (map
541
531
542
532
return slashStatus , nil
543
533
}
534
+
535
+ // sortedChildrenFromDirname returns a lexicographically sorted list of child
536
+ // nodes for the specified directory.
537
+ func sortedChildrenFromDirname (osDirname string ) ([]string , error ) {
538
+ fh , err := os .Open (osDirname )
539
+ if err != nil {
540
+ return nil , errors .Wrap (err , "cannot Open" )
541
+ }
542
+
543
+ osChildrenNames , err := fh .Readdirnames (0 ) // 0: read names of all children
544
+ if err != nil {
545
+ return nil , errors .Wrap (err , "cannot Readdirnames" )
546
+ }
547
+ sort .Strings (osChildrenNames )
548
+
549
+ // Close the file handle to the open directory without masking possible
550
+ // previous error value.
551
+ if er := fh .Close (); err == nil {
552
+ err = errors .Wrap (er , "cannot Close" )
553
+ }
554
+ return osChildrenNames , err
555
+ }
0 commit comments