#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <grp.h>
#include <pwd.h>
#include <sys/param.h>
#include <atalk/unix.h>
#include <atalk/bstrlib.h>
#include <atalk/bstradd.h>
+#include <atalk/errchk.h>
+#include <atalk/globals.h>
+#include <atalk/fce_api.h>
#include "directory.h"
#include "dircache.h"
#include "fork.h"
#include "file.h"
#include "filedir.h"
-#include "globals.h"
#include "unix.h"
#include "mangle.h"
#include "hash.h"
*/
static int diroffcnt(struct dir *dir, struct stat *st)
{
- return st->st_ctime == dir->ctime;
+ return st->st_ctime == dir->d_ctime;
}
/* --------------------- */
{
static char temp[ MAXPATHLEN + 1];
char *t;
- cnid_t fileid;
+ cnid_t fileid = 0;
if (afp_version >= 30) {
if (toUTF8) {
return param;
}
+/*!
+ * Resolve struct dir for an absolute path
+ *
+ * Given a path like "/Volumes/volume/dir/subdir" in a volume "/Volumes/volume" return
+ * a pointer to struct dir of "subdir".
+ * 1. Remove volue path from absolute path
+ * 2. start path
+ * 3. loop through all elements of the remaining path from 1.
+ * 4. we only allow dirs
+ * 5. search dircache
+ * 6. if not found in the dircache query the CNID database for the DID
+ * 7. and use dirlookup to resolve the DID to a it's struct dir *
+ *
+ * @param vol (r) volume the path is in, must be known
+ * @param path (r) absoule path
+ *
+ * @returns pointer to struct dir or NULL on error
+ */
+struct dir *dirlookup_bypath(const struct vol *vol, const char *path)
+{
+ EC_INIT;
+
+ struct dir *dir = NULL;
+ cnid_t cnid, did;
+ bstring rpath = NULL;
+ bstring statpath = NULL;
+ struct bstrList *l = NULL;
+ struct stat st;
+
+ cnid = htonl(2);
+ dir = vol->v_root;
+
+ LOG(log_debug, logtype_afpd, "dirlookup_bypath(\"%s\")", path);
+
+ if (strcmp(vol->v_path, path) == 0)
+ return dir;
+
+ EC_NULL(rpath = rel_path_in_vol(path, vol->v_path)); /* 1. */
+
+ LOG(log_debug, logtype_afpd, "dirlookup_bypath: rpath: \"%s\"", cfrombstr(rpath));
+
+ EC_NULL(statpath = bfromcstr(vol->v_path)); /* 2. */
+
+ l = bsplit(rpath, '/');
+ for (int i = 0; i < l->qty ; i++) { /* 3. */
+ did = cnid;
+ EC_ZERO(bcatcstr(statpath, "/"));
+ EC_ZERO(bconcat(statpath, l->entry[i]));
+
+ LOG(log_debug, logtype_afpd, "dirlookup_bypath: statpath: \"%s\"", cfrombstr(statpath));
+
+ EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st),
+ "lstat(rpath: %s, elem: %s): %s: %s",
+ cfrombstr(rpath), cfrombstr(l->entry[i]),
+ cfrombstr(statpath), strerror(errno));
+
+ if (!(S_ISDIR(st.st_mode))) /* 4. */
+ EC_FAIL;
+
+ if ((dir = dircache_search_by_name(vol, /* 5. */
+ dir,
+ cfrombstr(l->entry[i]),
+ blength(l->entry[i]))) == NULL) {
+
+ if ((cnid = cnid_add(vol->v_cdb, /* 6. */
+ &st,
+ did,
+ cfrombstr(l->entry[i]),
+ blength(l->entry[i]),
+ 0)) == CNID_INVALID)
+ EC_FAIL;
+
+ if ((dir = dirlookup(vol, cnid)) == NULL) /* 7. */
+ EC_FAIL;
+ }
+ }
+
+EC_CLEANUP:
+ bdestroy(rpath);
+ bstrListDestroy(l);
+ bdestroy(statpath);
+ if (ret != 0)
+ return NULL;
+
+ LOG(log_debug, logtype_afpd, "dirlookup_bypath: result: \"%s\"",
+ cfrombstr(dir->d_fullpath));
+
+ return dir;
+}
+
/*!
* @brief Resolve a DID
*
* Resolve a DID, allocate a struct dir for it
* 1. Check for special CNIDs 0 (invalid), 1 and 2.
* 2a. Check if the DID is in the cache.
- * 2b. Check if it's really a dir (d_fullpath != NULL) because we cache files too.
+ * 2b. Check if it's really a dir because we cache files too.
* 3. If it's not in the cache resolve it via the database.
* 4. Build complete server-side path to the dir.
* 5. Check if it exists and is a directory.
* @param did (r) DID to resolve
*
* @returns pointer to struct dir
- *
- * @note FIXME: OSX calls it with bogus id, ie file ID not folder ID,
- * and we are really bad in this case.
*/
struct dir *dirlookup(const struct vol *vol, cnid_t did)
{
int utf8;
int err = 0;
- LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {start}", ntohl(did));
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): START", ntohl(did));
/* check for did 0, 1 and 2 */
if (did == 0 || vol == NULL) { /* 1 */
afp_errno = AFPERR_PARAM;
- return NULL;
+ ret = NULL;
+ goto exit;
} else if (did == DIRDID_ROOT_PARENT) {
rootParent.d_vid = vol->v_vid;
- return (&rootParent);
+ ret = &rootParent;
+ goto exit;
} else if (did == DIRDID_ROOT) {
- return vol->v_root;
+ ret = vol->v_root;
+ goto exit;
}
/* Search the cache */
if ((ret = dircache_search_by_did(vol, did)) != NULL) { /* 2a */
- if (ret->d_fullpath == NULL) { /* 2b */
+ if (ret->d_flags & DIRF_ISFILE) { /* 2b */
afp_errno = AFPERR_BADTYPE;
- return NULL;
+ ret = NULL;
+ goto exit;
}
if (lstat(cfrombstr(ret->d_fullpath), &st) != 0) {
- LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {lstat: %s}", ntohl(did), strerror(errno));
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u, path: \"%s\"): lstat: %s",
+ ntohl(did), cfrombstr(ret->d_fullpath), strerror(errno));
switch (errno) {
case ENOENT:
case ENOTDIR:
/* It's not there anymore, so remove it */
- LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {calling dir_remove()}", ntohl(did));
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): calling dir_remove", ntohl(did));
dir_remove(vol, ret);
afp_errno = AFPERR_NOOBJ;
- return NULL;
+ ret = NULL;
+ goto exit;
default:
- return ret;
+ ret = ret;
+ goto exit;
}
/* DEADC0DE */
- return NULL;
+ ret = NULL;
+ goto exit;
}
- return ret;
+ ret = ret;
+ goto exit;
}
utf8 = utf8_encoding();
/* Get it from the database */
cnid = did;
- if ( (upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL
- || (upath = strdup(upath)) == NULL) { /* 3 */
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): querying CNID database", ntohl(did));
+ if ((upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL) {
+ afp_errno = AFPERR_NOOBJ;
+ err = 1;
+ goto exit;
+ }
+ if ((upath = strdup(upath)) == NULL) { /* 3 */
afp_errno = AFPERR_NOOBJ;
err = 1;
goto exit;
* - DIRDID_ROOT is hit
* - a cached entry is found
*/
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): recursion for did: %u",
+ ntohl(did), ntohl(pdid));
if ((pdir = dirlookup(vol, pdid)) == NULL) {
err = 1;
goto exit;
}
/* stat it and check if it's a dir */
- LOG(log_debug, logtype_afpd, "dirlookup: {stating %s}", cfrombstr(fullpath));
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): stating \"%s\"",
+ ntohl(did), cfrombstr(fullpath));
- if (stat(cfrombstr(fullpath), &st) != 0) { /* 5a */
+ if (lstat(cfrombstr(fullpath), &st) != 0) { /* 5a */
switch (errno) {
case ENOENT:
afp_errno = AFPERR_NOOBJ;
}
/* Create struct dir */
- if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath, st.st_ctime)) == NULL) { /* 6 */
+ if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath, &st)) == NULL) { /* 6 */
LOG(log_error, logtype_afpd, "dirlookup(did: %u) {%s, %s}: %s", ntohl(did), mpath, upath, strerror(errno));
err = 1;
goto exit;
}
/* Add it to the cache only if it's a dir */
- if (dircache_add(ret) != 0) { /* 7 */
+ if (dircache_add(vol, ret) != 0) { /* 7 */
err = 1;
goto exit;
}
- LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {end: did:%u, path:'%s'}",
- ntohl(did), ntohl(pdid), cfrombstr(ret->d_fullpath));
-
exit:
if (upath) free(upath);
if (err) {
ret = NULL;
}
}
+ if (ret)
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): RESULT: pdid: %u, path: \"%s\"",
+ ntohl(ret->d_did), ntohl(ret->d_pdid), cfrombstr(ret->d_fullpath));
+
return ret;
}
DIR *dp;
struct dirent *de;
int ret;
- static u_int32_t did = 0;
+ static uint32_t did = 0;
static char cname[MAXPATHLEN];
static char lname[MAXPATHLEN];
ucs2_t u2_path[MAXPATHLEN];
* @param vol (r) pointer to struct vol
* @param pdid (r) Parent CNID
* @param did (r) CNID
- * @param path (r) Full unix path to dir or NULL for files
- * @param ctime (r) st_ctime from stat
+ * @param path (r) Full unix path to object
+ * @param st (r) struct stat of object
*
* @returns pointer to new struct dir or NULL on error
*
cnid_t pdid,
cnid_t did,
bstring path,
- time_t ctime)
+ struct stat *st)
{
struct dir *dir;
dir->d_pdid = pdid;
dir->d_vid = vol->v_vid;
dir->d_fullpath = path;
- dir->ctime_dircache = ctime;
+ dir->dcache_ctime = st->st_ctime;
+ dir->dcache_ino = st->st_ino;
+ if (!S_ISDIR(st->st_mode))
+ dir->d_flags = DIRF_ISFILE;
+ dir->d_rights_cache = 0xffffffff;
return dir;
}
AFP_ASSERT(path);
AFP_ASSERT(len > 0);
- if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name), path->st.st_ctime)) != NULL) {
+ if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name))) != NULL) {
/* there's a stray entry in the dircache */
LOG(log_debug, logtype_afpd, "dir_add(did:%u,'%s/%s'): {stray cache entry: did:%u,'%s', removing}",
ntohl(dir->d_did), cfrombstr(dir->d_fullpath), path->u_name,
}
/* get_id needs adp for reading CNID from adouble file */
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if ((ad_open(&ad, path->u_name, ADFLAGS_HF | ADFLAGS_DIR)) == 0) /* 1 */
+ ad_init(&ad, vol);
+ if ((ad_open(&ad, path->u_name, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDONLY)) == 0) /* 1 */
adp = &ad;
/* Get CNID */
}
if (adp)
- ad_close_metadata(adp);
+ ad_close(adp, ADFLAGS_HF);
/* Get macname from unixname */
if (path->m_name == NULL) {
if ((path->m_name = utompath(vol, path->u_name, id, utf8_encoding())) == NULL) {
+ LOG(log_error, logtype_afpd, "dir_add(\"%s\"): can't assign macname", path->u_name);
err = 2;
goto exit;
}
}
/* Allocate and initialize struct dir */
- if ((cdir = dir_new( path->m_name, path->u_name, vol, dir->d_did, id, fullpath, path->st.st_ctime)) == NULL) { /* 3 */
+ if ((cdir = dir_new(path->m_name,
+ path->u_name,
+ vol,
+ dir->d_did,
+ id,
+ fullpath,
+ &path->st)) == NULL) { /* 3 */
err = 4;
goto exit;
}
- if ((dircache_add(cdir)) != 0) { /* 4 */
+ if ((dircache_add(vol, cdir)) != 0) { /* 4 */
LOG(log_error, logtype_afpd, "dir_add: fatal dircache error: %s", cfrombstr(fullpath));
exit(EXITERR_SYS);
}
cfrombstr(dir->d_u_name), path->u_name, err);
if (adp)
- ad_close_metadata(adp);
+ ad_close(adp, ADFLAGS_HF);
if (!cdir && fullpath)
bdestroy(fullpath);
if (cdir)
* @brief Remove a dir from a cache and queue it for freeing
*
* 1. Check if the dir is locked or has opened forks
- * 2. If it's a request to remove curdir, just chdir to volume root
- * 3. Remove it from the cache
- * 4. Queue it for removal
+ * 2. Remove it from the cache
+ * 3. Queue it for removal
+ * 4. If it's a request to remove curdir, mark curdir as invalid
* 5. Mark it as invalid
*
* @param (r) pointer to struct vol
if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT)
return 0;
- if (dir->d_flags & DIRF_CACHELOCK) { /* 1 */
- LOG(log_warning, logtype_afpd, "dir_remove(did:%u,'%s'): dir is locked",
- ntohl(dir->d_did), cfrombstr(dir->d_u_name));
- return 0;
- }
-
- if (curdir == dir) { /* 2 */
- if (movecwd(vol, vol->v_root) < 0) {
- LOG(log_error, logtype_afpd, "dir_remove: can't chdir to : %s", vol->v_root);
- }
- }
-
LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}",
ntohl(dir->d_did), cfrombstr(dir->d_u_name));
- dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 3 */
- enqueue(invalid_dircache_entries, dir); /* 4 */
+ dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 2 */
+ enqueue(invalid_dircache_entries, dir); /* 3 */
+
+ if (curdir == dir) /* 4 */
+ curdir = NULL;
+
dir->d_did = CNID_INVALID; /* 5 */
+
return 0;
}
+#if 0 /* unused */
/*!
* @brief Modify a struct dir, adjust cache
*
dir->d_m_name_ucs2 = NULL;
/* Re-add it to the cache */
- if ((dircache_add(dir)) != 0) {
+ if ((dircache_add(vol, dir)) != 0) {
dircache_dump();
AFP_PANIC("dir_modify");
}
return ret;
}
+#endif
/*!
* @brief Resolve a catalog node name path
struct dir *cdir;
char *data, *p;
int len;
- u_int32_t hint;
- u_int16_t len16;
+ uint32_t hint;
+ uint16_t len16;
int size = 0;
int toUTF8 = 0;
/* 6*/
for ( p = path; *data != 0 && len > 0; len-- ) {
*p++ = *data++;
- if (p > &path[ MAXPATHLEN]) {
+ if (p > &path[UTF8FILELEN_EARLY]) { /* FIXME safeguard, limit of early Mac OS X */
afp_errno = AFPERR_PARAM;
return NULL;
}
/* Search the cache */
int unamelen = strlen(ret.u_name);
- cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen, ret.st.st_ctime); /* 14 */
+ cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen); /* 14 */
if (cdir == NULL) {
/* Not in cache, create one */
if ((cdir = dir_add(vol, dir, &ret, unamelen)) == NULL) { /* 15 */
AFP_ASSERT(vol);
AFP_ASSERT(dir);
- LOG(log_maxdebug, logtype_afpd, "movecwd(curdir:'%s', cwd:'%s')",
- cfrombstr(curdir->d_fullpath), getcwdpath());
+ LOG(log_maxdebug, logtype_afpd, "movecwd: from: curdir:\"%s\", cwd:\"%s\"",
+ curdir ? cfrombstr(curdir->d_fullpath) : "INVALID", getcwdpath());
- if ( dir == curdir)
- return( 0 );
if (dir->d_did == DIRDID_ROOT_PARENT) {
curdir = &rootParent;
return 0;
}
- LOG(log_debug, logtype_afpd, "movecwd(did:%u, '%s')",
+ LOG(log_debug, logtype_afpd, "movecwd(to: did: %u, \"%s\")",
ntohl(dir->d_did), cfrombstr(dir->d_fullpath));
if ((ret = lchdir(cfrombstr(dir->d_fullpath))) != 0 ) {
- LOG(log_debug, logtype_afpd, "movecwd('%s'): ret: %u, %s",
- cfrombstr(dir->d_fullpath), ret, strerror(errno));
+ LOG(log_debug, logtype_afpd, "movecwd(\"%s\"): %s",
+ cfrombstr(dir->d_fullpath), strerror(errno));
if (ret == 1) {
/* p is a symlink or getcwd failed */
afp_errno = AFPERR_BADTYPE;
if (!p)
return -1;
- accessmode(p, &ma, curdir, NULL);
+ accessmode(current_vol, p, &ma, curdir, NULL);
if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
return -1;
if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
{
struct maccess ma;
- accessmode(path->u_name, &ma, curdir, &path->st);
- if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
+ accessmode(current_vol, path->u_name, &ma, curdir, &path->st);
+
+ LOG(log_debug, logtype_afpd, "file_access(\"%s\"): mapped user mode: 0x%02x",
+ path->u_name, ma.ma_user);
+
+ if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE)) {
+ LOG(log_debug, logtype_afpd, "file_access(\"%s\"): write access denied", path->u_name);
return -1;
- if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
+ }
+ if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD)) {
+ LOG(log_debug, logtype_afpd, "file_access(\"%s\"): read access denied", path->u_name);
return -1;
+ }
return 0;
}
/* --------------------- */
-void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
+void setdiroffcnt(struct dir *dir, struct stat *st, uint32_t count)
{
- dir->offcnt = count;
- dir->ctime = st->st_ctime;
+ dir->d_offcnt = count;
+ dir->d_ctime = st->st_ctime;
dir->d_flags &= ~DIRF_CNID;
}
*/
int dirreenumerate(struct dir *dir, struct stat *st)
{
- return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
+ return st->st_ctime == dir->d_ctime && (dir->d_flags & DIRF_CNID);
}
/* ------------------------------
*/
int getdirparams(const struct vol *vol,
- u_int16_t bitmap, struct path *s_path,
+ uint16_t bitmap, struct path *s_path,
struct dir *dir,
char *buf, size_t *buflen )
{
struct adouble ad;
char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
int bit = 0, isad = 0;
- u_int32_t aint;
- u_int16_t ashort;
+ uint32_t aint;
+ uint16_t ashort;
int ret;
- u_int32_t utf8 = 0;
+ uint32_t utf8 = 0;
cnid_t pdid;
struct stat *st = &s_path->st;
char *upath = s_path->u_name;
(1 << DIRPBIT_BDATE) |
(1 << DIRPBIT_FINFO)))) {
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if ( !ad_metadata( upath, ADFLAGS_DIR, &ad) )
+ ad_init(&ad, vol);
+ if ( !ad_metadata( upath, ADFLAGS_DIR, &ad) ) {
isad = 1;
+ if (ad.ad_mdp->adf_flags & O_CREAT) {
+ /* We just created it */
+ if (s_path->m_name == NULL) {
+ if ((s_path->m_name = utompath(vol,
+ upath,
+ dir->d_did,
+ utf8_encoding())) == NULL) {
+ LOG(log_error, logtype_afpd,
+ "getdirparams(\"%s\"): can't assign macname",
+ cfrombstr(dir->d_fullpath));
+ return AFPERR_MISC;
+ }
+ }
+ ad_setname(&ad, s_path->m_name);
+ ad_setid( &ad,
+ s_path->st.st_dev,
+ s_path->st.st_ino,
+ dir->d_did,
+ dir->d_pdid,
+ vol->v_stamp);
+ ad_flush( &ad);
+ }
+ }
}
pdid = dir->d_pdid;
ashort = htons(ATTRBIT_INVISIBLE);
} else
ashort = 0;
- ashort |= htons(ATTRBIT_SHARED);
memcpy( data, &ashort, sizeof( ashort ));
data += sizeof( ashort );
break;
if (dir->d_m_name) /* root of parent can have a null name */
l_nameoff = data;
else
- memset(data, 0, sizeof(u_int16_t));
- data += sizeof( u_int16_t );
+ memset(data, 0, sizeof(uint16_t));
+ data += sizeof( uint16_t );
break;
case DIRPBIT_SNAME :
- memset(data, 0, sizeof(u_int16_t));
- data += sizeof( u_int16_t );
+ memset(data, 0, sizeof(uint16_t));
+ data += sizeof( uint16_t );
break;
case DIRPBIT_DID :
ashort = 0;
/* this needs to handle current directory access rights */
if (diroffcnt(dir, st)) {
- ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
+ ashort = (dir->d_offcnt > 0xffff)?0xffff:dir->d_offcnt;
}
else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
setdiroffcnt(dir, st, ret);
- ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
+ ashort = (dir->d_offcnt > 0xffff)?0xffff:dir->d_offcnt;
}
ashort = htons( ashort );
memcpy( data, &ashort, sizeof( ashort ));
break;
case DIRPBIT_ACCESS :
- accessmode( upath, &ma, dir , st);
+ accessmode(vol, upath, &ma, dir , st);
*data++ = ma.ma_user;
*data++ = ma.ma_world;
if (dir->d_m_name) /* root of parent can have a null name */
utf_nameoff = data;
else
- memset(data, 0, sizeof(u_int16_t));
- data += sizeof( u_int16_t );
+ memset(data, 0, sizeof(uint16_t));
+ data += sizeof( uint16_t );
aint = 0;
memcpy(data, &aint, sizeof( aint ));
data += sizeof( aint );
break;
case DIRPBIT_UNIXPR :
+ /* accessmode may change st_mode with ACLs */
+ accessmode(vol, upath, &ma, dir, st);
+
aint = htonl(st->st_uid);
memcpy( data, &aint, sizeof( aint ));
data += sizeof( aint );
memcpy( data, &aint, sizeof( aint ));
data += sizeof( aint );
- accessmode( upath, &ma, dir , st);
-
*data++ = ma.ma_user;
*data++ = ma.ma_world;
*data++ = ma.ma_group;
default :
if ( isad ) {
- ad_close_metadata( &ad );
+ ad_close(&ad, ADFLAGS_HF);
}
return( AFPERR_BITMAP );
}
data = set_name(vol, data, pdid, cfrombstr(dir->d_m_name), dir->d_did, utf8);
}
if ( isad ) {
- ad_close_metadata( &ad );
+ ad_close(&ad, ADFLAGS_HF);
}
*buflen = data - buf;
return( AFP_OK );
struct vol *vol;
struct dir *dir;
struct path *path;
- u_int16_t vid, bitmap;
- u_int32_t did;
+ uint16_t vid, bitmap;
+ uint32_t did;
int rc;
*rbuflen = 0;
}
/*
- * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
- *
* assume path == '\0' eg. it's a directory in canonical form
*/
-int setdirparams(struct vol *vol, struct path *path, u_int16_t d_bitmap, char *buf )
+int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *buf )
{
struct maccess ma;
struct adouble ad;
int bit, isad = 1;
int cdate, bdate;
int owner, group;
- u_int16_t ashort, bshort, oshort;
+ uint16_t ashort, bshort, oshort;
int err = AFP_OK;
int change_mdate = 0;
int change_parent_mdate = 0;
int newdate = 0;
- u_int16_t bitmap = d_bitmap;
+ uint16_t bitmap = d_bitmap;
u_char finder_buf[32];
- u_int32_t upriv;
+ uint32_t upriv;
mode_t mpriv = 0;
- u_int16_t upriv_bit = 0;
+ bool set_upriv = false, set_maccess = false;
+
+ LOG(log_debug, logtype_afpd, "setdirparams(%s)", path->u_name);
bit = 0;
upath = path->u_name;
buf += 32;
break;
case DIRPBIT_UID : /* What kind of loser mounts as root? */
- change_parent_mdate = 1;
memcpy( &owner, buf, sizeof(owner));
buf += sizeof( owner );
break;
case DIRPBIT_GID :
- change_parent_mdate = 1;
memcpy( &group, buf, sizeof( group ));
buf += sizeof( group );
break;
case DIRPBIT_ACCESS :
+ set_maccess = true;
change_mdate = 1;
- change_parent_mdate = 1;
ma.ma_user = *buf++;
ma.ma_world = *buf++;
ma.ma_group = *buf++;
ma.ma_owner = *buf++;
mpriv = mtoumode( &ma ) | vol->v_dperm;
- if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
- err = set_dir_errors(path, "setdirmode", errno);
- bitmap = 0;
- }
break;
/* Ignore what the client thinks we should do to the
ProDOS information block. Skip over the data and
break;
case DIRPBIT_UNIXPR :
if (vol_unix_priv(vol)) {
+ set_upriv = true;
memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
buf += sizeof( owner );
memcpy( &group, buf, sizeof( group ));
buf += sizeof( group );
change_mdate = 1;
- change_parent_mdate = 1;
memcpy( &upriv, buf, sizeof( upriv ));
buf += sizeof( upriv );
upriv = ntohl (upriv) | vol->v_dperm;
- if (dir_rx_set(upriv)) {
- /* maybe we are trying to set perms back */
- if ( setdirunixmode(vol, upath, upriv) < 0 ) {
- bitmap = 0;
- err = set_dir_errors(path, "setdirunixmode", errno);
- }
- }
- else {
- /* do it later */
- upriv_bit = 1;
- }
break;
}
/* fall through */
bitmap = bitmap>>1;
bit++;
}
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+ ad_init(&ad, vol);
- if (ad_open(&ad, upath, ADFLAGS_HF | ADFLAGS_DIR, O_CREAT, 0777) != 0) {
+ if (ad_open(&ad, upath, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) != 0) {
/*
* Check to see what we're trying to set. If it's anything
* but ACCESS, UID, or GID, give an error. If it's any of those
* note: we also don't need to worry about mdate. also, be quiet
* if we're using the noadouble option.
*/
+
if (!vol_noadouble(vol) && (d_bitmap &
~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
(1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
* Check to see if a create was necessary. If it was, we'll want
* to set our name, etc.
*/
- if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
+ if ( (ad_get_MD_flags( &ad ) & O_CREAT)) {
ad_setname(&ad, cfrombstr(curdir->d_m_name));
}
}
case DIRPBIT_FINFO :
if (isad) {
/* Fixes #2802236 */
- u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
+ uint16_t *fflags = (uint16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
*fflags &= htons(~FINDERINFO_ISHARED);
/* #2802236 end */
if ( dir->d_did == DIRDID_ROOT ) {
}
break;
case DIRPBIT_ACCESS :
- if (dir->d_did == DIRDID_ROOT) {
- setdeskmode(mpriv);
- if (!dir_rx_set(mpriv)) {
- /* we can't remove read and search for owner on volume root */
- err = AFPERR_ACCESS;
- goto setdirparam_done;
- }
- }
-
- if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
- err = set_dir_errors(path, "setdirmode", errno);
- goto setdirparam_done;
- }
break;
case DIRPBIT_PDINFO :
if (afp_version >= 30) {
}
break;
case DIRPBIT_UNIXPR :
- if (vol_unix_priv(vol)) {
- if (dir->d_did == DIRDID_ROOT) {
- if (!dir_rx_set(upriv)) {
- /* we can't remove read and search for owner on volume root */
- err = AFPERR_ACCESS;
- goto setdirparam_done;
- }
- setdeskowner( -1, ntohl(group) );
- setdeskmode( upriv );
- }
- if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
- err = set_dir_errors(path, "setdirowner", errno);
- goto setdirparam_done;
- }
-
- if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
- err = set_dir_errors(path, "setdirunixmode", errno);
- goto setdirparam_done;
- }
- }
- else {
+ if (!vol_unix_priv(vol)) {
err = AFPERR_BITMAP;
goto setdirparam_done;
}
ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_pdid, vol->v_stamp);
}
}
- ad_flush( &ad);
- ad_close_metadata( &ad);
+ if (ad_flush(&ad) != 0) {
+ switch (errno) {
+ case EACCES:
+ err = AFPERR_ACCESS;
+ break;
+ default:
+ err = AFPERR_MISC;
+ break;
+ }
+ }
+ ad_close(&ad, ADFLAGS_HF);
+ }
+
+ if (err == AFP_OK) {
+ if (set_maccess == true) {
+ if (dir->d_did == DIRDID_ROOT) {
+ setdeskmode(mpriv);
+ if (!dir_rx_set(mpriv)) {
+ /* we can't remove read and search for owner on volume root */
+ err = AFPERR_ACCESS;
+ goto setprivdone;
+ }
+ }
+ if (setdirmode(vol, upath, mpriv) < 0)
+ err = set_dir_errors(path, "setdirmode", errno);
+ }
+ if ((set_upriv == true) && vol_unix_priv(vol)) {
+ if (dir->d_did == DIRDID_ROOT) {
+ if (!dir_rx_set(upriv)) {
+ /* we can't remove read and search for owner on volume root */
+ err = AFPERR_ACCESS;
+ goto setprivdone;
+ }
+ setdeskowner(-1, ntohl(group));
+ setdeskmode(upriv);
+ }
+
+ if (setdirowner(vol, upath, -1, ntohl(group)) < 0) {
+ err = set_dir_errors(path, "setdirowner", errno);
+ goto setprivdone;
+ }
+
+
+ if (setdirunixmode(vol, upath, upriv) < 0)
+ err = set_dir_errors(path, "setdirunixmode", errno);
+ }
}
+setprivdone:
if (change_parent_mdate && dir->d_did != DIRDID_ROOT
&& gettimeofday(&tv, NULL) == 0) {
if (movecwd(vol, dirlookup(vol, dir->d_pdid)) == 0) {
/* should we reset curdir ?*/
}
}
-
return err;
}
int dfd;
struct vol *vol;
struct dir *dir;
- u_int32_t did;
- u_int16_t vid;
+ uint32_t did;
+ uint16_t vid;
*rbuflen = 0;
ibuf += 2;
struct dir *dir;
char *upath;
struct path *s_path;
- u_int32_t did;
- u_int16_t vid;
+ uint32_t did;
+ uint16_t vid;
int err;
*rbuflen = 0;
return AFPERR_MISC;
}
- curdir->offcnt++;
+ curdir->d_offcnt++;
if ((dir = dir_add(vol, curdir, s_path, strlen(s_path->u_name))) == NULL) {
return AFPERR_MISC;
return( AFPERR_PARAM );
}
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR, O_CREAT, 0777) < 0) {
+ ad_init(&ad, vol);
+ if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) < 0) {
if (vol_noadouble(vol))
goto createdir_done;
return( AFPERR_ACCESS );
ad_setname(&ad, s_path->m_name);
ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
- ad_flush( &ad);
- ad_close_metadata( &ad);
+ fce_register_new_dir(s_path);
+
+ ad_flush(&ad);
+ ad_close(&ad, ADFLAGS_HF);
createdir_done:
- memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
- *rbuflen = sizeof( u_int32_t );
+ memcpy( rbuf, &dir->d_did, sizeof( uint32_t ));
+ *rbuflen = sizeof( uint32_t );
setvoltime(obj, vol );
return( AFP_OK );
}
vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+ ad_init(&ad, vol);
- if (ad_open(&ad, dst, ADFLAGS_HF | ADFLAGS_DIR) == 0) {
+ if (ad_open(&ad, dst, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR) == 0) {
ad_setname(&ad, newname);
- ad_flush( &ad);
- ad_close_metadata( &ad);
+ ad_flush(&ad);
+ ad_close(&ad, ADFLAGS_HF);
}
return( AFP_OK );
{
struct dirent *de;
struct stat st;
- struct dir *fdir;
+ struct dir *fdir, *pdir;
DIR *dp;
struct adouble ad;
- u_int16_t ashort;
+ uint16_t ashort;
int err;
- if ( dirlookup(vol, curdir->d_pdid) == NULL ) {
+ if ((pdir = dirlookup(vol, curdir->d_pdid)) == NULL) {
return( AFPERR_ACCESS );
}
fdir = curdir;
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+ ad_init(&ad, vol);
/* we never want to create a resource fork here, we are going to delete it */
if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
ad_getattr(&ad, &ashort);
- ad_close_metadata(&ad);
+ ad_close(&ad, ADFLAGS_HF);
if ((ashort & htons(ATTRBIT_NODELETE))) {
return AFPERR_OLOCK;
}
}
err = vol->vfs->vfs_deletecurdir(vol);
if (err) {
+ LOG(log_error, logtype_afpd, "deletecurdir: error deleting .AppleDouble in \"%s\"",
+ curdir->d_fullpath);
return err;
}
/* bail if it's not a symlink */
if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
+ LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): not empty",
+ curdir->d_fullpath);
closedir(dp);
return AFPERR_DIRNEMPT;
}
}
}
- if ( movecwd(vol, dirlookup(vol, curdir->d_pdid)) < 0 ) {
+ if (movecwd(vol, pdir) < 0) {
err = afp_errno;
goto delete_done;
}
+ LOG(log_debug, logtype_afpd, "deletecurdir: moved to \"%s\"",
+ cfrombstr(curdir->d_fullpath));
+
err = netatalk_rmdir_all_errors(-1, cfrombstr(fdir->d_u_name));
if ( err == AFP_OK || err == AFPERR_NOOBJ) {
cnid_delete(vol->v_cdb, fdir->d_did);
dir_remove( vol, fdir );
+ } else {
+ LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): netatalk_rmdir_all_errors error",
+ cfrombstr(curdir->d_fullpath));
}
+
delete_done:
if (dp) {
/* inode is used as key for cnid.
struct passwd *pw;
struct group *gr;
char *name;
- u_int32_t id;
+ uint32_t id;
int len, sfunc;
int utf8 = 0;
rbuf += sizeof( id );
*rbuflen = 2 * sizeof( id );
break;
- case UUID_LOCAL:
- free(name);
- return (AFPERR_NOITEM);
default:
return AFPERR_MISC;
}
len = strlen( name );
if (utf8) {
- u_int16_t tp = htons(len);
+ uint16_t tp = htons(len);
memcpy(rbuf, &tp, sizeof(tp));
rbuf += sizeof(tp);
*rbuflen += 2;
struct passwd *pw;
struct group *gr;
int len, sfunc;
- u_int32_t id;
- u_int16_t ulen;
+ uint32_t id;
+ uint16_t ulen;
ibuf++;
sfunc = (unsigned char) *ibuf++;
case 2 : /* unicode */
case 4 :
- LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
+ LOG(log_debug, logtype_afpd, "afp_mapname: getgrnam for name: %s",ibuf);
if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
return( AFPERR_NOITEM );
}
id = gr->gr_gid;
- LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
+ LOG(log_debug, logtype_afpd, "afp_mapname: getgrnam for name: %s -> id: %d",ibuf, id);
id = htonl(id);
memcpy( rbuf, &id, sizeof( id ));
*rbuflen = sizeof( id );
#if 0
struct vol *vol;
struct dir *dir;
- u_int16_t vid;
- u_int32_t did;
+ uint16_t vid;
+ uint32_t did;
#endif /* 0 */
*rbuflen = 0;
struct vol *vol;
struct dir *parentdir;
struct path *path;
- u_int32_t did;
- u_int16_t vid;
+ uint32_t did;
+ uint16_t vid;
*rbuflen = 0;
ibuf += 2;