History

feat(gix-tempfile)!: support shared permissions for parent directories

<!-- agent --> Temporary files created in shared repositories can require new parent directories. Callers need those directories to honor the repository's sharing policy even when the process umask would make them private. Replace the tuple field of `ContainingDirectory::CreateAllRaceProof` with named `retries` and `shared_repository_permissions` fields, and pass the policy to directory creation in `gix_fs`. Setting the policy to `0` preserves the previous umask behavior. Adapt the existing tempfile tests to the new variant shape.

Byron committed 2 months ago

Commit edea3751 parent 6d016874 files · +39 −9Browse files

Unified · Split

4 files
  1. gix-lock/src/acquire.rs +4 −1
  2. gix-tempfile/src/handle.rs +4 −1
  3. gix-tempfile/src/lib.rs +7 −1
  4. gix-tempfile/tests/tempfile/handle.rs +24 −6
gix-lock/src/acquire.rs+4−1
@@ -238,7 +238,10 @@ fn dir_cleanup(boundary: Option<PathBuf>) -> (ContainingDirectory, AutoRemove) { · 237 unmodified lines
238 match boundary {238 match boundary {
239 None => (ContainingDirectory::Exists, AutoRemove::Tempfile),239 None => (ContainingDirectory::Exists, AutoRemove::Tempfile),
240 Some(boundary_directory) => (240 Some(boundary_directory) => (
241 ContainingDirectory::CreateAllRaceProof(Default::default()),241 ContainingDirectory::CreateAllRaceProof {
242 retries: Default::default(),
243 shared_repository_permissions: 0,
244 },
242 AutoRemove::TempfileAndEmptyParentDirectoriesUntil { boundary_directory },245 AutoRemove::TempfileAndEmptyParentDirectoriesUntil { boundary_directory },
243 ),246 ),
244 }247 }
gix-tempfile/src/handle.rs+4−1
@@ -343,7 +343,10 @@ impl ContainingDirectory { · 342 unmodified lines
343 fn resolve(self, dir: &Path) -> std::io::Result<&Path> {343 fn resolve(self, dir: &Path) -> std::io::Result<&Path> {
344 match self {344 match self {
345 ContainingDirectory::Exists => Ok(dir),345 ContainingDirectory::Exists => Ok(dir),
346 ContainingDirectory::CreateAllRaceProof(retries) => crate::create_dir::all(dir, retries, 0),346 ContainingDirectory::CreateAllRaceProof {
347 retries,
348 shared_repository_permissions,
349 } => crate::create_dir::all(dir, retries, shared_repository_permissions),
347 }350 }
348 }351 }
349}352}
gix-tempfile/src/lib.rs+7−1
@@ -160,7 +160,13 @@ pub enum ContainingDirectory { · 159 unmodified lines
160 Exists,160 Exists,
161 /// Create the directory recursively with the given number of retries in a way that is somewhat race resistant161 /// Create the directory recursively with the given number of retries in a way that is somewhat race resistant
162 /// depending on the amount of retries.162 /// depending on the amount of retries.
163 CreateAllRaceProof(create_dir::Retries),163 CreateAllRaceProof {
164 /// How often to retry directory creation when other processes interfere.
165 retries: create_dir::Retries,
166 /// Git's parsed sharing policy for newly created directories; `0` keeps the umask permissions.
167 /// See [`gix_fs::adjust_shared_repository_permissions()`] for the encoding.
168 shared_repository_permissions: i32,
169 },
164}170}
165 171
166/// A type expressing the ways we cleanup after ourselves to remove resources we created.172/// A type expressing the ways we cleanup after ourselves to remove resources we created.
gix-tempfile/tests/tempfile/handle.rs+24−6
@@ -8,7 +8,10 @@ mod mark_path { · 7 unmodified lines
8 let new_filename = target.parent().unwrap().join("file.ext");8 let new_filename = target.parent().unwrap().join("file.ext");
9 let handle = gix_tempfile::mark_at(9 let handle = gix_tempfile::mark_at(
10 &target,10 &target,
11 ContainingDirectory::CreateAllRaceProof(Default::default()),11 ContainingDirectory::CreateAllRaceProof {
12 retries: Default::default(),
13 shared_repository_permissions: 0,
14 },
12 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {15 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {
13 boundary_directory: dir.path().into(),16 boundary_directory: dir.path().into(),
14 },17 },
@@ -37,7 +40,10 @@ mod mark_path { · 22 unmodified lines
37 let filename = dir.path().join(first_dir).join("subdir").join("file.tmp");40 let filename = dir.path().join(first_dir).join("subdir").join("file.tmp");
38 let tempfile = gix_tempfile::mark_at(41 let tempfile = gix_tempfile::mark_at(
39 &filename,42 &filename,
40 ContainingDirectory::CreateAllRaceProof(Default::default()),43 ContainingDirectory::CreateAllRaceProof {
44 retries: Default::default(),
45 shared_repository_permissions: 0,
46 },
41 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {47 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {
42 boundary_directory: dir.path().into(),48 boundary_directory: dir.path().into(),
43 },49 },
@@ -65,7 +71,10 @@ mod at_path { · 21 unmodified lines
65 let new_filename = target.parent().unwrap().join("file.ext");71 let new_filename = target.parent().unwrap().join("file.ext");
66 let mut file = gix_tempfile::writable_at(72 let mut file = gix_tempfile::writable_at(
67 &target,73 &target,
68 ContainingDirectory::CreateAllRaceProof(Default::default()),74 ContainingDirectory::CreateAllRaceProof {
75 retries: Default::default(),
76 shared_repository_permissions: 0,
77 },
69 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {78 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {
70 boundary_directory: dir.path().into(),79 boundary_directory: dir.path().into(),
71 },80 },
@@ -98,7 +107,10 @@ mod at_path { · 26 unmodified lines
98 );107 );
99 let handle = gix_tempfile::writable_at(108 let handle = gix_tempfile::writable_at(
100 &target,109 &target,
101 ContainingDirectory::CreateAllRaceProof(Default::default()),110 ContainingDirectory::CreateAllRaceProof {
111 retries: Default::default(),
112 shared_repository_permissions: 0,
113 },
102 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {114 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {
103 boundary_directory: dir.path().into(),115 boundary_directory: dir.path().into(),
104 },116 },
@@ -163,7 +175,10 @@ mod at_path { · 58 unmodified lines
163 let filename = dir.path().join(first_dir).join("subdir").join("file.tmp");175 let filename = dir.path().join(first_dir).join("subdir").join("file.tmp");
164 let tempfile = gix_tempfile::writable_at(176 let tempfile = gix_tempfile::writable_at(
165 &filename,177 &filename,
166 ContainingDirectory::CreateAllRaceProof(Default::default()),178 ContainingDirectory::CreateAllRaceProof {
179 retries: Default::default(),
180 shared_repository_permissions: 0,
181 },
167 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {182 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {
168 boundary_directory: dir.path().into(),183 boundary_directory: dir.path().into(),
169 },184 },
@@ -244,7 +259,10 @@ mod new { · 74 unmodified lines
244 {259 {
245 let mut writable = gix_tempfile::new(260 let mut writable = gix_tempfile::new(
246 &containing_dir,261 &containing_dir,
247 ContainingDirectory::CreateAllRaceProof(Default::default()),262 ContainingDirectory::CreateAllRaceProof {
263 retries: Default::default(),
264 shared_repository_permissions: 0,
265 },
248 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {266 AutoRemove::TempfileAndEmptyParentDirectoriesUntil {
249 boundary_directory: dir.path().into(),267 boundary_directory: dir.path().into(),
250 },268 },