+
+/*
+ * 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;
+}