…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 | let mut buf = Vec::new(); | 95 | let mut buf = Vec::new(); |
| 96 | let ref_path = self.ref_path(&relative_path); | 96 | let ref_path = self.ref_path(&relative_path); |
| 97 | 97 | ||
| 98 | if ref_path.is_dir() { | 98 | match std::fs::File::open(&ref_path) { |
| 99 | return Ok(None); | ||
| 100 | } | ||
| 101 | |||
| 102 | match std::fs::File::open(ref_path) { | ||
| 103 | Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), | 99 | Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), |
| 104 | Err(err) => return Err(err), | 100 | Err(err) => return if ref_path.is_dir() { Ok(None) } else { Err(err) }, |
| 105 | Ok(mut file) => file.read_to_end(&mut buf)?, | 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 | Ok(Some(buf)) | 107 | Ok(Some(buf)) |
| 108 | } | 108 | } |
| @@ -19,10 +19,11 @@ impl file::Store { · 18 unmodified lines | |||
| 19 | crate::name::Error: From<E>, | 19 | crate::name::Error: From<E>, |
| 20 | { | 20 | { |
| 21 | let name: FullName<'_> = name.try_into().map_err(|err| Error::RefnameValidation(err.into()))?; | 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 | Ok(file) => file, | 24 | Ok(file) => file, |
| 24 | Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None), | 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 | Ok(Some(log::iter::reverse(file, buf)?)) | 28 | Ok(Some(log::iter::reverse(file, buf)?)) |
| 28 | } | 29 | } |
| @@ -41,13 +42,16 @@ impl file::Store { · 12 unmodified lines | |||
| 41 | crate::name::Error: From<E>, | 42 | crate::name::Error: From<E>, |
| 42 | { | 43 | { |
| 43 | let name: FullName<'_> = name.try_into().map_err(|err| Error::RefnameValidation(err.into()))?; | 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 | Ok(mut file) => { | 47 | Ok(mut file) => { |
| 46 | buf.clear(); | 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 | Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None), | 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 | Ok(Some(log::iter::forward(buf))) | 56 | Ok(Some(log::iter::forward(buf))) |
| 53 | } | 57 | } |
| @@ -95,20 +99,31 @@ pub mod create_or_update { · 41 unmodified lines | |||
| 95 | options.create(true); | 99 | options.create(true); |
| 96 | }; | 100 | }; |
| 97 | 101 | ||
| 98 | let file_for_appending: Option<std::fs::File> = options | 102 | let file_for_appending: Option<std::fs::File> = match options.open(&log_path) { |
| 99 | .open(&log_path) | 103 | Ok(f) => Some(f), |
| 100 | .map(Some) | 104 | Err(err) if err.kind() == std::io::ErrorKind::NotFound => None, |
| 101 | .or_else(|err| { | 105 | Err(err) => { |
| 102 | if err.kind() == std::io::ErrorKind::NotFound { | 106 | #[cfg(target_os = "windows")] |
| 103 | Ok(None) | 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 | } else { | 119 | } else { |
| 105 | Err(err) | 120 | return Err(Error::Append { |
| 121 | err, | ||
| 122 | reflog_path: log_path, | ||
| 123 | }); | ||
| 106 | } | 124 | } |
| 107 | }) | 125 | } |
| 108 | .map_err(|err| Error::Append { | 126 | }; |
| 109 | err, | ||
| 110 | reflog_path: log_path, | ||
| 111 | })?; | ||
| 112 | 127 | ||
| 113 | if let Some(mut file) = file_for_appending { | 128 | if let Some(mut file) = file_for_appending { |
| 114 | write!( | 129 | write!( |
| @@ -294,7 +309,7 @@ pub mod create_or_update { · 179 unmodified lines | |||
| 294 | let full_name = "refs/heads/other"; | 309 | let full_name = "refs/heads/other"; |
| 295 | let lock = reflock(&store, full_name).unwrap(); | 310 | let lock = reflock(&store, full_name).unwrap(); |
| 296 | let reflog_path = store.reflog_path_inner(Path::new(full_name)); | 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 | store | 314 | store |
| 300 | .reflog_create_or_append( | 315 | .reflog_create_or_append( |