| | @@ -27,33 +27,90 @@ |
| 27 | 27 | #include <sys/types.h> |
| 28 | 28 | #include <sys/stat.h> |
| 29 | 29 | #include <unistd.h> |
| 30 | 30 | #include "file.h" |
| 31 | 31 | |
| 32 | +/* |
| 33 | +** The file status information from the most recent stat() call. |
| 34 | +*/ |
| 35 | +static struct stat fileStat; |
| 36 | +static int fileStatValid = 0; |
| 37 | + |
| 38 | +/* |
| 39 | +** Fill in the fileStat variable for the file named zFilename. |
| 40 | +** If zFilename==0, then use the previous value of fileStat if |
| 41 | +** there is a previous value. |
| 42 | +** |
| 43 | +** Return the number of errors. No error messages are generated. |
| 44 | +*/ |
| 45 | +static int getStat(const char *zFilename){ |
| 46 | + if( zFilename==0 ){ |
| 47 | + if( fileStatValid==0 ) return 1; |
| 48 | + }else{ |
| 49 | + if( stat(zFilename, &fileStat)!=0 ) return 1; |
| 50 | + } |
| 51 | + return 0; |
| 52 | +} |
| 53 | + |
| 32 | 54 | |
| 33 | 55 | /* |
| 34 | 56 | ** Return the size of a file in bytes. Return -1 if the file does not |
| 35 | | -** exist. |
| 57 | +** exist. If zFilename is NULL, return the size of the most recently |
| 58 | +** stat-ed file. |
| 36 | 59 | */ |
| 37 | 60 | i64 file_size(const char *zFilename){ |
| 38 | | - struct stat buf; |
| 39 | | - if( stat(zFilename, &buf)!=0 ){ |
| 40 | | - return -1; |
| 41 | | - } |
| 42 | | - return buf.st_size; |
| 61 | + return getStat(zFilename) ? -1 : fileStat.st_size; |
| 43 | 62 | } |
| 44 | 63 | |
| 45 | 64 | /* |
| 46 | 65 | ** Return the modification time for a file. Return -1 if the file |
| 47 | | -** does not exist. |
| 66 | +** does not exist. If zFilename is NULL return the size of the most |
| 67 | +** recently stat-ed file. |
| 48 | 68 | */ |
| 49 | 69 | i64 file_mtime(const char *zFilename){ |
| 50 | | - struct stat buf; |
| 51 | | - if( stat(zFilename, &buf)!=0 ){ |
| 52 | | - return -1; |
| 70 | + return getStat(zFilename) ? -1 : fileStat.st_mtime; |
| 71 | +} |
| 72 | + |
| 73 | +/* |
| 74 | +** Return TRUE if the named file is an ordinary file. Return false |
| 75 | +** for directories, devices, fifos, symlinks, etc. |
| 76 | +*/ |
| 77 | +int file_isfile(const char *zFilename){ |
| 78 | + return getStat(zFilename) ? 0 : S_ISREG(fileStat.st_mode); |
| 79 | +} |
| 80 | + |
| 81 | +/* |
| 82 | +** Return TRUE if the named file is an executable. Return false |
| 83 | +** for directories, devices, fifos, symlinks, etc. |
| 84 | +*/ |
| 85 | +int file_isexe(const char *zFilename){ |
| 86 | + if( getStat(zFilename) || !S_ISREG(fileStat.st_mode) ) return 0; |
| 87 | +#ifdef __MINGW32__ |
| 88 | + return ((S_IXUSR)&fileStat.st_mode)!=0; |
| 89 | +#else |
| 90 | + return ((S_IXUSR|S_IXGRP|S_IXOTH)&fileStat.st_mode)!=0; |
| 91 | +#endif |
| 92 | +} |
| 93 | + |
| 94 | + |
| 95 | +/* |
| 96 | +** Return 1 if zFilename is a directory. Return 0 if zFilename |
| 97 | +** does not exist. Return 2 if zFilename exists but is something |
| 98 | +** other than a directory. |
| 99 | +*/ |
| 100 | +int file_isdir(const char *zFilename){ |
| 101 | + int rc; |
| 102 | + |
| 103 | + if( zFilename ){ |
| 104 | + char *zFN = mprintf("%s", zFilename); |
| 105 | + file_simplify_name(zFN, strlen(zFN)); |
| 106 | + rc = getStat(zFN); |
| 107 | + free(zFN); |
| 108 | + }else{ |
| 109 | + rc = getStat(0); |
| 53 | 110 | } |
| 54 | | - return buf.st_mtime; |
| 111 | + return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2); |
| 55 | 112 | } |
| 56 | 113 | |
| 57 | 114 | /* |
| 58 | 115 | ** Return the tail of a file pathname. The tail is the last component |
| 59 | 116 | ** of the path. For example, the tail of "/a/b/c.d" is "c.d". |
| | @@ -83,39 +140,10 @@ |
| 83 | 140 | } |
| 84 | 141 | fclose(in); |
| 85 | 142 | fclose(out); |
| 86 | 143 | } |
| 87 | 144 | |
| 88 | | -/* |
| 89 | | -** Return TRUE if the named file is an ordinary file. Return false |
| 90 | | -** for directories, devices, fifos, symlinks, etc. |
| 91 | | -*/ |
| 92 | | -int file_isfile(const char *zFilename){ |
| 93 | | - struct stat buf; |
| 94 | | - if( stat(zFilename, &buf)!=0 ){ |
| 95 | | - return 0; |
| 96 | | - } |
| 97 | | - return S_ISREG(buf.st_mode); |
| 98 | | -} |
| 99 | | - |
| 100 | | -/* |
| 101 | | -** Return TRUE if the named file is an executable. Return false |
| 102 | | -** for directories, devices, fifos, symlinks, etc. |
| 103 | | -*/ |
| 104 | | -int file_isexe(const char *zFilename){ |
| 105 | | - struct stat buf; |
| 106 | | - if( stat(zFilename, &buf)!=0 ){ |
| 107 | | - return 0; |
| 108 | | - } |
| 109 | | - if( !S_ISREG(buf.st_mode) ) return 0; |
| 110 | | -#ifdef __MINGW32__ |
| 111 | | - return ((S_IXUSR)&buf.st_mode)!=0; |
| 112 | | -#else |
| 113 | | - return ((S_IXUSR|S_IXGRP|S_IXOTH)&buf.st_mode)!=0; |
| 114 | | -#endif |
| 115 | | -} |
| 116 | | - |
| 117 | 145 | /* |
| 118 | 146 | ** Set or clear the execute bit on a file. |
| 119 | 147 | */ |
| 120 | 148 | void file_setexe(const char *zFilename, int onoff){ |
| 121 | 149 | #ifndef __MINGW32__ |
| | @@ -131,27 +159,10 @@ |
| 131 | 159 | } |
| 132 | 160 | } |
| 133 | 161 | #endif |
| 134 | 162 | } |
| 135 | 163 | |
| 136 | | -/* |
| 137 | | -** Return 1 if zFilename is a directory. Return 0 if zFilename |
| 138 | | -** does not exist. Return 2 if zFilename exists but is something |
| 139 | | -** other than a directory. |
| 140 | | -*/ |
| 141 | | -int file_isdir(const char *zFilename){ |
| 142 | | - struct stat buf; |
| 143 | | - int rc; |
| 144 | | - char *zFN; |
| 145 | | - |
| 146 | | - zFN = mprintf("%s", zFilename); |
| 147 | | - file_simplify_name(zFN, strlen(zFN)); |
| 148 | | - rc = stat(zFN, &buf); |
| 149 | | - free(zFN); |
| 150 | | - return rc!=0 ? 0 : (S_ISDIR(buf.st_mode) ? 1 : 2); |
| 151 | | -} |
| 152 | | - |
| 153 | 164 | /* |
| 154 | 165 | ** Create the directory named in the argument, if it does not already |
| 155 | 166 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| 156 | 167 | ** with the same name. |
| 157 | 168 | ** |
| 158 | 169 | |