Makefile
Makefile.in
+ad
cnid2_create
cnid_maint
cnid_index
# Makefile.am for bin/cnid/
EXTRA_DIST = cnid_maint.in cnid2_create.in
+noinst_HEADERS = ad.h
if USE_BDB
+bin_PROGRAMS = ad
bin_SCRIPTS = cnid_maint cnid2_create
-else
-#bin_SCRIPTS =
+
+ad_SOURCES = ad.c ad_util.c \
+ ad_ls.c \
+ ad_cp.c
+
+ad_LDADD = $(top_builddir)/libatalk/libatalk.la
endif
--- /dev/null
+/*
+ $Id: ad.c,v 1.1 2009-09-01 14:28:07 franklahm Exp $
+
+ Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+
+#include <atalk/cnid.h>
+#include <atalk/volinfo.h>
+#include "ad.h"
+
+static void usage_main()
+{
+/*
+ printf("Usage: ad ls|rm|cp|mv|set [file|dir, ...]\n");
+*/
+ printf("Usage: ad ls [file|dir, ...]\n");
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 2) {
+ usage_main();
+ return 1;
+ }
+
+ if (STRCMP(argv[1], ==, "ls"))
+ return ad_ls(argc - 1, argv + 1);
+ else if (STRCMP(argv[1], ==, "cp"))
+ return ad_cp(argc - 1, argv + 1);
+ else {
+ usage_main();
+ return 1;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ $Id: ad.h,v 1.1 2009-09-01 14:28:07 franklahm Exp $
+
+ Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifndef AD_H
+#define AD_H
+
+#include <atalk/volinfo.h>
+
+#define STRCMP(a,b,c) (strcmp(a,c) b 0)
+
+#define DIR_DOT_OR_DOTDOT(a) \
+ ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
+
+typedef struct {
+ struct volinfo volinfo;
+// char *dirname;
+// char *basename;
+// int adflags; /* file:0, dir:ADFLAGS_DIR */
+} afpvol_t;
+
+
+extern int newvol(const char *path, afpvol_t *vol);
+extern void freevol(afpvol_t *vol);
+
+extern int ad_ls(int argc, char **argv);
+extern int ad_cp(int argc, char **argv);
+
+#endif /* AD_H */
--- /dev/null
+/*
+ $Id: ad_cp.c,v 1.1 2009-09-01 14:28:07 franklahm Exp $
+
+ Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <libgen.h>
+
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+#include <atalk/volinfo.h>
+#include <atalk/util.h>
+#include "ad.h"
+
+#define ADv2_DIRNAME ".AppleDouble"
+
+/* options */
+static int cp_R;
+static int cp_L;
+static int cp_P;
+static int cp_n;
+static int cp_p;
+static int cp_v;
+
+static char *netatalk_dirs[] = {
+ ADv2_DIRNAME,
+ ".AppleDB",
+ ".AppleDesktop",
+ NULL
+};
+
+/*
+ Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
+ Returns pointer to name or NULL.
+*/
+static const char *check_netatalk_dirs(const char *name)
+{
+ int c;
+
+ for (c=0; netatalk_dirs[c]; c++) {
+ if ((strcmp(name, netatalk_dirs[c])) == 0)
+ return netatalk_dirs[c];
+ }
+ return NULL;
+}
+
+
+static void usage_cp()
+{
+ printf(
+ "Usage: ad cp [-R [-L | -P]] [-pv] <source_file> <target_file>\n"
+ "Usage: ad cp [-R [-L | -P]] [-pv] <source_file [source_file ...]> <target_directory>\n"
+ );
+}
+
+static int ad_cp_copy(const afpvol_t *srcvol, const afpvol_t *dstvol,
+ char *srcfile, char *dstfile, struct stat *st)
+{
+ printf("copy: '%s' -> '%s'\n", srcfile, dstfile);
+ return 0;
+}
+
+static int ad_cp_r(const afpvol_t *srcvol, const afpvol_t *dstvol, char *srcdir, char *dstdir)
+{
+ int ret = 0, cwd, dirprinted = 0, dirempty;
+ static char srcpath[MAXPATHLEN+1];
+ static char dstpath[MAXPATHLEN+1];
+ char *tmp;
+ DIR *dp;
+ struct dirent *ep;
+ static struct stat st; /* Save some stack space */
+
+ strlcat(srcpath, srcdir, sizeof(srcpath));
+ strlcat(dstpath, dstdir, sizeof(dstpath));
+
+ if ((dp = opendir (srcdir)) == NULL) {
+ perror("Couldn't opendir .");
+ return -1;
+ }
+
+ /* First run: copy files */
+ while ((ep = readdir (dp))) {
+ /* Check if its "." or ".." */
+ if (DIR_DOT_OR_DOTDOT(ep->d_name))
+ continue;
+
+ /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
+ if ((check_netatalk_dirs(ep->d_name)) != NULL)
+ continue;
+
+ if (lstat(ep->d_name, &st) < 0) {
+ perror("Can't stat");
+ return -1;
+ }
+
+ /* Build paths, copy, strip name */
+ strlcat(srcpath, "/", sizeof(srcpath));
+ strlcat(dstpath, "/", sizeof(dstpath));
+ strlcat(srcpath, ep->d_name, sizeof(srcpath));
+ strlcat(dstpath, ep->d_name, sizeof(dstpath));
+
+ ret = ad_cp_copy(srcvol, dstvol, srcpath, dstpath, &st);
+
+ if ((tmp = strrchr(srcpath, '/')))
+ *tmp = 0;
+ if ((tmp = strrchr(dstpath, '/')))
+ *tmp = 0;
+
+ if (ret != 0)
+ goto exit;
+ }
+
+ /* Second run: recurse to dirs */
+ rewinddir(dp);
+ while ((ep = readdir (dp))) {
+ /* Check if its "." or ".." */
+ if (DIR_DOT_OR_DOTDOT(ep->d_name))
+ continue;
+
+ /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
+ if (check_netatalk_dirs(ep->d_name) != NULL)
+ continue;
+
+ if (lstat(ep->d_name, &st) < 0) {
+ perror("Can't stat");
+ return -1;
+ }
+
+ /* Recursion */
+ if (S_ISDIR(st.st_mode)) {
+ strlcat(srcpath, "/", sizeof(srcpath));
+ strlcat(dstpath, "/", sizeof(dstpath));
+ ret = ad_cp_r(srcvol, dstvol, ep->d_name, ep->d_name);
+ }
+ if (ret != 0)
+ goto exit;
+ }
+
+exit:
+ closedir(dp);
+ fchdir(cwd);
+ close(cwd);
+
+ if ((tmp = strrchr(srcpath, '/')))
+ *tmp = 0;
+ if ((tmp = strrchr(dstpath, '/')))
+ *tmp = 0;
+
+ return ret;
+}
+
+int ad_cp(int argc, char **argv)
+{
+ int c, numpaths;
+ afpvol_t srcvvol;
+ struct stat sst;
+ struct stat dst;
+ afpvol_t srcvol;
+ afpvol_t dstvol;
+ char *srcfile = NULL;
+ char *srcdir = NULL;
+ char *dstfile = NULL;
+ char *dstdir = NULL;
+ char path[MAXPATHLEN+1];
+ char *basenametmp;
+
+ while ((c = getopt(argc, argv, ":npvLPR")) != -1) {
+ switch(c) {
+ case 'n':
+ cp_n = 1;
+ break;
+ case 'p':
+ cp_p = 1;
+ break;
+ case 'v':
+ cp_v = 1;
+ break;
+ case 'L':
+ cp_L = 1;
+ break;
+ case 'P':
+ cp_P = 1;
+ break;
+ case 'R':
+ cp_R = 1;
+ break;
+ case ':':
+ case '?':
+ usage_cp();
+ return -1;
+ break;
+ }
+ }
+
+ /* How many pathnames do we have */
+ numpaths = argc - optind;
+ printf("Number of paths: %u\n", numpaths);
+ if (numpaths < 2) {
+ usage_cp();
+ exit(EXIT_FAILURE);
+ }
+
+ while ( argv[argc-1][(strlen(argv[argc-1]) - 1)] == '/')
+ argv[argc-1][(strlen(argv[argc-1]) - 1)] = 0;
+ printf("Destination is: %s\n", argv[argc-1]);
+
+ /* Create vol for destination */
+ newvol(argv[argc-1], &dstvol);
+
+ if (numpaths == 2) {
+ /* Case 1: 2 paths */
+ if (stat(argv[optind], &sst) != 0)
+ goto next;
+ if (S_ISREG(sst.st_mode)) {
+ /* Either file to file or file to dir copy */
+ newvol(argv[optind], &srcvol);
+ ad_cp_copy(&srcvol, &dstvol, srcfile, path, &sst);
+ freevol(&srcvol);
+ freevol(&dstvol);
+
+ } else if (S_ISDIR(sst.st_mode)) {
+ /* dir to dir copy. Check if -R is requested */
+ if (!cp_R) {
+ usage_cp();
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ } else {
+ /* Case 2: >2 paths */
+ while (optind < (argc-1)) {
+ printf("Source is: %s\n", argv[optind]);
+ newvol(argv[optind], &srcvol);
+ if (stat(argv[optind], &sst) != 0)
+ goto next;
+ if (S_ISDIR(sst.st_mode)) {
+ /* Source is a directory */
+ if (!cp_R) {
+ printf("Source %s is a directory\n", argv[optind]);
+ goto next;
+ }
+ srcdir = argv[optind];
+ dstdir = argv[argc-1];
+
+ ad_cp_r(&srcvol, &dstvol, srcdir, dstdir);
+ freevol(&srcvol);
+ } else {
+ /* Source is a file */
+ srcfile = argv[optind];
+ if (numpaths != 2 && !dstdir) {
+ usage_cp();
+ exit(EXIT_FAILURE);
+ }
+ path[0] = 0;
+ strlcat(path, dstdir, sizeof(path));
+ basenametmp = strdup(srcfile);
+ strlcat(path, basename(basenametmp), sizeof(path));
+ free(basenametmp);
+ printf("%s %s\n", srcfile, path);
+ if (ad_cp_copy(&srcvol, &dstvol, srcfile, path, &sst) != 0) {
+ freevol(&srcvol);
+ freevol(&dstvol);
+ exit(EXIT_FAILURE);
+ }
+ } /* else */
+ next:
+ optind++;
+ } /* while */
+ } /* else (numpath>2) */
+
+ freevol(&dstvol);
+
+ return 0;
+
+}
--- /dev/null
+/*
+ $Id: ad_ls.c,v 1.1 2009-09-01 14:28:07 franklahm Exp $
+
+ Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+#include <atalk/volinfo.h>
+#include "ad.h"
+
+#define ADv2_DIRNAME ".AppleDouble"
+
+#define DIR_DOT_OR_DOTDOT(a) \
+ ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
+
+/* ls options */
+static int ls_a;
+static int ls_l;
+static int ls_R;
+static int ls_d;
+static int ls_u;
+
+/* Used for pretty printing */
+static int first = 1;
+static int recursion;
+
+static char *netatalk_dirs[] = {
+ ADv2_DIRNAME,
+ ".AppleDB",
+ ".AppleDesktop",
+ NULL
+};
+
+static char *labels[] = {
+ "---",
+ "gry",
+ "gre",
+ "vio",
+ "blu",
+ "yel",
+ "red",
+ "ora"
+};
+
+/*
+ Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
+ Returns pointer to name or NULL.
+*/
+static const char *check_netatalk_dirs(const char *name)
+{
+ int c;
+
+ for (c=0; netatalk_dirs[c]; c++) {
+ if ((strcmp(name, netatalk_dirs[c])) == 0)
+ return netatalk_dirs[c];
+ }
+ return NULL;
+}
+
+
+static void usage_ls()
+{
+ printf(
+ "Usage: ad ls [-dRl[u]] [file|dir, ...]\n\n"
+ " -l Long Output [-u: unix info]:\n"
+ " <unixinfo ...> <FinderFlags> <AFPAttributes> <Color> <Type> <Creator> <CNID from AppleDouble> <name>\n\n"
+ " FinderFlags (valid for (f)ile and/or (d)irectory):\n"
+ " d = On Desktop (f/d)\n"
+ " e = Hidden extension (f/d)\n"
+ " m = Shared (can run multiple times) (f)\n"
+ " n = No INIT resources (f)\n"
+ " i = Inited (f/d)\n"
+ " c = Custom icon (f/d)\n"
+ " t = Stationery (f)\n"
+ " s = Name locked (f/d)\n"
+ " b = Bundle (f/d)\n"
+ " v = Invisible (f/d)\n"
+ " a = Alias file (f/d)\n\n"
+ " AFPAttributes:\n"
+ " y = System (f/d)\n"
+ " w = No write (f)\n"
+ " p = Needs backup (f/d)\n"
+ " r = No rename (f/d)\n"
+ " l = No delete (f/d)\n"
+ " o = No copy (f)\n\n"
+ " Note: any letter appearing in uppercase means the flag is set\n"
+ " but it's a directory for which the flag is not allowed.\n"
+ );
+}
+
+static void print_numlinks(const struct stat *statp)
+{
+ printf("%5ld", (long)statp->st_nlink);
+}
+
+static void print_owner(const struct stat *statp)
+{
+ struct passwd *pwd = getpwuid(statp->st_uid);
+
+ if (pwd == NULL)
+ printf(" %-8ld", (long)statp->st_uid);
+ else
+ printf(" %-8s", pwd->pw_name);
+}
+
+static void print_group(const struct stat *statp)
+{
+ struct group *grp = getgrgid(statp->st_gid);
+
+ if (grp == NULL)
+ printf(" %-8ld", (long)statp->st_gid);
+ else
+ printf(" %-8s", grp->gr_name);
+}
+
+static void print_size(const struct stat *statp)
+{
+ switch (statp->st_mode & S_IFMT) {
+ case S_IFCHR:
+ case S_IFBLK:
+ printf("%4u,%4u", (unsigned)(statp->st_rdev >> 8),
+ (unsigned)(statp->st_rdev & 0xFF));
+ break;
+ default:
+ printf("%9lu", (unsigned long)statp->st_size);
+ }
+}
+
+static void print_date(const struct stat *statp)
+{
+ time_t now;
+ double diff;
+ char buf[100], *fmt;
+
+ if (time(&now) == -1) {
+ printf(" ????????????");
+ return;
+ }
+ diff = difftime(now, statp->st_mtime);
+ if (diff < 0 || diff > 60 * 60 * 24 * 182.5)
+ fmt = "%b %e %Y";
+ else
+ fmt = "%b %e %H:%M";
+ strftime(buf, sizeof(buf), fmt, localtime(&statp->st_mtime));
+ printf(" %s", buf);
+}
+
+static void print_flags(char *path, afpvol_t *vol, const struct stat *st)
+{
+ int adflags = 0;
+ struct adouble ad;
+ char *FinderInfo;
+ uint16_t FinderFlags;
+ uint16_t AFPattributes;
+ char type[5] = "----";
+ char creator[5] = "----";
+
+ if (S_ISDIR(st->st_mode))
+ adflags = ADFLAGS_DIR;
+
+ if (vol->volinfo.v_path == NULL)
+ return;
+
+ ad_init(&ad, vol->volinfo.v_adouble, vol->volinfo.v_ad_options);
+
+ if ( ad_metadata(path, adflags, &ad) < 0 )
+ return;
+
+ FinderInfo = ad_entry(&ad, ADEID_FINDERI);
+
+ memcpy(&FinderFlags, FinderInfo + 8, 2);
+ FinderFlags = ntohs(FinderFlags);
+
+ memcpy(type, FinderInfo, 4);
+ memcpy(creator, FinderInfo + 4, 4);
+
+ ad_getattr(&ad, &AFPattributes);
+ AFPattributes = ntohs(AFPattributes);
+
+ /*
+ Finder flags. Lowercase means valid, uppercase means invalid because
+ object is a dir and flag is only valid for files.
+ */
+ putchar(' ');
+ if (FinderFlags & FINDERINFO_ISONDESK)
+ putchar('d');
+ else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_HIDEEXT)
+ putchar('e');
+ else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_ISHARED) {
+ if (adflags & ADFLAGS_DIR)
+ putchar('M');
+ else
+ putchar('m');
+ } else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_HASNOINITS) {
+ if (adflags & ADFLAGS_DIR)
+ putchar('N');
+ else
+ putchar('n');
+ } else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_HASBEENINITED)
+ putchar('i');
+ else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_HASCUSTOMICON)
+ putchar('c');
+ else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_ISSTATIONNERY) {
+ if (adflags & ADFLAGS_DIR)
+ putchar('T');
+ else
+ putchar('t');
+ } else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_NAMELOCKED)
+ putchar('s');
+ else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_HASBUNDLE)
+ putchar('b');
+ else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_INVISIBLE)
+ putchar('v');
+ else
+ putchar('-');
+
+ if (FinderFlags & FINDERINFO_ISALIAS)
+ putchar('a');
+ else
+ putchar('-');
+
+ putchar(' ');
+
+ /* AFP attributes */
+ if (AFPattributes & ATTRBIT_SYSTEM)
+ putchar('y');
+ else
+ putchar('-');
+
+ if (AFPattributes & ATTRBIT_NOWRITE) {
+ if (adflags & ADFLAGS_DIR)
+ putchar('W');
+ else
+ putchar('w');
+ } else
+ putchar('-');
+
+ if (AFPattributes & ATTRBIT_BACKUP)
+ putchar('p');
+ else
+ putchar('-');
+
+ if (AFPattributes & ATTRBIT_NORENAME)
+ putchar('r');
+ else
+ putchar('-');
+
+ if (AFPattributes & ATTRBIT_NODELETE)
+ putchar('l');
+ else
+ putchar('-');
+
+ if (AFPattributes & ATTRBIT_NOCOPY) {
+ if (adflags & ADFLAGS_DIR)
+ putchar('O');
+ else
+ putchar('o');
+ } else
+ putchar('-');
+
+ /* Color */
+ printf(" %s ", labels[(FinderFlags & FINDERINFO_COLOR) >> 1]);
+
+ /* Type & Creator */
+ int i;
+ for(i=0; i<4; i++) {
+ if (isalnum(type[i]))
+ putchar(type[i]);
+ else
+ putchar('-');
+ }
+ putchar(' ');
+ for(i=0; i<4; i++) {
+ if (isalnum(creator[i]))
+ putchar(creator[i]);
+ else
+ putchar('-');
+ }
+ putchar(' ');
+
+ /* CNID */
+ uint32_t cnid = ad_forcegetid(&ad);
+ if (cnid)
+ printf(" %10u ", ntohl(cnid));
+ else
+ printf(" !ADVOL_CACHE ");
+
+ ad_close_metadata(&ad);
+}
+
+#define TYPE(b) ((st->st_mode & (S_IFMT)) == (b))
+#define MODE(b) ((st->st_mode & (b)) == (b))
+
+static void print_mode(const struct stat *st)
+{
+ if (TYPE(S_IFBLK))
+ putchar('b');
+ else if (TYPE(S_IFCHR))
+ putchar('c');
+ else if (TYPE(S_IFDIR))
+ putchar('d');
+ else if (TYPE(S_IFIFO))
+ putchar('p');
+ else if (TYPE(S_IFREG))
+ putchar('-');
+ else if (TYPE(S_IFLNK))
+ putchar('l');
+ else if (TYPE(S_IFSOCK))
+ putchar('s');
+ else
+ putchar('?');
+ putchar(MODE(S_IRUSR) ? 'r' : '-');
+ putchar(MODE(S_IWUSR) ? 'w' : '-');
+ if (MODE(S_ISUID)) {
+ if (MODE(S_IXUSR))
+ putchar('s');
+ else
+ putchar('S');
+ }
+ else if (MODE(S_IXUSR))
+ putchar('x');
+ else
+ putchar('-');
+ putchar(MODE(S_IRGRP) ? 'r' : '-');
+ putchar(MODE(S_IWGRP) ? 'w' : '-');
+ if (MODE(S_ISGID)) {
+ if (MODE(S_IXGRP))
+ putchar('s');
+ else
+ putchar('S');
+ }
+ else if (MODE(S_IXGRP))
+ putchar('x');
+ else
+ putchar('-');
+ putchar(MODE(S_IROTH) ? 'r' : '-');
+ putchar(MODE(S_IWOTH) ? 'w' : '-');
+ if (MODE(S_IFDIR) && MODE(S_ISVTX)) {
+ if (MODE(S_IXOTH))
+ putchar('t');
+ else
+ putchar('T');
+ }
+ else if (MODE(S_IXOTH))
+ putchar('x');
+ else
+ putchar('-');
+}
+#undef TYPE
+#undef MODE
+
+int ad_print(char *path, const struct stat *st, afpvol_t *vol)
+{
+ if ( ! ls_l) {
+ printf("%s ", path);
+ if (ls_d)
+ printf("\n");
+ return 0;
+ }
+
+ /* Long output */
+ if (ls_u) {
+ print_mode(st);
+ print_numlinks(st);
+ print_owner(st);
+ print_group(st);
+ print_size(st);
+ print_date(st);
+ }
+ print_flags(path, vol, st);
+ printf(" %s\n", path);
+
+
+ return 0;
+}
+
+int ad_ls_r(char *path, afpvol_t *vol)
+{
+ int ret = 0, cwd, dirprinted = 0, dirempty;
+ const char *name;
+ char *tmp;
+ static char cwdpath[MAXPATHLEN+1];
+ DIR *dp;
+ struct dirent *ep;
+ static struct stat st; /* Save some stack space */
+
+ if ( first)
+ cwdpath[0] = 0;
+ else
+ strcat(cwdpath, "/");
+
+ strcat(cwdpath, path);
+ first = 0;
+
+ if (lstat(path, &st) < 0) {
+ perror("Can't stat");
+ return -1;
+ }
+ /* If its a file or a dir with -d option call ad_print and return */
+ if (S_ISREG(st.st_mode) || ls_d)
+ return ad_print(path, &st, vol);
+
+ /* Its a dir: chdir to it remembering where we started */
+ if ((cwd = open(".", O_RDONLY)) == -1) {
+ perror("Cant open .");
+ return -1;
+ }
+ if (chdir(path) != 0) {
+ perror("Cant chdir");
+ close(cwd);
+ return -1;
+ }
+
+ if ((dp = opendir (".")) == NULL) {
+ perror("Couldn't opendir .");
+ return -1;
+ }
+
+ /* First run: print everything */
+ dirempty = 1;
+ while ((ep = readdir (dp))) {
+ /* Check if its "." or ".." */
+ if (DIR_DOT_OR_DOTDOT(ep->d_name))
+ continue;
+
+ /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
+ if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
+ continue;
+
+ if ((ep->d_name[0] == '.') && ! ls_a)
+ continue;
+
+ dirempty = 0;
+
+ if (recursion && ! dirprinted) {
+ printf("\n%s:\n", cwdpath);
+ dirprinted = 1;
+ }
+
+ if (lstat(ep->d_name, &st) < 0) {
+ perror("Can't stat");
+ return -1;
+ }
+
+ ret = ad_print(ep->d_name, &st, vol);
+ if (ret != 0)
+ goto exit;
+ }
+
+ if (! ls_l && ! dirempty)
+ printf("\n");
+
+ /* Second run: recurse to dirs */
+ if (ls_R) {
+ rewinddir(dp);
+ while ((ep = readdir (dp))) {
+ /* Check if its "." or ".." */
+ if (DIR_DOT_OR_DOTDOT(ep->d_name))
+ continue;
+
+ /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
+ if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
+ continue;
+
+ if (lstat(ep->d_name, &st) < 0) {
+ perror("Can't stat");
+ return -1;
+ }
+
+ /* Recursion */
+ if (S_ISDIR(st.st_mode)) {
+ recursion = 1;
+ ret = ad_ls_r(ep->d_name, vol);
+ }
+ if (ret != 0)
+ goto exit;
+ }
+ }
+
+exit:
+ closedir(dp);
+ fchdir(cwd);
+ close(cwd);
+
+ tmp = strrchr(cwdpath, '/');
+ if (tmp)
+ *tmp = 0;
+
+ return ret;
+}
+
+int ad_ls(int argc, char **argv)
+{
+ int c, firstarg;
+ afpvol_t vol;
+ struct stat st;
+
+ while ((c = getopt(argc, argv, ":adlRu")) != -1) {
+ switch(c) {
+ case 'a':
+ ls_a = 1;
+ break;
+ case 'd':
+ ls_d = 1;
+ break;
+ case 'l':
+ ls_l = 1;
+ break;
+ case 'R':
+ ls_R = 1;
+ break;
+ case 'u':
+ ls_u = 1;
+ break;
+ case ':':
+ case '?':
+ usage_ls();
+ return -1;
+ break;
+ }
+
+ }
+
+ if ((argc - optind) == 0) {
+ newvol(".", &vol);
+ ad_ls_r(".", &vol);
+ freevol(&vol);
+ }
+ else {
+ firstarg = optind;
+
+ /* First run: only print files from argv paths */
+ int havefile = 0;
+ while(optind < argc) {
+ if (stat(argv[optind], &st) != 0)
+ goto next;
+ if (S_ISDIR(st.st_mode))
+ goto next;
+
+ havefile = 1;
+ first = 1;
+ recursion = 0;
+
+ newvol(argv[optind], &vol);
+ ad_ls_r(argv[optind], &vol);
+ freevol(&vol);
+ next:
+ optind++;
+ }
+ if (havefile && (! ls_l))
+ printf("\n");
+
+ /* Second run: print dirs */
+ optind = firstarg;
+ while(optind < argc) {
+ if (stat(argv[optind], &st) != 0)
+ goto next2;
+ if ( ! S_ISDIR(st.st_mode))
+ goto next2;
+ if ((optind > firstarg) || havefile)
+ printf("\n%s:\n", argv[optind]);
+
+ first = 1;
+ recursion = 0;
+
+ newvol(argv[optind], &vol);
+ ad_ls_r(argv[optind], &vol);
+ freevol(&vol);
+
+ next2:
+ optind++;
+ }
+
+
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ $Id: ad_util.c,v 1.1 2009-09-01 14:28:07 franklahm Exp $
+
+ Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <libgen.h>
+
+#include <atalk/cnid.h>
+#include <atalk/volinfo.h>
+#include "ad.h"
+
+
+int newvol(const char *path, afpvol_t *vol)
+{
+// char *pathdup;
+
+ memset(vol, sizeof(afpvol_t), 0);
+
+// pathdup = strdup(path);
+// vol->dirname = strdup(dirname(pathdup));
+// free(pathdup);
+
+// pathdup = strdup(path);
+// vol->basename = strdup(basename(pathdup));
+// free(pathdup);
+
+ loadvolinfo((char *)path, &vol->volinfo);
+
+ return 0;
+}
+
+void freevol(afpvol_t *vol)
+{
+#if 0
+ if (vol->dirname) {
+ free(vol->dirname);
+ vol->dirname = NULL;
+ }
+ if (vol->basename) {
+ free(vol->basename);
+ vol->basename = NULL;
+ }
+#endif
+}
/*
- * $Id: adouble.h,v 1.39 2009-07-21 13:41:16 didg Exp $
+ * $Id: adouble.h,v 1.40 2009-09-01 14:28:07 franklahm Exp $
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
*
#define FINDERINFO_FRCREATOFF 4
#define FINDERINFO_FRFLAGOFF 8
-/* finderinfo flags */
-#define FINDERINFO_ISONDESK (1) /* "d" */
+/* FinderInfo Flags, char in `ad ls`, valid for files|dirs */
+#define FINDERINFO_ISONDESK (1) /* "d", fd */
#define FINDERINFO_COLOR (0x0e)
-#define FINDERINFO_ISHARED (1<<6) /* "m" */
-#define FINDERINFO_HASNOINITS (1<<7) /* "n" */
-#define FINDERINFO_HASBEENINITED (1<<8) /* "i" */
-#define FINDERINFO_HASCUSTOMICON (1<<10) /* "c" */
-#define FINDERINFO_ISSTATIONNERY (1<<11) /* "t" */
-#define FINDERINFO_NAMELOCKED (1<<12) /* "s" */
-#define FINDERINFO_HASBUNDLE (1<<13) /* "b" */
-#define FINDERINFO_INVISIBLE (1<<14) /* "v" */
-#define FINDERINFO_ISALIAS (1<<15) /* "a" */
+#define FINDERINFO_HIDEEXT (1<<4) /* "e", fd */
+#define FINDERINFO_ISHARED (1<<6) /* "m", f */
+#define FINDERINFO_HASNOINITS (1<<7) /* "n", f */
+#define FINDERINFO_HASBEENINITED (1<<8) /* "i", fd */
+#define FINDERINFO_HASCUSTOMICON (1<<10) /* "c", fd */
+#define FINDERINFO_ISSTATIONNERY (1<<11) /* "t", f */
+#define FINDERINFO_NAMELOCKED (1<<12) /* "s", fd */
+#define FINDERINFO_HASBUNDLE (1<<13) /* "b", fd */
+#define FINDERINFO_INVISIBLE (1<<14) /* "v", fd */
+#define FINDERINFO_ISALIAS (1<<15) /* "a", fd */
#define FINDERINFO_FRVIEWOFF 14
#define FINDERINFO_CUSTOMICON 0x4
<https://sourceforge.net/tracker/?func=detail&aid=2802236&group_id=8642&atid=108642>
*/
-/* AFP attributes for files and dirs. (d) = only these are valid for directories */
-#define ATTRBIT_INVISIBLE (1<<0) /* (d) */
-#define ATTRBIT_MULTIUSER (1<<1)
-#define ATTRBIT_SYSTEM (1<<2) /* "y" (d) */
-#define ATTRBIT_DOPEN (1<<3) /* data fork already open */
-#define ATTRBIT_ROPEN (1<<4) /* resource fork already open */
-#define ATTRBIT_NOWRITE (1<<5) /* "w" write inhibit(v2)/read-only(v1) bit ("") */
-#define ATTRBIT_BACKUP (1<<6) /* "b" (d) */
-#define ATTRBIT_NORENAME (1<<7) /* "r" (d) */
-#define ATTRBIT_NODELETE (1<<8) /* "d" (d) */
-#define ATTRBIT_NOCOPY (1<<10) /* "c" */
-#define ATTRBIT_SETCLR (1<<15) /* set/clear bits (d) */
-
-/* AFP attributes for dirs */
-#define ATTRBIT_EXPFLDR (1<<1) /* Folder is a sharepoint ("p") */
-#define ATTRBIT_MOUNTED (1<<3) /* Directory is mounted by a user ("") */
-#define ATTRBIT_SHARED (1<<4) /* shared area, called IsExpFolder in spec ("") */
+/* AFP attributes, char in `ad ls`, valid for files|dirs */
+#define ATTRBIT_INVISIBLE (1<<0) /* opaque from FinderInfo */
+#define ATTRBIT_MULTIUSER (1<<1) /* file: opaque, dir: see below */
+#define ATTRBIT_SYSTEM (1<<2) /* "y", fd */
+#define ATTRBIT_DOPEN (1<<3) /* data fork already open. Not stored, computed on the fly */
+#define ATTRBIT_ROPEN (1<<4) /* resource fork already open. Not stored, computed on the fly */
+#define ATTRBIT_NOWRITE (1<<5) /* "w", f, write inhibit(v2)/read-only(v1) bit */
+#define ATTRBIT_BACKUP (1<<6) /* "p", fd */
+#define ATTRBIT_NORENAME (1<<7) /* "r", fd */
+#define ATTRBIT_NODELETE (1<<8) /* "l", fd */
+#define ATTRBIT_NOCOPY (1<<10) /* "o", f */
+#define ATTRBIT_SETCLR (1<<15) /* set/clear bit (d) */
+
+/* AFP attributes for dirs. These should probably be computed on the fly.
+ * We don't do that, nor does e.g. OS S X 10.5 Server */
+#define ATTRBIT_EXPFLDR (1<<1) /* Folder is a sharepoint */
+#define ATTRBIT_MOUNTED (1<<3) /* Directory is mounted by a user */
+#define ATTRBIT_SHARED (1<<4) /* Shared area, called IsExpFolder in spec */
/* private AFPFileInfo bits */
#define AD_AFPFILEI_OWNER (1 << 0) /* any owner */
/*
- * $Id: volinfo.h,v 1.5 2009-05-14 13:46:08 franklahm Exp $
+ * $Id: volinfo.h,v 1.6 2009-09-01 14:28:07 franklahm Exp $
*/
#ifndef _ATALK_VOLINFO_H
#define AFPVOL_ULOWERMUPPER (AFPVOL_MTOULOWER | AFPVOL_UTOMUPPER)
/* volinfo for shell utilities */
+#define VOLINFODIR ".AppleDesktop"
#define VOLINFOFILE ".volinfo"
struct volinfo {
if (!S_ISDIR(st.st_mode)) {
if (NULL == (p=strrchr(abspath, '/')) )
- return NULL;
- *p = '\0';
+ strcpy(abspath, ".");
+ else
+ *p = '\0';
}
if (!getcwd(savecwd, sizeof(savecwd)) || chdir(abspath) < 0)
if (!getcwd(abspath, sizeof(abspath)) || chdir (savecwd) < 0)
return NULL;
-
if (strlen(abspath) > bufsize)
return NULL;
strlcpy(path, abspath, bufsize);
-
return path;
}