X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Ffiledir.c;h=7adbeed61c94e9fb02bfa80ed75f21b8e8e9912b;hp=469586966ea53680094d79e180aade23f09ad828;hb=d3dff4ba4b8db3131a16641d35a6554be5fb5160;hpb=33f44ea7f93b30678659d7e50b23c5056991dfd0 diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index 46958696..7adbeed6 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -1,6 +1,4 @@ /* - * $Id: filedir.c,v 1.73 2010-03-12 15:16:49 franklahm Exp $ - * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. */ @@ -11,24 +9,7 @@ #include #include -/* STDC check */ -#if STDC_HEADERS #include -#else /* STDC_HEADERS */ -#ifndef HAVE_STRCHR -#define strchr index -#define strrchr index -#endif /* HAVE_STRCHR */ -char *strchr (), *strrchr (); -#ifndef HAVE_MEMCPY -#define memcpy(d,s,n) bcopy ((s), (d), (n)) -#define memmove(d,s,n) bcopy ((s), (d), (n)) -#endif /* ! HAVE_MEMCPY */ -#endif /* STDC_HEADERS */ - -#ifdef HAVE_STRINGS_H -#include -#endif #include #include @@ -39,107 +20,32 @@ char *strchr (), *strrchr (); #include #include #include +#include +#include +#include +#include +#include +#include +#include #include "directory.h" +#include "dircache.h" #include "desktop.h" #include "volume.h" #include "fork.h" #include "file.h" -#include "globals.h" #include "filedir.h" #include "unix.h" -#include "fce_api.h" - -#ifdef DROPKLUDGE -int matchfile2dirperms( -/* Since it's kinda' big; I decided against an -inline function */ - char *upath, - struct vol *vol, - int did) -/* The below code changes the way file ownership is determined in the name of -fixing dropboxes. It has known security problem. See the netatalk FAQ for -more information */ -{ - struct stat st, sb; - struct dir *dir; - char *adpath; - uid_t uid; - int ret = AFP_OK; -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "begin matchfile2dirperms:"); -#endif - - if (stat(upath, &st ) < 0) { - LOG(log_error, logtype_afpd, "Could not stat %s: %s", upath, strerror(errno)); - return AFPERR_NOOBJ ; - } - - adpath = vol->vfs->ad_path( upath, ADFLAGS_HF ); - /* FIXME dirsearch doesn't move cwd to did ! */ - if (( dir = dirlookup( vol, did )) == NULL ) { - LOG(log_error, logtype_afpd, "matchfile2dirperms: Unable to get directory info."); - ret = AFPERR_NOOBJ; - } - else if (stat(".", &sb) < 0) { - LOG(log_error, logtype_afpd, - "matchfile2dirperms: Error checking directory \"%s\": %s", - dir->d_m_name, strerror(errno)); - ret = AFPERR_NOOBJ; - } - else { - uid=geteuid(); - if ( uid != sb.st_uid ) - { - seteuid(0); - if (lchown(upath, sb.st_uid, sb.st_gid) < 0) - { - LOG(log_error, logtype_afpd, - "matchfile2dirperms(%s): Error changing owner/gid: %s", - upath, strerror(errno)); - ret = AFPERR_ACCESS; - } - else if ((!S_ISLNK(st->st_mode)) && (chmod(upath,(st.st_mode&~default_options.umask)| S_IRGRP| S_IROTH) < 0)) - { - LOG(log_error, logtype_afpd, - "matchfile2dirperms(%s): Error adding file read permissions: %s", - upath, strerror(errno)); - ret = AFPERR_ACCESS; - } - else if (lchown(adpath, sb.st_uid, sb.st_gid) < 0) - { - LOG(log_error, logtype_afpd, - "matchfile2dirperms(%s): Error changing AppleDouble owner/gid: %s", - adpath, strerror(errno)); - ret = AFPERR_ACCESS; - } - else if (chmod(adpath, (st.st_mode&~default_options.umask)| S_IRGRP| S_IROTH) < 0) - { - LOG(log_error, logtype_afpd, - "matchfile2dirperms(%s): Error adding AD file read permissions: %s", - adpath, strerror(errno)); - ret = AFPERR_ACCESS; - } - seteuid(uid); - } - } /* end else if stat success */ - -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "end matchfile2dirperms:"); -#endif - return ret; -} -#endif int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) { - struct stat *st; - struct vol *vol; - struct dir *dir; - u_int32_t did; - int ret; - size_t buflen; - u_int16_t fbitmap, dbitmap, vid; + struct stat *st; + struct vol *vol; + struct dir *dir; + uint32_t did; + int ret; + size_t buflen; + uint16_t fbitmap, dbitmap, vid; struct path *s_path; *rbuflen = 0; @@ -150,7 +56,7 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r if (NULL == ( vol = getvolbyvid( vid )) ) { /* was AFPERR_PARAM but it helps OS 10.3 when a volume has been removed * from the list. - */ + */ return( AFPERR_ACCESS ); } @@ -169,11 +75,12 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r ibuf += sizeof( dbitmap ); if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) { - return get_afp_errno(AFPERR_NOOBJ); + return get_afp_errno(AFPERR_NOOBJ); } - LOG(log_debug, logtype_afpd, "getfildirparams(vid:%u, did:%u, name:'%s', f/d:%04x/%04x) {cwd: %s}", - ntohs(vid), ntohl(dir->d_did), s_path->u_name, fbitmap, dbitmap, getcwdpath()); + LOG(log_debug, logtype_afpd, "getfildirparams(vid:%u, did:%u, f/d:%04x/%04x) {cwdid:%u, cwd: %s, name:'%s'}", + ntohs(vid), ntohl(dir->d_did), fbitmap, dbitmap, + ntohl(curdir->d_did), cfrombstr(curdir->d_fullpath), s_path->u_name); st = &s_path->st; if (!s_path->st_valid) { @@ -185,7 +92,9 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r of_statdir(vol, s_path); } if ( s_path->st_errno != 0 ) { - return( AFPERR_NOOBJ ); + if (afp_errno != AFPERR_ACCESS) { + return( AFPERR_NOOBJ ); + } } @@ -193,25 +102,25 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r if (S_ISDIR(st->st_mode)) { if (dbitmap) { dir = s_path->d_dir; - if (!dir) + if (!dir) return AFPERR_NOOBJ; - ret = getdirparams(vol, dbitmap, s_path, dir, - rbuf + 3 * sizeof( u_int16_t ), &buflen ); + ret = getdirparams(obj, vol, dbitmap, s_path, dir, + rbuf + 3 * sizeof( uint16_t ), &buflen ); if (ret != AFP_OK ) return( ret ); } /* this is a directory */ - *(rbuf + 2 * sizeof( u_int16_t )) = (char) FILDIRBIT_ISDIR; + *(rbuf + 2 * sizeof( uint16_t )) = (char) FILDIRBIT_ISDIR; } else { - if (fbitmap && AFP_OK != (ret = getfilparams(vol, fbitmap, s_path, curdir, - rbuf + 3 * sizeof( u_int16_t ), &buflen )) ) { + if (fbitmap && AFP_OK != (ret = getfilparams(obj, vol, fbitmap, s_path, curdir, + rbuf + 3 * sizeof( uint16_t ), &buflen, 0)) ) { return( ret ); } /* this is a file */ - *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISFILE; + *(rbuf + 2 * sizeof( uint16_t )) = FILDIRBIT_ISFILE; } - *rbuflen = buflen + 3 * sizeof( u_int16_t ); + *rbuflen = buflen + 3 * sizeof( uint16_t ); fbitmap = htons( fbitmap ); memcpy( rbuf, &fbitmap, sizeof( fbitmap )); rbuf += sizeof( fbitmap ); @@ -225,12 +134,12 @@ int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *r int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { - struct stat *st; - struct vol *vol; - struct dir *dir; + struct stat *st; + struct vol *vol; + struct dir *dir; struct path *path; - u_int16_t vid, bitmap; - int did, rc; + uint16_t vid, bitmap; + int did, rc; *rbuflen = 0; ibuf += 2; @@ -248,7 +157,7 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf ibuf += sizeof( did); if (NULL == ( dir = dirlookup( vol, did )) ) { - return afp_errno; + return afp_errno; } memcpy( &bitmap, ibuf, sizeof( bitmap )); @@ -256,7 +165,7 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf ibuf += sizeof( bitmap ); if (NULL == ( path = cname( vol, dir, &ibuf ))) { - return get_afp_errno(AFPERR_NOOBJ); + return get_afp_errno(AFPERR_NOOBJ); } st = &path->st; @@ -268,7 +177,8 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf } if ( path->st_errno != 0 ) { - return( AFPERR_NOOBJ ); + if (afp_errno != AFPERR_ACCESS) + return( AFPERR_NOOBJ ); } /* * If ibuf is odd, make it even. @@ -280,7 +190,7 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf if (S_ISDIR(st->st_mode)) { rc = setdirparams(vol, path, bitmap, ibuf ); } else { - rc = setfilparams(vol, path, bitmap, ibuf ); + rc = setfilparams(obj, vol, path, bitmap, ibuf ); } if ( rc == AFP_OK ) { setvoltime(obj, vol ); @@ -289,18 +199,11 @@ int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf return( rc ); } -/* -------------------------------------------- +/* -------------------------------------------- Factorise some checks on a pathname */ int check_name(const struct vol *vol, char *name) { - /* check for illegal characters in the unix filename */ - if (!wincheck(vol, name)) - return AFPERR_PARAM; - - if ((vol->v_flags & AFPVOL_NOHEX) && strchr(name, '/')) - return AFPERR_PARAM; - if (!vol->vfs->vfs_validupath(vol, name)) { LOG(log_error, logtype_afpd, "check_name: illegal name: '%s'", name); return AFPERR_EXIST; @@ -316,14 +219,15 @@ int check_name(const struct vol *vol, char *name) move and rename sdir:oldname to curdir:newname in volume vol special care is needed for lock */ -static int moveandrename(const struct vol *vol, +static int moveandrename(const AFPObj *obj, + struct vol *vol, struct dir *sdir, int sdir_fd, char *oldname, char *newname, int isdir) { - char *p; + char *oldunixname = NULL; char *upath; int rc; struct stat *st, nst; @@ -333,134 +237,188 @@ static int moveandrename(const struct vol *vol, struct ofork *opened = NULL; struct path path; cnid_t id; - int cwd_fd; + int cwd_fd = -1; - ad_init(&ad, vol->v_adouble, vol->v_ad_options); + ad_init(&ad, vol); adp = &ad; adflags = 0; if (!isdir) { - if ((p = mtoupath(vol, oldname, sdir->d_did, utf8_encoding())) == NULL) + if ((oldunixname = strdup(mtoupath(vol, oldname, sdir->d_did, utf8_encoding(vol->v_obj)))) == NULL) return AFPERR_PARAM; /* can't convert */ + AFP_CNID_START("cnid_get"); + id = cnid_get(vol->v_cdb, sdir->d_did, oldunixname, strlen(oldunixname)); + AFP_CNID_DONE(); -#ifndef HAVE_RENAMEAT +#ifndef HAVE_ATFUNCS /* Need full path */ - id = cnid_get(vol->v_cdb, sdir->d_did, p, strlen(p)); - p = ctoupath( vol, sdir, oldname ); - if (!p) + free(oldunixname); + if ((oldunixname = strdup(ctoupath(vol, sdir, oldname))) == NULL) return AFPERR_PARAM; /* pathname too long */ -#endif /* HAVE_RENAMEAT */ +#endif /* HAVE_ATFUNCS */ path.st_valid = 0; - path.u_name = p; -#ifdef HAVE_RENAMEAT + path.u_name = oldunixname; + +#ifdef HAVE_ATFUNCS opened = of_findnameat(sdir_fd, &path); #else - opened = of_findname(&path); -#endif /* HAVE_RENAMEAT */ + opened = of_findname(vol, &path); +#endif /* HAVE_ATFUNCS */ + if (opened) { /* reuse struct adouble so it won't break locks */ adp = opened->of_ad; } } else { id = sdir->d_did; /* we already have the CNID */ - p = ctoupath( vol, sdir->d_parent, oldname ); - if (!p) { + if ((oldunixname = strdup(ctoupath( vol, dirlookup(vol, sdir->d_pdid), oldname))) == NULL) return AFPERR_PARAM; - } adflags = ADFLAGS_DIR; } - /* - * p now points to either + * oldunixname now points to either * a) full pathname of the source fs object (if renameat is not available) * b) the oldname (renameat is available) * we are in the dest folder so we need to use - * a) p for ad_open + * a) oldunixname for ad_open * b) fchdir sdir_fd before eg ad_open or use *at functions where appropiate */ if (sdir_fd != -1) { if ((cwd_fd = open(".", O_RDONLY)) == -1) return AFPERR_MISC; - if (fchdir(sdir_fd) != 0) - return AFPERR_MISC; + if (fchdir(sdir_fd) != 0) { + rc = AFPERR_MISC; + goto exit; + } } - if (!ad_metadata(p, adflags, adp)) { - u_int16_t bshort; + if (!ad_metadata(oldunixname, adflags, adp)) { + uint16_t bshort; ad_getattr(adp, &bshort); - ad_close_metadata( adp); - if ((bshort & htons(ATTRBIT_NORENAME))) - return(AFPERR_OLOCK); + + ad_close(adp, ADFLAGS_HF); + if (!(vol->v_ignattr & ATTRBIT_NORENAME) && (bshort & htons(ATTRBIT_NORENAME))) { + rc = AFPERR_OLOCK; + goto exit; + } } if (sdir_fd != -1) { if (fchdir(cwd_fd) != 0) { LOG(log_error, logtype_afpd, "moveandrename: %s", strerror(errno) ); - return AFPERR_MISC; + rc = AFPERR_MISC; + goto exit; } } - if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))){ - return AFPERR_PARAM; + if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding(vol->v_obj)))){ + rc = AFPERR_PARAM; + goto exit; } path.u_name = upath; - st = &path.st; + st = &path.st; if (0 != (rc = check_name(vol, upath))) { - return rc; + goto exit; } + if (isdir) + LOG(log_debug, logtype_afpd, + "moveandrename(\"%s\" -> \"%s/%s\")", + oldunixname, bdata(curdir->d_fullpath), upath); + else + LOG(log_debug, logtype_afpd, + "moveandrename(\"%s/%s\" -> \"%s/%s\")", + bdata(sdir->d_fullpath), oldunixname, bdata(curdir->d_fullpath), upath); + /* source == destination. we just silently accept this. */ - if ((!isdir && curdir == sdir) || (isdir && curdir == sdir->d_parent)) { - if (strcmp(oldname, newname) == 0) - return AFP_OK; + if ((!isdir && curdir == sdir) || (isdir && curdir->d_did == sdir->d_pdid)) { + if (strcmp(oldname, newname) == 0) { + rc = AFP_OK; + goto exit; + } - if (stat(upath, st) == 0 || caseenumerate(vol, &path, curdir) == 0) { - if (!stat(p, &nst) && !(nst.st_dev == st->st_dev && nst.st_ino == st->st_ino) ) { + if (stat(upath, st) == 0) { + if (!stat(oldunixname, &nst) && !(nst.st_dev == st->st_dev && nst.st_ino == st->st_ino) ) { /* not the same file */ - return AFPERR_EXIST; + rc = AFPERR_EXIST; + goto exit; } errno = 0; } - } else if (stat(upath, st ) == 0 || caseenumerate(vol, &path, curdir) == 0) - return AFPERR_EXIST; + } else if (stat(upath, st ) == 0) { + rc = AFPERR_EXIST; + goto exit; + } if ( !isdir ) { path.st_valid = 1; path.st_errno = errno; - if (of_findname(&path)) { + if (of_findname(vol, &path)) { rc = AFPERR_EXIST; /* was AFPERR_BUSY; */ } else { - rc = renamefile(vol, sdir_fd, p, upath, newname, adp ); + rc = renamefile(vol, curdir, sdir_fd, oldunixname, upath, newname, adp ); if (rc == AFP_OK) of_rename(vol, opened, sdir, oldname, curdir, newname); } } else { - rc = renamedir(vol, sdir_fd, p, upath, sdir, curdir, newname); + rc = renamedir(vol, sdir_fd, oldunixname, upath, sdir, curdir, newname); } if ( rc == AFP_OK && id ) { /* renaming may have moved the file/dir across a filesystem */ - if (stat(upath, st) < 0) - return AFPERR_MISC; + if (stat(upath, st) < 0) { + rc = AFPERR_MISC; + goto exit; + } + + /* Remove it from the cache */ + struct dir *cacheddir = dircache_search_by_did(vol, id); + if (cacheddir) { + LOG(log_warning, logtype_afpd,"Still cached: \"%s/%s\"", getcwdpath(), upath); + (void)dir_remove(vol, cacheddir); + } + + /* Fixup adouble info */ + if (!ad_metadata(upath, adflags, adp)) { + ad_setid(adp, st->st_dev, st->st_ino, id, curdir->d_did, vol->v_stamp); + ad_flush(adp); + ad_close(adp, ADFLAGS_HF); + } /* fix up the catalog entry */ + AFP_CNID_START("cnid_update"); cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath)); + AFP_CNID_DONE(); + + /* Send FCE event */ + if (isdir) { + fce_register(obj, FCE_DIR_MOVE, fullpathname(upath), oldunixname); + } else { + bstring srcpath = bformat("%s/%s", bdata(sdir->d_fullpath), oldunixname); + fce_register(obj, FCE_FILE_MOVE, fullpathname(upath), bdata(srcpath)); + bdestroy(srcpath); + } } +exit: + if (cwd_fd != -1) + close(cwd_fd); + if (oldunixname) + free(oldunixname); return rc; } /* -------------------------------------------- */ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { - struct vol *vol; - struct dir *sdir; + struct vol *vol; + struct dir *sdir; char *oldname, *newname; struct path *path; - u_int32_t did; + uint32_t did; int plen; - u_int16_t vid; + uint16_t vid; int isdir = 0; int rc; @@ -479,12 +437,12 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size memcpy( &did, ibuf, sizeof( did )); ibuf += sizeof( did ); if (NULL == ( sdir = dirlookup( vol, did )) ) { - return afp_errno; + return afp_errno; } /* source pathname */ if (NULL == ( path = cname( vol, sdir, &ibuf )) ) { - return get_afp_errno(AFPERR_NOOBJ); + return get_afp_errno(AFPERR_NOOBJ); } sdir = curdir; @@ -499,14 +457,14 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size } } else { - if ( sdir->d_parent == NULL ) { /* root directory */ + if ( sdir->d_did == DIRDID_ROOT ) { /* root directory */ return( AFPERR_NORENAME ); } /* move to destination dir */ - if ( movecwd( vol, sdir->d_parent ) < 0 ) { + if ( movecwd( vol, dirlookup(vol, sdir->d_pdid) ) < 0 ) { return afp_errno; } - strcpy(oldname, sdir->d_m_name); + memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) +1); } /* another place where we know about the path type */ @@ -518,7 +476,7 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size return AFP_OK; /* newname == oldname same dir */ } - rc = moveandrename(vol, sdir, -1, oldname, newname, isdir); + rc = moveandrename(obj, vol, sdir, -1, oldname, newname, isdir); if ( rc == AFP_OK ) { setvoltime(obj, vol ); } @@ -526,15 +484,93 @@ int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size return( rc ); } +/* + * Recursivley delete vetoed files and directories if the volume option is set + * + * @param vol (r) volume handle + * @param upath (r) path of directory + * + * If the volume option delete veto files is set, this function recursively scans the + * directory "upath" for vetoed files and tries deletes these, the it will try to delete + * the directory. That may fail if the directory contains normal files that aren't vetoed. + * + * @returns 0 if the directory upath and all of its contents were deleted, otherwise -1. + * If the volume option is not set it returns -1. + */ +int delete_vetoed_files(struct vol *vol, const char *upath, bool in_vetodir) +{ + EC_INIT; + DIR *dp = NULL; + struct dirent *de; + struct stat sb; + int pwd = -1; + bool vetoed; + + if (!(vol->v_flags & AFPVOL_DELVETO)) + return -1; + + EC_NEG1( pwd = open(".", O_RDONLY)); + EC_ZERO( chdir(upath) ); + EC_NULL( dp = opendir(".") ); + + while ((de = readdir(dp))) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + + if (stat(de->d_name, &sb) != 0) { + LOG(log_error, logtype_afpd, "delete_vetoed_files(\"%s/%s\"): %s", + upath, de->d_name, strerror(errno)); + EC_EXIT_STATUS(AFPERR_DIRNEMPT); + } + + if (in_vetodir || veto_file(vol->v_veto, de->d_name)) + vetoed = true; + else + vetoed = false; + + if (vetoed) { + LOG(log_debug, logtype_afpd, "delete_vetoed_files(\"%s/%s\"): deleting vetoed file", + upath, de->d_name); + switch (sb.st_mode & S_IFMT) { + case S_IFDIR: + /* recursion */ + EC_ZERO( delete_vetoed_files(vol, de->d_name, vetoed)); + break; + case S_IFREG: + case S_IFLNK: + EC_ZERO( netatalk_unlink(de->d_name) ); + break; + default: + break; + } + } + } + + EC_ZERO_LOG( fchdir(pwd) ); + pwd = -1; + EC_ZERO_LOG( rmdir(upath) ); + +EC_CLEANUP: + if (dp) + closedir(dp); + if (pwd != -1) { + if (fchdir(pwd) != 0) + ret = -1; + } + + EC_EXIT; +} + /* ------------------------------- */ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { - struct vol *vol; - struct dir *dir; - struct path *s_path; - char *upath; - int did, rc; - u_int16_t vid; + struct vol *vol; + struct dir *dir; + struct path *s_path; + char *upath; + int did; + int rc = AFP_OK; + uint16_t vid; *rbuflen = 0; ibuf += 2; @@ -550,30 +586,62 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size memcpy( &did, ibuf, sizeof( did )); ibuf += sizeof( int ); + if (NULL == ( dir = dirlookup( vol, did )) ) { - return afp_errno; + return afp_errno; } if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) { - return get_afp_errno(AFPERR_NOOBJ); + return get_afp_errno(AFPERR_NOOBJ); } upath = s_path->u_name; - if ( path_isadir( s_path) ) { - if (*s_path->m_name != '\0') { - rc = AFPERR_ACCESS; - } - else - { - - /* we have to cache this, the structs are lost in deletcurdir*/ - /* but we need the positive returncode to send our event */ - char dname[256]; - strncpy(dname, curdir->d_u_name, 255 ); + if (path_isadir(s_path)) { + if (*s_path->m_name != '\0' || curdir->d_did == DIRDID_ROOT) { + if (vol->v_adouble == AD_VERSION2) + return AFPERR_ACCESS; + if (*s_path->m_name == '\0' && curdir->d_did == DIRDID_ROOT) + return AFPERR_ACCESS; + if (rmdir(upath) != 0) { + switch (errno) { + case ENOTEMPTY: + if (delete_vetoed_files(vol, upath, false) != 0) + return AFPERR_DIRNEMPT; + break; + case EACCES: + return AFPERR_ACCESS; + default: + return AFPERR_MISC; + } + } + struct dir *deldir; + cnid_t delcnid = CNID_INVALID; + if ((deldir = dircache_search_by_name(vol, curdir, upath, strlen(upath)))) { + delcnid = deldir->d_did; + dir_remove(vol, deldir); + } + if (delcnid == CNID_INVALID) { + AFP_CNID_START("cnid_get"); + delcnid = cnid_get(vol->v_cdb, curdir->d_did, upath, strlen(upath)); + AFP_CNID_DONE(); + } + if (delcnid != CNID_INVALID) { + AFP_CNID_START("cnid_delete"); + cnid_delete(vol->v_cdb, delcnid); + AFP_CNID_DONE(); + } + fce_register(obj, FCE_DIR_DELETE, fullpathname(upath), NULL); + } else { + /* we have to cache this, the structs are lost in deletcurdir*/ + /* but we need the positive returncode to send our event */ + bstring dname; + if ((dname = bstrcpy(curdir->d_u_name)) == NULL) + return AFPERR_MISC; if ((rc = deletecurdir(vol)) == AFP_OK) - fce_register_delete_dir(dname); + fce_register(obj, FCE_DIR_DELETE, fullpathname(cfrombstr(dname)), NULL); + bdestroy(dname); } - } else if (of_findname(s_path)) { + } else if (of_findname(vol, s_path)) { rc = AFPERR_BUSY; } else { /* it's a file st_valid should always be true @@ -583,12 +651,22 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size if (s_path->st_valid && s_path->st_errno == ENOENT) { rc = AFPERR_NOOBJ; } else { - if ((rc = deletefile(vol, -1, upath, 1)) === AFP_OK) - fce_register_delete_file( s_path ); + if ((rc = deletefile(vol, -1, upath, 1)) == AFP_OK) { + fce_register(obj, FCE_FILE_DELETE, fullpathname(upath), NULL); + if (vol->v_tm_used < s_path->st.st_size) + vol->v_tm_used = 0; + else + vol->v_tm_used -= s_path->st.st_size; + } + struct dir *cachedfile; + if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath)))) { + dircache_remove(vol, cachedfile, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); + dir_free(cachedfile); + } } } if ( rc == AFP_OK ) { - curdir->offcnt--; + curdir->d_offcnt--; setvoltime(obj, vol ); } @@ -597,67 +675,51 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size /* ------------------------ */ char *absupath(const struct vol *vol, struct dir *dir, char *u) { - struct dir *d; - static char path[ MAXPATHLEN + 1]; - char *p; - int len; + static char pathbuf[MAXPATHLEN + 1]; + bstring path; - if (u == NULL) + if (u == NULL || dir == NULL || vol == NULL) return NULL; - - p = path + sizeof( path ) - 1; - *p = '\0'; - len = strlen( u ); - p -= len; - memcpy( p, u, len ); - if (dir) for ( d = dir; d->d_parent; d = d->d_parent ) { - u = d->d_u_name; - len = strlen( u ); - if (p -len -1 < path) { - /* FIXME - rather rare so LOG error and/or client message ? - */ - return NULL; - } - *--p = '/'; - p -= len; - memcpy( p, u, len ); - } - len = strlen( vol->v_path ); - if (p -len -1 < path) { + + if ((path = bstrcpy(dir->d_fullpath)) == NULL) + return NULL; + if (bcatcstr(path, "/") != BSTR_OK) + return NULL; + if (bcatcstr(path, u) != BSTR_OK) + return NULL; + if (path->slen > MAXPATHLEN) { + bdestroy(path); return NULL; } - *--p = '/'; - p -= len; - memcpy( p, vol->v_path, len ); - return( p ); + LOG(log_debug, logtype_afpd, "absupath: %s", cfrombstr(path)); + + strncpy(pathbuf, cfrombstr(path), blength(path) + 1); + bdestroy(path); + + return(pathbuf); } -/* ------------------------ - * FIXME dir could be NULL -*/ char *ctoupath(const struct vol *vol, struct dir *dir, char *name) { - return absupath(vol, dir, mtoupath(vol, name, dir->d_did, utf8_encoding())); + if (vol == NULL || dir == NULL || name == NULL) + return NULL; + return absupath(vol, dir, mtoupath(vol, name, dir->d_did, utf8_encoding(vol->v_obj))); } /* ------------------------- */ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { - struct vol *vol; - struct dir *sdir, *ddir; + struct vol *vol; + struct dir *sdir, *ddir; int isdir; - char *oldname, *newname; + char *oldname, *newname; struct path *path; - int did; - int pdid; + int did; + int pdid; int plen; - u_int16_t vid; + uint16_t vid; int rc; -#ifdef DROPKLUDGE - int retvalue; -#endif /* DROPKLUDGE */ int sdir_fd = -1; @@ -685,13 +747,13 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U /* source pathname */ if (NULL == ( path = cname( vol, sdir, &ibuf )) ) { - return get_afp_errno(AFPERR_NOOBJ); + return get_afp_errno(AFPERR_NOOBJ); } sdir = curdir; newname = obj->newtmp; oldname = obj->oldtmp; - + isdir = path_isadir(path); if ( *path->m_name != '\0' ) { if (isdir) { @@ -699,10 +761,10 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U } strcpy(oldname, path->m_name); /* an extra copy for of_rename */ } else { - strcpy(oldname, sdir->d_m_name); + memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) + 1); } -#ifdef HAVE_RENAMEAT +#ifdef HAVE_ATFUNCS if ((sdir_fd = open(".", O_RDONLY)) == -1) return AFPERR_MISC; #endif @@ -733,39 +795,29 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U } /* This does the work */ - rc = moveandrename(vol, sdir, sdir_fd, oldname, newname, isdir); + LOG(log_debug, logtype_afpd, "afp_move(oldname:'%s', newname:'%s', isdir:%u)", + oldname, newname, isdir); + rc = moveandrename(obj, vol, sdir, sdir_fd, oldname, newname, isdir); if ( rc == AFP_OK ) { - char *upath = mtoupath(vol, newname, pdid, utf8_encoding()); - + char *upath = mtoupath(vol, newname, pdid, utf8_encoding(obj)); + if (NULL == upath) { rc = AFPERR_PARAM; goto exit; } - curdir->offcnt++; - sdir->offcnt--; -#ifdef DROPKLUDGE - if (vol->v_flags & AFPVOL_DROPBOX) { - /* FIXME did is not always the source id */ - if ((retvalue=matchfile2dirperms (upath, vol, did)) != AFP_OK) { - rc = retvalue; - goto exit; - } - } - else -#endif /* DROPKLUDGE */ - /* if unix priv don't try to match perm with dest folder */ - if (!isdir && !vol_unix_priv(vol)) { - int admode = ad_mode("", 0777) | vol->v_fperm; + /* if unix priv don't try to match perm with dest folder */ + if (!isdir && !vol_unix_priv(vol)) { + int admode = ad_mode("", 0777) | vol->v_fperm; - setfilmode(upath, admode, NULL, vol->v_umask); - vol->vfs->vfs_setfilmode(vol, upath, admode, NULL); - } + setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL); + vol->vfs->vfs_setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL); + } setvoltime(obj, vol ); } exit: -#ifdef HAVE_RENAMEAT +#ifdef HAVE_ATFUNCS if (sdir_fd != -1) close(sdir_fd); #endif @@ -780,8 +832,8 @@ int veto_file(const char*veto_str, const char*path) * otherwise, 0 is returned. */ { - int i; /* index to veto_str */ - int j; /* index to path */ + int i; /* index to veto_str */ + int j; /* index to path */ if ((veto_str == NULL) || (path == NULL)) return 0; @@ -796,7 +848,7 @@ int veto_file(const char*veto_str, const char*path) } else { if (veto_str[i] != path[j]) { while ((veto_str[i] != '/') - && (veto_str[i] != '\0')) + && (veto_str[i] != '\0')) i++; j = 0; continue;