[9] | 1 | /*
|
---|
| 2 | * mk_direntry.c
|
---|
| 3 | * Make new directory entries, and handles name clashes
|
---|
| 4 | *
|
---|
| 5 | */
|
---|
| 6 |
|
---|
| 7 | /*
|
---|
| 8 | * This file is used by those commands that need to create new directory entries
|
---|
| 9 | */
|
---|
| 10 |
|
---|
| 11 | #include "sysincludes.h"
|
---|
| 12 | #include "msdos.h"
|
---|
| 13 | #include "mtools.h"
|
---|
| 14 | #include "vfat.h"
|
---|
| 15 | #include "nameclash.h"
|
---|
| 16 | #include "fs.h"
|
---|
| 17 | #include "stream.h"
|
---|
| 18 | #include "mainloop.h"
|
---|
| 19 |
|
---|
| 20 | static inline int ask_rename(ClashHandling_t *ch,
|
---|
| 21 | char *longname, int isprimary, char *argname)
|
---|
| 22 | {
|
---|
| 23 | char shortname[13];
|
---|
| 24 | int mangled;
|
---|
| 25 |
|
---|
| 26 | /* TODO: Would be nice to suggest "autorenamed" version of name, press
|
---|
| 27 | * <Return> to get it.
|
---|
| 28 | */
|
---|
| 29 | #if 0
|
---|
| 30 | fprintf(stderr,"Entering ask_rename, isprimary=%d.\n", isprimary);
|
---|
| 31 | #endif
|
---|
| 32 |
|
---|
| 33 | if(!opentty(0))
|
---|
| 34 | return 0;
|
---|
| 35 |
|
---|
| 36 | #define maxsize (isprimary ? MAX_VNAMELEN+1 : 11+1)
|
---|
| 37 | #define name (isprimary ? argname : shortname)
|
---|
| 38 |
|
---|
| 39 | mangled = 0;
|
---|
| 40 | do {
|
---|
| 41 | fprintf(stderr, "New %s name for \"%s\": ",
|
---|
| 42 | isprimary ? "primary" : "secondary", longname);
|
---|
| 43 | fflush(stderr);
|
---|
| 44 | if (! fgets(name, maxsize, opentty(0)))
|
---|
| 45 | return 0;
|
---|
| 46 |
|
---|
| 47 | /* Eliminate newline(s) in the file name */
|
---|
| 48 | name[strlen(name)-1]='\0';
|
---|
| 49 | if (!isprimary)
|
---|
| 50 | ch->name_converter(shortname,0, &mangled, argname);
|
---|
| 51 | } while (mangled & 1);
|
---|
| 52 | return 1;
|
---|
| 53 | #undef maxsize
|
---|
| 54 | #undef name
|
---|
| 55 | }
|
---|
| 56 |
|
---|
| 57 | static inline clash_action ask_namematch(char *name, int isprimary,
|
---|
| 58 | ClashHandling_t *ch, int no_overwrite,
|
---|
| 59 | int reason)
|
---|
| 60 | {
|
---|
| 61 | char ans[10];
|
---|
| 62 | clash_action a;
|
---|
| 63 | int perm;
|
---|
| 64 | char unix_shortname[13];
|
---|
| 65 |
|
---|
| 66 |
|
---|
| 67 | #define EXISTS 0
|
---|
| 68 | #define RESERVED 1
|
---|
| 69 | #define ILLEGALS 2
|
---|
| 70 |
|
---|
| 71 | static const char *reasons[]= {
|
---|
| 72 | "already exists",
|
---|
| 73 | "is reserved",
|
---|
| 74 | "contains illegal character(s)"};
|
---|
| 75 |
|
---|
| 76 |
|
---|
| 77 | if (!isprimary)
|
---|
| 78 | name = unix_normalize(unix_shortname, name, name+8);
|
---|
| 79 |
|
---|
| 80 | a = ch->action[isprimary];
|
---|
| 81 |
|
---|
| 82 | if(a == NAMEMATCH_NONE && !opentty(1)) {
|
---|
| 83 | /* no default, and no tty either . Skip the troublesome file */
|
---|
| 84 | return NAMEMATCH_SKIP;
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 | perm = 0;
|
---|
| 88 | while (a == NAMEMATCH_NONE) {
|
---|
| 89 | fprintf(stderr, "%s file name \"%s\" %s.\n",
|
---|
| 90 | isprimary ? "Long" : "Short", name, reasons[reason]);
|
---|
| 91 | fprintf(stderr,
|
---|
| 92 | "a)utorename A)utorename-all r)ename R)ename-all ");
|
---|
| 93 | if(!no_overwrite)
|
---|
| 94 | fprintf(stderr,"o)verwrite O)verwrite-all");
|
---|
| 95 | fprintf(stderr,
|
---|
| 96 | "\ns)kip S)kip-all q)uit (aArR");
|
---|
| 97 | if(!no_overwrite)
|
---|
| 98 | fprintf(stderr,"oO");
|
---|
| 99 | fprintf(stderr,"sSq): ");
|
---|
| 100 | fflush(stderr);
|
---|
| 101 | fflush(opentty(1));
|
---|
| 102 | if (mtools_raw_tty) {
|
---|
| 103 | int rep;
|
---|
| 104 | rep = fgetc(opentty(1));
|
---|
| 105 | fputs("\n", stderr);
|
---|
| 106 | if(rep == EOF)
|
---|
| 107 | ans[0] = 'q';
|
---|
| 108 | else
|
---|
| 109 | ans[0] = rep;
|
---|
| 110 | } else {
|
---|
| 111 | fgets(ans, 9, opentty(0));
|
---|
| 112 | }
|
---|
| 113 | perm = isupper((unsigned char)ans[0]);
|
---|
| 114 | switch(tolower((unsigned char)ans[0])) {
|
---|
| 115 | case 'a':
|
---|
| 116 | a = NAMEMATCH_AUTORENAME;
|
---|
| 117 | break;
|
---|
| 118 | case 'r':
|
---|
| 119 | if(isprimary)
|
---|
| 120 | a = NAMEMATCH_PRENAME;
|
---|
| 121 | else
|
---|
| 122 | a = NAMEMATCH_RENAME;
|
---|
| 123 | break;
|
---|
| 124 | case 'o':
|
---|
| 125 | if(no_overwrite)
|
---|
| 126 | continue;
|
---|
| 127 | a = NAMEMATCH_OVERWRITE;
|
---|
| 128 | break;
|
---|
| 129 | case 's':
|
---|
| 130 | a = NAMEMATCH_SKIP;
|
---|
| 131 | break;
|
---|
| 132 | case 'q':
|
---|
| 133 | perm = 0;
|
---|
| 134 | a = NAMEMATCH_QUIT;
|
---|
| 135 | break;
|
---|
| 136 | default:
|
---|
| 137 | perm = 0;
|
---|
| 138 | }
|
---|
| 139 | }
|
---|
| 140 |
|
---|
| 141 | /* Keep track of this action in case this file collides again */
|
---|
| 142 | ch->action[isprimary] = a;
|
---|
| 143 | if (perm)
|
---|
| 144 | ch->namematch_default[isprimary] = a;
|
---|
| 145 |
|
---|
| 146 | /* if we were asked to overwrite be careful. We can't set the action
|
---|
| 147 | * to overwrite, else we get won't get a chance to specify another
|
---|
| 148 | * action, should overwrite fail. Indeed, we'll be caught in an
|
---|
| 149 | * infinite loop because overwrite will fail the same way for the
|
---|
| 150 | * second time */
|
---|
| 151 | if(a == NAMEMATCH_OVERWRITE)
|
---|
| 152 | ch->action[isprimary] = NAMEMATCH_NONE;
|
---|
| 153 | return a;
|
---|
| 154 | }
|
---|
| 155 |
|
---|
| 156 | /* Returns:
|
---|
| 157 | * 2 if file is to be overwritten
|
---|
| 158 | * 1 if file was renamed
|
---|
| 159 | * 0 if it was skipped
|
---|
| 160 | *
|
---|
| 161 | * If a short name is involved, handle conversion between the 11-character
|
---|
| 162 | * fixed-length record DOS name and a literal null-terminated name (e.g.
|
---|
| 163 | * "COMMAND COM" (no null) <-> "COMMAND.COM" (null terminated)).
|
---|
| 164 | *
|
---|
| 165 | * Also, immediately copy the original name so that messages can use it.
|
---|
| 166 | */
|
---|
| 167 | static inline clash_action process_namematch(char *name,
|
---|
| 168 | char *longname,
|
---|
| 169 | int isprimary,
|
---|
| 170 | ClashHandling_t *ch,
|
---|
| 171 | int no_overwrite,
|
---|
| 172 | int reason)
|
---|
| 173 | {
|
---|
| 174 | clash_action action;
|
---|
| 175 |
|
---|
| 176 | #if 0
|
---|
| 177 | fprintf(stderr,
|
---|
| 178 | "process_namematch: name=%s, default_action=%d, ask=%d.\n",
|
---|
| 179 | name, default_action, ch->ask);
|
---|
| 180 | #endif
|
---|
| 181 |
|
---|
| 182 | action = ask_namematch(name, isprimary, ch, no_overwrite, reason);
|
---|
| 183 |
|
---|
| 184 | switch(action){
|
---|
| 185 | case NAMEMATCH_QUIT:
|
---|
| 186 | got_signal = 1;
|
---|
| 187 | return NAMEMATCH_SKIP;
|
---|
| 188 | case NAMEMATCH_SKIP:
|
---|
| 189 | return NAMEMATCH_SKIP;
|
---|
| 190 | case NAMEMATCH_RENAME:
|
---|
| 191 | case NAMEMATCH_PRENAME:
|
---|
| 192 | /* We need to rename the file now. This means we must pass
|
---|
| 193 | * back through the loop, a) ensuring there isn't a potential
|
---|
| 194 | * new name collision, and b) finding a big enough VSE.
|
---|
| 195 | * Change the name, so that it won't collide again.
|
---|
| 196 | */
|
---|
| 197 | ask_rename(ch, longname, isprimary, name);
|
---|
| 198 | return action;
|
---|
| 199 | case NAMEMATCH_AUTORENAME:
|
---|
| 200 | /* Very similar to NAMEMATCH_RENAME, except that we need to
|
---|
| 201 | * first generate the name.
|
---|
| 202 | * TODO: Remember previous name so we don't
|
---|
| 203 | * keep trying the same one.
|
---|
| 204 | */
|
---|
| 205 | if (isprimary) {
|
---|
| 206 | autorename_long(name, 1);
|
---|
| 207 | return NAMEMATCH_PRENAME;
|
---|
| 208 | } else {
|
---|
| 209 | autorename_short(name, 1);
|
---|
| 210 | return NAMEMATCH_RENAME;
|
---|
| 211 | }
|
---|
| 212 | case NAMEMATCH_OVERWRITE:
|
---|
| 213 | if(no_overwrite)
|
---|
| 214 | return NAMEMATCH_SKIP;
|
---|
| 215 | else
|
---|
| 216 | return NAMEMATCH_OVERWRITE;
|
---|
| 217 | default:
|
---|
| 218 | return NAMEMATCH_NONE;
|
---|
| 219 | }
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 |
|
---|
| 223 | static void clear_scan(char *longname, int use_longname, struct scan_state *s)
|
---|
| 224 | {
|
---|
| 225 | s->shortmatch = s->longmatch = s->slot = -1;
|
---|
| 226 | s->free_end = s->got_slots = s->free_start = 0;
|
---|
| 227 |
|
---|
| 228 | if (use_longname & 1)
|
---|
| 229 | s->size_needed = 2 + (strlen(longname)/VSE_NAMELEN);
|
---|
| 230 | else
|
---|
| 231 | s->size_needed = 1;
|
---|
| 232 | }
|
---|
| 233 |
|
---|
| 234 |
|
---|
| 235 | static int contains_illegals(const char *string, const char *illegals)
|
---|
| 236 | {
|
---|
| 237 | for(; *string ; string++)
|
---|
| 238 | if((*string < ' ' && *string != '\005' && !(*string & 0x80)) ||
|
---|
| 239 | strchr(illegals, *string))
|
---|
| 240 | return 1;
|
---|
| 241 | return 0;
|
---|
| 242 | }
|
---|
| 243 |
|
---|
| 244 | static int is_reserved(char *ans, int islong)
|
---|
| 245 | {
|
---|
| 246 | int i;
|
---|
| 247 | static const char *dev3[] = {"CON", "AUX", "PRN", "NUL", " "};
|
---|
| 248 | static const char *dev4[] = {"COM", "LPT" };
|
---|
| 249 |
|
---|
| 250 | for (i = 0; i < sizeof(dev3)/sizeof(*dev3); i++)
|
---|
| 251 | if (!strncasecmp(ans, dev3[i], 3) &&
|
---|
| 252 | ((islong && !ans[3]) ||
|
---|
| 253 | (!islong && !strncmp(ans+3," ",5))))
|
---|
| 254 | return 1;
|
---|
| 255 |
|
---|
| 256 | for (i = 0; i < sizeof(dev4)/sizeof(*dev4); i++)
|
---|
| 257 | if (!strncasecmp(ans, dev4[i], 3) &&
|
---|
| 258 | (ans[3] >= '1' && ans[3] <= '4') &&
|
---|
| 259 | ((islong && !ans[4]) ||
|
---|
| 260 | (!islong && !strncmp(ans+4," ",4))))
|
---|
| 261 | return 1;
|
---|
| 262 |
|
---|
| 263 | return 0;
|
---|
| 264 | }
|
---|
| 265 |
|
---|
| 266 | static inline clash_action get_slots(Stream_t *Dir,
|
---|
| 267 | char *dosname, char *longname,
|
---|
| 268 | struct scan_state *ssp,
|
---|
| 269 | ClashHandling_t *ch)
|
---|
| 270 | {
|
---|
| 271 | int error;
|
---|
| 272 | clash_action ret;
|
---|
| 273 | int match=0;
|
---|
| 274 | direntry_t entry;
|
---|
| 275 | int isprimary;
|
---|
| 276 | int no_overwrite;
|
---|
| 277 | int reason;
|
---|
| 278 | int pessimisticShortRename;
|
---|
| 279 |
|
---|
| 280 | pessimisticShortRename = (ch->action[0] == NAMEMATCH_AUTORENAME);
|
---|
| 281 |
|
---|
| 282 | entry.Dir = Dir;
|
---|
| 283 | no_overwrite = 1;
|
---|
| 284 | if((is_reserved(longname,1)) ||
|
---|
| 285 | longname[strspn(longname,". ")] == '\0'){
|
---|
| 286 | reason = RESERVED;
|
---|
| 287 | isprimary = 1;
|
---|
| 288 | } else if(contains_illegals(longname,long_illegals)) {
|
---|
| 289 | reason = ILLEGALS;
|
---|
| 290 | isprimary = 1;
|
---|
| 291 | } else if(is_reserved(dosname,0)) {
|
---|
| 292 | reason = RESERVED;
|
---|
| 293 | ch->use_longname = 1;
|
---|
| 294 | isprimary = 0;
|
---|
| 295 | } else if(contains_illegals(dosname,short_illegals)) {
|
---|
| 296 | reason = ILLEGALS;
|
---|
| 297 | ch->use_longname = 1;
|
---|
| 298 | isprimary = 0;
|
---|
| 299 | } else {
|
---|
| 300 | reason = EXISTS;
|
---|
| 301 | clear_scan(longname, ch->use_longname, ssp);
|
---|
| 302 | switch (lookupForInsert(Dir, dosname, longname, ssp,
|
---|
| 303 | ch->ignore_entry,
|
---|
| 304 | ch->source_entry,
|
---|
| 305 | pessimisticShortRename &&
|
---|
| 306 | ch->use_longname)) {
|
---|
| 307 | case -1:
|
---|
| 308 | return NAMEMATCH_ERROR;
|
---|
| 309 |
|
---|
| 310 | case 0:
|
---|
| 311 | return NAMEMATCH_SKIP;
|
---|
| 312 | /* Single-file error error or skip request */
|
---|
| 313 |
|
---|
| 314 | case 5:
|
---|
| 315 | return NAMEMATCH_GREW;
|
---|
| 316 | /* Grew directory, try again */
|
---|
| 317 |
|
---|
| 318 | case 6:
|
---|
| 319 | return NAMEMATCH_SUCCESS; /* Success */
|
---|
| 320 | }
|
---|
| 321 | match = -2;
|
---|
| 322 | if (ssp->longmatch > -1) {
|
---|
| 323 | /* Primary Long Name Match */
|
---|
| 324 | #ifdef debug
|
---|
| 325 | fprintf(stderr,
|
---|
| 326 | "Got longmatch=%d for name %s.\n",
|
---|
| 327 | longmatch, longname);
|
---|
| 328 | #endif
|
---|
| 329 | match = ssp->longmatch;
|
---|
| 330 | isprimary = 1;
|
---|
| 331 | } else if ((ch->use_longname & 1) && (ssp->shortmatch != -1)) {
|
---|
| 332 | /* Secondary Short Name Match */
|
---|
| 333 | #ifdef debug
|
---|
| 334 | fprintf(stderr,
|
---|
| 335 | "Got secondary short name match for name %s.\n",
|
---|
| 336 | longname);
|
---|
| 337 | #endif
|
---|
| 338 |
|
---|
| 339 | match = ssp->shortmatch;
|
---|
| 340 | isprimary = 0;
|
---|
| 341 | } else if (ssp->shortmatch >= 0) {
|
---|
| 342 | /* Primary Short Name Match */
|
---|
| 343 | #ifdef debug
|
---|
| 344 | fprintf(stderr,
|
---|
| 345 | "Got primary short name match for name %s.\n",
|
---|
| 346 | longname);
|
---|
| 347 | #endif
|
---|
| 348 | match = ssp->shortmatch;
|
---|
| 349 | isprimary = 1;
|
---|
| 350 | } else
|
---|
| 351 | return NAMEMATCH_RENAME;
|
---|
| 352 |
|
---|
| 353 | if(match > -1) {
|
---|
| 354 | entry.entry = match;
|
---|
| 355 | dir_read(&entry, &error);
|
---|
| 356 | if (error)
|
---|
| 357 | return NAMEMATCH_ERROR;
|
---|
| 358 | /* if we can't overwrite, don't propose it */
|
---|
| 359 | no_overwrite = (match == ch->source || IS_DIR(&entry));
|
---|
| 360 | }
|
---|
| 361 | }
|
---|
| 362 | ret = process_namematch(isprimary ? longname : dosname, longname,
|
---|
| 363 | isprimary, ch, no_overwrite, reason);
|
---|
| 364 |
|
---|
| 365 | if (ret == NAMEMATCH_OVERWRITE && match > -1){
|
---|
| 366 | if((entry.dir.attr & 0x5) &&
|
---|
| 367 | (ask_confirmation("file is read only, overwrite anyway (y/n) ? ",0,0)))
|
---|
| 368 | return NAMEMATCH_RENAME;
|
---|
| 369 |
|
---|
| 370 | /* Free up the file to be overwritten */
|
---|
| 371 | if(fatFreeWithDirentry(&entry))
|
---|
| 372 | return NAMEMATCH_ERROR;
|
---|
| 373 |
|
---|
| 374 | #if 0
|
---|
| 375 | if(isprimary &&
|
---|
| 376 | match - ssp->match_free + 1 >= ssp->size_needed){
|
---|
| 377 | /* reuse old entry and old short name for overwrite */
|
---|
| 378 | ssp->free_start = match - ssp->size_needed + 1;
|
---|
| 379 | ssp->free_size = ssp->size_needed;
|
---|
| 380 | ssp->slot = match;
|
---|
| 381 | ssp->got_slots = 1;
|
---|
| 382 | strncpy(dosname, dir.name, 3);
|
---|
| 383 | strncpy(dosname + 8, dir.ext, 3);
|
---|
| 384 | return ret;
|
---|
| 385 | } else
|
---|
| 386 | #endif
|
---|
| 387 | {
|
---|
| 388 | entry.dir.name[0] = DELMARK;
|
---|
| 389 | dir_write(&entry);
|
---|
| 390 | return NAMEMATCH_RENAME;
|
---|
| 391 | }
|
---|
| 392 | }
|
---|
| 393 |
|
---|
| 394 | return ret;
|
---|
| 395 | }
|
---|
| 396 |
|
---|
| 397 |
|
---|
| 398 | static inline int write_slots(Stream_t *Dir,
|
---|
| 399 | char *dosname,
|
---|
| 400 | char *longname,
|
---|
| 401 | struct scan_state *ssp,
|
---|
| 402 | write_data_callback *cb,
|
---|
| 403 | void *arg,
|
---|
| 404 | int Case)
|
---|
| 405 | {
|
---|
| 406 | direntry_t entry;
|
---|
| 407 |
|
---|
| 408 | /* write the file */
|
---|
| 409 | if (fat_error(Dir))
|
---|
| 410 | return 0;
|
---|
| 411 |
|
---|
| 412 | entry.Dir = Dir;
|
---|
| 413 | entry.entry = ssp->slot;
|
---|
| 414 | strncpy(entry.name, longname, sizeof(entry.name)-1);
|
---|
| 415 | entry.name[sizeof(entry.name)-1]='\0';
|
---|
| 416 | entry.dir.Case = Case & (EXTCASE | BASECASE);
|
---|
| 417 | if (cb(dosname, longname, arg, &entry) >= 0) {
|
---|
| 418 | if ((ssp->size_needed > 1) &&
|
---|
| 419 | (ssp->free_end - ssp->free_start >= ssp->size_needed)) {
|
---|
| 420 | ssp->slot = write_vfat(Dir, dosname, longname,
|
---|
| 421 | ssp->free_start, &entry);
|
---|
| 422 | } else {
|
---|
| 423 | ssp->size_needed = 1;
|
---|
| 424 | write_vfat(Dir, dosname, 0,
|
---|
| 425 | ssp->free_start, &entry);
|
---|
| 426 | }
|
---|
| 427 | /* clear_vses(Dir, ssp->free_start + ssp->size_needed,
|
---|
| 428 | ssp->free_end); */
|
---|
| 429 | } else
|
---|
| 430 | return 0;
|
---|
| 431 |
|
---|
| 432 | return 1; /* Successfully wrote the file */
|
---|
| 433 | }
|
---|
| 434 |
|
---|
| 435 | static void stripspaces(char *name)
|
---|
| 436 | {
|
---|
| 437 | char *p,*non_space;
|
---|
| 438 |
|
---|
| 439 | non_space = name;
|
---|
| 440 | for(p=name; *p; p++)
|
---|
| 441 | if (*p != ' ')
|
---|
| 442 | non_space = p;
|
---|
| 443 | if(name[0])
|
---|
| 444 | non_space[1] = '\0';
|
---|
| 445 | }
|
---|
| 446 |
|
---|
| 447 |
|
---|
| 448 | int _mwrite_one(Stream_t *Dir,
|
---|
| 449 | char *argname,
|
---|
| 450 | char *shortname,
|
---|
| 451 | write_data_callback *cb,
|
---|
| 452 | void *arg,
|
---|
| 453 | ClashHandling_t *ch)
|
---|
| 454 | {
|
---|
| 455 | char longname[VBUFSIZE];
|
---|
| 456 | const char *dstname;
|
---|
| 457 | char dosname[13];
|
---|
| 458 | int expanded;
|
---|
| 459 | struct scan_state scan;
|
---|
| 460 | clash_action ret;
|
---|
| 461 |
|
---|
| 462 | expanded = 0;
|
---|
| 463 |
|
---|
| 464 | if(isSpecial(argname)) {
|
---|
| 465 | fprintf(stderr, "Cannot create entry named . or ..\n");
|
---|
| 466 | return -1;
|
---|
| 467 | }
|
---|
| 468 |
|
---|
| 469 | if(ch->name_converter == dos_name) {
|
---|
| 470 | if(shortname)
|
---|
| 471 | stripspaces(shortname);
|
---|
| 472 | if(argname)
|
---|
| 473 | stripspaces(argname);
|
---|
| 474 | }
|
---|
| 475 |
|
---|
| 476 | if(shortname){
|
---|
| 477 | ch->name_converter(shortname,0, &ch->use_longname, dosname);
|
---|
| 478 | if(ch->use_longname & 1){
|
---|
| 479 | /* short name mangled, treat it as a long name */
|
---|
| 480 | argname = shortname;
|
---|
| 481 | shortname = 0;
|
---|
| 482 | }
|
---|
| 483 | }
|
---|
| 484 |
|
---|
| 485 | /* Skip drive letter */
|
---|
| 486 | dstname = skip_drive(argname);
|
---|
| 487 |
|
---|
| 488 | /* Copy original argument dstname to working value longname */
|
---|
| 489 | strncpy(longname, dstname, VBUFSIZE-1);
|
---|
| 490 |
|
---|
| 491 | if(shortname) {
|
---|
| 492 | ch->name_converter(shortname,0, &ch->use_longname, dosname);
|
---|
| 493 | if(strcmp(shortname, longname))
|
---|
| 494 | ch->use_longname |= 1;
|
---|
| 495 | } else
|
---|
| 496 | ch->name_converter(longname,0, &ch->use_longname, dosname);
|
---|
| 497 |
|
---|
| 498 | ch->action[0] = ch->namematch_default[0];
|
---|
| 499 | ch->action[1] = ch->namematch_default[1];
|
---|
| 500 |
|
---|
| 501 | while (1) {
|
---|
| 502 | switch((ret=get_slots(Dir, dosname, longname,
|
---|
| 503 | &scan, ch))){
|
---|
| 504 | case NAMEMATCH_ERROR:
|
---|
| 505 | return -1; /* Non-file-specific error,
|
---|
| 506 | * quit */
|
---|
| 507 |
|
---|
| 508 | case NAMEMATCH_SKIP:
|
---|
| 509 | return -1; /* Skip file (user request or
|
---|
| 510 | * error) */
|
---|
| 511 |
|
---|
| 512 | case NAMEMATCH_PRENAME:
|
---|
| 513 | ch->name_converter(longname,0,
|
---|
| 514 | &ch->use_longname, dosname);
|
---|
| 515 | continue;
|
---|
| 516 | case NAMEMATCH_RENAME:
|
---|
| 517 | continue; /* Renamed file, loop again */
|
---|
| 518 |
|
---|
| 519 | case NAMEMATCH_GREW:
|
---|
| 520 | /* No collision, and not enough slots.
|
---|
| 521 | * Try to grow the directory
|
---|
| 522 | */
|
---|
| 523 | if (expanded) { /* Already tried this
|
---|
| 524 | * once, no good */
|
---|
| 525 | fprintf(stderr,
|
---|
| 526 | "%s: No directory slots\n",
|
---|
| 527 | progname);
|
---|
| 528 | return -1;
|
---|
| 529 | }
|
---|
| 530 | expanded = 1;
|
---|
| 531 |
|
---|
| 532 | if (dir_grow(Dir, scan.max_entry))
|
---|
| 533 | return -1;
|
---|
| 534 | continue;
|
---|
| 535 | case NAMEMATCH_OVERWRITE:
|
---|
| 536 | case NAMEMATCH_SUCCESS:
|
---|
| 537 | return write_slots(Dir, dosname, longname,
|
---|
| 538 | &scan, cb, arg,
|
---|
| 539 | ch->use_longname);
|
---|
| 540 | default:
|
---|
| 541 | fprintf(stderr,
|
---|
| 542 | "Internal error: clash_action=%d\n",
|
---|
| 543 | ret);
|
---|
| 544 | return -1;
|
---|
| 545 | }
|
---|
| 546 |
|
---|
| 547 | }
|
---|
| 548 | }
|
---|
| 549 |
|
---|
| 550 | int mwrite_one(Stream_t *Dir,
|
---|
| 551 | const char *_argname,
|
---|
| 552 | const char *_shortname,
|
---|
| 553 | write_data_callback *cb,
|
---|
| 554 | void *arg,
|
---|
| 555 | ClashHandling_t *ch)
|
---|
| 556 | {
|
---|
| 557 | char *argname;
|
---|
| 558 | char *shortname;
|
---|
| 559 | int ret;
|
---|
| 560 |
|
---|
| 561 | if(_argname)
|
---|
| 562 | argname = strdup(_argname);
|
---|
| 563 | else
|
---|
| 564 | argname = 0;
|
---|
| 565 | if(_shortname)
|
---|
| 566 | shortname = strdup(_shortname);
|
---|
| 567 | else
|
---|
| 568 | shortname = 0;
|
---|
| 569 | ret = _mwrite_one(Dir, argname, shortname, cb, arg, ch);
|
---|
| 570 | if(argname)
|
---|
| 571 | free(argname);
|
---|
| 572 | if(shortname)
|
---|
| 573 | free(shortname);
|
---|
| 574 | return ret;
|
---|
| 575 | }
|
---|
| 576 |
|
---|
| 577 | void init_clash_handling(ClashHandling_t *ch)
|
---|
| 578 | {
|
---|
| 579 | ch->ignore_entry = -1;
|
---|
| 580 | ch->source_entry = -2;
|
---|
| 581 | ch->nowarn = 0; /*Don't ask, just do default action if name collision */
|
---|
| 582 | ch->namematch_default[0] = NAMEMATCH_AUTORENAME;
|
---|
| 583 | ch->namematch_default[1] = NAMEMATCH_NONE;
|
---|
| 584 | ch->name_converter = dos_name; /* changed by mlabel */
|
---|
| 585 | ch->source = -2;
|
---|
| 586 | }
|
---|
| 587 |
|
---|
| 588 | int handle_clash_options(ClashHandling_t *ch, char c)
|
---|
| 589 | {
|
---|
| 590 | int isprimary;
|
---|
| 591 | if(isupper(c))
|
---|
| 592 | isprimary = 0;
|
---|
| 593 | else
|
---|
| 594 | isprimary = 1;
|
---|
| 595 | c = tolower(c);
|
---|
| 596 | switch(c) {
|
---|
| 597 | case 'o':
|
---|
| 598 | /* Overwrite if primary name matches */
|
---|
| 599 | ch->namematch_default[isprimary] = NAMEMATCH_OVERWRITE;
|
---|
| 600 | return 0;
|
---|
| 601 | case 'r':
|
---|
| 602 | /* Rename primary name interactively */
|
---|
| 603 | ch->namematch_default[isprimary] = NAMEMATCH_RENAME;
|
---|
| 604 | return 0;
|
---|
| 605 | case 's':
|
---|
| 606 | /* Skip file if primary name collides */
|
---|
| 607 | ch->namematch_default[isprimary] = NAMEMATCH_SKIP;
|
---|
| 608 | return 0;
|
---|
| 609 | case 'm':
|
---|
| 610 | ch->namematch_default[isprimary] = NAMEMATCH_NONE;
|
---|
| 611 | return 0;
|
---|
| 612 | case 'a':
|
---|
| 613 | ch->namematch_default[isprimary] = NAMEMATCH_AUTORENAME;
|
---|
| 614 | return 0;
|
---|
| 615 | default:
|
---|
| 616 | return -1;
|
---|
| 617 | }
|
---|
| 618 | }
|
---|