diff --git a/include/connect.h b/include/connect.h index a7e6aa8..6728e2b 100644 --- a/include/connect.h +++ b/include/connect.h @@ -120,6 +120,8 @@ extern int nw_mv_files(int searchattrib, extern int mv_dir(int dir_handle, uint8 *sourcedata, int qlen, uint8 *destdata, int destdatalen); +extern int nw_mv_dir_between_handles(int sourcedirhandle, uint8 *sourcedata, int qlen, + int zdirhandle, uint8 *destdata, int destdatalen); extern int nw_unlink_node(int volume, uint8 *unname, struct stat *stb); extern int nw_creat_node(int volume, uint8 *unname, int mode); diff --git a/src/connect.c b/src/connect.c index 3842e51..97eea83 100644 --- a/src/connect.c +++ b/src/connect.c @@ -1889,6 +1889,76 @@ int mv_dir(int dir_handle, uint8 *sourcedata, int sourcedatalen, return(completition); } +int nw_mv_dir_between_handles(int sourcedirhandle, uint8 *sourcedata, int sourcedatalen, + int zdirhandle, uint8 *destdata, int destdatalen) +/* + * Rename/move a directory where source and destination are expressed using + * separate directory handles. This is needed by NCP 22/46 Rename Or Move + * (old). The older mv_dir() helper only supports the classic NCP 22/15 + * style where the destination is just a new name below the source parent. + */ +{ + NW_PATH quellpath; + NW_PATH zielpath; + struct stat qstbuff; + struct stat zstbuff; + int completition = conn_get_kpl_path(&quellpath, &qstbuff, + sourcedirhandle, + sourcedata, sourcedatalen, 0); + if (completition > -1) { + char qfn[256]; + char zparent[256]; + char unziel[256]; + + if (!S_ISDIR(qstbuff.st_mode)) + return(-0x9c); + + completition = conn_get_kpl_path(&zielpath, &zstbuff, + zdirhandle, + destdata, destdatalen, 0); + if (completition < 0) + return(completition); + + if (quellpath.volume != zielpath.volume) + return(-0x9a); /* cross devices/volumes */ + + xstrcpy(qfn, build_unix_name(&quellpath, 0)); + xstrcpy(zparent, build_unix_name(&zielpath, 1)); + + if (stat(qfn, &qstbuff) || + tru_eff_rights_exists(quellpath.volume, qfn, &qstbuff, + TRUSTEE_W|TRUSTEE_M|TRUSTEE_R)) + completition=-0x8b; + else if (stat(zparent, &zstbuff) || + tru_eff_rights_exists(zielpath.volume, zparent, &zstbuff, + TRUSTEE_W)) + completition=-0x8b; + + if (completition > -1) { + int result; + xstrcpy(unziel, build_unix_name(&zielpath, 0)); + + if (seteuid(0)) {} + result = unx_mvdir((uint8 *)qfn, (uint8 *)unziel); + (void)reseteuid(); + + XDPRINTF((4,0, "rendir/movedir result=%d, '%s'->'%s'", + result, qfn, unziel)); + if (!result) + completition = 0; + else { + if (result == EEXIST) + completition=-0x92; /* already exists */ + else if (result == EXDEV) + completition=-0x9a; /* cross devices */ + else completition=-0x9c; /* wrong path */ + } + } + } + return(completition); +} + + static int change_dir_entry( NW_DIR *dir, int volume, uint8 *path, int dev, ino_t inode, diff --git a/src/nwconn.c b/src/nwconn.c index 2089515..f1af6a6 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -1360,6 +1360,17 @@ static int handle_ncp_serv(void) result = nw_mv_files(searchattr, src_handle, srcpath, srclen, (int)*q, dstpath, dstlen); + + /* + * nw_mv_files() is correct for file rename/move. + * Directories need the directory mover, and NCP22/2E + * can provide different source and destination handles. + */ + if (result == -0x9c) + result = nw_mv_dir_between_handles(src_handle, + srcpath, srclen, + (int)*q, dstpath, dstlen); + if (result < 0) completition = (uint8)(-result); } break;