Fossil

Check-in [2b951025]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Refactoring the "add", "del", and "addremove" commands.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: 2b95102592115cf2bedf2d81a900a1c2e755ae4a
User & Date: drh 2011-04-14 22:41:01.665
Context
2011-04-15
00:59
Completely forget about files that were added then removed without ever been committed. ... (Closed-Leaf check-in: 97e5ff20 user: drh tags: experimental)
2011-04-14
22:41
Refactoring the "add", "del", and "addremove" commands. ... (check-in: 2b951025 user: drh tags: experimental)
18:09
Refactoring the directory scanning code used by recursive add, extra, and clean. Seems to work but needs more testing prior to folding into trunk. ... (check-in: f60f5602 user: drh tags: experimental)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/add.c.
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

128
129
130
131

132
133
134
135
136
137
138
139



140

141
142
143
144
145
146
147
148
149
150
151
152
153
154

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183





184
185
186
187


188
189
190
191
192
193
194
}

/*
** Add a single file named zName to the VFILE table with vid.
**
** Omit any file whose name is pOmit.
*/
static void add_one_file(
  const char *zName,   /* Name of file to add */
  int vid,             /* Add to this VFILE */
  Blob *pOmit
){
  Blob pathname;
  const char *zPath;
  int i;
  const char *zReserved;

  file_tree_name(zName, &pathname, 1);
  zPath = blob_str(&pathname);
  for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){
    if( fossil_strcmp(zPath, zReserved)==0 ) break;
  }
  if( zReserved || (pOmit && blob_compare(&pathname, pOmit)==0) ){
    fossil_warning("cannot add %s", zPath);
  }else{
    if( !file_is_simple_pathname(zPath) ){
      fossil_fatal("filename contains illegal characters: %s", zPath);
    }
#if defined(_WIN32)
    if( db_exists("SELECT 1 FROM vfile"
                  " WHERE pathname=%Q COLLATE nocase", zPath) ){
      db_multi_exec("UPDATE vfile SET deleted=0"
                    " WHERE pathname=%Q COLLATE nocase", zPath);
    }
#else
    if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){
      db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath);
    }
#endif
    else{

      db_multi_exec(
        "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe)"
        "VALUES(%d,0,0,0,%Q,%d)",
        vid, zPath,file_isexe(zName));

    }
    printf("ADDED  %s\n", zPath);
  }
  blob_reset(&pathname);
}

/*
** All content of the zDir directory to the SFILE table.



*/

void add_directory_content(const char *zDir, Glob *pIgnore){
  DIR *d;
  int origSize;
  struct dirent *pEntry;
  Blob path;

  blob_zero(&path);
  blob_append(&path, zDir, -1);
  origSize = blob_size(&path);
  d = opendir(zDir);
  if( d ){
    while( (pEntry=readdir(d))!=0 ){
      char *zPath;
      if( pEntry->d_name[0]=='.' ){

        if( !includeDotFiles ) continue;
        if( pEntry->d_name[1]==0 ) continue;
        if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
      }
      blob_appendf(&path, "/%s", pEntry->d_name);
      zPath = blob_str(&path);
      if( glob_match(pIgnore, zPath) ){
        /* Noop */
      }else if( file_isdir(zPath)==1 ){
        add_directory_content(zPath, pIgnore);
      }else if( file_isfile(zPath) ){
        db_multi_exec("INSERT INTO sfile VALUES(%Q)", zPath);
      }
      blob_resize(&path, origSize);
    }
    closedir(d);
  }
  blob_reset(&path);
}

/*
** Add all content of a directory.
*/
void add_directory(const char *zDir, int vid, Blob *pOmit, Glob *pIgnore){
  Stmt q;
  add_directory_content(zDir, pIgnore);
  db_prepare(&q, "SELECT x FROM sfile ORDER BY x");
  while( db_step(&q)==SQLITE_ROW ){
    const char *zName = db_column_text(&q, 0);





    add_one_file(zName, vid, pOmit);
  }
  db_finalize(&q);
  db_multi_exec("DELETE FROM sfile");


}

