tempFileInWritableDir should only be called from tempFile.
(_ string)
| 156 | |
| 157 | // tempFileInWritableDir should only be called from tempFile. |
| 158 | func (s *sharedPullerState) tempFileInWritableDir(_ string) error { |
| 159 | // The permissions to use for the temporary file should be those of the |
| 160 | // final file, except we need user read & write at minimum. The |
| 161 | // permissions will be set to the final value later, but in the meantime |
| 162 | // we don't want to have a temporary file with looser permissions than |
| 163 | // the final outcome. |
| 164 | mode := fs.FileMode(s.file.Permissions) | 0o600 |
| 165 | if s.ignorePerms { |
| 166 | // When ignorePerms is set we use a very permissive mode and let the |
| 167 | // system umask filter it. |
| 168 | mode = 0o666 |
| 169 | } |
| 170 | |
| 171 | // Attempt to create the temp file |
| 172 | // RDWR because of issue #2994. |
| 173 | flags := fs.OptReadWrite |
| 174 | if s.reused == 0 { |
| 175 | flags |= fs.OptCreate | fs.OptExclusive |
| 176 | } else if !s.ignorePerms { |
| 177 | // With sufficiently bad luck when exiting or crashing, we may have |
| 178 | // had time to chmod the temp file to read only state but not yet |
| 179 | // moved it to its final name. This leaves us with a read only temp |
| 180 | // file that we're going to try to reuse. To handle that, we need to |
| 181 | // make sure we have write permissions on the file before opening it. |
| 182 | // |
| 183 | // When ignorePerms is set we trust that the permissions are fine |
| 184 | // already and make no modification, as we would otherwise override |
| 185 | // what the umask dictates. |
| 186 | |
| 187 | if err := s.fs.Chmod(s.tempName, mode); err != nil { |
| 188 | return fmt.Errorf("setting perms on temp file: %w", err) |
| 189 | } |
| 190 | } |
| 191 | fd, err := s.fs.OpenFile(s.tempName, flags, mode) |
| 192 | if err != nil { |
| 193 | return fmt.Errorf("opening temp file: %w", err) |
| 194 | } |
| 195 | |
| 196 | // Hide the temporary file |
| 197 | s.fs.Hide(s.tempName) |
| 198 | |
| 199 | // Don't truncate symlink files, as that will mean that the path will |
| 200 | // contain a bunch of nulls. |
| 201 | if s.sparse && !s.file.IsSymlink() { |
| 202 | size := s.file.Size |
| 203 | // Trailer added to encrypted files |
| 204 | if len(s.file.Encrypted) > 0 { |
| 205 | size += encryptionTrailerSize(s.file) |
| 206 | } |
| 207 | // Truncate sets the size of the file. This creates a sparse file or a |
| 208 | // space reservation, depending on the underlying filesystem. |
| 209 | if err := fd.Truncate(size); err != nil { |
| 210 | // The truncate call failed. That can happen in some cases when |
| 211 | // space reservation isn't possible or over some network |
| 212 | // filesystems... This generally doesn't matter. |
| 213 | |
| 214 | if s.reused > 0 { |
| 215 | // ... but if we are attempting to reuse a file we have a |