@@ -224,11 +224,6 @@ private function readData() {
224
224
continue ;
225
225
}
226
226
227
- // Try to acquire a file lock
228
- if (!flock ($ filePointer , LOCK_SH )) {
229
- throw new \Exception (sprintf ('Could not acquire a shared lock on the config file %s ' , $ file ));
230
- }
231
-
232
227
unset($ CONFIG );
233
228
include $ file ;
234
229
if (!defined ('PHPUNIT_RUN ' ) && headers_sent ()) {
@@ -244,7 +239,6 @@ private function readData() {
244
239
}
245
240
246
241
// Close the file pointer and release the lock
247
- flock ($ filePointer , LOCK_UN );
248
242
fclose ($ filePointer );
249
243
}
250
244
@@ -256,8 +250,7 @@ private function readData() {
256
250
*
257
251
* Saves the config to the config file.
258
252
*
259
- * @throws HintException If the config file cannot be written to
260
- * @throws \Exception If no file lock can be acquired
253
+ * @throws HintException If the config file cannot be written to, etc
261
254
*/
262
255
private function writeData () {
263
256
$ this ->checkReadOnly ();
@@ -272,30 +265,41 @@ private function writeData() {
272
265
$ content .= var_export ($ this ->cache , true );
273
266
$ content .= "; \n" ;
274
267
275
- touch ($ this ->configFilePath );
276
- $ filePointer = fopen ($ this ->configFilePath , 'r+ ' );
277
-
278
- // Prevent others not to read the config
279
- chmod ($ this ->configFilePath , 0640 );
268
+ // tmpfile must be in the same filesystem for the rename() to be atomic
269
+ $ tmpfile = tempnam (dirname ($ this ->configFilePath ), 'config.php.tmp. ' );
270
+ // dirname check is for PHP's fallback quirk
271
+ if (!$ tmpfile || dirname ($ tmpfile ) != dirname ($ this ->configFilePath )) {
272
+ if ($ tmpfile ) {
273
+ unlink ($ tmpfile );
274
+ }
275
+ throw new HintException (
276
+ "Can't create temporary file in config directory! " ,
277
+ 'This can usually be fixed by giving the webserver write access to the config directory. ' );
278
+ }
280
279
281
- // File does not exist, this can happen when doing a fresh install
280
+ chmod ($ tmpfile , 0640 );
281
+ $ filePointer = fopen ($ tmpfile , 'w ' );
282
282
if (!is_resource ($ filePointer )) {
283
283
throw new HintException (
284
- "Can't write into config directory! " ,
285
- 'This can usually be fixed by giving the webserver write access to the config directory . ' );
284
+ "Failed to open temporary file in config directory for writing " ,
285
+ 'Please report this to Nextcloud developers . ' );
286
286
}
287
287
288
- // Try to acquire a file lock
289
- if (!flock ($ filePointer , LOCK_EX )) {
290
- throw new \Exception (sprintf ('Could not acquire an exclusive lock on the config file %s ' , $ this ->configFilePath ));
288
+ $ write_ok = fwrite ($ filePointer , $ content );
289
+ $ close_ok = fclose ($ filePointer );
290
+ if (!$ write_ok || !$ close_ok ) {
291
+ unlink ($ tmpfile );
292
+ throw new HintException (
293
+ "Failed to save temporary file in config directory " ,
294
+ 'Please report this to Nextcloud developers. ' );
291
295
}
292
296
293
- // Write the config and release the lock
294
- ftruncate ( $ filePointer , 0 );
295
- fwrite ( $ filePointer , $ content );
296
- fflush ( $ filePointer );
297
- flock ( $ filePointer , LOCK_UN );
298
- fclose ( $ filePointer );
297
+ if (! rename ( $ tmpfile , $ this -> configFilePath )) {
298
+ unlink ( $ tmpfile );
299
+ throw new HintException (
300
+ " Failed to replace the config file with the new copy " ,
301
+ ' Please report this to Nextcloud developers. ' );
302
+ }
299
303
300
304
if (function_exists ('opcache_invalidate ' )) {
301
305
@opcache_invalidate ($ this ->configFilePath , true );
0 commit comments