mirror of https://github.com/mabam/CAP.git
5259 lines
130 KiB
C
5259 lines
130 KiB
C
/*
|
|
* $Author: djh $ $Date: 1996/09/10 14:30:03 $
|
|
* $Header: /mac/src/cap60/applications/aufs/RCS/afpos.c,v 2.80 1996/09/10 14:30:03 djh Rel djh $
|
|
* $Revision: 2.80 $
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* afpos.c - Appletalk Filing Protocol OS Interface.
|
|
*
|
|
* AppleTalk package for UNIX (4.2 BSD).
|
|
*
|
|
* Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University in the
|
|
* City of New York.
|
|
*
|
|
* Edit History:
|
|
*
|
|
* March 1987 Schilit Created.
|
|
* March 1988 CCKIM cleanup
|
|
* December 1990 djh tidy up for AFP 2.0
|
|
* May 1991 ber,jlm accept a part of the gcos or login name
|
|
* (PERMISSIVE_USER_NAME)
|
|
* March 1993 jbh/rns Add support for Shadow Password file
|
|
* July 1993 pabe/jbh Tidy up Shadow Password support; fix
|
|
* combination of same with PERMISSIVE_USER_NAME
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* POSSIBLE DEFINES:
|
|
*
|
|
* NONLXLATE
|
|
* Define to turn off translation of \n to \r on line at a time
|
|
* reads
|
|
* USECHOWN
|
|
* System allows user to use chown to give away file ownership
|
|
* Following are used to get volume information
|
|
* USEGETMNT - DECs getmnt call. Works for either Ultrix 1.2, 2.0 or
|
|
* 2.2 (to be verified). Call differs from 2.0 to 2.2
|
|
* USEQUOTA - base volume information on quota for user on file
|
|
* system if it exists (messed up by symlinks off the structure).
|
|
* This is for the "Melbourne" quota system as usually found in BSD
|
|
* systems.
|
|
* USESUNQUOTA - running with sun quota system. Basically, just turns on
|
|
* emulation of the Melbourne quota call
|
|
* USEBSDQUOTA - "new" BSD quota which uses the quotactl call and
|
|
* provides quotas for both users and groups
|
|
* USEUSTAT - not recommended. returns information about file, but
|
|
* information doesn't tell us how much space is there -- only
|
|
* how much is free and we need both
|
|
* USESTATFS - statfs is the Sun NFS solution to volume information.
|
|
* (has modified call arguments and structure elements under SGI IRIX).
|
|
*
|
|
* PERMISSIVE_USER_NAME - let the Chooser name be from the gcos field
|
|
* SHADOW_PASSWD - enable support of shadow password files
|
|
*
|
|
* aux has a couple of "ifdefs".
|
|
* - one to set full BSD compatibility
|
|
* - one to protect against rename("file1","file1"): it will
|
|
* incorrectly unlink "file1" (period - nothing left afterwards)
|
|
*
|
|
* OTHER: GGTYPE
|
|
* Some versions of unix return a gid_t array in getgroups instead of
|
|
* an int array. For those, define GGTYPE to gid_t. In particular,
|
|
* this is a problem with (at least some version of) "MORE/BSD"
|
|
* from Mt. Xinu.
|
|
*
|
|
* System V defines
|
|
* NOLSTAT - no lstat call - don't try to figure out things with symlinks
|
|
* USERAND - use sysv rand call not bsd random
|
|
*
|
|
*/
|
|
|
|
#if (defined(__386BSD__) || defined(__FreeBSD__))
|
|
#define __BSD_4_4__
|
|
#endif /* __386BSD__ */
|
|
|
|
#include <stdio.h>
|
|
#include <pwd.h>
|
|
#include <grp.h>
|
|
#include <errno.h>
|
|
#include <sys/param.h>
|
|
#ifndef _TYPES
|
|
# include <sys/types.h> /* assume included by param.h */
|
|
#endif _TYPES
|
|
#include <sys/file.h>
|
|
#include <sys/stat.h>
|
|
#include <netat/appletalk.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/time.h>
|
|
|
|
#ifdef aux
|
|
# include <compat.h>
|
|
#endif aux
|
|
|
|
#ifdef USEDIRENT
|
|
#include <dirent.h>
|
|
#else USEDIRENT
|
|
# ifdef xenix5
|
|
# include <sys/ndir.h>
|
|
# else xenix5
|
|
# ifndef drsnx
|
|
# include <sys/dir.h>
|
|
# endif drsnx
|
|
# endif xenix5
|
|
#endif USEDIRENT
|
|
|
|
#ifdef SHADOW_PASSWD
|
|
#include <shadow.h>
|
|
#endif SHADOW_PASSWD
|
|
|
|
#ifdef gould
|
|
# define USESUNQUOTA
|
|
#endif gould
|
|
|
|
#ifdef USESUNQUOTA
|
|
# ifndef USEQUOTA
|
|
# define USEQUOTA
|
|
# endif USEQUOTA
|
|
#endif USESUNQUOTA
|
|
|
|
#if defined (APPLICATION_MANAGER) || defined (DENYREADWRITE)
|
|
# define NEEDFCNTLDOTH
|
|
#endif APPLICATION_MANAGER|DENYREADWRITE
|
|
|
|
#ifdef NEEDFCNTLDOTH
|
|
# include <fcntl.h>
|
|
# ifdef apollo
|
|
# include <netat/fcntldomv.h>
|
|
# endif apollo
|
|
#endif NEEDFCNTLDOTH
|
|
|
|
#ifdef USESTRINGDOTH
|
|
# include <string.h>
|
|
#else USESTRINGDOTH
|
|
# include <strings.h>
|
|
#endif USESTRINGDOTH
|
|
|
|
#ifdef USEUSTAT
|
|
# include <ustat.h>
|
|
#endif USEUSTAT
|
|
|
|
#ifdef USESTATFS
|
|
# ifdef SOLARIS
|
|
# include <sys/statvfs.h>
|
|
# else /* SOLARIS */
|
|
# if defined(__BSD_4_4__) || defined(__osf__)
|
|
# include <sys/param.h>
|
|
# include <sys/mount.h>
|
|
# else /* __BSD_4_4__ || __osf__ */
|
|
# if defined(sgi) || defined(apollo)
|
|
# include <sys/statfs.h>
|
|
# else /* sgi || apollo */
|
|
# include <sys/vfs.h>
|
|
# endif /* sgi || apollo */
|
|
# endif /* __BSD_4_4__ || __osf__ */
|
|
# endif /* SOLARIS */
|
|
#endif /* USESTATFS */
|
|
|
|
#ifdef AIX
|
|
#include <sys/statfs.h>
|
|
#endif AIX
|
|
|
|
#ifdef __BSD_4_4__
|
|
#include <unistd.h>
|
|
#endif /* __BSD_4_4__ */
|
|
|
|
#ifdef linux
|
|
#include <unistd.h>
|
|
#endif /* linux */
|
|
|
|
#ifdef NeXT
|
|
#undef USEQUOTA
|
|
#undef USESUNQUOTA
|
|
#endif NeXT
|
|
|
|
#ifdef USEBSDQUOTA
|
|
# include <fstab.h>
|
|
# include <ufs/quota.h>
|
|
#endif USEBSDQUOTA
|
|
|
|
#ifdef USEQUOTA
|
|
# ifdef SOLARIS
|
|
# undef USESUNQUOTA
|
|
# include <sys/fs/ufs_quota.h>
|
|
# else SOLARIS
|
|
# ifndef USESUNQUOTA
|
|
# include <sys/quota.h>
|
|
/*
|
|
* NOTE: If there is not sys/quota.h and there is a ufs/quota.h
|
|
* then you should probably define SUN_QUOTA -- especially if your
|
|
* NFS is based on the sun model
|
|
*
|
|
*/
|
|
# else USESUNQUOTA
|
|
# include <mntent.h>
|
|
# include <ufs/quota.h>
|
|
# endif USESUNQUOTA
|
|
# endif SOLARIS
|
|
# ifndef Q_GETDLIM
|
|
# ifdef Q_GETQUOTA
|
|
# define Q_GETDLIM Q_GETQUOTA
|
|
# else Q_GETQUOTA
|
|
/*
|
|
* Error: You have turned on quotas and aren't using the
|
|
* bsd or sun quota system.
|
|
*
|
|
*/
|
|
# endif Q_GETQUOTA
|
|
# endif Q_GETDLIM
|
|
#endif USEQUOTA
|
|
|
|
/* assumes that ultrix 1.1 doesn't have getmnt or if it does, then it */
|
|
/* has limits.h and uname */
|
|
#ifdef USEGETMNT
|
|
# include <sys/mount.h>
|
|
/* the following assumes ultrix 1.2 or above */
|
|
/* well, do you really think dec would license their code to another */
|
|
/* vendor :-) */
|
|
# include <limits.h>
|
|
# include <sys/utsname.h>
|
|
#endif USEGETMNT
|
|
|
|
#ifdef drsnx
|
|
# ifdef USESTATFS
|
|
# undef USESTATFS /* ICL DRS/NX statfs() is a little different */
|
|
# endif USESTATFS
|
|
#endif drsnx
|
|
|
|
#ifdef SOLARIS
|
|
# include <unistd.h>
|
|
# define NGROUPS NGROUPS_MAX_DEFAULT
|
|
#endif SOLARIS
|
|
|
|
#include <netat/afp.h>
|
|
#include <netat/afpcmd.h> /* flags should be in misc */
|
|
#include "afps.h" /* common includes */
|
|
#include "afpvols.h"
|
|
#include "afppasswd.h" /* in case we are using privates */
|
|
#include "afposncs.h"
|
|
#include "afpgc.h"
|
|
|
|
#ifdef SIZESERVER
|
|
#include <setjmp.h>
|
|
#include <signal.h>
|
|
#include <sys/socket.h>
|
|
#include "sizeserver.h"
|
|
#endif SIZESERVER
|
|
|
|
#ifdef PERMISSIVE_USER_NAME
|
|
#include <ctype.h>
|
|
#endif PERMISSIVE_USER_NAME
|
|
|
|
#ifdef ULTRIX_SECURITY
|
|
#include <sys/svcinfo.h>
|
|
#include <auth.h>
|
|
#endif ULTRIX_SECURITY
|
|
|
|
#ifdef DIGITAL_UNIX_SECURITY
|
|
#include <sys/types.h>
|
|
#include <sys/security.h>
|
|
#include <prot.h>
|
|
#endif DIGITAL_UNIX_SECURITY
|
|
|
|
#ifdef LOG_WTMP
|
|
# if defined(sgi) || defined(SOLARIS)
|
|
# define LOG_WTMPX
|
|
# endif /* sgi || SOLARIS */
|
|
# ifdef LOG_WTMPX
|
|
# include <utmpx.h>
|
|
# else /* LOG_WTMPX */
|
|
# include <utmp.h>
|
|
# endif /* LOG_WTMPX */
|
|
#endif /* LOG_WTMP */
|
|
|
|
#ifdef DISTRIB_PASSWDS
|
|
#include <netat/afppass.h>
|
|
#endif /* DISTRIB_PASSWDS */
|
|
|
|
#ifdef MAXBSIZE
|
|
# define IOBSIZE MAXBSIZE /* set to max buf entry size by if there */
|
|
#else MAXBSIZE
|
|
# ifdef BLKDEV_IOSIZE
|
|
# define IOBSIZE BLKDEV_IOSIZE /* set to std block device read size */
|
|
# else BLKDEV_IOSIZE
|
|
# define IOBSIZE BUFSIZ /* use stdio bufsiz */
|
|
# endif BLKDEV_IOSIZE
|
|
#endif MAXBSIZE
|
|
|
|
#define NILPWD ((struct passwd *) 0)
|
|
|
|
#ifdef SHADOW_PASSWD
|
|
#define NILSPWD ((struct spwd *) 0)
|
|
#endif SHADOW_PASSWD
|
|
|
|
/* macro to test for directory file */
|
|
|
|
#ifndef S_ISDIR
|
|
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
|
#endif S_ISDIR
|
|
|
|
#define E_IOWN 0x80000000 /* owner of file */
|
|
|
|
#define I_SETUID 04000 /* internal set user ID */
|
|
#define I_SETGID 02000 /* internal set group ID */
|
|
|
|
#define I_RD 04 /* Internal (Unix) bits for read */
|
|
#define I_WR 02 /* write */
|
|
#define I_EX 01 /* execute (search) */
|
|
|
|
#define E_RD 02 /* External bits for read */
|
|
#define E_WR 04 /* write */
|
|
#define E_SR 01 /* search */
|
|
|
|
#define IS_OWNER 6 /* internal owner shift amount */
|
|
#define IS_GROUP 3 /* internal group shift amount */
|
|
#define IS_WORLD 0 /* internal world shift amount */
|
|
|
|
#define ES_USER 24 /* external user shift amount */
|
|
/* which is a calculated access based on: */
|
|
#define ES_WORLD 16 /* external world shift amount */
|
|
#define ES_GROUP 8 /* external group shift amount */
|
|
#define ES_OWNER 0 /* external owner shift amount */
|
|
|
|
/* Mask search (is unix execute) bits for world, group and owner */
|
|
|
|
#define IS_EX_WGO ((I_EX << IS_OWNER) | \
|
|
(I_EX << IS_GROUP) | \
|
|
(I_EX << IS_WORLD))
|
|
|
|
private char *usrnam,*usrdir;
|
|
private int usruid;
|
|
private int usrgid;
|
|
private int ngroups;
|
|
|
|
#ifndef GGTYPE
|
|
# ifdef SOLARIS
|
|
# define GGTYPE gid_t
|
|
# else SOLARIS
|
|
# define GGTYPE int
|
|
# endif SOLARIS
|
|
#endif GGTYPE
|
|
|
|
private GGTYPE groups[NGROUPS+1];
|
|
|
|
#ifdef USEGETMNT
|
|
# ifndef NOSTAT_ONE
|
|
/* no big deal if this changes, it just means you can't compile under */
|
|
/* ultrix 2.0/1.2 for ultrix 2.2 (you probably can't for 1.2 anyway) */
|
|
/* WARNING: not 100% sure that there aren't other problems preventing */
|
|
/* a compile from ultrix 2.0 from working on 2.2 */
|
|
# define NOSTAT_ONE 4 /* as of ultrix 2.2 */
|
|
# define ISOLDGETMNT 1
|
|
# else NOSTAT_ONE
|
|
# define ISOLDGETMNT 0
|
|
# endif NOSTAT_ONE
|
|
private int oldgetmnt = ISOLDGETMNT; /* use new or old format getmnt */
|
|
/* default is based on compiling system */
|
|
# ifndef NUMGETMNTBUF
|
|
# define NUMGETMNTBUF 8 /* 8 before, let's not be conservative */
|
|
/* because on systems with many file */
|
|
/* systems we will get killed with 8 */
|
|
/* Back off!!!!! struct fs_data is huge */
|
|
# endif NUMGETMNTBUF
|
|
#endif USEGETMNT
|
|
|
|
import int errno;
|
|
|
|
/*
|
|
* AFPOS functions
|
|
*
|
|
* Generally, a name like: OSXxxxx means that it is a "primary" function
|
|
* that accomplishes a afp command (not always though).
|
|
*
|
|
*/
|
|
|
|
export int OSEnable();
|
|
export void tellaboutos();
|
|
export OSErr OSMapID();
|
|
export OSErr OSMapName();
|
|
export OSErr OSDelete();
|
|
private OSErr os_rmdir();
|
|
private OSErr os_delete();
|
|
export OSErr OSRename();
|
|
export OSErr OSMove();
|
|
private OSErr os_move();
|
|
export OSErr OSFlush();
|
|
export OSErr OSFlushFork();
|
|
export OSErr OSClose();
|
|
export OSErr OSRead();
|
|
export OSErr OSWrite();
|
|
export OSErr OSCreateDir();
|
|
private OSErr os_mkdir();
|
|
export OSErr OSCreateDir();
|
|
export OSErr OSFileDirInfo();
|
|
export OSErr OSDirInfo(); /* from old spec */
|
|
export OSErr OSFileInfo(); /* from old spec */
|
|
export void OSValidateDIDDirInfo();
|
|
export OSErr OSFileExists();
|
|
export OSErr OSSetFileDirParms();
|
|
export OSErr OSSetFileParms();
|
|
export OSErr OSSetDirParms();
|
|
export OSErr OSSetForklen();
|
|
export OSErr OSGetSrvrMsg();
|
|
private OSErr os_chmod();
|
|
private void os_change_all();
|
|
private u_short EtoIPriv();
|
|
private int OSInGroup();
|
|
private u_short EtoIAccess();
|
|
private dword ItoEPriv();
|
|
private dword ItoEAccess();
|
|
export OSErr OSAccess();
|
|
export OSErr OSVolInfo();
|
|
#ifdef USEGETMNT
|
|
private OSErr ultrix_volinfo();
|
|
#endif USEGETMNT
|
|
export OSErr OSCopyFile();
|
|
private OSErr os_copy();
|
|
export OSErr OSCreateFile();
|
|
export OSErr OSOpenFile();
|
|
export boolean setguestid();
|
|
export boolean setpasswdfile();
|
|
export OSErr OSLoginRand();
|
|
export OSErr OSLogin();
|
|
export word OSRandom();
|
|
export sdword CurTime(); /* current time in internal form */
|
|
export char *tilde(); /* tilde expansion */
|
|
export char *logdir(); /* user login directory */
|
|
export int guestlogin; /* session is a guest login */
|
|
private OSErr unix_rmdir();
|
|
private OSErr unix_unlink();
|
|
private OSErr unix_rename();
|
|
#ifdef XDEV_RENAME
|
|
private OSErr xdev_rename(); /* rename across devices */
|
|
#endif XDEV_RENAME
|
|
private OSErr unix_open();
|
|
private OSErr unix_close();
|
|
private OSErr unix_mkdir();
|
|
private OSErr unix_create();
|
|
private OSErr unix_createo();
|
|
private OSErr unix_chown();
|
|
private OSErr unix_chmod();
|
|
private OSErr unix_stat();
|
|
private OSErr ItoEErr();
|
|
private int filemode();
|
|
private char *syserr();
|
|
|
|
#ifdef SIZESERVER
|
|
private void getvolsize();
|
|
#endif SIZESERVER
|
|
|
|
#ifdef LWSRV_AUFS_SECURITY
|
|
char *bin, *tempbin ;
|
|
#endif LWSRV_AUFS_SECURITY
|
|
|
|
#ifdef SHADOW_PASSWD
|
|
int shadow_flag;
|
|
#endif SHADOW_PASSWD
|
|
|
|
#ifdef DENYREADWRITE
|
|
struct accessMode {
|
|
struct accessMode *next;
|
|
char path[MAXPATHLEN];
|
|
int mode;
|
|
int fd;
|
|
};
|
|
struct accessMode *accessMQueue = (struct accessMode *)NULL;
|
|
#endif DENYREADWRITE
|
|
|
|
/*
|
|
* Enable OS Dependent functions
|
|
*
|
|
* For now: under AUX, set full BSD compatibility
|
|
* under sun quota systems, build a mount table for use in quota call
|
|
*
|
|
*/
|
|
export int
|
|
OSEnable()
|
|
{
|
|
#ifdef USEGETMNT
|
|
struct utsname unames;
|
|
#endif USEGETMNT
|
|
|
|
#ifdef USEGETMNT
|
|
if (uname(&unames) >= 0) {
|
|
/* don't think getmnt was available in ultrix 1.1. If it was */
|
|
/* then we assume it had uname too */
|
|
if (strcmp(unames.sysname, "ULTRIX-32") == 0) {
|
|
if (strcmp(unames.release, "2.0") == 0 ||
|
|
strcmp(unames.release, "1.2") == 0 ||
|
|
strcmp(unames.release, "1.1") == 0) {
|
|
oldgetmnt = TRUE;
|
|
} else oldgetmnt = FALSE;
|
|
}
|
|
}
|
|
#endif USEGETMNT
|
|
#ifdef aux
|
|
/* ensure reliable signals, etc */
|
|
#define BSDCOMPAT COMPAT_BSDNBIO|COMPAT_BSDPROT|COMPAT_BSDSIGNALS|\
|
|
COMPAT_BSDTTY|COMPAT_EXEC|COMPAT_SYSCALLS
|
|
setcompat(BSDCOMPAT);
|
|
#endif aux
|
|
#ifdef USESUNQUOTA
|
|
build_mount_table();
|
|
#endif USESUNQUOTA
|
|
#ifdef SHADOW_PASSWD
|
|
shadow_flag = (access(SHADOW, F_OK) == 0);
|
|
#endif SHADOW_PASSWD
|
|
}
|
|
|
|
void
|
|
tellaboutos()
|
|
{
|
|
int haveflock;
|
|
int havelockf;
|
|
|
|
logit(0,"CONFIGURATION");
|
|
getlockinfo(&haveflock, &havelockf);
|
|
if (haveflock)
|
|
logit(0," Configured: FLOCK");
|
|
if (havelockf)
|
|
logit(0," Configured: LOCKF");
|
|
#ifdef USEUSTAT
|
|
logit(0," Configured: Volume space information: ustat");
|
|
#endif USEUSTAT
|
|
#ifdef USESTATFS
|
|
logit(0," Configured: Volume space information: stat[v]fs");
|
|
#endif USESTATFS
|
|
#ifdef USEGETMNT
|
|
logit(0," Configured: Volume space information: getmnt");
|
|
if (oldgetmnt)
|
|
logit(0," using old style (Ultrix 1.2, 2.0) getmnt");
|
|
#endif USEGETMNT
|
|
|
|
#ifdef USEQUOTA
|
|
# if defined(USESUNQUOTA) || defined(SOLARIS)
|
|
logit(0," Configured: SUN quota system");
|
|
# else /* USESUNQUOTA || SOLARIS */
|
|
# ifdef USEBSDQUOTA
|
|
logit(0," Configured: New BSD quota system");
|
|
# else /* USEBSDQUOTA */
|
|
logit(0," Configured: Melbourne (BSD) quota system");
|
|
# endif /* USEBSDQUOTA */
|
|
# endif /* USESUNQUOTA || SOLARIS */
|
|
#endif /* USEQUOTA */
|
|
|
|
#ifdef USECHOWN
|
|
logit(0," Configured: chown: system allows one to give away ownership of files");
|
|
#endif USECHOWN
|
|
if (os_issmartunixfi())
|
|
logit(0," Configured: reading unknown unix files to get finder information");
|
|
logit(0," Configured translation tables are:");
|
|
ncs_table_dump();
|
|
#ifdef DISTRIB_PASSWDS
|
|
logit(0," Configured: Using Distributed Passwords for authentication");
|
|
#endif DISTRIB_PASSWDS
|
|
}
|
|
|
|
/*
|
|
* OwnerID = 0 means that the folder is "unowned" or owned by
|
|
* <any user>. The owner bit of the User Rights summary is always
|
|
* set for such a folder.
|
|
*
|
|
* GroupID = 0 means that the folder has no group affiliation; hence
|
|
* the group's access privileges (R, W, S) are ignored for such a
|
|
* folder.
|
|
*
|
|
*/
|
|
|
|
#define NOID (-1) /* internal group/user id for <any user> */
|
|
|
|
/*
|
|
* Make external and internal ids differ by one. Then 1 (administrator)
|
|
* maps to 0 (root), and 0 (any user or group) maps to -1. Thus the
|
|
* AFP client thinks user ids are 1 higher than what the server (and the
|
|
* unix machine) use internally.
|
|
*
|
|
*/
|
|
|
|
#define ItoEID(iid) ((sdword) (iid + 1))
|
|
#define EtoIID(eid) ((int) (eid - 1))
|
|
|
|
/*
|
|
*
|
|
* OSErr OSMapID(byte fcn,char *name,dword id)
|
|
*
|
|
*
|
|
* This function is used to map a creator ID to a creator name, or
|
|
* a group ID to a group name.
|
|
*
|
|
* The creator name/id is identical to the user name and UID under
|
|
* Unix.
|
|
*
|
|
* Inputs:
|
|
* fcn MapID_C for creator, MapID_G for group.
|
|
* id The id to be mapped, either group ID or creator ID.
|
|
*
|
|
* Outputs:
|
|
* OSErr Function result.
|
|
* name name corresponding to input ID.
|
|
*
|
|
*
|
|
*/
|
|
|
|
export OSErr
|
|
OSMapID(fcn,name,idd)
|
|
byte fcn;
|
|
char *name;
|
|
sdword idd; /* 4 bytes */
|
|
{
|
|
struct passwd *pwd;
|
|
struct group *grp;
|
|
int id = EtoIID(idd); /* convert to internal id */
|
|
|
|
if (DBOSI)
|
|
printf("OSMapID fcn=%s id=%d\n",
|
|
((fcn == MapID_C) ? "Creator" : "Group"),id);
|
|
|
|
if (idd == 0) {
|
|
name[0] = '\0';
|
|
return(noErr);
|
|
}
|
|
|
|
switch (fcn) {
|
|
case MapID_C:
|
|
pwd = getpwuid(id);
|
|
if (pwd == NULL)
|
|
return(aeItemNotFound);
|
|
strcpy(name,pwd->pw_name);
|
|
break;
|
|
|
|
case MapID_G:
|
|
grp = getgrgid(id);
|
|
if (grp == NULL)
|
|
return(aeItemNotFound);
|
|
strcpy(name,grp->gr_name);
|
|
break;
|
|
default:
|
|
return(aeParamErr);
|
|
}
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* OSErr OSMapName(byte fcn,char *name,sdword *id);
|
|
*
|
|
* This call is used to map a creator name to a creator ID or
|
|
* a group name to a group id.
|
|
*
|
|
* The creator name/id is identical to the user name and UID under
|
|
* Unix.
|
|
*
|
|
* Inputs:
|
|
* fcn MapName_C for creator, MapName_G for group.
|
|
* name Item to be mapped, either creator name or group name.
|
|
*
|
|
* Outputs:
|
|
* OSErr Function result.
|
|
* id ID corresponding to input name.
|
|
*
|
|
*
|
|
*/
|
|
|
|
OSErr
|
|
OSMapName(fcn,name,eid)
|
|
byte fcn;
|
|
char *name;
|
|
sdword *eid; /* 4 bytes */
|
|
{
|
|
struct passwd *pwd;
|
|
struct group *grp;
|
|
int id;
|
|
|
|
if (DBOSI)
|
|
printf("OSMapName fcn=%s name=%s\n",
|
|
(fcn == MapName_C) ? "Creator" : "Group",name);
|
|
|
|
if (name[0] == '\0') {
|
|
*eid = 0;
|
|
return(noErr);
|
|
}
|
|
|
|
switch (fcn) {
|
|
case MapName_C:
|
|
pwd = getpwnam(name);
|
|
if (pwd == NULL)
|
|
return(aeItemNotFound);
|
|
id = pwd->pw_uid; /* return user ID */
|
|
break;
|
|
|
|
case MapName_G:
|
|
grp = getgrnam(name); /* get group entry */
|
|
if (grp == NULL)
|
|
return(aeItemNotFound);
|
|
id = grp->gr_gid; /* return group ID */
|
|
break;
|
|
}
|
|
*eid = ItoEID(id); /* convert to external */
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* return information about a particular user id.
|
|
* if doself is true then return information about logged in user
|
|
* AFP2.0
|
|
*
|
|
*/
|
|
OSGetUserInfo(doself, userid, guirp)
|
|
boolean doself;
|
|
dword userid;
|
|
GetUserInfoReplyPkt *guirp;
|
|
{
|
|
int bm = guirp->guir_bitmap;
|
|
int usr = usruid;
|
|
int grp = usrgid;
|
|
struct passwd *pwd;
|
|
|
|
if (!doself) {
|
|
if ((pwd = (struct passwd *)getpwuid(EtoIID(userid))) == NULL)
|
|
return(aeItemNotFound);
|
|
usr = pwd->pw_uid;
|
|
grp = pwd->pw_gid;
|
|
}
|
|
/* Convert to external form */
|
|
guirp->guir_userid = ItoEID(usr);
|
|
guirp->guir_pgroup = ItoEID(grp);
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* get the server or login message from the specified file
|
|
* AFP2.1
|
|
*
|
|
*/
|
|
|
|
#define LOGINMSG 0
|
|
#define SERVERMSG 1
|
|
|
|
OSErr
|
|
OSGetSrvrMsg(typ, msg)
|
|
word typ;
|
|
byte *msg;
|
|
{
|
|
int fd, i, len;
|
|
char *msgfile;
|
|
extern char *motdfile;
|
|
extern char *messagefile;
|
|
|
|
msg[0] = '\0';
|
|
|
|
if (typ != LOGINMSG && typ != SERVERMSG)
|
|
return(noErr);
|
|
|
|
msgfile = (typ == LOGINMSG) ? motdfile : messagefile;
|
|
|
|
if (msgfile == NULL)
|
|
return(noErr);
|
|
|
|
if ((fd = open(msgfile, O_RDONLY, 0644)) >= 0) {
|
|
if ((len = read(fd, (char *)msg, SRVRMSGLEN-1)) >= 0) {
|
|
if (len == SRVRMSGLEN-1)
|
|
msg[len-1] = 0xc9; /* ... */
|
|
msg[len] = '\0';
|
|
for (i = 0; i < len; i++)
|
|
if (msg[i] == '\n')
|
|
msg[i] = '\r';
|
|
}
|
|
close(fd);
|
|
return(noErr);
|
|
}
|
|
|
|
sprintf(msg, "<no path to message file>");
|
|
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* OSErr OSDelete(IDirP ipdir, idir ,char *file)
|
|
*
|
|
* OSDelete is used to delete a file or an empty directory.
|
|
*
|
|
* Inputs:
|
|
* parent directory
|
|
* directory id of directory (null if file)
|
|
* file name in parent directory
|
|
*
|
|
* Outputs, OSErr Function result:
|
|
*
|
|
* ParamErr Bad path.
|
|
* ObjectNotFound Path does not point to an existing file or directory.
|
|
* DirNotEmpty The directory is not empty.
|
|
* FileBusy The file is open.
|
|
* AccessDenied User does not have the rights (specified in AFP spec).
|
|
* ObjectLocked AFP2.0: file or dir marked DeleteInhibit
|
|
* VolLocked AFP2.0: the volume is ReadOnly
|
|
*
|
|
*/
|
|
OSErr
|
|
OSDelete(ipdir,idir,file)
|
|
IDirP ipdir, idir;
|
|
char *file;
|
|
{
|
|
int err;
|
|
word attr;
|
|
extern int sessvers;
|
|
char path[MAXPATHLEN];
|
|
|
|
OSfname(path,ipdir,file,F_DATA); /* create data fork name */
|
|
#ifdef NOCASEMATCH
|
|
noCaseMatch(path);
|
|
#endif NOCASEMATCH
|
|
|
|
/* new for AFP2.0 */
|
|
OSGetAttr(ipdir,file,&attr);
|
|
if (attr & FPA_DEI)
|
|
return((sessvers == AFPVersion1DOT1) ? aeAccessDenied : aeObjectLocked);
|
|
|
|
if (DBOSI)
|
|
printf("OSDelete file=%s\n",path);
|
|
|
|
if (idir) {
|
|
err = os_rmdir(path,F_FNDR); /* remove finder dir */
|
|
if (err != noErr)
|
|
return(err);
|
|
err = os_rmdir(path,F_RSRC); /* delete resource directory */
|
|
if (err != noErr)
|
|
return(err);
|
|
err = unix_rmdir(path); /* delete the data file */
|
|
if (err != noErr)
|
|
return(err);
|
|
(void) os_delete(ipdir,file,F_FNDR); /* delete finder fork */
|
|
/* remove the dirid */
|
|
FModified(ipdir, file);
|
|
Idrdirid(ipdir, idir); /* idir is invalid after this point */
|
|
return(noErr); /* and return result */
|
|
}
|
|
|
|
err = unix_unlink(path); /* rid the data file */
|
|
if (err != noErr)
|
|
return(err);
|
|
(void) os_delete(ipdir,file,F_RSRC); /* delete resource fork */
|
|
(void) os_delete(ipdir,file,F_FNDR); /* delete finder fork */
|
|
FModified(ipdir, file);
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* OSErr os_rmdir(char *dir, int typ)
|
|
*
|
|
* Delete a finder/resource directory as specified by type which
|
|
* is either F_FNDR or F_RSRC.
|
|
*
|
|
* If a simple unix_rmdir fails because the directory is not empty
|
|
* then scan the directory for "junk" files and remove those.
|
|
*
|
|
* Junk files are leftovers which exist in our finder/resource
|
|
* directory but do not exist in the data directory. They don't
|
|
* usually occur under normal operation but cause a headache when
|
|
* they do since the folder can stay locked after a delete error.
|
|
*
|
|
*/
|
|
private OSErr
|
|
os_rmdir(dir,typ)
|
|
char *dir;
|
|
int typ;
|
|
{
|
|
char path[MAXPATHLEN]; /* resource/finder path */
|
|
char dpath[MAXPATHLEN]; /* data file path */
|
|
DIR *dirp;
|
|
#ifdef USEDIRENT
|
|
struct dirent *dp, *readdir();
|
|
#else USEDIRENT
|
|
struct direct *dp, *readdir();
|
|
#endif USEDIRENT
|
|
struct stat stb;
|
|
int pl,dpl,err;
|
|
|
|
/* create the directory path for this rmdir... either fndr or rsrc dir */
|
|
|
|
strcpy(path,dir); /* local copy of dir name */
|
|
if (typ == F_RSRC)
|
|
strcat(path,RFDIR); /* build resource directory name */
|
|
else
|
|
strcat(path,FIDIR); /* build finder directory name */
|
|
|
|
/* try deleting the directory */
|
|
|
|
err = unix_rmdir(path); /* try rmdir */
|
|
if (err == aeObjectNotFound) /* does not exist error? */
|
|
err = noErr; /* then ok by use */
|
|
if (err == noErr || /* deleted ok? */
|
|
err != aeDirNotEmpty) /* or unknown cause? */
|
|
return(err); /* then return now */
|
|
|
|
/* directory could not be deleted because it was not empty */
|
|
/* delete dir entries which are not in the data directory and try again */
|
|
|
|
strcpy(dpath,dir); /* local copy of data dir name */
|
|
dpl = strlen(dpath); /* find length */
|
|
dpath[dpl++] = '/'; /* append slash */
|
|
|
|
dirp = opendir(path); /* open the fndr/rsrc dir... */
|
|
if (dirp == NULL) /* does not exist etc? */
|
|
return(noErr); /* then no directory */
|
|
|
|
pl = strlen(path); /* set length of fndr/rsrc dir */
|
|
path[pl++] = '/'; /* add slash for file concats */
|
|
|
|
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
|
|
|
|
if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
|
|
(dp->d_name[0] == '.' && dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
|
|
continue; /* skip dot and dot dot */
|
|
|
|
strcpy(dpath+dpl,dp->d_name); /* compose name in data dir */
|
|
if (stat(dpath,&stb) == 0) { /* to see if it exists there */
|
|
closedir(dirp);
|
|
return(aeDirNotEmpty); /* if so... dir really not empty */
|
|
}
|
|
|
|
strcpy(path+pl,dp->d_name); /* otherwise use fndr/rsrc file name */
|
|
if (DBOSI)
|
|
printf("os_rmdir: cleaning %s\n",path);
|
|
err = unix_unlink(path); /* and remove */
|
|
if (err != noErr) { /* if that failed... */
|
|
closedir(dirp);
|
|
return(err); /* then return now */
|
|
}
|
|
}
|
|
closedir(dirp); /* finished with directory */
|
|
path[pl-1] = '\0'; /* back to fndr/rsrc name */
|
|
return(unix_rmdir(path)); /* try deleting now */
|
|
}
|
|
|
|
private OSErr
|
|
os_delete(pdir,file,typ)
|
|
IDirP pdir;
|
|
char *file;
|
|
int typ;
|
|
{
|
|
char path[MAXPATHLEN];
|
|
#ifdef NOCASEMATCH
|
|
register int i;
|
|
#endif NOCASEMATCH
|
|
|
|
OSfname(path,pdir,file,typ); /* build unix file name */
|
|
#ifdef NOCASEMATCH
|
|
if((i = unix_unlink(path)) != noErr) {
|
|
noCaseMatch(path);
|
|
i = unix_unlink(path);
|
|
}
|
|
return(i); /* do the work... */
|
|
#else NOCASEMATCH
|
|
return(unix_unlink(path)); /* do the work... */
|
|
#endif NOCASEMATCH
|
|
}
|
|
|
|
|
|
/*
|
|
* OSErr OSRename(IDirP pdir, char *from, char *to);
|
|
*
|
|
* OSRename is used to rename a file or directory.
|
|
*
|
|
* Inputs:
|
|
* pdir parent directory id.
|
|
* from name of file or directory to rename.
|
|
* to new name for file or directory.
|
|
*
|
|
* Outputs:
|
|
* OSErr Function result.
|
|
*
|
|
* Pass the work along to os_move, which handles the general case.
|
|
*
|
|
*/
|
|
|
|
OSErr
|
|
OSRename(pdir,from,to)
|
|
IDirP pdir; /* parent directory id */
|
|
char *from,*to; /* from and to file names */
|
|
{
|
|
return(os_move(pdir,from,pdir,to)); /* do the work */
|
|
}
|
|
|
|
/*
|
|
* OSErr OSMove(IDirP fpdir, char *from, IDirP tpdir, char *to)
|
|
*
|
|
* OSMove is used to move a directory or file to another location on
|
|
* a single volume (source and destination must be on the same volume).
|
|
* The destination of the move is specified by provinding a pathname
|
|
* that indicates the object's new parent directory.
|
|
*
|
|
* Inputs:
|
|
* fpdir parent directory id of from.
|
|
* from name of file or directory to rename.
|
|
* tpdir parent directory id of to.
|
|
* to new directory for file or directory.
|
|
*
|
|
* Outputs:
|
|
* OSErr Function result.
|
|
*
|
|
* Create an internal directory id for the new directory name by
|
|
* combining the parent dir id (tpdir), and directory name of the
|
|
* destination (to) and call the general routine os_move(). Note
|
|
* that the new name is the same as the old name and to specifies
|
|
* the destination directory.
|
|
*
|
|
*/
|
|
|
|
export OSErr
|
|
OSMove(fpdir,from,tpdir,to)
|
|
IDirP fpdir,tpdir; /* from and to parent dirs */
|
|
char *from; /* from file name */
|
|
char *to; /* to file name is dest directory */
|
|
{
|
|
return(os_move(fpdir, from, tpdir, to));
|
|
}
|
|
|
|
/*
|
|
* OSErr os_move(IDirP fpdir, char *from, IDirP tpdir, char *to)
|
|
*
|
|
* Move the file.
|
|
*
|
|
*/
|
|
private OSErr
|
|
os_move(fpdir,from,tpdir,to)
|
|
IDirP fpdir,tpdir; /* from and to parent dirs */
|
|
char *from,*to; /* from and to file names */
|
|
{
|
|
char f_path[MAXPATHLEN];
|
|
char t_path[MAXPATHLEN];
|
|
char fpath[MAXPATHLEN];
|
|
char tpath[MAXPATHLEN];
|
|
extern int sessvers;
|
|
struct stat stb;
|
|
word attr;
|
|
int err,cerr;
|
|
int mo;
|
|
#ifdef NOCASEMATCH
|
|
register char *pp;
|
|
#endif NOCASEMATCH
|
|
|
|
/* new for AFP2.0 */
|
|
OSGetAttr(fpdir,from,&attr);
|
|
if (attr & FPA_RNI)
|
|
return((sessvers == AFPVersion1DOT1) ? aeAccessDenied : aeObjectLocked);
|
|
|
|
OSfname(f_path,fpdir,from,F_DATA); /* build data file name */
|
|
OSfname(t_path,tpdir,to,F_DATA); /* for from and to files */
|
|
|
|
if (DBOSI)
|
|
printf("OSRename from=%s, to=%s\n",f_path,t_path);
|
|
|
|
if ((fpdir->flags & DID_FINDERINFO) && (tpdir->flags & DID_FINDERINFO) == 0)
|
|
return(aeCantMove);
|
|
if ((fpdir->flags & DID_RESOURCE) && (tpdir->flags & DID_RESOURCE) == 0)
|
|
return(aeCantMove);
|
|
|
|
/* must be able to stat destination */
|
|
#ifdef NOCASEMATCH
|
|
if ((err = unix_stat(pp = pathstr(tpdir), &stb)) != noErr) {
|
|
noCaseFind(pp);
|
|
if ((err = unix_stat(pp, &stb)) != noErr)
|
|
return(err);
|
|
}
|
|
#else NOCASEMATCH
|
|
if ((err = unix_stat(pathstr(tpdir), &stb)) != noErr)
|
|
return(err);
|
|
#endif NOCASEMATCH
|
|
mo = filemode(stb.st_mode, stb.st_uid, stb.st_gid);
|
|
|
|
#ifdef NOCASEMATCH
|
|
if ((err = unix_stat(f_path,&stb)) != noErr) {
|
|
noCaseFind(f_path);
|
|
if ((err = unix_stat(f_path,&stb)) != noErr)
|
|
return(err);
|
|
}
|
|
noCaseMatch(t_path);
|
|
#else NOCASEMATCH
|
|
if ((err = unix_stat(f_path,&stb)) != noErr)
|
|
return(err);
|
|
#endif NOCASEMATCH
|
|
|
|
err = unix_rename(f_path,t_path); /* give unix the args */
|
|
if (err != noErr) /* if an error on data files */
|
|
return(err); /* then give up */
|
|
|
|
#ifdef DENYREADWRITE
|
|
{
|
|
struct accessMode *p = accessMQueue;
|
|
|
|
while (p != (struct accessMode *)NULL) {
|
|
if (strcmp(f_path, p->path) == 0) {
|
|
strcpy(p->path, t_path);
|
|
break;
|
|
}
|
|
p = p->next;
|
|
}
|
|
}
|
|
#endif DENYREADWRITE
|
|
|
|
if (!S_ISDIR(stb.st_mode)) { /* directories have no rsrc fork */
|
|
unix_chmod(t_path, mo); /* file: try to reset protection */
|
|
if (fpdir->flags & DID_RESOURCE) {
|
|
strcpy(fpath, f_path);
|
|
strcpy(tpath, t_path);
|
|
toResFork(fpath,from); /* build resource file names */
|
|
toResFork(tpath,to);
|
|
err = unix_rename(fpath,tpath); /* give unix a shot at it */
|
|
/* allow non-existant resource */
|
|
if (err != noErr && err != aeObjectNotFound) { /* error on rename? */
|
|
if (DBOSI)
|
|
printf("os_rename: failed %s for %s -> %s\n",
|
|
afperr(err),fpath,tpath);
|
|
cerr = unix_rename(t_path,f_path); /* rename back to orignal */
|
|
if (cerr != noErr && DBOSI)
|
|
printf("os_rename: cleanup failed\n");
|
|
unix_chmod(t_path, stb.st_mode&0777); /* file:try to reset protection */
|
|
return(err);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fpdir->flags & DID_FINDERINFO) {
|
|
strcpy(fpath, f_path);
|
|
strcpy(tpath, t_path);
|
|
toFinderInfo(fpath,from); /* build finder info file names */
|
|
toFinderInfo(tpath,to);
|
|
err = unix_rename(fpath,tpath); /* give unix a shot at it */
|
|
if (err != noErr && DBOSI) {
|
|
printf("os_rename: failed %s for %s -> %s\n", afperr(err),fpath,tpath);
|
|
} else {
|
|
if (!S_ISDIR(stb.st_mode))
|
|
unix_chmod(tpath, mo); /* file: try to reset protection */
|
|
OSSetMacFileName(tpdir, to);
|
|
}
|
|
} else
|
|
if (DBOSI)
|
|
printf("os_rename: no finder info to rename\n");
|
|
|
|
if (S_ISDIR(stb.st_mode)) /* if a directory then need to */
|
|
Idmove(fpdir,from,tpdir,to); /* change internal structure */
|
|
else
|
|
FIdmove(fpdir,from,tpdir,to);
|
|
|
|
FModified(fpdir, from); /* does an emodified */
|
|
/* EModified(fpdir); */
|
|
/* don't need to mark dest file as modified since mac won't let this */
|
|
/* happen */
|
|
EModified(tpdir);
|
|
return(noErr);
|
|
}
|
|
|
|
|
|
/*
|
|
* OSErr OSFlush(int vid)
|
|
*
|
|
* OSFlush is used to flush to disk any data relating to the specified
|
|
* volume that has been modified by the user.
|
|
*
|
|
* The Unix system call sync is used. We should probably be dumping out
|
|
* internal volume buffers instead.
|
|
*
|
|
* Inputs:
|
|
* vid Volume ID.
|
|
*
|
|
* Outputs:
|
|
* OSErr Function Result.
|
|
*
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
export OSErr
|
|
OSFlush(vid)
|
|
int vid;
|
|
{
|
|
import GCHandle *fich; /* get FinderInfo cache */
|
|
|
|
GCFlush(fich, NILDIR); /* flush the finderinfo of bad data */
|
|
FlushDeskTop(vid);
|
|
/* sync(); /* this is probably a waste */
|
|
/* above is a waste and slows down system unnecessarily */
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* OSErr OSFlushFork(int fd)
|
|
*
|
|
* Forces the write to disk of any pending file activity.
|
|
*
|
|
* Really intended for buffered OSWrites.
|
|
*
|
|
* Inputs:
|
|
* fd File descriptor.
|
|
*
|
|
* Outputs:
|
|
* OSErr Function Result.
|
|
*
|
|
*/
|
|
|
|
OSErr
|
|
OSFlushFork(fd)
|
|
int fd;
|
|
{
|
|
if (DBOSI)
|
|
printf("OSFlushFork fd=%d\n",fd);
|
|
|
|
return(fsync(fd) == 0 ? noErr : aeMiscErr);
|
|
}
|
|
|
|
|
|
export OSErr
|
|
OSClose(fd)
|
|
int fd;
|
|
{
|
|
return(unix_close(fd)); /* return OSErr */
|
|
}
|
|
|
|
/*
|
|
* From the open file referenced by fd
|
|
* at the offset offs
|
|
* read "reqcnt" bytes
|
|
* using the new line mask nlmsk
|
|
* and the newline character nlchr
|
|
* into the buffer r for at most rl bytes
|
|
* keeping the file position in fpos
|
|
* translating from lf to cr if unixtomac is nonzero
|
|
*
|
|
*/
|
|
export OSErr
|
|
OSRead(fd,offs,reqcnt,nlmsk,nlchr,r,rl,fpos,trans_table_index)
|
|
int fd;
|
|
sdword offs,reqcnt;
|
|
byte nlmsk,nlchr;
|
|
byte *r;
|
|
int *rl;
|
|
sdword *fpos;
|
|
int trans_table_index;
|
|
{
|
|
register char c;
|
|
int cnt,i;
|
|
|
|
if (DBOSI)
|
|
printf("OSRead: fd=%d, pos=%d, off=%d, req=%d\n", fd, *fpos, offs, reqcnt);
|
|
|
|
#ifdef APPLICATION_MANAGER
|
|
{
|
|
extern int fdplist[NOFILE];
|
|
extern struct flist *applist;
|
|
|
|
if (applist != NULL && fdplist[fd] == 1) {
|
|
/* we want Finder copy protection */
|
|
if (offs == 0 && reqcnt > 128)
|
|
return(aeAccessDenied);
|
|
}
|
|
}
|
|
#endif APPLICATION_MANAGER
|
|
|
|
/* want to probe for eof -- probably there */
|
|
/* back off this. If the request count is zero, then */
|
|
/* don't tell them about EOF because zero length files */
|
|
/* will not get xfered properly */
|
|
if (reqcnt == 0) {
|
|
*rl = 0;
|
|
return(noErr);
|
|
}
|
|
|
|
if (offs != *fpos)
|
|
*fpos = lseek(fd,(off_t)offs,L_SET);
|
|
|
|
#ifdef APPLICATION_MANAGER
|
|
/*
|
|
* we have to resort to fcntl() lock tests
|
|
* because lockf() as used by OSTestLock()
|
|
* returns "permission denied" if more than
|
|
* one single byte read lock exists on fd.
|
|
* This is probably a bug, but since we are
|
|
* only interested in any write lock in the
|
|
* range it doesn't matter ...
|
|
*
|
|
*/
|
|
{
|
|
struct flock flck;
|
|
extern struct flist *applist;
|
|
|
|
if (applist != NULL) {
|
|
flck.l_type = F_RDLCK;
|
|
flck.l_whence = 1; /* SEEK_CUR */
|
|
#ifdef DENYREADWRITE
|
|
flck.l_start = 4;
|
|
#else DENYREADWRITE
|
|
flck.l_start = 0;
|
|
#endif DENYREADWRITE
|
|
flck.l_len = reqcnt;
|
|
if (fcntl(fd, F_GETLK, &flck) != -1) {
|
|
if (flck.l_type == F_WRLCK)
|
|
return(aeLockErr);
|
|
}
|
|
} else {
|
|
if (OSTestLock(fd, reqcnt) != noErr)
|
|
return(aeLockErr);
|
|
}
|
|
}
|
|
#else APPLICATION_MANAGER
|
|
if (OSTestLock(fd, reqcnt) != noErr) {
|
|
return(aeLockErr);
|
|
}
|
|
#endif APPLICATION_MANAGER
|
|
|
|
cnt = read(fd,r,reqcnt);
|
|
if (cnt < 0) {
|
|
printf("OSRead: Error from read %s\n",syserr());
|
|
return(aeParamErr);
|
|
}
|
|
|
|
if (cnt == 0)
|
|
return(aeEOFErr);
|
|
|
|
*fpos += cnt;
|
|
|
|
/* under appleshare prior to version 2.0, nlmask was either 0 or 0xff */
|
|
/* so no anding needed to be done (either use or not). shouldn't hurt */
|
|
/* to do it for previous versions though */
|
|
if (nlmsk != 0) {
|
|
#ifndef NONLXLATE
|
|
if (nlchr == ENEWLINE) {
|
|
for (i=0; i < cnt; i++) {
|
|
c = r[i] & nlmsk;
|
|
if (c == ENEWLINE || c == INEWLINE)
|
|
break;
|
|
}
|
|
if (r[i] == INEWLINE) /* if ended on internal newline */
|
|
r[i] = ENEWLINE; /* then convert to external */
|
|
} else
|
|
for (i=0; i < cnt && (r[i]&nlmsk) != nlchr; i++)
|
|
/* NULL */;
|
|
#else
|
|
for (i=0; i < cnt && (r[i]&nlmsk) != nlchr; i++)
|
|
/* NULL */;
|
|
#endif NONLXLATE
|
|
|
|
if (i < cnt) /* found it? */
|
|
cnt = i+1; /* yes count is position plus 1 */
|
|
}
|
|
if (trans_table_index >= 0) {
|
|
if (DBOSI)
|
|
printf("FPRead: translating to macintosh according to: %s\n",
|
|
ncs_tt_name(trans_table_index));
|
|
ncs_translate(NCS_TRANS_UNIXTOMAC, trans_table_index, r, cnt);
|
|
}
|
|
|
|
*rl = cnt; /* store count of bytes read */
|
|
if (cnt < reqcnt && nlmsk == 0) /* less than request and no nlchr */
|
|
return(aeEOFErr); /* means we found eof */
|
|
return(noErr); /* else no error.... */
|
|
}
|
|
|
|
/*
|
|
* Write to the open file referenced by fd
|
|
* the write buffer is wbuf of length wlen
|
|
* do the write at offset offs
|
|
* keeping file position in fpos
|
|
* flg - marks whether offs relative to beginning or end of file
|
|
* unixtomax - if non-zero translate cr to lf on writes
|
|
*
|
|
*/
|
|
OSWrite(fd,wbuf,wlen,offs,flg,fpos,trans_table_index)
|
|
int fd;
|
|
byte *wbuf;
|
|
sdword wlen,offs;
|
|
byte flg;
|
|
sdword *fpos;
|
|
int trans_table_index;
|
|
{
|
|
int cnt;
|
|
|
|
if (wlen == 0) /* zero byte request? */
|
|
return(noErr); /* yes... no work */
|
|
|
|
if (flg == 0) {
|
|
if (offs != *fpos)
|
|
*fpos = lseek(fd,(off_t)offs,L_SET);
|
|
} else
|
|
*fpos = lseek(fd,(off_t)offs,L_XTND);
|
|
|
|
if (OSTestLock(fd, wlen) != noErr) {
|
|
return(aeLockErr);
|
|
}
|
|
if (trans_table_index >= 0) {
|
|
if (DBOSI)
|
|
printf("FPWrite: translating from macintosh according to: %s\n",
|
|
ncs_tt_name(trans_table_index));
|
|
ncs_translate(NCS_TRANS_MACTOUNIX, trans_table_index, wbuf, wlen);
|
|
}
|
|
|
|
cnt = write(fd,wbuf,wlen);
|
|
*fpos += cnt;
|
|
if (cnt == wlen)
|
|
return(noErr);
|
|
if (DBOSI)
|
|
printf("OSWrite: Error from write %s\n",syserr());
|
|
return(ItoEErr(errno));
|
|
}
|
|
|
|
/*
|
|
* OSErr OSCreateDir(char *path,dword *dirid)
|
|
*
|
|
* This function is used to create a new directory.
|
|
*
|
|
* Inputs:
|
|
* path The directory to create.
|
|
*
|
|
* Outputs:
|
|
* OSErr Function result.
|
|
* dirid Directory ID of newly created directory.
|
|
*
|
|
*/
|
|
|
|
private OSErr
|
|
os_mkdir(pdir,name,mode,typ)
|
|
IDirP pdir; /* parent directory */
|
|
char *name;
|
|
int typ,mode;
|
|
{
|
|
char path[MAXPATHLEN];
|
|
OSErr err;
|
|
/* want path/name/.resource */
|
|
/* want path/name/.finderinfo */
|
|
/* want path/name */
|
|
|
|
OSfname(path, pdir, name, F_DATA); /* get path/name */
|
|
#ifdef NOCASEMATCH
|
|
noCaseMatch(path);
|
|
#endif NOCASEMATCH
|
|
switch (typ) {
|
|
case F_RSRC:
|
|
strcat(path, RFDIR);
|
|
break;
|
|
case F_FNDR:
|
|
strcat(path, FIDIR);
|
|
break;
|
|
}
|
|
if (DBOSI)
|
|
printf("os_mkdir: creating mode=o%o dir=%s\n",mode,path);
|
|
|
|
err = unix_mkdir(path,mode); /* let unix do the work */
|
|
if (err != noErr)
|
|
return(err);
|
|
EModified(pdir);
|
|
return(noErr);
|
|
}
|
|
|
|
|
|
OSErr
|
|
OSCreateDir(pdir,name, newdirid)
|
|
IDirP pdir; /* parent directory id */
|
|
char *name; /* name of new directory */
|
|
IDirP *newdirid;
|
|
{
|
|
char path[MAXPATHLEN];
|
|
int err,mo;
|
|
struct stat stb;
|
|
|
|
if (DBOSI)
|
|
printf("OSCreateDir: creating %s\n",name);
|
|
|
|
err = unix_stat(pathstr(pdir),&stb); /* get current protections */
|
|
mo = stb.st_mode & 0777;
|
|
|
|
err = os_mkdir(pdir,name,mo,F_DATA); /* create the data directory */
|
|
if (err != noErr) /* if that failed... then */
|
|
return(err); /* return the error */
|
|
|
|
if (pdir->flags & DID_FINDERINFO) {
|
|
OSfname(path,pdir,name,F_FNDR); /* create finderinfo for folder */
|
|
#ifdef NOCASEMATCH
|
|
noCaseMatch(path);
|
|
#endif NOCASEMATCH
|
|
err = unix_create(path,TRUE,mo); /* do delete if exists... */
|
|
os_mkdir(pdir,name,mo,F_FNDR); /* create the finderinfo directory */
|
|
}
|
|
if (pdir->flags & DID_RESOURCE)
|
|
os_mkdir(pdir,name,mo,F_RSRC); /* create the resource directory */
|
|
*newdirid = Idndirid(pdir,name); /* now install the directory */
|
|
return(noErr);
|
|
}
|
|
|
|
|
|
/*
|
|
* OSErr OSFileDirInfo(IDirP ipdir, char *fn,
|
|
* FileDirParms *fdp, int volid);
|
|
*
|
|
* Return information for file fn, existing in directory ipdir into
|
|
* the fdp structure.
|
|
*
|
|
* fdp->fdp_dbitmap and fdp->fdp_fbitmap are set with the request
|
|
* bitmaps so we don't necessarily need to fetch unwanted (costly)
|
|
* items.
|
|
*
|
|
*/
|
|
export OSErr
|
|
OSFileDirInfo(ipdir,idir,fn,fdp,volid)
|
|
IDirP ipdir; /* parent directory */
|
|
IDirP idir; /* directory id if directory */
|
|
char *fn; /* file name */
|
|
FileDirParm *fdp; /* returned parms */
|
|
int volid; /* volume */
|
|
{
|
|
char path[MAXPATHLEN];
|
|
struct stat buf;
|
|
time_t sometime;
|
|
|
|
OSfname(path,ipdir,fn,F_DATA);
|
|
|
|
if (DBOSI)
|
|
printf("OSFileDirInfo on %s, idir = %02x,%02x\n",path,idir,VolRootD(volid));
|
|
|
|
#ifndef STAT_CACHE
|
|
if (stat(path,&buf) != 0) { /* file exists? */
|
|
#else STAT_CACHE
|
|
if (OSstat(path,&buf) != 0) { /* file exists? */
|
|
#endif STAT_CACHE
|
|
#ifdef NOCASEMATCH
|
|
noCaseFind(path); /* case-insensitive */
|
|
#ifndef STAT_CACHE
|
|
if (stat(path,&buf) != 0) { /* file exists? */
|
|
#else STAT_CACHE
|
|
if (OSstat(path,&buf) != 0) { /* file exists? */
|
|
#endif STAT_CACHE
|
|
if (idir) /* was in directory tree? */
|
|
Idrdirid(ipdir, idir); /* invalidate the entry then */
|
|
return(aeObjectNotFound); /* no... */
|
|
}
|
|
#else NOCASEMATCH
|
|
if (idir) /* was in directory tree? */
|
|
Idrdirid(ipdir, idir); /* invalidate the entry then */
|
|
return(aeObjectNotFound); /* no... */
|
|
#endif NOCASEMATCH
|
|
}
|
|
|
|
/* pick out the earliest date for mac creation time */
|
|
sometime = (buf.st_mtime > buf.st_ctime) ? buf.st_ctime : buf.st_mtime;
|
|
fdp->fdp_cdate = (sometime > buf.st_atime) ? buf.st_atime : sometime;
|
|
/* pick the later of status change and modification for mac modified */
|
|
fdp->fdp_mdate = (buf.st_mtime < buf.st_ctime) ? buf.st_ctime : buf.st_mtime;
|
|
|
|
#ifdef USE_MAC_DATES
|
|
{ time_t when;
|
|
OSGetCDate(ipdir,fn,&fdp->fdp_cdate);
|
|
if (OSGetMDate(ipdir,fn,&sometime,&when) == noErr)
|
|
if (fdp->fdp_mdate < (when+5)) /* fuzz factor */
|
|
fdp->fdp_mdate = sometime;
|
|
}
|
|
#endif USE_MAC_DATES
|
|
|
|
fdp->fdp_bdate = 0;
|
|
fdp->fdp_zero = 0; /* zero the zero byte (?) */
|
|
#ifdef SHORT_NAMES
|
|
if (idir == VolRootD(volid)) {
|
|
if ((fdp->fdp_dbitmap & DP_SNAME) || (fdp->fdp_fbitmap & FP_SNAME)) {
|
|
/* change this for volume names */
|
|
strcpy(fdp->fdp_sname,(char *) VolSName(volid));
|
|
if (DBOSI && fdp != NULL)
|
|
printf("dirParms sname %s\n",fdp->fdp_sname);
|
|
}
|
|
if ((fdp->fdp_dbitmap & DP_LNAME) || (fdp->fdp_fbitmap & FP_LNAME)) {
|
|
strcpy(fdp->fdp_lname, (char *) VolName(volid));
|
|
if (DBOSI && fdp != NULL)
|
|
printf("dirParms lname %s\n",fdp->fdp_lname);
|
|
}
|
|
} else {
|
|
if ((fdp->fdp_dbitmap & DP_SNAME) || (fdp->fdp_fbitmap & FP_SNAME))
|
|
ItoEName_Short(ipdir,fn,fdp->fdp_sname);
|
|
if ((fdp->fdp_dbitmap & DP_LNAME) || (fdp->fdp_fbitmap & FP_LNAME))
|
|
ItoEName(fn,fdp->fdp_lname);
|
|
}
|
|
#else SHORT_NAMES
|
|
if (idir == VolRootD(volid))
|
|
strcpy(fdp->fdp_lname, (char *) VolName(volid));
|
|
else
|
|
ItoEName(fn,fdp->fdp_lname);
|
|
#endif SHORT_NAMES
|
|
|
|
if (S_ISDIR(buf.st_mode)) { /* is this a directory? */
|
|
fdp->fdp_flg = FDP_DIRFLG; /* yes... */
|
|
return(OSDirInfo(ipdir,fn,fdp,&buf,volid)); /* fill in */
|
|
}
|
|
fdp->fdp_flg = 0; /* otherwise a file */
|
|
#ifdef SHORT_NAMES
|
|
/* The PC asks for this information and wasn't implemented */
|
|
/* should we be doing this for directories as well as files ? */
|
|
if (fdp->fdp_fbitmap & FP_PDIR)
|
|
fdp->fdp_pdirid = ItoEdirid(ipdir,volid);
|
|
#endif SHORT_NAMES
|
|
return(OSFileInfo(ipdir,fn,fdp,&buf,path)); /* fill in */
|
|
}
|
|
|
|
|
|
export OSErr
|
|
OSDirInfo(ipdir,fn,fdp,buf,volid)
|
|
IDirP ipdir;
|
|
char *fn;
|
|
FileDirParm *fdp;
|
|
struct stat *buf;
|
|
int volid;
|
|
{
|
|
IDirP idirid;
|
|
dword ItoEAccess();
|
|
char path[MAXPATHLEN];
|
|
dirFinderInfo *dfi;
|
|
word bm;
|
|
int nchild;
|
|
extern int sessvers;
|
|
|
|
fdp->fdp_dbitmap &= DP_AUFS_VALID; /* truncate to findable */
|
|
if (sessvers == AFPVersion1DOT1) /* AFP1.1 ignores PRODOS */
|
|
fdp->fdp_dbitmap &= ~DP_PDOS;
|
|
bm = fdp->fdp_dbitmap;
|
|
|
|
if (DBDIR)
|
|
printf("OSDirInfo on %s bm=%x\n",fn,bm);
|
|
|
|
if (bm & DP_ATTR) /* skip attr if not requested */
|
|
OSGetAttr(ipdir,fn,&fdp->fdp_attr);
|
|
|
|
if (bm & (DP_FINFO|DP_PDOS)) { /* skip finfo if not requested */
|
|
OSGetFNDR(ipdir,fn,fdp->fdp_finfo);
|
|
dfi = (dirFinderInfo *)fdp->fdp_finfo;
|
|
OSfname(path, ipdir, fn, F_DATA);
|
|
strcat(path, "/Icon:0d");
|
|
if (access(path, R_OK) == 0)
|
|
dfi->frFlags |= htons(FNDR_fHasCustomIcon); /* has custom ICON */
|
|
else
|
|
dfi->frFlags &= htons(~FNDR_fHasCustomIcon); /* no custom ICON */
|
|
}
|
|
|
|
if (bm & DP_PDOS) /* generate some ProDOS info. */
|
|
mapFNDR2PDOS(fdp);
|
|
|
|
fdp->fdp_parms.dp_parms.dp_ownerid = ItoEID(buf->st_uid);
|
|
fdp->fdp_parms.dp_parms.dp_groupid = ItoEID(buf->st_gid);
|
|
fdp->fdp_parms.dp_parms.dp_accright =
|
|
ItoEAccess(buf->st_mode,buf->st_uid,buf->st_gid);
|
|
|
|
idirid = Idndirid(ipdir,fn); /* must validate the entry now */
|
|
if (idirid == NILDIR)
|
|
return(aeAccessDenied);
|
|
InitDIDVol(idirid, volid);
|
|
#ifdef notdef
|
|
/* should be done already - so don't do it here! */
|
|
if ((idirid->flags & DID_VALID) == 0) /* info valid? */
|
|
OSValidateDIDDirInfo(idirid); /* valid it then */
|
|
#endif
|
|
if (bm & DP_CHILD) {
|
|
nchild = OSEnumCount(idirid);
|
|
if (nchild < 0) /* error if less than zero */
|
|
nchild = 0; /* probably no read... set to 0 */
|
|
fdp->fdp_parms.dp_parms.dp_nchild = nchild;
|
|
}
|
|
fdp->fdp_parms.dp_parms.dp_dirid = ItoEdirid(idirid,volid);
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* validates a did by making sure:
|
|
* - idirid points to a directory
|
|
* - limits number of symbolic links we will follow in any given path!
|
|
* o note: overlapping volumes may cause us to follow too many
|
|
* symbolic links, but things should eventually catch up.
|
|
* also checks if the .resource and .finderinfo directories exists
|
|
* (must not be symbolic links)
|
|
* double check that parent exists
|
|
*/
|
|
export void
|
|
OSValidateDIDDirInfo(idirid)
|
|
IDirP idirid;
|
|
{
|
|
char path[MAXPATHLEN];
|
|
char p_ath[MAXPATHLEN];
|
|
struct stat stb;
|
|
IDirP pdir;
|
|
int i;
|
|
|
|
OSfname(p_ath,idirid,"",F_DATA);
|
|
#ifndef STAT_CACHE
|
|
i = stat(p_ath, &stb);
|
|
#else STAT_CACHE
|
|
i = OSstat(p_ath, &stb);
|
|
#endif STAT_CACHE
|
|
#ifdef NOCASEMATCH
|
|
if(i != 0) {
|
|
noCaseFind(p_ath);
|
|
#ifndef STAT_CACHE
|
|
i = stat(p_ath, &stb);
|
|
#else STAT_CACHE
|
|
i = OSstat(p_ath, &stb);
|
|
#endif STAT_CACHE
|
|
}
|
|
#endif NOCASEMATCH
|
|
if (i == 0) {
|
|
if (S_ISDIR(stb.st_mode))
|
|
idirid->flags |= DID_DATA;
|
|
#ifndef NOLSTAT
|
|
#ifndef STAT_CACHE
|
|
if (lstat(p_ath, &stb) != 0) { /* shouldn't fail! */
|
|
idirid->flags = DID_VALID;
|
|
return;
|
|
}
|
|
if ((pdir = Ipdirid(idirid)) != NILDIR) { /* get parent */
|
|
/* get count of symlinks of parent */
|
|
i = ((pdir->flags & DID_SYMLINKS) >> DID_SYMLINKS_SHIFT);
|
|
if ((stb.st_mode & S_IFMT) == S_IFLNK) {
|
|
i++; /* bump up count */
|
|
if (i > DID_MAXSYMLINKS) {
|
|
idirid->flags = DID_VALID; /* toss it, too many links down */
|
|
return;
|
|
}
|
|
}
|
|
/* really shouldn't need to mask it - means we are overinc'ed */
|
|
idirid->flags |= ((i << DID_SYMLINKS_SHIFT) & DID_SYMLINKS);
|
|
}
|
|
#endif STAT_CACHE
|
|
/* don't follow symbolic links here! */
|
|
#ifdef STAT_CACHE
|
|
if (idirid->flags & DID_DATA) { /* Dan */
|
|
#endif STAT_CACHE
|
|
strcpy(path,p_ath);
|
|
toFinderInfo(path,"");
|
|
#ifndef STAT_CACHE
|
|
if (lstat(path, &stb) == 0)
|
|
if (S_ISDIR(stb.st_mode))
|
|
#else STAT_CACHE
|
|
if (OSfinderinfo(p_ath))
|
|
#endif STAT_CACHE
|
|
idirid->flags |= DID_FINDERINFO;
|
|
strcpy(path,p_ath);
|
|
toResFork(path,"");
|
|
#ifndef STAT_CACHE
|
|
if (lstat(path, &stb) == 0)
|
|
if (S_ISDIR(stb.st_mode))
|
|
#else STAT_CACHE
|
|
if (OSresourcedir(p_ath))
|
|
#endif STAT_CACHE
|
|
idirid->flags |= DID_RESOURCE;
|
|
#ifdef STAT_CACHE
|
|
}
|
|
#endif STAT_CACHE
|
|
#else NOLSTAT
|
|
/* no symolic links then */
|
|
strcpy(path,p_ath);
|
|
toFinderInfo(path,"");
|
|
#ifndef STAT_CACHE
|
|
if (stat(path, &stb) == 0)
|
|
if (S_ISDIR(stb.st_mode))
|
|
#else STAT_CACHE
|
|
if (OSfinderinfo(p_ath)
|
|
#endif STAT_CACHE
|
|
idirid->flags |= DID_FINDERINFO;
|
|
strcpy(path,p_ath);
|
|
toResFork(path,"");
|
|
#ifndef STAT_CACHE
|
|
if (stat(path, &stb) == 0)
|
|
if (S_ISDIR(stb.st_mode))
|
|
#else STAT_CACHE
|
|
if (OSresourcedir(p_ath)
|
|
#endif STAT_CACHE
|
|
idirid->flags |= DID_RESOURCE;
|
|
#endif NOLSTAT
|
|
}
|
|
idirid->flags |= DID_VALID;
|
|
}
|
|
|
|
export OSErr
|
|
OSFileInfo(ipdir,fn,fdp,buf,rpath)
|
|
IDirP ipdir;
|
|
char *fn,*rpath;
|
|
FileDirParm *fdp;
|
|
struct stat *buf;
|
|
{
|
|
struct stat stb;
|
|
word bm;
|
|
extern int sessvers;
|
|
|
|
fdp->fdp_fbitmap &= FP_AUFS_VALID; /* truncate to aufs supported */
|
|
if (sessvers == AFPVersion1DOT1) /* AFP1.1 ignores PRODOS */
|
|
fdp->fdp_dbitmap &= ~FP_PDOS;
|
|
bm = fdp->fdp_fbitmap; /* fetch file bitmap */
|
|
|
|
if (DBDIR)
|
|
printf("OSFileInfo on %s bm=%x\n",fn,bm);
|
|
|
|
if (bm & FP_ATTR) /* skip attr if not requested */
|
|
OSGetAttr(ipdir,fn,&fdp->fdp_attr);
|
|
|
|
if (bm & (FP_FINFO|FP_PDOS)) /* skip finfo if not requested */
|
|
OSGetFNDR(ipdir,fn,fdp->fdp_finfo);
|
|
|
|
if (bm & FP_PDOS) /* generate some ProDOS info. */
|
|
mapFNDR2PDOS(fdp);
|
|
|
|
/* don't have volid available here ...
|
|
#ifdef SHORT_NAMES
|
|
if (fdp->fdp_fbitmap & FP_PDIR)
|
|
fdp->fdp_pdirid = ItoEdirid(ipdir,volid);
|
|
#endif SHORT_NAMES
|
|
*/
|
|
|
|
fdp->fdp_parms.fp_parms.fp_fileno = buf->st_ino;
|
|
fdp->fdp_parms.fp_parms.fp_dflen = buf->st_size;
|
|
fdp->fdp_parms.fp_parms.fp_rflen = 0;
|
|
|
|
#ifndef STAT_CACHE
|
|
if (bm & FP_RFLEN) {
|
|
#else STAT_CACHE
|
|
if ((bm & FP_RFLEN) && ipdir != NULL && (ipdir->flags&DID_RESOURCE)) {/*Dan*/
|
|
#endif STAT_CACHE
|
|
toResFork(rpath,fn); /* convert to rsrc name */
|
|
if (stat(rpath,&stb) != 0) /* to figure size of resource fork */
|
|
return(noErr);
|
|
if (DBFIL)
|
|
printf("OSFileInfo: %s size is %d\n", rpath, (int)stb.st_size);
|
|
fdp->fdp_parms.fp_parms.fp_rflen = stb.st_size;
|
|
}
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* simply check to see if a particular file exists
|
|
*
|
|
*/
|
|
export OSErr
|
|
OSFileExists(ipdir, fn, type)
|
|
IDirP ipdir;
|
|
char *fn;
|
|
int type;
|
|
{
|
|
char path[MAXPATHLEN];
|
|
struct stat stb;
|
|
#ifdef NOCASEMATCH
|
|
register int i;
|
|
#endif NOCASEMATCH
|
|
|
|
OSfname(path, ipdir, fn, type);
|
|
#ifdef NOCASEMATCH
|
|
if((i = unix_stat(path, &stb)) != noErr) {
|
|
noCaseFind(path);
|
|
i = unix_stat(path, &stb);
|
|
}
|
|
return(i);
|
|
#else NOCASEMATCH
|
|
return(unix_stat(path, &stb));
|
|
#endif NOCASEMATCH
|
|
}
|
|
|
|
export OSErr
|
|
OSSetFileDirParms(ipdir,idir,fn,fdp)
|
|
IDirP ipdir;
|
|
IDirP idir; /* directory id if dir */
|
|
char *fn;
|
|
FileDirParm *fdp;
|
|
{
|
|
char path[MAXPATHLEN];
|
|
struct stat stb;
|
|
int err;
|
|
|
|
OSfname(path,ipdir,fn,F_DATA); /* unix file name */
|
|
if ((err = unix_stat(path,&stb)) != noErr) {
|
|
#ifdef NOCASEMATCH
|
|
noCaseFind(path);
|
|
if ((err = unix_stat(path,&stb)) != noErr) {
|
|
#endif NOCASEMATCH
|
|
/* can't find it !!! */
|
|
if (idir)
|
|
Idrdirid(ipdir, idir); /* remove from tree */
|
|
return(err);
|
|
#ifdef NOCASEMATCH
|
|
}
|
|
#endif NOCASEMATCH
|
|
}
|
|
|
|
if (S_ISDIR(stb.st_mode)) /* if a directory */
|
|
return(OSSetDirParms(ipdir,fn,fdp)); /* then set dir parms... */
|
|
else /* else set file parms */
|
|
return(OSSetFileParms(ipdir,fn,fdp));
|
|
}
|
|
|
|
export OSErr
|
|
OSSetFileParms(ipdir,fn,fdp)
|
|
IDirP ipdir;
|
|
char *fn;
|
|
FileDirParm *fdp;
|
|
{
|
|
word bm = fdp->fdp_fbitmap;
|
|
|
|
#ifdef USE_MAC_DATES
|
|
if (bm & (FP_FINFO|FP_ATTR|FP_PDOS|FP_CDATE|FP_MDATE))
|
|
#else USE_MAC_DATES
|
|
if (bm & (FP_FINFO|FP_ATTR|FP_PDOS))
|
|
#endif USE_MAC_DATES
|
|
OSSetFA(ipdir,fn,fdp->fdp_fbitmap,fdp);
|
|
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* OSSetDirParms
|
|
*
|
|
*/
|
|
|
|
OSErr
|
|
OSSetDirParms(ipdir,fn,fdp)
|
|
IDirP ipdir;
|
|
char *fn;
|
|
FileDirParm *fdp;
|
|
{
|
|
u_short EtoIAccess();
|
|
char p_ath[MAXPATHLEN];
|
|
char path[MAXPATHLEN];
|
|
int flags, err;
|
|
int own, grp; /* owner and group ids */
|
|
DirParm *dp = &fdp->fdp_parms.dp_parms;
|
|
#ifdef NETWORKTRASH
|
|
struct stat buf;
|
|
#endif NETWORKTRASH
|
|
|
|
#ifdef USE_MAC_DATES
|
|
if (fdp->fdp_dbitmap & (DP_FINFO|DP_ATTR|DP_PDOS|DP_CDATE|DP_MDATE))
|
|
#else USE_MAC_DATES
|
|
if (fdp->fdp_dbitmap & (DP_FINFO|DP_ATTR|DP_PDOS))
|
|
#endif USE_MAC_DATES
|
|
OSSetFA(ipdir,fn,fdp->fdp_dbitmap,fdp);
|
|
|
|
grp = own = -1;
|
|
if (fdp->fdp_dbitmap & DP_CRTID)
|
|
own = EtoIID(dp->dp_ownerid);
|
|
if (fdp->fdp_dbitmap & DP_GRPID)
|
|
grp = EtoIID(dp->dp_groupid);
|
|
|
|
flags = ipdir->flags; /* should use to prevent overworking */
|
|
if (own != -1 || grp != -1) {
|
|
/* error recovery? do all just in case */
|
|
OSfname(p_ath,ipdir,fn,F_DATA);
|
|
/* change owner/group for fn */
|
|
if ((err = unix_chown(p_ath,own,grp)) != noErr) {
|
|
#ifdef NOCASEMATCH
|
|
noCaseFind(p_ath);
|
|
if ((err = unix_chown(p_ath,own,grp)) != noErr)
|
|
#endif NOCASEMATCH
|
|
return(err);
|
|
}
|
|
/* change owner/group for fn/.resource */
|
|
strcpy(path,p_ath); strcat(path,RFDIR);
|
|
if ((err = unix_chown(path,own,grp)) != noErr && err != aeObjectNotFound)
|
|
return(err);
|
|
|
|
/* change owner/group for fn/.finderinfo */
|
|
strcpy(path,p_ath); strcat(path,FIDIR);
|
|
if ((err = unix_chown(path,own,grp)) != noErr && err != aeObjectNotFound)
|
|
return(err);
|
|
|
|
/* change owner/group for ../.resource/fn */
|
|
OSfname(path,ipdir,fn,F_RSRC);
|
|
if ((err = unix_chown(path,own,grp)) != noErr && err != aeObjectNotFound) {
|
|
#ifdef NOCASEMATCH
|
|
noCaseFind(path);
|
|
if ((err = unix_chown(path,own,grp)) != noErr && err != aeObjectNotFound)
|
|
#endif NOCASEMATCH
|
|
return(err);
|
|
}
|
|
|
|
/* change owner/group for ../.finderinfo/fn */
|
|
OSfname(path,ipdir,fn,F_FNDR);
|
|
if ((err = unix_chown(path,own,grp)) != noErr && err != aeObjectNotFound) {
|
|
#ifdef NOCASEMATCH
|
|
noCaseFind(path);
|
|
if ((err = unix_chown(path,own,grp)) != noErr && err != aeObjectNotFound)
|
|
#endif NOCASEMATCH
|
|
return(err);
|
|
}
|
|
EModified(ipdir);
|
|
}
|
|
|
|
if (fdp->fdp_dbitmap & DP_ACCES) {
|
|
u_short acc, accd; /* file, directory mode */
|
|
acc = accd = EtoIAccess(dp->dp_accright);
|
|
#ifdef NETWORKTRASH
|
|
/* make the Network Trash Folder the same */
|
|
/* access mode as the parent directory */
|
|
if (*fn == 'N') { /* if first letter is 'N' */
|
|
if (strcmp(fn, "Network Trash Folder") == 0
|
|
#ifndef STAT_CACHE
|
|
&& stat(pathstr(ipdir),&buf) == 0 /* and stat() OK */
|
|
#else STAT_CACHE
|
|
&& OSstat(pathstr(ipdir),&buf) == 0 /* and stat() OK */
|
|
#endif STAT_CACHE
|
|
)
|
|
/* parent directory mode */
|
|
acc = accd = buf.st_mode;
|
|
}
|
|
#endif NETWORKTRASH
|
|
#ifdef USEDIRSETGID
|
|
if (grp != usrgid)
|
|
accd |= I_SETGID;
|
|
#endif USEDIRSETGID
|
|
|
|
/* change mode for fn */
|
|
if ((err = os_chmod(ipdir,fn,accd,F_DATA)) != noErr)
|
|
return(err);
|
|
|
|
/* change all file protections, owner & group in fn */
|
|
os_change_all(ipdir, fn, acc, own, grp, F_DATA);
|
|
os_change_all(ipdir, fn, acc, own, grp, F_RSRC);
|
|
os_change_all(ipdir, fn, acc, own, grp, F_FNDR);
|
|
|
|
OSfname(p_ath,ipdir,fn,F_DATA);
|
|
/* change mode for fn/.resource */
|
|
strcpy(path,p_ath); strcat(path,RFDIR);
|
|
if (( err = unix_chmod(path,accd)) != noErr && err != aeObjectNotFound) {
|
|
#ifdef NOCASEMATCH
|
|
noCaseFind(path);
|
|
if (( err = unix_chmod(path,accd)) != noErr && err != aeObjectNotFound)
|
|
#endif NOCASEMATCH
|
|
return(err);
|
|
}
|
|
|
|
/* change mode for fn/.finderinfo */
|
|
strcpy(path,p_ath); strcat(path,FIDIR);
|
|
if (( err = unix_chmod(path,accd)) != noErr && err != aeObjectNotFound) {
|
|
#ifdef NOCASEMATCH
|
|
noCaseFind(path);
|
|
if (( err = unix_chmod(path,accd)) != noErr && err != aeObjectNotFound)
|
|
#endif NOCASEMATCH
|
|
return(err);
|
|
}
|
|
|
|
/* change mode for ../.resource/fn */
|
|
if ((err = os_chmod(ipdir,fn,acc,F_RSRC)) != noErr &&
|
|
err != aeObjectNotFound)
|
|
return(err);
|
|
|
|
/* change mode for ../.finderinfo/fn */
|
|
if ((err = os_chmod(ipdir,fn,acc,F_FNDR)) != noErr &&
|
|
err != aeObjectNotFound)
|
|
return(err);
|
|
}
|
|
return(noErr);
|
|
}
|
|
|
|
|
|
/*
|
|
* Set fork length specified the file handle
|
|
* - careful about len - should be at least a signed double word
|
|
* on mac (4 bytes)
|
|
*/
|
|
export OSErr
|
|
OSSetForklen(fd, len)
|
|
int fd;
|
|
int len;
|
|
{
|
|
int err;
|
|
if (DBOSI)
|
|
printf("OSSetForklen: truncating file on file descriptor %d to %d\n",
|
|
fd,len);
|
|
if (ftruncate(fd, len) < 0) {
|
|
err = errno;
|
|
if (DBOSI)
|
|
printf("OSSetForklen: error on truncate %s\n",syserr());
|
|
return(ItoEErr(err));
|
|
}
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* OSErr os_chmod(IDirP idir, u_short mode, int typ)
|
|
*
|
|
* Directory id (idir), and type (typ) specify a directory name.
|
|
* Internal access bits are mode.
|
|
*
|
|
* Change the protection of the directory to eacc.
|
|
*
|
|
*/
|
|
private OSErr
|
|
os_chmod(idir,fn,mode,typ)
|
|
IDirP idir;
|
|
char *fn;
|
|
u_short mode;
|
|
int typ;
|
|
{
|
|
char path[MAXPATHLEN];
|
|
int err;
|
|
|
|
OSfname(path,idir,fn,typ); /* convert unix name */
|
|
if (DBOSI)
|
|
printf("os_chmod: setting %o for %s\n",mode,path);
|
|
|
|
err = unix_chmod(path,mode); /* and set for the directory */
|
|
#ifdef NOCASEMATCH
|
|
if (err != noErr) {
|
|
noCaseFind(path);
|
|
if((err = unix_chmod(path,mode)) != noErr)
|
|
return(err);
|
|
}
|
|
#else NOCASEMATCH
|
|
if (err != noErr)
|
|
return(err);
|
|
#endif NOCASEMATCH
|
|
|
|
EModified(idir);
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* Change file protection, owner & group for all files in directory
|
|
*
|
|
* Have to do because:
|
|
* unix has file protection and AFP does not, change the protection
|
|
* of each file in the directory as well.
|
|
*
|
|
* Do not change the protection of directories contained within
|
|
* the directory...
|
|
*
|
|
*/
|
|
private void
|
|
os_change_all(idir,fn,mode,own,grp,typ)
|
|
IDirP idir;
|
|
char *fn;
|
|
u_short mode;
|
|
int own, grp, typ;
|
|
{
|
|
char path[MAXPATHLEN];
|
|
char p_ath[MAXPATHLEN];
|
|
struct stat stb;
|
|
#ifdef USEDIRENT
|
|
struct dirent *dp, *readdir();
|
|
#else USEDIRENT
|
|
struct direct *dp, *readdir();
|
|
#endif USEDIRENT
|
|
DIR *dirp;
|
|
int pl,err;
|
|
|
|
OSfname(path,idir,fn,F_DATA); /* convert unix name */
|
|
pl = strlen(path);
|
|
switch (typ) {
|
|
case F_DATA:
|
|
break;
|
|
case F_RSRC:
|
|
strcpy(path+pl, RFDIR);
|
|
break;
|
|
case F_FNDR:
|
|
strcpy(path+pl, FIDIR);
|
|
break;
|
|
}
|
|
if (DBOSI)
|
|
printf("os_change_all: setting %o for %s\n",mode,path);
|
|
|
|
dirp = opendir(path);
|
|
if (dirp == NULL) {
|
|
#ifdef NOCASEMATCH
|
|
noCaseFind(path);
|
|
if((dirp = opendir(path)) == NULL) {
|
|
#endif NOCASEMATCH
|
|
if (DBOSI)
|
|
printf("os_change_all: opendir failed on %s\n",path);
|
|
return;
|
|
#ifdef NOCASEMATCH
|
|
}
|
|
#endif NOCASEMATCH
|
|
}
|
|
|
|
pl = strlen(path); /* length of the path */
|
|
path[pl++] = '/'; /* add component terminator */
|
|
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
|
|
strcpy(path+pl,dp->d_name); /* create file name */
|
|
if (stat(path,&stb) != 0) { /* get the file status */
|
|
if (DBOSI)
|
|
printf("os_change_all: stat failed for %s\n",path);
|
|
continue; /* some error... */
|
|
}
|
|
if (S_ISDIR(stb.st_mode))
|
|
continue;
|
|
if (typ == F_FNDR) {
|
|
OSfname(p_ath,idir,fn,F_DATA);
|
|
strcat(p_ath,"/"); strcat(p_ath,dp->d_name);
|
|
if (stat(p_ath,&stb) == 0) {
|
|
if (S_ISDIR(stb.st_mode))
|
|
continue;
|
|
}
|
|
}
|
|
/* ignore errors */
|
|
unix_chmod(path,mode); /* set the mode for this file */
|
|
unix_chown(path,own,grp); /* set owner and group for file */
|
|
}
|
|
closedir(dirp); /* close the directory */
|
|
}
|
|
|
|
|
|
private u_short
|
|
EtoIPriv(emode,eshift,ishift)
|
|
dword emode;
|
|
int eshift,ishift;
|
|
{
|
|
u_short i = 0;
|
|
|
|
emode = (emode >> eshift);
|
|
if (emode & E_RD) i = I_RD | I_EX;
|
|
if (emode & E_WR) i |= I_WR | I_EX;
|
|
/* if (emode & E_SR) i |= I_EX; */
|
|
return(i << ishift);
|
|
}
|
|
|
|
|
|
/*
|
|
* Is the current user in the group gid?
|
|
*
|
|
*/
|
|
private int
|
|
OSInGroup(gid)
|
|
int gid;
|
|
{
|
|
int i;
|
|
int gtgid;
|
|
|
|
/* if ngroups gets very large, do a binary search */
|
|
for (i=0; i < ngroups; i++) {
|
|
gtgid = groups[i];
|
|
if (gtgid == gid)
|
|
return(TRUE);
|
|
if (gtgid > gid) /* limiting case */
|
|
return(FALSE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
* Get groups that a user is valid in
|
|
*
|
|
* Sort the array for later use
|
|
*
|
|
*/
|
|
dogetgroups()
|
|
{
|
|
int ng;
|
|
int i,k,idxofmin;
|
|
int t;
|
|
|
|
if ((ng = getgroups(NGROUPS, groups)) < 0) {
|
|
return(-1);
|
|
}
|
|
if (ng == 0) /* not in any groups? */
|
|
return(0);
|
|
|
|
/* sort groups array */
|
|
/* we assume n is very small, else possibly replace with quicker sort */
|
|
/* n**2 performance (comparisons), but no more than n swaps */
|
|
/* the array tends to be mostly sorted with the first element out */
|
|
/* of place. Don't use std quicksort -- under this assumption */
|
|
/* it will give very poor performance on average (at much higher overhead) */
|
|
/* NOTE: we could really speed this up if we knew that the */
|
|
/* array was sorted after the first "n" items, but with N so */
|
|
/* small (usually less than 32), it's not a big deal */
|
|
for (i = 0 ; i < ng; i++) {
|
|
for ( idxofmin = i, k = i + 1; k < ng; k++) /* find (i+1)'th min */
|
|
if (groups[k] < groups[idxofmin])
|
|
idxofmin = k;
|
|
if (i != idxofmin) {
|
|
t = groups[idxofmin];
|
|
groups[idxofmin] = groups[i];
|
|
groups[i] = t;
|
|
}
|
|
}
|
|
return(ng);
|
|
}
|
|
|
|
private u_short
|
|
EtoIAccess(emode)
|
|
dword emode;
|
|
{
|
|
u_short imode;
|
|
|
|
imode = (EtoIPriv(emode,ES_OWNER,IS_OWNER) |
|
|
EtoIPriv(emode,ES_GROUP,IS_GROUP) |
|
|
EtoIPriv(emode,ES_WORLD,IS_WORLD));
|
|
|
|
if (DBOSI)
|
|
printf("EtoIAccess: E=0x%x, I=o%o\n",emode,imode);
|
|
|
|
return(imode);
|
|
}
|
|
|
|
private dword
|
|
ItoEPriv(imode,ishift,eshift)
|
|
u_short imode;
|
|
int ishift,eshift;
|
|
{
|
|
dword e = 0;
|
|
|
|
imode = (imode >> ishift);
|
|
if (imode & I_RD) e = E_RD | E_SR;
|
|
if (imode & I_WR) e |= E_WR;
|
|
/* if (imode & I_EX) e |= E_SR; */
|
|
return(e << eshift);
|
|
}
|
|
|
|
private dword
|
|
ItoEAccess(imode,uid,gid)
|
|
u_short imode;
|
|
int uid;
|
|
int gid;
|
|
{
|
|
dword e = 0;
|
|
|
|
/* set user rights summary byte */
|
|
|
|
if (usruid == 0) /* are we running as root? */
|
|
e |= ((E_RD|E_WR|E_SR)<<ES_USER)|E_IOWN; /* we can do anything */
|
|
else if (usruid == uid) /* but if the real owner then */
|
|
e |= ItoEPriv(imode,IS_OWNER,ES_USER)|E_IOWN; /* set owner bits */
|
|
else if (OSInGroup(gid)) /* if in one of the groups */
|
|
e |= ItoEPriv(imode,IS_GROUP,ES_USER); /* set group access as well */
|
|
else /* otherwise */
|
|
e |= ItoEPriv(imode,IS_WORLD,ES_USER); /* set user rights for world */
|
|
|
|
if (imode & I_SETUID) /* if directory is setuid (say on shared volume) */
|
|
e |= E_IOWN; /* then set owner bit so FinderInfo etc. can be written */
|
|
|
|
if (uid == NOID) /* owned by <any user> */
|
|
e |= E_IOWN; /* must set owner bit */
|
|
|
|
/* set owner, group and world bytes */
|
|
|
|
e |= (ItoEPriv(imode,IS_OWNER,ES_OWNER) | /* other access */
|
|
ItoEPriv(imode,IS_GROUP,ES_GROUP) |
|
|
ItoEPriv(imode,IS_WORLD,ES_WORLD));
|
|
|
|
if (DBOSI)
|
|
printf("ItoEAccess: I=o%o, E=0x%x\n",imode,e);
|
|
|
|
return(e);
|
|
}
|
|
|
|
export OSErr
|
|
OSAccess(idir,fn,mode)
|
|
IDirP idir;
|
|
char *fn;
|
|
int mode;
|
|
{
|
|
int imode = 0;
|
|
int err;
|
|
char path[MAXPATHLEN];
|
|
|
|
if (mode & OFK_MWR)
|
|
imode |= W_OK;
|
|
if (mode & OFK_MRD)
|
|
imode |= R_OK;
|
|
|
|
OSfname(path,idir,fn,F_DATA); /* create unix style filename */
|
|
err = access(path,imode);
|
|
if (err == 0)
|
|
return(noErr);
|
|
#ifdef NOCASEMATCH
|
|
noCaseFind(path);
|
|
if(access(path,imode) == 0)
|
|
return(noErr);
|
|
#endif NOCASEMATCH
|
|
switch (errno) {
|
|
case ENOTDIR:
|
|
return(aeDirNotFound);
|
|
case ENOENT:
|
|
return(aeObjectNotFound);
|
|
case EACCES:
|
|
return(aeAccessDenied);
|
|
}
|
|
return(aeAccessDenied);
|
|
}
|
|
|
|
/*
|
|
* scale the AUFS volume size information to comply
|
|
* with the upper limit of Macintosh file systems
|
|
* (currently 2 Gigabytes)
|
|
*
|
|
* To avoid problems with "on disk" sizes being
|
|
* calculated incorrectly (ie: 2,546.9MB on disk for
|
|
* 8,903 bytes used) we seem to need an allocation
|
|
* block size smaller than 32k, so we arbitrarily
|
|
* choose 31k and apply the formula from IM vol IV,
|
|
* page 241
|
|
*
|
|
* abSize = (1 + ((volSize/512)/64k)) * 512
|
|
*
|
|
* giving a volume size of 2046820352 bytes (1,952MB)
|
|
*
|
|
*/
|
|
|
|
#ifndef MAXMACVOLSIZE
|
|
#define MAXMACVOLSIZE 2046820352
|
|
#endif MAXMACVOLSIZE
|
|
|
|
void
|
|
scaleVolSize(v)
|
|
VolPtr v;
|
|
{
|
|
float scale;
|
|
|
|
if (v->v_size >= MAXMACVOLSIZE) {
|
|
scale = (MAXMACVOLSIZE >> 16)/(float)(v->v_size >> 16);
|
|
v->v_free = scale * v->v_free;
|
|
v->v_size = MAXMACVOLSIZE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* set the extended volume size
|
|
* parameters defined by AFP 2.2
|
|
*
|
|
* size, free and blocks are 32-bit numbers.
|
|
* We want to end up with a 64-bit number in
|
|
* network-byte-order.
|
|
*
|
|
* For the moment we note that block-sizes
|
|
* are usually a simple power of two so we
|
|
* just bit-shift the original numbers.
|
|
*
|
|
*/
|
|
|
|
void
|
|
extendedVolSize(v, size, free, blk)
|
|
VolPtr v;
|
|
dword size, free, blk;
|
|
{
|
|
int off;
|
|
int i, j;
|
|
int shift;
|
|
|
|
bzero((char *)v->v_esize, sizeof(v->v_esize));
|
|
bzero((char *)v->v_efree, sizeof(v->v_efree));
|
|
|
|
switch (blk) {
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 8:
|
|
case 16:
|
|
case 32:
|
|
case 64:
|
|
case 128:
|
|
off = 0;
|
|
break;
|
|
case 256:
|
|
case 512:
|
|
case 1024:
|
|
case 2048:
|
|
case 4096:
|
|
case 8192:
|
|
case 16384:
|
|
case 32768:
|
|
off = 1;
|
|
break;
|
|
case 65536:
|
|
case 131072:
|
|
case 262144:
|
|
off = 2;
|
|
break;
|
|
default:
|
|
/* set some arbitrary number */
|
|
v->v_esize[4] = 0x80;
|
|
v->v_efree[4] = 0x40;
|
|
return;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* initialize the array in network byte
|
|
* order. If the multiplier is 1, 256 or
|
|
* 65536 there is nothing else to do.
|
|
*
|
|
*/
|
|
v->v_esize[7-off] = size & 0xff;
|
|
v->v_esize[6-off] = (size >> 8) & 0xff;
|
|
v->v_esize[5-off] = (size >> 16) & 0xff;
|
|
v->v_esize[4-off] = (size >> 24) & 0xff;
|
|
|
|
v->v_efree[7-off] = free & 0xff;
|
|
v->v_efree[6-off] = (free >> 8) & 0xff;
|
|
v->v_efree[5-off] = (free >> 16) & 0xff;
|
|
v->v_efree[4-off] = (free >> 24) & 0xff;
|
|
|
|
if (blk == 1 || blk == 256 || blk == 65536)
|
|
return;
|
|
|
|
/*
|
|
* now bit shift each group of bytes
|
|
*
|
|
*/
|
|
shift = (blk < 256) ? blk : ((blk < 65536) ? (blk/256) : (blk/65536));
|
|
|
|
for (i = 1; i < 20; i++) {
|
|
for (j = 0 ; j < 8; j++) {
|
|
v->v_esize[j] <<= 1;
|
|
v->v_efree[j] <<= 1;
|
|
if (j < 7 && (v->v_esize[j+1] & 0x80))
|
|
v->v_esize[j] |= 1;
|
|
if (j < 7 && (v->v_efree[j+1] & 0x80))
|
|
v->v_efree[j] |= 1;
|
|
}
|
|
if (shift == (0x0001 << i))
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* OSErr OSVolInfo(VolPtr v)
|
|
*
|
|
* Update volume information for volume pointed to by v.
|
|
* Returns error if path does not exist.
|
|
*
|
|
* Update:
|
|
*
|
|
* v_attr Read only flag (V_RONLY)
|
|
* v_cdate creation date (of v_path)
|
|
* v_mdate modification date (of v_path)
|
|
* v_size size of volume in bytes (32 bits ##)
|
|
* v_free free bytes on volume (32 bits ##)
|
|
*
|
|
* ## expect trouble if the volume size exceeds 4 Gigabytes.
|
|
*
|
|
*/
|
|
|
|
export OSErr
|
|
OSVolInfo(path,v, bitmap)
|
|
char *path;
|
|
VolPtr v;
|
|
word bitmap; /* bitmap of info needed */
|
|
{
|
|
struct stat buf;
|
|
#if defined(USEQUOTA) || defined(USEBSDQUOTA)
|
|
struct dqblk dqblk;
|
|
#endif USEQUOTA
|
|
#ifdef USEUSTAT
|
|
struct ustat ubuf;
|
|
#endif USEUSTAT
|
|
#ifdef USESTATFS
|
|
# ifdef SOLARIS
|
|
struct statvfs fsbuf;
|
|
# else SOLARIS
|
|
struct statfs fsbuf;
|
|
# endif SOLARIS
|
|
#endif USESTATFS
|
|
time_t sometime;
|
|
void extendedVolSize();
|
|
void scaleVolSize();
|
|
|
|
if (stat(path,&buf) != 0) /* directory exists? */
|
|
return(aeObjectNotFound); /* no... */
|
|
if (!(S_ISDIR(buf.st_mode))) /* check for directory */
|
|
return(aeParamErr); /* not a directory! */
|
|
|
|
if (bitmap & VP_CDATE) {
|
|
/* pick out the earliest date for mac creation time */
|
|
sometime = (buf.st_mtime > buf.st_ctime) ? buf.st_ctime : buf.st_mtime;
|
|
v->v_cdate = sometime > buf.st_atime ? buf.st_atime : sometime;
|
|
}
|
|
if (bitmap & VP_MDATE) {
|
|
/* pick the later of status change and modification for */
|
|
/* mac modified */
|
|
v->v_mdate = (buf.st_mtime < buf.st_ctime) ? buf.st_ctime : buf.st_mtime;
|
|
}
|
|
#ifdef notdef
|
|
/* had it as v->v_mdate -- probably the reason we ifdef'ed it out */
|
|
if (bitmap & VP_BDATE)
|
|
v->v_bdate = 0;
|
|
#endif
|
|
|
|
if (bitmap & VP_ATTR) {
|
|
#ifdef notdef
|
|
/* don't really want this - causes problems when you have access */
|
|
/* futher down the tree - should only come up locked iff the */
|
|
/* tree is write locked (no (easy) way to tell because of symbolic */
|
|
/* links and mount points) */
|
|
if (access(v->v_path,W_OK) != 0) /* ok to write into directory? */
|
|
v->v_attr |= V_RONLY; /* no, set read-only */
|
|
else
|
|
#endif
|
|
v->v_attr &= ~V_RONLY; /* clear read-only */
|
|
}
|
|
|
|
if ((bitmap & (VP_FREE|VP_SIZE|VP_EFREE|VP_ESIZE)) == 0)
|
|
return(noErr); /* naught else to do */
|
|
|
|
/* All the following is good and fine unless: (a) the volume */
|
|
/* has symlinks off the volume or (b) there are mounted file systems */
|
|
/* under the mac volume. In those cases, returning this information */
|
|
/* could be damaging because some "good" programs base what they */
|
|
/* can do on the volume information --- but people really like this */
|
|
/* information!!! so we take the trade off (even though it is one */
|
|
/* of the most system dependent parts of aufs) */
|
|
|
|
/* don't know how to calculate disk free and size without being su */
|
|
/* (in the general case) */
|
|
|
|
/* hard coded values of 512 for quotas and 1024 for ustat are bad */
|
|
/* where are the "real" numbers defined? */
|
|
|
|
/* careful on the ordering - these must go last and if you can possibly */
|
|
/* define more than one then you must define in order you wish */
|
|
#ifdef USEQUOTA
|
|
#if defined(gould)
|
|
if (gquota(Q_GETDLIM, usruid, buf.st_dev, &dqblk) == 0 &&
|
|
#elif defined(encore)
|
|
if (equota(Q_GETDLIM, usruid, buf.st_dev, &dqblk) == 0 &&
|
|
#elif defined(SOLARIS)
|
|
if (solaris_quota(Q_GETDLIM, usruid, path, &dqblk) == 0 &&
|
|
#else /* gould || encore || SOLARIS */
|
|
if (quota(Q_GETDLIM, usruid, buf.st_dev, &dqblk) == 0 &&
|
|
#endif /* gould || encore || SOLARIS */
|
|
dqblk.dqb_bhardlimit != 0) { /* make sure not unlimited */
|
|
v->v_size = dqblk.dqb_bhardlimit*512;
|
|
v->v_free = (dqblk.dqb_bhardlimit-dqblk.dqb_curblocks)*512;
|
|
extendedVolSize(v, dqblk.dqb_bhardlimit,
|
|
dqblk.dqb_bhardlimit-dqblk.dqb_curblocks, 512);
|
|
scaleVolSize(v);
|
|
return(noErr);
|
|
}
|
|
#endif USEQUOTA
|
|
#ifdef USEBSDQUOTA
|
|
{
|
|
char *fsname;
|
|
private char *find_mount_spec();
|
|
if ((fsname = find_mount_spec(buf.st_dev)) == NULL) {
|
|
errno = EPERM;
|
|
return(-1);
|
|
}
|
|
if (quotactl(fsname, QCMD(Q_GETQUOTA,USRQUOTA), usruid, &dqblk) == 0 &&
|
|
dqblk.dqb_bhardlimit != 0) {
|
|
v->v_size = dqblk.dqb_bhardlimit*512;
|
|
v->v_free = (dqblk.dqb_bhardlimit-dqblk.dqb_curblocks)*512;
|
|
extendedVolSize(v, dqblk.dqb_bhardlimit,
|
|
dqblk.dqb_bhardlimit-dqblk.dqb_curblocks, 512);
|
|
scaleVolSize(v);
|
|
return(noErr);
|
|
}
|
|
}
|
|
#endif USEBSDQUOTA
|
|
#ifdef USEGETMNT
|
|
if (ultrix_volinfo(path, &buf, v) == noErr)
|
|
return(noErr);
|
|
#endif USEGETMNT
|
|
#ifdef USEUSTAT
|
|
if (ustat(buf.st_dev, &ubuf) >= 0) {
|
|
if (VP_SIZE & bitmap) {
|
|
/* should do something better here */
|
|
v->v_size = ubuf.f_tfree*1024;
|
|
}
|
|
v->v_free = ubuf.f_tfree*1024;
|
|
extendedVolSize(v, ubuf.f_tfree, ubuf.f_tfree, 1024);
|
|
scaleVolSize(v);
|
|
return(noErr);
|
|
}
|
|
#endif USEUSTAT
|
|
#ifdef USESTATFS
|
|
#ifdef SOLARIS
|
|
if (statvfs(path, &fsbuf) >= 0) {
|
|
v->v_size = fsbuf.f_frsize * fsbuf.f_blocks;
|
|
/* limiting factor: cannot report on overutilization of a volume */
|
|
v->v_free = (fsbuf.f_bavail < 0) ? 0 : fsbuf.f_frsize * fsbuf.f_bavail;
|
|
extendedVolSize(v, fsbuf.f_blocks, fsbuf.f_bavail, fsbuf.f_frsize);
|
|
scaleVolSize(v);
|
|
return(noErr);
|
|
}
|
|
#else /* SOLARIS */
|
|
# if defined(sgi) || defined(apollo)
|
|
if (statfs(path, &fsbuf, sizeof(fsbuf), 0) >= 0) {
|
|
v->v_size = fsbuf.f_bsize * fsbuf.f_blocks;
|
|
/* limiting factor: cannot report on overutilization of a volume */
|
|
v->v_free = (fsbuf.f_bfree < 0) ? 0 : fsbuf.f_bsize * fsbuf.f_bfree;
|
|
extendedVolSize(v, fsbuf.f_blocks, fsbuf.f_bfree, fsbuf.f_bsize);
|
|
scaleVolSize(v);
|
|
return(noErr);
|
|
}
|
|
# else /* sgi || apollo */
|
|
if (statfs(path, &fsbuf) >= 0) {
|
|
#if (defined(__386BSD__) && !defined(__NetBSD__)) || defined(__osf__)
|
|
/*
|
|
* on 386/BSD, the block size is in f_fsize
|
|
* and f_bsize is the optimum transfer size
|
|
*
|
|
*/
|
|
v->v_size = fsbuf.f_fsize * fsbuf.f_blocks;
|
|
/* limiting factor: cannot report on overutilization of a volume */
|
|
v->v_free = (fsbuf.f_bavail < 0) ? 0 : fsbuf.f_fsize * fsbuf.f_bavail;
|
|
extendedVolSize(v, fsbuf.f_blocks, fsbuf.f_bavail, fsbuf.f_fsize);
|
|
#else /* __386BSD__ || __osf__ */
|
|
v->v_size = fsbuf.f_bsize * fsbuf.f_blocks;
|
|
/* limiting factor: cannot report on overutilization of a volume */
|
|
v->v_free = (fsbuf.f_bavail < 0) ? 0 : fsbuf.f_bsize * fsbuf.f_bavail;
|
|
extendedVolSize(v, fsbuf.f_blocks, fsbuf.f_bavail, fsbuf.f_bsize);
|
|
#endif /* __386BSD__ || __osf__ */
|
|
scaleVolSize(v);
|
|
return(noErr);
|
|
}
|
|
# endif /* sgi || apollo */
|
|
#endif /* SOLARIS */
|
|
#endif USESTATFS
|
|
#ifdef SIZESERVER
|
|
getvolsize(path, &v->v_size, &v->v_free);
|
|
#else SIZESERVER
|
|
v->v_size = 0x1000000; /* some random number */
|
|
v->v_free = 0x1000000; /* same random number */
|
|
#endif SIZESERVER
|
|
extendedVolSize(v, 0x1000000, 0x1000000, 512);
|
|
scaleVolSize(v);
|
|
return(noErr); /* all ok */
|
|
}
|
|
|
|
#ifdef SIZESERVER
|
|
|
|
#ifndef SIZESERVER_PATH
|
|
#define SIZESERVER_PATH "/usr/local/cap/sizeserver"
|
|
#endif SIZESERVER_PATH
|
|
|
|
static jmp_buf gotpipe;
|
|
|
|
private void
|
|
getvolsize(path, ntot, nfree)
|
|
char *path;
|
|
sdword *ntot, *nfree;
|
|
{
|
|
register int i;
|
|
int mask, socket[2];
|
|
struct volsize vs;
|
|
static int server = -1, server1, servmask;
|
|
static struct timeval servtimeout = {0, 500000L};
|
|
|
|
if(setjmp(gotpipe)) {
|
|
if(server >= 0)
|
|
close(server);
|
|
server = -1;
|
|
unknown:
|
|
*ntot = 0x1000000;
|
|
*nfree = 0x1000000;
|
|
return;
|
|
}
|
|
if(server < 0) {
|
|
register int pid;
|
|
int catchsigpipe();
|
|
|
|
if(socketpair(AF_UNIX, SOCK_STREAM, 0, socket) < 0)
|
|
goto unknown;
|
|
if((pid = fork()) < 0) {
|
|
close(socket[0]);
|
|
close(socket[1]);
|
|
goto unknown;
|
|
}
|
|
if(pid == 0) { /* the child */
|
|
close(socket[0]);
|
|
if(socket[1] != 0) {
|
|
dup2(socket[1], 0);
|
|
close(socket[1]);
|
|
}
|
|
execl(SIZESERVER_PATH, "sizeserver", 0);
|
|
_exit(1);
|
|
}
|
|
close(socket[1]);
|
|
server = socket[0];
|
|
server1 = server + 1;
|
|
servmask = 1 << server;
|
|
signal(SIGPIPE, catchsigpipe);
|
|
}
|
|
for(i = 3 ; ; ) {
|
|
if(i-- <= 0)
|
|
goto unknown;
|
|
lseek(server, 0L, 2);
|
|
write(server, path, strlen(path) + 1);
|
|
mask = servmask;
|
|
if(select(server1, &mask, NULL, NULL, &servtimeout) < 1)
|
|
goto unknown;
|
|
if(read(server, (char *)&vs, sizeof(vs)) == sizeof(vs))
|
|
break;
|
|
}
|
|
*ntot = vs.total;
|
|
*nfree = vs.free;
|
|
}
|
|
|
|
catchsigpipe()
|
|
{
|
|
longjmp(gotpipe, 1);
|
|
}
|
|
#endif SIZESERVER
|
|
|
|
#ifdef USEGETMNT
|
|
/* get info on path using buf when there is ambiguity (ultrix 2.0 or before) */
|
|
/* fill in info on v */
|
|
private OSErr
|
|
ultrix_volinfo(path,buf,v)
|
|
char *path;
|
|
struct stat *buf;
|
|
VolPtr v;
|
|
{
|
|
int context = 0;
|
|
int i, num;
|
|
u_int vfree;
|
|
/* multiple buffers are wasteful when using Ultrix 2.2, but code is */
|
|
/* good enough */
|
|
struct fs_data buffer[NUMGETMNTBUF];
|
|
struct fs_data *bp;
|
|
int nbytes = sizeof(struct fs_data)*NUMGETMNTBUF;
|
|
void extendedVolSize();
|
|
void scaleVolSize();
|
|
|
|
if (!oldgetmnt) {
|
|
/* Ultrix 2.2 */
|
|
/* use nostat_one -- we don't want to hang on nfs */
|
|
/* return none if error or (0) - not found */
|
|
nbytes = sizeof(struct fs_data);
|
|
if ((num=getmnt(&context, buffer, nbytes, NOSTAT_ONE, path)) <= 0)
|
|
return(-1);
|
|
bp = buffer;
|
|
} else {
|
|
while ((num=getmnt(&context, buffer, nbytes)) > 0) {
|
|
for (i = 0, bp = buffer; i < num; i++, bp++)
|
|
if (buf->st_dev == bp->fd_req.dev)
|
|
goto found;
|
|
/* context is set to zero if last call to getmnt returned */
|
|
/* all file systems */
|
|
if (context == 0)
|
|
return(-1);
|
|
}
|
|
/* should never reach here, means getmnt returned an error */
|
|
return(-1); /* nothing found */
|
|
}
|
|
found:
|
|
/* "overflow" space if any - looks used */
|
|
v->v_size = bp->fd_req.btot * 1024;
|
|
/* bfreen must be "good" in that it cannot go below 0 when */
|
|
/* out of space -- it is unsigned! */
|
|
v->v_free = ((getuid() == 0) ? bp->fd_req.bfree : bp->fd_req.bfreen) * 1024;
|
|
extendedVolSize(v, bp->fd_req.btot,
|
|
(getuid() == 0) ? bp->fd_req.bfree : bp->fd_req.bfreen, 1024);
|
|
scaleVolSize(v);
|
|
return(noErr);
|
|
}
|
|
#endif /* GETMNT */
|
|
|
|
#if defined(USEQUOTA) && defined(SOLARIS)
|
|
int
|
|
solaris_quota(cmd, uid, path, dq)
|
|
int cmd, uid;
|
|
char *path;
|
|
struct dqblk *dq;
|
|
{
|
|
int fd, res;
|
|
struct quotctl qctl;
|
|
|
|
switch (cmd) {
|
|
case Q_GETQUOTA: /* let it be "read-only" */
|
|
break;
|
|
default:
|
|
errno = EINVAL;
|
|
return(-1);
|
|
}
|
|
|
|
if ((fd = open(path, O_RDONLY)) < 0)
|
|
return(-1);
|
|
|
|
qctl.op = cmd;
|
|
qctl.uid = uid;
|
|
qctl.addr = (caddr_t)dq;
|
|
res = ioctl(fd, Q_QUOTACTL, &qctl);
|
|
close(fd);
|
|
|
|
return(res);
|
|
}
|
|
#endif /* USEQUOTA && SOLARIS */
|
|
|
|
#if defined(USESUNQUOTA) || defined(USEBSDQUOTA)
|
|
|
|
#ifndef MAXUFSMOUNTED
|
|
# ifdef NMOUNT
|
|
# define MAXUFSMOUNTED NMOUNT /* NMOUNT in param.h */
|
|
# else NMOUNT
|
|
# define MAXUFSMOUNTED 32 /* arb. value */
|
|
# endif NMOUNT
|
|
#endif MAXUFSMOUNTED
|
|
|
|
private struct mount_points {
|
|
char *mp_fsname; /* name of "block" device */
|
|
dev_t mp_dev; /* device number */
|
|
} mount_points[MAXUFSMOUNTED];
|
|
|
|
private int num_mount_points = -1;
|
|
|
|
private struct mount_points *
|
|
find_mount_spec_intable(dev)
|
|
dev_t dev;
|
|
{
|
|
int i;
|
|
struct mount_points *mp;
|
|
|
|
for (i = 0, mp = mount_points; i < num_mount_points; i++, mp++) {
|
|
if (dev == mp->mp_dev)
|
|
return(mp);
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
#ifdef USEBSDQUOTA
|
|
/*
|
|
* find the block special device...
|
|
* try updating mount point table if possible
|
|
*
|
|
* returns name if it can, null o.w.
|
|
*
|
|
*/
|
|
private char *
|
|
find_mount_spec(dev)
|
|
{
|
|
struct mount_points *mp;
|
|
struct fstab *mtent;
|
|
struct stat sbuf;
|
|
char *strdup();
|
|
|
|
if ((mp = find_mount_spec_intable(dev)) != NULL) /* try once */
|
|
return(mp->mp_fsname);
|
|
|
|
if (num_mount_points < MAXUFSMOUNTED) {
|
|
/* check to see if mounted */
|
|
if (setfsent() == 0) {
|
|
if (DBOSI)
|
|
logit(0,"setfsent failed!");
|
|
return(NULL);
|
|
}
|
|
mp = NULL;
|
|
while ((mtent = getfsent()) != NULL) {
|
|
if (stat(mtent->fs_file, &sbuf) < 0)
|
|
continue;
|
|
if (dev != sbuf.st_dev)
|
|
continue;
|
|
mp = mount_points+num_mount_points;
|
|
num_mount_points++;
|
|
mp->mp_fsname = strdup(mtent->fs_file);
|
|
mp->mp_dev = sbuf.st_dev;
|
|
break;
|
|
}
|
|
endfsent();
|
|
} else {
|
|
/* table would overflow, try rebuilding */
|
|
if (build_mount_table() < 0) /* try rebuilding table */
|
|
return(NULL);
|
|
mp = find_mount_spec_intable(dev);
|
|
}
|
|
|
|
if (mp)
|
|
return(mp->mp_fsname);
|
|
|
|
if (DBOSI)
|
|
logit(0,"Cannot find file system on device (%d,%d)\n",
|
|
major(dev), minor(dev));
|
|
|
|
return(NULL); /* total failure */
|
|
}
|
|
|
|
/*
|
|
* build a table of the various mounted file systems
|
|
* using getmntent. We want to use /etc/mtab, but
|
|
* if we can't, then we use /etc/fstab to get some
|
|
* information anyway if this is the first time around (to
|
|
* prevent constant rereads since /etc/fstab is pretty constant)
|
|
*
|
|
*/
|
|
int
|
|
build_mount_table()
|
|
{
|
|
struct stat sbuf;
|
|
struct fstab *mtent;
|
|
struct mount_points *mp;
|
|
char *strdup();
|
|
|
|
setfsent();
|
|
|
|
/* free old info */
|
|
if (num_mount_points) {
|
|
for (mp = mount_points ; num_mount_points > 0; num_mount_points--, mp++)
|
|
if (mp->mp_fsname)
|
|
free(mp->mp_fsname);
|
|
}
|
|
num_mount_points = 0; /* paranoia */
|
|
|
|
mp = mount_points;
|
|
while ((mtent = getfsent()) != NULL) {
|
|
if (stat(mtent->fs_file, &sbuf) < 0)
|
|
continue;
|
|
mp->mp_fsname = strdup(mtent->fs_file);
|
|
mp->mp_dev = sbuf.st_dev;
|
|
num_mount_points++, mp++;
|
|
if (num_mount_points > MAXUFSMOUNTED) {
|
|
logit(0,"Grrr.. too many mounted file systems for build_mount_table");
|
|
break;
|
|
}
|
|
}
|
|
endfsent();
|
|
|
|
if (num_mount_points == 0 && DBOSI)
|
|
logit(0,"No mount points can be found");
|
|
|
|
return(0);
|
|
}
|
|
|
|
#else USEBSDQUOTA
|
|
|
|
/*
|
|
* find the block special device...
|
|
* try updating mount point table if possible
|
|
*
|
|
* returns name if it can, null o.w.
|
|
*
|
|
*/
|
|
private char *
|
|
find_mount_spec(dev)
|
|
{
|
|
struct mount_points *mp;
|
|
struct mntent *mtent;
|
|
struct stat sbuf;
|
|
FILE *mt;
|
|
char *strdup();
|
|
|
|
if ((mp = find_mount_spec_intable(dev)) != NULL) /* try once */
|
|
return(mp->mp_fsname);
|
|
|
|
if (num_mount_points < MAXUFSMOUNTED) {
|
|
/* check to see if mounted */
|
|
if ((mt = setmntent("/etc/mtab", "r")) == NULL) {
|
|
if (DBOSI)
|
|
logit(0,"/etc/mtab is read protected or nonexistant");
|
|
return(NULL);
|
|
}
|
|
mp = NULL;
|
|
while ((mtent = getmntent(mt)) != NULL) {
|
|
if (stat(mtent->mnt_fsname, &sbuf) < 0)
|
|
continue;
|
|
if (dev != sbuf.st_rdev)
|
|
continue;
|
|
mp = mount_points+num_mount_points;
|
|
num_mount_points++;
|
|
mp->mp_fsname = strdup(mtent->mnt_fsname);
|
|
mp->mp_dev = sbuf.st_rdev;
|
|
break;
|
|
}
|
|
endmntent(mt);
|
|
} else {
|
|
/* table would overflow, try rebuilding */
|
|
if (build_mount_table() < 0) /* try rebuilding table */
|
|
return(NULL);
|
|
mp = find_mount_spec_intable(dev);
|
|
}
|
|
if (mp)
|
|
return(mp->mp_fsname);
|
|
|
|
if (DBOSI)
|
|
logit(0,"Cannot find file system on device (%d,%d)\n",
|
|
major(dev), minor(dev));
|
|
|
|
return(NULL); /* total failure */
|
|
}
|
|
|
|
/*
|
|
* build a table of the various mounted file systems
|
|
* using getmntent. We want to use /etc/mtab, but
|
|
* if we can't, then we use /etc/fstab to get some
|
|
* information anyway if this is the first time around (to
|
|
* prevent constant rereads since /etc/fstab is pretty constant)
|
|
*
|
|
*/
|
|
int
|
|
build_mount_table()
|
|
{
|
|
FILE *mt;
|
|
struct stat sbuf;
|
|
struct mntent *mtent;
|
|
struct mount_points *mp;
|
|
char *strdup();
|
|
|
|
if ((mt = setmntent("/etc/mtab", "r")) == NULL) {
|
|
if (DBOSI)
|
|
logit(0,"/etc/mtab is read protected or nonexistant");
|
|
if (num_mount_points != 0)
|
|
return(-1);
|
|
if ((mt = setmntent("/etc/fstab", "r")) == NULL) {
|
|
if (DBOSI)
|
|
logit(0,"/etc/fstab is read protected or nonexistant");
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
/* free old info */
|
|
if (num_mount_points) {
|
|
for (mp = mount_points ; num_mount_points > 0; num_mount_points--, mp++)
|
|
if (mp->mp_fsname)
|
|
free(mp->mp_fsname);
|
|
}
|
|
num_mount_points = 0; /* paranoia */
|
|
|
|
mp = mount_points;
|
|
while ((mtent = getmntent(mt)) != NULL) {
|
|
if (stat(mtent->mnt_fsname, &sbuf) < 0)
|
|
continue;
|
|
mp->mp_fsname = strdup(mtent->mnt_fsname);
|
|
mp->mp_dev = sbuf.st_rdev;
|
|
num_mount_points++, mp++;
|
|
if (num_mount_points > MAXUFSMOUNTED) {
|
|
logit(0,"Grrr.. too many mounted file systems for build_mount_table");
|
|
break;
|
|
}
|
|
}
|
|
endmntent(mt);
|
|
|
|
if (num_mount_points == 0 && DBOSI)
|
|
logit(0,"No mount points can be found");
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* SunOS doesn't use the Melbourne quota system - it has its own
|
|
* private one that uses quotactl instead of quota. We emulate
|
|
* quota here...
|
|
*
|
|
*/
|
|
int
|
|
#ifdef gould
|
|
gquota(cmd, uid, arg, addr)
|
|
#else gould
|
|
#ifdef encore
|
|
equota(cmd, uid, arg, addr)
|
|
#else encore
|
|
quota(cmd, uid, arg, addr)
|
|
#endif encore
|
|
#endif gould
|
|
int cmd, uid, arg;
|
|
caddr_t addr;
|
|
{
|
|
char *fsname;
|
|
private char *find_mount_spec();
|
|
|
|
switch (cmd) {
|
|
case Q_QUOTAON:
|
|
case Q_QUOTAOFF:
|
|
case Q_SETQUOTA:
|
|
case Q_GETQUOTA:
|
|
case Q_SETQLIM:
|
|
case Q_SYNC:
|
|
break;
|
|
default:
|
|
errno = EINVAL;
|
|
return(-1);
|
|
}
|
|
|
|
if ((fsname = find_mount_spec(arg)) == NULL) {
|
|
errno = EPERM;
|
|
return(-1);
|
|
}
|
|
#ifdef gould
|
|
/* oh dear, whose idea was this ? */
|
|
return(quota(cmd, fsname, uid, addr));
|
|
#else gould
|
|
return(quotactl(cmd, fsname, uid, addr));
|
|
#endif gould
|
|
}
|
|
#endif USEBSDQUOTA
|
|
#endif USESUNQUOTA || USEBSDQUOTA
|
|
|
|
export OSErr
|
|
OSCopyFile(spdir,sfile,dpdir,dfile)
|
|
IDirP spdir,dpdir; /* source and destination parents */
|
|
char *sfile,*dfile; /* source and destination file names */
|
|
{
|
|
char s_path[MAXPATHLEN];
|
|
char d_path[MAXPATHLEN];
|
|
char spath[MAXPATHLEN];
|
|
char dpath[MAXPATHLEN];
|
|
struct stat stb;
|
|
int mo;
|
|
int err;
|
|
|
|
OSfname(s_path,spdir,sfile,F_DATA); /* create unix style name for data */
|
|
OSfname(d_path,dpdir,dfile,F_DATA); /* same for destination */
|
|
#ifdef NOCASEMATCH
|
|
noCaseMatch(s_path);
|
|
noCaseMatch(d_path);
|
|
#endif NOCASEMATCH
|
|
|
|
if (DBOSI)
|
|
printf("OSCopyFile: %s -> %s\n",s_path,d_path);
|
|
|
|
err = unix_stat(d_path,&stb); /* see if destination exists... */
|
|
if (err == noErr) /* yes... it does */
|
|
return(aeObjectExists); /* return error... */
|
|
|
|
/* get info on parent of destination */
|
|
if ((err = unix_stat(pathstr(dpdir), &stb)) != noErr)
|
|
return(err);
|
|
mo = filemode(stb.st_mode, stb.st_uid, stb.st_gid);
|
|
err = os_copy(s_path,d_path, mo);
|
|
|
|
if (err != noErr && DBOSI)
|
|
printf("OSCopyFile: DATA copy failed %s\n",afperr(err));
|
|
|
|
if (err != noErr)
|
|
return(err);
|
|
|
|
strcpy(spath,s_path);
|
|
toResFork(spath,sfile); /* create unix style name for rsrc */
|
|
strcpy(dpath,d_path);
|
|
toResFork(dpath,dfile); /* same for destination */
|
|
err = os_copy(spath,dpath,mo); /* do the copy... */
|
|
/* allow object not found */
|
|
if (err != noErr && err != aeObjectNotFound) { /* if failure.... */
|
|
if (DBOSI)
|
|
printf("OSCopyFile: RSRC copy failed %s\n",afperr(err));
|
|
(void) os_delete(dpdir,dfile,F_DATA); /* cleanup dest files */
|
|
return(err);
|
|
}
|
|
|
|
strcpy(spath,s_path);
|
|
toFinderInfo(spath,sfile); /* create unix style name for fndr */
|
|
strcpy(dpath,d_path);
|
|
toFinderInfo(dpath,dfile); /* same for destination */
|
|
err = os_copy(spath,dpath,mo); /* do the copy... */
|
|
/* allow object not found */
|
|
if (err != noErr && err != aeObjectNotFound) {
|
|
if (DBOSI)
|
|
printf("OSCopyFile: FNDR copy failed %s\n",afperr(err));
|
|
(void) os_delete(dpdir,dfile,F_DATA); /* cleanup dest files */
|
|
(void) os_delete(dpdir,dfile,F_RSRC); /* .... */
|
|
return(err);
|
|
}
|
|
OSSetMacFileName(dpdir, dfile);
|
|
|
|
FModified(dpdir, dfile); /* mark as modified */
|
|
#ifdef notdef
|
|
EModified(dpdir); /* destination dir is modified */
|
|
#endif
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* OSErr os_copy(char *from, char *to, mo)
|
|
*
|
|
* Copy the file from, to the file to. If "to" already exists then
|
|
* overwrite. File is created with mode "mo".
|
|
*
|
|
* Should probably lock the file!
|
|
*
|
|
*/
|
|
|
|
private OSErr
|
|
os_copy(from, to, mo)
|
|
char *from,*to;
|
|
{
|
|
int sfd,dfd,err;
|
|
char iobuf[IOBSIZE];
|
|
struct stat sstb;
|
|
struct stat dstb;
|
|
int i;
|
|
|
|
if ((err = unix_stat(from,&sstb)) != noErr)
|
|
return(err);
|
|
|
|
if (S_ISDIR(sstb.st_mode)) { /* dirs not allowed... */
|
|
printf("os_copy: source is directory\n");
|
|
return(aeObjectTypeErr);
|
|
}
|
|
|
|
if ((err=unix_open(from,0,&sfd)) != noErr) /* open source file */
|
|
return(err);
|
|
|
|
#ifdef APPLICATION_MANAGER
|
|
{
|
|
extern int fdplist[NOFILE];
|
|
extern struct flist *applist;
|
|
|
|
if (applist != NULL && fdplist[sfd] == 1) {
|
|
/* we want Finder copy protection */
|
|
(void) unix_close(sfd);
|
|
return(aeAccessDenied);
|
|
}
|
|
}
|
|
#endif APPLICATION_MANAGER
|
|
|
|
err = unix_stat(to,&dstb); /* check on destination */
|
|
if (err == noErr) { /* file is there */
|
|
if (sstb.st_dev == dstb.st_dev && sstb.st_ino == dstb.st_ino) {
|
|
if (DBOSI)
|
|
printf("os_copy: cannot copy to self\n");
|
|
unix_close(sfd);
|
|
return(aeParamErr);
|
|
}
|
|
} /* else ignore error from stat */
|
|
|
|
err = unix_createo(to,TRUE,mo,&dfd);
|
|
if (err != noErr) {
|
|
printf("os_copy; create failed\n");
|
|
(void) unix_close(sfd);
|
|
if (err == aeObjectNotFound) /* no destination? */
|
|
err = aeParamErr; /* then return this */
|
|
return(err);
|
|
}
|
|
|
|
/* copy loop */
|
|
for (i=0;;i++) {
|
|
register int len;
|
|
|
|
len = read(sfd,iobuf,IOBSIZE);
|
|
if (len == 0)
|
|
break;
|
|
|
|
if (len < 0) {
|
|
printf("os_copy: error during read\n");
|
|
(void) unix_close(sfd);
|
|
(void) unix_close(dfd);
|
|
return(aeParamErr); /* disk error */
|
|
}
|
|
|
|
if (write(dfd,iobuf,len) != len) {
|
|
err = errno; /* preserve error code */
|
|
if (DBOSI)
|
|
printf("os_copy: error on write %s\n",syserr());
|
|
(void) unix_close(sfd);
|
|
(void) unix_close(dfd);
|
|
return(ItoEErr(err));
|
|
}
|
|
if (i % 5)
|
|
abSleep(0, TRUE);
|
|
}
|
|
(void) unix_close(sfd);
|
|
(void) unix_close(dfd);
|
|
return(noErr);
|
|
}
|
|
|
|
export OSErr
|
|
OSCreateFile(pdir,file,delf)
|
|
IDirP pdir;
|
|
char *file;
|
|
int delf; /* if want to delete existing file */
|
|
{
|
|
char p_ath[MAXPATHLEN];
|
|
char path[MAXPATHLEN];
|
|
int err,derr,rerr,cerr,mo;
|
|
struct stat stb;
|
|
|
|
OSfname(p_ath,pdir,file,F_DATA); /* create data file name */
|
|
#ifdef NOCASEMATCH
|
|
noCaseMatch(p_ath);
|
|
#endif NOCASEMATCH
|
|
|
|
if (DBOSI)
|
|
printf("OSCreateFile: creating %s with %s\n",p_ath,
|
|
(delf) ? "OverWrite" : "No OverWrite");
|
|
|
|
err = unix_stat(pathstr(pdir),&stb);
|
|
if (err != noErr)
|
|
return(err);
|
|
mo = filemode(stb.st_mode, stb.st_uid, stb.st_gid);
|
|
|
|
/* should never get aeObjectExists if delf was true */
|
|
derr = unix_create(p_ath,delf,mo); /* using user delete flag */
|
|
if (derr != noErr && derr != aeObjectExists) {
|
|
if (DBOSI)
|
|
printf("OSCreateFile: DATA fork create failed\n");
|
|
/* previously under a conditional on delf, but not necessary */
|
|
/* anymore because we don't get here if the object was already there */
|
|
cerr = unix_unlink(p_ath); /* clean up... */
|
|
if (cerr != noErr && DBOSI)
|
|
printf("OSCreateFile: cleanup failed\n");
|
|
return(derr);
|
|
}
|
|
|
|
strcpy(path,p_ath);
|
|
toResFork(path,file); /* try creating resource fork */
|
|
rerr = unix_create(path,delf,mo); /* ... */
|
|
if (rerr != noErr && rerr != aeObjectExists && rerr != aeObjectNotFound) {
|
|
if (DBOSI)
|
|
printf("OSCreateFile: RSRC create failed\n");
|
|
/* previously under a conditional on delf, but not necessary */
|
|
/* anymore because we don't get here if the object was already there */
|
|
cerr = unix_unlink(path); /* clean up... */
|
|
if (cerr != noErr && DBOSI)
|
|
printf("OSCreateFile: cleanup failed\n");
|
|
/* should we clean up data fork? */
|
|
return(rerr);
|
|
}
|
|
|
|
strcpy(path,p_ath);
|
|
toFinderInfo(path,file); /* create finder fork */
|
|
err = unix_create(path,delf,mo);
|
|
/* ignore error here - exactly what should be done? */
|
|
|
|
/* at this point, each had better be: aeObjectExists or noErr */
|
|
if (rerr == aeObjectExists || derr == aeObjectExists)
|
|
return(aeObjectExists);
|
|
EModified(pdir);
|
|
return(noErr);
|
|
}
|
|
|
|
|
|
export OSErr
|
|
OSOpenFork(pdir,file,mode,typ,fhdl)
|
|
IDirP pdir; /* parent directory */
|
|
char *file;
|
|
word mode;
|
|
int typ,*fhdl;
|
|
{
|
|
register int i;
|
|
char path[MAXPATHLEN];
|
|
char *ms;
|
|
int mo;
|
|
word attr;
|
|
extern int sessvers;
|
|
#ifdef DENYREADWRITE
|
|
int getAccessDenyMode();
|
|
int setAccessDenyMode();
|
|
int accessConflict();
|
|
int cadm;
|
|
#endif DENYREADWRITE
|
|
|
|
/* new for AFP2.0 */
|
|
OSGetAttr(pdir,file,&attr);
|
|
if ((mode & OFK_MWR) && (attr & FPA_WRI))
|
|
return((sessvers == AFPVersion1DOT1) ? aeAccessDenied : aeObjectLocked);
|
|
|
|
OSfname(path,pdir,file,typ); /* expand name */
|
|
|
|
if ((mode & ~(OFK_MRD|OFK_MWR)) != 0)
|
|
if (DBOSI)
|
|
printf("OSOpenFork: open mode bits are octal %o\n",mode);
|
|
|
|
if ((mode & (OFK_MRD|OFK_MWR)) == (OFK_MRD|OFK_MWR)) {
|
|
ms = "Read/Write";
|
|
mo = O_RDWR;
|
|
} else if (mode & OFK_MWR) {
|
|
ms = "Write";
|
|
mo = O_WRONLY;
|
|
} else if (mode & OFK_MRD) {
|
|
ms = "Read";
|
|
mo = O_RDONLY;
|
|
}
|
|
|
|
#ifdef DENYREADWRITE
|
|
if (mo == O_WRONLY)
|
|
mo = O_RDWR;
|
|
#endif DENYREADWRITE
|
|
|
|
/* This is a special case hack for use with System 7.0 */
|
|
if (*file == 'T') { /* improve performance a little */
|
|
if (strcmp(file, "Trash Can Usage Map") == 0) {
|
|
ms = "Read/Write";
|
|
mo = O_RDWR;
|
|
}
|
|
}
|
|
|
|
if (DBOSI)
|
|
printf("OSOpenFork: Opening %s for %s\n",path,ms);
|
|
|
|
#ifdef NOCASEMATCH
|
|
if ((i = unix_open(path,mo,fhdl)) != noErr) {
|
|
noCaseFind(path);
|
|
i = unix_open(path,mo,fhdl);
|
|
}
|
|
#else NOCASEMATCH
|
|
i = unix_open(path,mo,fhdl);
|
|
#endif NOCASEMATCH
|
|
|
|
#ifdef DENYREADWRITE
|
|
if (*fhdl >= 0) {
|
|
if ((cadm = getAccessDenyMode(path, *fhdl)) >= 0) {
|
|
if (accessConflict(cadm, mode)) {
|
|
unix_close(*fhdl);
|
|
return(aeDenyConflict);
|
|
}
|
|
}
|
|
setAccessDenyMode(path, *fhdl, mode);
|
|
}
|
|
#endif DENYREADWRITE
|
|
|
|
if (i == noErr) {
|
|
attr |= ((typ == F_DATA) ? FPA_DAO : FPA_RAO);
|
|
OSSetAttr(pdir, file, attr);
|
|
}
|
|
|
|
return(i);
|
|
}
|
|
|
|
private char *guestname = NULL;
|
|
|
|
export boolean
|
|
setguestid(nam)
|
|
char *nam;
|
|
{
|
|
struct passwd *p;
|
|
if ((p = getpwnam(nam)) == NULL) {
|
|
logit(0,"Guest id %s NOT IN PASSWORD FILE",nam);
|
|
logit(0,"Guest id %s NOT IN PASSWORD FILE",nam);
|
|
return(FALSE);
|
|
}
|
|
if (p->pw_uid == 0) {
|
|
logit(0,"Guest id %s is a root id! NOT ALLOWED!", nam);
|
|
logit(0,"Guest id %s is a root id! NOT ALLOWED!", nam);
|
|
logit(0,"Guest id %s is a root id! NOT ALLOWED!", nam);
|
|
return(FALSE);
|
|
}
|
|
if (p->pw_gid == 0) {
|
|
logit(0,"Guest id %s is in group 0. BE WARNED!", nam);
|
|
logit(0,"Guest id %s is in group 0. BE WARNED!", nam);
|
|
logit(0,"Guest id %s is in group 0. BE WARNED!", nam);
|
|
}
|
|
logit(0,"Guest id is %s, uid %d, primary gid %d",nam, p->pw_uid, p->pw_gid);
|
|
guestname = nam;
|
|
return(TRUE);
|
|
}
|
|
|
|
private boolean apasswdfile = FALSE;
|
|
|
|
export boolean
|
|
setpasswdfile(pw)
|
|
char *pw;
|
|
{
|
|
|
|
if (desinit(0) < 0) {
|
|
logit(0,"error: no des routines, so no aufs password file used");
|
|
return(FALSE);
|
|
}
|
|
apasswdfile = init_aufs_passwd(pw);
|
|
return(apasswdfile);
|
|
}
|
|
|
|
/*
|
|
* check if user exists
|
|
*
|
|
* IE: check if user in file specified with -P option
|
|
* (not fatal if no file specified for DISTRIB_PASSWDS)
|
|
*
|
|
*/
|
|
|
|
export OSErr
|
|
OSLoginRand(nam)
|
|
char *nam;
|
|
{
|
|
OSErr err = aeParamErr;
|
|
|
|
#ifdef DISTRIB_PASSWDS
|
|
char *cp, line[80];
|
|
FILE *fp, *fopen();
|
|
extern char *distribpassfile;
|
|
if (distribpassfile == NULL)
|
|
return(noErr);
|
|
if ((fp = fopen(distribpassfile, "r")) == NULL)
|
|
return(noErr);
|
|
err = aeUserNotAuth;
|
|
while (fgets(line, sizeof(line), fp) != NULL) {
|
|
if (line[0] == '#')
|
|
continue;
|
|
for (cp = line; *cp != '\0'; cp++) {
|
|
if (*cp == ' ' || *cp == '\t' || *cp == '\n') {
|
|
*cp = '\0';
|
|
break;
|
|
}
|
|
}
|
|
if (strcmp(nam, line) == 0) {
|
|
err = noErr;
|
|
break;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
#else /* DISTRIB_PASSWDS */
|
|
if (is_aufs_user(nam))
|
|
return(noErr);
|
|
#endif /* DISTRIB_PASSWDS */
|
|
|
|
return(err);
|
|
}
|
|
|
|
#ifdef PERMISSIVE_USER_NAME
|
|
/*
|
|
* allow the specified user name to be
|
|
* from the gcos field of the passwd file
|
|
* IE: Chooser names don't have to be login names
|
|
*/
|
|
static struct passwd *
|
|
getpwgnam(nam)
|
|
unsigned char *nam;
|
|
{
|
|
char *ptm;
|
|
char nom[40];
|
|
char nomi[200];
|
|
struct passwd *pw;
|
|
int match, i, j;
|
|
|
|
/* map to lower case, translate some special characters */
|
|
|
|
for (i = 0 ; nam[i] ; i++) {
|
|
switch (nam[i]) {
|
|
case 0x8d:
|
|
nom[i] = 'c';
|
|
break;
|
|
case 0x8e:
|
|
case 0x8f:
|
|
case 0x90:
|
|
case 0x91:
|
|
nom[i] = 'e';
|
|
break;
|
|
case 0x92:
|
|
case 0x93:
|
|
case 0x94:
|
|
case 0x95:
|
|
nom[i] = 'i';
|
|
break;
|
|
case 0x96:
|
|
nom[i] = 'n';
|
|
break;
|
|
case 0x97:
|
|
case 0x98:
|
|
case 0x99:
|
|
case 0x9a:
|
|
case 0x9b:
|
|
nom[i] = 'o';
|
|
break;
|
|
case 0x9c:
|
|
case 0x9d:
|
|
case 0x9e:
|
|
case 0x9f:
|
|
nom[i] = 'u';
|
|
break;
|
|
default:
|
|
if (isupper(nam[i]))
|
|
nom[i] = tolower(nam[i]);
|
|
else
|
|
nom[i] = nam[i];
|
|
break;
|
|
}
|
|
}
|
|
nom[i] = '\0';
|
|
setpwent();
|
|
while ((pw = getpwent()) != 0) {
|
|
ptm = pw->pw_gecos;
|
|
for (i = 0 ; ptm && *ptm && (*ptm != ','); ptm++, i++) {
|
|
if (isupper(*ptm))
|
|
nomi[i] = tolower(*ptm);
|
|
else
|
|
nomi[i] = *ptm;
|
|
}
|
|
nomi[i] = '\0';
|
|
for (match=i=j=0 ; ((nom[j] != 0) && (nomi[i] != 0)) ; ) {
|
|
if (nomi[i] == nom[j]) {
|
|
if (match == 0)
|
|
match = i+1;
|
|
j++;
|
|
i++;
|
|
} else {
|
|
if (match != 0) {
|
|
i = match;
|
|
match = 0;
|
|
j = 0;
|
|
} else
|
|
i++;
|
|
}
|
|
}
|
|
if (nom[j] == '\0') { /* found it */
|
|
endpwent();
|
|
return(pw);
|
|
}
|
|
}
|
|
endpwent();
|
|
return(NILPWD);
|
|
}
|
|
#endif PERMISSIVE_USER_NAME
|
|
|
|
#ifdef DISTRIB_PASSWDS
|
|
struct afppass *afp = NULL;
|
|
#endif /* DISTRIB_PASSWDS */
|
|
|
|
/*
|
|
* validate user 'nam' using User Authentication Method 'uam'
|
|
*
|
|
*/
|
|
|
|
export OSErr
|
|
OSLogin(nam,pwd,pwdother,uam)
|
|
char *nam,*pwd;
|
|
byte *pwdother;
|
|
int uam;
|
|
{
|
|
struct passwd *p;
|
|
boolean safedebug;
|
|
byte encrypted[8]; /* 64 bits */
|
|
byte passkey[8]; /* password is 8 bytes max */
|
|
char *pass;
|
|
char *crypt();
|
|
#ifdef ULTRIX_SECURITY
|
|
char *ultrix_crypt();
|
|
char *crypted_password;
|
|
#endif ULTRIX_SECURITY
|
|
#ifdef DIGITAL_UNIX_SECURITY
|
|
char *bigcrypt();
|
|
struct pr_passwd *pr;
|
|
#endif DIGITAL_UNIX_SECURITY
|
|
#ifdef LWSRV_AUFS_SECURITY
|
|
extern char *userlogindir;
|
|
int namlen;
|
|
#endif LWSRV_AUFS_SECURITY
|
|
#ifdef SHADOW_PASSWD
|
|
struct spwd *sp;
|
|
int pw_check;
|
|
#endif SHADOW_PASSWD
|
|
#ifdef RUTGERS
|
|
extern char *ru_crypt();
|
|
#endif RUTGERS
|
|
#ifdef DISTRIB_PASSWDS
|
|
OSErr err;
|
|
void afpdp_encr();
|
|
int afpdp_init(), afpdp_writ();
|
|
struct afppass afpp, *afpdp_read();
|
|
#endif /* DISTRIB_PASSWDS */
|
|
extern int nousrvol;
|
|
|
|
safedebug = (DBOSI || (getuid() != 0 && geteuid() != 0));
|
|
|
|
logit(0,"Login requested for %s (we are %srunning as root)",
|
|
(uam == UAM_ANON) ? "<anonymous>" : nam,
|
|
(getuid() == 0 || geteuid() == 0) ? "" : "not ");
|
|
|
|
#ifdef LWSRV_AUFS_SECURITY
|
|
bin=malloc(strlen(nam)+1);
|
|
strcpy(bin,nam);
|
|
|
|
if ((tempbin = rindex(nam,':')) != NULL)
|
|
*tempbin='\0';
|
|
#endif LWSRV_AUFS_SECURITY
|
|
|
|
guestlogin = 0;
|
|
|
|
switch (uam) {
|
|
case UAM_RANDNUM:
|
|
#ifndef DISTRIB_PASSWDS
|
|
/*
|
|
* 'Randnum Exchange' UAM using lookaside password file
|
|
*
|
|
*/
|
|
if (!apasswdfile)
|
|
return(aeBadUAM);
|
|
if ((pass = user_aufs_passwd(nam)) == NULL) {
|
|
logit(0, "Login: entry %s not found in password file", nam);
|
|
return(aeUserNotAuth);
|
|
}
|
|
bzero(passkey,sizeof(passkey)); /* make sure zero */
|
|
strncpy((char *)passkey, pass, 8);
|
|
#ifdef SUNOS4_FASTDES
|
|
des_setparity(passkey);
|
|
/* copy the data to be encrypted */
|
|
bcopy(pwdother, encrypted, sizeof(encrypted));
|
|
ecb_crypt(passkey,encrypted,sizeof(encrypted),DES_ENCRYPT|DES_SW);
|
|
#else SUNOS4_FASTDES
|
|
dessetkey(passkey);
|
|
/* copy the data to be encrypted */
|
|
bcopy(pwdother, encrypted, sizeof(encrypted));
|
|
endes(encrypted);
|
|
#endif SUNOS4_FASTDES
|
|
if (bcmp(encrypted, pwd, 8) != 0) {
|
|
logit(0, "Login: encryption failed for user %s", nam);
|
|
return(aeUserNotAuth);
|
|
}
|
|
if ((p = aufs_unix_user(nam)) == NULL) {
|
|
logit(0, "Login: no UNIX user %s", nam);
|
|
return(aeUserNotAuth);
|
|
}
|
|
usrgid = p->pw_gid;
|
|
usruid = p->pw_uid;
|
|
usrnam = (char *)malloc(strlen(p->pw_name)+1);
|
|
strcpy(usrnam,p->pw_name);
|
|
usrdir = (char *)malloc(strlen(p->pw_dir)+1);
|
|
strcpy(usrdir,p->pw_dir);
|
|
break;
|
|
#else /* DISTRIB_PASSWDS */
|
|
case UAM_2WAYRAND:
|
|
/*
|
|
* 'Randnum Exchange' or '2-Way Randnum exchange'
|
|
* UAM using distributed passwords (in ~/.afppass)
|
|
*
|
|
*/
|
|
err = aeUserNotAuth;
|
|
if ((p = (struct passwd *)getpwnam(nam)) != NILPWD) {
|
|
if (afpdp_init(AFP_DISTPW_FILE) >= 0) {
|
|
if ((afp = afpdp_read(nam, p->pw_uid, p->pw_dir)) != NULL) {
|
|
bcopy(pwdother, encrypted, sizeof(encrypted));
|
|
if (uam == UAM_RANDNUM) {
|
|
desinit(0);
|
|
dessetkey(afp->afp_password);
|
|
endes(encrypted);
|
|
desdone();
|
|
} else /* use key-shifted DES code */
|
|
afpdp_encr(encrypted, afp->afp_password, NULL);
|
|
/* compare encrytpted passwords */
|
|
if (bcmp(encrypted, pwd, 8) == 0)
|
|
err = noErr;
|
|
/* enforce & count failed login attempts */
|
|
if (afp->afp_numattempt >= afp->afp_maxattempt
|
|
&& afp->afp_maxattempt > 0)
|
|
err = aeParamErr;
|
|
if (err != noErr) {
|
|
if (afp->afp_numattempt < 255)
|
|
afp->afp_numattempt++;
|
|
} else
|
|
afp->afp_numattempt = 0;
|
|
/* update user password file (using copy of structure) */
|
|
bcopy((char *)afp, (char *)&afpp, sizeof(struct afppass));
|
|
(void)afpdp_writ(nam, p->pw_uid, p->pw_dir, &afpp);
|
|
}
|
|
}
|
|
}
|
|
if (err != noErr) {
|
|
logit(0, "Login failed for %s (%s)", nam, afperr(err));
|
|
return(err);
|
|
}
|
|
/* save details */
|
|
usrgid = p->pw_gid;
|
|
usruid = p->pw_uid;
|
|
usrnam = (char *)malloc(strlen(p->pw_name)+1);
|
|
strcpy(usrnam,p->pw_name);
|
|
usrdir = (char *)malloc(strlen(p->pw_dir)+1);
|
|
strcpy(usrdir,p->pw_dir);
|
|
break;
|
|
#endif /* DISTRIB_PASSWDS */
|
|
case UAM_ANON:
|
|
/*
|
|
* 'No User Authent' UAM
|
|
*
|
|
*/
|
|
if (guestname == NULL)
|
|
return(aeParamErr);
|
|
p = (struct passwd *)getpwnam(guestname);
|
|
if (p == NILPWD) {
|
|
logit(0, "Login: guest user not valid %s", guestname);
|
|
return(aeParamErr); /* unknown user */
|
|
}
|
|
usrgid = p->pw_gid;
|
|
usruid = p->pw_uid;
|
|
usrnam = (char *)malloc(strlen(guestname)+1);
|
|
strcpy(usrnam,guestname);
|
|
guestlogin = 1;
|
|
usrdir = NULL;
|
|
break;
|
|
case UAM_CLEAR:
|
|
/*
|
|
* 'Cleartxt Passwrd' UAM
|
|
*
|
|
*/
|
|
if (!apasswdfile) {
|
|
p = (struct passwd *)getpwnam(nam); /* user name */
|
|
if (p == NILPWD) {
|
|
logit(0, "Login: user name %s NOT found in password file", nam);
|
|
#ifdef PERMISSIVE_USER_NAME
|
|
if ((p = (struct passwd *)getpwgnam(nam)) != NILPWD) /* gcos name */
|
|
logit(0, "Login: mapping \"%s\" to login name %s", nam, p->pw_name);
|
|
#endif PERMISSIVE_USER_NAME
|
|
} else {
|
|
logit(0, "Login: user %s found, real name is %s", nam, p->pw_gecos);
|
|
}
|
|
if (p == NILPWD) {
|
|
logit(0, "Login: Unknown user %s", nam);
|
|
return(aeParamErr); /* unknown user */
|
|
}
|
|
if (strlen(pwd) <= 0) {
|
|
logit(0, "Login: NULL password access denied for %s", nam);
|
|
return(aeUserNotAuth); /* null user passwords not allowed */
|
|
}
|
|
#ifdef SHADOW_PASSWD
|
|
if (shadow_flag) {
|
|
sp = (struct spwd *)getspnam(p->pw_name); /* get shadow info */
|
|
if (sp == NILSPWD) {
|
|
logit(0, "Login: user %s NOT found in shadow file", p->pw_name);
|
|
return(aeParamErr); /* unknown user */
|
|
} else {
|
|
logit(0, "Login: user %s found in shadow password file", p->pw_name);
|
|
}
|
|
endspent();
|
|
}
|
|
#else SHADOW_PASSWD
|
|
/* cope with some adjunct password file schemes */
|
|
if (strlen(p->pw_passwd) <= 0 || strlen(pwd) <= 0) {
|
|
logit(0, "Login: NULL password access denied for %s", nam);
|
|
return(aeUserNotAuth);
|
|
}
|
|
#endif SHADOW_PASSWD
|
|
#ifdef ULTRIX_SECURITY
|
|
/* avoid evaluation order problem */
|
|
crypted_password = ultrix_crypt(pwd, p);
|
|
if (strcmp(crypted_password, p->pw_passwd) != 0) {
|
|
#else ULTRIX_SECURITY
|
|
# ifdef DIGITAL_UNIX_SECURITY
|
|
pr = getprpwnam(nam);
|
|
if (pr == NULL || strcmp(bigcrypt(pwd, pr->ufld.fd_encrypt),
|
|
pr->ufld.fd_encrypt) != 0) {
|
|
# else DIGITAL_UNIX_SECURITY
|
|
# ifndef SHADOW_PASSWD
|
|
# ifdef RUTGERS
|
|
if (strcmp(ru_crypt(pwd,p->pw_passwd,p->pw_uid,p->pw_name),
|
|
p->pw_passwd) != 0) {
|
|
# else RUTGERS
|
|
if (strcmp(crypt(pwd,p->pw_passwd),p->pw_passwd) != 0) {
|
|
# endif RUTGERS
|
|
# else SHADOW_PASSWD
|
|
pw_check = (shadow_flag) ?
|
|
# ifdef RUTGERS
|
|
strcmp(ru_crypt(pwd,sp->sp_pwdp,p->pw_uid,p->pw_name),sp->sp_pwdp) :
|
|
strcmp(ru_crypt(pwd,p->pw_passwd,p->pw_uid,p->pw_name),p->pw_passwd);
|
|
# else RUTGERS
|
|
strcmp(crypt(pwd,sp->sp_pwdp),sp->sp_pwdp) :
|
|
strcmp(crypt(pwd,p->pw_passwd),p->pw_passwd);
|
|
# endif RUTGERS
|
|
if (pw_check) {
|
|
# endif SHADOW_PASSWD
|
|
# endif DIGITAL_UNIX_SECURITY
|
|
#endif ULTRIX_SECURITY
|
|
logit(0, "Login: Incorrect password for user %s", nam);
|
|
if (!safedebug)
|
|
return(aeUserNotAuth);
|
|
}
|
|
} else {
|
|
if ((p = aufs_unix_user(nam)) == NULL)
|
|
return(aeUserNotAuth);
|
|
if ((pass = user_aufs_passwd(nam)) == NULL)
|
|
return(aeUserNotAuth);
|
|
if (strcmp(pass,pwd) != 0)
|
|
return(aeUserNotAuth);
|
|
}
|
|
usrgid = p->pw_gid;
|
|
usruid = p->pw_uid;
|
|
usrnam = (char *)malloc(strlen(p->pw_name)+1);
|
|
strcpy(usrnam,p->pw_name);
|
|
usrdir = (char *)malloc(strlen(p->pw_dir)+1);
|
|
strcpy(usrdir,p->pw_dir);
|
|
break;
|
|
}
|
|
|
|
#ifdef ADMIN_GRP
|
|
if (uam != UAM_ANON) {
|
|
struct group *grps;
|
|
if ((grps = getgrnam(ADMIN_GRP)) != NULL) {
|
|
while (*(grps->gr_mem) != NULL) {
|
|
if (strcmp(p->pw_name, *grps->gr_mem) == 0) {
|
|
logit(0, "User %s has admin privs, logging in as superuser.",
|
|
p->pw_name);
|
|
usrgid = grps->gr_gid;
|
|
usruid = 0;
|
|
break;
|
|
}
|
|
*(grps->gr_mem)++;
|
|
}
|
|
}
|
|
}
|
|
#endif /* ADMIN_GRP */
|
|
|
|
#ifdef LOG_WTMP
|
|
/*
|
|
* write a 'wtmp' entry for user name, address & time (then we
|
|
* write a null entry to terminate, since wtmp is often set to
|
|
* mode 0644 and we're not running as root when we disconnect).
|
|
*
|
|
* This is unduly complex for the end result
|
|
*
|
|
*/
|
|
#ifdef LOG_WTMPX
|
|
# ifdef WTMPX_FILE
|
|
# undef WTMP_FILE
|
|
# define WTMP_FILE WTMPX_FILE
|
|
# define ut_time ut_xtime
|
|
# define utmp utmpx
|
|
# endif /* WTMPX_FILE */
|
|
#endif /* LOG_WTMPX */
|
|
{ extern AddrBlock addr;
|
|
struct utmp ut;
|
|
int fd;
|
|
|
|
bzero((char *)&ut, sizeof(struct utmp));
|
|
|
|
#if defined(WTMP_FILE) && defined(USER_PROCESS)
|
|
# define utusername ut.ut_user
|
|
ut.ut_type = USER_PROCESS;
|
|
ut.ut_id[0] = 'a';
|
|
ut.ut_id[1] = 'f';
|
|
ut.ut_id[2] = 'p';
|
|
ut.ut_id[3] = '\0';
|
|
#else /* WTMP_FILE && USER_PROCESS */
|
|
# define utusername ut.ut_name
|
|
# ifdef _PATH_WTMP
|
|
# define WTMP_FILE _PATH_WTMP
|
|
# else /* _PATH_WTMP */
|
|
# define WTMP_FILE "/var/adm/wtmp"
|
|
# endif /* _PATH_WTMP */
|
|
#endif /* WTMP_FILE && USER_PROCESS */
|
|
|
|
#ifdef LOG_WTMP_FILE
|
|
#undef WTMP_FILE
|
|
#define WTMP_FILE LOG_WTMP_FILE
|
|
#endif /* LOG_WTMP_FILE */
|
|
|
|
(void)sprintf(ut.ut_host, "%d.%d.%d",
|
|
ntohs(addr.net), addr.node, addr.skt);
|
|
(void)strncpy(ut.ut_line, "aufs", sizeof(ut.ut_line));
|
|
(void)strncpy(utusername, usrnam, sizeof(utusername));
|
|
ut.ut_time = time((time_t *)0);
|
|
#ifdef LOG_WTMPX
|
|
(void)updwtmpx(WTMP_FILE, &ut);
|
|
ut.ut_host[0] = '\0'; /* null hostname */
|
|
utusername[0] = '\0'; /* null username */
|
|
(void)updwtmpx(WTMP_FILE, &ut);
|
|
#else /* LOG_WTMPX */
|
|
if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
|
|
(void)write(fd, (char *)&ut, sizeof(struct utmp));
|
|
ut.ut_host[0] = '\0'; /* null hostname */
|
|
utusername[0] = '\0'; /* null username */
|
|
(void)write(fd, (char *)&ut, sizeof(struct utmp));
|
|
(void)close(fd);
|
|
}
|
|
#endif /* LOG_WTMPX */
|
|
}
|
|
#endif /* LOG_WTMP */
|
|
|
|
#ifdef LWSRV_AUFS_SECURITY
|
|
/* budd... */
|
|
if( userlogindir != NULL ) { /* need to save user logins? */
|
|
extern AddrBlock addr; /* is this valid now?? seems to be! */
|
|
char fname[ 100 ];
|
|
FILE *f;
|
|
|
|
#ifdef HIDE_LWSEC_FILE
|
|
if (hideLWSec(fname, userlogindir, usruid, usrgid, addr) < 0) {
|
|
logit(0, "OSLogin: error in hideLWSec() for %s", fname);
|
|
return(aeMiscErr);
|
|
}
|
|
#else HIDE_LWSEC_FILE
|
|
/* create file before setuid call so we can write in directory. */
|
|
make_userlogin( fname, userlogindir, addr );
|
|
#endif HIDE_LWSEC_FILE
|
|
|
|
if( (f = fopen( fname, "w" )) != NULL ) { /* sigh. leaves race. */
|
|
logit(0, "writing user %s into auth-file for %s", usrnam, bin);
|
|
fprintf( f, "%s\n", usrnam ); /* perhaps write temp */
|
|
fclose( f ); /* and rename? */
|
|
/* sigh. fchown and fchmod are BSDisms */
|
|
chmod( fname, 0644 ); /* make owned by user so they */
|
|
chown( fname, usruid, -1 ); /* can truncate it on exit!! */
|
|
} /* fopen ok */
|
|
else
|
|
logit(0,"Login: could not create %s: %s", fname, syserr() );
|
|
} /* userlogindir and not guest */
|
|
/* ...budd */
|
|
#endif LWSRV_AUFS_SECURITY
|
|
|
|
if (!safedebug && setgid(usrgid) != 0) {
|
|
logit(0,"Login: setgid failed for %s because %s",nam,syserr());
|
|
return(aeUserNotAuth);
|
|
}
|
|
#ifdef RUTGERS
|
|
if ((getuid() == 0 || geteuid() == 0) && ru_initgroups(usrnam, usrgid) < 0)
|
|
#else RUTGERS
|
|
if ((getuid() == 0 || geteuid() == 0) && initgroups(usrnam, usrgid) < 0)
|
|
#endif RUTGERS
|
|
logit(0,"OSLogin: initgroups failed for %s!: reason: %s",syserr(),usrnam);
|
|
if ((ngroups = dogetgroups()) < 0) {
|
|
logit(0,"OSLogin: getgroups failed for %s!: reason: %s",syserr(), usrnam);
|
|
ngroups = 0;
|
|
}
|
|
|
|
if (!safedebug && setuid(usruid) != 0) {
|
|
logit(0,"Login: setuid failed for %s because %s",nam,syserr());
|
|
return(aeUserNotAuth); /* or something */
|
|
}
|
|
|
|
logit(0,"Login: user %s, home directory %s",
|
|
usrnam, usrdir == NULL ? "none" : usrdir);
|
|
|
|
if ((usrdir != NULL) && (nousrvol != TRUE))
|
|
VInit(usrnam,usrdir); /* initialize volume stuff */
|
|
|
|
#ifdef USR_FILE_TYPES
|
|
{
|
|
char uftpath[MAXPATHLEN];
|
|
extern char *uftfilename;
|
|
|
|
uft_init(); /* initialize */
|
|
|
|
/* ~user UFT file */
|
|
if (usrdir != NULL) {
|
|
sprintf(uftpath, "%s/%s", usrdir, TYPFILE);
|
|
if (access(uftpath, R_OK) == 0) {
|
|
read_uft(uftpath); /* ~/afpfile */
|
|
} else {
|
|
sprintf(uftpath, "%s/%s", usrdir, TYPFILE1);
|
|
if (access(uftpath, R_OK) == 0)
|
|
read_uft(uftpath); /* ~/.afpfile */
|
|
}
|
|
}
|
|
/* global UFT file */
|
|
if (uftfilename != NULL)
|
|
if (access(uftfilename, R_OK) == 0)
|
|
read_uft(uftfilename);
|
|
}
|
|
#endif USR_FILE_TYPES
|
|
|
|
return(noErr);
|
|
}
|
|
|
|
/*
|
|
* change user password.
|
|
*
|
|
*/
|
|
|
|
OSChangePassword(nam, pwdold, pwdnew, uam)
|
|
char *nam;
|
|
byte *pwdold;
|
|
byte *pwdnew;
|
|
int uam;
|
|
{
|
|
switch (uam) {
|
|
case UAM_CLEAR:
|
|
case UAM_2WAYRAND:
|
|
return(aeBadUAM);
|
|
break;
|
|
case UAM_RANDNUM:
|
|
#ifdef DISTRIB_PASSWDS
|
|
{ struct passwd *p;
|
|
struct afppass *afpdp_read();
|
|
int afpdp_writ(), afpdp_pwex();
|
|
void afpdp_decr(), afpdp_upex();
|
|
|
|
/* must be an existing UNIX user */
|
|
if ((p = (struct passwd *)getpwnam(nam)) == NILPWD)
|
|
return(aeUserNotAuth);
|
|
/* grab user password details */
|
|
if ((afp = afpdp_read(nam, p->pw_uid, p->pw_dir)) == NULL)
|
|
return(aeUserNotAuth);
|
|
/* enforce different passwords */
|
|
if (bcmp(pwdold, pwdnew, 8) == 0)
|
|
return(aePwdSameErr);
|
|
desinit(0);
|
|
/* use current password to decrypt new */
|
|
dessetkey(afp->afp_password);
|
|
dedes(pwdnew);
|
|
/* use new password to decrypt old */
|
|
dessetkey(pwdnew);
|
|
dedes(pwdold);
|
|
desdone();
|
|
/* old password OK ? */
|
|
if (strncmp((char *)afp->afp_password, (char *)pwdold,
|
|
strlen((char *)afp->afp_password)) != 0)
|
|
return(aeUserNotAuth);
|
|
/* enforce password length control */
|
|
if (strlen((char *)pwdnew) < afp->afp_minmpwlen)
|
|
return(aePwdTooShort);
|
|
/* global expiry date, user changes not allowed */
|
|
if (afpdp_pwex(afp) < 0)
|
|
return(aeAccessDenied);
|
|
/* update structure & write */
|
|
afpdp_upex(afp);
|
|
afp->afp_numattempt = 0;
|
|
bcopy((char *)pwdnew, (char *)afp->afp_password, 8);
|
|
if (afpdp_writ(nam, p->pw_uid, p->pw_dir, afp) < 0)
|
|
return(aeUserNotAuth);
|
|
return(noErr);
|
|
}
|
|
#else /* DISTRIB_PASSWDS */
|
|
return(aeBadUAM);
|
|
#endif /* DISTRIB_PASSWDS */
|
|
break;
|
|
}
|
|
|
|
return(aeBadUAM);
|
|
}
|
|
|
|
/*
|
|
* OSErr OSExchangeFiles(IDirP apdir, char *afile, IDirP apdir, char *bfile)
|
|
*
|
|
* OSExchangeFiles swaps the data and resource forks but not the finder info
|
|
* of two files.
|
|
*
|
|
* Inputs:
|
|
* apdir parent directory id of one file.
|
|
* afile name of second file.
|
|
* bpdir parent directory id of second file.
|
|
* bfile name of second file.
|
|
*
|
|
* Outputs:
|
|
* OSErr Function result.
|
|
*
|
|
* Error recovery during renaming process is problematic ...
|
|
*
|
|
*/
|
|
|
|
export OSErr
|
|
OSExchangeFiles(apdir,afile,bpdir,bfile)
|
|
IDirP apdir,bpdir; /* parent dirs */
|
|
char *afile, *bfile; /* file names */
|
|
{
|
|
char a_path[MAXPATHLEN], b_path[MAXPATHLEN], t_path[MAXPATHLEN];
|
|
char apath[MAXPATHLEN], bpath[MAXPATHLEN], tpath[MAXPATHLEN];
|
|
char *temp = ".tXXX";
|
|
int err, cerr, amo, bmo;
|
|
extern int sessvers;
|
|
struct stat stb;
|
|
word attr;
|
|
|
|
/*
|
|
* either file rename-inhibited ?
|
|
*
|
|
*/
|
|
OSGetAttr(apdir, afile, &attr);
|
|
if (attr & FPA_RNI)
|
|
return((sessvers == AFPVersion1DOT1) ? aeAccessDenied : aeObjectLocked);
|
|
|
|
OSGetAttr(bpdir, bfile, &attr);
|
|
if (attr & FPA_RNI)
|
|
return((sessvers == AFPVersion1DOT1) ? aeAccessDenied : aeObjectLocked);
|
|
|
|
OSfname(a_path, apdir, afile, F_DATA); /* build A data file name */
|
|
OSfname(b_path, bpdir, bfile, F_DATA); /* same for B file */
|
|
OSfname(t_path, apdir, temp, F_DATA); /* same for tmp file */
|
|
|
|
#ifdef NOCASEMATCH
|
|
noCaseMatch(a_path);
|
|
noCaseMatch(b_path);
|
|
#endif NOCASEMATCH
|
|
|
|
if (DBOSI)
|
|
printf("OSExchangeFiles A=%s, B=%s\n", a_path, b_path);
|
|
|
|
/*
|
|
* can't exchange a file with itself
|
|
*
|
|
*/
|
|
if (strcmp(a_path, b_path) == 0)
|
|
return(aeSameObjectErr);
|
|
|
|
/*
|
|
* Not allowed if one doesn't have a resource directory
|
|
* and the other does.
|
|
*
|
|
*/
|
|
if ((apdir->flags & DID_RESOURCE) != (bpdir->flags & DID_RESOURCE))
|
|
return(aeParamErr);
|
|
|
|
/*
|
|
* get info on existing files so we can set them back afterwards
|
|
*
|
|
*/
|
|
if ((err = unix_stat(a_path, &stb)) != noErr)
|
|
return(err);
|
|
amo = filemode(stb.st_mode, stb.st_uid, stb.st_gid);
|
|
|
|
if ((err = unix_stat(b_path, &stb)) != noErr)
|
|
return(err);
|
|
bmo = filemode(stb.st_mode, stb.st_uid, stb.st_gid);
|
|
|
|
/*
|
|
* build resource file names
|
|
*
|
|
*/
|
|
if (apdir->flags & DID_RESOURCE) {
|
|
strcpy(apath, a_path);
|
|
strcpy(bpath, b_path);
|
|
strcpy(tpath, t_path);
|
|
toResFork(apath, afile);
|
|
toResFork(bpath, bfile);
|
|
toResFork(tpath, temp);
|
|
}
|
|
|
|
/*
|
|
* First: Rename the A data and resource forks as a temporary.
|
|
*
|
|
*/
|
|
err = unix_rename(a_path, t_path);
|
|
if (err != noErr) /* if an error on data files */
|
|
return(err); /* then give up */
|
|
|
|
if (apdir->flags & DID_RESOURCE) {
|
|
err = unix_rename(apath, tpath);
|
|
/* allow non-existant resource */
|
|
if (err != noErr && err != aeObjectNotFound) { /* error on rename? */
|
|
if (DBOSI)
|
|
printf("os_rename: failed %s for %s -> %s\n",
|
|
afperr(err), apath, tpath);
|
|
cerr = unix_rename(t_path, a_path); /* rename data back to original */
|
|
if (cerr != noErr && DBOSI)
|
|
printf("os_rename: cleanup failed\n");
|
|
unix_chmod(b_path, bmo); /* file:try to reset protection */
|
|
return(err);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Second: Rename the B file as A.
|
|
*
|
|
*/
|
|
err = unix_rename(b_path, a_path);
|
|
if (err != noErr) {
|
|
/* put A back as it was */
|
|
unix_rename(t_path, a_path);
|
|
unix_rename(tpath, apath);
|
|
return(err);
|
|
}
|
|
|
|
if (apdir->flags & DID_RESOURCE) {
|
|
err = unix_rename(bpath, apath);
|
|
/* allow non-existant resource */
|
|
if (err != noErr && err != aeObjectNotFound) { /* error on rename? */
|
|
if (DBOSI)
|
|
printf("os_rename: failed %s for %s -> %s\n",
|
|
afperr(err), bpath, apath);
|
|
cerr = unix_rename(a_path, b_path); /* rename data back to original */
|
|
if (cerr != noErr && DBOSI)
|
|
printf("os_rename: cleanup failed\n");
|
|
unix_chmod(b_path, bmo); /* file:try to reset protection */
|
|
/* put A back as it was */
|
|
unix_rename(t_path, a_path);
|
|
unix_rename(tpath, apath);
|
|
return(err);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Third: Rename the T file as B.
|
|
*
|
|
*/
|
|
err = unix_rename(t_path, b_path);
|
|
if (err != noErr) {
|
|
/* put B back as it was */
|
|
unix_rename(a_path, b_path);
|
|
unix_rename(apath, bpath);
|
|
/* put A back as it was */
|
|
unix_rename(t_path, a_path);
|
|
unix_rename(tpath, apath);
|
|
return(err);
|
|
}
|
|
|
|
if (apdir->flags & DID_RESOURCE) {
|
|
err = unix_rename(tpath, bpath);
|
|
/* allow non-existant resource */
|
|
if (err != noErr && err != aeObjectNotFound) { /* error on rename? */
|
|
if (DBOSI)
|
|
printf("os_rename: failed %s for %s -> %s\n",
|
|
afperr(err), tpath, bpath);
|
|
cerr = unix_rename(b_path, t_path); /* rename data back to original */
|
|
if (cerr != noErr && DBOSI)
|
|
printf("os_rename: cleanup failed\n");
|
|
unix_chmod(t_path, bmo); /* file:try to reset protection */
|
|
/* put B back as it was */
|
|
unix_rename(a_path, b_path);
|
|
unix_rename(apath, bpath);
|
|
/* put A back as it was */
|
|
unix_rename(t_path, a_path);
|
|
unix_rename(tpath, apath);
|
|
return(err);
|
|
}
|
|
}
|
|
|
|
FModified(apdir, afile); /* does an emodified */
|
|
FModified(bpdir, bfile); /* does an emodified */
|
|
|
|
return(noErr);
|
|
}
|
|
|
|
export word
|
|
OSRandom()
|
|
{
|
|
static time_t t = 0;
|
|
|
|
if (t == 0) {
|
|
time(&t);
|
|
#ifdef USERAND
|
|
srand(t);
|
|
#else
|
|
srandom(t);
|
|
#endif
|
|
}
|
|
#ifdef USERAND
|
|
return((word) rand());
|
|
#else
|
|
return((word) random());
|
|
#endif
|
|
}
|
|
|
|
sdword
|
|
CurTime()
|
|
{
|
|
return(time(0));
|
|
}
|
|
|
|
/*
|
|
* char *tilde(char *s)
|
|
*
|
|
* Expands a path starting with tilde, the same as the shell.
|
|
* Returns the expanded path.
|
|
*
|
|
*/
|
|
export char *
|
|
tilde(s)
|
|
char *s;
|
|
{
|
|
static char path[MAXPATHLEN];
|
|
char *sp,*logdir(),*l;
|
|
|
|
if (*s != '~') /* start with tilde? */
|
|
return(s); /* no, return original */
|
|
s++; /* skip over tilde */
|
|
if (*s == '\0') /* if nothing more, return */
|
|
return(usrdir);
|
|
|
|
if (*s == '/') { /* case of ~/ */
|
|
strcpy(path,usrdir); /* use user's dir */
|
|
strcat(path,s); /* and then the remainder */
|
|
return(path); /* return that */
|
|
}
|
|
|
|
if ((sp = index(s,'/')) == NULL) /* check for slash */
|
|
return(logdir(s)); /* return ~john expanded */
|
|
|
|
*sp = '\0'; /* otherwise tie off ~bill/mac */
|
|
if ((l = logdir(s)) == NULL) /* does the user exist? */
|
|
return NULL;
|
|
strcpy(path,l); /* copy in the expanded ~bill */
|
|
*sp = '/'; /* ... put back slash */
|
|
strcat(path,sp); /* append the remainder */
|
|
return(path); /* and return it */
|
|
}
|
|
|
|
export char *
|
|
logdir(user)
|
|
char *user;
|
|
{
|
|
struct passwd *p;
|
|
|
|
if (usrnam != NULL && strcmp(user,usrnam) == 0)
|
|
return(usrdir); /* already know logged in user dir */
|
|
|
|
p = (struct passwd *) getpwnam(user);
|
|
if (p != NILPWD)
|
|
return(p->pw_dir);
|
|
return(NULL);
|
|
}
|
|
|
|
private OSErr
|
|
unix_rmdir(path)
|
|
char *path;
|
|
{
|
|
if (DBUNX)
|
|
printf("unix_rmdir: path=%s\n",path);
|
|
|
|
if (rmdir(path) == 0) /* and try to delete it */
|
|
return(noErr);
|
|
|
|
if (DBUNX)
|
|
printf("unix_rmdir: failed %s\n",syserr());
|
|
|
|
return(ItoEErr(errno));
|
|
}
|
|
|
|
private OSErr
|
|
unix_unlink(path)
|
|
char *path;
|
|
{
|
|
if (DBUNX)
|
|
printf("unix_unlink: path=%s\n",path);
|
|
|
|
if (unlink(path) == 0) /* remove the file */
|
|
return(noErr); /* no error */
|
|
|
|
if (DBUNX)
|
|
printf("unix_unlink: failed %s\n",syserr());
|
|
|
|
return(ItoEErr(errno));
|
|
}
|
|
|
|
private OSErr
|
|
unix_rename(from,to)
|
|
char *from,*to;
|
|
{
|
|
if (DBUNX)
|
|
printf("unix_rename: from %s to %s\n",from,to);
|
|
|
|
#ifdef aux
|
|
if (strcmp(from, to) == 0)
|
|
return(noErr);
|
|
#endif aux
|
|
if (rename(from,to) == 0)
|
|
return(noErr);
|
|
|
|
#ifdef XDEV_RENAME
|
|
return(xdev_rename(from,to));
|
|
#else XDEV_RENAME
|
|
if (DBUNX)
|
|
printf("unix_rename: failed %s\n",syserr());
|
|
return(ItoEErr(errno));
|
|
#endif XDEV_RENAME
|
|
}
|
|
|
|
#ifdef XDEV_RENAME
|
|
private OSErr
|
|
xdev_rename(from,to)
|
|
char *from, *to;
|
|
{
|
|
struct stat fstb, tstb;
|
|
int err, mode, ffd, tfd;
|
|
|
|
if (DBUNX)
|
|
printf("xdev_rename: from %s to %s\n",from,to);
|
|
|
|
if ((err = unix_stat(from,&fstb)) != noErr)
|
|
return(ItoEErr(errno));
|
|
|
|
/* if "from" is a directory, recursively copy it */
|
|
if (S_ISDIR(fstb.st_mode)) {
|
|
#ifdef USEDIRENT
|
|
struct dirent *dinfp, *readdir();
|
|
#else USEDIRENT
|
|
struct direct *dinfp, *readdir();
|
|
#endif USEDIRENT
|
|
char fname[MAXPATHLEN];
|
|
char tname[MAXPATHLEN];
|
|
char *fend, *tend;
|
|
DIR *dptr;
|
|
|
|
if (DBUNX)
|
|
printf("xdev_rename: copying directory ...\n");
|
|
|
|
/* Create a destination directory with same owner, group */
|
|
if ((err = unix_mkdir(to,fstb.st_mode)) != noErr)
|
|
return(err);
|
|
if ((err = unix_chown(to,fstb.st_uid,fstb.st_gid)) != noErr)
|
|
return(err);
|
|
|
|
/* Read each item in the "from" dir and recurse to move it */
|
|
if ((dptr = opendir(from)) == NULL)
|
|
return(ItoEErr(errno));
|
|
|
|
fend = fname + strlen(strcpy(fname,from));
|
|
tend = tname + strlen(strcpy(tname,to));
|
|
*fend++ = '/';
|
|
*tend++ = '/';
|
|
|
|
for (dinfp = readdir(dptr); dinfp != NULL; dinfp = readdir(dptr)) {
|
|
if (*dinfp->d_name == '.') {
|
|
int namlen;
|
|
#if defined(USEDIRENT) && !defined(SOLARIS)
|
|
namlen = dinfp->d_namlen;
|
|
#else /* USEDIRENT */
|
|
namlen = strlen(dinfp->d_name);
|
|
#endif /* USEDIRENT */
|
|
if ((namlen == 1) ||
|
|
((namlen == 2) && (*(dinfp->d_name+1) == '.')))
|
|
continue;
|
|
}
|
|
*fend = *tend = '\0';
|
|
strcat(fname,dinfp->d_name);
|
|
strcat(tname,dinfp->d_name);
|
|
if ((err = xdev_rename(fname,tname)) != noErr) {
|
|
if (DBUNX)
|
|
printf("xdev_rename: copy failed %s\n",syserr());
|
|
closedir(dptr);
|
|
return(err);
|
|
}
|
|
}
|
|
closedir(dptr);
|
|
|
|
/* Finally, remove the directory */
|
|
return(unix_rmdir(from));
|
|
} else {
|
|
if ((err = os_copy(from,to,fstb.st_mode)) != noErr)
|
|
return(ItoEErr(err));
|
|
|
|
/* Remove the copied file */
|
|
return(unix_unlink(from));
|
|
}
|
|
}
|
|
#endif XDEV_RENAME
|
|
|
|
private OSErr
|
|
unix_open(path,mode,fd)
|
|
char *path;
|
|
int mode;
|
|
int *fd;
|
|
{
|
|
|
|
*fd = open(path,mode);
|
|
|
|
#ifdef APPLICATION_MANAGER
|
|
{
|
|
int lockn, protect;
|
|
extern int fdplist[NOFILE];
|
|
extern struct flist *applist;
|
|
|
|
/* don't check if we aren't read-only or open failed */
|
|
if (applist != NULL && *fd >=0 && mode == O_RDONLY) {
|
|
if (wantLock(path, &lockn, &protect) == 0) {
|
|
if (enforceLock(*fd, lockn) == 0) {
|
|
if (DBUNX)
|
|
printf("unix_open: open refused for %s (O > %d)\n", path, lockn);
|
|
close(*fd);
|
|
return(aeLockErr);
|
|
}
|
|
if (protect == 1) /* protect from copying */
|
|
fdplist[*fd] = 1;
|
|
}
|
|
}
|
|
}
|
|
#endif APPLICATION_MANAGER
|
|
|
|
if (DBUNX)
|
|
printf("unix_open: fd=%d, mode=%d, path=%s\n",*fd,mode,path);
|
|
|
|
if ((*fd) > 0)
|
|
return(noErr);
|
|
|
|
if (DBUNX)
|
|
printf("unix_open: failed %s\n",syserr());
|
|
|
|
return(ItoEErr(errno));
|
|
}
|
|
|
|
private OSErr
|
|
unix_close(fd)
|
|
int fd;
|
|
{
|
|
if (DBUNX)
|
|
printf("unix_close: fd=%d\n",fd);
|
|
|
|
#ifdef APPLICATION_MANAGER
|
|
{
|
|
extern int fdplist[NOFILE];
|
|
fdplist[fd] = -1;
|
|
}
|
|
#endif APPLICATION_MANAGER
|
|
|
|
#ifdef DENYREADWRITE
|
|
{
|
|
struct accessMode *p, *q;
|
|
|
|
p = accessMQueue;
|
|
q = (struct accessMode *)NULL;
|
|
|
|
while (p != (struct accessMode *)NULL) {
|
|
if (p->fd == fd) { /* delete from Q */
|
|
if (q == (struct accessMode *)NULL)
|
|
accessMQueue = p->next;
|
|
else
|
|
q->next = p->next;
|
|
free((char *)p);
|
|
break;
|
|
}
|
|
q = p;
|
|
p = p->next;
|
|
}
|
|
}
|
|
#endif DENYREADWRITE
|
|
|
|
if (close(fd) == 0)
|
|
return(noErr);
|
|
|
|
if (DBUNX)
|
|
printf("unix_close: failed %s\n",syserr());
|
|
|
|
return(ItoEErr(errno)); /* this would be a problem */
|
|
}
|
|
|
|
private OSErr
|
|
unix_mkdir(path,prot)
|
|
char *path;
|
|
int prot; /* protection */
|
|
{
|
|
if (DBUNX)
|
|
printf("unix_mkdir: path = %s\n",path);
|
|
|
|
if (mkdir(path,prot) == 0)
|
|
return(noErr);
|
|
|
|
if (DBUNX)
|
|
printf("unix_mkdir: failed %s\n",syserr());
|
|
|
|
return(ItoEErr(errno));
|
|
}
|
|
|
|
/*
|
|
* OSErr unix_create(char *path, int delf, int mode)
|
|
*
|
|
* Create a file.
|
|
*
|
|
*/
|
|
|
|
private OSErr
|
|
unix_create(path,delf,mode)
|
|
char *path;
|
|
int delf;
|
|
int mode;
|
|
{
|
|
int fd,flg;
|
|
|
|
if (DBUNX)
|
|
printf("unix_create: delf=%d, mode=o%o, path=%s\n",delf,mode,path);
|
|
|
|
flg = (delf) ? (O_CREAT | O_TRUNC) : (O_CREAT | O_EXCL);
|
|
|
|
if ((fd = open(path,flg,mode)) != -1) {
|
|
(void) close(fd);
|
|
return(noErr);
|
|
}
|
|
|
|
if (DBUNX)
|
|
printf("unix_create: failed %s\n",syserr());
|
|
|
|
return(ItoEErr(errno));
|
|
}
|
|
|
|
/*
|
|
* OSErr unix_createo(char *path, int delf, int mode, int *fd)
|
|
*
|
|
* Create a file and return the open file handle.
|
|
*
|
|
*/
|
|
|
|
private OSErr
|
|
unix_createo(path,delf,mode,fd)
|
|
char *path;
|
|
int delf;
|
|
int mode;
|
|
int *fd;
|
|
{
|
|
int flg;
|
|
|
|
if (DBUNX)
|
|
printf("unix_createo: delf=%d, path=%s\n",delf,path);
|
|
|
|
flg = (delf) ? (O_CREAT | O_TRUNC) : (O_CREAT | O_EXCL);
|
|
flg |= O_RDWR;
|
|
|
|
if ((*fd = open(path,flg,mode)) != -1)
|
|
return(noErr);
|
|
|
|
if (DBUNX)
|
|
printf("unix_createo: failed %s\n",syserr());
|
|
|
|
return(ItoEErr(errno));
|
|
}
|
|
|
|
#ifdef NOCHGRPEXEC
|
|
#ifndef USECHOWN
|
|
#define USECHOWN
|
|
#endif USECHOWN
|
|
#endif NOCHGRPEXEC
|
|
|
|
private OSErr
|
|
unix_chown(path,own,grp)
|
|
char *path;
|
|
int own,grp;
|
|
{
|
|
char gid[20]; /* big enough */
|
|
int pid, npid;
|
|
WSTATUS status;
|
|
#ifndef USECHOWN
|
|
struct stat stb;
|
|
OSErr err;
|
|
#endif USECHOWN
|
|
|
|
if (DBOSI)
|
|
printf("unix_chown: Attempting chown %s to owner %d, group %d\n",
|
|
path,own,grp);
|
|
#ifndef USECHOWN
|
|
if (usruid != 0) { /* not root, then do it hard way */
|
|
if (grp < 0) {
|
|
if (DBOSI)
|
|
printf("unix_chown: skipping owner and group for %s\n",path);
|
|
return(noErr);
|
|
}
|
|
if (DBOSI)
|
|
printf("unix_chown: skipping owner, chgrp %s to group %d\n",path,grp);
|
|
if ((err = unix_stat(path, &stb)) != noErr)
|
|
return(err);
|
|
if (stb.st_gid == grp) /* naught to do */
|
|
return(noErr);
|
|
sprintf(gid, "%d",grp);
|
|
#ifdef NOVFORK
|
|
if ((pid=fork()) == 0) {
|
|
#else NOVFORK
|
|
if ((pid=vfork()) == 0) {
|
|
#endif NOVFORK
|
|
execl("/bin/chgrp","chgrp",gid,path, 0);
|
|
_exit(1); /* no false eofs */
|
|
}
|
|
while ((npid = wait(&status)) != pid)
|
|
/* NULL */;
|
|
/* right half of status is non-zero if */
|
|
/* (a) stopped (&0xff == 0177) */
|
|
/* or */
|
|
/* (b) signaled (0x7f != 0) */
|
|
/* (c) coredumped (0x80 != 0) */
|
|
#if defined(WIFSTOPPED) && defined(WIFSIGNALED) && defined(W_COREDUMP)
|
|
if (WIFSTOPPED(status) || WIFSIGNALED(status) || (W_COREDUMP(status) != 0))
|
|
return(aeAccessDenied); /* oh well */
|
|
#else /* WIFSTOPPED && WIFSIGNALED && W_COREDUMP */
|
|
if ((status & 0xff) != 0)
|
|
return(aeAccessDenied); /* oh well */
|
|
#endif/* WIFSTOPPED && WIFSIGNALED && W_COREDUMP */
|
|
/* retcode is leftmost 8 bits */
|
|
#ifdef W_RETCODE
|
|
if (W_RETCODE(status) != 0)
|
|
return(aeAccessDenied); /* oh well */
|
|
#else /* W_RETCODE */
|
|
if ((status>>8) != 0)
|
|
return(aeAccessDenied); /* oh well */
|
|
#endif /* W_RETCODE */
|
|
return(noErr);
|
|
}
|
|
#endif USECHOWN
|
|
#ifdef NOCHGRPEXEC
|
|
if (usruid != 0) { /* not root, ignore user */
|
|
if (grp < 0) {
|
|
if (DBOSI)
|
|
printf("unix_chown: skipping owner and group for %s\n",path);
|
|
return(noErr);
|
|
}
|
|
own = -1;
|
|
if (DBOSI)
|
|
printf("unix_chown: skipping owner, chgrp %s to group %d\n",path,grp);
|
|
}
|
|
#endif NOCHGRPEXEC
|
|
/* root can do what it pleases, so can any user on sysv */
|
|
if (chown(path, own, grp) < 0)
|
|
return(ItoEErr(errno));
|
|
return(noErr);
|
|
}
|
|
|
|
|
|
private OSErr
|
|
unix_chmod(path,mode)
|
|
char *path;
|
|
u_short mode;
|
|
{
|
|
if (DBUNX)
|
|
printf("unix_chmod: mode=o%o path=%s\n",mode,path);
|
|
|
|
if (chmod(path,(int) mode) == 0)
|
|
return(noErr);
|
|
|
|
if (DBUNX)
|
|
printf("unix_chmod: failed %s\n",syserr());
|
|
|
|
return(ItoEErr(errno));
|
|
}
|
|
|
|
private OSErr
|
|
unix_stat(path,stb)
|
|
char *path;
|
|
struct stat *stb;
|
|
{
|
|
if (DBUNX)
|
|
printf("unix_stat: path=%s\n",path);
|
|
|
|
if (stat(path,stb) == 0)
|
|
return(noErr);
|
|
|
|
if (DBUNX)
|
|
printf("unix_stat: failed %s\n",syserr());
|
|
|
|
return(ItoEErr(errno));
|
|
}
|
|
|
|
/*
|
|
* figure out the mode a file should have based on the uid, gid, and mode
|
|
* of its parents. Mainly for drop folders.
|
|
*
|
|
* really shouldn't have to do this -- instead change the owner
|
|
* of the file -- however: (a) bsd doesn't allow and (b) must do after
|
|
* all file operations because we don't have handle -- mucho work --
|
|
* if we could.
|
|
*
|
|
*/
|
|
private int
|
|
filemode(mode, uid, gid)
|
|
int mode, uid, gid;
|
|
{
|
|
int mo = mode & 0777; /* convert st_mode to mode */
|
|
if (uid != usruid) {
|
|
/* check for conditions that would mean drop folder for us */
|
|
/* (but, don't accept a drop folder on basis of group that is */
|
|
/* world viewable even though it really is a drop folder for us) */
|
|
if ((mo & 04) == 0 && (mo & 040) == 0 && OSInGroup(gid))
|
|
mo |= 0666; /* let everyone else read/write */
|
|
/* We need to do this because the poor person who get's the file */
|
|
/* can't do anything with it otherwise */
|
|
}
|
|
return(mo);
|
|
}
|
|
|
|
private char *
|
|
syserr()
|
|
{
|
|
#if !(defined(__FreeBSD__) || defined(__NetBSD__))
|
|
extern char *sys_errlist[];
|
|
#endif
|
|
extern int sys_nerr;
|
|
static char buf[50];
|
|
int serrno;
|
|
|
|
serrno = errno;
|
|
if (serrno < 0 || serrno > sys_nerr) {
|
|
sprintf(buf,"Unknown error %d",serrno);
|
|
return(buf);
|
|
}
|
|
return(sys_errlist[serrno]);
|
|
}
|
|
|
|
private OSErr
|
|
ItoEErr(num)
|
|
int num;
|
|
{
|
|
extern int sessvers; /* AFP protocol version */
|
|
|
|
switch (num) {
|
|
case EPERM: /* Not owner */
|
|
return(aeAccessDenied);
|
|
case ENOENT: /* No such file or directory */
|
|
return(aeObjectNotFound);
|
|
case EACCES: /* Permission denied */
|
|
return(aeAccessDenied);
|
|
case EEXIST: /* File exists */
|
|
return(aeObjectExists);
|
|
case ENOTDIR: /* Not a directory */
|
|
return(aeDirNotFound);
|
|
case EISDIR: /* Is a directory */
|
|
return(aeObjectTypeErr);
|
|
case ENFILE: /* File table overflow */
|
|
return(aeDiskFull);
|
|
case EMFILE: /* Too many files open */
|
|
return(aeTooManyFilesOpen);
|
|
case ETXTBSY: /* Text file busy */
|
|
return(aeFileBusy);
|
|
case ENOSPC: /* No space left on device */
|
|
return(aeDiskFull);
|
|
case EROFS: /* read only file system */
|
|
if (sessvers == AFPVersion1DOT1)
|
|
return(aeAccessDenied);
|
|
else
|
|
return(aeVolumeLocked);
|
|
#ifndef AIX
|
|
# ifdef ENOTEMPTY
|
|
case ENOTEMPTY:
|
|
return(aeDirNotEmpty);
|
|
# endif ENOTEMPTY
|
|
#endif AIX
|
|
#ifdef EDQUOT
|
|
case EDQUOT:
|
|
return(aeDiskFull);
|
|
#endif EDQUOT
|
|
default:
|
|
if (DBUNX)
|
|
printf("ItoEErr: Unknown unix error code %d\n",errno);
|
|
return(aeMiscErr);
|
|
}
|
|
}
|
|
|
|
#ifdef ULTRIX_SECURITY
|
|
char *
|
|
ultrix_crypt(pwd, pw)
|
|
char *pwd;
|
|
struct passwd *pw;
|
|
{
|
|
extern char *crypt(), *crypt16();
|
|
extern AUTHORIZATION *getauthuid();
|
|
AUTHORIZATION *au;
|
|
struct svcinfo *si;
|
|
char *passwd;
|
|
|
|
/*
|
|
* the asterisk means that the real encrypted password
|
|
* is in the auth file. But we really should check to
|
|
* see if the security level is either SEC_UPGRADE or
|
|
* SEC_ENHANCED and the password is an asterisk because
|
|
* the security level could be BSD and someone put an
|
|
* asterisk in to turn an account off, but if that's the
|
|
* case the right thing will happen here anyways (i.e.,
|
|
* nothing encrypts to a single asterisk so the test will
|
|
* fail).
|
|
*/
|
|
if (strcmp(pw->pw_passwd, "*") == 0) {
|
|
si = getsvc();
|
|
if ((si->svcauth.seclevel == SEC_UPGRADE) ||
|
|
(si->svcauth.seclevel == SEC_ENHANCED)) {
|
|
/*
|
|
* if they aren't in the auth file return
|
|
* the empty string. this can't match since
|
|
* we've already thrown out empty passwords.
|
|
*/
|
|
if ((au = getauthuid(pw->pw_uid)) == NULL)
|
|
return("");
|
|
pw->pw_passwd = au->a_password;
|
|
}
|
|
return(crypt16(pwd, pw->pw_passwd));
|
|
}
|
|
return(crypt(pwd, pw->pw_passwd));
|
|
}
|
|
#endif ULTRIX_SECURITY
|
|
#ifdef APPLICATION_MANAGER
|
|
|
|
/*
|
|
* Enforce control on the number of file opens (or Applications
|
|
* run) by checking our 'Application List' and attempting to apply
|
|
* a single byte-range read lock on the file resource fork at byte N.
|
|
* Can also specify no Finder copying with 'P' flag on number.
|
|
*
|
|
* djh@munnari.OZ.AU
|
|
* September, 1991
|
|
*
|
|
*/
|
|
|
|
int
|
|
wantLock(file, num, protect)
|
|
char *file;
|
|
int *num, *protect;
|
|
{
|
|
int cmpval;
|
|
struct flist *applp;
|
|
extern struct flist *applist;
|
|
|
|
applp = applist;
|
|
while (applp != NULL) {
|
|
/* check the SORTED list, return 0 if found */
|
|
if ((cmpval = strcmp(file, applp->filename)) <= 0) {
|
|
*num = applp->incarnations;
|
|
*protect = applp->protected;
|
|
return(cmpval);
|
|
}
|
|
applp = applp->next;
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
int
|
|
enforceLock(fd, maxm)
|
|
int fd, maxm;
|
|
{
|
|
int i;
|
|
struct flock flck;
|
|
|
|
for (i = 1; i <= maxm; i++) {
|
|
flck.l_type = F_WRLCK;
|
|
flck.l_whence = 0; /* SEEK_SET */
|
|
flck.l_start = i+4;
|
|
flck.l_len = 1;
|
|
|
|
if (fcntl(fd, F_GETLK, &flck) == -1)
|
|
return(-1); /* not supported ? */
|
|
|
|
if (flck.l_type == F_RDLCK)
|
|
continue;
|
|
|
|
if (flck.l_type == F_UNLCK) {
|
|
flck.l_type = F_RDLCK;
|
|
flck.l_whence = 0; /* SEEK_SET */
|
|
flck.l_start = i+4;
|
|
flck.l_len = 1;
|
|
if (fcntl(fd, F_SETLK, &flck) == -1)
|
|
return(-1); /* not supported ? */
|
|
|
|
return(1); /* success */
|
|
}
|
|
}
|
|
return(0); /* no locks left */
|
|
}
|
|
#endif APPLICATION_MANAGER
|
|
#ifdef HIDE_LWSEC_FILE
|
|
/*
|
|
* int HideLWSec(char *fname, char *userlogindir, int usruid, int
|
|
* usrgid, AddrBlock addr )
|
|
*
|
|
* Add additional security to LW security flag file when using
|
|
* LWSRV_AUFS_SECURITY. Only relevant if both HIDE_LWSEC_FILE
|
|
* and LWSRV_AUFS_SECURITY defined in m4.features.
|
|
* Original flag file in world read/writeable directory
|
|
* permitted links and "borrowing" laserWriters from others, thus
|
|
* circumventing laser page charges.
|
|
* This creates a directory with user id ownership and the flag
|
|
* file is placed in this directory.
|
|
*
|
|
*/
|
|
|
|
int
|
|
hideLWSec(fname, userlogindir, usruid, usrgid, addr)
|
|
char *fname, *userlogindir;
|
|
int usruid, usrgid;
|
|
AddrBlock addr;
|
|
{
|
|
char protecteddir[MAXPATHLEN], flagfile[MAXPATHLEN];
|
|
struct stat dbuf;
|
|
DIR *locdirp;
|
|
|
|
(void) strcpy(protecteddir, userlogindir);
|
|
make_userlogin(fname, protecteddir, addr);
|
|
(void) strcpy(protecteddir, fname);
|
|
fname[0] = '\0';
|
|
make_userlogin(fname, protecteddir, addr); /* create flag file */
|
|
|
|
if (stat(protecteddir, &dbuf) == 0) {
|
|
/* dir found and stat sucessful, we need to zap dir */
|
|
if (stat(fname, &dbuf) == 0)
|
|
if (S_ISREG(dbuf.st_mode))
|
|
if (unlink(fname) < 0 )
|
|
logit(0, "hideLWSec: errno=%d unlinking %s\n", errno, fname);
|
|
if (rmdir(protecteddir ) < 0 ) {
|
|
logit(0, "hideLWSec: errno=%d Can't zap %s\n", errno, fname);
|
|
return(-1);
|
|
}
|
|
} else /* error occured in stat, but not no entry */
|
|
if (errno != ENOENT ) {
|
|
logit(0, "hideLWSec: stat errno= %d for %s\n", errno, fname);
|
|
return(-1);
|
|
}
|
|
if (mkdir(protecteddir, 0700) < 0) {
|
|
logit(0, "hideLWSec: unable to create %s,errno=%d\n", fname, errno);
|
|
return(-1);
|
|
} else {
|
|
chown(protecteddir, usruid, usrgid);
|
|
}
|
|
return(0);
|
|
}
|
|
#endif HIDE_LWSEC_FILE
|
|
#ifdef DENYREADWRITE
|
|
/*
|
|
* Implement full "access modes" and "deny modes" as
|
|
* specified in Inside AppleTalk 2nd Ed. page 13-35.
|
|
*
|
|
* Reserve four single byte locks at the beginning of
|
|
* each fork (ie: byte range locks are offset by four
|
|
* from their protected data. This is OK since locks
|
|
* are maintained by kernel tables and are independent
|
|
* of the data and the actual file length).
|
|
*
|
|
* byte 0 = access mode read bit
|
|
* byte 1 = access mode write bit
|
|
* byte 2 = deny mode read bit
|
|
* byte 3 = deny mode write bit
|
|
*
|
|
* DENYREADWRITE uses fcntl(2) advisory F_RDLCKs. F_GETLK
|
|
* returns F_UNLCK if the requesting process holds the
|
|
* specified lock. Thus, there is no way for a process to
|
|
* determine if it is still holding a specific lock. For
|
|
* this reason we maintain a separate queue of access modes
|
|
* and file names for files opened by this process.
|
|
*
|
|
*/
|
|
|
|
int
|
|
getAccessDenyMode(path, fd)
|
|
char *path;
|
|
int fd;
|
|
{
|
|
int i;
|
|
int mode = 0;
|
|
int mask = 0x01;
|
|
struct flock flck;
|
|
struct accessMode *p = accessMQueue;
|
|
|
|
for (i = 1; i <= 4; i++) {
|
|
flck.l_type = F_WRLCK;
|
|
flck.l_whence = 0; /* SEEK_SET */
|
|
flck.l_start = i;
|
|
flck.l_len = 1;
|
|
if (fcntl(fd, F_GETLK, &flck) != -1)
|
|
if (flck.l_type != F_UNLCK)
|
|
mode |= mask;
|
|
mask <<= 1;
|
|
}
|
|
|
|
while (p != (struct accessMode *)NULL) {
|
|
if (strcmp(p->path, path) == 0)
|
|
mode |= p->mode;
|
|
p = p->next;
|
|
}
|
|
|
|
return(((mode & 0x0c) << 2) | (mode & 0x03));
|
|
}
|
|
|
|
/*
|
|
* set access and deny modes on fd for 'path'
|
|
*
|
|
*/
|
|
|
|
int
|
|
setAccessDenyMode(path, fd, mode)
|
|
char *path;
|
|
int fd, mode;
|
|
{
|
|
int i;
|
|
int mask = 0x01;
|
|
struct flock flck;
|
|
struct accessMode *p;
|
|
|
|
mode = ((mode & 0x30) >> 2) | (mode & 0x03);
|
|
|
|
for (i = 1; i <= 4; i++) {
|
|
if (mode & mask) {
|
|
flck.l_type = F_RDLCK;
|
|
flck.l_whence = 0; /* SEEK_SET */
|
|
flck.l_start = i;
|
|
flck.l_len = 1;
|
|
if (fcntl(fd, F_SETLK, &flck) == -1)
|
|
mode &= ~mask;
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
|
|
if ((p = (struct accessMode *)malloc(sizeof(struct accessMode))) != NULL) {
|
|
strcpy(p->path, path);
|
|
p->fd = fd;
|
|
p->mode = mode;
|
|
p->next = accessMQueue;
|
|
accessMQueue = p;
|
|
}
|
|
|
|
return(((mode & 0x0c) << 2) | (mode & 0x03));
|
|
}
|
|
|
|
/*
|
|
* Inside AppleTalk, 2nd Ed.
|
|
* Table 13-1: Synchronization rules
|
|
*
|
|
*/
|
|
|
|
int accessTable[16] = {
|
|
0x0000, 0xf0f0, 0xff00, 0xfff0,
|
|
0xaaaa, 0xfafa, 0xffaa, 0xfffa,
|
|
0xcccc, 0xfcfc, 0xffcc, 0xfffc,
|
|
0xeeee, 0xfefe, 0xffee, 0xfffe
|
|
};
|
|
|
|
/*
|
|
* check current file access/deny
|
|
* mode against requested mode
|
|
*
|
|
*/
|
|
|
|
int
|
|
accessConflict(cadm, mode)
|
|
int cadm, mode;
|
|
{
|
|
cadm = ((cadm & 0x30) >> 2) | (cadm & 0x03);
|
|
mode = ((mode & 0x30) >> 2) | (mode & 0x03);
|
|
|
|
return((accessTable[cadm] >> mode) & 0x01);
|
|
}
|
|
#endif DENYREADWRITE
|