# HG changeset patch # User Michael Witten # Date 1475887737 0 # Sat Oct 08 00:48:57 2016 +0000 # Branch 2.7 # Node ID feecb6c8609b395ca8781608b85d45e25c4087f7 # Parent 59260b38f7cd4a2ae66928de5227798524006e64 PEP 235: Extend to every POSIX system the case-sensitivity semantics for `import' (Note: As per PEP 235, this explicit checking of case may be effectively disabled by defining the environment variable `PYTHONCASEOK'.) From time to time, even a user of a sane system has been known [to be forced] to use an insane file system; the semantics of PEP 235 need to be implemented in this case as well. On a sane system, mount an insane file system at "$mount", and then run this example: $ cd "$mount" $ touch Insane.py $ python -c 'import Insane; import insane; print(dir())' Before this revision, the resulting output is: ['Insane', '__builtins__', '__doc__', '__name__', '__package__', 'insane'] After this commit, the resulting output is sane: Traceback (most recent call last): File "", line 1, in ImportError: No module named insane Because POSIX systems may be a subset of sane systems, this is only a partial fix to the overall problem; as much as possible, *every* system should implement the same semantics. diff -r 59260b38f7cd -r feecb6c8609b Python/import.c --- a/Python/import.c Wed Oct 05 23:26:24 2016 -0700 +++ b/Python/import.c Sat Oct 08 00:48:57 2016 +0000 @@ -1666,7 +1666,7 @@ #elif defined(DJGPP) #include -#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) +#elif _POSIX_C_SOURCE || (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) #include #include @@ -1723,7 +1723,7 @@ return strncmp(ffblk.ff_name, name, namelen) == 0; /* new-fangled macintosh (macosx) or Cygwin */ -#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) +#elif _POSIX_C_SOURCE || (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) DIR *dirp; struct dirent *dp; char dirname[MAXPATHLEN + 1]; # HG changeset patch # User Michael Witten # Date 1475955396 0 # Sat Oct 08 19:36:36 2016 +0000 # Branch 2.7 # Node ID cab072a518643e33d399b2e02a48a3419420c3ad # Parent feecb6c8609b395ca8781608b85d45e25c4087f7 PEP 235: Refactor each system-dependent implementation into its own function This change is mostly a matter of aesthetic taste, but it does confer a few technical benefits: * There is now no longer a repitition of the same #if/#elif conditional compilations; there is no longer a need to maintain these repititions in the same order (a request which has been ignored, anyway). * By being self-contained, each implementation is more comprehensible; for each one, there is a clear beginning and end. * Macros have been used only in a way that deliberately preserves and explicitly employs the C-funtion construct; tools that analyze and search the source should be able to identify these functions easily without macro magic obscuring their meanings. diff -r feecb6c8609b -r cab072a51864 Python/import.c --- a/Python/import.c Sat Oct 08 00:48:57 2016 +0000 +++ b/Python/import.c Sat Oct 08 19:36:36 2016 +0000 @@ -1657,164 +1657,193 @@ * nightmare for systems with case-insensitive filesystems. */ -/* First we may need a pile of platform-specific header files; the sequence - * of #if's here should match the sequence in the body of case_ok(). - */ +#define CASE_OK_PARAMS char *buf, Py_ssize_t len, Py_ssize_t namelen, char *name +#define CASE_OK_ARGS buf, len, namelen, name + #if defined(MS_WINDOWS) -#include + + #define CASE_OK_IMP imp_ms_windows_case_ok + + #include + + static int + imp_ms_windows_case_ok(CASE_OK_PARAMS) + { + WIN32_FIND_DATA data; + HANDLE h; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + h = FindFirstFile(buf, &data); + if (h == INVALID_HANDLE_VALUE) { + PyErr_Format(PyExc_NameError, + "Can't find file for module %.100s\n(filename %.300s)", + name, buf); + return 0; + } + FindClose(h); + return strncmp(data.cFileName, name, namelen) == 0; + } #elif defined(DJGPP) -#include + + #define CASE_OK_IMP imp_djgpp_case_ok + + #include + + static int + imp_djgpp_case_ok(CASE_OK_PARAMS) + { + struct ffblk ffblk; + int done; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + done = findfirst(buf, &ffblk, FA_ARCH|FA_RDONLY|FA_HIDDEN|FA_DIREC); + if (done) { + PyErr_Format(PyExc_NameError, + "Can't find file for module %.100s\n(filename %.300s)", + name, buf); + return 0; + } + return strncmp(ffblk.ff_name, name, namelen) == 0; + } #elif _POSIX_C_SOURCE || (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) -#include -#include + + #define CASE_OK_IMP imp_posix_case_ok + + #ifdef _DIRENT_HAVE_D_NAMELEN + #define NAMLEN(dp) dp->d_namlen; + #else + #define NAMLEN(dp) strlen(dp->d_name); + #endif + + #include + #include + + static int + imp_posix_case_ok(CASE_OK_PARAMS) + { + DIR *dirp; + struct dirent *dp; + char dirname[MAXPATHLEN + 1]; + const int dirlen = len - namelen - 1; /* don't want trailing SEP */ + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + /* Copy the dir component into dirname; substitute "." if empty */ + if (dirlen <= 0) { + dirname[0] = '.'; + dirname[1] = '\0'; + } + else { + assert(dirlen <= MAXPATHLEN); + memcpy(dirname, buf, dirlen); + dirname[dirlen] = '\0'; + } + /* Open the directory and search the entries for an exact match. */ + dirp = opendir(dirname); + if (dirp) { + char *nameWithExt = buf + len - namelen; + while ((dp = readdir(dirp)) != NULL) { + const int thislen = NAMLEN(dp); + if (thislen >= namelen && + strcmp(dp->d_name, nameWithExt) == 0) { + (void)closedir(dirp); + return 1; /* Found */ + } + } + (void)closedir(dirp); + } + return 0 ; /* Not found */ + } #elif defined(PYOS_OS2) -#define INCL_DOS -#define INCL_DOSERRORS -#define INCL_NOPMAPI -#include + + #define CASE_OK_IMP imp_os2_case_ok + + #define INCL_DOS + #define INCL_DOSERRORS + #define INCL_NOPMAPI + #include + + static int + imp_os2_case_ok(CASE_OK_PARAMS) + { + HDIR hdir = 1; + ULONG srchcnt = 1; + FILEFINDBUF3 ffbuf; + APIRET rc; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + rc = DosFindFirst(buf, + &hdir, + FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY, + &ffbuf, sizeof(ffbuf), + &srchcnt, + FIL_STANDARD); + if (rc != NO_ERROR) + return 0; + return strncmp(ffbuf.achName, name, namelen) == 0; + } #elif defined(RISCOS) -#include "oslib/osfscontrol.h" + + #define CASE_OK_IMP imp_riscos_case_ok + + #include "oslib/osfscontrol.h" + + static int + imp_riscos_case_ok(CASE_OK_PARAMS) + { + char canon[MAXPATHLEN+1]; /* buffer for the canonical form of the path */ + char buf2[MAXPATHLEN+2]; + char *nameWithExt = buf+len-namelen; + int canonlen; + os_error *e; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + /* workaround: + append wildcard, otherwise case of filename wouldn't be touched */ + strcpy(buf2, buf); + strcat(buf2, "*"); + + e = xosfscontrol_canonicalise_path(buf2,canon,0,0,MAXPATHLEN+1,&canonlen); + canonlen = MAXPATHLEN+1-canonlen; + if (e || canonlen<=0 || canonlen>(MAXPATHLEN+1) ) + return 0; + if (strcmp(nameWithExt, canon+canonlen-strlen(nameWithExt))==0) + return 1; /* match */ + + return 0; + } + +#else + + #define CASE_OK_IMP imp_default_case_ok + + static int + imp_default_case_ok(CASE_OK_PARAMS) + { + return 1; + } + #endif static int +case_ok(CASE_OK_PARAMS) +{ + return CASE_OK_IMP(CASE_OK_ARGS); +} -case_ok(char *buf, Py_ssize_t len, Py_ssize_t namelen, char *name) -{ -/* Pick a platform-specific implementation; the sequence of #if's here should - * match the sequence just above. - */ - -/* MS_WINDOWS */ -#if defined(MS_WINDOWS) - WIN32_FIND_DATA data; - HANDLE h; - - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - - h = FindFirstFile(buf, &data); - if (h == INVALID_HANDLE_VALUE) { - PyErr_Format(PyExc_NameError, - "Can't find file for module %.100s\n(filename %.300s)", - name, buf); - return 0; - } - FindClose(h); - return strncmp(data.cFileName, name, namelen) == 0; - -/* DJGPP */ -#elif defined(DJGPP) - struct ffblk ffblk; - int done; - - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - - done = findfirst(buf, &ffblk, FA_ARCH|FA_RDONLY|FA_HIDDEN|FA_DIREC); - if (done) { - PyErr_Format(PyExc_NameError, - "Can't find file for module %.100s\n(filename %.300s)", - name, buf); - return 0; - } - return strncmp(ffblk.ff_name, name, namelen) == 0; - -/* new-fangled macintosh (macosx) or Cygwin */ -#elif _POSIX_C_SOURCE || (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) - DIR *dirp; - struct dirent *dp; - char dirname[MAXPATHLEN + 1]; - const int dirlen = len - namelen - 1; /* don't want trailing SEP */ - - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - - /* Copy the dir component into dirname; substitute "." if empty */ - if (dirlen <= 0) { - dirname[0] = '.'; - dirname[1] = '\0'; - } - else { - assert(dirlen <= MAXPATHLEN); - memcpy(dirname, buf, dirlen); - dirname[dirlen] = '\0'; - } - /* Open the directory and search the entries for an exact match. */ - dirp = opendir(dirname); - if (dirp) { - char *nameWithExt = buf + len - namelen; - while ((dp = readdir(dirp)) != NULL) { - const int thislen = -#ifdef _DIRENT_HAVE_D_NAMELEN - dp->d_namlen; -#else - strlen(dp->d_name); -#endif - if (thislen >= namelen && - strcmp(dp->d_name, nameWithExt) == 0) { - (void)closedir(dirp); - return 1; /* Found */ - } - } - (void)closedir(dirp); - } - return 0 ; /* Not found */ - -/* RISC OS */ -#elif defined(RISCOS) - char canon[MAXPATHLEN+1]; /* buffer for the canonical form of the path */ - char buf2[MAXPATHLEN+2]; - char *nameWithExt = buf+len-namelen; - int canonlen; - os_error *e; - - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - - /* workaround: - append wildcard, otherwise case of filename wouldn't be touched */ - strcpy(buf2, buf); - strcat(buf2, "*"); - - e = xosfscontrol_canonicalise_path(buf2,canon,0,0,MAXPATHLEN+1,&canonlen); - canonlen = MAXPATHLEN+1-canonlen; - if (e || canonlen<=0 || canonlen>(MAXPATHLEN+1) ) - return 0; - if (strcmp(nameWithExt, canon+canonlen-strlen(nameWithExt))==0) - return 1; /* match */ - - return 0; - -/* OS/2 */ -#elif defined(PYOS_OS2) - HDIR hdir = 1; - ULONG srchcnt = 1; - FILEFINDBUF3 ffbuf; - APIRET rc; - - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - - rc = DosFindFirst(buf, - &hdir, - FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY, - &ffbuf, sizeof(ffbuf), - &srchcnt, - FIL_STANDARD); - if (rc != NO_ERROR) - return 0; - return strncmp(ffbuf.achName, name, namelen) == 0; - -/* assuming it's a case-sensitive filesystem, so there's nothing to do! */ -#else - return 1; - -#endif -} # HG changeset patch # User Michael Witten # Date 1478883852 0 # Fri Nov 11 17:04:12 2016 +0000 # Branch 2.7 # Node ID 27f45f4d72a16f70eb73d112bfc3a8e1f0285de1 # Parent f513585d2fa120a2c14b88db3c46435c898c69c2 PEP 235: Factor out the `Py_GETENV("PYTHONCASEOK")' check The following code is common to every platform-specific implementation of the function `case_ok': if (Py_GETENV("PYTHONCASEOK") != NULL) return 1; Therefore, it has been factored out of each such implementation, and instead placed directly into the body of `case_ok'. diff -r f513585d2fa1 -r 27f45f4d72a1 Python/import.c --- a/Python/import.c Sat Oct 08 19:36:36 2016 +0000 +++ b/Python/import.c Fri Nov 11 17:04:12 2016 +0000 @@ -1672,9 +1672,6 @@ WIN32_FIND_DATA data; HANDLE h; - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - h = FindFirstFile(buf, &data); if (h == INVALID_HANDLE_VALUE) { PyErr_Format(PyExc_NameError, @@ -1698,9 +1695,6 @@ struct ffblk ffblk; int done; - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - done = findfirst(buf, &ffblk, FA_ARCH|FA_RDONLY|FA_HIDDEN|FA_DIREC); if (done) { PyErr_Format(PyExc_NameError, @@ -1732,9 +1726,6 @@ char dirname[MAXPATHLEN + 1]; const int dirlen = len - namelen - 1; /* don't want trailing SEP */ - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - /* Copy the dir component into dirname; substitute "." if empty */ if (dirlen <= 0) { dirname[0] = '.'; @@ -1779,9 +1770,6 @@ FILEFINDBUF3 ffbuf; APIRET rc; - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - rc = DosFindFirst(buf, &hdir, FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY, @@ -1808,9 +1796,6 @@ int canonlen; os_error *e; - if (Py_GETENV("PYTHONCASEOK") != NULL) - return 1; - /* workaround: append wildcard, otherwise case of filename wouldn't be touched */ strcpy(buf2, buf); @@ -1841,6 +1826,9 @@ static int case_ok(CASE_OK_PARAMS) { + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + return CASE_OK_IMP(CASE_OK_ARGS); }