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