424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
|
/*
** Return the tail of a file pathname. The tail is the last component
** of the path. For example, the tail of "/a/b/c.d" is "c.d".
*/
const char *file_tail(const char *z){
const char *zTail = z;
while( z[0] ){
if( z[0]=='/' ) zTail = &z[1];
z++;
}
return zTail;
}
/*
** Copy the content of a file from one place to another.
*/
void file_copy(const char *zFrom, const char *zTo){
FILE *in, *out;
int got;
char zBuf[8192];
in = fossil_fopen(zFrom, "rb");
if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom);
file_mkfolder(zTo, 0);
out = fossil_fopen(zTo, "wb");
if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo);
while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){
fwrite(zBuf, 1, got, out);
}
fclose(in);
fclose(out);
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
|
/*
** Return the tail of a file pathname. The tail is the last component
** of the path. For example, the tail of "/a/b/c.d" is "c.d".
*/
const char *file_tail(const char *z){
const char *zTail = z;
if( !zTail ) return 0;
while( z[0] ){
if( fossil_isdirsep(z[0]) ) zTail = &z[1];
z++;
}
return zTail;
}
/*
** Return the directory of a file path name. The directory is all components
** except the last one. For example, the directory of "/a/b/c.d" is "/a/b".
** If there is no directory, NULL is returned; otherwise, the returned memory
** should be freed via fossil_free().
*/
char *file_dirname(const char *z){
const char *zTail = file_tail(z);
if( zTail && zTail!=z ){
return mprintf("%.*s", (int)(zTail-z-1), z);
}else{
return 0;
}
}
/*
** Copy the content of a file from one place to another.
*/
void file_copy(const char *zFrom, const char *zTo){
FILE *in, *out;
int got;
char zBuf[8192];
in = fossil_fopen(zFrom, "rb");
if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom);
file_mkfolder(zTo, 0, 0);
out = fossil_fopen(zTo, "wb");
if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo);
while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){
fwrite(zBuf, 1, got, out);
}
fclose(in);
fclose(out);
|
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
|
}
return 0;
}
/*
** Create the tree of directories in which zFilename belongs, if that sequence
** of directories does not already exist.
*/
void file_mkfolder(const char *zFilename, int forceFlag){
int i, nName;
char *zName;
nName = strlen(zFilename);
zName = mprintf("%s", zFilename);
nName = file_simplify_name(zName, nName, 0);
for(i=1; i<nName; i++){
if( zName[i]=='/' ){
zName[i] = 0;
#if defined(_WIN32) || defined(__CYGWIN__)
/*
** On Windows, local path looks like: C:/develop/project/file.txt
** The if stops us from trying to create a directory of a drive letter
** C: in this example.
*/
if( !(i==2 && zName[1]==':') ){
#endif
if( file_mkdir(zName, forceFlag) && file_isdir(zName)!=1 ){
fossil_fatal_recursive("unable to create directory %s", zName);
return;
}
#if defined(_WIN32) || defined(__CYGWIN__)
}
#endif
zName[i] = '/';
}
}
free(zName);
}
/*
** Removes the directory named in the argument, if it exists. The directory
** must be empty and cannot be the current directory or the root directory.
**
** Returns zero upon success.
|
>
>
>
|
|
>
|
>
|
>
>
|
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
|
}
return 0;
}
/*
** Create the tree of directories in which zFilename belongs, if that sequence
** of directories does not already exist.
**
** On success, return zero. On error, return errorReturn if positive, otherwise
** print an error message and abort.
*/
int file_mkfolder(const char *zFilename, int forceFlag, int errorReturn){
int i, nName, rc = 0;
char *zName;
nName = strlen(zFilename);
zName = mprintf("%s", zFilename);
nName = file_simplify_name(zName, nName, 0);
for(i=1; i<nName; i++){
if( zName[i]=='/' ){
zName[i] = 0;
#if defined(_WIN32) || defined(__CYGWIN__)
/*
** On Windows, local path looks like: C:/develop/project/file.txt
** The if stops us from trying to create a directory of a drive letter
** C: in this example.
*/
if( !(i==2 && zName[1]==':') ){
#endif
if( file_mkdir(zName, forceFlag) && file_isdir(zName)!=1 ){
if (errorReturn <= 0) {
fossil_fatal_recursive("unable to create directory %s", zName);
}
rc = errorReturn;
break;
}
#if defined(_WIN32) || defined(__CYGWIN__)
}
#endif
zName[i] = '/';
}
}
free(zName);
return rc;
}
/*
** Removes the directory named in the argument, if it exists. The directory
** must be empty and cannot be the current directory or the root directory.
**
** Returns zero upon success.
|
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
|
file_relative_name(g.argv[i], &x, slashFlag);
fossil_print("%s\n", blob_buffer(&x));
blob_reset(&x);
}
}
/*
** Compute a pathname for a file relative to the root of the local
** tree. Return TRUE on success. On failure, print and error
** message and quit if the errFatal flag is true. If errFatal is
** false, then simply return 0.
**
** The root of the tree is defined by the g.zLocalRoot variable.
*/
int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){
Blob localRoot;
int nLocalRoot;
char *zLocalRoot;
Blob full;
int nFull;
char *zFull;
int (*xCmp)(const char*,const char*,int);
blob_zero(pOut);
if( !g.localOpen ){
blob_appendf(pOut, "%s", zOrigName);
return 1;
}
file_canonical_name(g.zLocalRoot, &localRoot, 1);
nLocalRoot = blob_size(&localRoot);
zLocalRoot = blob_buffer(&localRoot);
assert( nLocalRoot>0 && zLocalRoot[nLocalRoot-1]=='/' );
file_canonical_name(zOrigName, &full, 0);
nFull = blob_size(&full);
zFull = blob_buffer(&full);
if( filenames_are_case_sensitive() ){
xCmp = fossil_strncmp;
}else{
xCmp = fossil_strnicmp;
}
/* Special case. zOrigName refers to g.zLocalRoot directory. */
if( (nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0)
|| (nFull==1 && zFull[0]=='/' && nLocalRoot==1 && zLocalRoot[0]=='/') ){
blob_append(pOut, ".", 1);
blob_reset(&localRoot);
blob_reset(&full);
return 1;
}
if( nFull<=nLocalRoot || xCmp(zLocalRoot, zFull, nLocalRoot) ){
blob_reset(&localRoot);
blob_reset(&full);
if( errFatal ){
fossil_fatal("file outside of checkout tree: %s", zOrigName);
}
return 0;
}
blob_append(pOut, &zFull[nLocalRoot], nFull-nLocalRoot);
blob_reset(&localRoot);
blob_reset(&full);
return 1;
}
/*
** COMMAND: test-tree-name
**
** Test the operation of the tree name generator.
**
** Options:
** --case-sensitive B Enable or disable case-sensitive filenames. B is
** a boolean: "yes", "no", "true", "false", etc.
*/
void cmd_test_tree_name(void){
int i;
Blob x;
db_find_and_open_repository(0,0);
blob_zero(&x);
for(i=2; i<g.argc; i++){
if( file_tree_name(g.argv[i], &x, 1) ){
fossil_print("%s\n", blob_buffer(&x));
blob_reset(&x);
}
}
}
/*
|
>
>
>
|
>
|
|
|
<
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
|
>
>
>
>
>
>
>
>
>
|
>
>
>
|
|
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
|
file_relative_name(g.argv[i], &x, slashFlag);
fossil_print("%s\n", blob_buffer(&x));
blob_reset(&x);
}
}
/*
** Compute a full path name for a file in the local tree. If
** the absolute flag is non-zero, the computed path will be
** absolute, starting with the root path of the local tree;
** otherwise, it will be relative to the root of the local
** tree. In both cases, the root of the local tree is defined
** by the g.zLocalRoot variable. Return TRUE on success. On
** failure, print and error message and quit if the errFatal
** flag is true. If errFatal is false, then simply return 0.
*/
int file_tree_name(
const char *zOrigName,
Blob *pOut,
int absolute,
int errFatal
){
Blob localRoot;
int nLocalRoot;
char *zLocalRoot;
Blob full;
int nFull;
char *zFull;
int (*xCmp)(const char*,const char*,int);
blob_zero(pOut);
if( !g.localOpen ){
if( absolute && !file_is_absolute_path(zOrigName) ){
if( errFatal ){
fossil_fatal("relative to absolute needs open checkout tree: %s",
zOrigName);
}
return 0;
}else{
/*
** The original path may be relative or absolute; however, without
** an open checkout tree, the only things we can do at this point
** is return it verbatim or generate a fatal error. The caller is
** probably expecting a tree-relative path name will be returned;
** however, most places where this function is called already check
** if the local checkout tree is open, either directly or indirectly,
** which would make this situation impossible. Alternatively, they
** could check the returned path using the file_is_absolute_path()
** function.
*/
blob_appendf(pOut, "%s", zOrigName);
return 1;
}
}
file_canonical_name(g.zLocalRoot, &localRoot, 1);
nLocalRoot = blob_size(&localRoot);
zLocalRoot = blob_buffer(&localRoot);
assert( nLocalRoot>0 && zLocalRoot[nLocalRoot-1]=='/' );
file_canonical_name(zOrigName, &full, 0);
nFull = blob_size(&full);
zFull = blob_buffer(&full);
if( filenames_are_case_sensitive() ){
xCmp = fossil_strncmp;
}else{
xCmp = fossil_strnicmp;
}
/* Special case. zOrigName refers to g.zLocalRoot directory. */
if( (nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0)
|| (nFull==1 && zFull[0]=='/' && nLocalRoot==1 && zLocalRoot[0]=='/') ){
if( absolute ){
blob_append(pOut, zLocalRoot, nLocalRoot);
}else{
blob_append(pOut, ".", 1);
}
blob_reset(&localRoot);
blob_reset(&full);
return 1;
}
if( nFull<=nLocalRoot || xCmp(zLocalRoot, zFull, nLocalRoot) ){
blob_reset(&localRoot);
blob_reset(&full);
if( errFatal ){
fossil_fatal("file outside of checkout tree: %s", zOrigName);
}
return 0;
}
if( absolute ){
if( !file_is_absolute_path(zOrigName) ){
blob_append(pOut, zLocalRoot, nLocalRoot);
}
blob_append(pOut, zOrigName, -1);
blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
blob_size(pOut), 0));
}else{
blob_append(pOut, &zFull[nLocalRoot], nFull-nLocalRoot);
}
blob_reset(&localRoot);
blob_reset(&full);
return 1;
}
/*
** COMMAND: test-tree-name
**
** Test the operation of the tree name generator.
**
** Options:
** --absolute Return an absolute path instead of a relative one.
** --case-sensitive B Enable or disable case-sensitive filenames. B is
** a boolean: "yes", "no", "true", "false", etc.
*/
void cmd_test_tree_name(void){
int i;
Blob x;
int absoluteFlag = find_option("absolute",0,0)!=0;
db_find_and_open_repository(0,0);
blob_zero(&x);
for(i=2; i<g.argc; i++){
if( file_tree_name(g.argv[i], &x, absoluteFlag, 1) ){
fossil_print("%s\n", blob_buffer(&x));
blob_reset(&x);
}
}
}
/*
|