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