components/python/python26/patches/Python26-06-write_compiled_module-atomic.patch
changeset 4984 7145b15b7f0d
parent 4983 db2589571faa
child 4985 eed3576cafd0
equal deleted inserted replaced
4983:db2589571faa 4984:7145b15b7f0d
     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 @@ -868,8 +868,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 @@ -882,11 +883,21 @@
       
    17      mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH;
       
    18  #endif
       
    19  
       
    20 -    fp = open_exclusive(cpathname, mode);
       
    21 +    char *tmppathname;
       
    22 +
       
    23 +    /* the temporary file is called cpathname + ".tmp" */
       
    24 +    if ((tmppathname = PyMem_Malloc(strlen(cpathname) + strlen(".tmp") + 1))
       
    25 +        == NULL) {
       
    26 +        return;
       
    27 +    }
       
    28 +    sprintf (tmppathname, "%s.tmp", cpathname);
       
    29 +    fp = open_exclusive(tmppathname, mode);
       
    30 +
       
    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 @@ -895,10 +906,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 @@ -907,8 +919,29 @@
       
    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("# can't unlink %s\n", cpathname);
       
    64 +            (void) unlink(tmppathname);
       
    65 +            PyMem_Free(tmppathname);
       
    66 +            return;
       
    67 +        }
       
    68 +    }
       
    69 +    /* rename the tmp file to the real file name */
       
    70 +    if (rename (tmppathname, cpathname)) {
       
    71 +        if (Py_VerboseFlag)
       
    72 +            PySys_WriteStderr(
       
    73 +                "# can't rename %s to %s\n", tmppathname, cpathname);
       
    74 +        (void) unlink(tmppathname);
       
    75 +        PyMem_Free(tmppathname);
       
    76 +        return;
       
    77 +    }
       
    78      if (Py_VerboseFlag)
       
    79          PySys_WriteStderr("# wrote %s\n", cpathname);
       
    80 +    PyMem_Free(tmppathname);
       
    81  }
       
    82  
       
    83  static void