README.md | 1 + nnn.c | 49 ++++++++++++++++++++++++------------------------- diff --git a/README.md b/README.md index 4f0f72d9f3696c9d2b12b686e8b5022fa625f6cc..39bc8f191b69e89bd60e8693a89c996155bb4f27 100644 --- a/README.md +++ b/README.md @@ -289,6 +289,7 @@ | `*` | Executable | | | | Fifo | | `=` | Socket | | `@` | Symbolic Link | +| `@/` | Symbolic Link to directory | | `b` | Block Device | | `c` | Character Device | diff --git a/nnn.c b/nnn.c index 0e5e5ea722c7ecc23fd36287dbb2692fccb25433..1016d66bbc2c3cbc35b661c77ee7b8d91560cbea 100644 --- a/nnn.c +++ b/nnn.c @@ -160,6 +160,7 @@ #define NAMEBUF_INCR 0x1000 /* 64 dir entries at a time, avg. 64 chars per filename = 64*64B = 4KB */ #define DESCRIPTOR_LEN 32 #define _ALIGNMENT 0x10 #define _ALIGNMENT_MASK 0xF +#define SYMLINK_TO_DIR 0x1 /* Macros to define process spawn behaviour as flags */ #define F_NONE 0x00 /* no flag set */ @@ -202,6 +203,7 @@ /* TYPE DEFINITIONS */ typedef unsigned long ulong; typedef unsigned int uint; typedef unsigned char uchar; +typedef unsigned short ushort; /* STRUCTURES */ @@ -212,7 +214,8 @@ time_t t; off_t size; blkcnt_t blocks; /* number of 512B blocks allocated */ mode_t mode; - uint nlen; /* Length of file name; can be uchar (< NAME_MAX + 1) */ + ushort nlen; /* Length of file name; can be uchar (< NAME_MAX + 1) */ + uchar flags; /* Flags specific to the file */ } __attribute__ ((packed, aligned(_ALIGNMENT))) *pEntry; /* Bookmark */ @@ -1560,9 +1563,12 @@ if (cfg.blkorder) printw("%s%-16.16s %8.8s/ %s/\n", CURSYM(sel), buf, coolsize(ent->blocks << 9), pname); else printw("%s%-16.16s / %s/\n", CURSYM(sel), buf, pname); - } else if (S_ISLNK(ent->mode)) - printw("%s%-16.16s @ %s@\n", CURSYM(sel), buf, pname); - else if (S_ISSOCK(ent->mode)) + } else if (S_ISLNK(ent->mode)) { + if (ent->flags & SYMLINK_TO_DIR) + printw("%s%-16.16s @/ %s@\n", CURSYM(sel), buf, pname); + else + printw("%s%-16.16s @ %s@\n", CURSYM(sel), buf, pname); + } else if (S_ISSOCK(ent->mode)) printw("%s%-16.16s = %s=\n", CURSYM(sel), buf, pname); else if (S_ISFIFO(ent->mode)) printw("%s%-16.16s | %s|\n", CURSYM(sel), buf, pname); @@ -1752,19 +1758,6 @@ return grp->gr_name; } -static bool -istgtdir(const char *tgtpath) -{ - if (tgtpath) { - struct stat tgtsb; - int r = stat(tgtpath, &tgtsb); - if ((r == 0) && (tgtsb.st_mode & S_IFMT) == S_IFDIR) - return TRUE; - } - - return FALSE; -} - /* * Follows the stat(1) output closely */ @@ -1785,19 +1778,16 @@ /* Show file name or 'symlink' -> 'target' */ if (perms[0] == 'l') { /* Note that MAX_CMD_LEN > PATH_MAX */ - char *tgt = realpath(fpath, g_buf); - if (tgt) { - char ch[] = {'\'', '\0', '\0'}; - if (istgtdir(g_buf)) { - ch[1] = ch[0]; - ch[0] = '/'; - } + ssize_t len = readlink(fpath, g_buf, MAX_CMD_LEN); + + if (len != -1) { + g_buf[len] = '\0'; /* * We pass g_buf but unescape() operates on g_buf too! * Read the API notes for information on how this works. */ - dprintf(fd, " -> '%s%s", unescape(g_buf, 0), ch); + dprintf(fd, " -> '%s'", unescape(g_buf, 0)); } } @@ -2209,6 +2199,15 @@ dir_blocks += dentp->blocks; ++num_files; } } + + /* Flag if this is a symlink to a dir */ + if (S_ISLNK(sb.st_mode)) + if (!fstatat(fd, namep, &sb, 0)) { + if (S_ISDIR(sb.st_mode)) + dentp->flags |= SYMLINK_TO_DIR; + else + dentp->flags &= ~SYMLINK_TO_DIR; + } ++n; }