#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+
+#include <uuid/uuid.h>
+
#include <atalk/asp.h>
#include <atalk/dsi.h>
#include <atalk/adouble.h>
#endif /* BYTE_ORDER == BIG_ENDIAN */
#endif /* ! NO_LARGE_VOL_SUPPORT */
+#ifndef UUID_PRINTABLE_STRING_LENGTH
+#define UUID_PRINTABLE_STRING_LENGTH 37
+#endif
+
static struct vol *Volumes = NULL;
static u_int16_t lastvid = 0;
static char *Trash = "\02\024Network Trash Folder";
#define VOLOPT_EA_VFS 27 /* Extended Attributes vfs indirection */
#define VOLOPT_CNIDSERVER 28 /* CNID Server ip address*/
#define VOLOPT_CNIDPORT 30 /* CNID server tcp port */
-#define VOLOPT_UUID 31 /* CNID server tcp port */
-#define VOLOPT_MAX 32 /* <== IMPORTANT !!!!!! */
+#define VOLOPT_MAX 31 /* <== IMPORTANT !!!!!! */
#define VOLOPT_NUM (VOLOPT_MAX + 1)
#define VOLPASSLEN 8
} else if (optionok(tmp, "volsizelimit:", val)) {
options[VOLOPT_LIMITSIZE].i_value = (uint32_t)strtoul(val + 1, NULL, 10);
- } else if (optionok(tmp, "uuid:", val)) {
- setoption(options, save, VOLOPT_UUID, val);
-
} else {
/* ignore unknown options */
LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp);
if (options[VOLOPT_LIMITSIZE].i_value)
volume->v_limitsize = options[VOLOPT_LIMITSIZE].i_value;
- if (options[VOLOPT_UUID].c_value)
- volume->v_uuid = strdup(options[VOLOPT_UUID].c_value);
-
/* Mac to Unix conversion flags*/
volume->v_mtou_flags = 0;
if (!(volume->v_flags & AFPVOL_NOHEX))
check_ea_sys_support(volume);
initvol_vfs(volume);
+ /* get/store uuid from file */
+ if (volume->v_flags & AFPVOL_TM) {
+ char *uuid = get_uuid(obj, volume->v_localname);
+ if (!uuid) {
+ LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID",
+ volume->v_localname);
+ } else {
+ volume->v_uuid = uuid;
+ LOG(log_debug, logtype_afpd, "Volume '%s': UUID '%s'",
+ volume->v_localname, volume->v_uuid);
+ }
+ }
+
volume->v_next = Volumes;
Volumes = volume;
return 0;
free(vol->v_forceuid);
free(vol->v_forcegid);
#endif /* FORCE_UIDGID */
+ if (vol->v_uuid)
+ free(vol->v_uuid);
}
/* ------------------------------- */
if ( obj->options.flags & OPTION_USERVOLFIRST ) {
readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent );
}
-
+
if ( obj->options.closevol ) {
struct vol *vol;
LOG(log_info, logtype_afpd, "CNID server: %s:%s",
volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv,
volume->v_cnidport ? volume->v_cnidport : Cnid_port);
-
+
#if 0
/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
return (!volume->v_cdb)?-1:0;
}
-/*
- Check if the underlying filesystem supports EAs for ea:sys volumes.
- If not, switch to ea:ad.
- As we can't check (requires write access) on ro-volumes, we switch ea:auto
- volumes that are options:ro to ea:none.
+/*
+ Check if the underlying filesystem supports EAs for ea:sys volumes.
+ If not, switch to ea:ad.
+ As we can't check (requires write access) on ro-volumes, we switch ea:auto
+ volumes that are options:ro to ea:none.
*/
static void check_ea_sys_support(struct vol *vol)
{
if ((tmp = strdup(volume->v_path)) == NULL) {
free(volume->v_path);
return AFPERR_MISC;
- }
+ }
free(volume->v_path);
volume->v_path = tmp;
#endif
free(q);
return (-1);
}
-
+
ad_setname(&ad, folder->name);
ad_getattr(&ad, &attr);
free_extmap();
free_volumes();
}
+
+/*
+ * Get a volumes UUID from the config file.
+ * If there is none, it is generated and stored there.
+ *
+ * Returns pointer to allocated storage on success, NULL on error.
+ */
+char *get_uuid(const AFPObj *obj, const char *volname)
+{
+ char *volname_conf;
+ char buf[1024], uuid[UUID_PRINTABLE_STRING_LENGTH], *p;
+ FILE *fp;
+ struct stat tmpstat;
+ int fd;
+
+ if ((fp = fopen(obj->options.uuidconf, "r")) != NULL) { /* read open? */
+ /* scan in the conf file */
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ p = buf;
+ while (p && isblank(*p))
+ p++;
+ if (!p || (*p == '#') || (*p == '\n'))
+ continue; /* invalid line */
+ if (*p == '"') {
+ p++;
+ if ((volname_conf = strtok( p, "\"" )) == NULL)
+ continue; /* syntax error */
+ } else {
+ if ((volname_conf = strtok( p, " \t" )) == NULL)
+ continue; /* syntax error: invalid name */
+ }
+ p = strchr(p, '\0');
+ p++;
+ if (*p == '\0')
+ continue; /* syntax error */
+
+ if (strcmp(volname, volname_conf) != 0)
+ continue; /* another volume name */
+
+ while (p && isblank(*p))
+ p++;
+
+ if (sscanf(p, "%36s", uuid) == 1 ) {
+ for (int i=0; uuid[i]; i++)
+ uuid[i] = toupper(uuid[i]);
+ LOG(log_debug, logtype_afpd, "get_uuid('%s'): UUID: '%s'", volname, uuid);
+ fclose(fp);
+ return strdup(uuid);
+ }
+ }
+ }
+
+ if (fp)
+ fclose(fp);
+
+ /* not found or no file, reopen in append mode */
+
+ if (stat(obj->options.uuidconf, &tmpstat)) { /* no file */
+ if (( fd = creat(obj->options.uuidconf, 0644 )) < 0 ) {
+ LOG(log_error, logtype_atalkd, "ERROR: Cannot create %s (%s).",
+ obj->options.uuidconf, strerror(errno));
+ return NULL;
+ }
+ if (( fp = fdopen( fd, "w" )) == NULL ) {
+ LOG(log_error, logtype_atalkd, "ERROR: Cannot fdopen %s (%s).",
+ obj->options.uuidconf, strerror(errno));
+ close(fd);
+ return NULL;
+ }
+ } else if ((fp = fopen(obj->options.uuidconf, "a+")) == NULL) { /* not found */
+ LOG(log_error, logtype_afpd, "Cannot create or append to %s (%s).",
+ obj->options.uuidconf, strerror(errno));
+ return NULL;
+ }
+ fseek(fp, 0L, SEEK_END);
+ if(ftell(fp) == 0) { /* size = 0 */
+ fprintf(fp, "# DON'T TOUCH NOR COPY THOUGHTLESSLY!\n");
+ fprintf(fp, "# This file is auto-generated by afpd\n");
+ fprintf(fp, "# and stores UUIDs for TM volumes.\n\n");
+ } else {
+ fseek(fp, -1L, SEEK_END);
+ if(fgetc(fp) != '\n') fputc('\n', fp); /* last char is \n? */
+ }
+
+ /* generate uuid and write to file */
+ uuid_t id;
+ uuid_generate(id);
+ uuid_unparse(id, uuid);
+ for (int i=0; uuid[i]; i++)
+ uuid[i] = toupper(uuid[i]);
+ LOG(log_debug, logtype_afpd, "get_uuid('%s'): generated UUID '%s'", volname, uuid);
+
+ fprintf(fp, "\"%s\"\t%36s\n", volname, uuid);
+ fclose(fp);
+
+ return strdup(uuid);
+}