1 /*
2 ** Copyright (c) 2006 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
13 ** drh@hwaci.com
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** File utilities.
19 */
20 #include "config.h"
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <time.h>
28 #include "file.h"
29
30 /*
31 ** On Windows, include the Platform SDK header file.
32 */
33 #ifdef _WIN32
34 # include <direct.h>
35 # include <windows.h>
36 # include <sys/utime.h>
37 #else
38 # include <sys/time.h>
39 #endif
40
41 #if INTERFACE
42
43 /* Many APIs take a eFType argument which must be one of ExtFILE, RepoFILE,
44 ** or SymFILE.
45 **
46 ** The difference is in the handling of symbolic links. RepoFILE should be
47 ** used for files that are under management by a Fossil repository. ExtFILE
48 ** should be used for files that are not under management. SymFILE is for
49 ** a few special cases such as the "fossil test-tarball" command when we never
50 ** want to follow symlinks.
51 **
52 ** ExtFILE Symbolic links always refer to the object to which the
53 ** link points. Symlinks are never recognized as symlinks but
54 ** instead always appear to the the target object.
55 **
56 ** SymFILE Symbolic links always appear to be files whose name is
57 ** the target pathname of the symbolic link.
58 **
59 ** RepoFILE Like SymFILE if allow-symlinks is true, or like
60 ** ExtFILE if allow-symlinks is false. In other words,
61 ** symbolic links are only recognized as something different
62 ** from files or directories if allow-symlinks is true.
63 */
64 #define ExtFILE 0 /* Always follow symlinks */
65 #define RepoFILE 1 /* Follow symlinks if and only if allow-symlinks is OFF */
66 #define SymFILE 2 /* Never follow symlinks */
67
68 #include <dirent.h>
69 #if defined(_WIN32)
70 # define DIR _WDIR
71 # define dirent _wdirent
72 # define opendir _wopendir
73 # define readdir _wreaddir
74 # define closedir _wclosedir
75 #endif /* _WIN32 */
76
77 #if defined(_WIN32) && (defined(__MSVCRT__) || defined(_MSC_VER))
78 /*
79 ** File status information for windows systems.
80 */
81 struct fossilStat {
82 i64 st_size;
83 i64 st_mtime;
84 int st_mode;
85 };
86 #endif
87
88 #if defined(_WIN32) || defined(__CYGWIN__)
89 # define fossil_isdirsep(a) (((a) == '/') || ((a) == '\\'))
90 #else
91 # define fossil_isdirsep(a) ((a) == '/')
92 #endif
93
94 #endif /* INTERFACE */
95
96 #if !defined(_WIN32) || !(defined(__MSVCRT__) || defined(_MSC_VER))
97 /*
98 ** File status information for unix systems
99 */
100 # define fossilStat stat
101 #endif
102
103 /*
104 ** On Windows S_ISLNK always returns FALSE.
105 */
106 #if !defined(S_ISLNK)
107 # define S_ISLNK(x) (0)
108 #endif
109
110 /*
111 ** Local state information for the file status routines
112 */
113 static struct {
114 struct fossilStat fileStat; /* File status from last fossil_stat() */
115 int fileStatValid; /* True if fileStat is valid */
116 } fx;
117
118 /*
119 ** Fill *buf with information about zFilename.
120 **
121 ** If zFilename refers to a symbolic link:
122 **
123 ** (A) If allow-symlinks is on and eFType is RepoFILE, then fill
124 ** *buf with information about the symbolic link itself.
125 **
126 ** (B) If allow-symlinks is off or eFType is ExtFILE, then fill
127 ** *buf with information about the object that the symbolic link
128 ** points to.
129 */
fossil_stat(const char * zFilename,struct fossilStat * buf,int eFType)130 static int fossil_stat(
131 const char *zFilename, /* name of file or directory to inspect. */
132 struct fossilStat *buf, /* pointer to buffer where info should go. */
133 int eFType /* Look at symlink itself if RepoFILE and enabled. */
134 ){
135 int rc;
136 void *zMbcs = fossil_utf8_to_path(zFilename, 0);
137 #if !defined(_WIN32)
138 if( (eFType==RepoFILE && db_allow_symlinks())
139 || eFType==SymFILE ){
140 /* Symlinks look like files whose content is the name of the target */
141 rc = lstat(zMbcs, buf);
142 }else{
143 /* Symlinks look like the object to which they point */
144 rc = stat(zMbcs, buf);
145 }
146 #else
147 rc = win32_stat(zMbcs, buf, eFType);
148 #endif
149 fossil_path_free(zMbcs);
150 return rc;
151 }
152
153 /*
154 ** Clears the fx.fileStat variable and its associated validity flag.
155 */
resetStat()156 static void resetStat(){
157 fx.fileStatValid = 0;
158 memset(&fx.fileStat, 0, sizeof(struct fossilStat));
159 }
160
161 /*
162 ** Fill in the fx.fileStat variable for the file named zFilename.
163 ** If zFilename==0, then use the previous value of fx.fileStat if
164 ** there is a previous value.
165 **
166 ** Return the number of errors. No error messages are generated.
167 */
getStat(const char * zFilename,int eFType)168 static int getStat(const char *zFilename, int eFType){
169 int rc = 0;
170 if( zFilename==0 ){
171 if( fx.fileStatValid==0 ) rc = 1;
172 }else{
173 if( fossil_stat(zFilename, &fx.fileStat, eFType)!=0 ){
174 fx.fileStatValid = 0;
175 rc = 1;
176 }else{
177 fx.fileStatValid = 1;
178 rc = 0;
179 }
180 }
181 return rc;
182 }
183
184 /*
185 ** Return the size of a file in bytes. Return -1 if the file does not
186 ** exist. If zFilename is NULL, return the size of the most recently
187 ** stat-ed file.
188 */
file_size(const char * zFilename,int eFType)189 i64 file_size(const char *zFilename, int eFType){
190 return getStat(zFilename, eFType) ? -1 : fx.fileStat.st_size;
191 }
192
193 /*
194 ** Return the modification time for a file. Return -1 if the file
195 ** does not exist. If zFilename is NULL return the size of the most
196 ** recently stat-ed file.
197 */
file_mtime(const char * zFilename,int eFType)198 i64 file_mtime(const char *zFilename, int eFType){
199 return getStat(zFilename, eFType) ? -1 : fx.fileStat.st_mtime;
200 }
201
202 /*
203 ** Return the mode bits for a file. Return -1 if the file does not
204 ** exist. If zFilename is NULL return the size of the most recently
205 ** stat-ed file.
206 */
file_mode(const char * zFilename,int eFType)207 int file_mode(const char *zFilename, int eFType){
208 return getStat(zFilename, eFType) ? -1 : fx.fileStat.st_mode;
209 }
210
211 /*
212 ** Return TRUE if either of the following are true:
213 **
214 ** (1) zFilename is an ordinary file
215 **
216 ** (2) allow_symlinks is on and zFilename is a symbolic link to
217 ** a file, directory, or other object
218 */
file_isfile_or_link(const char * zFilename)219 int file_isfile_or_link(const char *zFilename){
220 if( getStat(zFilename, RepoFILE) ){
221 return 0; /* stat() failed. Return false. */
222 }
223 return S_ISREG(fx.fileStat.st_mode) || S_ISLNK(fx.fileStat.st_mode);
224 }
225
226 /*
227 ** Return TRUE if the named file is an ordinary file. Return false
228 ** for directories, devices, fifos, symlinks, etc.
229 */
file_isfile(const char * zFilename,int eFType)230 int file_isfile(const char *zFilename, int eFType){
231 return getStat(zFilename, eFType) ? 0 : S_ISREG(fx.fileStat.st_mode);
232 }
233
234 /*
235 ** Create a symbolic link named zLinkFile that points to zTargetFile.
236 **
237 ** If allow-symlinks is off, create an ordinary file named zLinkFile
238 ** with the name of zTargetFile as its content.
239 **/
symlink_create(const char * zTargetFile,const char * zLinkFile)240 void symlink_create(const char *zTargetFile, const char *zLinkFile){
241 #if !defined(_WIN32)
242 if( db_allow_symlinks() ){
243 int i, nName;
244 char *zName, zBuf[1000];
245
246 nName = strlen(zLinkFile);
247 if( nName>=sizeof(zBuf) ){
248 zName = mprintf("%s", zLinkFile);
249 }else{
250 zName = zBuf;
251 memcpy(zName, zLinkFile, nName+1);
252 }
253 nName = file_simplify_name(zName, nName, 0);
254 for(i=1; i<nName; i++){
255 if( zName[i]=='/' ){
256 zName[i] = 0;
257 if( file_mkdir(zName, ExtFILE, 1) ){
258 fossil_fatal_recursive("unable to create directory %s", zName);
259 return;
260 }
261 zName[i] = '/';
262 }
263 }
264 if( symlink(zTargetFile, zName)!=0 ){
265 fossil_fatal_recursive("unable to create symlink \"%s\"", zName);
266 }
267 if( zName!=zBuf ) free(zName);
268 }else
269 #endif
270 {
271 Blob content;
272 blob_set(&content, zTargetFile);
273 blob_write_to_file(&content, zLinkFile);
274 blob_reset(&content);
275 }
276 }
277
278 /*
279 ** Copy symbolic link from zFrom to zTo.
280 */
symlink_copy(const char * zFrom,const char * zTo)281 void symlink_copy(const char *zFrom, const char *zTo){
282 Blob content;
283 blob_read_link(&content, zFrom);
284 symlink_create(blob_str(&content), zTo);
285 blob_reset(&content);
286 }
287
288 /*
289 ** Return file permissions (normal, executable, or symlink):
290 ** - PERM_EXE on Unix if file is executable;
291 ** - PERM_LNK on Unix if file is symlink and allow-symlinks option is on;
292 ** - PERM_REG for all other cases (regular file, directory, fifo, etc).
293 **
294 ** If eFType is ExtFile then symbolic links are followed and so this
295 ** routine can only return PERM_EXE and PERM_REG.
296 **
297 ** On windows, this routine returns only PERM_REG.
298 */
file_perm(const char * zFilename,int eFType)299 int file_perm(const char *zFilename, int eFType){
300 #if !defined(_WIN32)
301 if( !getStat(zFilename, eFType) ){
302 if( S_ISREG(fx.fileStat.st_mode) && ((S_IXUSR)&fx.fileStat.st_mode)!=0 )
303 return PERM_EXE;
304 else if( db_allow_symlinks() && S_ISLNK(fx.fileStat.st_mode) )
305 return PERM_LNK;
306 }
307 #endif
308 return PERM_REG;
309 }
310
311 /*
312 ** Return TRUE if the named file is an executable. Return false
313 ** for directories, devices, fifos, symlinks, etc.
314 */
file_isexe(const char * zFilename,int eFType)315 int file_isexe(const char *zFilename, int eFType){
316 return file_perm(zFilename, eFType)==PERM_EXE;
317 }
318
319 /*
320 ** Return TRUE if the named file is a symlink and symlinks are allowed.
321 ** Return false for all other cases.
322 **
323 ** This routines assumes RepoFILE - that zFilename is always a file
324 ** under management.
325 **
326 ** On Windows, always return False.
327 */
file_islink(const char * zFilename)328 int file_islink(const char *zFilename){
329 return file_perm(zFilename, RepoFILE)==PERM_LNK;
330 }
331
332 /*
333 ** Check every sub-directory of zRoot along the path to zFile.
334 ** If any sub-directory is really an ordinary file or a symbolic link,
335 ** return an integer which is the length of the prefix of zFile which
336 ** is the name of that object. Return 0 if all no non-directory
337 ** objects are found along the path.
338 **
339 ** Example: Given inputs
340 **
341 ** zRoot = /home/alice/project1
342 ** zFile = /home/alice/project1/main/src/js/fileA.js
343 **
344 ** Look for objects in the following order:
345 **
346 ** /home/alice/project/main
347 ** /home/alice/project/main/src
348 ** /home/alice/project/main/src/js
349 **
350 ** If any of those objects exist and are something other than a directory
351 ** then return the length of the name of the first non-directory object
352 ** seen.
353 */
file_nondir_objects_on_path(const char * zRoot,const char * zFile)354 int file_nondir_objects_on_path(const char *zRoot, const char *zFile){
355 int i = (int)strlen(zRoot);
356 char *z = fossil_strdup(zFile);
357 assert( fossil_strnicmp(zRoot, z, i)==0 );
358 if( i && zRoot[i-1]=='/' ) i--;
359 while( z[i]=='/' ){
360 int j, rc;
361 for(j=i+1; z[j] && z[j]!='/'; j++){}
362 if( z[j]!='/' ) break;
363 z[j] = 0;
364 rc = file_isdir(z, SymFILE);
365 if( rc!=1 ){
366 if( rc==2 ){
367 fossil_free(z);
368 return j;
369 }
370 break;
371 }
372 z[j] = '/';
373 i = j;
374 }
375 fossil_free(z);
376 return 0;
377 }
378
379 /*
380 ** The file named zFile is suppose to be an in-tree file. Check to
381 ** ensure that it will be safe to write to this file by verifying that
382 ** there are no symlinks or other non-directory objects in between the
383 ** root of the checkout and zFile.
384 **
385 ** If a problem is found, print a warning message (using fossil_warning())
386 ** and return non-zero. If everything is ok, return zero.
387 */
file_unsafe_in_tree_path(const char * zFile)388 int file_unsafe_in_tree_path(const char *zFile){
389 int n;
390 if( !file_is_absolute_path(zFile) ){
391 fossil_fatal("%s is not an absolute pathname",zFile);
392 }
393 if( fossil_strnicmp(g.zLocalRoot, zFile, (int)strlen(g.zLocalRoot)) ){
394 fossil_fatal("%s is not a prefix of %s", g.zLocalRoot, zFile);
395 }
396 n = file_nondir_objects_on_path(g.zLocalRoot, zFile);
397 if( n ){
398 fossil_warning("cannot write to %s because non-directory object %.*s"
399 " is in the way", zFile, n, zFile);
400 }
401 return n;
402 }
403
404 /*
405 ** Return 1 if zFilename is a directory. Return 0 if zFilename
406 ** does not exist. Return 2 if zFilename exists but is something
407 ** other than a directory.
408 */
file_isdir(const char * zFilename,int eFType)409 int file_isdir(const char *zFilename, int eFType){
410 int rc;
411 char *zFN;
412
413 zFN = mprintf("%s", zFilename);
414 file_simplify_name(zFN, -1, 0);
415 rc = getStat(zFN, eFType);
416 if( rc ){
417 rc = 0; /* It does not exist at all. */
418 }else if( S_ISDIR(fx.fileStat.st_mode) ){
419 rc = 1; /* It exists and is a real directory. */
420 }else{
421 rc = 2; /* It exists and is something else. */
422 }
423 free(zFN);
424 return rc;
425 }
426
427 /*
428 ** Return true (1) if zFilename seems like it seems like a valid
429 ** repository database.
430 */
file_is_repository(const char * zFilename)431 int file_is_repository(const char *zFilename){
432 i64 sz;
433 sqlite3 *db = 0;
434 sqlite3_stmt *pStmt = 0;
435 int rc;
436 int i;
437 static const char *azReqTab[] = {
438 "blob", "delta", "rcvfrom", "user", "config"
439 };
440 if( !file_isfile(zFilename, ExtFILE) ) return 0;
441 sz = file_size(zFilename, ExtFILE);
442 if( sz<35328 ) return 0;
443 if( sz%512!=0 ) return 0;
444 rc = sqlite3_open_v2(zFilename, &db,
445 SQLITE_OPEN_READWRITE, 0);
446 if( rc!=0 ) goto not_a_repo;
447 for(i=0; i<count(azReqTab); i++){
448 if( sqlite3_table_column_metadata(db, "main", azReqTab[i],0,0,0,0,0,0) ){
449 goto not_a_repo;
450 }
451 }
452 rc = sqlite3_prepare_v2(db, "SELECT 1 FROM config WHERE name='project-code'",
453 -1, &pStmt, 0);
454 if( rc ) goto not_a_repo;
455 rc = sqlite3_step(pStmt);
456 if( rc!=SQLITE_ROW ) goto not_a_repo;
457 sqlite3_finalize(pStmt);
458 sqlite3_close(db);
459 return 1;
460
461 not_a_repo:
462 sqlite3_finalize(pStmt);
463 sqlite3_close(db);
464 return 0;
465 }
466
467
468 /*
469 ** Wrapper around the access() system call.
470 */
file_access(const char * zFilename,int flags)471 int file_access(const char *zFilename, int flags){
472 int rc;
473 void *zMbcs = fossil_utf8_to_path(zFilename, 0);
474 #ifdef _WIN32
475 rc = win32_access(zMbcs, flags);
476 #else
477 rc = access(zMbcs, flags);
478 #endif
479 fossil_path_free(zMbcs);
480 return rc;
481 }
482
483 /*
484 ** Wrapper around the chdir() system call.
485 ** If bChroot=1, do a chroot to this dir as well
486 ** (UNIX only)
487 */
file_chdir(const char * zChDir,int bChroot)488 int file_chdir(const char *zChDir, int bChroot){
489 int rc;
490 void *zPath = fossil_utf8_to_path(zChDir, 1);
491 #ifdef _WIN32
492 rc = win32_chdir(zPath, bChroot);
493 #else
494 rc = chdir(zPath);
495 if( !rc && bChroot ){
496 rc = chroot(zPath);
497 if( !rc ) rc = chdir("/");
498 }
499 #endif
500 fossil_path_free(zPath);
501 return rc;
502 }
503
504 /*
505 ** Find an unused filename similar to zBase with zSuffix appended.
506 **
507 ** Make the name relative to the working directory if relFlag is true.
508 **
509 ** Space to hold the new filename is obtained form mprintf() and should
510 ** be freed by the caller.
511 */
file_newname(const char * zBase,const char * zSuffix,int relFlag)512 char *file_newname(const char *zBase, const char *zSuffix, int relFlag){
513 char *z = 0;
514 int cnt = 0;
515 z = mprintf("%s-%s", zBase, zSuffix);
516 while( file_size(z, ExtFILE)>=0 ){
517 fossil_free(z);
518 z = mprintf("%s-%s-%d", zBase, zSuffix, cnt++);
519 }
520 if( relFlag ){
521 Blob x;
522 file_relative_name(z, &x, 0);
523 fossil_free(z);
524 z = blob_str(&x);
525 }
526 return z;
527 }
528
529 /*
530 ** Return the tail of a file pathname. The tail is the last component
531 ** of the path. For example, the tail of "/a/b/c.d" is "c.d".
532 */
file_tail(const char * z)533 const char *file_tail(const char *z){
534 const char *zTail = z;
535 if( !zTail ) return 0;
536 while( z[0] ){
537 if( fossil_isdirsep(z[0]) ) zTail = &z[1];
538 z++;
539 }
540 return zTail;
541 }
542
543 /*
544 ** Return the directory of a file path name. The directory is all components
545 ** except the last one. For example, the directory of "/a/b/c.d" is "/a/b".
546 ** If there is no directory, NULL is returned; otherwise, the returned memory
547 ** should be freed via fossil_free().
548 */
file_dirname(const char * z)549 char *file_dirname(const char *z){
550 const char *zTail = file_tail(z);
551 if( zTail && zTail!=z ){
552 return mprintf("%.*s", (int)(zTail-z-1), z);
553 }else{
554 return 0;
555 }
556 }
557
558 /* SQL Function: file_dirname(NAME)
559 **
560 ** Return the directory for NAME
561 */
file_dirname_sql_function(sqlite3_context * context,int argc,sqlite3_value ** argv)562 void file_dirname_sql_function(
563 sqlite3_context *context,
564 int argc,
565 sqlite3_value **argv
566 ){
567 const char *zName = (const char*)sqlite3_value_text(argv[0]);
568 char *zDir;
569 if( zName==0 ) return;
570 zDir = file_dirname(zName);
571 if( zDir ){
572 sqlite3_result_text(context,zDir,-1,fossil_free);
573 }
574 }
575
576
577 /*
578 ** Rename a file or directory.
579 ** Returns zero upon success.
580 */
file_rename(const char * zFrom,const char * zTo,int isFromDir,int isToDir)581 int file_rename(
582 const char *zFrom,
583 const char *zTo,
584 int isFromDir,
585 int isToDir
586 ){
587 int rc;
588 #if defined(_WIN32)
589 wchar_t *zMbcsFrom = fossil_utf8_to_path(zFrom, isFromDir);
590 wchar_t *zMbcsTo = fossil_utf8_to_path(zTo, isToDir);
591 rc = _wrename(zMbcsFrom, zMbcsTo);
592 #else
593 char *zMbcsFrom = fossil_utf8_to_path(zFrom, isFromDir);
594 char *zMbcsTo = fossil_utf8_to_path(zTo, isToDir);
595 rc = rename(zMbcsFrom, zMbcsTo);
596 #endif
597 fossil_path_free(zMbcsTo);
598 fossil_path_free(zMbcsFrom);
599 return rc;
600 }
601
602 /*
603 ** Copy the content of a file from one place to another.
604 */
file_copy(const char * zFrom,const char * zTo)605 void file_copy(const char *zFrom, const char *zTo){
606 FILE *in, *out;
607 int got;
608 char zBuf[8192];
609 in = fossil_fopen(zFrom, "rb");
610 if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom);
611 file_mkfolder(zTo, ExtFILE, 0, 0);
612 out = fossil_fopen(zTo, "wb");
613 if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo);
614 while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){
615 fwrite(zBuf, 1, got, out);
616 }
617 fclose(in);
618 fclose(out);
619 if( file_isexe(zFrom, ExtFILE) ) file_setexe(zTo, 1);
620 }
621
622 /*
623 ** COMMAND: test-file-copy
624 **
625 ** Usage: %fossil test-file-copy SOURCE DESTINATION
626 **
627 ** Make a copy of the file at SOURCE into a new name DESTINATION. Any
628 ** directories in the path leading up to DESTINATION that do not already
629 ** exist are created automatically.
630 */
test_file_copy(void)631 void test_file_copy(void){
632 if( g.argc!=4 ){
633 fossil_fatal("Usage: %s test-file-copy SOURCE DESTINATION", g.argv[0]);
634 }
635 file_copy(g.argv[2], g.argv[3]);
636 }
637
638 /*
639 ** Set or clear the execute bit on a file. Return true if a change
640 ** occurred and false if this routine is a no-op.
641 **
642 ** This routine assumes RepoFILE as the eFType. In other words, if
643 ** zFilename is a symbolic link, it is the object that zFilename points
644 ** to that is modified.
645 */
file_setexe(const char * zFilename,int onoff)646 int file_setexe(const char *zFilename, int onoff){
647 int rc = 0;
648 #if !defined(_WIN32)
649 struct stat buf;
650 if( fossil_stat(zFilename, &buf, RepoFILE)!=0
651 || S_ISLNK(buf.st_mode)
652 || S_ISDIR(buf.st_mode)
653 ){
654 return 0;
655 }
656 if( onoff ){
657 int targetMode = (buf.st_mode & 0444)>>2;
658 if( (buf.st_mode & 0100)==0 ){
659 chmod(zFilename, buf.st_mode | targetMode);
660 rc = 1;
661 }
662 }else{
663 if( (buf.st_mode & 0100)!=0 ){
664 chmod(zFilename, buf.st_mode & ~0111);
665 rc = 1;
666 }
667 }
668 #endif /* _WIN32 */
669 return rc;
670 }
671
672 /*
673 ** Set the mtime for a file.
674 */
file_set_mtime(const char * zFilename,i64 newMTime)675 void file_set_mtime(const char *zFilename, i64 newMTime){
676 #if !defined(_WIN32)
677 char *zMbcs;
678 struct timeval tv[2];
679 memset(tv, 0, sizeof(tv[0])*2);
680 tv[0].tv_sec = newMTime;
681 tv[1].tv_sec = newMTime;
682 zMbcs = fossil_utf8_to_path(zFilename, 0);
683 utimes(zMbcs, tv);
684 #else
685 struct _utimbuf tb;
686 wchar_t *zMbcs = fossil_utf8_to_path(zFilename, 0);
687 tb.actime = newMTime;
688 tb.modtime = newMTime;
689 _wutime(zMbcs, &tb);
690 #endif
691 fossil_path_free(zMbcs);
692 }
693
694 /*
695 ** COMMAND: test-set-mtime
696 **
697 ** Usage: %fossil test-set-mtime FILENAME DATE/TIME
698 **
699 ** Sets the mtime of the named file to the date/time shown.
700 */
test_set_mtime(void)701 void test_set_mtime(void){
702 const char *zFile;
703 char *zDate;
704 i64 iMTime;
705 if( g.argc!=4 ){
706 usage("FILENAME DATE/TIME");
707 }
708 db_open_or_attach(":memory:", "mem");
709 iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
710 zFile = g.argv[2];
711 file_set_mtime(zFile, iMTime);
712 iMTime = file_mtime(zFile, RepoFILE);
713 zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
714 fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
715 }
716
717 /*
718 ** Delete a file.
719 **
720 ** If zFilename is a symbolic link, then it is the link itself that is
721 ** removed, not the object that zFilename points to.
722 **
723 ** Returns zero upon success.
724 */
file_delete(const char * zFilename)725 int file_delete(const char *zFilename){
726 int rc;
727 #ifdef _WIN32
728 wchar_t *z = fossil_utf8_to_path(zFilename, 0);
729 rc = _wunlink(z);
730 #else
731 char *z = fossil_utf8_to_path(zFilename, 0);
732 rc = unlink(zFilename);
733 #endif
734 fossil_path_free(z);
735 return rc;
736 }
737
738 /* SQL Function: file_delete(NAME)
739 **
740 ** Remove file NAME. Return zero on success and non-zero if anything goes
741 ** wrong.
742 */
file_delete_sql_function(sqlite3_context * context,int argc,sqlite3_value ** argv)743 void file_delete_sql_function(
744 sqlite3_context *context,
745 int argc,
746 sqlite3_value **argv
747 ){
748 const char *zName = (const char*)sqlite3_value_text(argv[0]);
749 int rc;
750 if( zName==0 ){
751 rc = 1;
752 }else{
753 rc = file_delete(zName);
754 }
755 sqlite3_result_int(context, rc);
756 }
757
758 /*
759 ** Create a directory called zName, if it does not already exist.
760 ** If forceFlag is 1, delete any prior non-directory object
761 ** with the same name.
762 **
763 ** Return the number of errors.
764 */
file_mkdir(const char * zName,int eFType,int forceFlag)765 int file_mkdir(const char *zName, int eFType, int forceFlag){
766 int rc = file_isdir(zName, eFType);
767 if( rc==2 ){
768 if( !forceFlag ) return 1;
769 file_delete(zName);
770 }
771 if( rc!=1 ){
772 #if defined(_WIN32)
773 wchar_t *zMbcs = fossil_utf8_to_path(zName, 1);
774 rc = _wmkdir(zMbcs);
775 #else
776 char *zMbcs = fossil_utf8_to_path(zName, 1);
777 rc = mkdir(zMbcs, 0755);
778 #endif
779 fossil_path_free(zMbcs);
780 return rc;
781 }
782 return 0;
783 }
784
785 /*
786 ** Create the tree of directories in which zFilename belongs, if that sequence
787 ** of directories does not already exist.
788 **
789 ** On success, return zero. On error, return errorReturn if positive, otherwise
790 ** print an error message and abort.
791 */
file_mkfolder(const char * zFilename,int eFType,int forceFlag,int errorReturn)792 int file_mkfolder(
793 const char *zFilename, /* Pathname showing directories to be created */
794 int eFType, /* Follow symlinks if ExtFILE */
795 int forceFlag, /* Delete non-directory objects in the way */
796 int errorReturn /* What to do when an error is seen */
797 ){
798 int nName, rc = 0;
799 char *zName;
800
801 nName = strlen(zFilename);
802 zName = mprintf("%s", zFilename);
803 nName = file_simplify_name(zName, nName, 0);
804 while( nName>0 && zName[nName-1]!='/' ){ nName--; }
805 if( nName>1 ){
806 zName[nName-1] = 0;
807 if( file_isdir(zName, eFType)!=1 ){
808 rc = file_mkfolder(zName, eFType, forceFlag, errorReturn);
809 if( rc==0 ){
810 if( file_mkdir(zName, eFType, forceFlag)
811 && file_isdir(zName, eFType)!=1
812 ){
813 if( errorReturn <= 0 ){
814 fossil_fatal_recursive("unable to create directory %s", zName);
815 }
816 rc = errorReturn;
817 }
818 }
819 }
820 }
821 free(zName);
822 return rc;
823 }
824
825 #if defined(_WIN32)
826 /*
827 ** Returns non-zero if the specified name represents a real directory, i.e.
828 ** not a junction or symbolic link. This is important for some operations,
829 ** e.g. removing directories via _wrmdir(), because its detection of empty
830 ** directories will (apparently) not work right for junctions and symbolic
831 ** links, etc.
832 */
file_is_normal_dir(wchar_t * zName)833 int file_is_normal_dir(wchar_t *zName){
834 /*
835 ** Mask off attributes, applicable to directories, that are harmless for
836 ** our purposes. This may need to be updated if other attributes should
837 ** be ignored by this function.
838 */
839 DWORD dwAttributes = GetFileAttributesW(zName);
840 if( dwAttributes==INVALID_FILE_ATTRIBUTES ) return 0;
841 dwAttributes &= ~(
842 FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_COMPRESSED |
843 FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_NORMAL |
844 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
845 );
846 return dwAttributes==FILE_ATTRIBUTE_DIRECTORY;
847 }
848
849 /*
850 ** COMMAND: test-is-normal-dir
851 **
852 ** Usage: %fossil test-is-normal-dir NAME...
853 **
854 ** Returns non-zero if the specified names represent real directories, i.e.
855 ** not junctions, symbolic links, etc.
856 */
test_is_normal_dir(void)857 void test_is_normal_dir(void){
858 int i;
859 for(i=2; i<g.argc; i++){
860 wchar_t *zMbcs = fossil_utf8_to_path(g.argv[i], 1);
861 fossil_print("ATTRS \"%s\" -> %lx\n", g.argv[i], GetFileAttributesW(zMbcs));
862 fossil_print("ISDIR \"%s\" -> %d\n", g.argv[i], file_is_normal_dir(zMbcs));
863 fossil_path_free(zMbcs);
864 }
865 }
866 #endif
867
868 /*
869 ** Removes the directory named in the argument, if it exists. The directory
870 ** must be empty and cannot be the current directory or the root directory.
871 **
872 ** Returns zero upon success.
873 */
file_rmdir(const char * zName)874 int file_rmdir(const char *zName){
875 int rc = file_isdir(zName, RepoFILE);
876 if( rc==2 ) return 1; /* cannot remove normal file */
877 if( rc==1 ){
878 #if defined(_WIN32)
879 wchar_t *zMbcs = fossil_utf8_to_path(zName, 1);
880 if( file_is_normal_dir(zMbcs) ){
881 rc = _wrmdir(zMbcs);
882 }else{
883 rc = ENOTDIR; /* junction, symbolic link, etc. */
884 }
885 #else
886 char *zMbcs = fossil_utf8_to_path(zName, 1);
887 rc = rmdir(zName);
888 #endif
889 fossil_path_free(zMbcs);
890 return rc;
891 }
892 return 0;
893 }
894
895 /* SQL Function: rmdir(NAME)
896 **
897 ** Try to remove the directory NAME. Return zero on success and non-zero
898 ** for failure.
899 */
file_rmdir_sql_function(sqlite3_context * context,int argc,sqlite3_value ** argv)900 void file_rmdir_sql_function(
901 sqlite3_context *context,
902 int argc,
903 sqlite3_value **argv
904 ){
905 const char *zName = (const char*)sqlite3_value_text(argv[0]);
906 int rc;
907 if( zName==0 ){
908 rc = 1;
909 }else{
910 rc = file_rmdir(zName);
911 }
912 sqlite3_result_int(context, rc);
913 }
914
915 /*
916 ** Check the input argument to see if it looks like it has an prefix that
917 ** indicates a remote file. If so, return the tail of the specification,
918 ** which is the name of the file on the remote system.
919 **
920 ** If the input argument does not have a prefix that makes it look like
921 ** a remote file reference, then return NULL.
922 **
923 ** Remote files look like: "HOST:PATH" or "USER@HOST:PATH". Host must
924 ** be a valid hostname, meaning it must follow these rules:
925 **
926 ** * Only characters [-.a-zA-Z0-9]. No spaces or other punctuation
927 ** * Does not begin or end with -
928 ** * Name is two or more characters long (otherwise it might be
929 ** confused with a drive-letter on Windows).
930 **
931 ** The USER section, if it exists, must not contain the '@' character.
932 */
file_skip_userhost(const char * zIn)933 const char *file_skip_userhost(const char *zIn){
934 const char *zTail;
935 int n, i;
936 if( zIn[0]==':' ) return 0;
937 zTail = strchr(zIn, ':');
938 if( zTail==0 ) return 0;
939 if( zTail - zIn > 10000 ) return 0;
940 n = (int)(zTail - zIn);
941 if( n<2 ) return 0;
942 if( zIn[n-1]=='-' || zIn[n-1]=='.' ) return 0;
943 for(i=n-1; i>0 && zIn[i-1]!='@'; i--){
944 if( !fossil_isalnum(zIn[i]) && zIn[i]!='-' && zIn[i]!='.' ) return 0;
945 }
946 if( zIn[i]=='-' || zIn[i]=='.' || i==1 ) return 0;
947 if( i>1 ){
948 i -= 2;
949 while( i>=0 ){
950 if( zIn[i]=='@' ) return 0;
951 i--;
952 }
953 }
954 return zTail+1;
955 }
956
957 /*
958 ** Return true if the filename given is a valid filename for
959 ** a file in a repository. Valid filenames follow all of the
960 ** following rules:
961 **
962 ** * Does not begin with "/"
963 ** * Does not contain any path element named "." or ".."
964 ** * Does not contain any of these characters in the path: "\"
965 ** * Does not end with "/".
966 ** * Does not contain two or more "/" characters in a row.
967 ** * Contains at least one character
968 **
969 ** Invalid UTF8 characters result in a false return if bStrictUtf8 is
970 ** true. If bStrictUtf8 is false, invalid UTF8 characters are silently
971 ** ignored. See http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
972 ** and http://en.wikipedia.org/wiki/Unicode (for the noncharacters)
973 **
974 ** The bStrictUtf8 flag is true for new inputs, but is false when parsing
975 ** legacy manifests, for backwards compatibility.
976 */
file_is_simple_pathname(const char * z,int bStrictUtf8)977 int file_is_simple_pathname(const char *z, int bStrictUtf8){
978 int i;
979 unsigned char c = (unsigned char) z[0];
980 char maskNonAscii = bStrictUtf8 ? 0x80 : 0x00;
981 if( c=='/' || c==0 ) return 0;
982 if( c=='.' ){
983 if( z[1]=='/' || z[1]==0 ) return 0;
984 if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
985 }
986 for(i=0; (c=(unsigned char)z[i])!=0; i++){
987 if( c & maskNonAscii ){
988 if( (z[++i]&0xc0)!=0x80 ){
989 /* Invalid first continuation byte */
990 return 0;
991 }
992 if( c<0xc2 ){
993 /* Invalid 1-byte UTF-8 sequence, or 2-byte overlong form. */
994 return 0;
995 }else if( (c&0xe0)==0xe0 ){
996 /* 3-byte or more */
997 int unicode;
998 if( c&0x10 ){
999 /* Unicode characters > U+FFFF are not supported.
1000 * Windows XP and earlier cannot handle them.
1001 */
1002 return 0;
1003 }
1004 /* This is a 3-byte UTF-8 character */
1005 unicode = ((c&0x0f)<<12) + ((z[i]&0x3f)<<6) + (z[i+1]&0x3f);
1006 if( unicode <= 0x07ff ){
1007 /* overlong form */
1008 return 0;
1009 }else if( unicode>=0xe000 ){
1010 /* U+E000..U+FFFF */
1011 if( (unicode<=0xf8ff) || (unicode>=0xfffe) ){
1012 /* U+E000..U+F8FF are for private use.
1013 * U+FFFE..U+FFFF are noncharacters. */
1014 return 0;
1015 } else if( (unicode>=0xfdd0) && (unicode<=0xfdef) ){
1016 /* U+FDD0..U+FDEF are noncharacters. */
1017 return 0;
1018 }
1019 }else if( (unicode>=0xd800) && (unicode<=0xdfff) ){
1020 /* U+D800..U+DFFF are for surrogate pairs. */
1021 return 0;
1022 }
1023 if( (z[++i]&0xc0)!=0x80 ){
1024 /* Invalid second continuation byte */
1025 return 0;
1026 }
1027 }
1028 }else if( bStrictUtf8 && (c=='\\') ){
1029 return 0;
1030 }
1031 if( c=='/' ){
1032 if( z[i+1]=='/' ) return 0;
1033 if( z[i+1]=='.' ){
1034 if( z[i+2]=='/' || z[i+2]==0 ) return 0;
1035 if( z[i+2]=='.' && (z[i+3]=='/' || z[i+3]==0) ) return 0;
1036 }
1037 }
1038 }
1039 if( z[i-1]=='/' ) return 0;
1040 return 1;
1041 }
file_is_simple_pathname_nonstrict(const char * z)1042 int file_is_simple_pathname_nonstrict(const char *z){
1043 unsigned char c = (unsigned char) z[0];
1044 if( c=='/' || c==0 ) return 0;
1045 if( c=='.' ){
1046 if( z[1]=='/' || z[1]==0 ) return 0;
1047 if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
1048 }
1049 while( (z = strchr(z+1, '/'))!=0 ){
1050 if( z[1]=='/' ) return 0;
1051 if( z[1]==0 ) return 0;
1052 if( z[1]=='.' ){
1053 if( z[2]=='/' || z[2]==0 ) return 0;
1054 if( z[2]=='.' && (z[3]=='/' || z[3]==0) ) return 0;
1055 }
1056 }
1057 return 1;
1058 }
1059
1060 /*
1061 ** If the last component of the pathname in z[0]..z[j-1] is something
1062 ** other than ".." then back it out and return true. If the last
1063 ** component is empty or if it is ".." then return false.
1064 */
backup_dir(const char * z,int * pJ)1065 static int backup_dir(const char *z, int *pJ){
1066 int j = *pJ;
1067 int i;
1068 if( j<=0 ) return 0;
1069 for(i=j-1; i>0 && z[i-1]!='/'; i--){}
1070 if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0;
1071 *pJ = i-1;
1072 return 1;
1073 }
1074
1075 /*
1076 ** Simplify a filename by
1077 **
1078 ** * Remove extended path prefix on windows and cygwin
1079 ** * Convert all \ into / on windows and cygwin
1080 ** * removing any trailing and duplicate /
1081 ** * removing /./
1082 ** * removing /A/../
1083 **
1084 ** Changes are made in-place. Return the new name length.
1085 ** If the slash parameter is non-zero, the trailing slash, if any,
1086 ** is retained.
1087 */
file_simplify_name(char * z,int n,int slash)1088 int file_simplify_name(char *z, int n, int slash){
1089 int i = 1, j;
1090 assert( z!=0 );
1091 if( n<0 ) n = strlen(z);
1092 if( n==0 ) return 0;
1093
1094 /* On windows and cygwin convert all \ characters to /
1095 * and remove extended path prefix if present */
1096 #if defined(_WIN32) || defined(__CYGWIN__)
1097 for(j=0; j<n; j++){
1098 if( z[j]=='\\' ) z[j] = '/';
1099 }
1100 if( n>3 && !memcmp(z, "//?/", 4) ){
1101 if( fossil_strnicmp(z+4,"UNC", 3) ){
1102 i += 4;
1103 z[0] = z[4];
1104 }else{
1105 i += 6;
1106 z[0] = '/';
1107 }
1108 }
1109 #endif
1110
1111 /* Removing trailing "/" characters */
1112 if( !slash ){
1113 while( n>1 && z[n-1]=='/' ){ n--; }
1114 }
1115
1116 /* Remove duplicate '/' characters. Except, two // at the beginning
1117 ** of a pathname is allowed since this is important on windows. */
1118 for(j=1; i<n; i++){
1119 z[j++] = z[i];
1120 while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
1121 }
1122 n = j;
1123
1124 /* Skip over zero or more initial "./" sequences */
1125 for(i=0; i<n-1 && z[i]=='.' && z[i+1]=='/'; i+=2){}
1126
1127 /* Begin copying from z[i] back to z[j]... */
1128 for(j=0; i<n; i++){
1129 if( z[i]=='/' ){
1130 /* Skip over internal "/." directory components */
1131 if( z[i+1]=='.' && (i+2==n || z[i+2]=='/') ){
1132 i += 1;
1133 continue;
1134 }
1135
1136 /* If this is a "/.." directory component then back out the
1137 ** previous term of the directory if it is something other than ".."
1138 ** or "."
1139 */
1140 if( z[i+1]=='.' && i+2<n && z[i+2]=='.' && (i+3==n || z[i+3]=='/')
1141 && backup_dir(z, &j)
1142 ){
1143 i += 2;
1144 continue;
1145 }
1146 }
1147 if( j>=0 ) z[j] = z[i];
1148 j++;
1149 }
1150 if( j==0 ) z[j++] = '/';
1151 z[j] = 0;
1152 return j;
1153 }
1154
1155 /*
1156 ** COMMAND: test-simplify-name
1157 **
1158 ** Usage: %fossil test-simplify-name FILENAME...
1159 **
1160 ** Print the simplified versions of each FILENAME. This is used to test
1161 ** the file_simplify_name() routine.
1162 **
1163 ** If FILENAME is of the form "HOST:PATH" or "USER@HOST:PATH", then remove
1164 ** and print the remote host prefix first. This is used to test the
1165 ** file_skip_userhost() interface.
1166 */
cmd_test_simplify_name(void)1167 void cmd_test_simplify_name(void){
1168 int i;
1169 char *z;
1170 const char *zTail;
1171 for(i=2; i<g.argc; i++){
1172 zTail = file_skip_userhost(g.argv[i]);
1173 if( zTail ){
1174 fossil_print("... ON REMOTE: %.*s\n", (int)(zTail-g.argv[i]), g.argv[i]);
1175 z = mprintf("%s", zTail);
1176 }else{
1177 z = mprintf("%s", g.argv[i]);
1178 }
1179 fossil_print("[%s] -> ", z);
1180 file_simplify_name(z, -1, 0);
1181 fossil_print("[%s]\n", z);
1182 fossil_free(z);
1183 }
1184 }
1185
1186 /*
1187 ** Get the current working directory.
1188 **
1189 ** On windows, the name is converted from unicode to UTF8 and all '\\'
1190 ** characters are converted to '/'. No conversions are needed on
1191 ** unix.
1192 **
1193 ** Store the value of the CWD in zBuf which is nBuf bytes in size.
1194 ** or if zBuf==0, allocate space to hold the result using fossil_malloc().
1195 */
file_getcwd(char * zBuf,int nBuf)1196 char *file_getcwd(char *zBuf, int nBuf){
1197 char zTemp[2000];
1198 if( zBuf==0 ){
1199 zBuf = zTemp;
1200 nBuf = sizeof(zTemp);
1201 }
1202 #ifdef _WIN32
1203 win32_getcwd(zBuf, nBuf);
1204 #else
1205 if( getcwd(zBuf, nBuf-1)==0 ){
1206 if( errno==ERANGE ){
1207 fossil_fatal("pwd too big: max %d", nBuf-1);
1208 }else{
1209 fossil_fatal("cannot find current working directory; %s",
1210 strerror(errno));
1211 }
1212 }
1213 #endif
1214 return zBuf==zTemp ? fossil_strdup(zBuf) : zBuf;
1215 }
1216
1217 /*
1218 ** Return true if zPath is an absolute pathname. Return false
1219 ** if it is relative.
1220 */
file_is_absolute_path(const char * zPath)1221 int file_is_absolute_path(const char *zPath){
1222 if( fossil_isdirsep(zPath[0])
1223 #if defined(_WIN32) || defined(__CYGWIN__)
1224 || (fossil_isalpha(zPath[0]) && zPath[1]==':'
1225 && (fossil_isdirsep(zPath[2]) || zPath[2]=='\0'))
1226 #endif
1227 ){
1228 return 1;
1229 }else{
1230 return 0;
1231 }
1232 }
1233
1234 /*
1235 ** Compute a canonical pathname for a file or directory.
1236 ** Make the name absolute if it is relative.
1237 ** Remove redundant / characters
1238 ** Remove all /./ path elements.
1239 ** Convert /A/../ to just /
1240 ** If the slash parameter is non-zero, the trailing slash, if any,
1241 ** is retained.
1242 **
1243 ** See also: file_canonical_name_dup()
1244 */
file_canonical_name(const char * zOrigName,Blob * pOut,int slash)1245 void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
1246 blob_zero(pOut);
1247 if( file_is_absolute_path(zOrigName) ){
1248 blob_appendf(pOut, "%/", zOrigName);
1249 }else{
1250 char zPwd[2000];
1251 file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
1252 if( zPwd[0]=='/' && strlen(zPwd)==1 ){
1253 /* when on '/', don't add an extra '/' */
1254 if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){
1255 /* '.' when on '/' mean '/' */
1256 blob_appendf(pOut, "%/", zPwd);
1257 }else{
1258 blob_appendf(pOut, "%/%/", zPwd, zOrigName);
1259 }
1260 }else{
1261 blob_appendf(pOut, "%//%/", zPwd, zOrigName);
1262 }
1263 }
1264 #if defined(_WIN32) || defined(__CYGWIN__)
1265 {
1266 char *zOut;
1267 /*
1268 ** On Windows/cygwin, normalize the drive letter to upper case.
1269 */
1270 zOut = blob_str(pOut);
1271 if( fossil_islower(zOut[0]) && zOut[1]==':' && zOut[2]=='/' ){
1272 zOut[0] = fossil_toupper(zOut[0]);
1273 }
1274 }
1275 #endif
1276 blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
1277 blob_size(pOut), slash));
1278 }
1279
1280 /*
1281 ** Compute the canonical name of a file. Store that name in
1282 ** memory obtained from fossil_malloc() and return a pointer to the
1283 ** name.
1284 **
1285 ** See also: file_canonical_name()
1286 */
file_canonical_name_dup(const char * zOrigName)1287 char *file_canonical_name_dup(const char *zOrigName){
1288 Blob x;
1289 if( zOrigName==0 ) return 0;
1290 blob_init(&x, 0, 0);
1291 file_canonical_name(zOrigName, &x, 0);
1292 return blob_str(&x);
1293 }
1294
1295 /*
1296 ** The input is the name of an executable, such as one might
1297 ** type on a command-line. This routine resolves that name into
1298 ** a full pathname. The result is obtained from fossil_malloc()
1299 ** and should be freed by the caller.
1300 **
1301 ** This routine only works on unix. On Windows, simply return
1302 ** a copy of the input.
1303 */
file_fullexename(const char * zCmd)1304 char *file_fullexename(const char *zCmd){
1305 #ifdef _WIN32
1306 char *zPath;
1307 char *z = 0;
1308 const char *zExe = "";
1309 if( sqlite3_strlike("%.exe",zCmd,0)!=0 ) zExe = ".exe";
1310 if( file_is_absolute_path(zCmd) ){
1311 return mprintf("%s%s", zCmd, zExe);
1312 }
1313 if( strchr(zCmd,'\\')!=0 && strchr(zCmd,'/')!=0 ){
1314 int i;
1315 Blob out = BLOB_INITIALIZER;
1316 file_canonical_name(zCmd, &out, 0);
1317 blob_append(&out, zExe, -1);
1318 z = fossil_strdup(blob_str(&out));
1319 blob_reset(&out);
1320 for(i=0; z[i]; i++){ if( z[i]=='/' ) z[i] = '\\'; }
1321 return z;
1322 }
1323 z = mprintf(".\\%s%s", zCmd, zExe);
1324 if( file_isfile(z, ExtFILE) ){
1325 int i;
1326 Blob out = BLOB_INITIALIZER;
1327 file_canonical_name(zCmd, &out, 0);
1328 blob_append(&out, zExe, -1);
1329 z = fossil_strdup(blob_str(&out));
1330 blob_reset(&out);
1331 for(i=0; z[i]; i++){ if( z[i]=='/' ) z[i] = '\\'; }
1332 return z;
1333 }
1334 fossil_free(z);
1335 zPath = fossil_getenv("PATH");
1336 while( zPath && zPath[0] ){
1337 int n;
1338 char *zColon;
1339 zColon = strchr(zPath, ';');
1340 n = zColon ? (int)(zColon-zPath) : (int)strlen(zPath);
1341 while( n>0 && zPath[n-1]=='\\' ){ n--; }
1342 z = mprintf("%.*s\\%s%s", n, zPath, zCmd, zExe);
1343 if( file_isfile(z, ExtFILE) ){
1344 return z;
1345 }
1346 fossil_free(z);
1347 if( zColon==0 ) break;
1348 zPath = zColon+1;
1349 }
1350 return fossil_strdup(zCmd);
1351 #else
1352 char *zPath;
1353 char *z;
1354 if( zCmd[0]=='/' ){
1355 return fossil_strdup(zCmd);
1356 }
1357 if( strchr(zCmd,'/')!=0 ){
1358 Blob out = BLOB_INITIALIZER;
1359 file_canonical_name(zCmd, &out, 0);
1360 z = fossil_strdup(blob_str(&out));
1361 blob_reset(&out);
1362 return z;
1363 }
1364 zPath = fossil_getenv("PATH");
1365 while( zPath && zPath[0] ){
1366 int n;
1367 char *zColon;
1368 zColon = strchr(zPath, ':');
1369 n = zColon ? (int)(zColon-zPath) : (int)strlen(zPath);
1370 z = mprintf("%.*s/%s", n, zPath, zCmd);
1371 if( file_isexe(z, ExtFILE) ){
1372 return z;
1373 }
1374 fossil_free(z);
1375 if( zColon==0 ) break;
1376 zPath = zColon+1;
1377 }
1378 return fossil_strdup(zCmd);
1379 #endif
1380 }
1381
1382 /*
1383 ** COMMAND: test-which
1384 **
1385 ** Usage: %fossil test-which ARGS...
1386 **
1387 ** For each argument, search the PATH for the executable with the name
1388 ** and print its full pathname.
1389 */
test_which_cmd(void)1390 void test_which_cmd(void){
1391 int i;
1392 for(i=2; i<g.argc; i++){
1393 char *z = file_fullexename(g.argv[i]);
1394 fossil_print("%z\n", z);
1395 }
1396 }
1397
1398 /*
1399 ** Emits the effective or raw stat() information for the specified
1400 ** file or directory, optionally preserving the trailing slash and
1401 ** resetting the cached stat() information.
1402 */
emitFileStat(const char * zPath,int slash,int reset)1403 static void emitFileStat(
1404 const char *zPath,
1405 int slash,
1406 int reset
1407 ){
1408 char zBuf[200];
1409 char *z;
1410 Blob x;
1411 char *zFull;
1412 int rc;
1413 sqlite3_int64 iMtime;
1414 struct fossilStat testFileStat;
1415 memset(zBuf, 0, sizeof(zBuf));
1416 blob_zero(&x);
1417 file_canonical_name(zPath, &x, slash);
1418 zFull = blob_str(&x);
1419 fossil_print("[%s] -> [%s]\n", zPath, zFull);
1420 memset(&testFileStat, 0, sizeof(struct fossilStat));
1421 rc = fossil_stat(zPath, &testFileStat, 0);
1422 fossil_print(" stat_rc = %d\n", rc);
1423 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", testFileStat.st_size);
1424 fossil_print(" stat_size = %s\n", zBuf);
1425 if( g.db==0 ) sqlite3_open(":memory:", &g.db);
1426 z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", testFileStat.st_mtime);
1427 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", testFileStat.st_mtime, z);
1428 fossil_free(z);
1429 fossil_print(" stat_mtime = %s\n", zBuf);
1430 fossil_print(" stat_mode = 0%o\n", testFileStat.st_mode);
1431 memset(&testFileStat, 0, sizeof(struct fossilStat));
1432 rc = fossil_stat(zPath, &testFileStat, 1);
1433 fossil_print(" l_stat_rc = %d\n", rc);
1434 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", testFileStat.st_size);
1435 fossil_print(" l_stat_size = %s\n", zBuf);
1436 z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", testFileStat.st_mtime);
1437 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", testFileStat.st_mtime, z);
1438 fossil_free(z);
1439 fossil_print(" l_stat_mtime = %s\n", zBuf);
1440 fossil_print(" l_stat_mode = 0%o\n", testFileStat.st_mode);
1441 if( reset ) resetStat();
1442 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zPath,ExtFILE));
1443 fossil_print(" file_size(ExtFILE) = %s\n", zBuf);
1444 iMtime = file_mtime(zPath, ExtFILE);
1445 z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMtime);
1446 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", iMtime, z);
1447 fossil_free(z);
1448 fossil_print(" file_mtime(ExtFILE) = %s\n", zBuf);
1449 fossil_print(" file_mode(ExtFILE) = 0%o\n", file_mode(zPath,ExtFILE));
1450 fossil_print(" file_isfile(ExtFILE) = %d\n", file_isfile(zPath,ExtFILE));
1451 fossil_print(" file_isdir(ExtFILE) = %d\n", file_isdir(zPath,ExtFILE));
1452 if( reset ) resetStat();
1453 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zPath,RepoFILE));
1454 fossil_print(" file_size(RepoFILE) = %s\n", zBuf);
1455 iMtime = file_mtime(zPath,RepoFILE);
1456 z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMtime);
1457 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", iMtime, z);
1458 fossil_free(z);
1459 fossil_print(" file_mtime(RepoFILE) = %s\n", zBuf);
1460 fossil_print(" file_mode(RepoFILE) = 0%o\n", file_mode(zPath,RepoFILE));
1461 fossil_print(" file_isfile(RepoFILE) = %d\n", file_isfile(zPath,RepoFILE));
1462 fossil_print(" file_isfile_or_link = %d\n", file_isfile_or_link(zPath));
1463 fossil_print(" file_islink = %d\n", file_islink(zPath));
1464 fossil_print(" file_isexe(RepoFILE) = %d\n", file_isexe(zPath,RepoFILE));
1465 fossil_print(" file_isdir(RepoFILE) = %d\n", file_isdir(zPath,RepoFILE));
1466 fossil_print(" file_is_repository = %d\n", file_is_repository(zPath));
1467 fossil_print(" file_is_reserved_name = %d\n",
1468 file_is_reserved_name(zFull,-1));
1469 fossil_print(" file_in_cwd = %d\n", file_in_cwd(zPath));
1470 blob_reset(&x);
1471 if( reset ) resetStat();
1472 }
1473
1474 /*
1475 ** COMMAND: test-file-environment
1476 **
1477 ** Usage: %fossil test-file-environment FILENAME...
1478 **
1479 ** Display the effective file handling subsystem "settings" and then
1480 ** display file system information about the files specified, if any.
1481 **
1482 ** Options:
1483 **
1484 ** --allow-symlinks BOOLEAN Temporarily turn allow-symlinks on/off
1485 ** --open-config Open the configuration database first.
1486 ** --reset Reset cached stat() info for each file.
1487 ** --root ROOT Use ROOT as the root of the checkout
1488 ** --slash Trailing slashes, if any, are retained.
1489 */
cmd_test_file_environment(void)1490 void cmd_test_file_environment(void){
1491 int i;
1492 int slashFlag = find_option("slash",0,0)!=0;
1493 int resetFlag = find_option("reset",0,0)!=0;
1494 const char *zRoot = find_option("root",0,1);
1495 const char *zAllow = find_option("allow-symlinks",0,1);
1496 if( find_option("open-config", 0, 0)!=0 ){
1497 Th_OpenConfig(1);
1498 }
1499 db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0);
1500 fossil_print("filenames_are_case_sensitive() = %d\n",
1501 filenames_are_case_sensitive());
1502 if( zAllow ){
1503 g.allowSymlinks = !is_false(zAllow);
1504 }
1505 if( zRoot==0 ) zRoot = g.zLocalRoot;
1506 fossil_print("db_allow_symlinks() = %d\n", db_allow_symlinks());
1507 fossil_print("local-root = [%s]\n", zRoot);
1508 for(i=2; i<g.argc; i++){
1509 char *z;
1510 emitFileStat(g.argv[i], slashFlag, resetFlag);
1511 z = file_canonical_name_dup(g.argv[i]);
1512 fossil_print(" file_canonical_name = %s\n", z);
1513 fossil_print(" file_nondir_path = ");
1514 if( fossil_strnicmp(zRoot,z,(int)strlen(zRoot))!=0 ){
1515 fossil_print("(--root is not a prefix of this file)\n");
1516 }else{
1517 int n = file_nondir_objects_on_path(zRoot, z);
1518 fossil_print("%.*s\n", n, z);
1519 }
1520 fossil_free(z);
1521 }
1522 }
1523
1524 /*
1525 ** COMMAND: test-canonical-name
1526 **
1527 ** Usage: %fossil test-canonical-name FILENAME...
1528 **
1529 ** Test the operation of the canonical name generator.
1530 ** Also test Fossil's ability to measure attributes of a file.
1531 */
cmd_test_canonical_name(void)1532 void cmd_test_canonical_name(void){
1533 int i;
1534 Blob x;
1535 int slashFlag = find_option("slash",0,0)!=0;
1536 blob_zero(&x);
1537 for(i=2; i<g.argc; i++){
1538 char zBuf[100];
1539 const char *zName = g.argv[i];
1540 file_canonical_name(zName, &x, slashFlag);
1541 fossil_print("[%s] -> [%s]\n", zName, blob_buffer(&x));
1542 blob_reset(&x);
1543 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName,RepoFILE));
1544 fossil_print(" file_size = %s\n", zBuf);
1545 sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName,RepoFILE));
1546 fossil_print(" file_mtime = %s\n", zBuf);
1547 fossil_print(" file_isfile = %d\n", file_isfile(zName,RepoFILE));
1548 fossil_print(" file_isfile_or_link = %d\n", file_isfile_or_link(zName));
1549 fossil_print(" file_islink = %d\n", file_islink(zName));
1550 fossil_print(" file_isexe = %d\n", file_isexe(zName,RepoFILE));
1551 fossil_print(" file_isdir = %d\n", file_isdir(zName,RepoFILE));
1552 }
1553 }
1554
1555 /*
1556 ** Return TRUE if the given filename is canonical.
1557 **
1558 ** Canonical names are full pathnames using "/" not "\" and which
1559 ** contain no "/./" or "/../" terms.
1560 */
file_is_canonical(const char * z)1561 int file_is_canonical(const char *z){
1562 int i;
1563 if( z[0]!='/'
1564 #if defined(_WIN32) || defined(__CYGWIN__)
1565 && (!fossil_isupper(z[0]) || z[1]!=':' || z[2]!='/')
1566 #endif
1567 ) return 0;
1568
1569 for(i=0; z[i]; i++){
1570 if( z[i]=='\\' ) return 0;
1571 if( z[i]=='/' ){
1572 if( z[i+1]=='.' ){
1573 if( z[i+2]=='/' || z[i+2]==0 ) return 0;
1574 if( z[i+2]=='.' && (z[i+3]=='/' || z[i+3]==0) ) return 0;
1575 }
1576 }
1577 }
1578 return 1;
1579 }
1580
1581 /*
1582 ** Return a pointer to the first character in a pathname past the
1583 ** drive letter. This routine is a no-op on unix.
1584 */
file_without_drive_letter(char * zIn)1585 char *file_without_drive_letter(char *zIn){
1586 #ifdef _WIN32
1587 if( fossil_isalpha(zIn[0]) && zIn[1]==':' ) zIn += 2;
1588 #endif
1589 return zIn;
1590 }
1591
1592 /*
1593 ** Compute a pathname for a file or directory that is relative
1594 ** to the current directory. If the slash parameter is non-zero,
1595 ** the trailing slash, if any, is retained.
1596 */
file_relative_name(const char * zOrigName,Blob * pOut,int slash)1597 void file_relative_name(const char *zOrigName, Blob *pOut, int slash){
1598 char *zPath;
1599 blob_set(pOut, zOrigName);
1600 blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
1601 blob_size(pOut), slash));
1602 zPath = file_without_drive_letter(blob_buffer(pOut));
1603 if( zPath[0]=='/' ){
1604 int i, j;
1605 Blob tmp;
1606 char *zPwd;
1607 char zBuf[2000];
1608 zPwd = zBuf;
1609 file_getcwd(zBuf, sizeof(zBuf)-20);
1610 zPwd = file_without_drive_letter(zBuf);
1611 i = 1;
1612 #if defined(_WIN32) || defined(__CYGWIN__)
1613 while( zPath[i] && fossil_tolower(zPwd[i])==fossil_tolower(zPath[i]) ) i++;
1614 #else
1615 while( zPath[i] && zPwd[i]==zPath[i] ) i++;
1616 #endif
1617 if( zPath[i]==0 ){
1618 memcpy(&tmp, pOut, sizeof(tmp));
1619 if( zPwd[i]==0 ){
1620 blob_set(pOut, ".");
1621 }else{
1622 blob_set(pOut, "..");
1623 for(j=i+1; zPwd[j]; j++){
1624 if( zPwd[j]=='/' ){
1625 blob_append(pOut, "/..", 3);
1626 }
1627 }
1628 while( i>0 && (zPwd[i]!='/')) --i;
1629 blob_append(pOut, zPath+i, j-i);
1630 }
1631 if( slash && i>0 && zPath[strlen(zPath)-1]=='/'){
1632 blob_append(pOut, "/", 1);
1633 }
1634 blob_reset(&tmp);
1635 return;
1636 }
1637 if( zPwd[i]==0 && zPath[i]=='/' ){
1638 memcpy(&tmp, pOut, sizeof(tmp));
1639 blob_set(pOut, "./");
1640 blob_append(pOut, &zPath[i+1], -1);
1641 blob_reset(&tmp);
1642 return;
1643 }
1644 while( zPath[i-1]!='/' ){ i--; }
1645 if( zPwd[0]=='/' && strlen(zPwd)==1 ){
1646 /* If on '/', don't go to higher level */
1647 blob_zero(&tmp);
1648 }else{
1649 blob_set(&tmp, "../");
1650 }
1651 for(j=i; zPwd[j]; j++){
1652 if( zPwd[j]=='/' ){
1653 blob_append(&tmp, "../", 3);
1654 }
1655 }
1656 blob_append(&tmp, &zPath[i], -1);
1657 blob_reset(pOut);
1658 memcpy(pOut, &tmp, sizeof(tmp));
1659 }
1660 }
1661
1662 /*
1663 ** COMMAND: test-relative-name
1664 **
1665 ** Test the operation of the relative name generator.
1666 */
cmd_test_relative_name(void)1667 void cmd_test_relative_name(void){
1668 int i;
1669 Blob x;
1670 int slashFlag = find_option("slash",0,0)!=0;
1671 blob_zero(&x);
1672 for(i=2; i<g.argc; i++){
1673 file_relative_name(g.argv[i], &x, slashFlag);
1674 fossil_print("%s\n", blob_buffer(&x));
1675 blob_reset(&x);
1676 }
1677 }
1678
1679 /*
1680 ** Compute a full path name for a file in the local tree. If
1681 ** the absolute flag is non-zero, the computed path will be
1682 ** absolute, starting with the root path of the local tree;
1683 ** otherwise, it will be relative to the root of the local
1684 ** tree. In both cases, the root of the local tree is defined
1685 ** by the g.zLocalRoot variable. Return TRUE on success. On
1686 ** failure, print and error message and quit if the errFatal
1687 ** flag is true. If errFatal is false, then simply return 0.
1688 */
file_tree_name(const char * zOrigName,Blob * pOut,int absolute,int errFatal)1689 int file_tree_name(
1690 const char *zOrigName,
1691 Blob *pOut,
1692 int absolute,
1693 int errFatal
1694 ){
1695 Blob localRoot;
1696 int nLocalRoot;
1697 char *zLocalRoot;
1698 Blob full;
1699 int nFull;
1700 char *zFull;
1701 int (*xCmp)(const char*,const char*,int);
1702
1703 blob_zero(pOut);
1704 if( !g.localOpen ){
1705 if( absolute && !file_is_absolute_path(zOrigName) ){
1706 if( errFatal ){
1707 fossil_fatal("relative to absolute needs open checkout tree: %s",
1708 zOrigName);
1709 }
1710 return 0;
1711 }else{
1712 /*
1713 ** The original path may be relative or absolute; however, without
1714 ** an open checkout tree, the only things we can do at this point
1715 ** is return it verbatim or generate a fatal error. The caller is
1716 ** probably expecting a tree-relative path name will be returned;
1717 ** however, most places where this function is called already check
1718 ** if the local checkout tree is open, either directly or indirectly,
1719 ** which would make this situation impossible. Alternatively, they
1720 ** could check the returned path using the file_is_absolute_path()
1721 ** function.
1722 */
1723 blob_appendf(pOut, "%s", zOrigName);
1724 return 1;
1725 }
1726 }
1727 file_canonical_name(g.zLocalRoot, &localRoot, 1);
1728 nLocalRoot = blob_size(&localRoot);
1729 zLocalRoot = blob_buffer(&localRoot);
1730 assert( nLocalRoot>0 && zLocalRoot[nLocalRoot-1]=='/' );
1731 file_canonical_name(zOrigName, &full, 0);
1732 nFull = blob_size(&full);
1733 zFull = blob_buffer(&full);
1734 if( filenames_are_case_sensitive() ){
1735 xCmp = fossil_strncmp;
1736 }else{
1737 xCmp = fossil_strnicmp;
1738 }
1739
1740 /* Special case. zOrigName refers to g.zLocalRoot directory. */
1741 if( (nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0)
1742 || (nFull==1 && zFull[0]=='/' && nLocalRoot==1 && zLocalRoot[0]=='/') ){
1743 if( absolute ){
1744 blob_append(pOut, zLocalRoot, nLocalRoot);
1745 }else{
1746 blob_append(pOut, ".", 1);
1747 }
1748 blob_reset(&localRoot);
1749 blob_reset(&full);
1750 return 1;
1751 }
1752
1753 if( nFull<=nLocalRoot || xCmp(zLocalRoot, zFull, nLocalRoot) ){
1754 blob_reset(&localRoot);
1755 blob_reset(&full);
1756 if( errFatal ){
1757 fossil_fatal("file outside of checkout tree: %s", zOrigName);
1758 }
1759 return 0;
1760 }
1761 if( absolute ){
1762 if( !file_is_absolute_path(zOrigName) ){
1763 blob_append(pOut, zLocalRoot, nLocalRoot);
1764 }
1765 blob_append(pOut, zOrigName, -1);
1766 blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
1767 blob_size(pOut), 0));
1768 }else{
1769 blob_append(pOut, &zFull[nLocalRoot], nFull-nLocalRoot);
1770 }
1771 blob_reset(&localRoot);
1772 blob_reset(&full);
1773 return 1;
1774 }
1775
1776 /*
1777 ** COMMAND: test-tree-name
1778 **
1779 ** Test the operation of the tree name generator.
1780 **
1781 ** Options:
1782 ** --absolute Return an absolute path instead of a relative one.
1783 ** --case-sensitive B Enable or disable case-sensitive filenames. B is
1784 ** a boolean: "yes", "no", "true", "false", etc.
1785 */
cmd_test_tree_name(void)1786 void cmd_test_tree_name(void){
1787 int i;
1788 Blob x;
1789 int absoluteFlag = find_option("absolute",0,0)!=0;
1790 db_find_and_open_repository(0,0);
1791 blob_zero(&x);
1792 for(i=2; i<g.argc; i++){
1793 if( file_tree_name(g.argv[i], &x, absoluteFlag, 1) ){
1794 fossil_print("%s\n", blob_buffer(&x));
1795 blob_reset(&x);
1796 }
1797 }
1798 }
1799
1800 /*
1801 ** zFile is the name of a file. Return true if that file is in the
1802 ** current working directory (the "pwd" or file_getcwd() directory).
1803 ** Return false if the file is someplace else.
1804 */
file_in_cwd(const char * zFile)1805 int file_in_cwd(const char *zFile){
1806 char *zFull = file_canonical_name_dup(zFile);
1807 char *zCwd = file_getcwd(0,0);
1808 size_t nCwd = strlen(zCwd);
1809 size_t nFull = strlen(zFull);
1810 int rc = 1;
1811 int (*xCmp)(const char*,const char*,int);
1812
1813 if( filenames_are_case_sensitive() ){
1814 xCmp = fossil_strncmp;
1815 }else{
1816 xCmp = fossil_strnicmp;
1817 }
1818
1819 if( nFull>nCwd+1
1820 && xCmp(zFull,zCwd,nCwd)==0
1821 && zFull[nCwd]=='/'
1822 && strchr(zFull+nCwd+1, '/')==0
1823 ){
1824 rc = 1;
1825 }else{
1826 rc = 0;
1827 }
1828 fossil_free(zFull);
1829 fossil_free(zCwd);
1830 return rc;
1831 }
1832
1833 /*
1834 ** Parse a URI into scheme, host, port, and path.
1835 */
file_parse_uri(const char * zUri,Blob * pScheme,Blob * pHost,int * pPort,Blob * pPath)1836 void file_parse_uri(
1837 const char *zUri,
1838 Blob *pScheme,
1839 Blob *pHost,
1840 int *pPort,
1841 Blob *pPath
1842 ){
1843 int i, j;
1844
1845 for(i=0; zUri[i] && zUri[i]>='a' && zUri[i]<='z'; i++){}
1846 if( zUri[i]!=':' ){
1847 blob_zero(pScheme);
1848 blob_zero(pHost);
1849 blob_set(pPath, zUri);
1850 return;
1851 }
1852 blob_init(pScheme, zUri, i);
1853 i++;
1854 if( zUri[i]=='/' && zUri[i+1]=='/' ){
1855 i += 2;
1856 j = i;
1857 while( zUri[i] && zUri[i]!='/' && zUri[i]!=':' ){ i++; }
1858 blob_init(pHost, &zUri[j], i-j);
1859 if( zUri[i]==':' ){
1860 i++;
1861 *pPort = atoi(&zUri[i]);
1862 while( zUri[i] && zUri[i]!='/' ){ i++; }
1863 }
1864 }else{
1865 blob_zero(pHost);
1866 }
1867 if( zUri[i]=='/' ){
1868 blob_set(pPath, &zUri[i]);
1869 }else{
1870 blob_set(pPath, "/");
1871 }
1872 }
1873
1874 /*
1875 ** Construct a random temporary filename into pBuf where the name of
1876 ** the temporary file is derived from zBasis. The suffix on the temp
1877 ** file is the same as the suffix on zBasis, and the temp file has
1878 ** the root of zBasis in its name.
1879 **
1880 ** If zTag is not NULL, then try to create the temp-file using zTag
1881 ** as a differentiator. If that fails, or if zTag is NULL, then use
1882 ** a bunch of random characters as the tag.
1883 **
1884 ** Dangerous characters in zBasis are changed.
1885 */
file_tempname(Blob * pBuf,const char * zBasis,const char * zTag)1886 void file_tempname(Blob *pBuf, const char *zBasis, const char *zTag){
1887 #if defined(_WIN32)
1888 const char *azDirs[] = {
1889 0, /* GetTempPath */
1890 0, /* TEMP */
1891 0, /* TMP */
1892 ".",
1893 };
1894 #else
1895 static const char *azDirs[] = {
1896 0, /* TMPDIR */
1897 "/var/tmp",
1898 "/usr/tmp",
1899 "/tmp",
1900 "/temp",
1901 ".",
1902 };
1903 #endif
1904 static const unsigned char zChars[] =
1905 "abcdefghijklmnopqrstuvwxyz"
1906 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1907 "0123456789";
1908 unsigned int i;
1909 const char *zDir = ".";
1910 int cnt = 0;
1911 char zRand[16];
1912 int nBasis;
1913 const char *zSuffix;
1914 char *z;
1915
1916 #if defined(_WIN32)
1917 wchar_t zTmpPath[MAX_PATH];
1918
1919 if( GetTempPathW(MAX_PATH, zTmpPath) ){
1920 azDirs[0] = fossil_path_to_utf8(zTmpPath);
1921 /* Removing trailing \ from the temp path */
1922 z = (char*)azDirs[0];
1923 i = (int)strlen(z)-1;
1924 if( i>0 && z[i]=='\\' ) z[i] = 0;
1925 }
1926
1927 azDirs[1] = fossil_getenv("TEMP");
1928 azDirs[2] = fossil_getenv("TMP");
1929 #else
1930 azDirs[0] = fossil_getenv("TMPDIR");
1931 #endif
1932
1933 for(i=0; i<count(azDirs); i++){
1934 if( azDirs[i]==0 ) continue;
1935 if( !file_isdir(azDirs[i], ExtFILE) ) continue;
1936 zDir = azDirs[i];
1937 break;
1938 }
1939
1940 assert( zBasis!=0 );
1941 zSuffix = 0;
1942 for(i=0; zBasis[i]; i++){
1943 if( zBasis[i]=='/' || zBasis[i]=='\\' ){
1944 zBasis += i+1;
1945 i = -1;
1946 }else if( zBasis[i]=='.' ){
1947 zSuffix = zBasis + i;
1948 }
1949 }
1950 if( zSuffix==0 || zSuffix<=zBasis ){
1951 zSuffix = "";
1952 nBasis = i;
1953 }else{
1954 nBasis = (int)(zSuffix - zBasis);
1955 }
1956 if( nBasis==0 ){
1957 nBasis = 6;
1958 zBasis = "fossil";
1959 }
1960 do{
1961 blob_zero(pBuf);
1962 if( cnt++>20 ) fossil_fatal("cannot generate a temporary filename");
1963 if( zTag==0 ){
1964 sqlite3_randomness(15, zRand);
1965 for(i=0; i<15; i++){
1966 zRand[i] = (char)zChars[ ((unsigned char)zRand[i])%(sizeof(zChars)-1) ];
1967 }
1968 zRand[15] = 0;
1969 zTag = zRand;
1970 }
1971 blob_appendf(pBuf, "%s/%.*s~%s%s", zDir, nBasis, zBasis, zTag, zSuffix);
1972 zTag = 0;
1973 for(z=blob_str(pBuf); z!=0 && (z=strpbrk(z,"'\"`;|$&"))!=0; z++){
1974 z[0] = '_';
1975 }
1976 }while( file_size(blob_str(pBuf), ExtFILE)>=0 );
1977
1978 #if defined(_WIN32)
1979 fossil_path_free((char *)azDirs[0]);
1980 fossil_path_free((char *)azDirs[1]);
1981 fossil_path_free((char *)azDirs[2]);
1982 /* Change all \ characters in the windows path into / so that they can
1983 ** be safely passed to a subcommand, such as by gdiff */
1984 z = blob_buffer(pBuf);
1985 for(i=0; z[i]; i++) if( z[i]=='\\' ) z[i] = '/';
1986 #else
1987 fossil_path_free((char *)azDirs[0]);
1988 #endif
1989 }
1990
1991 /*
1992 ** Compute a temporary filename in zDir. The filename is based on
1993 ** the current time.
1994 */
file_time_tempname(const char * zDir,const char * zSuffix)1995 char *file_time_tempname(const char *zDir, const char *zSuffix){
1996 struct tm *tm;
1997 unsigned int r;
1998 static unsigned int cnt = 0;
1999 time_t t;
2000 t = time(0);
2001 tm = gmtime(&t);
2002 sqlite3_randomness(sizeof(r), &r);
2003 return mprintf("%s/%04d%02d%02d%02d%02d%02d%04d%06d%s",
2004 zDir, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
2005 tm->tm_hour, tm->tm_min, tm->tm_sec, cnt++, r%1000000, zSuffix);
2006 }
2007
2008
2009 /*
2010 ** COMMAND: test-tempname
2011 ** Usage: fossil test-name [--time SUFFIX] [--tag NAME] BASENAME ...
2012 **
2013 ** Generate temporary filenames derived from BASENAME. Use the --time
2014 ** option to generate temp names based on the time of day. If --tag NAME
2015 ** is specified, try to use NAME as the differentiator in the temp file.
2016 */
file_test_tempname(void)2017 void file_test_tempname(void){
2018 int i;
2019 const char *zSuffix = find_option("time",0,1);
2020 Blob x = BLOB_INITIALIZER;
2021 char *z;
2022 const char *zTag = find_option("tag",0,1);
2023 verify_all_options();
2024 for(i=2; i<g.argc; i++){
2025 if( zSuffix ){
2026 z = file_time_tempname(g.argv[i], zSuffix);
2027 fossil_print("%s\n", z);
2028 fossil_free(z);
2029 }else{
2030 file_tempname(&x, g.argv[i], zTag);
2031 fossil_print("%s\n", blob_str(&x));
2032 blob_reset(&x);
2033 }
2034 }
2035 }
2036
2037
2038 /*
2039 ** Return true if a file named zName exists and has identical content
2040 ** to the blob pContent. If zName does not exist or if the content is
2041 ** different in any way, then return false.
2042 **
2043 ** This routine assumes RepoFILE
2044 */
file_is_the_same(Blob * pContent,const char * zName)2045 int file_is_the_same(Blob *pContent, const char *zName){
2046 i64 iSize;
2047 int rc;
2048 Blob onDisk;
2049
2050 iSize = file_size(zName, RepoFILE);
2051 if( iSize<0 ) return 0;
2052 if( iSize!=blob_size(pContent) ) return 0;
2053 blob_read_from_file(&onDisk, zName, RepoFILE);
2054 rc = blob_compare(&onDisk, pContent);
2055 blob_reset(&onDisk);
2056 return rc==0;
2057 }
2058
2059 /*
2060 ** Return the value of an environment variable as UTF8.
2061 ** Use fossil_path_free() to release resources.
2062 */
fossil_getenv(const char * zName)2063 char *fossil_getenv(const char *zName){
2064 #ifdef _WIN32
2065 wchar_t *uName = fossil_utf8_to_unicode(zName);
2066 void *zValue = _wgetenv(uName);
2067 fossil_unicode_free(uName);
2068 #else
2069 char *zValue = getenv(zName);
2070 #endif
2071 if( zValue ) zValue = fossil_path_to_utf8(zValue);
2072 return zValue;
2073 }
2074
2075 /*
2076 ** Sets the value of an environment variable as UTF8.
2077 */
fossil_setenv(const char * zName,const char * zValue)2078 int fossil_setenv(const char *zName, const char *zValue){
2079 int rc;
2080 char *zString = mprintf("%s=%s", zName, zValue);
2081 #ifdef _WIN32
2082 wchar_t *uString = fossil_utf8_to_unicode(zString);
2083 rc = _wputenv(uString);
2084 fossil_unicode_free(uString);
2085 fossil_free(zString);
2086 #else
2087 rc = putenv(zString);
2088 /* NOTE: Cannot free the string on POSIX. */
2089 /* fossil_free(zString); */
2090 #endif
2091 return rc;
2092 }
2093
2094 /*
2095 ** Clear all environment variables
2096 */
fossil_clearenv(void)2097 int fossil_clearenv(void){
2098 #ifdef _WIN32
2099 int rc = 0;
2100 LPWCH zzEnv = GetEnvironmentStringsW();
2101 if( zzEnv ){
2102 LPCWSTR zEnv = zzEnv; /* read-only */
2103 while( 1 ){
2104 LPWSTR zNewEnv = _wcsdup(zEnv); /* writable */
2105 if( zNewEnv ){
2106 LPWSTR zEquals = wcsstr(zNewEnv, L"=");
2107 if( zEquals ){
2108 zEquals[1] = 0; /* no value */
2109 if( zNewEnv==zEquals || _wputenv(zNewEnv)==0 ){ /* via CRT */
2110 /* do nothing */
2111 }else{
2112 zEquals[0] = 0; /* name only */
2113 if( !SetEnvironmentVariableW(zNewEnv, NULL) ){ /* via Win32 */
2114 rc = 1;
2115 }
2116 }
2117 if( rc==0 ){
2118 zEnv += (lstrlenW(zEnv) + 1); /* double NUL term? */
2119 if( zEnv[0]==0 ){
2120 free(zNewEnv);
2121 break; /* no more vars */
2122 }
2123 }
2124 }else{
2125 rc = 1;
2126 }
2127 }else{
2128 rc = 1;
2129 }
2130 free(zNewEnv);
2131 if( rc!=0 ) break;
2132 }
2133 if( !FreeEnvironmentStringsW(zzEnv) ){
2134 rc = 2;
2135 }
2136 }else{
2137 rc = 1;
2138 }
2139 return rc;
2140 #else
2141 extern char **environ;
2142 environ[0] = 0;
2143 return 0;
2144 #endif
2145 }
2146
2147 /*
2148 ** Like fopen() but always takes a UTF8 argument.
2149 **
2150 ** This function assumes ExtFILE. In other words, symbolic links
2151 ** are always followed.
2152 */
fossil_fopen(const char * zName,const char * zMode)2153 FILE *fossil_fopen(const char *zName, const char *zMode){
2154 #ifdef _WIN32
2155 wchar_t *uMode = fossil_utf8_to_unicode(zMode);
2156 wchar_t *uName = fossil_utf8_to_path(zName, 0);
2157 FILE *f = _wfopen(uName, uMode);
2158 fossil_path_free(uName);
2159 fossil_unicode_free(uMode);
2160 #else
2161 FILE *f = fopen(zName, zMode);
2162 #endif
2163 return f;
2164 }
2165
2166 /*
2167 ** Wrapper for freopen() that understands UTF8 arguments.
2168 */
fossil_freopen(const char * zName,const char * zMode,FILE * stream)2169 FILE *fossil_freopen(const char *zName, const char *zMode, FILE *stream){
2170 #ifdef _WIN32
2171 wchar_t *uMode = fossil_utf8_to_unicode(zMode);
2172 wchar_t *uName = fossil_utf8_to_path(zName, 0);
2173 FILE *f = _wfreopen(uName, uMode, stream);
2174 fossil_path_free(uName);
2175 fossil_unicode_free(uMode);
2176 #else
2177 FILE *f = freopen(zName, zMode, stream);
2178 #endif
2179 return f;
2180 }
2181
2182 /*
2183 ** Works like fclose() except that:
2184 **
2185 ** 1) is a no-op if f is 0 or if it is stdin.
2186 **
2187 ** 2) If f is one of (stdout, stderr), it is flushed but not closed.
2188 */
fossil_fclose(FILE * f)2189 void fossil_fclose(FILE *f){
2190 if(f!=0){
2191 if(stdout==f || stderr==f){
2192 fflush(f);
2193 }else if(stdin!=f){
2194 fclose(f);
2195 }
2196 }
2197 }
2198
2199 /*
2200 ** Works like fopen(zName,"wb") except that:
2201 **
2202 ** 1) If zName is "-", the stdout handle is returned.
2203 **
2204 ** 2) Else file_mkfolder() is used to create all directories
2205 ** which lead up to the file before opening it.
2206 **
2207 ** 3) It fails fatally if the file cannot be opened.
2208 */
fossil_fopen_for_output(const char * zFilename)2209 FILE *fossil_fopen_for_output(const char *zFilename){
2210 if(zFilename[0]=='-' && zFilename[1]==0){
2211 return stdout;
2212 }else{
2213 FILE * p;
2214 file_mkfolder(zFilename, ExtFILE, 1, 0);
2215 p = fossil_fopen(zFilename, "wb");
2216 if( p==0 ){
2217 #if defined(_WIN32)
2218 const char *zReserved = file_is_win_reserved(zFilename);
2219 if( zReserved ){
2220 fossil_fatal("cannot open \"%s\" because \"%s\" is "
2221 "a reserved name on Windows", zFilename,
2222 zReserved);
2223 }
2224 #endif
2225 fossil_fatal("unable to open file \"%s\" for writing",
2226 zFilename);
2227 }
2228 return p;
2229 }
2230 }
2231
2232
2233 /*
2234 ** Return non-NULL if zFilename contains pathname elements that
2235 ** are reserved on Windows. The returned string is the disallowed
2236 ** path element.
2237 */
file_is_win_reserved(const char * zPath)2238 const char *file_is_win_reserved(const char *zPath){
2239 static const char *const azRes[] = { "CON", "PRN", "AUX", "NUL", "COM", "LPT" };
2240 static char zReturn[5];
2241 int i;
2242 while( zPath[0] ){
2243 for(i=0; i<count(azRes); i++){
2244 if( sqlite3_strnicmp(zPath, azRes[i], 3)==0
2245 && ((i>=4 && fossil_isdigit(zPath[3])
2246 && (zPath[4]=='/' || zPath[4]=='.' || zPath[4]==0))
2247 || (i<4 && (zPath[3]=='/' || zPath[3]=='.' || zPath[3]==0)))
2248 ){
2249 sqlite3_snprintf(5,zReturn,"%.*s", i>=4 ? 4 : 3, zPath);
2250 return zReturn;
2251 }
2252 }
2253 while( zPath[0] && zPath[0]!='/' ) zPath++;
2254 while( zPath[0]=='/' ) zPath++;
2255 }
2256 return 0;
2257 }
2258
2259 /*
2260 ** COMMAND: test-valid-for-windows
2261 ** Usage: fossil test-valid-for-windows FILENAME ....
2262 **
2263 ** Show which filenames are not valid for Windows
2264 */
file_test_valid_for_windows(void)2265 void file_test_valid_for_windows(void){
2266 int i;
2267 for(i=2; i<g.argc; i++){
2268 fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]);
2269 }
2270 }
2271
2272 /*
2273 ** Remove surplus "/" characters from the beginning of a full pathname.
2274 ** Extra leading "/" characters are benign on unix. But on Windows
2275 ** machines, they must be removed. Example: Convert "/C:/fossil/xyx.fossil"
2276 ** into "C:/fossil/xyz.fossil". Cygwin should behave as Windows here.
2277 */
file_cleanup_fullpath(const char * z)2278 const char *file_cleanup_fullpath(const char *z){
2279 #if defined(_WIN32) || defined(__CYGWIN__)
2280 if( z[0]=='/' && fossil_isalpha(z[1]) && z[2]==':' && z[3]=='/' ) z++;
2281 #else
2282 while( z[0]=='/' && z[1]=='/' ) z++;
2283 #endif
2284 return z;
2285 }
2286
2287 /*
2288 ** Count the number of objects (files and subdirectories) in a given
2289 ** directory. Return the count. Return -1 if the object is not a
2290 ** directory.
2291 */
file_directory_size(const char * zDir,const char * zGlob,int omitDotFiles)2292 int file_directory_size(const char *zDir, const char *zGlob, int omitDotFiles){
2293 void *zNative;
2294 DIR *d;
2295 int n = -1;
2296 zNative = fossil_utf8_to_path(zDir,1);
2297 d = opendir(zNative);
2298 if( d ){
2299 struct dirent *pEntry;
2300 n = 0;
2301 while( (pEntry=readdir(d))!=0 ){
2302 if( pEntry->d_name[0]==0 ) continue;
2303 if( omitDotFiles && pEntry->d_name[0]=='.' ) continue;
2304 if( zGlob ){
2305 char *zUtf8 = fossil_path_to_utf8(pEntry->d_name);
2306 int rc = sqlite3_strglob(zGlob, zUtf8);
2307 fossil_path_free(zUtf8);
2308 if( rc ) continue;
2309 }
2310 n++;
2311 }
2312 closedir(d);
2313 }
2314 fossil_path_free(zNative);
2315 return n;
2316 }
2317
2318 /*
2319 ** COMMAND: test-dir-size
2320 **
2321 ** Usage: %fossil test-dir-size NAME [GLOB] [--nodots]
2322 **
2323 ** Return the number of objects in the directory NAME. If GLOB is
2324 ** provided, then only count objects that match the GLOB pattern.
2325 ** if --nodots is specified, omit files that begin with ".".
2326 */
test_dir_size_cmd(void)2327 void test_dir_size_cmd(void){
2328 int omitDotFiles = find_option("nodots",0,0)!=0;
2329 const char *zGlob;
2330 const char *zDir;
2331 verify_all_options();
2332 if( g.argc!=3 && g.argc!=4 ){
2333 usage("NAME [GLOB] [-nodots]");
2334 }
2335 zDir = g.argv[2];
2336 zGlob = g.argc==4 ? g.argv[3] : 0;
2337 fossil_print("%d\n", file_directory_size(zDir, zGlob, omitDotFiles));
2338 }
2339
2340 /*
2341 ** Internal helper for touch_cmd(). zAbsName must be resolvable as-is
2342 ** to an existing file - this function does not expand/normalize
2343 ** it. i.e. it "really should" be an absolute path. zTreeName is
2344 ** strictly cosmetic: it is used when dryRunFlag, verboseFlag, or
2345 ** quietFlag generate output, and is assumed to be a repo-relative or
2346 ** or subdir-relative filename.
2347 **
2348 ** newMTime is the file's new timestamp (Unix epoch).
2349 **
2350 ** Returns 1 if it sets zAbsName's mtime, 0 if it does not (indicating
2351 ** that the file already has that timestamp or a warning was emitted
2352 ** or was not found). If dryRunFlag is true then it outputs the name
2353 ** of the file it would have timestamped but does not stamp the
2354 ** file. If verboseFlag is true, it outputs a message if the file's
2355 ** timestamp is actually modified. If quietFlag is true then the
2356 ** output of non-fatal warning messages is suppressed.
2357 **
2358 ** As a special case, if newMTime is 0 then this function emits a
2359 ** warning (unless quietFlag is true), does NOT set the timestamp, and
2360 ** returns 0. The timestamp is known to be zero when
2361 ** mtime_of_manifest_file() is asked to provide the timestamp for a
2362 ** file which is currently undergoing an uncommitted merge (though
2363 ** this may depend on exactly where that merge is happening the
2364 ** history of the project).
2365 */
touch_cmd_stamp_one_file(char const * zAbsName,char const * zTreeName,i64 newMtime,int dryRunFlag,int verboseFlag,int quietFlag)2366 static int touch_cmd_stamp_one_file(char const *zAbsName,
2367 char const *zTreeName,
2368 i64 newMtime, int dryRunFlag,
2369 int verboseFlag, int quietFlag){
2370 i64 currentMtime;
2371 if(newMtime==0){
2372 if( quietFlag==0 ){
2373 fossil_print("SKIPPING timestamp of 0: %s\n", zTreeName);
2374 }
2375 return 0;
2376 }
2377 currentMtime = file_mtime(zAbsName, 0);
2378 if(currentMtime<0){
2379 fossil_print("SKIPPING: cannot stat file: %s\n", zAbsName);
2380 return 0;
2381 }else if(currentMtime==newMtime){
2382 return 0;
2383 }else if( dryRunFlag!=0 ){
2384 fossil_print( "dry-run: %s\n", zTreeName );
2385 }else{
2386 file_set_mtime(zAbsName, newMtime);
2387 if( verboseFlag!=0 ){
2388 fossil_print( "touched %s\n", zTreeName );
2389 }
2390 }
2391 return 1;
2392 }
2393
2394 /*
2395 ** Internal helper for touch_cmd(). If the given file name is found in
2396 ** the given checkout version, which MUST be the checkout version
2397 ** currently populating the vfile table, the vfile.mrid value for the
2398 ** file is returned, else 0 is returned. zName must be resolvable
2399 ** as-is from the vfile table - this function neither expands nor
2400 ** normalizes it, though it does compare using the repo's
2401 ** filename_collation() preference.
2402 */
touch_cmd_vfile_mrid(int vid,char const * zName)2403 static int touch_cmd_vfile_mrid( int vid, char const *zName ){
2404 int mrid = 0;
2405 static Stmt q = empty_Stmt_m;
2406 db_static_prepare(&q,
2407 "SELECT vfile.mrid "
2408 "FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid "
2409 "WHERE vid=:vid AND pathname=:pathname %s",
2410 filename_collation());
2411 db_bind_int(&q, ":vid", vid);
2412 db_bind_text(&q, ":pathname", zName);
2413 if(SQLITE_ROW==db_step(&q)){
2414 mrid = db_column_int(&q, 0);
2415 }
2416 db_reset(&q);
2417 return mrid;
2418 }
2419
2420 /*
2421 ** COMMAND: touch*
2422 **
2423 ** Usage: %fossil touch ?OPTIONS? ?FILENAME...?
2424 **
2425 ** For each file in the current checkout matching one of the provided
2426 ** list of glob patterns and/or file names, the file's mtime is
2427 ** updated to a value specified by one of the flags --checkout,
2428 ** --checkin, or --now.
2429 **
2430 ** If neither glob patterns nor filenames are provided, it operates on
2431 ** all files managed by the currently checked-out version.
2432 **
2433 ** This command gets its name from the conventional Unix "touch"
2434 ** command.
2435 **
2436 ** Options:
2437 ** --now Stamp each affected file with the current time.
2438 ** This is the default behavior.
2439 ** -c|--checkin Stamp each affected file with the time of the
2440 ** most recent check-in which modified that file.
2441 ** -C|--checkout Stamp each affected file with the time of the
2442 ** currently-checked-out version.
2443 ** -g GLOBLIST Comma-separated list of glob patterns.
2444 ** -G GLOBFILE Similar to -g but reads its globs from a
2445 ** fossil-conventional glob list file.
2446 ** -v|--verbose Outputs extra information about its globs
2447 ** and each file it touches.
2448 ** -n|--dry-run Outputs which files would require touching,
2449 ** but does not touch them.
2450 ** -q|--quiet Suppress warnings, e.g. when skipping unmanaged
2451 ** or out-of-tree files.
2452 **
2453 ** Only one of --now, --checkin, and --checkout may be used. The
2454 ** default is --now.
2455 **
2456 ** Only one of -g or -G may be used. If neither is provided and no
2457 ** additional filenames are provided, the effect is as if a glob of
2458 ** '*' were provided, i.e. all files belonging to the
2459 ** currently-checked-out version. Note that all glob patterns provided
2460 ** via these flags are always evaluated as if they are relative to the
2461 ** top of the source tree, not the current working (sub)directory.
2462 ** Filenames provided without these flags, on the other hand, are
2463 ** treated as relative to the current directory.
2464 **
2465 ** As a special case, files currently undergoing an uncommitted merge
2466 ** might not get timestamped with --checkin because it may be
2467 ** impossible for fossil to choose between multiple potential
2468 ** timestamps. A non-fatal warning is emitted for such cases.
2469 **
2470 */
touch_cmd()2471 void touch_cmd(){
2472 const char * zGlobList; /* -g List of glob patterns */
2473 const char * zGlobFile; /* -G File of glob patterns */
2474 Glob * pGlob = 0; /* List of glob patterns */
2475 int verboseFlag;
2476 int dryRunFlag;
2477 int vid; /* Checkout version */
2478 int changeCount = 0; /* Number of files touched */
2479 int quietFlag = 0; /* -q|--quiet */
2480 int timeFlag; /* -1==--checkin, 1==--checkout, 0==--now */
2481 i64 nowTime = 0; /* Timestamp of --now or --checkout */
2482 Stmt q;
2483 Blob absBuffer = empty_blob; /* Absolute filename buffer */
2484
2485 verboseFlag = find_option("verbose","v",0)!=0;
2486 quietFlag = find_option("quiet","q",0)!=0 || g.fQuiet;
2487 dryRunFlag = find_option("dry-run","n",0)!=0
2488 || find_option("dryrun",0,0)!=0;
2489 zGlobList = find_option("glob", "g",1);
2490 zGlobFile = find_option("globfile", "G",1);
2491
2492 if(zGlobList && zGlobFile){
2493 fossil_fatal("Options -g and -G may not be used together.");
2494 }
2495
2496 {
2497 int const ci =
2498 (find_option("checkin","c",0) || find_option("check-in",0,0))
2499 ? 1 : 0;
2500 int const co = find_option("checkout","C",0) ? 1 : 0;
2501 int const now = find_option("now",0,0) ? 1 : 0;
2502 if(ci + co + now > 1){
2503 fossil_fatal("Options --checkin, --checkout, and --now may "
2504 "not be used together.");
2505 }else if(co){
2506 timeFlag = 1;
2507 if(verboseFlag){
2508 fossil_print("Timestamp = current checkout version.\n");
2509 }
2510 }else if(ci){
2511 timeFlag = -1;
2512 if(verboseFlag){
2513 fossil_print("Timestamp = checkin in which each file was "
2514 "most recently modified.\n");
2515 }
2516 }else{
2517 timeFlag = 0;
2518 if(verboseFlag){
2519 fossil_print("Timestamp = current system time.\n");
2520 }
2521 }
2522 }
2523
2524 verify_all_options();
2525
2526 db_must_be_within_tree();
2527 vid = db_lget_int("checkout", 0);
2528 if(vid==0){
2529 fossil_fatal("Cannot determine checkout version.");
2530 }
2531
2532 if(zGlobList){
2533 pGlob = *zGlobList ? glob_create(zGlobList) : 0;
2534 }else if(zGlobFile){
2535 Blob globs = empty_blob;
2536 blob_read_from_file(&globs, zGlobFile, ExtFILE);
2537 pGlob = glob_create( globs.aData );
2538 blob_reset(&globs);
2539 }
2540 if( pGlob && verboseFlag!=0 ){
2541 int i;
2542 for(i=0; i<pGlob->nPattern; ++i){
2543 fossil_print("glob: %s\n", pGlob->azPattern[i]);
2544 }
2545 }
2546
2547 db_begin_transaction();
2548 if(timeFlag==0){/*--now*/
2549 nowTime = time(0);
2550 }else if(timeFlag>0){/*--checkout: get the checkout
2551 manifest's timestamp*/
2552 assert(vid>0);
2553 nowTime = db_int64(-1,
2554 "SELECT CAST(strftime('%%s',"
2555 "(SELECT mtime FROM event WHERE objid=%d)"
2556 ") AS INTEGER)", vid);
2557 if(nowTime<0){
2558 fossil_fatal("Could not determine checkout version's time!");
2559 }
2560 }else{ /* --checkin */
2561 assert(0 == nowTime);
2562 }
2563 if((pGlob && pGlob->nPattern>0) || g.argc<3){
2564 /*
2565 ** We have either (1) globs or (2) no trailing filenames. If there
2566 ** are neither globs nor filenames then we operate on all managed
2567 ** files.
2568 */
2569 db_prepare(&q,
2570 "SELECT vfile.mrid, pathname "
2571 "FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid "
2572 "WHERE vid=%d", vid);
2573 while(SQLITE_ROW==db_step(&q)){
2574 int const fid = db_column_int(&q, 0);
2575 const char * zName = db_column_text(&q, 1);
2576 i64 newMtime = nowTime;
2577 char const * zAbs = 0; /* absolute path */
2578 absBuffer.nUsed = 0;
2579 assert(timeFlag<0 ? newMtime==0 : newMtime>0);
2580 if(pGlob){
2581 if(glob_match(pGlob, zName)==0) continue;
2582 }
2583 blob_appendf( &absBuffer, "%s%s", g.zLocalRoot, zName );
2584 zAbs = blob_str(&absBuffer);
2585 if( newMtime || mtime_of_manifest_file(vid, fid, &newMtime)==0 ){
2586 changeCount +=
2587 touch_cmd_stamp_one_file( zAbs, zName, newMtime, dryRunFlag,
2588 verboseFlag, quietFlag );
2589 }
2590 }
2591 db_finalize(&q);
2592 }
2593 glob_free(pGlob);
2594 pGlob = 0;
2595 if(g.argc>2){
2596 /*
2597 ** Trailing filenames on the command line. These require extra
2598 ** care to avoid modifying unmanaged or out-of-tree files and
2599 ** finding an associated --checkin timestamp.
2600 */
2601 int i;
2602 Blob treeNameBuf = empty_blob; /* Buffer for file_tree_name(). */
2603 for( i = 2; i < g.argc; ++i,
2604 blob_reset(&treeNameBuf) ){
2605 char const * zArg = g.argv[i];
2606 char const * zTreeFile; /* repo-relative filename */
2607 char const * zAbs; /* absolute filename */
2608 i64 newMtime = nowTime;
2609 int nameCheck;
2610 int fid; /* vfile.mrid of file */
2611 nameCheck = file_tree_name( zArg, &treeNameBuf, 0, 0 );
2612 if(nameCheck==0){
2613 if(quietFlag==0){
2614 fossil_print("SKIPPING out-of-tree file: %s\n", zArg);
2615 }
2616 continue;
2617 }
2618 zTreeFile = blob_str(&treeNameBuf);
2619 fid = touch_cmd_vfile_mrid( vid, zTreeFile );
2620 if(fid==0){
2621 if(quietFlag==0){
2622 fossil_print("SKIPPING unmanaged file: %s\n", zArg);
2623 }
2624 continue;
2625 }
2626 absBuffer.nUsed = 0;
2627 blob_appendf(&absBuffer, "%s%s", g.zLocalRoot, zTreeFile);
2628 zAbs = blob_str(&absBuffer);
2629 if(timeFlag<0){/*--checkin*/
2630 if(mtime_of_manifest_file( vid, fid, &newMtime )!=0){
2631 fossil_fatal("Could not resolve --checkin mtime of %s", zTreeFile);
2632 }
2633 }else{
2634 assert(newMtime>0);
2635 }
2636 changeCount +=
2637 touch_cmd_stamp_one_file( zAbs, zArg, newMtime, dryRunFlag,
2638 verboseFlag, quietFlag );
2639 }
2640 }
2641 db_end_transaction(0);
2642 blob_reset(&absBuffer);
2643 if( dryRunFlag!=0 ){
2644 fossil_print("dry-run: would have touched %d file(s)\n",
2645 changeCount);
2646 }else{
2647 fossil_print("Touched %d file(s)\n", changeCount);
2648 }
2649 }
2650
2651 /*
2652 ** If zFileName is not NULL and contains a '.', this returns a pointer
2653 ** to the position after the final '.', else it returns NULL. As a
2654 ** special case, if it ends with a period then a pointer to the
2655 ** terminating NUL byte is returned.
2656 */
file_extension(const char * zFileName)2657 const char * file_extension(const char *zFileName){
2658 const char * zExt = zFileName ? strrchr(zFileName, '.') : 0;
2659 return zExt ? &zExt[1] : 0;
2660 }
2661
2662 /*
2663 ** Returns non-zero if the specified file name ends with any reserved name,
2664 ** e.g.: _FOSSIL_ or .fslckout. Specifically, it returns 1 for exact match
2665 ** or 2 for a tail match on a longer file name.
2666 **
2667 ** For the sake of efficiency, zFilename must be a canonical name, e.g. an
2668 ** absolute path using only forward slash ('/') as a directory separator.
2669 **
2670 ** nFilename must be the length of zFilename. When negative, strlen() will
2671 ** be used to calculate it.
2672 */
file_is_reserved_name(const char * zFilename,int nFilename)2673 int file_is_reserved_name(const char *zFilename, int nFilename){
2674 const char *zEnd; /* one-after-the-end of zFilename */
2675 int gotSuffix = 0; /* length of suffix (-wal, -shm, -journal) */
2676
2677 assert( zFilename && "API misuse" );
2678 if( nFilename<0 ) nFilename = (int)strlen(zFilename);
2679 if( nFilename<8 ) return 0; /* strlen("_FOSSIL_") */
2680 zEnd = zFilename + nFilename;
2681 if( nFilename>=12 ){ /* strlen("_FOSSIL_-(shm|wal)") */
2682 /* Check for (-wal, -shm, -journal) suffixes, with an eye towards
2683 ** runtime speed. */
2684 if( zEnd[-4]=='-' ){
2685 if( fossil_strnicmp("wal", &zEnd[-3], 3)
2686 && fossil_strnicmp("shm", &zEnd[-3], 3) ){
2687 return 0;
2688 }
2689 gotSuffix = 4;
2690 }else if( nFilename>=16 && zEnd[-8]=='-' ){ /*strlen(_FOSSIL_-journal) */
2691 if( fossil_strnicmp("journal", &zEnd[-7], 7) ) return 0;
2692 gotSuffix = 8;
2693 }
2694 if( gotSuffix ){
2695 assert( 4==gotSuffix || 8==gotSuffix );
2696 zEnd -= gotSuffix;
2697 nFilename -= gotSuffix;
2698 gotSuffix = 1;
2699 }
2700 assert( nFilename>=8 && "strlen(_FOSSIL_)" );
2701 assert( gotSuffix==0 || gotSuffix==1 );
2702 }
2703 switch( zEnd[-1] ){
2704 case '_':{
2705 if( fossil_strnicmp("_FOSSIL_", &zEnd[-8], 8) ) return 0;
2706 if( 8==nFilename ) return 1;
2707 return zEnd[-9]=='/' ? 2 : gotSuffix;
2708 }
2709 case 'T':
2710 case 't':{
2711 if( nFilename<9 || zEnd[-9]!='.'
2712 || fossil_strnicmp(".fslckout", &zEnd[-9], 9) ){
2713 return 0;
2714 }
2715 if( 9==nFilename ) return 1;
2716 return zEnd[-10]=='/' ? 2 : gotSuffix;
2717 }
2718 default:{
2719 return 0;
2720 }
2721 }
2722 }
2723
2724 /*
2725 ** COMMAND: test-is-reserved-name
2726 **
2727 ** Usage: %fossil test-is-reserved-name FILENAMES...
2728 **
2729 ** Passes each given name to file_is_reserved_name() and outputs one
2730 ** line per file: the result value of that function followed by the
2731 ** name.
2732 */
test_is_reserved_name_cmd(void)2733 void test_is_reserved_name_cmd(void){
2734 int i;
2735
2736 if(g.argc<3){
2737 usage("FILENAME_1 [...FILENAME_N]");
2738 }
2739 for( i = 2; i < g.argc; ++i ){
2740 const int check = file_is_reserved_name(g.argv[i], -1);
2741 fossil_print("%d %s\n", check, g.argv[i]);
2742 }
2743 }
2744
2745
2746 /*
2747 ** Returns 1 if the given directory contains a file named .fslckout, 2
2748 ** if it contains a file named _FOSSIL_, else returns 0.
2749 */
dir_has_ckout_db(const char * zDir)2750 int dir_has_ckout_db(const char *zDir){
2751 int rc = 0;
2752 char * zCkoutDb = mprintf("%//.fslckout", zDir);
2753 if(file_isfile(zCkoutDb, ExtFILE)){
2754 rc = 1;
2755 }else{
2756 fossil_free(zCkoutDb);
2757 zCkoutDb = mprintf("%//_FOSSIL_", zDir);
2758 if(file_isfile(zCkoutDb, ExtFILE)){
2759 rc = 2;
2760 }
2761 }
2762 fossil_free(zCkoutDb);
2763 return rc;
2764 }
2765