#include <atalk/util.h>
#include <atalk/logger.h>
#include <atalk/volinfo.h>
+#include <atalk/volume.h>
#ifdef CNID_DB
#include <atalk/cnid.h>
#endif /* CNID_DB*/
+static const vol_opt_name_t vol_opt_names[] = {
+ {AFPVOL_A2VOL, "PRODOS"}, /* prodos volume */
+ {AFPVOL_CRLF, "CRLF"}, /* cr/lf translation */
+ {AFPVOL_NOADOUBLE, "NOADOUBLE"}, /* don't create .AppleDouble by default */
+ {AFPVOL_RO, "READONLY"}, /* read-only volume */
+ {AFPVOL_MSWINDOWS, "MSWINDOWS"}, /* deal with ms-windows yuckiness. this is going away. */
+ {AFPVOL_NOHEX, "NOHEX"}, /* don't do :hex translation */
+ {AFPVOL_USEDOTS, "USEDOTS"}, /* use real dots */
+ {AFPVOL_LIMITSIZE, "LIMITSIZE"}, /* limit size for older macs */
+ {AFPVOL_MAPASCII, "MAPASCII"}, /* map the ascii range as well */
+ {AFPVOL_DROPBOX, "DROPBOX"}, /* dropkludge dropbox support */
+ {AFPVOL_NOFILEID, "NOFILEID"}, /* don't advertise createid resolveid and deleteid calls */
+ {AFPVOL_NOSTAT, "NOSTAT"}, /* advertise the volume even if we can't stat() it
+ * maybe because it will be mounted later in preexec */
+ {AFPVOL_UNIX_PRIV, "UNIXPRIV"}, /* support unix privileges */
+ {AFPVOL_NODEV, "NODEV"}, /* always use 0 for device number in cnid calls */
+ {AFPVOL_CASEINSEN, "CASEINSENSITIVE"}, /* volume is case insensitive */
+ {AFPVOL_EILSEQ, "ILLEGALSEQ"}, /* encode illegal sequence */
+ {AFPVOL_CACHE, "CACHEID"}, /* Use adouble v2 CNID caching, default don't use it */
+ {AFPVOL_INV_DOTS, "INVISIBLEDOTS"},
+ {AFPVOL_ACLS, "ACLS"}, /* Vol supports ACLs */
+ {AFPVOL_TM, "TM"}, /* Set "kSupportsTMLockSteal" is volume attributes */
+ {0, NULL}
+};
+
+static const vol_opt_name_t vol_opt_casefold[] = {
+ {AFPVOL_MTOUUPPER, "MTOULOWER"},
+ {AFPVOL_MTOULOWER, "MTOULOWER"},
+ {AFPVOL_UTOMUPPER, "UTOMUPPER"},
+ {AFPVOL_UTOMLOWER, "UTOMLOWER"},
+ {0, NULL}
+};
+
+typedef struct {
+ const char *name;
+ int type;
+} info_option_t;
+
#define MAC_CHARSET 0
#define VOL_CHARSET 1
#define ADOUBLE_VER 2
#define CNID_DBPATH 6
#define VOLUME_OPTS 7
#define VOLCASEFOLD 8
+#define EXTATTRTYPE 9
-typedef struct _info_option {
- const char *name;
- int type;
-} _info_option;
-
-static const _info_option info_options[] = {
+static const info_option_t info_options[] = {
{"MAC_CHARSET", MAC_CHARSET},
{"VOL_CHARSET", VOL_CHARSET},
{"ADOUBLE_VER", ADOUBLE_VER},
{"CNID_DBPATH", CNID_DBPATH},
{"VOLUME_OPTS", VOLUME_OPTS},
{"VOLCASEFOLD", VOLCASEFOLD},
- {NULL, 0}
-};
-
-typedef struct _vol_opt_name {
- const u_int32_t option;
- const char *name;
-} _vol_opt_name;
-
-static const _vol_opt_name vol_opt_names[] = {
- {AFPVOL_A2VOL, "PRODOS"}, /* prodos volume */
- {AFPVOL_CRLF, "CRLF"}, /* cr/lf translation */
- {AFPVOL_NOADOUBLE, "NOADOUBLE"}, /* don't create .AppleDouble by default */
- {AFPVOL_RO, "READONLY"}, /* read-only volume */
- {AFPVOL_MSWINDOWS, "MSWINDOWS"}, /* deal with ms-windows yuckiness. this is going away. */
- {AFPVOL_NOHEX, "NOHEX"}, /* don't do :hex translation */
- {AFPVOL_USEDOTS, "USEDOTS"}, /* use real dots */
- {AFPVOL_LIMITSIZE, "LIMITSIZE"}, /* limit size for older macs */
- {AFPVOL_MAPASCII, "MAPASCII"}, /* map the ascii range as well */
- {AFPVOL_DROPBOX, "DROPBOX"}, /* dropkludge dropbox support */
- {AFPVOL_NOFILEID, "NOFILEID"}, /* don't advertise createid resolveid and deleteid calls */
- {AFPVOL_NOSTAT, "NOSTAT"}, /* advertise the volume even if we can't stat() it
- * maybe because it will be mounted later in preexec */
- {AFPVOL_UNIX_PRIV, "UNIXPRIV"}, /* support unix privileges */
- {AFPVOL_NODEV, "NODEV"}, /* always use 0 for device number in cnid calls */
- {0, NULL}
-};
-
-static const _vol_opt_name vol_opt_casefold[] = {
- {AFPVOL_MTOUUPPER, "MTOULOWER"},
- {AFPVOL_MTOULOWER, "MTOULOWER"},
- {AFPVOL_UTOMUPPER, "UTOMUPPER"},
- {AFPVOL_UTOMLOWER, "UTOMLOWER"},
- {0, NULL}
+ {"EXTATTRTYPE", EXTATTRTYPE},
+ {NULL, 0}
};
static char* find_in_path( char *path, char *subdir, size_t maxlen)
pos = strrchr(path, '/');
while ( stat(path, &st) != 0) {
-#ifdef DEBUG
- fprintf(stderr, "searching in path %s\n", path);
-#endif
path[pos-path]=0;
if ((pos = strrchr(path, '/'))) {
path[pos-path]=0;
path[pos-path] = '/';
path[pos-path+1] = 0;
-#ifdef DEBUG
- fprintf(stderr, "%s path %s\n", subdir, path);
-#endif
+
return path;
}
if (!S_ISDIR(st.st_mode)) {
if (NULL == (p=strrchr(abspath, '/')) )
- return NULL;
- *p = '\0';
+ strcpy(abspath, ".");
+ else
+ *p = '\0';
}
- getcwd(savecwd, sizeof(savecwd));
- if ((chdir(abspath)) < 0)
+ if (!getcwd(savecwd, sizeof(savecwd)) || chdir(abspath) < 0)
return NULL;
- getcwd(abspath, sizeof(abspath));
- chdir (savecwd);
-
+ if (!getcwd(abspath, sizeof(abspath)) || chdir (savecwd) < 0)
+ return NULL;
+
if (strlen(abspath) > bufsize)
return NULL;
strlcpy(path, abspath, bufsize);
-
return path;
}
return 0;
}
-static int parse_options (char *buf, int *flags, const _vol_opt_name* options)
+static int parse_options (char *buf, int *flags, const vol_opt_name_t *options)
{
char *p, *q;
- const _vol_opt_name *op;
+ const vol_opt_name_t *op;
q = p = buf;
char *value;
size_t len;
int option=-1;
- const _info_option *p = &info_options[0];
+ const info_option_t *p = &info_options[0];
if (NULL == ( value = strchr(buf, ':')) )
return 1;
case VOLCASEFOLD:
parse_options(value, &vol->v_casefold, &vol_opt_casefold[0]);
break;
+ case EXTATTRTYPE:
+ if (strcasecmp(value, "AFPVOL_EA_AD") == 0)
+ vol->v_vfs_ea = AFPVOL_EA_AD;
+ else if (strcasecmp(value, "AFPVOL_EA_SYS") == 0)
+ vol->v_vfs_ea = AFPVOL_EA_SYS;
+ break;
default:
fprintf (stderr, "unknown volume information: %s, %s", buf, value);
return (-1);
break;
}
-#ifdef DEBUG
- printf ("volume information: %s, %s", buf, value);
-#endif
return 0;
}
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &lock);
+ /* Translate vol options to ad options like afp/volume.c does it */
+ vol->v_ad_options = 0;
+ if ((vol->v_flags & AFPVOL_NODEV))
+ vol->v_ad_options |= ADVOL_NODEV;
+ if ((vol->v_flags & AFPVOL_CACHE))
+ vol->v_ad_options |= ADVOL_CACHE;
+ if ((vol->v_flags & AFPVOL_UNIX_PRIV))
+ vol->v_ad_options |= ADVOL_UNIXPRIV;
+ if ((vol->v_flags & AFPVOL_INV_DOTS))
+ vol->v_ad_options |= ADVOL_INVDOTS;
+
fclose(fp);
return 0;
}
+
+/*
+ * Save the volume options to a file, used by shell utilities. Writing the file
+ * everytime a volume is opened is unnecessary, but it shouldn't hurt much.
+ */
+int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_port)
+{
+ char buf[16348];
+ char item[MAXPATHLEN];
+ int fd;
+ int ret = 0;
+ struct flock lock;
+ const vol_opt_name_t *op = &vol_opt_names[0];
+ const vol_opt_name_t *cf = &vol_opt_casefold[0];
+
+ strlcpy (item, vol->v_path, sizeof(item));
+ strlcat (item, "/.AppleDesktop/", sizeof(item));
+ strlcat (item, VOLINFOFILE, sizeof(item));
+
+ if ((fd = open( item, O_RDWR | O_CREAT , 0666)) <0 ) {
+ LOG(log_debug, logtype_afpd,"Error opening %s: %s", item, strerror(errno));
+ return (-1);
+ }
+
+ /* try to get a lock */
+ lock.l_start = 0;
+ lock.l_whence = SEEK_SET;
+ lock.l_len = 0;
+ lock.l_type = F_WRLCK;
+
+ if (fcntl(fd, F_SETLK, &lock) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ /* ignore, other process already writing the file */
+ return 0;
+ } else {
+ LOG(log_error, logtype_cnid, "savevoloptions: cannot get lock: %s", strerror(errno));
+ return (-1);
+ }
+ }
+
+ /* write volume options */
+ snprintf(buf, sizeof(buf), "MAC_CHARSET:%s\n", vol->v_maccodepage);
+ snprintf(item, sizeof(item), "VOL_CHARSET:%s\n", vol->v_volcodepage);
+ strlcat(buf, item, sizeof(buf));
+
+ switch (vol->v_adouble) {
+ case AD_VERSION1:
+ strlcat(buf, "ADOUBLE_VER:v1\n", sizeof(buf));
+ break;
+ case AD_VERSION2:
+ strlcat(buf, "ADOUBLE_VER:v2\n", sizeof(buf));
+ break;
+ case AD_VERSION2_OSX:
+ strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf));
+ break;
+ case AD_VERSION1_SFM:
+ strlcat(buf, "ADOUBLE_VER:sfm\n", sizeof(buf));
+ break;
+ }
+
+ strlcat(buf, "CNIDBACKEND:", sizeof(buf));
+ strlcat(buf, vol->v_cnidscheme, sizeof(buf));
+ strlcat(buf, "\n", sizeof(buf));
+
+ strlcat(buf, "CNIDDBDHOST:", sizeof(buf));
+ strlcat(buf, Cnid_srv, sizeof(buf));
+ strlcat(buf, "\n", sizeof(buf));
+
+ strlcat(buf, "CNIDDBDPORT:", sizeof(buf));
+ strlcat(buf, Cnid_port, sizeof(buf));
+ strlcat(buf, "\n", sizeof(buf));
+
+ strcpy(item, "CNID_DBPATH:");
+ if (vol->v_dbpath)
+ strlcat(item, vol->v_dbpath, sizeof(item));
+ else
+ strlcat(item, vol->v_path, sizeof(item));
+ strlcat(item, "\n", sizeof(item));
+ strlcat(buf, item, sizeof(buf));
+
+ /* volume flags */
+ strcpy(item, "VOLUME_OPTS:");
+ for (;op->name; op++) {
+ if ( (vol->v_flags & op->option) ) {
+ strlcat(item, op->name, sizeof(item));
+ strlcat(item, " ", sizeof(item));
+ }
+ }
+ strlcat(item, "\n", sizeof(item));
+ strlcat(buf, item, sizeof(buf));
+
+ /* casefold flags */
+ strcpy(item, "VOLCASEFOLD:");
+ for (;cf->name; cf++) {
+ if ( (vol->v_casefold & cf->option) ) {
+ strlcat(item, cf->name, sizeof(item));
+ strlcat(item, " ", sizeof(item));
+ }
+ }
+ strlcat(item, "\n", sizeof(item));
+ strlcat(buf, item, sizeof(buf));
+
+ /* ExtendedAttributes */
+ strcpy(item, "EXTATTRTYPE:");
+ switch (vol->v_vfs_ea) {
+ case AFPVOL_EA_SYS:
+ strlcat(item, "AFPVOL_EA_SYS\n", sizeof(item));
+ break;
+ case AFPVOL_EA_AD:
+ strlcat(item, "AFPVOL_EA_AD\n", sizeof(item));
+ break;
+ case AFPVOL_EA_NONE:
+ strlcat(item, "AFPVOL_EA_NONE\n", sizeof(item));
+ break;
+ default:
+ strlcat(item, "AFPVOL_EA_UNKNOWN\n", sizeof(item));
+ }
+
+ strlcat(buf, item, sizeof(buf));
+
+ if (strlen(buf) >= sizeof(buf)-1)
+ LOG(log_debug, logtype_afpd,"Error writing .volinfo file: buffer too small, %s", buf);
+ if (write( fd, buf, strlen(buf)) < 0 || ftruncate(fd, strlen(buf)) < 0 ) {
+ LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno));
+ }
+
+ lock.l_type = F_UNLCK;
+ fcntl(fd, F_SETLK, &lock);
+ close (fd);
+ return ret;
+}