X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Futil%2Fvolinfo.c;h=ef438c5d278f5b103a968e8e41953c9cad4d5021;hb=387c621d04a928b7e362432b9b56d1960b5045a1;hp=ac1e61d0c175c338f6785beb00981a1479e572f0;hpb=fc4c444fb4abc4406467472a83d13971f43552f9;p=netatalk.git diff --git a/libatalk/util/volinfo.c b/libatalk/util/volinfo.c index ac1e61d0..ef438c5d 100644 --- a/libatalk/util/volinfo.c +++ b/libatalk/util/volinfo.c @@ -39,10 +39,49 @@ #include #include #include +#include #ifdef CNID_DB #include #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 @@ -52,13 +91,9 @@ #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}, @@ -68,39 +103,8 @@ static const _info_option info_options[] = { {"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) @@ -112,9 +116,6 @@ 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; @@ -127,9 +128,7 @@ static char* find_in_path( char *path, char *subdir, size_t maxlen) path[pos-path] = '/'; path[pos-path+1] = 0; -#ifdef DEBUG - fprintf(stderr, "%s path %s\n", subdir, path); -#endif + return path; } @@ -148,22 +147,21 @@ static char * make_path_absolute(char *path, size_t bufsize) 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; } @@ -195,10 +193,10 @@ int vol_load_charsets( struct volinfo *vol) 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; @@ -227,7 +225,7 @@ static int parseline ( char *buf, struct volinfo *vol) 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; @@ -308,14 +306,17 @@ static int parseline ( char *buf, struct volinfo *vol) 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; } @@ -375,6 +376,148 @@ int loadvolinfo (char *path, struct volinfo *vol) 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; +}