/*
** COMMAND: add
**
** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...?
**







|
|
|
<

<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
|

|
|
|
|
|

|
|
|

|
>
|
|
|
|
>
|
|
<
|



<
>
>
>

>
|
<
|
<
<
|
<
<
<
<
<
<
|
<
>
|
<
<
|
|
|
<
|
<
<
<
<
|
<
<
<
<
|
|
<
<
<
<
<
<
<
|
|
|
>
>
>
>
>
|

|
<
>
>







88
89
90
91
92
93
94
95
96
97

98













99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

122
123
124
125

126
127
128
129
130
131

132


133






134

135
136


137
138
139

140




141




142
143







144
145
146
147
148
149
150
151
152
153
154

155
156
157
158
159
160
161
162
163
}

/*
** Add a single file named zName to the VFILE table with vid.
**
** Omit any file whose name is pOmit.
*/
static int add_one_file(
  const char *zPath,   /* Tree-name of file to add. */
  int vid              /* Add to this VFILE */

){













  if( !file_is_simple_pathname(zPath) ){
    fossil_fatal("filename contains illegal characters: %s", zPath);
  }
#if defined(_WIN32)
  if( db_exists("SELECT 1 FROM vfile"
                " WHERE pathname=%Q COLLATE nocase", zPath) ){
    db_multi_exec("UPDATE vfile SET deleted=0"
                  " WHERE pathname=%Q COLLATE nocase", zPath);
  }
#else
  if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){
    db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath);
  }
#endif
  else{
    char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
    db_multi_exec(
      "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe)"
      "VALUES(%d,0,0,0,%Q,%d)",
      vid, zPath, file_isexe(zFullname));
    fossil_free(zFullname);
  }
  printf("ADDED  %s\n", zPath);

  return 1;
}

/*

** Add all files in the sfile temp table.
**
** Automatically exclude the repository file.
*/
static int add_files_in_sfile(int vid){
  const char *zRepo;        /* Name of the repository database file */

  int nAdd = 0;             /* Number of files added */


  int i;                    /* Loop counter */






  const char *zReserved;    /* Name of a reserved file */

  Blob repoName;            /* Treename of the repository */
  Stmt loop;                /* SQL to loop over all files to add */


 
  if( !file_tree_name(g.zRepositoryName, &repoName, 0) ){
    blob_zero(&repoName);

    zRepo = "";




  }else{




    zRepo = blob_str(&repoName);
  }







  db_prepare(&loop, "SELECT x FROM sfile ORDER BY x");
  while( db_step(&loop)==SQLITE_ROW ){
    const char *zToAdd = db_column_text(&loop, 0);
    if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
    for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){
      if( fossil_strcmp(zToAdd, zReserved)==0 ) break;
    }
    if( zReserved ) continue;
    nAdd += add_one_file(zToAdd, vid);
  }
  db_finalize(&loop);

  blob_reset(&repoName);
  return nAdd;
}

/*
** COMMAND: add
**
** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...?
**
204
205
206
207
208
209
210
211
212

213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238



239
240
241

242

243
244
245
246
247
248
249
250
251
252
253




254

255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
** does not appear on the command line then the "ignore-glob" setting is
** used.
**
** SUMMARY: fossil add ?OPTIONS? FILE1 ?FILE2 ...?
** Options: --dotfiles, --ignore
*/
void add_cmd(void){
  int i;
  int vid;

  const char *zIgnoreFlag;
  Blob repo;
  Glob *pIgnore;       /* Ignore everything matching this glob pattern */

  zIgnoreFlag = find_option("ignore",0,1);
  includeDotFiles = find_option("dotfiles",0,0)!=0;
  db_must_be_within_tree();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  vid = db_lget_int("checkout",0);
  if( vid==0 ){
    fossil_panic("no checkout to add to");
  }
  db_begin_transaction();
  if( !file_tree_name(g.zRepositoryName, &repo, 0) ){
    blob_zero(&repo);
  }
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
#if defined(_WIN32)
  db_multi_exec(
     "CREATE INDEX IF NOT EXISTS vfile_pathname "
     "  ON vfile(pathname COLLATE nocase)"
  );
#endif
  pIgnore = glob_create(zIgnoreFlag);



  for(i=2; i<g.argc; i++){
    char *zName;
    int isDir;



    zName = mprintf("%/", g.argv[i]);
    isDir = file_isdir(zName);
    if( isDir==1 ){
      int sz = strlen(zName);
      if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; }
      add_directory(zName, vid, &repo, pIgnore);
    }else if( isDir==0 ){
      fossil_fatal("not found: %s", zName);
    }else if( access(zName, R_OK) ){
      fossil_fatal("cannot open %s", zName);
    }else{




      add_one_file(zName, vid, &repo);

    }
    free(zName);
  }
  glob_free(pIgnore);
  db_end_transaction(0);
}


