Fossil SCM

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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button