This is afpos.c in view mode; [Download] [Up]
/*
* $Author: cck $ $Date: 88/05/25 14:37:02 $
* $Header: afpos.c,v 1.83 88/05/25 14:37:02 cck Rel $
* $Revision: 1.83 $
*/
/*
* 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
*
*/
/*
* 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
* 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.
*
* 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
*/
#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
#include <sys/file.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <netat/appletalk.h>
#include <sys/time.h>
#ifdef aux
# include <compat.h>
#endif
#ifdef USESUNQUOTA
# ifndef USEQUOTA
# define USEQUOTA
# endif
#endif
#ifdef NEEDFCNTLDOTH
# include <fcntl.h>
#endif
#ifdef USESTRINGDOTH
# include <string.h>
#else
# include <strings.h>
#endif
#ifdef USEUSTAT
# include <ustat.h>
#endif
#ifdef USESTATFS
# include <sys/vfs.h>
#endif
#ifdef USEQUOTA
# 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
# include <mntent.h>
# include <ufs/quota.h>
# endif
# ifndef Q_GETDLIM
# ifdef Q_GETQUOTA
# define Q_GETDLIM Q_GETQUOTA
/* If you're here you've turned on quotas but aren't using the bsd
or Sun quota systems -- add an else and whatever you need */
# 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
#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 MAXBSIZE
# define IOBSIZE MAXBSIZE /* set to max buf entry size by if there */
#else
# ifdef BLKDEV_IOSIZE
# define IOBSIZE BLKDEV_IOSIZE /* set to std block device read size */
# else
# define IOBSIZE BUFSIZ /* use stdio bufsiz */
# endif
#endif
#define NILPWD ((struct passwd *) 0)
/* macro to test for directory file */
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#define E_IOWN 0x80000000 /* owner of file */
#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
# define GGTYPE int
#endif
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
# define ISOLDGETMNT 0
# endif
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
#endif
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();
private OSErr os_chmod();
private void os_chmod_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
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 */
private OSErr unix_rmdir();
private OSErr unix_unlink();
private OSErr unix_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();
/*
* 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
#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
#ifdef USESUNQUOTA
build_mount_table();
#endif
}
void
tellaboutos()
{
int haveflock;
int havelockf;
log("CONFIGURATION");
getlockinfo(&haveflock, &havelockf);
if (haveflock)
log(" Configured: FLOCK");
if (havelockf)
log(" Configured: LOCKF");
#ifdef USEUSTAT
log(" Configured: Volume space information: ustat");
#endif
#ifdef USESTATFS
log(" Configured: Volume space information: statfs");
#endif
#ifdef USEGETMNT
log(" Configured: Volume space information: getmnt");
if (oldgetmnt)
log(" using old style (Ultrix 1.2, 2.0) getmnt");
#endif
#ifdef USESUNQUOTA
log(" Configured: SUN quota system");
#endif
#ifndef USESUNQUOTA
/* sunquota turns on usequota */
# ifdef USEQUOTA
log(" Configured: Melbourne (BSD) quota system");
# endif
#endif
#ifdef USECHOWN
log(" Configured: chown: system allows one to give away ownership of files");
#endif
if (os_issmartunixfi())
log(" Configured: reading unknown unix files to get finder information");
log(" Configured translation tables are:");
ncs_table_dump();
}
/*
* 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) /* unused internal group/user id */
#define ItoEID(iid) ((sdword) (iid == 0 ? NOID : iid))
#define EtoIID(eid) ((int) (eid == NOID ? 0 : eid))
/*
*
* 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);
switch (fcn) {
case MapID_C:
pwd = getpwuid(id);
if (pwd == NULL)
sprintf(name,"%08d",id);
else
strcpy(name,pwd->pw_name);
break;
case MapID_G:
grp = getgrgid(id);
if (grp == NULL)
sprintf(name,"%08d",id);
else
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);
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(userid)) == NULL)
return(aeItemNotFound);
usr = pwd->pw_uid;
grp = pwd->pw_gid;
}
guirp->guir_userid = usr;
guirp->guir_pgroup = grp;
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).
*
*/
OSErr
OSDelete(ipdir,idir,file)
IDirP ipdir, idir;
char *file;
{
int err;
char path[MAXPATHLEN];
OSfname(path,ipdir,file,F_DATA); /* create data fork name */
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;
struct direct *dp;
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_namlen <= 2 &&
dp->d_name[0] == '.' &&
(dp->d_name[1] == '.' || dp->d_name[1] == '\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];
OSfname(path,pdir,file,typ); /* build unix file name */
return(unix_unlink(path)); /* do the work... */
}
/*
* 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 fpath[MAXPATHLEN];
char tpath[MAXPATHLEN];
struct stat stb;
int err,cerr;
int mo;
OSfname(fpath,fpdir,from,F_DATA); /* build data file name */
OSfname(tpath,tpdir,to,F_DATA); /* for from and to files */
if (DBOSI)
printf("OSRename from=%s, to=%s\n",fpath,tpath);
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 */
if ((err = unix_stat(pathstr(tpdir), &stb)) != noErr)
return(err);
mo = filemode(stb.st_mode, stb.st_uid, stb.st_gid);
if ((err = unix_stat(fpath,&stb)) != noErr)
return(err);
err = unix_rename(fpath,tpath); /* give unix the args */
if (err != noErr) /* if an error on data files */
return(err); /* then give up */
if (!S_ISDIR(stb.st_mode)) { /* directories have no rsrc fork */
unix_chmod(tpath, mo); /* file: try to reset protection */
if (fpdir->flags & DID_RESOURCE) {
OSfname(fpath,fpdir,from,F_RSRC); /* build resource file names */
OSfname(tpath,tpdir,to,F_RSRC);
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);
OSfname(fpath,fpdir,from,F_DATA); /* try to rebuild */
OSfname(tpath,tpdir,to,F_DATA);
cerr = unix_rename(tpath,fpath); /* rename back to orignal */
if (cerr != noErr && DBOSI)
printf("os_rename: cleanup failed\n");
unix_chmod(tpath, stb.st_mode&0777); /* file:try to reset protection */
return(err);
}
}
}
if (fpdir->flags & DID_FINDERINFO) {
OSfname(fpath,fpdir,from,F_FNDR); /* build finder info file names */
OSfname(tpath,tpdir,to,F_FNDR);
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 */
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;
/* 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)
lseek(fd,(off_t)offs,L_SET);
if (OSTestLock(fd, reqcnt) != noErr) {
return(aeLockErr);
}
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 */
switch (typ) {
case F_RSRC:
strcat(path, "/");
strcat(path, RFDIRFN);
break;
case F_FNDR:
strcat(path, "/");
strcat(path, FIDIRFN);
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 */
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\n",path);
if (stat(path,&buf) != 0) { /* file exists? */
if (idir) /* was in directory tree? */
Idrdirid(ipdir, idir); /* invalidate the entry then */
return(aeObjectNotFound); /* no... */
}
/* 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;
fdp->fdp_bdate = 0;
fdp->fdp_zero = 0; /* zero the zero byte (?) */
/* strcpy(fdp->fdp_lname,fn); /* copy long name */
if (idir == VolRootD(volid))
strcpy(fdp->fdp_lname, VolName(volid));
else
ItoEName(fn,fdp->fdp_lname);
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 */
return(OSFileInfo(ipdir,fn,fdp,&buf)); /* 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();
word bm;
int nchild;
fdp->fdp_dbitmap &= DP_AUFS_VALID; /* truncate to findable */
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) /* skip finfo if not requested */
OSGetFNDR(ipdir,fn,fdp->fdp_finfo);
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];
struct stat stb;
IDirP pdir;
int i;
OSfname(path,idirid,"",F_DATA);
if (stat(path, &stb) == 0) {
if (S_ISDIR(stb.st_mode))
idirid->flags |= DID_DATA;
#ifndef NOLSTAT
if (lstat(path, &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);
}
/* don't follow symbolic links here! */
OSfname(path,idirid,"",F_FNDR);
if (lstat(path, &stb) == 0)
if (S_ISDIR(stb.st_mode))
idirid->flags |= DID_FINDERINFO;
OSfname(path,idirid,"",F_RSRC);
if (lstat(path, &stb) == 0)
if (S_ISDIR(stb.st_mode))
idirid->flags |= DID_RESOURCE;
#else
/* no symolic links then */
OSfname(path,idirid,"",F_FNDR);
if (stat(path, &stb) == 0)
if (S_ISDIR(stb.st_mode))
idirid->flags |= DID_FINDERINFO;
OSfname(path,idirid,"",F_RSRC);
if (stat(path, &stb) == 0)
if (S_ISDIR(stb.st_mode))
idirid->flags |= DID_RESOURCE;
#endif
}
idirid->flags |= DID_VALID;
}
export OSErr
OSFileInfo(ipdir,fn,fdp,buf)
IDirP ipdir;
char *fn;
FileDirParm *fdp;
struct stat *buf;
{
struct stat stb;
char rpath[MAXPATHLEN];
word bm;
fdp->fdp_fbitmap &= FP_AUFS_VALID; /* truncate to aufs supported */
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) /* skip finfo if not requested */
OSGetFNDR(ipdir,fn,fdp->fdp_finfo);
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;
if (bm & FP_RFLEN) {
OSfname(rpath,ipdir,fn,F_RSRC); /* 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,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;
OSfname(path, ipdir, fn, type);
return(unix_stat(path, &stb));
}
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) {
/* can't find it !!! */
if (idir)
Idrdirid(ipdir, idir); /* remove from tree */
return(err);
}
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;
if (bm & (FP_FINFO|FP_ATTR))
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 path[MAXPATHLEN];
int own,grp,err; /* owner and group ids */
DirParm *dp = &fdp->fdp_parms.dp_parms;
int flags;
if (fdp->fdp_dbitmap & (DP_FINFO|DP_ATTR))
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(path,ipdir,fn,F_DATA); /* change unix name */
if ((err = unix_chown(path,own,grp)) != noErr)
return(err);
OSfname(path,ipdir,fn,F_RSRC); /* change unix name */
if ((err = unix_chown(path,own,grp)) != noErr && err != aeObjectNotFound)
return(err);
OSfname(path,ipdir,fn,F_FNDR); /* create unix name */
if ((err = unix_chown(path,own,grp)) != noErr && err != aeObjectNotFound)
return(err);
EModified(ipdir);
}
if (fdp->fdp_dbitmap & DP_ACCES) {
u_short acc = EtoIAccess(dp->dp_accright);
if ((err = os_chmod(ipdir,fn,acc,F_DATA)) != noErr)
return(err);
os_chmod_all(ipdir, fn, acc, F_DATA); /* change all file protections */
os_chmod_all(ipdir, fn, acc, F_RSRC);
os_chmod_all(ipdir, fn, acc, F_FNDR);
if ((err = os_chmod(ipdir,fn,acc,F_RSRC)) != noErr &&
err != aeObjectNotFound)
return(err);
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 */
if (err != noErr)
return(err);
EModified(idir);
return(noErr);
}
/*
* Change file protection 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_chmod_all(idir,fn,mode,typ)
IDirP idir;
char *fn;
u_short mode;
int typ;
{
char path[MAXPATHLEN];
struct stat stb;
struct direct *dp;
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:
path[pl] = '/';
strcpy(path+pl+1, RFDIRFN);
break;
case F_FNDR:
path[pl] = '/';
strcpy(path+pl+1, FIDIRFN);
break;
}
if (DBOSI)
printf("os_chmod: setting %o for %s\n",mode,path);
dirp = opendir(path);
if (dirp == NULL) {
if (DBOSI)
printf("os_chmod: opendir failed on %s\n",path);
return;
}
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_chmod: stat failed for %s\n",path);
continue; /* some error... */
}
if (S_ISDIR(stb.st_mode)) {
if (dp->d_name[0] != '.')
continue;
/* was . or .. */
if (dp->d_name[1] == '\0' ||
(dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
continue; /* skip it */
/* if not .resource or .finderinfo then skip */
if (typ != F_DATA &&
strcmp(dp->d_name,RFDIRFN) != 0 && strcmp(dp->d_name, FIDIRFN) != 0)
continue;
}
err = unix_chmod(path,mode); /* set the mode for this file */
/* ignore errors */
}
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;
if (usruid == 0) /* root? */
e |= ((E_RD|E_WR|E_SR)<<ES_USER);
else if (usruid == uid) /* but if the 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 e = ItoEPriv(imode,IS_WORLD,ES_USER); /* user rights = world */
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);
switch (errno) {
case ENOTDIR:
return(aeDirNotFound);
case ENOENT:
return(aeObjectNotFound);
case EACCES:
return(aeAccessDenied);
}
return(aeAccessDenied);
}
/*
* 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 ????
* v_free free bytes on volume ????
*
*/
export OSErr
OSVolInfo(path,v, bitmap)
char *path;
VolPtr v;
word bitmap; /* bitmap of info needed */
{
struct stat buf;
#ifdef USEQUOTA
struct dqblk dqblk;
#endif
#ifdef USEUSTAT
struct ustat ubuf;
#endif
#ifdef USESTATFS
struct statfs fsbuf;
#endif
time_t sometime;
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)) == 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 (quota(Q_GETDLIM, usruid, buf.st_dev, &dqblk) == 0 &&
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;
return(noErr);
}
#endif
#ifdef USEGETMNT
if (ultrix_volinfo(path, &buf, v) == noErr)
return(noErr);
#endif
#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;
return(noErr);
}
#endif
#ifdef USESTATFS
if (statfs(path, &fsbuf) >= 0) {
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;
return(noErr);
}
#endif
v->v_size = 0x1000000; /* some random number */
v->v_free = 0x1000000; /* same random number */
return(noErr); /* all ok */
}
#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;
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;
return(noErr);
}
#endif /* GETMNT */
#ifdef USESUNQUOTA
#ifndef MAXUFSMOUNTED
# ifdef NMOUNT
# define MAXUFSMOUNTED NMOUNT /* NMOUNT in param.h */
# else
# define MAXUFSMOUNTED 32 /* arb. value */
# endif
#endif
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);
}
/*
* 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)
log("/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)
log("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)
log("/etc/mtab is read protected or nonexistant");
if (num_mount_points != 0)
return(-1);
if ((mt = setmntent("/etc/fstab", "r")) == NULL) {
if (DBOSI)
log("/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) {
log("Grrr.. too many mounted file systems for build_mount_table");
break;
}
}
endmntent(mt);
if (num_mount_points == 0 && DBOSI)
log("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
quota(cmd, uid, arg, addr)
int cmd, uid, arg;
caddr_t addr;
{
char *fsname;
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);
}
return(quotactl(cmd, fsname, uid, addr));
}
#endif
export OSErr
OSCopyFile(spdir,sfile,dpdir,dfile)
IDirP spdir,dpdir; /* source and destination parents */
char *sfile,*dfile; /* source and destination file names */
{
char spath[MAXPATHLEN];
char dpath[MAXPATHLEN];
struct stat stb;
int mo;
int err;
OSfname(spath,spdir,sfile,F_DATA); /* create unix style name for data */
OSfname(dpath,dpdir,dfile,F_DATA); /* same for destination */
if (DBOSI)
printf("OSCopyFile: %s -> %s\n",spath,dpath);
err = unix_stat(dpath,&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(spath,dpath, mo);
if (err != noErr && DBOSI)
printf("OSCopyFile: DATA copy failed %s\n",afperr(err));
if (err != noErr)
return(err);
OSfname(spath,spdir,sfile,F_RSRC); /* create unix style name for rsrc */
OSfname(dpath,dpdir,dfile,F_RSRC); /* 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);
}
OSfname(spath,spdir,sfile,F_FNDR); /* create unix style name for fndr */
OSfname(dpath,dpdir,dfile,F_FNDR); /* 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);
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 path[MAXPATHLEN];
int err,derr,rerr,cerr,mo;
struct stat stb;
OSfname(path,pdir,file,F_DATA); /* create data file name */
if (DBOSI)
printf("OSCreateFile: creating %s with %s\n",path,
(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 */
OSfname(path,pdir,file,F_DATA); /* create data fork */
derr = unix_create(path,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 */
OSfname(path,pdir,file,F_DATA);
cerr = unix_unlink(path); /* clean up... */
if (cerr != noErr && DBOSI)
printf("OSCreateFile: cleanup failed\n");
return(derr);
}
OSfname(path,pdir,file,F_RSRC); /* 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 */
OSfname(path,pdir,file,F_RSRC);
cerr = unix_unlink(path); /* clean up... */
if (cerr != noErr && DBOSI)
printf("OSCreateFile: cleanup failed\n");
/* should we clean up data fork? */
return(rerr);
}
OSfname(path,pdir,file,F_FNDR); /* create finder fork */
err = unix_create(path,TRUE,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;
{
char path[MAXPATHLEN];
char *ms;
int mo;
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;
}
if (DBOSI)
printf("OSOpenFork: Opening %s for %s\n",path,ms);
return(unix_open(path,mo,fhdl));
}
private char *guestname = NULL;
export boolean
setguestid(nam)
char *nam;
{
struct passwd *p;
if ((p = getpwnam(nam)) == NULL) {
log("Guest id %s NOT IN PASSWORD FILE",nam);
log("Guest id %s NOT IN PASSWORD FILE",nam);
return(FALSE);
}
if (p->pw_uid == 0) {
log("Guest id %s is a root id! NOT ALLOWED!", nam);
log("Guest id %s is a root id! NOT ALLOWED!", nam);
log("Guest id %s is a root id! NOT ALLOWED!", nam);
return(FALSE);
}
if (p->pw_gid == 0) {
log("Guest id %s is in group 0. BE WARNED!", nam);
log("Guest id %s is in group 0. BE WARNED!", nam);
log("Guest id %s is in group 0. BE WARNED!", nam);
}
log("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) {
log("error: no des routines, so no aufs password file used");
return(FALSE);
}
apasswdfile = init_aufs_passwd(pw);
return(apasswdfile);
}
export OSErr
OSLoginRand(nam)
char *nam;
{
if (is_aufs_user(nam))
return(noErr);
return(aeParamErr);
}
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;
safedebug = (DBOSI || (getuid() != 0 && geteuid() != 0));
log("Login requested for %s (we are %srunning as root)",
(uam == UAM_ANON) ? "<anonymous>" : nam,
(getuid() == 0 || geteuid() == 0) ? "" : "not ");
switch (uam) {
case UAM_RANDNUM:
if (!apasswdfile)
return(aeBadUAM);
if ((pass = user_aufs_passwd(nam)) == NULL)
return(aeUserNotAuth);
bzero(passkey,sizeof(passkey)); /* make sure zero */
strncpy(passkey, pass, 8);
dessetkey(passkey);
/* copy the data to be encrypted */
bcopy(pwdother, encrypted, sizeof(encrypted));
endes(encrypted);
if (bcmp(encrypted, pwd, 8) != 0)
return(aeUserNotAuth);
if ((p = aufs_unix_user(nam)) == NULL)
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;
case UAM_ANON:
if (guestname == NULL)
return(aeParamErr);
p = (struct passwd *)getpwnam(guestname);
if (p == NILPWD) {
log("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);
usrdir = NULL;
break;
case UAM_CLEAR:
if (!apasswdfile) {
p = (struct passwd *) getpwnam(nam); /* user name */
if (p == NILPWD) {
log("Login: Unknown user %s",nam);
return(aeParamErr); /* unknown user */
}
if (strcmp(crypt(pwd,p->pw_passwd),p->pw_passwd) != 0) {
log("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;
}
if (!safedebug && setgid(usrgid) != 0) {
log("Login: setgid failed for %s because %s",nam,syserr());
return(aeUserNotAuth);
}
if ((getuid() == 0 || geteuid() == 0) && initgroups(usrnam, usrgid) < 0)
log("OSLogin: initgroups failed for %s!: reason: %s",syserr(),usrnam);
if ((ngroups = dogetgroups()) < 0) {
log("OSLogin: getgroups failed for %s!: reason: %s",syserr(), usrnam);
ngroups = 0;
}
if (!safedebug && setuid(usruid) != 0) {
log("Login: setuid failed for %s because %s",nam,syserr());
return(aeUserNotAuth); /* or something */
}
log("Login: user %s, home directory %s",
usrnam, usrdir == NULL ? "none" : usrdir);
if (usrdir != NULL)
VInit(usrnam,usrdir); /* initialize volume stuff */
return(noErr);
}
/*
* change password.
*
* nice idea, but not really workable right now.
* best we could do is fork passwd
* AFP2.0
*
*/
OSChangePassword(nam, pwdold, pwdnew, uam)
char *nam;
byte *pwdold;
byte *pwdnew;
int uam;
{
return(aeCallNotSupported);
}
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();
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 */
strcpy(path,logdir(s)); /* 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 (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
if (rename(from,to) == 0)
return(noErr);
if (DBUNX)
printf("unix_rename: failed %s\n",syserr());
return(ItoEErr(errno));
}
private OSErr
unix_open(path,mode,fd)
char *path;
int mode;
int *fd;
{
*fd = open(path,mode);
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);
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_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_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));
}
private OSErr
unix_chown(path,own,grp)
char *path;
int own,grp;
{
char gid[20]; /* big enough */
int pid, npid;
int status;
#ifndef USECHOWN
struct stat stb;
OSErr err;
#endif
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 (DBOSI)
printf("unix_chown: skipping owern, 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);
if ((pid=vfork()) == 0) {
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 ((status & 0xff) != 0)
return(aeAccessDenied); /* oh well */
/* retcode is leftmost 8 bits */
if ((status>>8) != 0)
return(aeAccessDenied); /* oh well */
return(noErr);
}
#endif
/* 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()
{
extern char *sys_errlist[];
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;
{
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 */
return(aeAccessDenied);
case ENOTEMPTY:
return(aeDirNotEmpty);
#ifdef EDQUOT
case EDQUOT:
return(aeDiskFull);
#endif EDQUOT
default:
if (DBUNX)
printf("ItoEErr: Unknown unix error code %d\n",errno);
return(aeMiscErr);
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.