…and push the cost for checking if it's a directory or not to the error case, instead of doing it beforehand like in `find_one()`.
Unified · Split
| @@ -95,14 +95,14 @@ impl file::Store { · 94 unmodified lines | ||
| 95 | 95 | let mut buf = Vec::new(); |
| 96 | 96 | let ref_path = self.ref_path(&relative_path); |
| 97 | 97 | |
| 98 | − if ref_path.is_dir() { | |
| 99 | − return Ok(None); | |
| 100 | − } | |
| 101 | − | |
| 102 | − match std::fs::File::open(ref_path) { | |
| 98 | + match std::fs::File::open(&ref_path) { | |
| 103 | 99 | Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), |
| 104 | − Err(err) => return Err(err), | |
| 105 | − Ok(mut file) => file.read_to_end(&mut buf)?, | |
| 100 | + Err(err) => return if ref_path.is_dir() { Ok(None) } else { Err(err) }, | |
| 101 | + Ok(mut file) => { | |
| 102 | + if let Err(err) = file.read_to_end(&mut buf) { | |
| 103 | + return if ref_path.is_dir() { Ok(None) } else { Err(err) }; | |
| 104 | + } | |
| 105 | + } | |
| 106 | 106 | }; |
| 107 | 107 | Ok(Some(buf)) |
| 108 | 108 | } |
| @@ -19,10 +19,11 @@ impl file::Store { · 18 unmodified lines | ||
| 19 | 19 | crate::name::Error: From<E>, |
| 20 | 20 | { |
| 21 | 21 | let name: FullName<'_> = name.try_into().map_err(|err| Error::RefnameValidation(err.into()))?; |
| 22 | − let file = match std::fs::File::open(self.reflog_path(name)) { | |
| 22 | + let path = self.reflog_path(name); | |
| 23 | + let file = match std::fs::File::open(&path) { | |
| 23 | 24 | Ok(file) => file, |
| 24 | 25 | Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None), |
| 25 | − Err(err) => return Err(err.into()), | |
| 26 | + Err(err) => return if path.is_dir() { Ok(None) } else { Err(err.into()) }, // TODO: a test to validate this | |
| 26 | 27 | }; |
| 27 | 28 | Ok(Some(log::iter::reverse(file, buf)?)) |
| 28 | 29 | } |
| @@ -41,13 +42,16 @@ impl file::Store { · 12 unmodified lines | ||
| 41 | 42 | crate::name::Error: From<E>, |
| 42 | 43 | { |
| 43 | 44 | let name: FullName<'_> = name.try_into().map_err(|err| Error::RefnameValidation(err.into()))?; |
| 44 | − match std::fs::File::open(self.reflog_path(name)) { | |
| 45 | + let path = self.reflog_path(name); | |
| 46 | + match std::fs::File::open(&path) { | |
| 45 | 47 | Ok(mut file) => { |
| 46 | 48 | buf.clear(); |
| 47 | − file.read_to_end(buf)?; | |
| 49 | + if let Err(err) = file.read_to_end(buf) { | |
| 50 | + return if path.is_dir() { Ok(None) } else { Err(err.into()) }; | |
| 51 | + } | |
| 48 | 52 | } |
| 49 | 53 | Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None), |
| 50 | − Err(err) => return Err(err.into()), | |
| 54 | + Err(err) => return if path.is_dir() { Ok(None) } else { Err(err.into()) }, | |
| 51 | 55 | }; |
| 52 | 56 | Ok(Some(log::iter::forward(buf))) |
| 53 | 57 | } |
| @@ -95,20 +99,31 @@ pub mod create_or_update { · 41 unmodified lines | ||
| 95 | 99 | options.create(true); |
| 96 | 100 | }; |
| 97 | 101 | |
| 98 | − let file_for_appending: Option<std::fs::File> = options | |
| 99 | − .open(&log_path) | |
| 100 | − .map(Some) | |
| 101 | − .or_else(|err| { | |
| 102 | − if err.kind() == std::io::ErrorKind::NotFound { | |
| 103 | − Ok(None) | |
| 102 | + let file_for_appending: Option<std::fs::File> = match options.open(&log_path) { | |
| 103 | + Ok(f) => Some(f), | |
| 104 | + Err(err) if err.kind() == std::io::ErrorKind::NotFound => None, | |
| 105 | + Err(err) => { | |
| 106 | + #[cfg(target_os = "windows")] | |
| 107 | + let special_kind = std::io::ErrorKind::PermissionDenied; | |
| 108 | + #[cfg(not(target_os = "windows"))] | |
| 109 | + let special_kind = std::io::ErrorKind::Other; | |
| 110 | + | |
| 111 | + if err.kind() == special_kind { | |
| 112 | + std::fs::remove_dir(&log_path) | |
| 113 | + .and_then(|_| options.open(&log_path)) | |
| 114 | + .map(Some) | |
| 115 | + .map_err(|_| Error::Append { | |
| 116 | + err, | |
| 117 | + reflog_path: self.reflock_resource_to_log_path(lock), | |
| 118 | + })? | |
| 104 | 119 | } else { |
| 105 | − Err(err) | |
| 120 | + return Err(Error::Append { | |
| 121 | + err, | |
| 122 | + reflog_path: log_path, | |
| 123 | + }); | |
| 106 | 124 | } |
| 107 | − }) | |
| 108 | − .map_err(|err| Error::Append { | |
| 109 | − err, | |
| 110 | − reflog_path: log_path, | |
| 111 | − })?; | |
| 125 | + } | |
| 126 | + }; | |
| 112 | 127 | |
| 113 | 128 | if let Some(mut file) = file_for_appending { |
| 114 | 129 | write!( |
| @@ -294,7 +309,7 @@ pub mod create_or_update { · 179 unmodified lines | ||
| 294 | 309 | let full_name = "refs/heads/other"; |
| 295 | 310 | let lock = reflock(&store, full_name).unwrap(); |
| 296 | 311 | let reflog_path = store.reflog_path_inner(Path::new(full_name)); |
| 297 | − std::fs::create_dir(&reflog_path).unwrap(); | |
| 312 | + std::fs::create_dir_all(&reflog_path).unwrap(); | |
| 298 | 313 | |
| 299 | 314 | store |
| 300 | 315 | .reflog_create_or_append( |