Merge pull request #2266 from zed-industries/avoid-panic

Julia created

Avoid panic scanning recursive symlink before gitignore is encountered

Change summary

crates/project/src/worktree.rs | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)

Detailed changes

crates/project/src/worktree.rs 🔗

@@ -2361,7 +2361,7 @@ impl BackgroundScanner {
         job: &ScanJob,
     ) -> Result<()> {
         let mut new_entries: Vec<Entry> = Vec::new();
-        let mut new_jobs: Vec<ScanJob> = Vec::new();
+        let mut new_jobs: Vec<Option<ScanJob>> = Vec::new();
         let mut ignore_stack = job.ignore_stack.clone();
         let mut new_ignore = None;
 
@@ -2374,6 +2374,7 @@ impl BackgroundScanner {
                     continue;
                 }
             };
+
             let child_name = child_abs_path.file_name().unwrap();
             let child_path: Arc<Path> = job.path.join(child_name).into();
             let child_metadata = match self.fs.metadata(&child_abs_path).await {
@@ -2412,12 +2413,15 @@ impl BackgroundScanner {
                     let entry_abs_path = self.abs_path().join(&entry.path);
                     entry.is_ignored =
                         ignore_stack.is_abs_path_ignored(&entry_abs_path, entry.is_dir());
+
                     if entry.is_dir() {
-                        new_jobs.next().unwrap().ignore_stack = if entry.is_ignored {
-                            IgnoreStack::all()
-                        } else {
-                            ignore_stack.clone()
-                        };
+                        if let Some(job) = new_jobs.next().expect("Missing scan job for entry") {
+                            job.ignore_stack = if entry.is_ignored {
+                                IgnoreStack::all()
+                            } else {
+                                ignore_stack.clone()
+                            };
+                        }
                     }
                 }
             }
@@ -2433,10 +2437,12 @@ impl BackgroundScanner {
                 let is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, true);
                 child_entry.is_ignored = is_ignored;
 
+                // Avoid recursing until crash in the case of a recursive symlink
                 if !job.ancestor_inodes.contains(&child_entry.inode) {
                     let mut ancestor_inodes = job.ancestor_inodes.clone();
                     ancestor_inodes.insert(child_entry.inode);
-                    new_jobs.push(ScanJob {
+
+                    new_jobs.push(Some(ScanJob {
                         abs_path: child_abs_path,
                         path: child_path,
                         ignore_stack: if is_ignored {
@@ -2446,7 +2452,9 @@ impl BackgroundScanner {
                         },
                         ancestor_inodes,
                         scan_queue: job.scan_queue.clone(),
-                    });
+                    }));
+                } else {
+                    new_jobs.push(None);
                 }
             } else {
                 child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false);
@@ -2461,8 +2469,11 @@ impl BackgroundScanner {
             new_ignore,
             self.fs.as_ref(),
         );
+
         for new_job in new_jobs {
-            job.scan_queue.send(new_job).await.unwrap();
+            if let Some(new_job) = new_job {
+                job.scan_queue.send(new_job).await.unwrap();
+            }
         }
 
         Ok(())