/*
- * $Id: directory.c,v 1.42 2002-10-11 14:18:27 didg Exp $
+ * $Id: directory.c,v 1.56 2003-01-12 14:39:58 didg Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
#include "unix.h"
struct dir *curdir;
+int afp_errno;
#define SENTINEL (&sentinel)
static struct dir sentinel = { SENTINEL, SENTINEL, NULL, DIRTREE_COLOR_BLACK,
/* check for 0 did */
- if (!did)
+ if (!did) {
+ afp_errno = AFPERR_PARAM;
return NULL;
-
+ }
if ( did == DIRDID_ROOT_PARENT ) {
if (!rootpar.d_did)
rootpar.d_did = DIRDID_ROOT_PARENT;
}
dir = vol->v_root;
+ afp_errno = AFPERR_NOOBJ;
while ( dir != SENTINEL ) {
if (dir->d_did == did)
return dir->d_m_name ? dir : NULL;
return ret;
id = did;
- if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL) {
+ if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) ) {
+ afp_errno = AFPERR_NOOBJ;
return NULL;
}
ptr = path + MAXPATHLEN;
if (ret != NULL) {
break;
}
- if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL)
+ if ((upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) == NULL) {
+ afp_errno = AFPERR_NOOBJ;
return NULL;
+ }
mpath = utompath(vol, upath);
len = strlen(mpath) + 1;
pathlen += len;
- if (pathlen > 255)
+ if (pathlen > 255) {
+ afp_errno = AFPERR_PARAM;
return NULL;
+ }
strcpy(ptr - len, mpath);
ptr -= len;
}
* process. It's fixable within afpd if fnctl_lock, doable with smb and
* next to impossible for nfs and local filesystem access.
*/
-
static void dir_invalidate( vol, dir )
const struct vol *vol;
struct dir *dir;
static struct path ret;
char *data, *p;
- char *u;
int extend = 0;
int len;
- int olen = 0;
-
+ u_int32_t hint;
+ u_int16_t len16;
+ int size = 0;
+ char sep;
+
data = *cpath;
- if ( *data++ != 2 ) { /* path type */
+ afp_errno = AFPERR_NOOBJ;
+ switch (ret.m_type = *data) { /* path type */
+ case 2:
+ data++;
+ len = (unsigned char) *data++;
+ size = 2;
+ sep = 0;
+ break;
+ case 3:
+ if (afp_version >= 30) {
+ data++;
+ memcpy(&hint, data, sizeof(hint));
+ hint = ntohl(hint);
+ data += sizeof(hint);
+
+ memcpy(&len16, data, sizeof(len16));
+ len = ntohs(len16);
+ data += 2;
+ size = 7;
+ sep = 0; /* '/';*/
+ break;
+ }
+ /* else it's an error */
+ default:
+ afp_errno = AFPERR_PARAM;
return( NULL );
+
}
- len = (unsigned char) *data++;
- *cpath += len + 2;
+ *cpath += len + size;
*path = '\0';
- u = NULL;
ret.m_name = path;
ret.st_errno = 0;
ret.st_valid = 0;
if ( len == 0 ) {
if ( !extend && movecwd( vol, dir ) < 0 ) {
/* it's tricky:
- movecwd failed so dir is not there anymore.
+ movecwd failed some of dir path are not there anymore.
FIXME Is it true with other errors?
- if path == '\0' ==> the cpath parameter is that dir,
- and maybe we are trying to recreate it! So we can't
- fail here.
-
+ so we remove dir from the cache
*/
- if ( dir->d_did == DIRDID_ROOT_PARENT)
- return NULL;
- cdir = dir->d_parent;
+ if (dir->d_did == DIRDID_ROOT_PARENT)
+ return NULL;
+ if (afp_errno == AFPERR_ACCESS)
+ return NULL;
+
dir_invalidate(vol, dir);
- if (*path != '\0' || u == NULL) {
- /* FIXME: if path != '\0' then extend != 0 ?
- * u == NUL ==> cpath is something like:
- * toto\0\0\0
- */
- return NULL;
- }
- if (movecwd(vol, cdir) < 0) {
- printf("can't change to parent\n");
- return NULL; /* give up the whole tree is out of synch*/
- }
- /* restore the previous token */
- strncpy(path, u, olen);
- path[olen] = '\0';
+ return NULL;
}
- if (!ret.st_valid || *path == '\0') {
+ if (*path == '\0') {
ret.u_name = ".";
}
return &ret;
}
- if ( *data == '\0' ) {
+ if (*data == sep ) {
data++;
len--;
}
- u = NULL;
-
- while ( *data == '\0' && len > 0 ) {
+ while (*data == sep && len > 0 ) {
if ( dir->d_parent == NULL ) {
return NULL;
}
/* would this be faster with strlen + strncpy? */
p = path;
- if (len > 0) {
- u = data;
- olen = len;
- }
- while ( *data != '\0' && len > 0 ) {
+ while ( *data != sep && len > 0 ) {
*p++ = *data++;
len--;
}
if ( !extend ) {
cdir = dir->d_child;
while (cdir) {
- if ( strcasecmp( cdir->d_m_name, path ) == 0 ) {
+ if ( strcmp( cdir->d_m_name, path ) == 0 ) {
break;
}
cdir = (cdir == dir->d_child->d_prev) ? NULL :
/* dir is not valid anymore
we delete dir from the cache and abort.
*/
- dir_invalidate(vol, dir);
+ if ( dir->d_did != DIRDID_ROOT_PARENT &&
+ (afp_errno != AFPERR_ACCESS)) {
+ dir_invalidate(vol, dir);
+ }
return NULL;
}
cdir = extenddir( vol, dir, &ret );
}
if ( cdir == NULL ) {
+
if ( len > 0 ) {
return NULL;
}
return( 0 );
}
if ( dir->d_did == DIRDID_ROOT_PARENT) {
+ afp_errno = AFPERR_PARAM;
return( -1 );
}
*p-- = '\0';
*p = '.';
for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
- *--p = '/';
u = d->d_u_name;
n = strlen( u );
+ if (p -n -1 < path) {
+ afp_errno = AFPERR_PARAM;
+ return -1;
+ }
+ *--p = '/';
p -= n;
strncpy( p, u, n );
}
if ( d != curdir ) {
- *--p = '/';
n = strlen( vol->v_path );
+ if (p -n -1 < path) {
+ afp_errno = AFPERR_PARAM;
+ return -1;
+ }
+ *--p = '/';
p -= n;
strncpy( p, vol->v_path, n );
}
if ( chdir( p ) < 0 ) {
+ switch (errno) {
+ case EACCES:
+ case EPERM:
+ afp_errno = AFPERR_ACCESS;
+ break;
+ default:
+ afp_errno = AFPERR_NOOBJ;
+
+ }
return( -1 );
}
curdir = dir;
(".", curdir)
(name, dir) with curdir:name == dir, from afp_enumerate
*/
+
int getdirparams(const struct vol *vol,
u_int16_t bitmap, struct path *s_path,
struct dir *dir,
{
struct maccess ma;
struct adouble ad;
- char *data, *nameoff = NULL;
+ char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
int bit = 0, isad = 0;
u_int32_t aint;
u_int16_t ashort;
- int ret;
+ int ret;
+ u_int32_t utf8 = 0;
struct stat *st = &s_path->st;
char *upath = s_path->u_name;
case DIRPBIT_LNAME :
if (dir->d_m_name) /* root of parent can have a null name */
- nameoff = data;
+ l_nameoff = data;
else
memset(data, 0, sizeof(u_int16_t));
data += sizeof( u_int16_t );
/* Client has requested the ProDOS information block.
Just pass back the same basic block for all
directories. <shirsch@ibm.net> */
- case DIRPBIT_PDINFO : /* ProDOS Info Block */
- *data++ = 0x0f;
- *data++ = 0;
- ashort = htons( 0x0200 );
- memcpy( data, &ashort, sizeof( ashort ));
- data += sizeof( ashort );
- memset( data, 0, sizeof( ashort ));
- data += sizeof( ashort );
+ case DIRPBIT_PDINFO :
+ if (afp_version >= 30) { /* UTF8 name */
+ utf8 = kTextEncodingUTF8;
+ 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 );
+ aint = 0;
+ memcpy(data, &aint, sizeof( aint ));
+ data += sizeof( aint );
+ }
+ else { /* ProDOS Info Block */
+ *data++ = 0x0f;
+ *data++ = 0;
+ ashort = htons( 0x0200 );
+ memcpy( data, &ashort, sizeof( ashort ));
+ data += sizeof( ashort );
+ memset( data, 0, sizeof( ashort ));
+ data += sizeof( ashort );
+ }
break;
default :
bitmap = bitmap>>1;
bit++;
}
- if ( nameoff ) {
+ if ( l_nameoff ) {
ashort = htons( data - buf );
- memcpy( nameoff, &ashort, sizeof( ashort ));
-
- if ((aint = strlen( dir->d_m_name )) > MACFILELEN)
- aint = MACFILELEN;
-
- *data++ = aint;
- memcpy( data, dir->d_m_name, aint );
- data += aint;
+ memcpy( l_nameoff, &ashort, sizeof( ashort ));
+ data = set_name(data, dir->d_m_name, 0);
+ }
+ if ( utf_nameoff ) {
+ ashort = htons( data - buf );
+ memcpy( utf_nameoff, &ashort, sizeof( ashort ));
+ data = set_name(data, dir->d_m_name, utf8);
}
if ( isad ) {
ad_close( &ad, ADFLAGS_HF );
memcpy( &vid, ibuf, sizeof( vid ));
ibuf += sizeof( vid );
- if (( vol = getvolbyvid( vid )) == NULL ) {
+ if (NULL == ( vol = getvolbyvid( vid )) ) {
return( AFPERR_PARAM );
}
ibuf += sizeof( int );
if (( dir = dirlookup( vol, did )) == NULL ) {
- return( AFPERR_NOOBJ );
+ return afp_errno;
}
memcpy( &bitmap, ibuf, sizeof( bitmap ));
ibuf += sizeof( bitmap );
if (( path = cname( vol, dir, &ibuf )) == NULL ) {
- return( AFPERR_NOOBJ );
+ return afp_errno;
}
if ( *path->m_name != '\0' ) {
*/
struct path Cur_Path = {
+ 0,
"", /* mac name */
".", /* unix name */
0, /* stat is not set */
ProDOS information block. Skip over the data and
report nothing amiss. <shirsch@ibm.net> */
case DIRPBIT_PDINFO :
- buf += 6;
- break;
-
+ if (afp_version < 30) {
+ buf += 6;
+ break;
+ }
default :
err = AFPERR_BITMAP;
goto setdirparam_done;
memcpy( &vid, ibuf, sizeof( vid ));
ibuf += sizeof( vid );
- if (( vol = getvolbyvid( vid )) == NULL ) {
+ if (NULL == ( vol = getvolbyvid( vid )) ) {
return( AFPERR_PARAM );
}
memcpy( &did, ibuf, sizeof( did ));
ibuf += sizeof( did );
- if (( dir = dirlookup( vol, did )) == NULL ) {
+ if (NULL == ( dir = dirlookup( vol, did )) ) {
return( AFPERR_NOOBJ );
}
- if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
- switch( errno ) {
- case EACCES:
- return( AFPERR_ACCESS );
- case EEXIST: /* FIXME this one is impossible? */
- return( AFPERR_EXIST );
- default:
- return( AFPERR_NOOBJ );
- }
+ if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+ return afp_errno;
}
/* FIXME check done elswhere? cname was able to move curdir to it! */
if (*s_path->m_name == '\0')
if (of_stat(s_path) < 0) {
return AFPERR_MISC;
}
+ curdir->offcnt++;
if ((dir = adddir( vol, curdir, s_path)) == NULL) {
return AFPERR_MISC;
}
}
memset(&ad, 0, sizeof(ad));
- if (ad_open( "", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
+ if (ad_open( ".", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
O_RDWR|O_CREAT, 0666, &ad ) < 0) {
if (vol_noadouble(vol))
goto createdir_done;
struct dir *parent;
char *buf;
int len, err;
-
+
/* existence check moved to afp_moveandrename */
- if ( rename( src, dst ) < 0 ) {
+ if ( unix_rename( src, dst ) < 0 ) {
switch ( errno ) {
case ENOENT :
return( AFPERR_NOOBJ );
}
memset(&ad, 0, sizeof(ad));
- if ( ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad) < 0 ) {
- switch ( errno ) {
- case ENOENT :
- if (noadouble) {
- len = strlen(newname);
- goto renamedir_done;
- }
- return( AFPERR_NOOBJ );
- case EACCES :
- return( AFPERR_ACCESS );
- default :
- return( AFPERR_PARAM );
- }
- }
len = strlen( newname );
- ad_setentrylen( &ad, ADEID_NAME, len );
- memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
- ad_flush( &ad, ADFLAGS_HF );
- ad_close( &ad, ADFLAGS_HF );
-
-renamedir_done:
+ /* rename() succeeded so we need to update our tree even if we can't open
+ * .Parent
+ */
+ if ( !ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad)) {
+ ad_setentrylen( &ad, ADEID_NAME, len );
+ memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
+ ad_flush( &ad, ADFLAGS_HF );
+ ad_close( &ad, ADFLAGS_HF );
+ }
+
if (dir->d_m_name == dir->d_u_name)
dir->d_u_name = NULL;
}
if ( movecwd( vol, curdir->d_parent ) < 0 ) {
- return( AFPERR_NOOBJ );
+ return afp_errno;
}
if ( rmdir(fdir->d_u_name) < 0 ) {
char *name;
u_int32_t id;
int len, sfunc;
-
+ int utf8 = 0;
+
ibuf++;
sfunc = (unsigned char) *ibuf++;
memcpy( &id, ibuf, sizeof( id ));
id = ntohl(id);
+ *rbuflen = 0;
if ( id != 0 ) {
switch ( sfunc ) {
case 1 :
+ case 3 :/* unicode */
if (( pw = getpwuid( id )) == NULL ) {
- *rbuflen = 0;
return( AFPERR_NOITEM );
}
name = pw->pw_name;
break;
case 2 :
+ case 4 : /* unicode */
if (( gr = (struct group *)getgrgid( id )) == NULL ) {
- *rbuflen = 0;
return( AFPERR_NOITEM );
}
name = gr->gr_name;
break;
default :
- *rbuflen = 0;
return( AFPERR_PARAM );
}
-
+ switch ( sfunc ) {
+ case 3:
+ case 4:
+ if (afp_version < 30) {
+ return( AFPERR_PARAM );
+ }
+ utf8 = 1;
+ /* map to unicode */
+ break;
+ }
len = strlen( name );
} else {
len = 0;
name = NULL;
}
-
- *rbuf++ = len;
+ if (utf8) {
+ u_int16_t tp = htons(len);
+ memcpy(rbuf, &tp, sizeof(tp));
+ rbuf += sizeof(tp);
+ *rbuflen += 2;
+ }
+ else {
+ *rbuf++ = len;
+ *rbuflen += 1;
+ }
if ( len > 0 ) {
memcpy( rbuf, name, len );
}
- *rbuflen = len + 1;
+ *rbuflen += len;
return( AFP_OK );
}
{
struct passwd *pw;
struct group *gr;
- int len, sfunc;
- u_int32_t id;
+ int len, sfunc;
+ u_int32_t id;
+ u_int16_t ulen;
ibuf++;
sfunc = (unsigned char) *ibuf++;
- len = (unsigned char) *ibuf++;
+ switch ( sfunc ) {
+ case 1 :
+ case 2 : /* unicode */
+ memcpy(&ulen, ibuf, sizeof(ulen));
+ len = ntohs(ulen);
+ ibuf += 2;
+ break;
+ case 3 :
+ case 4 :
+ len = (unsigned char) *ibuf++;
+ break;
+ default :
+ *rbuflen = 0;
+ return( AFPERR_PARAM );
+ }
+
ibuf[ len ] = '\0';
if ( len != 0 ) {
switch ( sfunc ) {
+ case 1 : /* unicode */
case 3 :
if (( pw = (struct passwd *)getpwnam( ibuf )) == NULL ) {
*rbuflen = 0;
id = pw->pw_uid;
break;
+ case 2 : /* unicode */
case 4 :
if (( gr = (struct group *)getgrnam( ibuf )) == NULL ) {
*rbuflen = 0;
}
id = gr->gr_gid;
break;
- default :
- *rbuflen = 0;
- return( AFPERR_PARAM );
}
} else {
id = 0;
memcpy(&vid, ibuf, sizeof(vid));
ibuf += sizeof( vid );
- if (( vol = getvolbyvid( vid )) == NULL ) {
+ if (NULL == ( vol = getvolbyvid( vid )) ) {
return( AFPERR_PARAM );
}
memcpy(&did, ibuf, sizeof(did));
ibuf += sizeof(did);
- if (( parentdir = dirlookup( vol, did )) == NULL ) {
- return( AFPERR_NOOBJ );
+ if (NULL == ( parentdir = dirlookup( vol, did )) ) {
+ return afp_errno;
}
- if (( path = cname( vol, parentdir, &ibuf )) == NULL ) {
- switch( errno ) {
- case EACCES:
- return( AFPERR_ACCESS );
- default:
- return( AFPERR_NOOBJ );
- }
+ if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
+ return afp_errno;
}
if ( *path->m_name != '\0' ) {