/*
** Unmangage a single file.
*/
void delete_one_file(const char *zName){
  char *zPath;
  Blob pathname;
  file_tree_name(zName, &pathname, 1);
  zPath = blob_str(&pathname);
  if( !db_exists(
           "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zPath) ){
    fossil_fatal("not in the repository: %s", zName);
  }else{
    db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath);
    printf("DELETED  %s\n", zPath);
  }
  blob_reset(&pathname);
}

/*
** Remove all contents of zDir
*/
void del_directory_content(const char *zDir){
  DIR *d;
  int origSize;
  struct dirent *pEntry;
  Blob path;

  blob_zero(&path);
  blob_append(&path, zDir, -1);
  origSize = blob_size(&path);
  d = opendir(zDir);
  if( d ){
    while( (pEntry=readdir(d))!=0 ){
      char *zPath;
      if( pEntry->d_name[0]=='.'){
        if( !includeDotFiles ) continue;
        if( pEntry->d_name[1]==0 ) continue;
        if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
      }
      blob_appendf(&path, "/%s", pEntry->d_name);
      zPath = blob_str(&path);
      if( file_isdir(zPath)==1 ){
        del_directory_content(zPath);
      }else if( file_isfile(zPath) ){
        delete_one_file(zPath);
      }
      blob_resize(&path, origSize);
    }
    closedir(d);
  }
  blob_reset(&path);
}

/*
** COMMAND: rm
** COMMAND: delete
**
** Usage: %fossil rm FILE1 ?FILE2 ...?







|
|
>
|
<
|












<
<
<








>
>
>



>

>
|


<
<
|





>
>
>
>
|
>




<
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







173
174
175
176
177
178
179
180
181
182
183

184
185
186
187
188
189
190
191
192
193
194
195
196



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216


217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

233
234
235



















































236
237
238
239
240
241
242
** does not appear on the command line then the "ignore-glob" setting is
** used.
**
** SUMMARY: fossil add ?OPTIONS? FILE1 ?FILE2 ...?
** Options: --dotfiles, --ignore
*/
void add_cmd(void){
  int i;                     /* Loop counter */
  int vid;                   /* Currently checked out version */
  int nRoot;                 /* Full path characters in g.zLocalRoot */
  const char *zIgnoreFlag;   /* The --ignore option or ignore-glob setting */

  Glob *pIgnore;             /* Ignore everything matching this glob pattern */

  zIgnoreFlag = find_option("ignore",0,1);
  includeDotFiles = find_option("dotfiles",0,0)!=0;
  db_must_be_within_tree();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  vid = db_lget_int("checkout",0);
  if( vid==0 ){
    fossil_panic("no checkout to add to");
  }
  db_begin_transaction();



  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
#if defined(_WIN32)
  db_multi_exec(
     "CREATE INDEX IF NOT EXISTS vfile_pathname "
     "  ON vfile(pathname COLLATE nocase)"
  );
#endif
  pIgnore = glob_create(zIgnoreFlag);
  nRoot = strlen(g.zLocalRoot);
  
  /* Load the names of all files that are to be added into sfile temp table */
  for(i=2; i<g.argc; i++){
    char *zName;
    int isDir;
    Blob fullName;

    file_canonical_name(g.argv[i], &fullName);
    zName = blob_str(&fullName);
    isDir = file_isdir(zName);
    if( isDir==1 ){


      vfile_scan(&fullName, nRoot-1, includeDotFiles, pIgnore);
    }else if( isDir==0 ){
      fossil_fatal("not found: %s", zName);
    }else if( access(zName, R_OK) ){
      fossil_fatal("cannot open %s", zName);
    }else{
      char *zTreeName = &zName[nRoot];
      db_multi_exec(
         "INSERT OR IGNORE INTO sfile(x)"
         "  SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE pathname=%Q)",
         zTreeName, zTreeName
      );
    }
    free(zName);
  }
  glob_free(pIgnore);


  add_files_in_sfile(vid);  
  db_end_transaction(0);



















































}

