@@ -227,61 +227,70 @@ impl<Fs: FileSystem> Cache<Fs> {
227227 ///
228228 /// <https://github.com/parcel-bundler/parcel/blob/4d27ec8b8bd1792f536811fef86e74a31fa0e704/crates/parcel-resolver/src/cache.rs#L232>
229229 pub ( crate ) fn canonicalize_impl ( & self , path : & CachedPath ) -> Result < CachedPath , ResolveError > {
230- // Check if this thread is already canonicalizing. If so, we have found a circular symlink.
231- // If a different thread is canonicalizing, OnceLock will queue this thread to wait for the result.
232- let tid = THREAD_ID . with ( |t| * t) ;
233- if path. canonicalizing . load ( Ordering :: Acquire ) == tid {
234- return Err ( io:: Error :: new ( io:: ErrorKind :: NotFound , "Circular symlink" ) . into ( ) ) ;
235- }
230+ let mut result: Option < _ > = None ;
231+ while result. is_none ( ) {
232+ result = {
233+ // Check if this thread is already canonicalizing. If so, we have found a circular symlink.
234+ // If a different thread is canonicalizing, OnceLock will queue this thread to wait for the result.
235+ let tid = THREAD_ID . with ( |t| * t) ;
236+ if path. canonicalizing . load ( Ordering :: Acquire ) == tid {
237+ return Err ( io:: Error :: new ( io:: ErrorKind :: NotFound , "Circular symlink" ) . into ( ) ) ;
238+ }
236239
237- #[ expect( clippy:: collection_is_never_read) ]
238- let mut _temp = None ;
240+ #[ expect( clippy:: collection_is_never_read) ]
241+ let mut _temp = None ;
239242
240- path. canonicalized
241- . get_or_init ( || {
242- path. canonicalizing . store ( tid, Ordering :: Release ) ;
243+ path. canonicalized
244+ . get_or_init ( || {
245+ path. canonicalizing . store ( tid, Ordering :: Release ) ;
243246
244- let res = path. parent ( ) . map_or_else (
245- || Ok ( path. normalize_root ( self ) ) ,
246- |parent| {
247- self . canonicalize_impl ( & parent) . and_then ( |parent_canonical| {
248- let normalized = parent_canonical. normalize_with (
249- path. path ( ) . strip_prefix ( parent. path ( ) ) . unwrap ( ) ,
250- self ,
251- ) ;
247+ let res = path. parent ( ) . map_or_else (
248+ || Ok ( path. normalize_root ( self ) ) ,
249+ |parent| {
250+ self . canonicalize_impl ( & parent) . and_then ( |parent_canonical| {
251+ let normalized = parent_canonical. normalize_with (
252+ path. path ( ) . strip_prefix ( parent. path ( ) ) . unwrap ( ) ,
253+ self ,
254+ ) ;
252255
253- if self . fs . symlink_metadata ( path. path ( ) ) . is_ok_and ( |m| m. is_symlink ) {
254- let link = self . fs . read_link ( normalized. path ( ) ) ?;
255- if link. is_absolute ( ) {
256- return self . canonicalize_impl ( & self . value ( & link. normalize ( ) ) ) ;
257- } else if let Some ( dir) = normalized. parent ( ) {
258- // Symlink is relative `../../foo.js`, use the path directory
259- // to resolve this symlink.
260- return self
261- . canonicalize_impl ( & dir. normalize_with ( & link, self ) ) ;
262- }
263- debug_assert ! (
264- false ,
265- "Failed to get path parent for {}." ,
266- normalized. path( ) . display( )
267- ) ;
268- }
256+ if self
257+ . fs
258+ . symlink_metadata ( path. path ( ) )
259+ . is_ok_and ( |m| m. is_symlink )
260+ {
261+ let link = self . fs . read_link ( normalized. path ( ) ) ?;
262+ if link. is_absolute ( ) {
263+ return self
264+ . canonicalize_impl ( & self . value ( & link. normalize ( ) ) ) ;
265+ } else if let Some ( dir) = normalized. parent ( ) {
266+ // Symlink is relative `../../foo.js`, use the path directory
267+ // to resolve this symlink.
268+ return self . canonicalize_impl (
269+ & dir. normalize_with ( & link, self ) ,
270+ ) ;
271+ }
272+ debug_assert ! (
273+ false ,
274+ "Failed to get path parent for {}." ,
275+ normalized. path( ) . display( )
276+ ) ;
277+ }
269278
270- Ok ( normalized)
271- } )
272- } ,
273- ) ;
279+ Ok ( normalized)
280+ } )
281+ } ,
282+ ) ;
274283
275- path. canonicalizing . store ( 0 , Ordering :: Release ) ;
276- _temp = res. as_ref ( ) . ok ( ) . map ( |cp| Arc :: clone ( & cp. 0 ) ) ;
277- res. map ( |cp| Arc :: downgrade ( & cp. 0 ) )
278- } )
279- . as_ref ( )
280- . map_err ( Clone :: clone)
281- . and_then ( |weak| {
282- weak . upgrade ( ) . map ( CachedPath ) . ok_or_else ( || {
283- ResolveError :: from ( io :: Error :: other ( "Canonicalized path was dropped" ) )
284- } )
285- } )
284+ path. canonicalizing . store ( 0 , Ordering :: Release ) ;
285+ _temp = res. as_ref ( ) . ok ( ) . map ( |cp| Arc :: clone ( & cp. 0 ) ) ;
286+ res. map ( |cp| Arc :: downgrade ( & cp. 0 ) )
287+ } )
288+ . as_ref ( )
289+ . map_err ( Clone :: clone)
290+ . map ( |weak| weak . upgrade ( ) . map ( CachedPath ) )
291+ . transpose ( )
292+ } ;
293+ }
294+ result . unwrap ( )
286295 }
287296}
0 commit comments