components/python/python26/Python26-06-write_compiled_module-atomic.patch
changeset 99 c15c9099bb44
equal deleted inserted replaced
98:7eea11439375 99:c15c9099bb44
       
     1 diff --git Python-2.6.4/Python/import.c Python-2.6.4/Python/import.c
       
     2 --- Python-2.6.4/Python/import.c
       
     3 +++ Python-2.6.4/Python/import.c
       
     4 @@ -866,8 +866,9 @@
       
     5  
       
     6  /* Write a compiled module to a file, placing the time of last
       
     7     modification of its source into the header.
       
     8 -   Errors are ignored, if a write error occurs an attempt is made to
       
     9 -   remove the file. */
       
    10 +   Write to a temporary file first so that creating the file is atomic.
       
    11 +   Errors are ignored, if a write/unlink/rename error occurs an attempt
       
    12 +   is made to remove the temporary file. */
       
    13  
       
    14  static void
       
    15  write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat)
       
    16 @@ -879,12 +880,21 @@
       
    17  #else
       
    18  	mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH;
       
    19  #endif 
       
    20 +	char *tmppathname;
       
    21 + 
       
    22 +	/* the temporary file is called cpathname + ".tmp" */
       
    23 +	if ((tmppathname = PyMem_Malloc(strlen(cpathname) + strlen(".tmp") + 1))
       
    24 +		== NULL) {
       
    25 +		return;
       
    26 +	}
       
    27 +	sprintf (tmppathname, "%s.tmp", cpathname);
       
    28 +	fp = open_exclusive(tmppathname, mode);
       
    29  
       
    30 -	fp = open_exclusive(cpathname, mode);
       
    31  	if (fp == NULL) {
       
    32  		if (Py_VerboseFlag)
       
    33  			PySys_WriteStderr(
       
    34 -				"# can't create %s\n", cpathname);
       
    35 +				"# can't create %s\n", tmppathname);
       
    36 +		PyMem_Free(tmppathname);
       
    37  		return;
       
    38  	}
       
    39  	PyMarshal_WriteLongToFile(pyc_magic, fp, Py_MARSHAL_VERSION);
       
    40 @@ -893,10 +903,11 @@
       
    41  	PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
       
    42  	if (fflush(fp) != 0 || ferror(fp)) {
       
    43  		if (Py_VerboseFlag)
       
    44 -			PySys_WriteStderr("# can't write %s\n", cpathname);
       
    45 +			PySys_WriteStderr("# can't write %s\n", tmppathname);
       
    46  		/* Don't keep partial file */
       
    47  		fclose(fp);
       
    48 -		(void) unlink(cpathname);
       
    49 +		(void) unlink(tmppathname);
       
    50 +		PyMem_Free(tmppathname);
       
    51  		return;
       
    52  	}
       
    53  	/* Now write the true mtime */
       
    54 @@ -905,8 +916,30 @@
       
    55  	PyMarshal_WriteLongToFile((long)mtime, fp, Py_MARSHAL_VERSION);
       
    56  	fflush(fp);
       
    57  	fclose(fp);
       
    58 +	/* Delete the old compiled file, if exists */
       
    59 +	if (unlink (cpathname)) {
       
    60 +		if ((errno != ENOENT)) {
       
    61 +			/* the file exists but could not be deleted */
       
    62 +			if (Py_VerboseFlag)
       
    63 +				PySys_WriteStderr(
       
    64 +					"# can't unlink %s\n", cpathname);
       
    65 +			(void) unlink(tmppathname);
       
    66 +			PyMem_Free(tmppathname);
       
    67 +			return;
       
    68 +		}
       
    69 +	}
       
    70 +	/* rename the tmp file to the real file name */
       
    71 +	if (rename (tmppathname, cpathname)) {
       
    72 +		if (Py_VerboseFlag)
       
    73 +			PySys_WriteStderr(
       
    74 +				"# can't rename %s to %s\n", tmppathname, cpathname);
       
    75 +		(void) unlink(tmppathname);
       
    76 +		PyMem_Free(tmppathname);
       
    77 +		return;
       
    78 +	}
       
    79  	if (Py_VerboseFlag)
       
    80  		PySys_WriteStderr("# wrote %s\n", cpathname);
       
    81 +	PyMem_Free(tmppathname);
       
    82  }
       
    83  
       
    84  static void