/*
** COMMAND: rm
** COMMAND: delete
**
** Usage: %fossil rm FILE1 ?FILE2 ...?
328
329
330
331
332
333
334

335
336
337
338
339
340
341

342

343
344
345
346



347


348
349
350
351
352
353



354

355


356
357
358
359
360
361
362
**
** SUMMARY: fossil rm FILE1 ?FILE2 ...?
**      or: fossil delete FILE1 ?FILE2 ...?
*/
void delete_cmd(void){
  int i;
  int vid;


  db_must_be_within_tree();
  vid = db_lget_int("checkout", 0);
  if( vid==0 ){
    fossil_panic("no checkout to remove from");
  }
  db_begin_transaction();

  for(i=2; i<g.argc; i++){

    char *zName;

    zName = mprintf("%/", g.argv[i]);
    if( file_isdir(zName) == 1 ){



      int sz = strlen(zName);


      if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; }
      del_directory_content(zName);
    } else {
      delete_one_file(zName);
    }
    free(zName);



  }

  db_multi_exec("DELETE FROM vfile WHERE deleted AND rid=0");


  db_end_transaction(0);
}

/*
** COMMAND: addremove
**
** Usage: %fossil addremove ?--dotfiles? ?--ignore GLOBPATTERN? ?--test?







>







>

>
|

|
|
>
>
>
|
>
>
|
|
<
|
|
|
>
>
>

>
|
>
>







250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279

280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
**
** SUMMARY: fossil rm FILE1 ?FILE2 ...?
**      or: fossil delete FILE1 ?FILE2 ...?
*/
void delete_cmd(void){
  int i;
  int vid;
  Stmt loop;

  db_must_be_within_tree();
  vid = db_lget_int("checkout", 0);
  if( vid==0 ){
    fossil_panic("no checkout to remove from");
  }
  db_begin_transaction();
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
  for(i=2; i<g.argc; i++){
    Blob treeName;
    char *zTreeName;

    file_tree_name(g.argv[i], &treeName, 1);
    zTreeName = blob_str(&treeName);
    db_multi_exec(
       "INSERT OR IGNORE INTO sfile"
       " SELECT pathname FROM vfile"
       "  WHERE (pathname=%Q"
       "     OR (pathname>'%q/' AND pathname<'%q0'))"
       "    AND NOT deleted",
       zTreeName, zTreeName, zTreeName
    );

    blob_reset(&treeName);
  }
  
  db_prepare(&loop, "SELECT x FROM sfile");
  while( db_step(&loop)==SQLITE_ROW ){
    printf("DELETED %s\n", db_column_text(&loop, 0));
  }
  db_finalize(&loop);
  db_multi_exec(
    "UPDATE vfile SET deleted=1 WHERE pathname IN sfile"
  );
  db_end_transaction(0);
}

