1 /* $OpenBSD: dired.c,v 1.71 2015/03/19 21:48:05 bcallah Exp $ */ 2 3 /* This file is in the public domain. */ 4 5 /* dired module for mg 2a 6 * by Robert A. Larson 7 */ 8 9 #include <sys/queue.h> 10 #include <sys/resource.h> 11 #include <sys/stat.h> 12 #include <sys/time.h> 13 #include <sys/types.h> 14 #include <sys/wait.h> 15 #include <ctype.h> 16 #include <err.h> 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <libgen.h> 20 #include <limits.h> 21 #include <signal.h> 22 #include <stdarg.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "def.h" 29 #include "funmap.h" 30 #include "kbd.h" 31 32 void dired_init(void); 33 static int dired(int, int); 34 static int d_otherwindow(int, int); 35 static int d_undel(int, int); 36 static int d_undelbak(int, int); 37 static int d_findfile(int, int); 38 static int d_ffotherwindow(int, int); 39 static int d_expunge(int, int); 40 static int d_copy(int, int); 41 static int d_del(int, int); 42 static int d_rename(int, int); 43 static int d_exec(int, struct buffer *, const char *, const char *, ...); 44 static int d_shell_command(int, int); 45 static int d_create_directory(int, int); 46 static int d_makename(struct line *, char *, size_t); 47 static int d_warpdot(struct line *, int *); 48 static int d_forwpage(int, int); 49 static int d_backpage(int, int); 50 static int d_forwline(int, int); 51 static int d_backline(int, int); 52 static int d_killbuffer_cmd(int, int); 53 static int d_refreshbuffer(int, int); 54 static void reaper(int); 55 static struct buffer *refreshbuffer(struct buffer *); 56 57 extern struct keymap_s helpmap, cXmap, metamap; 58 59 static PF dirednul[] = { 60 setmark, /* ^@ */ 61 gotobol, /* ^A */ 62 backchar, /* ^B */ 63 rescan, /* ^C */ 64 d_del, /* ^D */ 65 gotoeol, /* ^E */ 66 forwchar, /* ^F */ 67 ctrlg, /* ^G */ 68 NULL, /* ^H */ 69 }; 70 71 static PF diredcl[] = { 72 reposition, /* ^L */ 73 d_findfile, /* ^M */ 74 d_forwline, /* ^N */ 75 rescan, /* ^O */ 76 d_backline, /* ^P */ 77 rescan, /* ^Q */ 78 backisearch, /* ^R */ 79 forwisearch, /* ^S */ 80 rescan, /* ^T */ 81 universal_argument, /* ^U */ 82 d_forwpage, /* ^V */ 83 rescan, /* ^W */ 84 NULL /* ^X */ 85 }; 86 87 static PF diredcz[] = { 88 spawncli, /* ^Z */ 89 NULL, /* esc */ 90 rescan, /* ^\ */ 91 rescan, /* ^] */ 92 rescan, /* ^^ */ 93 rescan, /* ^_ */ 94 d_forwline, /* SP */ 95 d_shell_command, /* ! */ 96 rescan, /* " */ 97 rescan, /* # */ 98 rescan, /* $ */ 99 rescan, /* % */ 100 rescan, /* & */ 101 rescan, /* ' */ 102 rescan, /* ( */ 103 rescan, /* ) */ 104 rescan, /* * */ 105 d_create_directory /* + */ 106 }; 107 108 static PF diredc[] = { 109 d_copy, /* c */ 110 d_del, /* d */ 111 d_findfile, /* e */ 112 d_findfile, /* f */ 113 d_refreshbuffer /* g */ 114 }; 115 116 static PF diredn[] = { 117 d_forwline, /* n */ 118 d_ffotherwindow, /* o */ 119 d_backline, /* p */ 120 d_killbuffer_cmd, /* q */ 121 d_rename, /* r */ 122 rescan, /* s */ 123 rescan, /* t */ 124 d_undel, /* u */ 125 rescan, /* v */ 126 rescan, /* w */ 127 d_expunge /* x */ 128 }; 129 130 static PF direddl[] = { 131 d_undelbak /* del */ 132 }; 133 134 static PF diredbp[] = { 135 d_backpage /* v */ 136 }; 137 138 static PF dirednull[] = { 139 NULL 140 }; 141 142 static struct KEYMAPE (1) d_backpagemap = { 143 1, 144 1, 145 rescan, 146 { 147 { 148 'v', 'v', diredbp, NULL 149 } 150 } 151 }; 152 153 static struct KEYMAPE (7) diredmap = { 154 7, 155 7, 156 rescan, 157 { 158 { 159 CCHR('@'), CCHR('H'), dirednul, (KEYMAP *) & helpmap 160 }, 161 { 162 CCHR('L'), CCHR('X'), diredcl, (KEYMAP *) & cXmap 163 }, 164 { 165 CCHR('['), CCHR('['), dirednull, (KEYMAP *) & 166 d_backpagemap 167 }, 168 { 169 CCHR('Z'), '+', diredcz, (KEYMAP *) & metamap 170 }, 171 { 172 'c', 'g', diredc, NULL 173 }, 174 { 175 'n', 'x', diredn, NULL 176 }, 177 { 178 CCHR('?'), CCHR('?'), direddl, NULL 179 }, 180 } 181 }; 182 183 void 184 dired_init(void) 185 { 186 funmap_add(dired, "dired"); 187 funmap_add(d_undelbak, "dired-unmark-backward"); 188 funmap_add(d_create_directory, "dired-create-directory"); 189 funmap_add(d_copy, "dired-do-copy"); 190 funmap_add(d_expunge, "dired-do-flagged-delete"); 191 funmap_add(d_findfile, "dired-find-file"); 192 funmap_add(d_ffotherwindow, "dired-find-file-other-window"); 193 funmap_add(d_del, "dired-flag-file-deletion"); 194 funmap_add(d_forwline, "dired-next-line"); 195 funmap_add(d_otherwindow, "dired-other-window"); 196 funmap_add(d_backline, "dired-previous-line"); 197 funmap_add(d_rename, "dired-do-rename"); 198 funmap_add(d_backpage, "dired-scroll-down"); 199 funmap_add(d_forwpage, "dired-scroll-up"); 200 funmap_add(d_undel, "dired-unmark"); 201 funmap_add(d_killbuffer_cmd, "quit-window"); 202 maps_add((KEYMAP *)&diredmap, "dired"); 203 dobindkey(fundamental_map, "dired", "^Xd"); 204 } 205 206 /* ARGSUSED */ 207 int 208 dired(int f, int n) 209 { 210 char dname[NFILEN], *bufp, *slash; 211 struct buffer *bp; 212 213 if (curbp->b_fname[0] != '\0') { 214 (void)strlcpy(dname, curbp->b_fname, sizeof(dname)); 215 if ((slash = strrchr(dname, '/')) != NULL) { 216 *(slash + 1) = '\0'; 217 } 218 } else { 219 if (getcwd(dname, sizeof(dname)) == NULL) 220 dname[0] = '\0'; 221 } 222 223 if ((bufp = eread("Dired: ", dname, NFILEN, 224 EFDEF | EFNEW | EFCR)) == NULL) 225 return (ABORT); 226 if (bufp[0] == '\0') 227 return (FALSE); 228 if ((bp = dired_(bufp)) == NULL) 229 return (FALSE); 230 231 curbp = bp; 232 return (showbuffer(bp, curwp, WFFULL | WFMODE)); 233 } 234 235 /* ARGSUSED */ 236 int 237 d_otherwindow(int f, int n) 238 { 239 char dname[NFILEN], *bufp, *slash; 240 struct buffer *bp; 241 struct mgwin *wp; 242 243 if (curbp->b_fname[0] != '\0') { 244 (void)strlcpy(dname, curbp->b_fname, sizeof(dname)); 245 if ((slash = strrchr(dname, '/')) != NULL) { 246 *(slash + 1) = '\0'; 247 } 248 } else { 249 if (getcwd(dname, sizeof(dname)) == NULL) 250 dname[0] = '\0'; 251 } 252 253 if ((bufp = eread("Dired other window: ", dname, NFILEN, 254 EFDEF | EFNEW | EFCR)) == NULL) 255 return (ABORT); 256 else if (bufp[0] == '\0') 257 return (FALSE); 258 if ((bp = dired_(bufp)) == NULL) 259 return (FALSE); 260 if ((wp = popbuf(bp, WNONE)) == NULL) 261 return (FALSE); 262 curbp = bp; 263 curwp = wp; 264 return (TRUE); 265 } 266 267 /* ARGSUSED */ 268 int 269 d_del(int f, int n) 270 { 271 if (n < 0) 272 return (FALSE); 273 while (n--) { 274 if (llength(curwp->w_dotp) > 0) 275 lputc(curwp->w_dotp, 0, 'D'); 276 if (lforw(curwp->w_dotp) != curbp->b_headp) 277 curwp->w_dotp = lforw(curwp->w_dotp); 278 } 279 curwp->w_rflag |= WFEDIT | WFMOVE; 280 return (d_warpdot(curwp->w_dotp, &curwp->w_doto)); 281 } 282 283 /* ARGSUSED */ 284 int 285 d_undel(int f, int n) 286 { 287 if (n < 0) 288 return (d_undelbak(f, -n)); 289 while (n--) { 290 if (llength(curwp->w_dotp) > 0) 291 lputc(curwp->w_dotp, 0, ' '); 292 if (lforw(curwp->w_dotp) != curbp->b_headp) 293 curwp->w_dotp = lforw(curwp->w_dotp); 294 } 295 curwp->w_rflag |= WFEDIT | WFMOVE; 296 return (d_warpdot(curwp->w_dotp, &curwp->w_doto)); 297 } 298 299 /* ARGSUSED */ 300 int 301 d_undelbak(int f, int n) 302 { 303 if (n < 0) 304 return (d_undel(f, -n)); 305 while (n--) { 306 if (lback(curwp->w_dotp) != curbp->b_headp) 307 curwp->w_dotp = lback(curwp->w_dotp); 308 if (llength(curwp->w_dotp) > 0) 309 lputc(curwp->w_dotp, 0, ' '); 310 } 311 curwp->w_rflag |= WFEDIT | WFMOVE; 312 return (d_warpdot(curwp->w_dotp, &curwp->w_doto)); 313 } 314 315 /* ARGSUSED */ 316 int 317 d_findfile(int f, int n) 318 { 319 struct buffer *bp; 320 int s; 321 char fname[NFILEN]; 322 323 if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT) 324 return (FALSE); 325 if (s == TRUE) 326 bp = dired_(fname); 327 else 328 bp = findbuffer(fname); 329 if (bp == NULL) 330 return (FALSE); 331 curbp = bp; 332 if (showbuffer(bp, curwp, WFFULL) != TRUE) 333 return (FALSE); 334 if (bp->b_fname[0] != 0) 335 return (TRUE); 336 return (readin(fname)); 337 } 338 339 /* ARGSUSED */ 340 int 341 d_ffotherwindow(int f, int n) 342 { 343 char fname[NFILEN]; 344 int s; 345 struct buffer *bp; 346 struct mgwin *wp; 347 348 if ((s = d_makename(curwp->w_dotp, fname, sizeof(fname))) == ABORT) 349 return (FALSE); 350 if ((bp = (s ? dired_(fname) : findbuffer(fname))) == NULL) 351 return (FALSE); 352 if ((wp = popbuf(bp, WNONE)) == NULL) 353 return (FALSE); 354 curbp = bp; 355 curwp = wp; 356 if (bp->b_fname[0] != 0) 357 return (TRUE); /* never true for dired buffers */ 358 return (readin(fname)); 359 } 360 361 /* ARGSUSED */ 362 int 363 d_expunge(int f, int n) 364 { 365 struct line *lp, *nlp; 366 char fname[NFILEN], sname[NFILEN]; 367 368 for (lp = bfirstlp(curbp); lp != curbp->b_headp; lp = nlp) { 369 nlp = lforw(lp); 370 if (llength(lp) && lgetc(lp, 0) == 'D') { 371 switch (d_makename(lp, fname, sizeof(fname))) { 372 case ABORT: 373 dobeep(); 374 ewprintf("Bad line in dired buffer"); 375 return (FALSE); 376 case FALSE: 377 if (unlink(fname) < 0) { 378 (void)xbasename(sname, fname, NFILEN); 379 dobeep(); 380 ewprintf("Could not delete '%s'", sname); 381 return (FALSE); 382 } 383 break; 384 case TRUE: 385 if (rmdir(fname) < 0) { 386 (void)xbasename(sname, fname, NFILEN); 387 dobeep(); 388 ewprintf("Could not delete directory " 389 "'%s'", sname); 390 return (FALSE); 391 } 392 break; 393 } 394 lfree(lp); 395 curwp->w_bufp->b_lines--; 396 curwp->w_rflag |= WFFULL; 397 } 398 } 399 return (TRUE); 400 } 401 402 /* ARGSUSED */ 403 int 404 d_copy(int f, int n) 405 { 406 char frname[NFILEN], toname[NFILEN], sname[NFILEN]; 407 char *topath, *bufp; 408 int ret; 409 size_t off; 410 struct buffer *bp; 411 412 if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) { 413 dobeep(); 414 ewprintf("Not a file"); 415 return (FALSE); 416 } 417 off = strlcpy(toname, curbp->b_fname, sizeof(toname)); 418 if (off >= sizeof(toname) - 1) { /* can't happen, really */ 419 dobeep(); 420 ewprintf("Directory name too long"); 421 return (FALSE); 422 } 423 (void)xbasename(sname, frname, NFILEN); 424 bufp = eread("Copy %s to: ", toname, sizeof(toname), 425 EFDEF | EFNEW | EFCR, sname); 426 if (bufp == NULL) 427 return (ABORT); 428 else if (bufp[0] == '\0') 429 return (FALSE); 430 431 topath = adjustname(toname, TRUE); 432 ret = (copy(frname, topath) >= 0) ? TRUE : FALSE; 433 if (ret != TRUE) 434 return (ret); 435 if ((bp = refreshbuffer(curbp)) == NULL) 436 return (FALSE); 437 return (showbuffer(bp, curwp, WFFULL | WFMODE)); 438 } 439 440 /* ARGSUSED */ 441 int 442 d_rename(int f, int n) 443 { 444 char frname[NFILEN], toname[NFILEN]; 445 char *topath, *bufp; 446 int ret; 447 size_t off; 448 struct buffer *bp; 449 char sname[NFILEN]; 450 451 if (d_makename(curwp->w_dotp, frname, sizeof(frname)) != FALSE) { 452 dobeep(); 453 ewprintf("Not a file"); 454 return (FALSE); 455 } 456 off = strlcpy(toname, curbp->b_fname, sizeof(toname)); 457 if (off >= sizeof(toname) - 1) { /* can't happen, really */ 458 dobeep(); 459 ewprintf("Directory name too long"); 460 return (FALSE); 461 } 462 (void)xbasename(sname, frname, NFILEN); 463 bufp = eread("Rename %s to: ", toname, 464 sizeof(toname), EFDEF | EFNEW | EFCR, sname); 465 if (bufp == NULL) 466 return (ABORT); 467 else if (bufp[0] == '\0') 468 return (FALSE); 469 470 topath = adjustname(toname, TRUE); 471 ret = (rename(frname, topath) >= 0) ? TRUE : FALSE; 472 if (ret != TRUE) 473 return (ret); 474 if ((bp = refreshbuffer(curbp)) == NULL) 475 return (FALSE); 476 return (showbuffer(bp, curwp, WFFULL | WFMODE)); 477 } 478 479 /* ARGSUSED */ 480 void 481 reaper(int signo __attribute__((unused))) 482 { 483 int save_errno = errno, status; 484 485 while (waitpid(-1, &status, WNOHANG) >= 0) 486 ; 487 errno = save_errno; 488 } 489 490 /* 491 * Pipe the currently selected file through a shell command. 492 */ 493 /* ARGSUSED */ 494 int 495 d_shell_command(int f, int n) 496 { 497 char command[512], fname[PATH_MAX], *bufp; 498 struct buffer *bp; 499 struct mgwin *wp; 500 char sname[NFILEN]; 501 502 bp = bfind("*Shell Command Output*", TRUE); 503 if (bclear(bp) != TRUE) 504 return (ABORT); 505 506 if (d_makename(curwp->w_dotp, fname, sizeof(fname)) != FALSE) { 507 dobeep(); 508 ewprintf("bad line"); 509 return (ABORT); 510 } 511 512 command[0] = '\0'; 513 (void)xbasename(sname, fname, NFILEN); 514 bufp = eread("! on %s: ", command, sizeof(command), EFNEW, sname); 515 if (bufp == NULL) 516 return (ABORT); 517 518 if (d_exec(0, bp, fname, "sh", "-c", command, NULL) != TRUE) 519 return (ABORT); 520 521 if ((wp = popbuf(bp, WNONE)) == NULL) 522 return (ABORT); /* XXX - free the buffer?? */ 523 curwp = wp; 524 curbp = wp->w_bufp; 525 return (TRUE); 526 } 527 528 /* 529 * Pipe input file to cmd and insert the command's output in the 530 * given buffer. Each line will be prefixed with the given 531 * number of spaces. 532 */ 533 static int 534 d_exec(int space, struct buffer *bp, const char *input, const char *cmd, ...) 535 { 536 char buf[BUFSIZ]; 537 va_list ap; 538 struct sigaction olda, newa; 539 char **argv = NULL, *cp; 540 FILE *fin; 541 int fds[2] = { -1, -1 }; 542 int infd = -1; 543 int ret = (ABORT), n; 544 pid_t pid; 545 546 if (sigaction(SIGCHLD, NULL, &olda) == -1) 547 return (ABORT); 548 549 /* Find the number of arguments. */ 550 va_start(ap, cmd); 551 for (n = 2; va_arg(ap, char *) != NULL; n++) 552 ; 553 va_end(ap); 554 555 /* Allocate and build the argv. */ 556 if ((argv = calloc(n, sizeof(*argv))) == NULL) { 557 dobeep(); 558 ewprintf("Can't allocate argv : %s", strerror(errno)); 559 goto out; 560 } 561 562 n = 1; 563 argv[0] = (char *)cmd; 564 va_start(ap, cmd); 565 while ((argv[n] = va_arg(ap, char *)) != NULL) 566 n++; 567 va_end(ap); 568 569 if (input == NULL) 570 input = "/dev/null"; 571 572 if ((infd = open(input, O_RDONLY)) == -1) { 573 dobeep(); 574 ewprintf("Can't open input file : %s", strerror(errno)); 575 goto out; 576 } 577 578 if (pipe(fds) == -1) { 579 dobeep(); 580 ewprintf("Can't create pipe : %s", strerror(errno)); 581 goto out; 582 } 583 584 newa.sa_handler = reaper; 585 newa.sa_flags = 0; 586 if (sigaction(SIGCHLD, &newa, NULL) == -1) 587 goto out; 588 589 if ((pid = fork()) == -1) { 590 dobeep(); 591 ewprintf("Can't fork"); 592 goto out; 593 } 594 595 switch (pid) { 596 case 0: /* Child */ 597 close(fds[0]); 598 dup2(infd, STDIN_FILENO); 599 dup2(fds[1], STDOUT_FILENO); 600 dup2(fds[1], STDERR_FILENO); 601 if (execvp(argv[0], argv) == -1) 602 ewprintf("Can't exec %s: %s", argv[0], strerror(errno)); 603 exit(1); 604 break; 605 default: /* Parent */ 606 close(infd); 607 close(fds[1]); 608 infd = fds[1] = -1; 609 if ((fin = fdopen(fds[0], "r")) == NULL) 610 goto out; 611 while (fgets(buf, sizeof(buf), fin) != NULL) { 612 cp = strrchr(buf, '\n'); 613 if (cp == NULL && !feof(fin)) { /* too long a line */ 614 int c; 615 addlinef(bp, "%*s%s...", space, "", buf); 616 while ((c = getc(fin)) != EOF && c != '\n') 617 ; 618 continue; 619 } else if (cp) 620 *cp = '\0'; 621 addlinef(bp, "%*s%s", space, "", buf); 622 } 623 fclose(fin); 624 break; 625 } 626 ret = (TRUE); 627 628 out: 629 if (sigaction(SIGCHLD, &olda, NULL) == -1) 630 ewprintf("Warning, couldn't reset previous signal handler"); 631 if (fds[0] != -1) 632 close(fds[0]); 633 if (fds[1] != -1) 634 close(fds[1]); 635 if (infd != -1) 636 close(infd); 637 if (argv != NULL) 638 free(argv); 639 return ret; 640 } 641 642 /* ARGSUSED */ 643 int 644 d_create_directory(int f, int n) 645 { 646 int ret; 647 struct buffer *bp; 648 649 ret = ask_makedir(); 650 if (ret != TRUE) 651 return(ret); 652 653 if ((bp = refreshbuffer(curbp)) == NULL) 654 return (FALSE); 655 656 return (showbuffer(bp, curwp, WFFULL | WFMODE)); 657 } 658 659 /* ARGSUSED */ 660 int 661 d_killbuffer_cmd(int f, int n) 662 { 663 return(killbuffer_cmd(FFRAND, 0)); 664 } 665 666 int 667 d_refreshbuffer(int f, int n) 668 { 669 struct buffer *bp; 670 671 if ((bp = refreshbuffer(curbp)) == NULL) 672 return (FALSE); 673 674 return (showbuffer(bp, curwp, WFFULL | WFMODE)); 675 } 676 677 struct buffer * 678 refreshbuffer(struct buffer *bp) 679 { 680 char *tmp; 681 682 tmp = strdup(bp->b_fname); 683 if (tmp == NULL) { 684 dobeep(); 685 ewprintf("Out of memory"); 686 return (NULL); 687 } 688 689 killbuffer(bp); 690 691 /* dired_() uses findbuffer() to create new buffer */ 692 if ((bp = dired_(tmp)) == NULL) { 693 free(tmp); 694 return (NULL); 695 } 696 free(tmp); 697 curbp = bp; 698 699 return (bp); 700 } 701 702 static int 703 d_makename(struct line *lp, char *fn, size_t len) 704 { 705 int start, nlen; 706 char *namep; 707 708 if (d_warpdot(lp, &start) == FALSE) 709 return (ABORT); 710 namep = &lp->l_text[start]; 711 nlen = llength(lp) - start; 712 713 if (snprintf(fn, len, "%s%.*s", curbp->b_fname, nlen, namep) >= len) 714 return (ABORT); /* Name is too long. */ 715 716 /* Return TRUE if the entry is a directory. */ 717 return ((lgetc(lp, 2) == 'd') ? TRUE : FALSE); 718 } 719 720 #define NAME_FIELD 9 721 722 static int 723 d_warpdot(struct line *dotp, int *doto) 724 { 725 char *tp = dotp->l_text; 726 int off = 0, field = 0, len; 727 728 /* 729 * Find the byte offset to the (space-delimited) filename 730 * field in formatted ls output. 731 */ 732 len = llength(dotp); 733 while (off < len) { 734 if (tp[off++] == ' ') { 735 if (++field == NAME_FIELD) { 736 *doto = off; 737 return (TRUE); 738 } 739 /* Skip the space. */ 740 while (off < len && tp[off] == ' ') 741 off++; 742 } 743 } 744 /* We didn't find the field. */ 745 *doto = 0; 746 return (FALSE); 747 } 748 749 static int 750 d_forwpage(int f, int n) 751 { 752 forwpage(f | FFRAND, n); 753 return (d_warpdot(curwp->w_dotp, &curwp->w_doto)); 754 } 755 756 static int 757 d_backpage (int f, int n) 758 { 759 backpage(f | FFRAND, n); 760 return (d_warpdot(curwp->w_dotp, &curwp->w_doto)); 761 } 762 763 static int 764 d_forwline (int f, int n) 765 { 766 forwline(f | FFRAND, n); 767 return (d_warpdot(curwp->w_dotp, &curwp->w_doto)); 768 } 769 770 static int 771 d_backline (int f, int n) 772 { 773 backline(f | FFRAND, n); 774 return (d_warpdot(curwp->w_dotp, &curwp->w_doto)); 775 } 776 777 /* 778 * XXX dname needs to have enough place to store an additional '/'. 779 */ 780 struct buffer * 781 dired_(char *dname) 782 { 783 struct buffer *bp; 784 int i; 785 size_t len; 786 787 if ((dname = adjustname(dname, FALSE)) == NULL) { 788 dobeep(); 789 ewprintf("Bad directory name"); 790 return (NULL); 791 } 792 /* this should not be done, instead adjustname() should get a flag */ 793 len = strlen(dname); 794 if (dname[len - 1] != '/') { 795 dname[len++] = '/'; 796 dname[len] = '\0'; 797 } 798 if ((access(dname, R_OK | X_OK)) == -1) { 799 if (errno == EACCES) { 800 dobeep(); 801 ewprintf("Permission denied"); 802 } 803 return (NULL); 804 } 805 if ((bp = findbuffer(dname)) == NULL) { 806 dobeep(); 807 ewprintf("Could not create buffer"); 808 return (NULL); 809 } 810 if (bclear(bp) != TRUE) 811 return (NULL); 812 bp->b_flag |= BFREADONLY | BFIGNDIRTY; 813 814 if ((d_exec(2, bp, NULL, "ls", "-al", dname, NULL)) != TRUE) 815 return (NULL); 816 817 /* Find the line with ".." on it. */ 818 bp->b_dotp = bfirstlp(bp); 819 for (i = 0; i < bp->b_lines; i++) { 820 bp->b_dotp = lforw(bp->b_dotp); 821 if (d_warpdot(bp->b_dotp, &bp->b_doto) == FALSE) 822 continue; 823 if (strcmp(ltext(bp->b_dotp) + bp->b_doto, "..") == 0) 824 break; 825 } 826 827 /* We want dot on the entry right after "..", if possible. */ 828 if (++i < bp->b_lines - 2) 829 bp->b_dotp = lforw(bp->b_dotp); 830 d_warpdot(bp->b_dotp, &bp->b_doto); 831 832 (void)strlcpy(bp->b_fname, dname, sizeof(bp->b_fname)); 833 (void)strlcpy(bp->b_cwd, dname, sizeof(bp->b_cwd)); 834 if ((bp->b_modes[1] = name_mode("dired")) == NULL) { 835 bp->b_modes[0] = name_mode("fundamental"); 836 dobeep(); 837 ewprintf("Could not find mode dired"); 838 return (NULL); 839 } 840 bp->b_nmodes = 1; 841 return (bp); 842 } 843