X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=libatalk%2Fvfs%2Fea.c;h=70d281068f766c4ae437eebd161fe418138e09ea;hb=2bf71d3ccf20c072bc67a9d075b6ac8b0798021e;hp=d6e7d87e08aefe8c624bc35ea4fbc52b56820ee4;hpb=e7e2c2e5cbc7dfb24b16b49436cc48dec0ac2f21;p=netatalk.git diff --git a/libatalk/vfs/ea.c b/libatalk/vfs/ea.c index d6e7d87e..70d28106 100644 --- a/libatalk/vfs/ea.c +++ b/libatalk/vfs/ea.c @@ -1,5 +1,5 @@ /* - $Id: ea.c,v 1.10 2009-10-23 14:09:51 franklahm Exp $ + $Id: ea.c,v 1.19 2010-02-10 14:05:37 franklahm Exp $ Copyright (c) 2009 Frank Lahm This program is free software; you can redistribute it and/or modify @@ -78,7 +78,7 @@ static char *mtoupath(const struct vol *vol, const char *mpath) char *u; size_t inplen; size_t outlen; - uint16_t flags = CONV_ESCAPEHEX; + uint16_t flags = CONV_ESCAPEHEX | CONV_ALLOW_COLON; if (!mpath) return NULL; @@ -121,7 +121,8 @@ static char *mtoupath(const struct vol *vol, const char *mpath) */ static int unpack_header(struct ea * restrict ea) { - int ret = 0, count = 0; + int ret = 0; + unsigned int count = 0; uint32_t uint32; char *buf; @@ -199,7 +200,7 @@ exit: */ static int pack_header(struct ea * restrict ea) { - int count = 0, eacount = 0; + unsigned int count = 0, eacount = 0; uint16_t uint16; uint32_t uint32; size_t bufsize = EA_HEADER_SIZE; @@ -274,48 +275,6 @@ static int pack_header(struct ea * restrict ea) return 0; } -/* - * Function: ea_path - * - * Purpose: return name of ea header filename - * - * Arguments: - * - * ea (r) ea handle - * eaname (r) name of EA or NULL - * - * Returns: pointer to name in static buffer, NULL on error - * - * Effects: - * - * Calls ad_open, copies buffer, appends "::EA" and if supplied append eanme - * Files: "file" -> "file/.AppleDouble/file::EA" - * Dirs: "dir" -> "dir/.AppleDouble/.Parent::EA" - * "file" with EA "myEA" -> "file/.AppleDouble/file::EA:myEA" - */ -static char * ea_path(const struct ea * restrict ea, - const char * restrict eaname) -{ - char *adname; - static char pathbuf[MAXPATHLEN + 1]; - - /* get name of a adouble file from uname */ - adname = ea->vol->vfs->ad_path(ea->filename, (ea->ea_flags & EA_DIR) ? ADFLAGS_DIR : 0); - /* copy it so we can work with it */ - strlcpy(pathbuf, adname, MAXPATHLEN + 1); - /* append "::EA" */ - strlcat(pathbuf, "::EA", MAXPATHLEN + 1); - - if (eaname) { - strlcat(pathbuf, "::", MAXPATHLEN + 1); - if ((eaname = mtoupath(ea->vol, eaname)) == NULL) - return NULL; - strlcat(pathbuf, eaname, MAXPATHLEN + 1); - } - - return pathbuf; -} - /* * Function: ea_addentry * @@ -340,7 +299,7 @@ static int ea_addentry(struct ea * restrict ea, size_t attrsize, int bitmap) { - int count = 0; + unsigned int count = 0; void *tmprealloc; /* First check if an EA of the requested name already exist */ @@ -397,51 +356,6 @@ error: return -1; } -/* - * Function: ea_delentry - * - * Purpose: delete one EA from ea->ea_entries[] - * - * Arguments: - * - * ea (rw) pointer to struct ea - * attruname (r) EA name - * - * Returns: new number of EA entries, -1 on error - * - * Effects: - * - * Remove entry from ea->ea_entries[]. Decrement ea->ea_count. - * Marks it as unused just by freeing name and setting it to NULL. - * ea_close and pack_buffer must honor this. - */ -static int ea_delentry(struct ea * restrict ea, - const char * restrict attruname) -{ - int ret = 0, count = 0; - - if (ea->ea_count == 0) { - LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion"); - return -1; - } - - while (count < ea->ea_count) { - /* search matching EA */ - if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) { - free((*ea->ea_entries)[count].ea_name); - (*ea->ea_entries)[count].ea_name = NULL; - - LOG(log_debug, logtype_afpd, "ea_delentry('%s'): deleted no %u/%u", - attruname, count + 1, ea->ea_count); - - break; - } - count++; - } - - return ret; -} - /* * Function: create_ea_header * @@ -532,7 +446,7 @@ static int write_ea(const struct ea * restrict ea, struct stat st; char *eaname; - if ((eaname = ea_path(ea, attruname)) == NULL) { + if ((eaname = ea_path(ea, attruname, 1)) == NULL) { LOG(log_error, logtype_afpd, "write_ea('%s'): ea_path error", attruname); return AFPERR_MISC; } @@ -561,7 +475,7 @@ static int write_ea(const struct ea * restrict ea, goto exit; } - if ((write(fd, ibuf, attrsize)) != attrsize) { + if (write(fd, ibuf, attrsize) != (ssize_t)attrsize) { LOG(log_error, logtype_afpd, "write_ea('%s'): write: %s", eaname, strerror(errno)); ret = -1; goto exit; @@ -573,6 +487,51 @@ exit: return ret; } +/* + * Function: ea_delentry + * + * Purpose: delete one EA from ea->ea_entries[] + * + * Arguments: + * + * ea (rw) pointer to struct ea + * attruname (r) EA name + * + * Returns: new number of EA entries, -1 on error + * + * Effects: + * + * Remove entry from ea->ea_entries[]. Decrement ea->ea_count. + * Marks it as unused just by freeing name and setting it to NULL. + * ea_close and pack_buffer must honor this. + */ +static int ea_delentry(struct ea * restrict ea, const char * restrict attruname) +{ + int ret = 0; + unsigned int count = 0; + + if (ea->ea_count == 0) { + LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion"); + return -1; + } + + while (count < ea->ea_count) { + /* search matching EA */ + if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) { + free((*ea->ea_entries)[count].ea_name); + (*ea->ea_entries)[count].ea_name = NULL; + + LOG(log_debug, logtype_afpd, "ea_delentry('%s'): deleted no %u/%u", + attruname, count + 1, ea->ea_count); + + break; + } + count++; + } + + return ret; +} + /* * Function: delete_ea_file * @@ -585,14 +544,13 @@ exit: * * Returns: 0 on success, -1 on error */ -static int delete_ea_file(const struct ea * restrict ea, - const char *eaname) +static int delete_ea_file(const struct ea * restrict ea, const char *eaname) { int ret = 0; char *eafile; struct stat st; - if ((eafile = ea_path(ea, eaname)) == NULL) { + if ((eafile = ea_path(ea, eaname, 1)) == NULL) { LOG(log_error, logtype_afpd, "delete_ea_file('%s'): ea_path error", eaname); return -1; } @@ -610,6 +568,53 @@ static int delete_ea_file(const struct ea * restrict ea, return ret; } +/************************************************************************************* + * ea_path, ea_open and ea_close are only global so that dbd can call them + *************************************************************************************/ + +/* + * Function: ea_path + * + * Purpose: return name of ea header filename + * + * Arguments: + * + * ea (r) ea handle + * eaname (r) name of EA or NULL + * macname (r) if != 0 call mtoupath on eaname + * + * Returns: pointer to name in static buffer, NULL on error + * + * Effects: + * + * Calls ad_open, copies buffer, appends "::EA" and if supplied append eanme + * Files: "file" -> "file/.AppleDouble/file::EA" + * Dirs: "dir" -> "dir/.AppleDouble/.Parent::EA" + * "file" with EA "myEA" -> "file/.AppleDouble/file::EA:myEA" + */ +char *ea_path(const struct ea * restrict ea, const char * restrict eaname, int macname) +{ + char *adname; + static char pathbuf[MAXPATHLEN + 1]; + + /* get name of a adouble file from uname */ + adname = ea->vol->ad_path(ea->filename, (ea->ea_flags & EA_DIR) ? ADFLAGS_DIR : 0); + /* copy it so we can work with it */ + strlcpy(pathbuf, adname, MAXPATHLEN + 1); + /* append "::EA" */ + strlcat(pathbuf, "::EA", MAXPATHLEN + 1); + + if (eaname) { + strlcat(pathbuf, "::", MAXPATHLEN + 1); + if (macname) + if ((eaname = mtoupath(ea->vol, eaname)) == NULL) + return NULL; + strlcat(pathbuf, eaname, MAXPATHLEN + 1); + } + + return pathbuf; +} + /* * Function: ea_open * @@ -625,7 +630,9 @@ static int delete_ea_file(const struct ea * restrict ea, * Eiterh EA_RDONLY or EA_RDWR MUST be requested * ea (w) pointer to a struct ea that we fill * - * Returns: 0 on success, -1 on error + * Returns: 0 on success + * -1 on misc error with errno = EFAULT + * -2 if no EA header exists with errno = ENOENT * * Effects: * @@ -634,10 +641,10 @@ static int delete_ea_file(const struct ea * restrict ea, * file is either read or write locked depending on the open flags. * When you're done with struct ea you must call ea_close on it. */ -static int ea_open(const struct vol * restrict vol, - const char * restrict uname, - eaflags_t eaflags, - struct ea * restrict ea) +int ea_open(const struct vol * restrict vol, + const char * restrict uname, + eaflags_t eaflags, + struct ea * restrict ea) { int ret = 0; char *eaname; @@ -654,9 +661,8 @@ static int ea_open(const struct vol * restrict vol, ea->vol = vol; /* ea_close needs it */ ea->ea_flags = eaflags; - /* Dont check for errors, eg when removing the file is already gone */ - stat(uname, &st); - if (S_ISDIR(st.st_mode)) + /* Dont care for errors, eg when removing the file is already gone */ + if (!stat(uname, &st) && S_ISDIR(st.st_mode)) ea->ea_flags |= EA_DIR; if ( ! (ea->filename = strdup(uname))) { @@ -664,7 +670,7 @@ static int ea_open(const struct vol * restrict vol, return -1; } - eaname = ea_path(ea, NULL); + eaname = ea_path(ea, NULL, 0); LOG(log_maxdebug, logtype_afpd, "ea_open: ea_path: %s", eaname); /* Check if it exists, if not create it if EA_CREATE is in eaflags */ @@ -675,7 +681,7 @@ static int ea_open(const struct vol * restrict vol, if ( ! (eaflags & EA_CREATE)) { /* creation was not requested, so return with error */ - ret = -1; + ret = -2; goto exit; } @@ -707,6 +713,11 @@ static int ea_open(const struct vol * restrict vol, /* header file exists, so read and parse it */ /* malloc buffer where we read disk file into */ + if (st.st_size < EA_HEADER_SIZE) { + LOG(log_error, logtype_afpd, "ea_open('%s'): bogus EA header file", eaname); + ret = -1; + goto exit; + } ea->ea_size = st.st_size; ea->ea_data = malloc(st.st_size); if (! ea->ea_data) { @@ -740,7 +751,7 @@ static int ea_open(const struct vol * restrict vol, } /* read it */ - if ((read(ea->ea_fd, ea->ea_data, ea->ea_size)) != ea->ea_size) { + if (read(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) { LOG(log_error, logtype_afpd, "ea_open: short read on header: %s", eaname); ret = -1; goto exit; @@ -753,9 +764,14 @@ static int ea_open(const struct vol * restrict vol, } exit: - if (ret == 0) { + switch (ret) { + case 0: ea->ea_inited = EA_INITED; - } else { + break; + case -1: + errno = EFAULT; /* force some errno distinguishable from ENOENT */ + /* fall through */ + case -2: if (ea->ea_data) { free(ea->ea_data); ea->ea_data = NULL; @@ -764,6 +780,7 @@ exit: close(ea->ea_fd); ea->ea_fd = -1; } + break; } return ret; @@ -785,9 +802,10 @@ exit: * Flushes and then closes and frees all resouces held by ea handle. * Pack data in ea into ea_data, then write ea_data to disk */ -static int ea_close(struct ea * restrict ea) +int ea_close(struct ea * restrict ea) { - int ret = 0, count = 0; + int ret = 0; + unsigned int count = 0; char *eaname; struct stat st; @@ -806,7 +824,7 @@ static int ea_close(struct ea * restrict ea) } else { if (ea->ea_count == 0) { /* Check if EA header exists and remove it */ - eaname = ea_path(ea, NULL); + eaname = ea_path(ea, NULL, 0); if ((stat(eaname, &st)) == 0) { if ((unlink(eaname)) != 0) { LOG(log_error, logtype_afpd, "ea_close('%s'): unlink: %s", @@ -836,7 +854,7 @@ static int ea_close(struct ea * restrict ea) goto exit; } - if (write(ea->ea_fd, ea->ea_data, ea->ea_size) != ea->ea_size) { + if (write(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) { LOG(log_error, logtype_afpd, "ea_close: write: %s", strerror(errno)); ret = -1; } @@ -905,15 +923,20 @@ exit: */ int get_easize(VFS_FUNC_ARGS_EA_GETSIZE) { - int ret = AFPERR_MISC, count = 0; + int ret = AFPERR_MISC; + unsigned int count = 0; uint32_t uint32; struct ea ea; LOG(log_debug, logtype_afpd, "get_easize: file: %s", uname); if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) { - LOG(log_error, logtype_afpd, "get_easize: error calling ea_open for file: %s", uname); - return AFPERR_MISC; + if (errno != ENOENT) + LOG(log_error, logtype_afpd, "get_easize: error calling ea_open for file: %s", uname); + + memset(rbuf, 0, 4); + *rbuflen += 4; + return ret; } while (count < ea.ea_count) { @@ -961,7 +984,8 @@ int get_easize(VFS_FUNC_ARGS_EA_GETSIZE) */ int get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT) { - int ret = AFPERR_MISC, count = 0, fd = -1; + int ret = AFPERR_MISC, fd = -1; + unsigned int count = 0; uint32_t uint32; size_t toread; struct ea ea; @@ -970,13 +994,16 @@ int get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT) LOG(log_debug, logtype_afpd, "get_eacontent('%s/%s')", uname, attruname); if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) { - LOG(log_error, logtype_afpd, "get_eacontent('%s'): ea_open error", uname); - return AFPERR_MISC; + if (errno != ENOENT) + LOG(log_error, logtype_afpd, "get_eacontent('%s'): ea_open error", uname); + memset(rbuf, 0, 4); + *rbuflen += 4; + return ret; } while (count < ea.ea_count) { if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) { - if ( (eafile = ea_path(&ea, attruname)) == NULL) { + if ( (eafile = ea_path(&ea, attruname, 1)) == NULL) { ret = AFPERR_MISC; break; } @@ -999,7 +1026,7 @@ int get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT) rbuf += 4; *rbuflen += 4; - if ((read(fd, rbuf, toread)) != toread) { + if (read(fd, rbuf, toread) != (ssize_t)toread) { LOG(log_error, logtype_afpd, "get_eacontent('%s/%s'): short read", uname, attruname); ret = AFPERR_MISC; break; @@ -1044,7 +1071,8 @@ int get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT) */ int list_eas(VFS_FUNC_ARGS_EA_LIST) { - int count = 0, attrbuflen = *buflen, ret = AFP_OK, len; + unsigned int count = 0; + int attrbuflen = *buflen, ret = AFP_OK, len; char *buf = attrnamebuf; struct ea ea; @@ -1214,11 +1242,12 @@ exit: int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE) { - LOG(log_debug, logtype_afpd, "ea_deletefile('%s')", file); - - int count = 0, ret = AFP_OK; + unsigned int count = 0; + int ret = AFP_OK; struct ea ea; + LOG(log_debug, logtype_afpd, "ea_deletefile('%s')", file); + /* Open EA stuff */ if ((ea_open(vol, file, EA_RDWR, &ea)) != 0) { if (errno == ENOENT) @@ -1251,7 +1280,7 @@ int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE) int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE) { - int count = 0; + unsigned int count = 0; int ret = AFP_OK; size_t easize; char srceapath[ MAXPATHLEN + 1]; @@ -1299,12 +1328,12 @@ int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE) easize = (*srcea.ea_entries)[count].ea_size; /* Build src and dst paths for rename() */ - if ((eapath = ea_path(&srcea, eaname)) == NULL) { + if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } strcpy(srceapath, eapath); - if ((eapath = ea_path(&dstea, eaname)) == NULL) { + if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } @@ -1349,7 +1378,7 @@ exit: int ea_copyfile(VFS_FUNC_ARGS_COPYFILE) { - int count = 0; + unsigned int count = 0; int ret = AFP_OK; size_t easize; char srceapath[ MAXPATHLEN + 1]; @@ -1396,12 +1425,12 @@ int ea_copyfile(VFS_FUNC_ARGS_COPYFILE) easize = (*srcea.ea_entries)[count].ea_size; /* Build src and dst paths for copy_file() */ - if ((eapath = ea_path(&srcea, eaname)) == NULL) { + if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } strcpy(srceapath, eapath); - if ((eapath = ea_path(&dstea, eaname)) == NULL) { + if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } @@ -1436,12 +1465,13 @@ exit: int ea_chown(VFS_FUNC_ARGS_CHOWN) { - LOG(log_debug, logtype_afpd, "ea_chown('%s')", path); - int count = 0, ret = AFP_OK; + unsigned int count = 0; + int ret = AFP_OK; char *eaname; struct ea ea; + LOG(log_debug, logtype_afpd, "ea_chown('%s')", path); /* Open EA stuff */ if ((ea_open(vol, path, EA_RDWR, &ea)) != 0) { if (errno == ENOENT) @@ -1453,7 +1483,7 @@ int ea_chown(VFS_FUNC_ARGS_CHOWN) } } - if ((chown(ea_path(&ea, NULL), uid, gid)) != 0) { + if ((lchown(ea_path(&ea, NULL, 0), uid, gid)) != 0) { switch (errno) { case EPERM: case EACCES: @@ -1466,11 +1496,11 @@ int ea_chown(VFS_FUNC_ARGS_CHOWN) } while (count < ea.ea_count) { - if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name)) == NULL) { + if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } - if ((chown(eaname, uid, gid)) != 0) { + if ((lchown(eaname, uid, gid)) != 0) { switch (errno) { case EPERM: case EACCES: @@ -1497,12 +1527,13 @@ exit: int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE) { - LOG(log_debug, logtype_afpd, "ea_chmod_file('%s')", name); - int count = 0, ret = AFP_OK; + unsigned int count = 0; + int ret = AFP_OK; const char *eaname; struct ea ea; + LOG(log_debug, logtype_afpd, "ea_chmod_file('%s')", name); /* Open EA stuff */ if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) { if (errno == ENOENT) @@ -1513,8 +1544,8 @@ int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE) } /* Set mode on EA header file */ - if ((setfilmode(ea_path(&ea, NULL), ea_header_mode(mode), NULL, vol->v_umask)) != 0) { - LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL), strerror(errno)); + if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) { + LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno)); switch (errno) { case EPERM: case EACCES: @@ -1528,7 +1559,7 @@ int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE) /* Set mode on EA files */ while (count < ea.ea_count) { - if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name)) == NULL) { + if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } @@ -1560,34 +1591,37 @@ exit: int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE) { - LOG(log_debug, logtype_afpd, "ea_chmod_dir('%s')", name); int ret = AFP_OK; + unsigned int count = 0; uid_t uid; const char *eaname; const char *eaname_safe = NULL; struct ea ea; + LOG(log_debug, logtype_afpd, "ea_chmod_dir('%s')", name); /* .AppleDouble already might be inaccesible, so we must run as id 0 */ uid = geteuid(); if (seteuid(0)) { LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): seteuid: %s", name, strerror(errno)); - ret = AFPERR_MISC; - goto exit; + return AFPERR_MISC; } /* Open EA stuff */ if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) { - if (errno == ENOENT) - /* no EA files, nothing to do */ - return AFP_OK; - else - return AFPERR_MISC; + /* ENOENT --> no EA files, nothing to do */ + if (errno != ENOENT) + ret = AFPERR_MISC; + if (seteuid(uid) < 0) { + LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno)); + exit(EXITERR_SYS); + } + return ret; } /* Set mode on EA header */ - if ((setfilmode(ea_path(&ea, NULL), ea_header_mode(mode), NULL, vol->v_umask)) != 0) { - LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL), strerror(errno)); + if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) { + LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno)); switch (errno) { case EPERM: case EACCES: @@ -1600,7 +1634,6 @@ int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE) } /* Set mode on EA files */ - int count = 0; while (count < ea.ea_count) { eaname = (*ea.ea_entries)[count].ea_name; /* @@ -1613,7 +1646,7 @@ int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE) LOG(log_warning, logtype_afpd, "ea_chmod_dir('%s'): contains a slash", eaname); eaname = eaname_safe; } - if ((eaname = ea_path(&ea, eaname)) == NULL) { + if ((eaname = ea_path(&ea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; }