/*
** COMMAND: addremove
**
** Usage: %fossil addremove ?--dotfiles? ?--ignore GLOBPATTERN? ?--test?
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413







414
415
416
417
418
419
420
421
422
423
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
  Blob path;
  const char *zIgnoreFlag = find_option("ignore",0,1);
  int allFlag = find_option("dotfiles",0,0)!=0;
  int isTest = find_option("test",0,0)!=0;
  int n;
  Stmt q;
  int vid;
  Blob repo;
  int nAdd = 0;
  int nDelete = 0;
  Glob *pIgnore;

  db_must_be_within_tree();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  vid = db_lget_int("checkout",0);
  if( vid==0 ){
    fossil_panic("no checkout to add to");
  }
  db_begin_transaction();







  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  /* now we read the complete file structure into a temp table */
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
  glob_free(pIgnore);
  if( file_tree_name(g.zRepositoryName, &repo, 0) ){
    db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
  }

  /* step 1: search for extra files */
  db_prepare(&q,
      "SELECT x, %Q || x FROM sfile"
      " WHERE x NOT IN (%s)"
      " ORDER BY 1",
      g.zLocalRoot,
      fossil_all_reserved_names()
  );
  while( db_step(&q)==SQLITE_ROW ){
    add_one_file(db_column_text(&q, 1), vid, 0);
    nAdd++;
  }
  db_finalize(&q);
  /* step 2: search for missing files */
  db_prepare(&q,
      "SELECT pathname,%Q || pathname,deleted FROM vfile"
      " WHERE deleted!=1"
      " ORDER BY 1",
      g.zLocalRoot
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char * zFile;
    const char * zPath;








<













>
>
>
>
>
>
>







<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
|
<


|
|







328
329
330
331
332
333
334

335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361



362











363

364
365
366
367
368
369
370
371
372
373
374
  Blob path;
  const char *zIgnoreFlag = find_option("ignore",0,1);
  int allFlag = find_option("dotfiles",0,0)!=0;
  int isTest = find_option("test",0,0)!=0;
  int n;
  Stmt q;
  int vid;

  int nAdd = 0;
  int nDelete = 0;
  Glob *pIgnore;

  db_must_be_within_tree();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  vid = db_lget_int("checkout",0);
  if( vid==0 ){
    fossil_panic("no checkout to add to");
  }
  db_begin_transaction();

  /* step 1:  
  ** Populate the temp table "sfile" with the names of all unmanged
  ** files currently in the check-out, except for files that match the
  ** --ignore or ignore-glob patterns and dot-files.  Then add all of
  ** the files in the sfile temp table to the set of managed files.
  */
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  /* now we read the complete file structure into a temp table */
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
  glob_free(pIgnore);



  nAdd = add_files_in_sfile(vid);













  /* step 2: search for missing files */
  db_prepare(&q,
      "SELECT pathname, %Q || pathname, deleted FROM vfile"
      " WHERE NOT deleted"
      " ORDER BY 1",
      g.zLocalRoot
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char * zFile;
    const char * zPath;

540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
      int nOrig;
      file_tree_name(g.argv[i], &orig, 1);
      zOrig = blob_str(&orig);
      nOrig = blob_size(&orig);
      db_prepare(&q,
         "SELECT pathname FROM vfile"
         " WHERE vid=%d"
         "   AND (pathname='%s' OR pathname GLOB '%s/*')"
         " ORDER BY 1",
         vid, zOrig, zOrig
      );
      while( db_step(&q)==SQLITE_ROW ){
        const char *zPath = db_column_text(&q, 0);
        int nPath = db_column_bytes(&q, 0);
        const char *zTail;
        if( nPath==nOrig ){
          zTail = file_tail(zPath);







|

|







466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
      int nOrig;
      file_tree_name(g.argv[i], &orig, 1);
      zOrig = blob_str(&orig);
      nOrig = blob_size(&orig);
      db_prepare(&q,
         "SELECT pathname FROM vfile"
         " WHERE vid=%d"
         "   AND (pathname='%q' OR (pathname>'%q/' AND pathname<'%q0'))"
         " ORDER BY 1",
         vid, zOrig, zOrig, zOrig
      );
      while( db_step(&q)==SQLITE_ROW ){
        const char *zPath = db_column_text(&q, 0);
        int nPath = db_column_bytes(&q, 0);
        const char *zTail;
        if( nPath==nOrig ){
          zTail = file_tail(zPath);