From 6738516b5336475fbd69872d5d23c2ea44434a44 Mon Sep 17 00:00:00 2001 From: Manuel Pereira Date: Fri, 26 Jul 2002 06:33:59 +0000 Subject: [PATCH] jafs-library-20020725 Java API work --- Makefile.in | 22 +- configure.in | 1 + src/JAVA/classes/ErrorMessages.properties | 910 ++++++++ src/JAVA/classes/org/openafs/jafs/ACL.java | 743 +++++++ .../classes/org/openafs/jafs/AFSException.java | 204 ++ .../classes/org/openafs/jafs/AFSFileException.java | 195 ++ .../org/openafs/jafs/AFSSecurityException.java | 202 ++ src/JAVA/classes/org/openafs/jafs/Cell.java | 1874 ++++++++++++++++ src/JAVA/classes/org/openafs/jafs/ErrorTable.java | 203 ++ src/JAVA/classes/org/openafs/jafs/File.java | 942 ++++++++ .../classes/org/openafs/jafs/FileInputStream.java | 167 ++ .../classes/org/openafs/jafs/FileOutputStream.java | 217 ++ src/JAVA/classes/org/openafs/jafs/Group.java | 1278 +++++++++++ src/JAVA/classes/org/openafs/jafs/Key.java | 467 ++++ src/JAVA/classes/org/openafs/jafs/PTSEntry.java | 99 + src/JAVA/classes/org/openafs/jafs/Partition.java | 1052 +++++++++ src/JAVA/classes/org/openafs/jafs/Process.java | 953 ++++++++ src/JAVA/classes/org/openafs/jafs/Server.java | 2351 ++++++++++++++++++++ src/JAVA/classes/org/openafs/jafs/Token.java | 493 ++++ src/JAVA/classes/org/openafs/jafs/User.java | 1948 ++++++++++++++++ src/JAVA/classes/org/openafs/jafs/Volume.java | 1394 ++++++++++++ src/JAVA/libjafs/ACL.c | 192 ++ src/JAVA/libjafs/AdminToken.c | 415 ++++ src/JAVA/libjafs/Cell.c | 1485 +++++++++++++ src/JAVA/libjafs/Exceptions.h | 12 + src/JAVA/libjafs/File.c | 674 ++++++ src/JAVA/libjafs/FileInputStream.c | 153 ++ src/JAVA/libjafs/FileOutputStream.c | 175 ++ src/JAVA/libjafs/Group.c | 827 +++++++ src/JAVA/libjafs/Internal.c | 909 ++++++++ src/JAVA/libjafs/Internal.h | 63 + src/JAVA/libjafs/JAFS_README | 123 + src/JAVA/libjafs/Key.c | 249 +++ src/JAVA/libjafs/Makefile.in | 240 ++ src/JAVA/libjafs/Partition.c | 482 ++++ src/JAVA/libjafs/Process.c | 567 +++++ src/JAVA/libjafs/Server.c | 1657 ++++++++++++++ src/JAVA/libjafs/User.c | 1484 ++++++++++++ src/JAVA/libjafs/UserToken.c | 321 +++ src/JAVA/libjafs/Volume.c | 901 ++++++++ src/JAVA/libjafs/etc/CacheConfig | 16 + src/JAVA/libjafs/etc/CacheConfig.100MB | 16 + src/JAVA/libjafs/etc/CacheConfig.40MB | 16 + src/TechNotes-JavaAPI | 94 + src/config/Makefile.config.in | 1 + 45 files changed, 26785 insertions(+), 2 deletions(-) create mode 100644 src/JAVA/classes/ErrorMessages.properties create mode 100644 src/JAVA/classes/org/openafs/jafs/ACL.java create mode 100644 src/JAVA/classes/org/openafs/jafs/AFSException.java create mode 100644 src/JAVA/classes/org/openafs/jafs/AFSFileException.java create mode 100644 src/JAVA/classes/org/openafs/jafs/AFSSecurityException.java create mode 100644 src/JAVA/classes/org/openafs/jafs/Cell.java create mode 100644 src/JAVA/classes/org/openafs/jafs/ErrorTable.java create mode 100644 src/JAVA/classes/org/openafs/jafs/File.java create mode 100644 src/JAVA/classes/org/openafs/jafs/FileInputStream.java create mode 100644 src/JAVA/classes/org/openafs/jafs/FileOutputStream.java create mode 100644 src/JAVA/classes/org/openafs/jafs/Group.java create mode 100644 src/JAVA/classes/org/openafs/jafs/Key.java create mode 100644 src/JAVA/classes/org/openafs/jafs/PTSEntry.java create mode 100644 src/JAVA/classes/org/openafs/jafs/Partition.java create mode 100644 src/JAVA/classes/org/openafs/jafs/Process.java create mode 100644 src/JAVA/classes/org/openafs/jafs/Server.java create mode 100644 src/JAVA/classes/org/openafs/jafs/Token.java create mode 100644 src/JAVA/classes/org/openafs/jafs/User.java create mode 100644 src/JAVA/classes/org/openafs/jafs/Volume.java create mode 100644 src/JAVA/libjafs/ACL.c create mode 100644 src/JAVA/libjafs/AdminToken.c create mode 100644 src/JAVA/libjafs/Cell.c create mode 100644 src/JAVA/libjafs/Exceptions.h create mode 100644 src/JAVA/libjafs/File.c create mode 100644 src/JAVA/libjafs/FileInputStream.c create mode 100644 src/JAVA/libjafs/FileOutputStream.c create mode 100644 src/JAVA/libjafs/Group.c create mode 100644 src/JAVA/libjafs/Internal.c create mode 100644 src/JAVA/libjafs/Internal.h create mode 100644 src/JAVA/libjafs/JAFS_README create mode 100644 src/JAVA/libjafs/Key.c create mode 100644 src/JAVA/libjafs/Makefile.in create mode 100644 src/JAVA/libjafs/Partition.c create mode 100644 src/JAVA/libjafs/Process.c create mode 100644 src/JAVA/libjafs/Server.c create mode 100644 src/JAVA/libjafs/User.c create mode 100644 src/JAVA/libjafs/UserToken.c create mode 100644 src/JAVA/libjafs/Volume.c create mode 100644 src/JAVA/libjafs/etc/CacheConfig create mode 100644 src/JAVA/libjafs/etc/CacheConfig.100MB create mode 100644 src/JAVA/libjafs/etc/CacheConfig.40MB create mode 100644 src/TechNotes-JavaAPI diff --git a/Makefile.in b/Makefile.in index b025d5e..ac65599 100644 --- a/Makefile.in +++ b/Makefile.in @@ -58,7 +58,7 @@ dest_nolibafs: all_nolibafs dest_dirs dest_only_libafs: only_libafs dest_dirs $(MAKE) build TARGET=libafs COMPILE_PART2B=dest -${TOP_INCDIR} ${TOP_INCDIR}/afs ${TOP_LIBDIR}: +${TOP_INCDIR} ${TOP_INCDIR}/afs ${TOP_LIBDIR} ${TOP_JLIBDIR}: mkdir -p $@ install_dirs: force @@ -434,6 +434,20 @@ libadmin: libafsauthent bozo echo Not building MT libadmin for ${SYS_NAME} ;; \ esac +libjafs: libadmin + case ${SYS_NAME} in \ + alpha_dux*|sgi_*|sun4x_*|rs_aix*|*linux*|hp_ux110) \ + ${COMPILE_PART1} JAVA/libjafs ${COMPILE_PART2} ;; \ + *) \ + echo Not building MT libjafs for ${SYS_NAME} ;; \ + esac + +libjafsadm: libjafs + +jafs: libjafs + +jafsadm: libjafsadm + finale: project cmd comerr afsd allrcmds butc tbutc @ENABLE_KERNEL_MODULE@ libuafs audit kauth log package \ ptserver scout bu_utils ubik uss bozo vfsck volser \ venus update xstat afsmonitor dauth rxdebug libafsrpc \ @@ -547,6 +561,7 @@ clean2: -${COMPILE_PART1} libadmin/cfg ${COMPILE_CLEAN} -${COMPILE_PART1} libadmin/test ${COMPILE_CLEAN} -${COMPILE_PART1} libadmin/samples ${COMPILE_CLEAN} + -${COMPILE_PART1} JAVA/libjafs ${COMPILE_CLEAN} -${COMPILE_PART1} finale ${COMPILE_CLEAN} -${COMPILE_PART1} mpp ${COMPILE_CLEAN} -${COMPILE_PART1} package ${COMPILE_CLEAN} @@ -560,7 +575,7 @@ clean2: -${COMPILE_PART1} libuafs ${COMPILE_CLEAN} -(cd src/libafs; /bin/rm -rf afs afsint config rx) -(cd src/libuafs; /bin/rm -rf afs afsint config rx des) - -/bin/rm -rf ${TOP_INCDIR} ${TOP_LIBDIR} + -/bin/rm -rf ${TOP_INCDIR} ${TOP_LIBDIR} ${TOP_JLIBDIR} -/bin/rm -rf libafs_tree ${SYS_NAME} @@ -620,6 +635,7 @@ distclean: clean src/libadmin/samples/Makefile \ src/libadmin/test/Makefile \ src/libadmin/vos/Makefile \ + src/JAVA/libjafs/Makefile \ src/libafs/Makefile \ src/libafs/Makefile.common \ src/libafs/MakefileProto.${MKAFS_OSTYPE} \ @@ -763,3 +779,5 @@ rcp: project rsh inetd allrcmds: project rcp rlogind + + diff --git a/configure.in b/configure.in index 6df54c1..eb2723f 100644 --- a/configure.in +++ b/configure.in @@ -50,6 +50,7 @@ src/fsprobe/Makefile \ src/ftpd43+/Makefile \ src/gtx/Makefile \ src/inetd/Makefile \ +src/JAVA/libjafs/Makefile \ src/kauth/test/Makefile \ src/kauth/Makefile \ src/libacl/test/Makefile \ diff --git a/src/JAVA/classes/ErrorMessages.properties b/src/JAVA/classes/ErrorMessages.properties new file mode 100644 index 0000000..2f20124 --- /dev/null +++ b/src/JAVA/classes/ErrorMessages.properties @@ -0,0 +1,910 @@ +#----------------------------------------------------------- +# Custom UFiler Error Codes +#----------------------------------------------------------- +UNKNOWN = Unknown error. +SPECIAL_CASE = Special case error. +GENERAL_FAILURE = Operation returned unsuccessful. + +E1000 = Data requested does not exist or is null. +E1001 = User session is invalid +E1002 = Session has expired, please login again +E1003 = Operation aborted +E1004 = Operation was forced to abort + +#----------------------------------------------------------- +# Standard UNIX Error Codes +#----------------------------------------------------------- +E1 = Operation not permitted +E2 = No such file or directory +E3 = No such process +E4 = Interrupted system call +E5 = I/O error +E6 = No such device or address +E7 = Arg list too long +E8 = Exec format error +E9 = Bad file number +E10 = No child processes +E11 = Try again +E12 = Out of memory +E13 = Permission denied +E14 = Bad address +E15 = Block device required +E16 = Device or resource busy +E17 = File exists +E18 = Cross-device link +E19 = No such device +E20 = Not a directory +E21 = Is a directory +E22 = Invalid argument +E23 = File table overflow +E24 = Too many open files +E25 = Not a typewriter +E26 = Text file busy +E27 = File too large +E28 = No space left on device +E29 = Illegal seek +E30 = Read-only file system +E31 = Too many links +E32 = Broken pipe +E33 = Math argument out of domain of func +E34 = Math result not representable +E35 = Resource deadlock would occur +E36 = File name too long +E37 = No record locks available +E38 = Function not implemented +E39 = Directory not empty +E40 = Too many symbolic links encountered +E41 = Operation would block +E42 = No message of desired type +E43 = Identifier removed +E44 = Channel number out of range +E45 = Level 2 not synchronized +E46 = Level 3 halted +E47 = Level 3 reset +E48 = Link number out of range +E49 = Protocol driver not attached +E50 = No CSI structure available +E51 = Level 2 halted +E52 = Invalid exchange +E53 = Invalid request descriptor +E54 = Exchange full +E55 = No anode +E56 = Invalid request code +E57 = Invalid slot +E58 = Dead lock +E59 = Bad font file format +E60 = Device not a stream +E61 = No data available +E62 = Timer expired +E63 = Out of streams resources +E64 = Machine is not on the network +E65 = Package not installed +E66 = Object is remote +E67 = Link has been severed +E68 = Advertise error +E69 = Srmount error +E70 = Communication error on send +E71 = Protocol error +E72 = Multihop attempted +E73 = RFS specific error +E74 = Not a data message +E75 = Value too large for defined data type +E76 = Name not unique on network +E77 = File descriptor in bad state +E78 = Remote address changed +E79 = Can not access a needed shared library +E80 = Accessing a corrupted shared library +E81 = .lib section in a.out corrupted +E82 = Attempting to link in too many shared libraries +E83 = Cannot exec a shared library directly +E84 = Illegal byte sequence +E85 = Interrupted system call should be restarted +E86 = Streams pipe error +E87 = Too many users +E88 = Socket operation on non-socket +E89 = Destination address required +E90 = Message too long +E91 = Protocol wrong type for socket +E92 = Protocol not available +E93 = Protocol not supported +E94 = Socket type not supported +E95 = Operation not supported on transport endpoint +E96 = Protocol family not supported +E97 = Address family not supported by protocol +E98 = Address already in use +E99 = Cannot assign requested address +E100 = Network is down +E101 = Network is unreachable +E102 = Network dropped connection because of reset +E103 = Software caused connection abort +E104 = Connection reset by peer +E105 = No buffer space available +E106 = Transport endpoint is already connected +E107 = Transport endpoint is not connected +E108 = Cannot send after transport endpoint shutdown +E109 = Too many references: cannot splice +E110 = Connection timed out +E111 = Connection refused +E112 = Host is down +E113 = No route to host +E114 = Operation already in progress +E115 = Operation now in progress +E116 = Stale NFS file handle +E117 = Structure needs cleaning +E118 = Not a XENIX named type file +E119 = No XENIX semaphores available +E120 = Is a named type file +E121 = Remote I/O error +E122 = Quota exceeded +E123 = No medium found +E124 = Wrong medium type +#----------------------------------------------------------- +# Error Codes for acfg_errors +#----------------------------------------------------------- +E70354688 = mysterious failure +E70354689 = could not find entry +E70354690 = do not know that information +E70354691 = line appears before a cell has been defined +E70354692 = syntax error +E70354693 = a database file is missing +E70354694 = no more entries +#----------------------------------------------------------- +# Error Codes for ktc_errors +#----------------------------------------------------------- +E11862784 = an unexpected error was encountered +E11862785 = a buffer was too small for the response +E11862786 = an invalid argument was passed in +E11862787 = no such entry +E11862788 = a pioctl failed +E11862789 = AFS kernel pioctl doesn't exist +E11862790 = unknown cell was passed to SetToken +E11862791 = Cache Manager is not initialized / afsd is not running +E11862792 = failed to send or receive session key via remote procedure call +E11862793 = Cache Manager RPC server is not responding +#----------------------------------------------------------- +# Error Codes for boserr +#----------------------------------------------------------- +E39424 = process not active +E39425 = no such entity +E39426 = can't do operation now +E39427 = entity already exists +E39428 = failed to create entity +E39429 = index out of range +E39430 = you are not authorized for this operation +E39431 = syntax error in create parameter +E39432 = I/O error +E39433 = network problem +E39434 = unrecognized bnode type +E39435 = kvno already used - have to remove existing kvno's before reuse +E39436 = this function requires encrypted input, use a newer client program +#----------------------------------------------------------- +# Error Codes for butc_errs +#----------------------------------------------------------- +E156566272 = error in dump/restore process +E156566273 = ungraceful abort +E156566274 = the process has already been aborted +E156566275 = unable to end dump/restore since work in progress +E156566276 = some of the dump/restores were unsuccessful +E156566277 = could not abort the process +E156566278 = the process was aborted by request +E156566279 = scan tape resulted in failure +E156566280 = No dump task with specified ID +E156566281 = No tasks active +E156566282 = the volume was not found on tape +E156566283 = unexpected EOF encountered on tape +E156566284 = missing file trailer on tape +E156566285 = unexpected tape label +E156566286 = tape was unusable +E156566287 = corrupted volume header on tape +E156566288 = internal error +E156566289 = corruption in internal queue data structures +E156566290 = memory allocation failure +E156566291 = access denied +E156566292 = tape requested to be skipped +E156566293 = invalid task +#----------------------------------------------------------- +# Error Codes for butm_errs +#----------------------------------------------------------- +E156568832 = interface incompatible +E156568833 = there is not an opened tape +E156568834 = multiple simultaneous opens not permitted +E156568835 = can't open tape +E156568836 = error during tape close +E156568837 = tape I/O error +E156568838 = write operation on read-only tape +E156568839 = operation inappropriate in this context +E156568840 = read file ended before all data read +E156568841 = write a zero length file +E156568842 = end of tape +E156568843 = problem reading configuration +E156568844 = argument too long or out of range +E156568845 = unexpected end of volume data +E156568846 = appended tape label +E156568847 = end of dump +E156568848 = tape device error +E156568849 = end-of-file marker +E156568850 = unexpected tape datablock +E156568851 = no label on tape +E156568852 = cannot position within the file +#----------------------------------------------------------- +# Error Codes for butx_errs +#----------------------------------------------------------- +E156571648 = Version 1 +E156571649 = XBSA couldn't mount shared library +E156571650 = XBSA handle already initialized +E156571651 = XBSA invalid serverType specified +E156571652 = XBSA invalid serverName specified +E156571653 = XBSA invalid bsaObjectOwner specified +E156571654 = XBSA invalid appObjectOwner specified +E156571655 = XBSA invalid secToken specified +E156571656 = XBSA invalid objectSpaceName specified +E156571657 = XBSA invalid pathName specified +E156571658 = XBSA invalid bufferSize specified +E156571659 = XBSA invalid dataBuffer specified +E156571660 = XBSA invalid lGName specified +E156571661 = XBSA invalid objectDescription specified +E156571662 = XBSA invalid objectInfo specified +E156571663 = XBSA version mismatch +E156571664 = XBSA unable to mount the XBSA library +E156571665 = XBSA initialization of the XBSA interface failed +E156571666 = XBSA begin transaction failed +E156571667 = XBSA has not been initialized, no handle +E156571668 = XBSA end transaction failed +E156571669 = XBSA terminate session failed +E156571670 = XBSA query object failed +E156571671 = XBSA get object failed +E156571672 = XBSA end data failed +E156571673 = XBSA create object failed +E156571674 = XBSA delete object failed +E156571675 = XBSA send data failed +E156571676 = XBSA get data failed +E156571677 = XBSA get environment failed +E156571678 = XBSA volume to delete not found +#----------------------------------------------------------- +# Error Codes for bucoord_errs +#----------------------------------------------------------- +E156288000 = Unacceptable user supplied argument +E156288001 = Object has been updated +E156288002 = Search matched more than one item +E156288003 = Can't allocate working memory +E156288004 = Can't get cell configuration information +E156288005 = Specified item already exists +E156288006 = Error in configuration parameters +E156288007 = No such volume set +E156288008 = No such volume entry +E156288009 = Volume set already exists +E156288010 = No such server +E156288011 = No such partition +E156288012 = Version number mismatch +E156288013 = Lock has not been acquired +E156288014 = Internal error +E156288015 = No such host/port entry +#----------------------------------------------------------- +# Error Codes for budb_errs +#----------------------------------------------------------- +E156303872 = dump with specified id already exists +E156303873 = no dump matching the id was found +E156303874 = no dump matching the name was found +E156303875 = no tape matching the name was found +E156303876 = no volume matching the name was found +E156303877 = entry doesn't exist +E156303878 = reference to a tape not being used +E156303879 = dump of database failed +E156303880 = access to database denied +E156303881 = incompatible version numbers +E156303882 = argument too long or out of range +E156303883 = sequence of operations incorrect +E156303884 = inconsistent or unsupported flags bit combination +E156303885 = requested list too large +E156303886 = index to iterator function is out of range +E156303887 = bad database block type +E156303888 = lock is not set +E156303889 = lock is held by another user +E156303890 = attempt to lock a lock already held +E156303891 = interface incompatible +E156303892 = Ubik I/O error +E156303893 = bad database address +E156303894 = backup database is inconsistent +E156303895 = internal error encountered in backup database server +E156303896 = error reading cell database +E156303897 = cell name not found +E156303898 = database empty or corrupted +E156303899 = Ubik ClientInit failed +E156303900 = couldn't allocate entry +E156303901 = can't allocate memory +E156303902 = dump is not an initial dump +E156303903 = reference to a dump not being used +#----------------------------------------------------------- +# Error Codes for cmd_errors +#----------------------------------------------------------- +E3359744 = More than the maximum number of parameters defined +E3359745 = Internal parsing error +E3359746 = Too many values specified after a CMD_SINGLE switch +E3359747 = Too many parameters specified +E3359748 = Impossibly few aguments specified +E3359749 = unrecognized or ambiguous command name +E3359750 = unrecognized or ambiguous switch name +E3359751 = +E3359752 = Insufficient required parameters provided +E3359753 = Token too large +#----------------------------------------------------------- +# Error Codes for test1 +#----------------------------------------------------------- +E11829760 = Can't read ticket file +E11829761 = Can't find ticket or TGT +E11829762 = TGT expired +E11829763 = Can't decode authenticator +E11829764 = Ticket expired +E11829765 = Repeated request +E11829766 = The ticket isn't for us +E11829767 = Request is inconsistent +E11829768 = Delta-T too big +E11829769 = Incorrect net address +E11829770 = Protocol version mismatch +E11829771 = Invalid message type +E11829772 = Message stream modified +E11829773 = Message out of order +E11829774 = Unauthorized request +E11829775 = Current password is null +E11829776 = Incorrect current password +E11829777 = Protocol error +E11829778 = Error returned by KDC +E11829779 = Null ticket returned by KDC +E11829780 = Retry count exceeded +E11829781 = Can't send request +#----------------------------------------------------------- +# Error Codes for test2 +#----------------------------------------------------------- +E1163220992 = foo +E1163220993 = bar +E1163220994 = meow +#----------------------------------------------------------- +# Error Codes for kaerrors +#----------------------------------------------------------- +E180480 = AuthServer database is inconsistent +E180481 = user already exists +E180482 = Ubik I/O error +E180483 = couldn't allocate entry +E180484 = user doesn't exist +E180485 = database empty or corrupted +E180486 = name or instance is too long or contains illegal characters +E180487 = bad index used internally +E180488 = caller not authorized +E180489 = answer packet too short for result +E180490 = password is incorrect +E180491 = interface incompatible +E180492 = argument out of range +E180493 = administrative command called incorrectly +E180494 = can't create session key +E180495 = can't read password from terminal +E180496 = illegal key: bad parity or weak +E180497 = Ubik ClientInit failed +E180498 = Ubik Call failed +E180499 = AuthServer returned incorrect response +E180500 = error reading cell database +E180501 = cell name not found +E180502 = too many Ubik security objects outstanding +E180503 = too many keys were passed to the server's security object +E180504 = authentication server was passed a bad ticket +E180505 = unknown key version number +E180506 = key cache invalidated by some key change +E180507 = may not issue ticket for server +E180508 = may not authenticate as this user +E180509 = may not change your key +E180510 = not allowed to create associate +E180511 = can't find suitable ticket +E180512 = operation not allowed for associate user +E180513 = not a special AuthServer principal +E180514 = server and client clocks are badly skewed +E180515 = not allowed to recursively call set_password from get_time +E180516 = Rx failed for some reason +E180517 = zero length password is illegal +E180518 = internal error encountered in kaserver +E180519 = password has expired (KAPWEXPIRED) +E180520 = it seems like a reused password (KAREUSED) +E180521 = you changed it too recently; see your systems administrator (KATOOSOON) +E180522 = ID is locked - see your system admin (KALOCKED) +#----------------------------------------------------------- +# Error Codes for afs_AdminBosErrors +#----------------------------------------------------------- +E16896 = the bos server name cannot be NULL +E16897 = the bos server handle cannot be NULL +E16898 = the bos server handle cannot be NULL +E16899 = the bos server handle failed to pass the magic number test. Most likely the server handle is invalid, or has been overwritten by mistake. +E16900 = the bos server handle is invalid +E16901 = the bos server handle does not reference a valid server +E16902 = unable to establish a connection with the specified bos server machine +E16903 = the process name cannot be NULL +E16904 = the process cannot be NULL +E16905 = the cron time cannot be NULL when creating a process of type cron +E16906 = the cron time must be NULL when creating a process of type fs or simple +E16907 = the process status cannot be NULL +E16908 = the process type cannot be NULL +E16909 = the process information cannot be NULL +E16910 = the parameter cannot be NULL +E16911 = the notifier cannot be NULL +E16912 = the administrator name cannot be NULL +E16913 = the key cannot be NULL +E16914 = the key cannot be NULL +E16915 = the host name cannot be NULL +E16916 = the source file cannot be NULL +E16917 = the destination file cannot be NULL +E16918 = the new time cannot be NULL +E16919 = the old time cannot be NULL +E16920 = the backup time cannot be NULL +E16921 = the restart time cannot be NULL +E16922 = the log name cannot be NULL +E16923 = the log buffer size cannot be NULL +E16924 = the log data buffer cannot be NULL +E16925 = the command cannot be NULL +E16926 = the auxiliary process status cannot be NULL +E16927 = the process status is invalid. You can only set a process state to BOS_PROCESS_STOPPED or BOS_PROCESS_RUNNING +E16928 = the process type retrieved from the bos server was invalid. +E16929 = the executable source file could not be opened for reading. +E16930 = unable to determine the size of the executable source file +E16931 = the executable source file could not be read. +E16932 = an error occurred transmitting the contents of the executable source file to the bos server. +E16933 = the executable source file cannot be NULL. +E16934 = the hour member of the time parameter must be between 0 and 23. +E16935 = the minute member of the time parameter must be between 0 and 60. +E16936 = the second member of the time parameter must be between 0 and 60. +E16937 = the day member of the time parameter must be between 0 and 6. +E16938 = unable to successfully read log file. +E16939 = the cell handle does not contain a valid token. +E16940 = the cell handle is not valid for vos requests. +E16941 = a parition must be specified when salvaging a volume . +E16942 = the log file could not be opened for writing. +E16943 = the resulting salvage command is too long to pass to the bos server. +E16944 = bos_ProcessCreate can't create fs processes, use bos_FSProcessCreate instead. +E16945 = the file server executable path cannot be NULL. +E16946 = the volume server executable path cannot be NULL. +E16947 = the salvager executable path cannot be NULL. +#----------------------------------------------------------- +# Error Codes for afs_AdminCfgErrors +#----------------------------------------------------------- +E17920 = the specified configuration option is not yet supported +E17921 = the host name parameter cannot be NULL +E17922 = the host name parameter exceeds the maximum allowed length +E17923 = the host handle reference parameter cannot be NULL +E17924 = the host handle parameter cannot be NULL +E17925 = the host handle parameter failed the magic number test; the handle is invalid or corrupted +E17926 = the host handle parameter is marked as invalid +E17927 = the host handle parameter contains a NULL host name reference +E17928 = the host handle parameter contains a NULL cell handle +E17929 = the host handle parameter contains a NULL cell name reference +E17930 = the administrator principal parameter cannot be NULL +E17931 = the administrator principal parameter exceeds the maximum allowed length +E17932 = the password parameter cannot be an empty string +E17933 = the configuration status reference parameter cannot be NULL +E17934 = the cell name reference parameter cannot be NULL +E17935 = the minimally required server configuration information is missing, unreadable, or invalid +E17936 = the server is not configured in any cell +E17937 = the server does not have any keys +E17938 = the server's cell is not listed in the server's cell database +E17939 = the server's cell database contains no database server entries for the server's cell +E17940 = the cell name parameter cannot be NULL +E17941 = the cell name parameter exceeds the maximum allowed length +E17942 = the cell name parameter conflicts with the cell name contained in the host handle parameter +E17943 = the database hosts parameter cannot be NULL +E17944 = the database hosts parameter contains too many host names +E17945 = unable to set the server cell information; most likely cause is an unknown database host name +E17946 = the bosserver process is currently running on the server host +E17947 = the vice partition table reference parameter cannot be NULL +E17948 = the vice partition table entry count reference parameter cannot be NULL +E17949 = unable to read the vice partition table +E17950 = the partition name parameter cannot be NULL +E17951 = the partition name parameter syntax is invalid +E17952 = the device name parameter cannot be NULL +E17953 = the device name parameter syntax is invalid +E17954 = the vice partition table entry is invalid +E17955 = unable to write to the vice partition table +E17956 = the valid flag reference parameter cannot be NULL +E17957 = the installed flag reference parameter cannot be NULL +E17958 = the version number reference parameter cannot be NULL +E17959 = the started flag reference parameter cannot be NULL +E17960 = the minimally required client configuration information is missing, unreadable, or invalid +E17961 = the client is not configured in any cell +E17962 = the client's cell is not listed in the client's cell database +E17963 = the client's cell database contains no database server entries for the client's cell +E17964 = unable to determine which version of the AFS client is installed +E17965 = unable to read the client's cell database +E17966 = unable to update the client's cell database +E17967 = the client's cell database contains the maximum number of entries for the specified cell; a new database host can not be added +E17968 = failed to edit client's cell database +E17969 = unable to set the client's current cell +E17970 = the AFS bosserver control service is not configured or is improperly configured +E17971 = the AFS bosserver control service is not prepared to accept a control request or is not responding +E17972 = timed out waiting for the AFS bosserver control service to start or stop +E17973 = cannot determine the status of the AFS bosserver control service +E17974 = failed to set or clear the AFS server authentication flag +E17975 = the bosserver-processes flag reference parameter cannot be NULL +E17976 = the database-servers-configured flag reference parameter cannot be NULL +E17977 = the fileserver-configured flag reference parameter cannot be NULL +E17978 = the upserver-configured flag reference parameter cannot be NULL +E17979 = the update client instance suffix cannot be NULL +E17980 = the update client instance suffix exceeds the maximum allowed length +E17981 = the update client's target server name cannot be NULL +E17982 = the update client's import directory list cannot be NULL +E17983 = the upclient-configured flag reference parameter cannot be NULL +E17984 = unable to establish a connection with the specified Ubik voting service on the specified host +E17985 = timed out waiting for one or more database servers to achieve quorum; common causes are time skew between database server machines and network connectivity problems +E17986 = the server's cell database contains too many database server entries +E17987 = the callback parameter cannot be NULL +E17988 = the update count reference parameter cannot be NULL +E17989 = the AFS server principal (afs) key can not be obtained from pre 3.5 database servers +E17990 = the specified AFS server principal (afs) password is invalid; the password generates a key that fails a checksum comparison with the current AFS server principal (afs) key +E17991 = the resolver is unable to retrieve host information from the default host database +E17992 = the specfied host name resolves to a fully qualified name that exceeds the maximum allowed length +E17993 = the AFS client service is not configured or is improperly configured +E17994 = the AFS client service is not prepared to accept a control request or is not responding +E17995 = timed out waiting for the AFS client service to start or stop +E17996 = cannot determine the status of the AFS client service +#----------------------------------------------------------- +# Error Codes for afs_AdminClientErrors +#----------------------------------------------------------- +E19456 = the cell handle parameter cannot be NULL +E19457 = the cell handle reference parameter cannot be NULL +E19458 = the server handle parameter failed to pass the magic number test. Most likely the server handle is invalid, or has been overwritten by mistake. +E19459 = the cell handle is not valid. +E19460 = the cell handle is not valid for authentication server requests +E19461 = the cell handle authentication server pointer is NULL +E19462 = the cell handle is not valid for protection server requests +E19463 = the cell handle protection server pointer is NULL +E19464 = the cell handle is not valid for volume server requests +E19465 = the cell handle volume server pointer is NULL +E19466 = the cell name parameter cannot be NULL +E19467 = the token handle parameter cannot be NULL +E19468 = the token handle is invalid +E19469 = the token handle parameter failed to pass the magic number test. Most likely the token handle is invalid, or has been overwritten by mistake +E19470 = failed to create a new client security object for the token handle +E19471 = unable to locate the location of AFS install +E19472 = unable to initialize the AFS rpc component +E19473 = unable to initialize the windows socket component +E19474 = afsclient_Init must be called before calling any other afsclient function +E19475 = an error occurred while trying to access the local client configuration information +E19476 = the token handle was marked as containing valid tokens, but the actual tokens were invalid +E19477 = the token handle must contain valid afs tokens for the cell +E19478 = the directory parameter cannot be NULL +E19479 = the volume name parameter cannot be NULL +E19480 = unable to determine the parent of the given directory +E19481 = the directory is not in AFS +E19482 = the server did not match any known AFS servers +E19483 = the rpc stat handle cannot be NULL +E19484 = the cell handle does not contain kas tokens +E19485 = there is no connection to the server +E19486 = the client stat handle cannot be NULL +E19487 = there is no connection to the client +E19488 = the cell name pointer cannot be NULL +E19489 = the client configuration pointer cannot be NULL +E19490 = the rxdebug handle cannot be NULL +E19491 = the rxdebug request timed out +E19492 = the rxdebug request is not supported +#----------------------------------------------------------- +# Error Codes for afs_AdminCommonErrors +#----------------------------------------------------------- +E17152 = couldn't allocate memory necessary to fulfill request +E17153 = insufficient privilege to complete operation +E17154 = failed to initialize a mutex +E17155 = failed to lock a mutex +E17156 = failed to unlock a mutex +E17157 = failed to destroy a mutex +E17158 = failed to initialize a condition variable +E17159 = failed to wait on a condition variable +E17160 = failed to destroy a condition variable +E17161 = failed to signal a condition variable +E17162 = failed to initialize a thread attribute +E17163 = failed to set thread detach state +E17164 = failed to create a thread +E17165 = failed to join a thread +E17166 = the iterator has been marked terminated (most likely by calling done). Next cannot be called after calling done. +E17167 = the iterator has been marked completed. +E17168 = the iterator parameter cannot be NULL. +E17169 = the rpc specific data parameter cannot be NULL. +E17170 = the iterator parameter failed to pass the magic number test. Most likely the iterator is invalid, or has been overwritten by mistake. +E17171 = the iterator parameter is marked invalid +E17172 = the iterator parameter cannot be NULL nor can it point to NULL +E17173 = the server name parameter cannot be NULL +E17174 = the server address parameter cannot be NULL +E17175 = the server name parameter cannot translated to an address +E17176 = unable to determine the name of the local host +E17177 = more data is available +E17178 = failed to create a socket +E17179 = the server type is invalid +#----------------------------------------------------------- +# Error Codes for afs_AdminKasErrors +#----------------------------------------------------------- +E19200 = the server handle parameter cannot be NULL +E19201 = the server handle parameter failed to pass the magic number test. Most likely the server handle is invalid, or has been overwritten by mistake. +E19202 = the server handle parameter is marked invalid +E19203 = the server handle parameter contains no servers +E19204 = the cell handle and the server handle parameter cannot both be NULL +E19205 = the cell handle and the server handle parameter cannot both be non-NULL +E19206 = the authentication server handle parameter cannot be NULL +E19207 = the from parameter cannot be NULL +E19208 = the to parameter cannot be NULL +E19209 = the server list parameter cannot be NULL +E19210 = the server list parameter contains too many servers +E19211 = the server handle parameter cannot be NULL nor can it point to NULL +E19212 = the who parameter cannot be NULL +E19213 = the password parameter cannot be NULL +E19214 = the authentication server parameter cannot be NULL +E19215 = the locked until parameter cannot be NULL +E19216 = the principal parameter cannot be NULL +E19217 = the key parameter cannot be NULL +E19218 = the lock end time parameter cannot be NULL +E19219 = the password expires parameter cannot be greater than 255 +E19220 = the failed password attempts parameter cannot be greater than 255 +E19221 = the failed password lock time parameter cannot be greater than 129600 +E19222 = the stats parameter cannot be NULL +E19223 = the debug parameter cannot be NULL +E19224 = the server list parameter didn't contain any servers +E19225 = at least one principal field to set must be specified +#----------------------------------------------------------- +# Error Codes for afs_AdminMiscErrors +#----------------------------------------------------------- +E19712 = the directory parameter cannot be NULL. +E19713 = the user parameter cannot be NULL. +E19714 = the acl parameter cannot be NULL. +E19715 = this interface does not support changing DFS acls. +#----------------------------------------------------------- +# Error Codes for afs_AdminPtsErrors +#----------------------------------------------------------- +E20480 = the protection server parameter cannot be NULL +E20481 = the user name parameter cannot be NULL +E20482 = the user name parameter is too long +E20483 = the group name parameter cannot be NULL +E20484 = the group name parameter is too long +E20485 = failed to translate a name to an identifier +E20486 = the new owner parameter cannot be NULL +E20487 = the new owner parameter is too long +E20488 = the new group parameter cannot be NULL +E20489 = the new group id parameter cannot be positive +E20490 = the target group parameter cannot be NULL +E20491 = the target group parameter is too long +E20492 = the group parameter cannot be NULL +E20493 = the group membership list is longer than the maximum retrievable +E20494 = the member name parameter cannot be NULL +E20495 = the old name parameter cannot be NULL +E20496 = the old name is too long +E20497 = the new name parameter cannot be NULL +E20498 = the new name is too long +E20499 = PTS_GROUP_ANYUSER_ACCESS is an invalid value for the list delete parameter +E20500 = PTS_GROUP_OWNER_ACCESS is an invalid value for the list groups owned parameter +E20501 = PTS_USER_ANYUSER_ACCESS is an invalid value for the list groups owned parameter +E20502 = the new entry parameter cannot be NULL +E20503 = the user parameter cannot be NULL +E20504 = the new group id parameter cannot be NULL +E20505 = the maximum group id parameter cannot be NULL +E20506 = the new user id parameter cannot be NULL +E20507 = the maximum user id parameter cannot be NULL +#----------------------------------------------------------- +# Error Codes for afs_AdminUtilErrors +#----------------------------------------------------------- +E21760 = the server entry parameter cannot be NULL +E21761 = the server name parameter cannot be NULL +E21762 = the server address parameter cannot be NULL +E21763 = the server address parameter cannot be NULL +E21764 = the server name parameter cannot translated to an address +E21765 = failed to open the client CellServDB file +E21766 = the error text parameter cannot be NULL +E21767 = the cell name parameter cannot be NULL +E21768 = the rx connection parameter cannot be NULL +E21769 = the rpc function parameter cannot be NULL +E21770 = the rpc stats parameter cannot be NULL +E21771 = the state parameter cannot be NULL +E21772 = the rpc version parameter cannot be NULL +E21773 = the rxdebug handle parameter cannot be null +E21774 = the rxdebug version parameter cannot be null +E21775 = the rxdebug stats parameter cannot be null +#----------------------------------------------------------- +# Error Codes for afs_AdminVosErrors +#----------------------------------------------------------- +E22016 = the volume server parameter cannot be NULL +E22017 = the cell handle parameter cannot be NULL +E22018 = the cell handle parameter failed to pass the magic number test. Most likely the cell handle is invalid, or has been overwritten by mistake. +E22019 = the cell handle parameter is marked as invalid. +E22020 = the cell handle parameter is marked as invalid for volume server requests. +E22021 = the cell handle does not contain valid AFS tokens. +E22022 = the volume identifier parameter must be a read write volume in order to make a backup volume. +E22023 = a backup volume already exists for volume identifier, but it exists on a server different from the one that holds volumeidentifier. +E22024 = the server handle parameter cannot be NULL +E22025 = the server handle parameter is marked as invalid +E22026 = the server handle parameter failed the magic number test. Most likely the server handle is invalid, or has been overwritten by mistake. +E22027 = a connection with the server could not be established. +E22028 = the partition parameter cannot be NULL +E22029 = the partition parameter is too large +E22030 = the volume name parameter is too long +E22031 = the volume name parameter cannot be NULL +E22032 = the volume name parameter cannot end with .readonly or .backup +E22033 = the volume identifier parameter cannot be NULL +E22034 = the volume identifier parameter cannot exceed VOLMAXPARTS +E22035 = the volume identifier does not exist on the specified server and partition +E22036 = the volume name is already in use. +E22037 = the partition name parameter cannot be NULL +E22038 = the partition name parameter must start with /vicep +E22039 = the partition name parameter is too long. +E22040 = the partition name parameter is too short. +E22041 = the partition name parameter must be all lower case letters. +E22042 = the partition identifier parameter cannot be NULL +E22043 = the resulting partition identifier exceeds VOLMAXPARTS +E22044 = the volume prefix parameter cannot be NULL when the exclude prefix is VOS_EXCLUDE +E22045 = the server address parameter cannot be NULL +E22046 = the server entry parameter cannot be NULL +E22047 = the server transaction status parameter cannot be NULL +E22048 = the vldb entry parameter cannot be NULL +E22049 = at least one of the arguments must not be null - server handle, partition, volume identifier. +E22050 = the new volume name parameter cannot be NULL +E22051 = both the server handle and the paritiion parameters must be specified. +E22052 = the dump file parameter cannot be NULL +E22053 = an error occurred while trying to write more data to the dump file +E22054 = an error occurred while trying to open dump file +E22055 = the volume to be restored exists on a server different from the one specified and you specified an incremental restore. If you wish to restore this volume, specify a full restore. +E22056 = an error occurred while trying open restore file +E22057 = an error occurred while trying close restore file +E22058 = an error occurred while trying read the restore file +E22059 = an error occurred while trying send the contents of the restore file +E22060 = the volume name is too big +E22061 = either the volume name or the volume identifier parameter must not be NULL +E22062 = the volume parameter cannot be NULL +E22063 = only read write volumes can be moved +E22064 = only read write volumes can be released +E22065 = only replicated volumes can be released +E22066 = unable to create a backup volume because no read write volume exists +E22067 = unable to create a backup volume because the vldb entry is invalid +E22068 = unable to get server's address from vldb +E22069 = skipping volume since read write is in a different location +E22070 = there were no entries in the vldb retrieved. +#----------------------------------------------------------- +# Error Codes for pterror +#----------------------------------------------------------- +E267264 = Entry for name already exists +E267265 = Entry for id already exists +E267266 = Couldn't allocate an id for this entry +E267267 = Couldn't read/write the database +E267268 = User or group doesn't exist +E267269 = Permission denied +E267270 = No group specified +E267271 = No user specified +E267272 = Badly formed name (group prefix doesn't match owner?) +E267273 = argument illegal or out of range +E267274 = may not create more groups +E267275 = database needs rebuilding +E267276 = can't make owner an empty group +E267277 = database is inconsistent +E267278 = bad database address +E267279 = too many elements in group +E267280 = malloc failed to alloc enough memory +#----------------------------------------------------------- +# Error Codes for stress_errs +#----------------------------------------------------------- +E19059456 = process created, not yet started +E19059457 = process running, no error +E19059458 = arguments illegal or inconsistent +E19059459 = incorrect input checksum +E19059460 = incorrect output checksum +E19059461 = unexpected number of bytes returned by rx_Read +E19059462 = unexpected number of bytes sent by rx_Write +E19059463 = connection unauthenticated +E19059464 = unknown key version number +E19059465 = incorrect client name/instance/cell +E19059466 = increment operation produced wrong value +E19059467 = clock on client and server too far apart +E19059468 = couldn't make a new connection +E19059469 = connection has unexpected call numbers +E19059470 = failed to detect duplicate call +E19059471 = failed to detect bad cksum +E19059472 = whole connection is not in error +E19059473 = idle connection is acting as a challenge oracle +#----------------------------------------------------------- +# Error Codes for rxkad_errs +#----------------------------------------------------------- +E19270400 = Security module structure inconsistent +E19270401 = Packet too short for security challenge +E19270402 = Security level negotiation failed +E19270403 = Ticket length too long or too short +E19270404 = packet had bad sequence number +E19270405 = caller not authorized +E19270406 = illegal key: bad parity or weak +E19270407 = security object was passed a bad ticket +E19270408 = ticket contained unknown key version number +E19270409 = authentication expired +E19270410 = sealed data inconsistent +E19270411 = user data too long +E19270412 = caller not authorized to use encrypted connections +#----------------------------------------------------------- +# Error Codes for uerrors +#----------------------------------------------------------- +E5376 = no quorum elected +E5377 = not synchronization site (should work on sync site) +E5378 = too many hosts +E5379 = I/O error writing dbase or log +E5380 = mysterious internal error +E5381 = major synchronization error +E5382 = file not found when processing dbase +E5383 = bad lock range size (must be 1) +E5384 = read error reprocessing log +E5385 = problems with host name +E5386 = bad operation for this transaction type +E5387 = two commits or aborts done to transaction +E5388 = operation done after abort (or commmit) +E5389 = no servers appear to be up +E5390 = premature EOF +E5391 = error writing log file +E5392 = unsupported address family -- bogus error +E5393 = inconsistent cell name -- bogus error +E5394 = security group bad or missing -- bogus error +E5395 = server group name bad or missing -- bogus error +E5396 = server uuid bad or missing -- bogus error +E5397 = memory allocation failure -- bogus error +E5398 = host not a member of server group -- bogus error +E5399 = too many bindings per server -- bogus error +E5400 = inconsistent principal name from binding -- bogus error +E5401 = I/O error in ubik pipe -- bogus error +E5402 = operation aborted to prevent dead lock (two sync sites?) +E5403 = rpc runtime exception caught -- bogus error +E5404 = vote thread pool queue operation failed -- bogus error +E5405 = clock skew among servers too high -- bogus error +E5406 = repeatedly failed to obtain ubik lock -- bogus error +E5407 = permission denied for attempted operation -- bogus error +E5408 = no space left on database device -- bogus error +E5409 = invalid DB pathname -- bogus error +E5410 = bad file descriptor -- bogus error +E5411 = Reinitialize called before initialize +E5412 = failed to initialize per client mutex +E5413 = failed to destroy per client mutex +#----------------------------------------------------------- +# Error Codes for vl_errors +#----------------------------------------------------------- +E363520 = Volume Id entry exists in vl database +E363521 = I/O related error +E363522 = Volume name entry exists in vl database +E363523 = Internal creation failure +E363524 = No such entry +E363525 = Vl database is empty +E363526 = Entry is deleted (soft delete) +E363527 = Volume name is illegal +E363528 = Index is out of range +E363529 = Bad volume type +E363530 = Illegal server number (out of range) +E363531 = Bad partition number +E363532 = Run out of space for Replication sites +E363533 = No such Replication server site exists +E363534 = Replication site already exists +E363535 = Parent R/W entry not found +E363536 = Illegal Reference Count number +E363537 = Vl size for attributes exceeded +E363538 = Bad incoming vl entry +E363539 = Illegal max volid increment +E363540 = RO/BACK id already hashed +E363541 = Vl entry is already locked +E363542 = Bad volume operation code +E363543 = Bad release lock type +E363544 = Status report: last release was aborted +E363545 = Invalid replication site server flag +E363546 = No permission access +E363547 = malloc(realloc) failed to alloc enough memory +E363548 = Wrong vldb version +E363549 = Index out of range +E363550 = Servers have the same ip address +E363551 = Illegal attribute mask value +#----------------------------------------------------------- +# Error Codes for volerr +#----------------------------------------------------------- +E1492325120 = internal error releasing transaction +E1492325121 = unknown internal error +E1492325122 = badly formatted dump +E1492325123 = badly formatted dump(2) +E1492325124 = could not attach volume +E1492325125 = illegal partition +E1492325126 = could not detach volume +E1492325127 = insufficient privilege for volume operation +E1492325128 = error from volume location database +E1492325129 = bad volume name +E1492325130 = volume moved +E1492325131 = illegal volume operation +E1492325132 = volume release failed +E1492325133 = volume still in use by volserver +E1492325134 = out of virtual memory in volserver +E1492325135 = no such volume +E1492325136 = more than one read/write volume +E1492325137 = failed volume server operation diff --git a/src/JAVA/classes/org/openafs/jafs/ACL.java b/src/JAVA/classes/org/openafs/jafs/ACL.java new file mode 100644 index 0000000..10b1b96 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/ACL.java @@ -0,0 +1,743 @@ +/* + * @(#)ACL.java 2.0 04/18/2001 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.StringTokenizer; + +/** + * An abstract representation of AFS file and directory pathnames. + * + * This class is an extension of the standard Java File class with file-based + * manipulation methods overridden by integrated AFS native methods. + * + * @version 2.0, 04/18/2001 - Completely revised class for efficiency. + */ + +public class ACL implements Serializable, Comparable +{ + private ACL.Entry[] positiveEntries; + private ACL.Entry[] negativeEntries; + + private String path; + + public ACL(String path) throws AFSException + { + int numberPositiveEntries = 0; + int numberNegativeEntries = 0; + ACL.Entry aclEntry; + String buffer; + + this.path = path; + + StringTokenizer st = new StringTokenizer(getACLString(path), "\n\t"); + + buffer = st.nextToken(); + numberPositiveEntries = new Integer(buffer).intValue(); + positiveEntries = new ACL.Entry[numberPositiveEntries]; + + buffer = st.nextToken(); + numberNegativeEntries = new Integer(buffer).intValue(); + negativeEntries = new ACL.Entry[numberNegativeEntries]; + + for(int i = 0; i < numberPositiveEntries; i++) + { + aclEntry = new ACL.Entry(); + aclEntry.setUser(st.nextToken()); + aclEntry.setPermissions(new Integer(st.nextToken()).intValue()); + positiveEntries[i] = aclEntry; + } + + for(int i = 0; i < numberNegativeEntries; i++) + { + aclEntry = new ACL.Entry(); + aclEntry.setUser(st.nextToken()); + aclEntry.setPermissions(new Integer(st.nextToken()).intValue()); + negativeEntries[i] = aclEntry; + } + } + public int getEntryCount() + { + return positiveEntries.length + positiveEntries.length; + } + public String getPath() + { + return path; + } + public ACL.Entry[] getPositiveEntries() + { + return positiveEntries; + } + public void addPositiveEntry(ACL.Entry entry) throws AFSException + { + int n = positiveEntries.length; + ACL.Entry[] e = new ACL.Entry[n + 1]; + System.arraycopy(positiveEntries, 0, e, 0, n); + e[n] = entry; + positiveEntries = e; + setACLString(path, getFormattedString()); + } + public void setPositiveEntries(ACL.Entry[] entries) throws AFSException + { + this.positiveEntries = entries; + setACLString(path, getFormattedString()); + } + public ACL.Entry[] getNegativeEntries() + { + return negativeEntries; + } + public void addNegativeEntry(ACL.Entry entry) throws AFSException + { + int n = negativeEntries.length; + ACL.Entry[] e = new ACL.Entry[n + 1]; + System.arraycopy(negativeEntries, 0, e, 0, n); + e[n] = entry; + negativeEntries = e; + setACLString(path, getFormattedString()); + } + public void setNegativeEntries(ACL.Entry[] entries) throws AFSException + { + this.negativeEntries = entries; + setACLString(path, getFormattedString()); + } + + public void flush() throws AFSException + { + setACLString(path, getFormattedString()); + } + + private ACL.Entry[] getNonEmptyEntries(ACL.Entry[] entries) + { + ArrayList response = new ArrayList(entries.length); + for (int i = 0; i < entries.length; i++) + { + boolean isNonEmpty = entries[i].canRead() || + entries[i].canLookup() || + entries[i].canWrite() || + entries[i].canInsert() || + entries[i].canDelete() || + entries[i].canLock() || + entries[i].canAdmin(); + if (isNonEmpty) response.add(entries[i]); + } + if (response.size() == entries.length) return entries; + return (ACL.Entry[])response.toArray(new ACL.Entry[response.size()]); + } + + private void entriesToString(ACL.Entry[] entries, StringBuffer response) + { + for (int i = 0; i < entries.length; i++) + { + this.entryToString((ACL.Entry)entries[i], response); + } + } + + private void entryToString(ACL.Entry entry, StringBuffer response) + { + response.append(entry.getUser() + '\t' + entry.getPermissionsMask() + '\n'); + } + + /** + * Returns a ViceIoctl formatted String representation of this + * ACL. + * + * @return a ViceIoctl formatted String representation of this + * ACL. + */ + private String getFormattedString() + { + StringBuffer out = null; + ACL.Entry[] nonEmptyPos = this.getNonEmptyEntries(this.getPositiveEntries()); + ACL.Entry[] nonEmptyNeg = this.getNonEmptyEntries(this.getNegativeEntries()); + + out = new StringBuffer(nonEmptyPos.length + "\n" + nonEmptyNeg.length + "\n"); + this.entriesToString(nonEmptyPos, out); + this.entriesToString(nonEmptyNeg, out); + + return out.toString(); + } + + /////////////// custom override methods //////////////////// + + /** + * Compares two ACL objects respective to their paths and does not + * factor any other attribute. Alphabetic case is significant in + * comparing names. + * + * @param acl The ACL object to be compared to this ACL + * instance + * + * @return Zero if the argument is equal to this ACL's path, a + * value less than zero if this ACL's path is + * lexicographically less than the argument, or a value greater + * than zero if this ACL's path is lexicographically + * greater than the argument + */ + public int compareTo(ACL acl) + { + return this.getPath().compareTo(acl.getPath()); + } + + /** + * Comparable interface method. + * + * @see #compareTo(ACL) + */ + public int compareTo(Object obj) + { + return compareTo((ACL)obj); + } + + /** + * Tests whether two ACL objects are equal, based on their + * paths and permission bits. + * + * @param acl the ACL to test + * @return whether the specifed ACL is the same as this ACL + */ + public boolean equals( ACL acl ) + { + return ( (this.getPath().equals(acl.getPath())) && + (positiveEntries.equals(acl.getPositiveEntries())) && + (negativeEntries.equals(acl.getNegativeEntries())) ); + } + + /** + * Returns a String representation of this ACL + * + * @return a String representation of this ACL + */ + public String toString() + { + ACL.Entry[] nonEmptyPos = this.getNonEmptyEntries(this.getPositiveEntries()); + ACL.Entry[] nonEmptyNeg = this.getNonEmptyEntries(this.getNegativeEntries()); + + StringBuffer out = new StringBuffer("ACL for "); + out.append(path); + out.append("\n"); + out.append("Positive Entries:\n"); + for (int i = 0; i < nonEmptyPos.length; i++) { + out.append(" "); + out.append(nonEmptyPos[i].toString()); + } + if (nonEmptyNeg.length > 0) { + out.append("Negative Entries:\n"); + for (int i = 0; i < nonEmptyNeg.length; i++) { + out.append(" "); + out.append(nonEmptyNeg[i].toString()); + } + } + + return out.toString(); + } + + /////////////// native methods //////////////////// + + /** + * Returns a formatted String representing the ACL for the specified path. + * + * The string format is in the form of a ViceIoctl and is as follows: + * printf("%d\n%d\n", positiveEntriesCount, negativeEntriesCount); + * printf("%s\t%d\n", userOrGroupName, rightsMask); + * + * @param path the directory path + * @returns a formatted String representing the ACL for the specified path. + * @throws an AFSException if an AFS or JNI exception is encountered. + */ + private native String getACLString(String path) throws AFSException; + + /** + * Sets the ACL in the file system according to this abstract representation. + * + * @param path the directory path + * @param aclString string representation of ACL to be set + * @throws an AFSException if an AFS or JNI exception is encountered. + */ + private native void setACLString(String path, String aclString) throws AFSException; + + /*====================================================================*/ + /* INNER CLASSES */ + /*====================================================================*/ + + /** + * AFS ACL Entry Class. + * + *

Documentation reference: + * Managing Access Control Lists + * + * @version 2.0, 04/18/2001 - Completely revised class for efficiency. + * @version 3.0, 05/01/2002 - Converted class to an inner class. + */ + public static final class Entry implements Serializable + { + /** ACL Mask read constant */ + public static final int READ = 1; + /** ACL Mask write constant */ + public static final int WRITE = 2; + /** ACL Mask insert constant */ + public static final int INSERT = 4; + /** ACL Mask lookup constant */ + public static final int LOOKUP = 8; + /** ACL Mask delete constant */ + public static final int DELETE = 16; + /** ACL Mask lock constant */ + public static final int LOCK = 32; + /** ACL Mask administer constant */ + public static final int ADMIN = 64; + + private String username; + + private boolean r = false; + private boolean l = false; + private boolean i = false; + private boolean d = false; + private boolean w = false; + private boolean k = false; + private boolean a = false; + + /** + * Constructs a new ACL entry with all permission bits set to false. + */ + public Entry() + { + } + /** + * Constructs a new ACL entry with all permission bits set to false + * and sets the associated user or group name. + * + * @param user The user or group name associated with this entry + */ + public Entry(String user) + { + this.setUser(user); + } + /** + * Constructs a new ACL entry setting each permission bit to its appropriate + * value according to the permissionsMask specified. + * + * @see #canRead + * @see #canWrite + * @see #canInsert + * @see #canLookup + * @see #canDelete + * @see #canLock + * @see #canAdmin + * @param permissionsMask An integer representation of the permissoin + * rights of this entry + */ + public Entry(int permissionsMask) + { + this.setPermissions(permissionsMask); + } + /** + * Constructs a new ACL entry setting each permission bit to its appropriate + * value according to the permissionsMask specified + * and sets the associated user or group name. + * + * @see #canRead + * @see #canWrite + * @see #canInsert + * @see #canLookup + * @see #canDelete + * @see #canLock + * @see #canAdmin + * @see #setUser + * @param permissionsMask An integer representation of the permissoin + * rights of this entry + * @param user The username or group associated with this entry + */ + public Entry(String user, int permissionsMask) + { + this.setUser(user); + this.setPermissions(permissionsMask); + } + /*-------------------------------------------------------------------------*/ + /** + * Set this entry's permission bits according to the value of the + * permissionsMask specified. + * + * @see #getPermissionsMask + * @param permissionsMask An integer representation of the permissoin + * rights of this entry + */ + public void setPermissions(int permissionsMask) + { + if ((permissionsMask & READ) != 0) { + this.setRead(true); + } + if ((permissionsMask & LOOKUP) != 0) { + this.setLookup(true); + } + if ((permissionsMask & INSERT) != 0) { + this.setInsert(true); + } + if ((permissionsMask & DELETE) != 0) { + this.setDelete(true); + } + if ((permissionsMask & WRITE) != 0) { + this.setWrite(true); + } + if ((permissionsMask & LOCK) != 0) { + this.setLock(true); + } + if ((permissionsMask & ADMIN) != 0) { + this.setAdmin(true); + } + } + /** + * Returns this entry's permission mask. + * + *

Permission Mask
+ * 01 - READ
+ * 02 - WRITE
+ * 04 - INSERT
+ * 08 - LOOKUP
+ * 16 - DELETE
+ * 32 - LOCK
+ * 64 - ADMIN
+ * + *

Any combination of the above mask values would equate to a valid combination of + * permission settings. For example, if the permission mask was 11, the ACL permissions + * would be as follows: read (1), write (2), and lookup (8).
+ * [1 + 2 + 8 = 11] + * + * @return An integer representation (mask) of the permissoin rights of this entry + */ + public int getPermissionsMask() + { + int permissionsMask = 0; + if (canRead()) permissionsMask |= READ; + if (canWrite()) permissionsMask |= WRITE; + if (canInsert()) permissionsMask |= INSERT; + if (canLookup()) permissionsMask |= LOOKUP; + if (canDelete()) permissionsMask |= DELETE; + if (canLock()) permissionsMask |= LOCK; + if (canAdmin()) permissionsMask |= ADMIN; + return permissionsMask; + } + /** + * Returns the user or group name associated with this ACL entry. + * + * @return String representation of the user or group name associated with this entry. + */ + public String getUser() + { + return username; + } + /** + * Sets the user or group name associated with this ACL entry. + * + * @param user representation of the user or group name associated with this entry. + */ + public void setUser(String user) + { + username = user; + } + /** + * File Permission Tests whether the ACL permits read access. + * + *

This permission enables a user to read the contents of files in the directory + * and to obtain complete status information for the files (read/retrieve the file + * attributes). + * + *

File Permission File Permission
+ * This permission is meaningful with respect to files in + * a directory, rather than the directory itself or its subdirectories. + * + *

Documentation reference: + * The AFS ACL Permissions + * + * @return true if and only if the ACL permits read access of + * files; false otherwise + */ + public boolean canRead() + { + return r; + } + /** + * Sets the ACL permission to accomodate read access for files. + * + * @see #canRead + * @param flag boolean flag that denotes the permission bit for read access. + */ + public void setRead(boolean flag) + { + r = flag; + } + /** + * Directory Permission Tests whether the ACL permits lookup access. + * + *

This permission functions as something of a gate keeper for access to the directory + * and its files, because a user must have it in order to exercise any other permissions. + * In particular, a user must have this permission to access anything in the directory's + * subdirectories, even if the ACL on a subdirectory grants extensive permissions. + * + *

This permission enables a user to list the names of the files and subdirectories in + * the directory (this does not permit read access to its respective entries), obtain + * complete status information for the directory element itself, and examine the directory's + * ACL. + * + *

This permission does not enable a user to read the contents of a file in the + * directory. + * + *

Similarly, this permission does not enable a user to lookup the contents of, + * obtain complete status information for, or examine the ACL of the subdirectory of + * the directory. Those operations require the lookup permission on the ACL + * of the subdirectory itself. + * + *

Directory Permission Directory Permission
+ * This permission is meaningful with respect to the + * directory itself. For example, the insert permission (see: {@link #canInsert}) + * does not control addition of data to a file, but rather creation of a new file or + * subdirectory. + * + *

Documentation reference: + * The AFS ACL Permissions + * + * @return true if and only if the ACL permits lookup access for + * directories; false otherwise + */ + public boolean canLookup() + { + return l; + } + /** + * Sets the ACL permission to accomodate lookup access for directories. + * + * @see #canLookup + * @param flag boolean flag that denotes the permission bit for lookup access. + */ + public void setLookup(boolean flag) + { + l = flag; + } + /** + * Directory Permission Tests whether the ACL permits insert access. + * + *

This permission enables a user to add new files to the directory, either by creating + * or copying, and to create new subdirectories. It does not extend into any subdirectories, + * which are protected by their own ACLs. + * + *

Directory Permission Directory Permission
+ * This permission is meaningful with respect to the + * directory itself. For example, the insert permission (see: {@link #canInsert}) + * does not control addition of data to a file, but rather creation of a new file or + * subdirectory. + * + *

Documentation reference: + * The AFS ACL Permissions + * + * @return true if and only if the ACL permits insert access for + * directories; false otherwise + */ + public boolean canInsert() + { + return i; + } + /** + * Sets the ACL permission to accomodate insert access for directories. + * + * @see #canInsert + * @param flag boolean flag that denotes the permission bit for insert access. + */ + public void setInsert(boolean flag) + { + i = flag; + } + /** + * Directory Permission Tests whether the ACL permits delete access. + * + *

This permission enables a user to remove files and subdirectories from the directory + * or move them into other directories (assuming that the user has the insert + * (see: {@link #canInsert}) permission on the ACL of the other directories). + * + *

Directory Permission Directory Permission
+ * This permission is meaningful with respect to the + * directory itself. For example, the insert permission (see: {@link #canInsert}) + * does not control addition of data to a file, but rather creation of a new file or + * subdirectory. + * + *

Documentation reference: + * The AFS ACL Permissions + * + * @return true if and only if the ACL permits delete access for + * directories; false otherwise + */ + public boolean canDelete() + { + return d; + } + /** + * Sets the ACL permission to accomodate delete access for directories. + * + * @see #canDelete + * @param flag boolean flag that denotes the permission bit for delete rights. + */ + public void setDelete(boolean flag) + { + d = flag; + } + /** + * File Permission Tests whether the ACL permits write access. + * + *

This permission enables a user to modify the contents of files in the directory + * and to change their operating system specific mode bits. + * + *

File Permission File Permission
+ * This permission is meaningful with respect to files in + * a directory, rather than the directory itself or its subdirectories. + * + *

Documentation reference: + * The AFS ACL Permissions + * + * @return true if and only if the ACL permits write access for + * files; false otherwise + */ + public boolean canWrite() + { + return w; + } + /** + * Sets the ACL permission to accomodate write access for files. + * + * @see #canWrite + * @param flag boolean flag that denotes the permission bit for write access. + */ + public void setWrite(boolean flag) + { + w = flag; + } + /** + * File Permission Tests whether the ACL permits the lock authority. + * + *

This permission enables the user to run programs that issue system calls to + * lock files in the directory. + * + *

File Permission File Permission
+ * This permission is meaningful with respect to files in + * a directory, rather than the directory itself or its subdirectories. + * + *

Documentation reference: + * The AFS ACL Permissions + * + * @return true if and only if the ACL permits lock authority for + * files; false otherwise + */ + public boolean canLock() + { + return k; + } + /** + * Sets the ACL permission to accomodate lock access for files. + * + * @see #canLock + * @param flag boolean flag that denotes the permission bit for lock rights. + */ + public void setLock(boolean flag) + { + k = flag; + } + /** + * Directory Permission Tests whether the ACL permits administer access. + * + *

This permission enables a user to change the directory's ACL. Members of the + * system:administrators group implicitly have this permission on every + * directory (that is, even if that group does not appear on the ACL). Similarly, the + * owner of a directory implicitly has this permission on its ACL and those of all + * directories below it that he or she owns. + * + *

Directory Permission Directory Permission
+ * This permission is meaningful with respect to the + * directory itself. For example, the insert permission (see: {@link #canInsert}) + * does not control addition of data to a file, but rather creation of a new file or + * subdirectory. + * + *

Documentation reference: + * The AFS ACL Permissions + * + * @return true if and only if the ACL permits administer access for + * directories; false otherwise + */ + public boolean canAdmin() + { + return a; + } + /** + * Sets the ACL permission to accomodate administer rights for directories. + * + * @see #canAdmin + * @param flag boolean flag that denotes the permission bit for administer rights. + */ + public void setAdmin(boolean flag) + { + a = flag; + } + + /////////////// custom override methods //////////////////// + + /** + * Tests whether two ACL.Entry objects are equal, based on associated + * username and permission bits. + * + * @param entry the ACL.Entry to test + * @return whether the specifed ACL.Entry is the same as this ACL.Entry + */ + public boolean equals( ACL.Entry entry ) + { + return ( (this.getUser().equals( entry.getUser() )) && + (this.getPermissionsMask() == entry.getPermissionsMask()) ); + } + + /** + * Returns a String representation of this ACL.Entry + * + * @return a String representation of this ACL.Entry + */ + public String toString() + { + StringBuffer out = new StringBuffer(username); + out.append("\t"); + if (r) out.append("r"); + if (l) out.append("l"); + if (i) out.append("i"); + if (d) out.append("d"); + if (w) out.append("w"); + if (k) out.append("k"); + if (a) out.append("a"); + out.append("\n"); + return out.toString(); + } + + } +} + + + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/AFSException.java b/src/JAVA/classes/org/openafs/jafs/AFSException.java new file mode 100644 index 0000000..a250f9a --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/AFSException.java @@ -0,0 +1,204 @@ +/* + * @(#)AFSException.java 2.0 01/04/16 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.Locale; + +/** + * An exception indicating that an error has occurred in the Java AFS + * API, in the Java AFS JNI, or in the AFS file system. + * + * @version 1.0, 04/16/2001 + * @see java.lang.Exception + */ +public class AFSException extends Exception +{ + /** + * The AFS specific error number (code). + * @see #getErrorCode() + */ + protected int errno; + + /** + * Constructs an AFSException with the specified detail + * message. + * + * @param reason the detail message. + */ + public AFSException(String reason) + { + super(reason); + } + /** + * Constructs an AFSException with the specified error code. + * This constructor will also generate the appropriate error message + * respective to the specified error code. + * + * @param errno the AFS error number (error code). + */ + public AFSException(int errno) + { + super(ErrorTable.getMessage( (errno == 0) ? ErrorTable.UNKNOWN : errno )); + this.errno = (errno == 0) ? ErrorTable.UNKNOWN : errno; + } + /** + * Constructs an AFSException with the specified detail message + * and specified error code. In this constructor the specified detail message + * overrides the default AFS error message defined by the + * ErrorTable class. Therefore, to retrieve the AFS specific + * error message, you must use the {@link #getAFSMessage} method. + * The {@link #getMessage} method will return the message specified + * in this constructor. + * + * @param reason the detail message. + * @param errno the AFS error number (error code). + */ + public AFSException(String reason, int errno) + { + super(reason); + this.errno = errno; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the AFS specific error number (code). This code can be interpreted + * by use of the {@link ErrorTable} class method + * {@link ErrorTable#getMessage(int)}. + * + * @return the AFS error code of this AFSException + * object. + * @see ErrorTable#getMessage(int) + */ + public int getErrorCode() + { + return errno; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the error message string of this exception. + * + * @return the error message string of this exception object. + * + * @see #getAFSMessage() + */ + public String getMessage() + { + String msg = super.getMessage(); + return (msg == null) ? ErrorTable.getMessage(errno) : msg; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the locale specific error message string of this exception. + * + * @return the error message string of this exception object. + * @param locale the locale for which this message will be displayed + * + * @see #getAFSMessage() + */ + public String getMessage(Locale locale) + { + String msg = super.getMessage(); + return (msg == null) ? ErrorTable.getMessage(errno, locale) : msg; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the AFS error message string defined by the ErrorTable + * class. The message will be formatted according to the default + * Locale. + * + *

This message is also available from this object's super class + * method getMessage. However, this method will always return + * the string message associated with the actual AFS error code/number + * specified, whereas the {@link #getMessage()} method will return the + * string message intended for this Exception object, which may be + * an overridden message defined in the constructor of this Exception. + * + * @return the AFS error message string of this exception object. + * + * @see #getAFSMessage(Locale) + * @see AFSException#AFSException(String, int) + * @see ErrorTable#getMessage(int) + * @see java.lang.Exception#getMessage() + */ + public String getAFSMessage() + { + return ErrorTable.getMessage(errno); + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the AFS error message defined by the ErrorTable + * class. The message will be formatted according to the specified Locale. + * + *

This message is also available from this object's super class + * method getMessage. However, this method will always return + * the string message associated with the actual AFS error code/number + * specified, whereas the {@link #getMessage()} method will return the + * string message intended for this Exception object, which may be + * an overridden message defined in the constructor of this Exception. + * + * @return the AFS error message string of this exception object. + * @param locale the locale for which this message will be displayed + * + * @see #getAFSMessage() + * @see AFSException#AFSException(String, int) + * @see ErrorTable#getMessage(int, Locale) + * @see java.lang.Exception#getMessage() + */ + public String getAFSMessage(Locale locale) + { + return ErrorTable.getMessage(errno, locale); + } + /*-----------------------------------------------------------------------*/ + /** + * Returns a string representation of this AFS Exception. + * + *

The message will be formatted according to the specified Locale. + * + * @return the AFS error message string of this exception object. + * + * @see #getAFSMessage() + * @see ErrorTable#getMessage(int) + * @see java.lang.Exception#getMessage() + */ + public String toString() + { + return "AFSException: Error Code: " + errno + "; Message: " + + getMessage(); + } + /*-----------------------------------------------------------------------*/ +} + + + + + + + + + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/AFSFileException.java b/src/JAVA/classes/org/openafs/jafs/AFSFileException.java new file mode 100644 index 0000000..3d6c398 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/AFSFileException.java @@ -0,0 +1,195 @@ +/* + * @(#)AFSFileException.java 2.0 01/04/16 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.Locale; + +/** + * An exception indicating that a file related error has occured in the + * Java AFS API, in the Java AFS JNI, or in the AFS file system. + * + *

This exception extends Java's java.io.IOException + * and is therefore often used as a substitution for + * {@link java.io.IOException}. + * + * @version 2.0, 04/16/2001 + * @version 1.0, 05/25/2000 + * @see AFSException + * @see java.io.IOException + */ +public class AFSFileException extends java.io.IOException +{ + /** + * The AFS specific error number (code). + * @see #getErrorCode() + */ + protected int errno; + + /** + * Constructs an AFSFileException with the specified detail + * message. + * + * @param reason the detail message. + */ + public AFSFileException (String reason) + { + super(reason); + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the AFS specific error number (code). This code can be interpreted + * by use of the {@link ErrorTable} class method + * {@link ErrorTable#getMessage(int)}. + * + * @return the AFS error code of this AFSException + * object. + * @see ErrorTable#getMessage(int) + */ + public int getErrorCode() + { + return errno; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the error message string of this exception. + * + * @return the error message string of this exception object. + * + * @see #getAFSMessage() + */ + public String getMessage() + { + String msg = super.getMessage(); + return (msg == null) ? ErrorTable.getMessage(errno) : msg; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the locale specific error message string of this exception. + * + * @return the error message string of this exception object. + * @param locale the locale for which this message will be displayed + * + * @see #getAFSMessage() + */ + public String getMessage(Locale locale) + { + String msg = super.getMessage(); + return (msg == null) ? ErrorTable.getMessage(errno, locale) : msg; + } + /** + * Constructs an AFSFileException with the specified error + * code. This constructor will also generate the appropriate error message + * respective to the specified error code. + * + * @param errno the AFS error number (error code). + */ + public AFSFileException (int errno) + { + super(ErrorTable.getMessage( (errno == 0) ? ErrorTable.UNKNOWN : errno )); + this.errno = (errno == 0) ? ErrorTable.UNKNOWN : errno; + } + /** + * Constructs an AFSFileException with the specified detail + * message and specified error code. In this constructor the specified + * detail message overrides the default AFS error message defined by the + * ErrorTable class. Therefore, to retrieve the AFS specific + * error message, you must use the {@link #getAFSMessage} + * method. The {@link #getMessage} method will return + * the message specified in this constructor. + * + * @param reason the detail message. + * @param errno the AFS error number (error code). + * @see #getAFSMessage() + */ + public AFSFileException (String reason, int errno) + { + super( (reason == null) ? ErrorTable.getMessage( errno ) : reason ); + this.errno = errno; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the AFS error message string defined by the ErrorTable + * class. The message will be formatted according to the default + * Locale. + * + *

This message is also available from this object's super class + * method getMessage. However, this method will always return + * the string message associated with the actual AFS error code/number + * specified, whereas the {@link #getMessage()} method will return the + * string message intended for this Exception object, which may be + * an overridden message defined in the constructor of this Exception. + * + * @return the AFS error message string of this exception object. + * + * @see #getAFSMessage(Locale) + * @see AFSFileException#AFSFileException(String, int) + * @see ErrorTable#getMessage(int) + * @see java.lang.Exception#getMessage() + */ + public String getAFSMessage() + { + return ErrorTable.getMessage(errno); + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the AFS error message defined by the ErrorTable + * class. The message will be formatted according to the specified Locale. + * + *

This message is also available from this object's super class + * method getMessage. However, this method will always return + * the string message associated with the actual AFS error code/number + * specified, whereas the {@link #getMessage()} method will return the + * string message intended for this Exception object, which may be + * an overridden message defined in the constructor of this Exception. + * + * @return the AFS error message string of this exception object. + * @param locale the locale for which this message will be displayed + * + * @see #getAFSMessage() + * @see AFSFileException#AFSFileException(String, int) + * @see ErrorTable#getMessage(int, Locale) + * @see java.lang.Exception#getMessage() + */ + public String getAFSMessage(Locale locale) + { + return ErrorTable.getMessage(errno, locale); + } + /*-----------------------------------------------------------------------*/ + /** + * Returns a string representation of this AFS Exception. + * + * @return the AFS error message string of this + * AFSFileException object. + * + * @see #getMessage() + */ + public String toString() + { + return "AFSFileException: Error Code: " + errno + "; Message: " + + getMessage(); + } + /*-----------------------------------------------------------------------*/ +} + + diff --git a/src/JAVA/classes/org/openafs/jafs/AFSSecurityException.java b/src/JAVA/classes/org/openafs/jafs/AFSSecurityException.java new file mode 100644 index 0000000..2aacb40 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/AFSSecurityException.java @@ -0,0 +1,202 @@ +/* + * @(#)AFSSecurityException.java 2.0 01/04/16 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.Locale; + +/** + * An exception indicating that a security related error has occured in the + * Java AFS API, in the Java AFS JNI, or in the AFS file system. + * + * @version 1.0, 04/16/2001 + * @see AFSException + */ +public class AFSSecurityException extends SecurityException +{ + /** + * The AFS specific error number (code). + * @see #getErrorCode() + */ + protected int errno; + + /** + * Constructs an AFSSecurityException with the specified detail + * message. + * + * @param reason the detail message. + */ + public AFSSecurityException (String reason) + { + super(reason); + } + /** + * Constructs an AFSSecurityException with the specified error + * code. This constructor will also generate the appropriate error message + * respective to the specified error code. + * + * @param errno the AFS error number (error code). + */ + public AFSSecurityException (int errno) + { + super(ErrorTable.getMessage( (errno == 0) ? ErrorTable.UNKNOWN : errno )); + this.errno = (errno == 0) ? ErrorTable.UNKNOWN : errno; + } + /** + * Constructs an AFSFileException with the specified detail + * message and specified error code. In this constructor the specified + * detail message overrides the default AFS error message defined by the + * ErrorTable class. Therefore, to retrieve the AFS specific + * error message, you must use the {@link #getAFSMessage} + * method. The {@link #getMessage} method will return + * the message specified in this constructor. + * + * @param reason the detail message. + * @param errno the AFS error number (error code). + * @see #getAFSMessage() + */ + public AFSSecurityException (String reason, int errno) + { + super( (reason == null) ? ErrorTable.getMessage( errno ) : reason ); + this.errno = errno; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the AFS specific error number (code). This code can be interpreted + * by use of the {@link ErrorTable} class method + * {@link ErrorTable#getMessage(int)}. + * + * @return the AFS error code of this AFSException + * object. + * @see ErrorTable#getMessage(int) + */ + public int getErrorCode() + { + return errno; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the error message string of this exception. + * + * @return the error message string of this exception object. + * + * @see #getAFSMessage() + */ + public String getMessage() + { + String msg = super.getMessage(); + return (msg == null) ? ErrorTable.getMessage(errno) : msg; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the locale specific error message string of this exception. + * + * @return the error message string of this exception object. + * @param locale the locale for which this message will be displayed + * + * @see #getAFSMessage() + */ + public String getMessage(Locale locale) + { + String msg = super.getMessage(); + return (msg == null) ? ErrorTable.getMessage(errno, locale) : msg; + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the AFS error message string defined by the ErrorTable + * class. The message will be formatted according to the default + * Locale. + * + *

This message is also available from this object's super class + * method getMessage. However, this method will always return + * the string message associated with the actual AFS error code/number + * specified, whereas the {@link #getMessage()} method will return the + * string message intended for this Exception object, which may be + * an overridden message defined in the constructor of this Exception. + * + * @return the AFS error message string of this exception object. + * + * @see #getAFSMessage(Locale) + * @see AFSSecurityException#AFSSecurityException(String, int) + * @see ErrorTable#getMessage(int) + * @see java.lang.Exception#getMessage() + */ + public String getAFSMessage() + { + return ErrorTable.getMessage(errno); + } + /*-----------------------------------------------------------------------*/ + /** + * Returns the AFS error message defined by the ErrorTable + * class. The message will be formatted according to the specified Locale. + * + *

This message is also available from this object's super class + * method getMessage. However, this method will always return + * the string message associated with the actual AFS error code/number + * specified, whereas the {@link #getMessage()} method will return the + * string message intended for this Exception object, which may be + * an overridden message defined in the constructor of this Exception. + * + * @return the AFS error message string of this exception object. + * @param locale the locale for which this message will be displayed + * + * @see #getAFSMessage() + * @see AFSSecurityException#AFSSecurityException(String, int) + * @see ErrorTable#getMessage(int, Locale) + * @see java.lang.Exception#getMessage() + */ + public String getAFSMessage(Locale locale) + { + return ErrorTable.getMessage(errno, locale); + } + /*-----------------------------------------------------------------------*/ + /** + * Returns a string representation of this AFS Exception. + * + * @return the AFS error message string of this + * AFSSecurityException object. + * + * @see #getMessage() + */ + public String toString() + { + return "AFSSecurityException: Error Code: " + errno + "; Message: " + + getMessage(); + } + /*-----------------------------------------------------------------------*/ +} + + + + + + + + + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/Cell.java b/src/JAVA/classes/org/openafs/jafs/Cell.java new file mode 100644 index 0000000..c723bd6 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/Cell.java @@ -0,0 +1,1874 @@ +/* + * @(#)Cell.java 1.0 6/29/2001 + * + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.ArrayList; +import java.util.GregorianCalendar; +import java.util.Date; + +/** + * An abstract representation of an AFS cell. It holds information about + * the cell, such as what users, groups, and servers exist in the cell. + *

+ * + * Constructing a Cell object does not mean a new cell is + * created in the AFS file system -- on the contrary, a Cell + * object must be a representation of an already existing AFS cell. There + * is no way to create a new AFS cell through this API. See + * OpenAFS.org for information on how + * to create a new cell.

+ * + * The construction of a Cell object acts as an entry point + * for authentication into the AFS system. Thus, when you construct a + * Cell, you must pass in an authenticated Token + * of a user in the AFS cell that the Cell represents. You + * will be authenticated as the user represented by token and + * you will only be allowed to perform actions that the user is + * authorized to perform. You must construct a Cell before + * attempting to construct any other object in this package, since the + * other objects all require a Cell object on construction, + * either directly or indirectly.

+ * + * Note that to successfully construct a Cell object, the + * code must be running on a machine with a running AFS client, and the + * cell this object is to represent must have an entry in the client's + * CellServDB file.

+ * + * Each Cell object has its own individual set of + * Servers, Users, and Groups. + * This represents the properties and attributes of an actual AFS cell. + * + * If an error occurs during a method call, an + * AFSException will be thrown. This class is the Java + * equivalent of errors thrown by AFS; see {@link AFSException} + * for a complete description.

+ * + * + * The following is a simple example of how to construct and use a + * Cell object. It shows how a Cell can be used to + * get an abstract representation of an AFS server, and how it can obtain an + * array of User objects, each of which is an abstract + * representation of an AFS user.

+ * + *

+ * import org.openafs.jafs.AFSException;
+ * import org.openafs.jafs.Cell;
+ * import org.openafs.jafs.Partition;
+ * import org.openafs.jafs.Server;
+ * import org.openafs.jafs.Token;
+ * import org.openafs.jafs.User;
+ * ...
+ * public class ...
+ * {
+ *   ...
+ *   private Cell cell;
+ *   private Server server;
+ *   private Token token;
+ *   ...
+ *   public static void main(String[] args) throws Exception
+ *   {
+ *     String username   = arg[0];
+ *     String password   = arg[1];
+ *     String cellName   = arg[2];
+ *     String serverName = arg[3];
+ * 
+ *     token = new Token(username, password, cellName);
+ *     cell   = new Cell(token);
+ *     server = cell.getServer(serverName);
+ *
+ *     User[] users = cell.getUsers();
+ *     ...
+ *   }
+ *   ...
+ * }
+ * 
+ * + */ +public class Cell implements java.io.Serializable +{ + protected ArrayList users; + protected ArrayList userNames; + protected ArrayList groups; + protected ArrayList groupNames; + protected ArrayList servers; + protected ArrayList serverNames; + + protected String name; + protected int cellHandle; + protected Token token; + + protected int maxGroupID; + protected int maxUserID; + + protected GregorianCalendar tokenExpiration; + + protected boolean cachedInfo; + + /** + * Constructs a new Cell object instance given + * the Token that should represents an authenticated user + * with administrative access. In order to get full access to the cell, + * it is best that the Token provided have administrative + * privileges. + * + * @param token the user's authenticated token + * @exception AFSException If an error occurs in the native code + */ + public Cell( Token token ) + throws AFSException + { + this.token = token; + this.name = token.getCellName(); + + cellHandle = getCellHandle( name, token.getHandle() ); + + users = null; + userNames = null; + groups = null; + groupNames = null; + servers = null; + serverNames = null; + cachedInfo = false; + tokenExpiration = null; + } + + /** + * Constructs a new Cell object instance given + * the Token that should represents an authenticated user + * with administrative access. In order to get full access to the cell, + * it is best that the Token provided have administrative + * privileges. + * + *

This constructor is ideal for point-in-time representation and + * transient applications. It ensures all data member values are set + * and available without calling back to the filesystem at the first + * request for them. Use the {@link #refresh()} method to address any + * coherency concerns. + * + * @param token the user's authenticated token + * @param preloadAllMembers true will ensure all object members are + * set upon construction; otherwise members + * will be set upon access, which is the default + * behavior. + * @exception AFSException If an error occurs in the native code + * @see #refresh + */ + public Cell( Token token, boolean preloadAllMembers ) + throws AFSException + { + this(token); + if (preloadAllMembers) refresh(true); + } + + /** + * Refreshes the properties of this Cell object instance with values + * from the AFS cell it represents. All properties that have been + * initialized and/or accessed will be renewed according to the values + * of the AFS cell this Cell object instance represents. + * + *

Since in most environments administrative changes can be administered + * from an AFS command-line program or an alternate GUI application, this + * method provides a means to refresh the Java object representation and + * thereby ascertain any possible modifications that may have been made + * from such alternate administrative programs. Using this method before + * an associated instance accessor will ensure the highest level of + * representative accuracy, accommodating changes made external to the + * Java application space. If administrative changes to the underlying AFS + * system are only allowed via this API, then the use of this method is + * unnecessary. + * + * @exception AFSException If an error occurs in the native code + */ + public void refresh() throws AFSException + { + this.refresh(false); + } + + /** + * Refreshes the properties of this Cell object instance with values + * from the AFS cell it represents. If all is true + * then all of the properties of this Cell object instance will be + * set, or renewed, according to the values of the AFS cell it represents, + * disregarding any previously set properties. + * + *

Thus, if all is false then properties that + * are currently set will be refreshed and properties that are not set will + * remain uninitialized. See {@link #refresh()} for more information. + * + * @param all if true set or renew all object properties; otherwise + * renew all set properties + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + protected void refresh(boolean all) throws AFSException + { + if( all || (users != null) ) { + refreshUsers(); + } + if( all || (userNames != null) ) { + refreshUserNames(); + } + if( all || (groups != null) ) { + refreshGroups(); + } + if( all || (groupNames != null) ) { + refreshGroupNames(); + } + if( all || (servers != null) ) { + refreshServers(); + } + if( all || (serverNames != null) ) { + refreshServerNames(); + } + if( all || cachedInfo ) { + refreshInfo(); + } + } + + /** + * Obtains the expiration time of the token being used by this + * Cell object. Does not actually refresh the token; that is, + * once a token is obtained, its expiration time will not change. This + * method is mostly for consistency with the other methods. It is mainly + * used for getting the token information once; after that, it need not + * be called again. + * + * @exception AFSException If an error occurs in the native code + */ + private void refreshTokenExpiration() throws AFSException + { + long expTime; + + expTime = token.getExpiration(); + + tokenExpiration = new GregorianCalendar(); + long longTime = expTime*1000; + Date d = new Date( longTime ); + tokenExpiration.setTime( d ); + } + + /** + * Sets all the information fields of this Cell object, + * such as max group and user ids, to trheir most current values. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshInfo() throws AFSException + { + maxGroupID = getMaxGroupID( cellHandle ); + maxUserID = getMaxUserID( cellHandle ); + cachedInfo = true; + } + + /** + * Obtains the most current list of User objects of this cell. + * Finds all users that currently have a kas and/or pts entry for this cell. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshUsers() throws AFSException + { + User currUser; + users = new ArrayList(); + + // get kas entries + int iterationId = getKasUsersBegin( cellHandle ); + + currUser = new User( this ); + boolean authorized = false; + int r = 1; + while( r != 0 ) { + try { + if (authorized) { + users.add( currUser ); + currUser = new User( this ); + } + r = getKasUsersNext( cellHandle, iterationId, currUser ); + authorized = true; + } catch (AFSException e) { + System.err.println("ERROR Cell::refreshUsers():kas (User: " + + currUser.getName() + ") -> " + e.getMessage()); + authorized = false; + //if (org.openafs.jafs.ErrorCodes.isPermissionDenied(e.getErrorCode())) + //r = 0; + } + } + getKasUsersDone( iterationId ); + + //take the union with the pts entries + iterationId = getPtsUsersBegin( cellHandle ); + authorized = false; + r = 1; + while( r != 0 ) { + try { + if (authorized) { + if( !users.contains( currUser ) ) { + users.add( currUser ); + } + currUser = new User( this ); + } + r = getPtsOnlyUsersNext( cellHandle, iterationId, currUser ); + authorized = true; + } catch (AFSException e) { + System.err.println("ERROR Cell::refreshUsers():pts (User: " + + currUser.getName() + ") -> " + e.getMessage()); + authorized = false; + //if (org.openafs.jafs.ErrorCodes.isPermissionDenied(e.getErrorCode())) + // r = 0; + } + } + getPtsUsersDone( iterationId ); + + } + + /** + * Obtains the most current list of user names of this cell. Finds + * all users that currently have a kas and/or pts entry for this cell. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshUserNames() throws AFSException + { + String currName; + userNames = new ArrayList(); + + // get kas entries + int iterationId = getKasUsersBegin( cellHandle ); + while( ( currName = getKasUsersNextString( iterationId )) != null ) { + userNames.add( currName ); + } + getKasUsersDone( iterationId ); + + //take the union with the pts entries + iterationId = Cell.getPtsUsersBegin( cellHandle ); + while( ( currName = getPtsOnlyUsersNextString( iterationId, cellHandle ) ) + != null ) { + if( !userNames.contains( currName ) ) { + userNames.add( currName ); + } + } + getPtsUsersDone( iterationId ); + } + + + /** + * Obtains the most current list of Group objects of this cell. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshGroups() throws AFSException + { + Group currGroup; + + int iterationId = getGroupsBegin( cellHandle ); + + groups = new ArrayList(); + + currGroup = new Group( this ); + boolean authorized = false; + int r = 1; + while( r != 0 ) { + try { + if (authorized) { + groups.add( currGroup ); + currGroup = new Group( this ); + } + r = getGroupsNext( cellHandle, iterationId, currGroup ); + authorized = true; + } catch (AFSException e) { + System.err.println("ERROR Cell::refreshGroups() (Group: " + + currGroup.getName() + ") -> " + e.getMessage()); + authorized = false; + //if (org.openafs.jafs.ErrorCodes.isPermissionDenied(e.getErrorCode())) + // r = 0; + } + } + Cell.getGroupsDone( iterationId ); + } + + /** + * Obtains the most current list of group names of this cell. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshGroupNames() throws AFSException + { + String currName; + + int iterationId = getGroupsBegin( cellHandle ); + + groupNames = new ArrayList(); + while( ( currName = getGroupsNextString( iterationId ) ) != null ) { + groupNames.add( currName ); + } + getGroupsDone( iterationId ); + } + + /** + * Obtains the most current list of Server objects of this cell. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshServers() throws AFSException + { + Server currServer; + + int iterationId = getServersBegin( cellHandle ); + + servers = new ArrayList(); + + currServer = new Server( this ); + boolean authorized = false; + int r = 1; + while( r != 0 ) { + try { + if (authorized) { + System.out.println("[Java] Cell::refreshServers() -> adding server: " + + currServer.getName()); + servers.add( currServer ); + currServer = new Server( this ); + } + r = getServersNext( cellHandle, iterationId, currServer ); +System.out.println("[Java] Cell::refreshServers() -> r: " + r); + authorized = true; + } catch (AFSException e) { + System.err.println("ERROR Cell::refreshServers() (Server: " + + currServer.getName() + ") -> " + e.getMessage()); + authorized = false; + //if (e.getErrorCode() == org.openafs.jafs.ErrorCodes.PERMISSION_DENIED) + // r = 0; + } + } + getServersDone( iterationId ); + } + + /** + * Obtains the most current list of server names of this cell. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshServerNames() + throws AFSException + { + String currName; + + int iterationId = getServersBegin( cellHandle ); + + serverNames = new ArrayList(); + while( ( currName = getServersNextString( iterationId ) ) != null ) { + serverNames.add( currName ); + } + getServersDone( iterationId ); + } + + /** + * Unauthenticates this Token object associated with this + * Cell and deletes all of its stored information. This + * method should only be called when this Cell or any of the + * objects constructed using this Cell will not be used + * anymore. Note that this does not delete the actual AFS cell that this + * Cell object represents; it merely closes the + * representation. + * + * @exception AFSException If an error occurs in the native code + */ + public void close() throws AFSException + { + Cell.closeCell( cellHandle ); + token.close(); + users = null; + userNames = null; + groups = null; + groupNames = null; + servers = null; + serverNames = null; + cachedInfo = false; + tokenExpiration = null; + } + + //////////////// ACCESSORS //////////////////////// + + /** + * Retrieves the User object (which is an abstract + * representation of an actual AFS user) designated by name. + * If a user by that name does not actually exist in AFS in the cell + * represented by this object, an {@link AFSException} will be + * thrown. + * + * @exception AFSException If an error occurs in the native code + * @exception NullPointerException If name is + * null. + * @param name the name of the user to retrieve + * @return User designated by name. + */ + public User getUser(String name) throws AFSException + { + if (name == null) throw new NullPointerException(); + User user = new User(name, this); + return user; + } + + /** + * Returns the total number of users who are registered with KAS and PTS, + * without duplicates. If a user has a KAS entry and not a PTS entry, + * it will still be counted. Conversely, if a user has a PTS entry and + * not KAS, it too will be counted. Effectively it is a non-duplicate + * union of KAS and PTS user entries. + * + *

If the total list of users or user names have already been + * collected (see {@link #getUsers()}), then the returning value will be + * calculated based upon the current list. Otherwise, KAS and PTS will be + * explicitly queried for the information. + * + * @exception AFSException If an error occurs in the native code + * @return a User array of the users of the cell. + * @see #getUsers() + * @see #getUserNames() + */ + public int getUserCount() throws AFSException + { + if( users != null ) { + return users.size(); + } else if( userNames != null ) { + return userNames.size(); + } else { + int k = getKasUserCount(cellHandle); + int p = getPtsOnlyUserCount(cellHandle); + return k + p; + } + } + + /** + * Retrieves an array containing all of the User objects + * associated with this Cell, each of which are an abstract + * representation of an actual user of the AFS cell. After this method + * is called once, it saves the array of Users and returns + * that saved array on subsequent calls, until the {@link #refresh()} method + * is called and a more current list is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return a User array of the users of the cell. + */ + public User[] getUsers() throws AFSException + { + if( users == null ) refreshUsers(); + return (User[]) users.toArray( new User[users.size()] ); + } + + /** + * Returns an array containing a subset of the User objects + * associated with this Cell, each of which is an abstract + * representation of an actual AFS user of the AFS cell. The subset + * is a point-in-time list of users (User objects + * representing AFS users) starting at the complete array's index of + * startIndex and containing up to length + * elements. + * + * If length is larger than the number of remaining elements, + * respective to startIndex, then this method will + * ignore the remaining positions requested by length and + * return an array that contains the remaining number of elements found in + * this cell's complete array of users. + * + *

This method is especially useful when managing iterations of very + * large lists. {@link #getUserCount()} can be used to determine if + * iteration management is practical. + * + *

This method does not save the resulting data and therefore + * queries AFS for each call. + * + *

Note: PTS-only users are collected before KAS users + * and therefore will always, if PTS-only users exist, be within the + * lowest range of this cell's complete list of users. PTS and KAS + * users are joined in a non-duplicating union and are consequently + * treated as a single list of users, thus startIndex + * does not necessarily indicate the first KAS user. + * + *

Example: If there are more than 50,000 users within this cell + * then only render them in increments of 10,000. + *

+   * ...
+   *   User[] users;
+   *   if (cell.getUserCount() > 50000) {
+   *     int index = 0;
+   *     int length = 10000;
+   *     while (index < cell.getUserCount()) {
+   *       users = cell.getUsers(index, length);
+   *       for (int i = 0; i < users.length; i++) {
+   *         ...
+   *       }
+   *       index += length;
+   *       ...
+   *     }
+   *   } else {
+   *     users = cell.getUsers();
+   *     for (int i = 0; i < users.length; i++) {
+   *       ...
+   *     }
+   *   }
+   * ...
+   * 
+ * + * @param startIndex the base zero index position at which the subset array + * should start from, relative to the complete list of + * elements present in AFS. + * @param length the number of elements that the subset should contain + * @return a subset array of users in this cell + * @exception AFSException If an error occurs in the native code + * @see #getUserCount() + * @see #getUserNames(int, int) + * @see #getUsers() + */ + public User[] getUsers(int startIndex, int length) throws AFSException + { + User[] users = new User[length]; + User currUser = new User( this ); + int ptsOnlyCount = getPtsOnlyUserCount(cellHandle); + int iterationID = 0; + int indexPTS = 0; + int indexKAS = 0; + + if (startIndex < ptsOnlyCount) { + int i = 0; + iterationID = getPtsUsersBegin(cellHandle); + while( getPtsOnlyUsersNext( cellHandle, iterationID, currUser ) != 0 && + indexPTS < length ) + { + if (i >= startIndex) { + users[indexPTS] = currUser; + currUser = new User( this ); + indexPTS++; + } + } + getPtsUsersDone( iterationID ); + + if (indexPTS < length) { + startIndex = 0; + length -= indexPTS; + } else { + return users; + } + } else { + startIndex -= (ptsOnlyCount - 1); + } + + iterationID = getKasUsersBeginAt( cellHandle, startIndex ); + while( getKasUsersNext(cellHandle, iterationID, currUser ) != 0 && + indexKAS < length ) + { + users[indexKAS] = currUser; + currUser = new User( this ); + indexKAS++; + } + getKasUsersDone( iterationID ); + + if (indexKAS < length) { + User[] u = new User[indexKAS + indexPTS]; + System.arraycopy(users, 0, u, 0, u.length); + return u; + } else { + return users; + } + } + + /** + * Retrieves an array containing all of the names of users + * associated with this Cell. After this method + * is called once, it saves the array of Strings and returns + * that saved array on subsequent calls, until the {@link #refresh()} method + * is called and a more current list is obtained. + * + *

This method is especially useful when managing iterations of + * large lists. {@link #getUserCount()} can be used to determine if + * iteration management is practical. In comparison to {@link #getUsers()}, + * this method has yielded an average performance advantage of approximately + * 82% at 10K users; this statistic, however, strictly compares the response + * time of each method and understands that the {@link #getUsers()} method + * will return an array of populated User objects, whereas this + * method will return an array of String names. + *

+ * + * @return an String array of the user names of the cell. + * @exception AFSException If an error occurs in the native code + */ + public String[] getUserNames() throws AFSException + { + if( userNames == null ) refreshUserNames(); + return (String[]) userNames.toArray( new String[userNames.size()] ); + } + + /** + * Returns an array containing a subset of the names of users + * associated with this Cell. The subset + * is a point-in-time list of users (String names + * of AFS users) starting at the complete array's index of + * startIndex and containing up to length + * elements. + * + * If length is larger than the number of remaining elements, + * respective to startIndex, then this method will + * ignore the remaining positions requested by length and + * return an array that contains the remaining number of elements found in + * this cell's complete array of users. + * + *

This method is especially useful when managing iterations of very + * large lists. {@link #getUserCount()} can be used to determine if + * iteration management is practical. + * + *

This method does not save the resulting data and therefore + * queries AFS for each call. + * + *

Note: PTS-only users are collected before KAS users + * and therefore will always, if PTS-only users exist, be within the + * lowest range of this cell's complete list of users. PTS and KAS + * users are joined in a non-duplicating union and are consequently + * treated as a single list of users, thus startIndex + * does not necessarily indicate the first KAS user. + * + *

Example: If there are more than 50,000 users within this cell + * then only render them in increments of 10,000. + *

+   * ...
+   *   String[] users;
+   *   if (cell.getUserCount() > 50000) {
+   *     int index = 0;
+   *     int length = 10000;
+   *     while (index < cell.getUserCount()) {
+   *       users = cell.getUserNames(index, length);
+   *       for (int i = 0; i < users.length; i++) {
+   *         ...
+   *       }
+   *       index += length;
+   *       ...
+   *     }
+   *   } else {
+   *     users = cell.getUserNames();
+   *     for (int i = 0; i < users.length; i++) {
+   *       ...
+   *     }
+   *   }
+   * ...
+   * 
+ * + * @param startIndex the base zero index position at which the subset array + * should start from, relative to the complete list of + * elements present in AFS. + * @param length the number of elements that the subset should contain + * @return a subset array of user names in this cell + * @exception AFSException If an error occurs in the native code + * @see #getUserCount() + * @see #getUserNames() + * @see #getUsers(int, int) + */ + public String[] getUserNames(int startIndex, int length) + throws AFSException + { + String[] users = new String[length]; + String currUser; + int ptsOnlyCount = getPtsOnlyUserCount(cellHandle); + int iterationID = 0; + int indexPTS = 0; + int indexKAS = 0; + + if (startIndex < ptsOnlyCount) { + int i = 0; + iterationID = getPtsUsersBegin(cellHandle); + while( (currUser = getPtsOnlyUsersNextString( iterationID, cellHandle )) + != null && indexPTS < length ) { + if (i >= startIndex) { + users[indexPTS] = currUser; + indexPTS++; + } + } + getPtsUsersDone( iterationID ); + + if (indexPTS < length) { + startIndex = 0; + length -= indexPTS; + } else { + return users; + } + } else { + startIndex -= (ptsOnlyCount - 1); + } + + iterationID = getKasUsersBeginAt( cellHandle, startIndex ); + while( (currUser = getKasUsersNextString( iterationID )) != null && + indexKAS < length ) { + users[indexKAS] = currUser; + indexKAS++; + } + getKasUsersDone( iterationID ); + + if (indexKAS < length) { + String[] u = new String[indexKAS + indexPTS]; + System.arraycopy(users, 0, u, 0, u.length); + return u; + } else { + return users; + } + } + + /** + * Retrieves the Group object (which is an abstract + * representation of an actual AFS group) designated by name. + * If a group by that name does not actually exist in AFS in the cell + * represented by this object, an {@link AFSException} will be + * thrown. + * + * @exception AFSException If an error occurs in the native code + * @exception NullPointerException If name is + * null. + * @param name the name of the group to retrieve + * @return Group designated by name. + */ + public Group getGroup(String name) throws AFSException + { + if (name == null) throw new NullPointerException(); + Group group = new Group(name, this); + group.refresh(true); + return group; + } + + /** + * Returns the total number of groups associated with this Cell. + * + *

If the total list of groups or group names have already been + * collected (see {@link #getGroups()}), then the returning value will be + * calculated based upon the current list. Otherwise, PTS will be + * explicitly queried for the information. + * + * @exception AFSException If an error occurs in the native code + * @return a User array of the users of the cell. + * @see #getGroups() + * @see #getGroupNames() + */ + public int getGroupCount() throws AFSException + { + if( groups != null ) { + return groups.size(); + } else if( groupNames != null ) { + return groupNames.size(); + } else { + return getGroupCount(cellHandle); + } + } + + /** + * Retrieves an array containing all of the Group objects + * associated with this Cell, each of which are an abstract + * representation of an actual group of the AFS cell. After this method + * is called once, it saves the array of Groups and returns + * that saved array on subsequent calls, until the {@link #refresh()} method + * is called and a more current list is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return a Group array of the groups of the cell. + */ + public Group[] getGroups() throws AFSException + { + if( groups == null ) refreshGroups(); + return (Group[]) groups.toArray( new Group[groups.size()] ); + } + + /** + * Returns an array containing a subset of the Group objects + * associated with this Cell, each of which is an abstract + * representation of an actual AFS group of the AFS cell. The subset + * is a point-in-time list of groups (Group objects + * representing AFS groups) starting at the complete array's index of + * startIndex and containing up to length + * elements. + * + * If length is larger than the number of remaining elements, + * respective to startIndex, then this method will + * ignore the remaining positions requested by length and + * return an array that contains the remaining number of elements found in + * this cell's complete array of groups. + * + *

This method is especially useful when managing iterations of very + * large lists. {@link #getGroupCount()} can be used to determine if + * iteration management is practical. + * + *

This method does not save the resulting data and therefore + * queries AFS for each call. + * + *

Example: If there are more than 50,000 groups within this cell + * then only render them in increments of 10,000. + *

+   * ...
+   *   Group[] groups;
+   *   if (cell.getGroupCount() > 50000) {
+   *     int index = 0;
+   *     int length = 10000;
+   *     while (index < cell.getGroupCount()) {
+   *       groups = cell.getGroups(index, length);
+   *       for (int i = 0; i < groups.length; i++) {
+   *         ...
+   *       }
+   *       index += length;
+   *       ...
+   *     }
+   *   } else {
+   *     groups = cell.getGroups();
+   *     for (int i = 0; i < groups.length; i++) {
+   *       ...
+   *     }
+   *   }
+   * ...
+   * 
+ * + * @param startIndex the base zero index position at which the subset array + * should start from, relative to the complete list of + * elements present in AFS. + * @param length the number of elements that the subset should contain + * @return a subset array of groups in this cell + * @exception AFSException If an error occurs in the native code + * @see #getGroupCount() + * @see #getGroupNames(int, int) + * @see #getGroups() + */ + public Group[] getGroups(int startIndex, int length) throws AFSException + { + Group[] groups = new Group[length]; + Group currGroup = new Group( this ); + int i = 0; + + int iterationID = getGroupsBeginAt( cellHandle, startIndex ); + + while( getGroupsNext( cellHandle, iterationID, currGroup ) != 0 + && i < length ) { + groups[i] = currGroup; + currGroup = new Group( this ); + i++; + } + getGroupsDone( iterationID ); + if (i < length) { + Group[] v = new Group[i]; + System.arraycopy(groups, 0, v, 0, i); + return v; + } else { + return groups; + } + } + + /** + * Retrieves an array containing all of the names of groups + * associated with this Cell. After this method + * is called once, it saves the array of Strings and returns + * that saved array on subsequent calls, until the {@link #refresh()} method + * is called and a more current list is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return a String array of the group names of the cell. + */ + public String[] getGroupNames() throws AFSException + { + if( groupNames == null ) refreshGroupNames(); + return (String[]) groupNames.toArray( new String[groupNames.size()] ); + } + + /** + * Returns an array containing a subset of the names of groups + * associated with this Cell. The subset + * is a point-in-time list of groups (String names + * of AFS groups) starting at the complete array's index of + * startIndex and containing up to length + * elements. + * + * If length is larger than the number of remaining elements, + * respective to startIndex, then this method will + * ignore the remaining positions requested by length and + * return an array that contains the remaining number of elements found in + * this cell's complete array of groups. + * + *

This method is especially useful when managing iterations of very + * large lists. {@link #getGroupCount()} can be used to determine if + * iteration management is practical. + * + *

This method does not save the resulting data and therefore + * queries AFS for each call. + * + *

Example: If there are more than 50,000 groups within this cell + * then only render them in increments of 10,000. + *

+   * ...
+   *   String[] groups;
+   *   if (cell.getGroupCount() > 50000) {
+   *     int index = 0;
+   *     int length = 10000;
+   *     while (index < cell.getGroupCount()) {
+   *       groups = cell.getGroupNames(index, length);
+   *       for (int i = 0; i < groups.length; i++) {
+   *         ...
+   *       }
+   *       index += length;
+   *       ...
+   *     }
+   *   } else {
+   *     groups = cell.getGroupNames();
+   *     for (int i = 0; i < groups.length; i++) {
+   *       ...
+   *     }
+   *   }
+   * ...
+   * 
+ * + * @param startIndex the base zero index position at which the subset array + * should start from, relative to the complete list of + * elements present in AFS. + * @param length the number of elements that the subset should contain + * @return a subset array of group names in this cell + * @exception AFSException If an error occurs in the native code + * @see #getGroupCount() + * @see #getGroups(int, int) + * @see #getGroupNames() + */ + public String[] getGroupNames(int startIndex, int length) + throws AFSException + { + String[] groups = new String[length]; + String currGroup; + int i = 0; + + int iterationID = getGroupsBeginAt( cellHandle, startIndex ); + + while( (currGroup = getGroupsNextString( iterationID )) != null && + i < length ) + { + groups[i] = currGroup; + i++; + } + getGroupsDone( iterationID ); + if (i < length) { + String[] v = new String[i]; + System.arraycopy(groups, 0, v, 0, i); + return v; + } else { + return groups; + } + } + + /** + * Retrieves the Server object (which is an abstract + * representation of an actual AFS server) designated by name. + * If a group by that name does not actually exist in AFS in the cell + * represented by this object, an {@link AFSException} will be + * thrown. + * + * @exception AFSException If an error occurs in the native code + * @exception NullPointerException If name is + * null. + * @param name the name of the server to retrieve + * @return Server designated by name. + */ + public Server getServer(String name) + throws AFSException + { + if (name == null) throw new NullPointerException(); + Server server = new Server(name, this); + server.refresh(true); + return server; + } + + /** + * Returns the total number of servers associated with this Cell. + * + *

If the total list of servers or server names have already been + * collected (see {@link #getServers()}), then the returning value will be + * calculated based upon the current list. Otherwise, AFS will be + * explicitly queried for the information. + * + * @exception AFSException If an error occurs in the native code + * @return a User array of the users of the cell. + * @see #getServers() + * @see #getServerNames() + */ + public int getServerCount() throws AFSException + { + if( servers != null ) { + return servers.size(); + } else if( serverNames != null ) { + return serverNames.size(); + } else { + return getServerCount(cellHandle); + } + } + + /** + * Retrieves an array containing all of the Server objects + * associated with this Cell, each of which are an abstract + * representation of an actual server of the AFS cell. After this method + * is called once, it saves the array of Servers and returns + * that saved array on subsequent calls, until the {@link #refresh()} method + * is called and a more current list is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return an Server array of the servers of the cell. + */ + public Server[] getServers() throws AFSException + { + if ( servers == null ) refreshServers(); + return (Server[]) servers.toArray( new Server[servers.size()] ); + } + + /** + * Retrieves an array containing all of the names of servers + * associated with this Cell. After this method + * is called once, it saves the array of Strings and returns + * that saved array on subsequent calls, until the {@link #refresh()} method + * is called and a more current list is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return a String array of the servers of the cell. + */ + public String[] getServerNames() throws AFSException + { + if ( serverNames == null ) refreshServerNames(); + return (String[]) serverNames.toArray( new String[serverNames.size()] ); + } + + /** + * Returns the maximum group ID that's been used within the cell. + * The next auto-assigned group ID will be one less (more negative) + * than this amount. After this method is called once, it saves the + * max group id and returns that id on subsequent calls, until the + * {@link #refresh()} method is called and a more current id is obtained. + * + * @return an integer representing the maximum group ID + * @exception AFSException If an error occurs in the native code + */ + public int getMaxGroupID() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return maxGroupID; + + } + + /** + * Returns the maximum user ID that's been used within the cell. + * The next auto-assigned user ID will be one greater (more positive) + * than this amount. After this method is called once, it saves the + * max user id and returns that id on subsequent calls, until the + * {@link #refresh()} method is called and a more current id is obtained. + * + * @return an integer representing the maximum user ID + * @exception AFSException If an error occurs in the native code + */ + public int getMaxUserID() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return maxUserID; + } + + /** + * Returns the expiration time of the authentication token being used + * by this Cell object. After this time, this + * Cell object will no longer be authorized to perform + * actions requiring administrative authority. + * + * @return expiration time of the token + * @exception AFSException If an error occurs in the native code + */ + public GregorianCalendar getTokenExpiration() throws AFSException + { + if( tokenExpiration == null ) refreshTokenExpiration(); + return tokenExpiration; + } + + /** + * Returns the cell handle of this cell. + * + * @return the cell handle + * @exception AFSException If an error occurs in the native code + */ + public int getCellHandle() throws AFSException + { + return cellHandle; + } + + /** + * Returns the name of this cell. + * + * @return the cell name + */ + public String getName() + { + return name; + } + + /** + * Sets the maximum group ID that's been used within the cell. The next + * auto-assigned group ID will be one less (more negative) than this amount. + * + * @param maxID an integer representing the maximum group ID + * @exception AFSException If an error occurs in the native code + */ + public void setMaxGroupID( int maxID ) throws AFSException + { + setMaxGroupID( cellHandle, maxID ); + maxGroupID = maxID; + } + + /** + * Sets the maximum user ID that's been used within the cell. The next + * auto-assigned user ID will be one greater (more positive) than this + * amount. + * + * @param maxID an integer representing the maximum user ID + * @exception AFSException If an error occurs in the native code + */ + public void setMaxUserID( int maxID ) throws AFSException + { + setMaxUserID( cellHandle, maxID ); + maxUserID = maxID; + } + + /////////////// information methods //////////////////// + + /** + * Returns a String representation of this Cell. + * Contains the cell name followed by the names of its users and groups. + * + * @return a String representation of this Cell + */ + protected String getInfo() + { + String r = "Cell: " + name + "\n\n"; + try { + r += "\tMax group ID: " + getMaxGroupID() + "\n"; + r += "\tMax user ID: " + getMaxUserID() + "\n"; + r += "\tToken expiration: " + getTokenExpiration().getTime() + "\n"; + } catch( AFSException e ) { + return e.toString(); + } + + String[] servs; + String[] usrs; + String[] grps; + try { + usrs = getUserNames(); + grps = getGroupNames(); + servs = getServerNames(); + + } catch( Exception e ) { + return e.toString(); + } + + r += "--Users--\n"; + + for( int i = 0; i < usrs.length; i++ ) { + + r += usrs[i] + "\n"; + } + + r += "\n--Groups--\n"; + + for( int i = 0; i < grps.length; i++ ) { + + r += grps[i] + "\n"; + } + + r += "\n--Servers--\n"; + + for( int i = 0; i < servs.length; i++ ) { + + r += servs[i] + "\n"; + } + + return r; + } + + /** + * Returns a String containing the String + * representations of all the users of this Cell. + * + * @return a String representation of the users + * @see User#getInfo + */ + protected String getInfoUsers() throws AFSException + { + String r; + + r = "Cell: " + name + "\n\n"; + r += "--Users--\n"; + + User usrs[] = getUsers(); + for( int i = 0; i < usrs.length; i++ ) { + r += usrs[i].getInfo() + "\n"; + } + + return r; + } + + /** + * Returns a String containing the String + * representations of all the groups of this Cell. + * + * @return a String representation of the groups + * @see Group#getInfo + */ + protected String getInfoGroups() throws AFSException + { + String r; + + r = "Cell: " + name + "\n\n"; + r += "--Groups--\n"; + + Group grps[] = getGroups(); + for( int i = 0; i < grps.length; i++ ) { + r += grps[i].getInfo() + "\n"; + } + return r; + } + + /** + * Returns a String containing the String + * representations of all the servers of this Cell. + * + * @return a String representation of the servers + * @see Server#getInfo + */ + protected String getInfoServers() + throws AFSException + { + String r; + r = "Cell: " + name + "\n\n"; + r += "--Servers--\n"; + Server[] servs = getServers(); + for( int i = 0; i < servs.length; i++ ) { + r += servs[i].getInfo() + "\n"; + } + return r; + } + + /////////////// override methods //////////////////// + + /** + * Tests whether two Cell objects are equal, based on their + * names. Does not test whether the objects are actually the same + * representational instance of the AFS cell. + * + * @param otherCell the Cell to test + * @return whether the specifed user is the same as this user + */ + public boolean equals( Cell otherCell ) + { + return name.equals( otherCell.getName() ); + } + + /** + * Returns the name of this Cell + * + * @return the name of this Cell + */ + public String toString() + { + return name; + } + + /////////////// native methods Cell //////////////////// + + /** + * Returns the total number of KAS users belonging to the cell denoted + * by cellHandle. + * + * @param cellHandle the handle of the cell to which the users belong + * @return total count of KAS users + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + */ + protected static native int getKasUserCount( int cellHandle ) + throws AFSException; + + /** + * Begin the process of getting the kas users that belong to the cell. + * Returns an iteration ID to be used by subsequent calls to + * getKasUsersNextString (or getKasUsersNext) + * and getKasUsersDone. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getKasUsersBegin( int cellHandle ) + throws AFSException; + + /** + * Begin the process of getting the KAS users, starting at + * startIndex, that belong to the cell. + * Returns an iteration ID to be used by subsequent calls to + * getKasUsersNextString (or getKasUsersNext) + * and getKasUsersDone. + * + * @param cellHandle the handle of the cell to which the users belong + * @param startIndex the starting base-zero index + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + */ + protected static native int getKasUsersBeginAt( int cellHandle, + int startIndex ) + throws AFSException; + + /** + * Returns the next kas user of the cell. Returns null if there + * are no more users. Appends instance names to principal names as follows: + * principal.instance + * + * @param iterationId the iteration ID of this iteration + * @see Cell#getKasUsersBegin + * @return the name of the next user of the cell + * @exception AFSException If an error occurs in the native code + */ + protected static native String getKasUsersNextString( int iterationId ) + throws AFSException; + + /** + * Fills the next kas user object of the cell. Returns 0 if there + * are no more users, != 0 otherwise. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @param iterationId the iteration ID of this iteration + * @see Cell#getKasUsersBegin + * @param theUser a User object to be populated with the values of + * the next kas user + * @return 0 if there are no more users, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getKasUsersNext( int cellHandle, + int iterationId, + User theUser ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see Cell#getKasUsersBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getKasUsersDone( int iterationId ) + throws AFSException; + + /** + * Returns the total number of PTS users belonging to the cell denoted + * by cellHandle. + * + * @param cellHandle the handle of the cell to which the users belong + * @return total number of PTS users + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + */ + protected static native int getPtsUserCount( int cellHandle ) + throws AFSException; + + /** + * Returns the total number of PTS users, belonging to the cell denoted + * by cellHandle, that are not in KAS. + * + * @param cellHandle the handle of the cell to which the users belong + * @return total number of users that are in PTS and not KAS + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + */ + protected static native int getPtsOnlyUserCount( int cellHandle ) + throws AFSException; + + /** + * Begin the process of getting the pts users that belong to the cell. + * Returns an iteration ID to be used by subsequent calls to + * getPtsUsersNextString (or getPtsUsersNext) + * and getPtsUsersDone. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getPtsUsersBegin( int cellHandle ) + throws AFSException; + + /** + * Returns the next pts user of the cell. Returns null if + * there are no more users. + * + * @param iterationId the iteration ID of this iteration + * @see Cell#getPtsUsersBegin + * @return the name of the next user of the cell + * @exception AFSException If an error occurs in the native code + */ + protected static native String getPtsUsersNextString( int iterationId ) + throws AFSException; + + /** + * Returns the next pts user (who is not a kas user) of the cell. + * Returns null if there are no more users. + * + * @param iterationId the iteration ID of this iteration + * @param cellHandle the cell handle to which these users will belong + * @see Cell#getPtsUsersBegin + * @return the name of the next pts user (not kas user) of the cell + * @exception AFSException If an error occurs in the native code + */ + protected static native String getPtsOnlyUsersNextString( int iterationId, + int cellHandle ) + throws AFSException; + + /** + * Fills the next pts user object of the cell. Returns 0 if there + * are no more users, != 0 otherwise. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @param iterationId the iteration ID of this iteration + * @see Cell#getPtsUsersBegin + * @param theUser a User object to be populated with the values of + * the next pts user + * @return 0 if there are no more users, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getPtsUsersNext( int cellHandle, int iterationId, + User theUser ) + throws AFSException; + + /** + * Fills the next pts user (who does not have a kas entry) object of + * the cell. Returns 0 if there are no more users, != 0 otherwise. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @param iterationId the iteration ID of this iteration + * @see Cell#getPtsUsersBegin + * @param theUser a User object to be populated with the values of + * the next pts (with no kas) user + * @return 0 if there are no more users, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getPtsOnlyUsersNext( int cellHandle, + int iterationId, + User theUser ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see Cell#getPtsUsersBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getPtsUsersDone( int iterationId ) + throws AFSException; + + /** + * Returns the total number of groups belonging to the cell denoted + * by cellHandle. + * + * @param cellHandle the handle of the cell to which the groups belong + * @return total number of groups + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + */ + protected static native int getGroupCount( int cellHandle ) + throws AFSException; + + /** + * Begin the process of getting the groups that belong to the cell. Returns + * an iteration ID to be used by subsequent calls to + * getGroupsNextString (or getGroupsNext) and + * getGroupsDone. + * + * @param cellHandle the handle of the cell to which the groups belong + * @see Cell#getCellHandle + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getGroupsBegin( int cellHandle ) + throws AFSException; + + /** + * Begin the process of getting the groups that belong to the cell, starting + * with element index startIndex. Returns an iteration ID to + * be used by subsequent calls to getGroupsNextString + * (or getGroupsNext) and getGroupsDone. + * + * @param cellHandle the handle of the cell to which the groups belong + * @param startIndex the starting base-zero index + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + */ + protected static native int getGroupsBeginAt( int cellHandle, + int startIndex ) + throws AFSException; + + /** + * Returns the next group of the cell. Returns null if there + * are no more groups. + * + * @param iterationId the iteration ID of this iteration + * @see Cell#getGroupsBegin + * @return the name of the next user of the cell + * @exception AFSException If an error occurs in the native code + */ + protected static native String getGroupsNextString( int iterationId ) + throws AFSException; + + /** + * Fills the next group object of the cell. Returns 0 if there + * are no more groups, != 0 otherwise. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @param iterationId the iteration ID of this iteration + * @see Cell#getGroupsBegin + * @param theGroup a Group object to be populated with the values of + * the next group + * @return 0 if there are no more users, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getGroupsNext( int cellHandle, int iterationId, + Group theGroup ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see Cell#getGroupsBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getGroupsDone( int iterationId ) + throws AFSException; + + /** + * Returns the total number of servers belonging to the cell denoted + * by cellHandle. + * + * @param cellHandle the handle of the cell to which the servers belong + * @return total number of servers + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + */ + protected static native int getServerCount( int cellHandle ) + throws AFSException; + + /** + * Begin the process of getting the servers in the cell. Returns + * an iteration ID to be used by subsequent calls to + * getServersNextString and getServersDone. + * + * @param cellHandle the handle of the cell to which the servers belong + * @see Cell#getCellHandle + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getServersBegin( int cellHandle ) + throws AFSException; + + /** + * Returns the next server of the cell. Returns null if there + * are no more servers. + * + * @param iterationId the iteration ID of this iteration + * @see Cell#getServersBegin + * @return the name of the next server of the cell + * @exception AFSException If an error occurs in the native code + */ + protected static native String getServersNextString( int iterationId ) + throws AFSException; + + /** + * Fills the next server object of the cell. Returns 0 if there are no + * more servers, != 0 otherwise. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @param iterationId the iteration ID of this iteration + * @param theServer a Server object to be populated with the values + * of the next server + * @see Cell#getServersBegin + * @return 0 if there are no more servers, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getServersNext( int cellHandle, int iterationId, + Server theServer ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see Cell#getServersBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getServersDone( int iterationId ) + throws AFSException; + + /** + * Returns the name of the cell. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @return the name of the cell + * @exception AFSException If an error occurs in the native code + */ + protected static native String getCellName( int cellHandle ) + throws AFSException; + + /** + * Creates a mount point for a volume within the file system. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param directory the full path of the place in the AFS file system + * at which to mount the volume + * @param volumeName the name of the volume to mount + * @param readWrite whether or not this is to be a readwrite mount point + * @param forceCheck whether or not to check if this volume name exists + * @exception AFSException If an error occurs in the native code + */ + protected static native void createMountPoint( int cellHandle, + String directory, + String volumeName, + boolean readWrite, + boolean forceCheck ) + throws AFSException; + + /* + * Sets an ACL for a given place in the AFS file system. + * + * @param directory the full path of the place in the AFS file system + * for which to add an entry + * @param username the name of the user or group for which to add an entry + * @param read whether or not to allow read access to this user + * @param write whether or not to allow write access to this user + * @param lookup whether or not to allow lookup access to this user + * @param delete whether or not to allow deletion access to this user + * @param insert whether or not to allow insertion access to this user + * @param lock whether or not to allow lock access to this user + * @param admin whether or not to allow admin access to this user + * @exception AFSException If an error occurs in the native code + */ + public static native void setACL( String directory, String username, + boolean read, boolean write, + boolean lookup, boolean delete, + boolean insert, boolean lock, + boolean admin ) + throws AFSException; + + /** + * Gets the maximum group pts ID that's been used within a cell. + * The next auto-assigned group ID will be one less (more negative) + * than this value. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @return an integer reresenting the max group id in a cell + * @exception AFSException If an error occurs in the native code + */ + protected static native int getMaxGroupID( int cellHandle ) + throws AFSException; + + /** + * Sets the maximum group pts ID that's been used within a cell. The next + * auto-assigned group ID will be one less (more negative) than this value. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @param maxID an integer reresenting the new max group id in a cell + * @exception AFSException If an error occurs in the native code + */ + protected static native void setMaxGroupID( int cellHandle, int maxID ) + throws AFSException; + + /** + * Gets the maximum user pts ID that's been used within a cell. + * The next auto-assigned user ID will be one greater (more positive) + * than this value. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @return an integer reresenting the max user id in a cell + * @exception AFSException If an error occurs in the native code + */ + protected static native int getMaxUserID( int cellHandle ) + throws AFSException; + + /** + * Sets the maximum user pts ID that's been used within a cell. The next + * auto-assigned user ID will be one greater (more positive) than this value. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param maxID an integer reresenting the new max user id in a cell + * @exception AFSException If an error occurs in the native code + */ + protected static native void setMaxUserID( int cellHandle, int maxID ) + throws AFSException; + + /** + * Reclaims all memory being saved by the cell portion of the native library. + * This method should be called when no more Cell objects + * are expected to be used. + */ + protected static native void reclaimCellMemory(); + + + /////////////// native methods jafs_Cell //////////////////// + + /** + * Opens a cell for administrative use, based on the token provided. + * Returns a cell handle to be used by other methods as a means of + * authentication. + * + * @param cellName the name of the cell for which to get the handle + * @param tokenHandle a token handle previously returned by a call to + * {@link Token#getHandle} + * @return a handle to the open cell + * @exception AFSException If an error occurs in the native code + * @see Token#getHandle + */ + protected static native int getCellHandle( String cellName, int tokenHandle ) + throws AFSException; + + /** + * Closes the given currently open cell handle. + * + * @param cellHandle the cell handle to close + * @exception AFSException If an error occurs in the native code + */ + protected static native void closeCell( int cellHandle ) + throws AFSException; +} + + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/ErrorTable.java b/src/JAVA/classes/org/openafs/jafs/ErrorTable.java new file mode 100644 index 0000000..431f51a --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/ErrorTable.java @@ -0,0 +1,203 @@ +/* + * @(#)ErrorTable.java 2.0 11/06/2000 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.ResourceBundle; +import java.util.Locale; + +/** + * Static class for error code message management. + * + *

Simply translates all error codes returned by the AFS native library + * to literal string messages according to the defined locale. + * + * @version 2.0, 11/06/2000 + */ +public final class ErrorTable +{ + /* Undefined Error Constants */ + public static final int UNKNOWN = -3; + public static final int SPECIAL_CASE = -2; + public static final int GENERAL_FAILURE = -1; + + /* Java Application Error Constants */ + public static final int NULL = 1000; + public static final int INVALID_SESSION = 1001; + public static final int EXPIRED_SESSION = 1002; + public static final int OPERATION_ABORTED = 1003; + public static final int FORCED_ABORT = 1004; + + /* General UNIX Error Constants */ + public static final int NOT_PERMITTED = 1; + public static final int NOT_FOUND = 2; + public static final int IO_ERROR = 5; + public static final int NO_DEVICE_ADDRESS = 6; + public static final int BAD_FILE = 9; + public static final int TRY_AGAIN = 11; + public static final int OUT_OF_MEMORY = 12; + public static final int PERMISSION_DENIED = 13; + public static final int BAD_ADDRESS = 14; + public static final int DEVICE_BUSY = 16; + public static final int FILE_EXISTS = 17; + public static final int NO_DEVICE = 19; + public static final int NOT_DIRECTORY = 20; + public static final int IS_DIRECTORY = 21; + public static final int INVALID_ARG = 22; + public static final int FILE_OVERFLOW = 23; + public static final int FILE_BUSY = 26; + public static final int NAME_TOO_LONG = 36; + public static final int DIRECTORY_NOT_EMPTY = 39; + public static final int CONNECTION_TIMED_OUT = 110; + public static final int QUOTA_EXCEEDED = 122; + + /* AFS Error Constants */ + public static final int BAD_USERNAME = 180486; + public static final int BAD_PASSWORD = 180490; + public static final int EXPIRED_PASSWORD = 180519; + public static final int SKEWED_CLOCK = 180514; + public static final int ID_LOCKED = 180522; + public static final int CELL_NOT_FOUND = 180501; + public static final int USERNAME_EXISTS = 180481; + public static final int USER_DOES_NOT_EXIST = 180484; + + /* AFS Authentication Error Constants */ + public static final int PRPERM = 267269; + public static final int UNOACCESS = 5407; + public static final int BZACCESS = 39430; + public static final int KANOAUTH = 180488; + public static final int RXKADNOAUTH = 19270405; + + private static java.util.Hashtable bundles; + + static + { + bundles = new java.util.Hashtable(2); + try { + bundles.put(Locale.US, + ResourceBundle.getBundle("ErrorMessages", Locale.US)); + bundles.put(Locale.SIMPLIFIED_CHINESE, + ResourceBundle.getBundle("ErrorMessages", Locale.SIMPLIFIED_CHINESE)); + } catch (Exception e) { + bundles.put(Locale.getDefault(), + ResourceBundle.getBundle("ErrorMessages")); + } + } + + /*-----------------------------------------------------------------------*/ + /** + * Tests to identify if the return code is a "Permission Denied" error. + * + *

This method will qualify errno against: + *

  • ErrorTable.PERMISSION_DENIED + *
  • ErrorTable.PRPERM + *
  • ErrorTable.UNOACCESS + *
  • ErrorTable.BZACCESS + *
  • ErrorTable.KANOAUTH + *
  • ErrorTable.RXKADNOAUTH + * + * @param errno Error Code/Number + * @return boolean If errno is a "Permission Denied" + * error. + */ + public static boolean isPermissionDenied(int errno) + { + return (errno == PERMISSION_DENIED || errno == PRPERM || + errno == UNOACCESS || errno == BZACCESS || errno == KANOAUTH + || errno == RXKADNOAUTH); + } + /*-----------------------------------------------------------------------*/ + /** + * Returns a String message representing the error code (number) provided. + * + *

    If the error code provided is out of range of the library of defined + * error codes, this method will return Error number [###] unknown + * . If an exception is thrown, this method will return either: + * Unknown error, Special case error, or + * Invalid error code: ###. + * + * @param errno Error Code/Number + * @return String Interpreted error message derived from + * errno. + */ + public static String getMessage(int errno) + { + return getMessage(errno, Locale.getDefault()); + } + /*-----------------------------------------------------------------------*/ + /** + * Returns a String message, respective to the provided locale, representing + * the error code (number) provided. + * + *

    If the error code provided is out of range of the library of defined + * error codes, this method will return Error number [###] unknown + * . If an exception is thrown, this method will return either: + * Unknown error, Special case error, or + * Invalid error code: ###. + * + * @param errno Error Code/Number + * @param locale Locale of to be used for translating the message. + * @return String Interpreted error message derived from + * errno. + */ + public static String getMessage(int errno, Locale locale) + { + String msg = "Error number [" + errno + "] unknown."; + try { + msg = getBundle(locale).getString("E" + errno); + } catch (Exception e) { + try { + if (errno == 0) { + msg = ""; + } else if (errno == GENERAL_FAILURE) { + msg = getBundle(locale).getString("GENERAL_FAILURE"); + } else if (errno == UNKNOWN) { + msg = getBundle(locale).getString("UNKNOWN"); + } else if (errno == SPECIAL_CASE) { + msg = getBundle(locale).getString("SPECIAL_CASE"); + } else { + System.err.println("ERROR in ErrorCode getMessage(): " + e); + msg = "Invaid error code: " + errno; + } + } catch (Exception e2) { + //INGORE + } + } finally { + return msg; + } + } + /*-----------------------------------------------------------------------*/ + private static ResourceBundle getBundle(Locale locale) throws Exception + { + if (locale == null) return getBundle(Locale.getDefault()); + ResourceBundle rb = (ResourceBundle)bundles.get(locale); + if (rb == null) { + rb = ResourceBundle.getBundle("ErrorMessages", locale); + bundles.put(locale, rb); + } + return rb; + } +} + + + diff --git a/src/JAVA/classes/org/openafs/jafs/File.java b/src/JAVA/classes/org/openafs/jafs/File.java new file mode 100644 index 0000000..fe58b2c --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/File.java @@ -0,0 +1,942 @@ +/* + * @(#)File.java 1.3 10/12/2000 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.io.IOException; +import java.util.ArrayList; + +/*****************************************************************************/ +/** + * + * An abstract representation of AFS file and directory pathnames. + * + * This class is an extension of the standard Java File class with file-based + * manipulation methods overridden by integrated AFS native methods. + * + *

    Extension methods include: + * + *

      + *
    1. {@link #isMountPoint} + *
    2. {@link #isLink} + *
    3. {@link #isValidated} + *
    4. {@link #validate} + *
    5. {@link #refresh} + *
    6. {@link #getErrorCode} + *
    7. {@link #getErrorMessage} + *
    + * + *

    For performance optimization, all newly constructed File + * objects are only validated once. Furthermore, if an abstract pathname + * denotes a symbolic-link, then the {@link #isLink} attribute is set + * to true and the {@link #getTarget} field member is populated with + * this symbolic-link's target resource. (see {@link #getTarget}) + * + *

    If you are interested in validating the target resource, simply + * call {@link #validate} before calling any of the attribute accessors. + * This action will stat the target resource, identifying + * its associated attributes and populating them in this objects field + * members. + * + *

    Following is an example of how to construct a new AFS File Object: + *

    + *     try {
    + *         File file = new File("/afs/mycell.com/proj/");
    + *         if (file.isDirectory()) {
    + *           System.out.println("This is a directory.");
    + *         } else if (file.isLink()) {
    + *           System.out.println("This is a symbolic-link.");
    + *           System.out.println("  Its target is: " + file.getTarget());
    + *           file.validate();
    + *           if (file.isFile()) {
    + *             System.out.println("  This object is now a file!");
    + *           } else if (file.isDirectory()) {
    + *             System.out.println("  This object is now a directory!");
    + *           } else if (file.isMountPoint()) {
    + *             System.out.println("  This object is now a volume mount point!");
    + *           }
    + *         } else if (file.isMountPoint()) {
    + *           System.out.println("This is a volume mount point.");
    + *         } else if (file.isFile()) {
    + *           System.out.println("This is file.");
    + *           System.out.println("  its size is: " + file.length());
    + *         }
    + *     } catch (AFSFileException ae) {
    + *         System.out.println("AFS Exception: " + ae.getMessage());
    + *         System.out.println("AFS Error Code: " + ae.getErrorCode());
    + *     } catch (Exception e) {
    + *         System.out.println("Exception: " + e.getMessage());
    + *         e.printStackTrace();
    + *     }
    + * 
    + * + * @version 2.0, 04/16/2001 - Completely revised class for efficiency. + * @version 1.3, 10/12/2000 - Introduced error code capture from native methods. + * @version 1.2, 05/30/2000 + */ +public class File extends java.io.File implements Comparable +{ + private String path; + private String type; + private String target; + + /** Each member is mutually exclusive */ + private boolean isMountPoint = false; + private boolean isDirectory = false; + private boolean isFile = false; + private boolean isLink = false; + + private boolean exists; + private long lastModified; + private long length; + + private ACL.Entry acl; + private boolean validated = false; + private long dirHandle; + private int permissionsMask; + private int errno; + + /** + * Creates a new File instance by converting the given + * pathname string into an abstract pathname and validating it against + * the file system. If the given string is an empty string, then the + * result is the empty abstract pathname; otherwise the abstract pathname + * is validated to represent a qualified file object. + * + * @param pathname A pathname string + * @throws NullPointerException + * If the pathname argument is null + * @throws AFSFileException + * If the user constructing this AFS file object is denied + * access to stat the file or simply a stat cannot be performed + * on the file. The reason code and message will be available + * from {@link org.openafs.jafs.AFSFileException#getErrorCode} and + * {@link org.openafs.jafs.AFSFileException#getMessage} respectively. + *

    This exception will not be thrown if the file does not + * exist. Rather, the {@link #exists} attribute will be set to + * false. + * @see #validate() + */ + public File(String pathname) throws AFSFileException + { + super(pathname); + path = getAbsolutePath(); + validated = setAttributes(); + if (!validated) throw new AFSFileException(errno); + } + /** + * Creates a new File instance by converting the given + * pathname string into an abstract pathname. If the given string is + * an empty string, then the result is the empty abstract pathname. + * + *

    The abstract pathname will remain abstract unless the + * validate parameter is set to true. This + * means that the abstract pathname will not be validated + * and therefore the file object will not represent a qualified, attributed, + * AFS file resource. Rather, this constructor provides a method by which + * you can construct a non-validated File object (one that + * does not contain the file's complete status information). + * + *

    This constructor is useful for creating file objects of file/path names + * that you know exist, however are unauthorized to validate (or + * stat - to obtain complete status information). For example, + * if you are permitted to lookup (see: {@link #canLookup}) the + * contents of a given directory yet not permitted to read + * (see: {@link #canRead}), then this constructor would enable you to render the + * contents of the directory without validating each entry. + * + *

    Please note: this is the only constructor that does not throw an AFSFileException. + * + * @param pathname A pathname string + * @param validate A boolean flag to indicate if this abstract path + * should be validated. + * @throws NullPointerException + * If the pathname argument is null + * @see #File(String) + * @see #validate() + */ + public File(String pathname, boolean validate) + { + super(pathname); + path = getAbsolutePath(); + if (validate) validated = setAttributes(); + } + /** + * Creates a new File instance from a parent pathname string + * and a child pathname string and validates it against the file system. + * + *

    If parent is null then the new + * File instance is created as if by invoking the + * single-argument File constructor on the given + * filename string (child pathname). + * + *

    Otherwise the parent pathname string is taken to denote + * a directory, and the filename string is taken to + * denote either a directory or a file. The directory or file will then be + * validated to represent a qualified file object. + * + * @param parent The parent pathname string + * @param filename This file's pathname string (child of specified parent) + * @throws NullPointerException + * If child is null + * @throws AFSFileException + * If the user constructing this AFS file object is denied + * access to stat the file or simply a stat cannot be performed + * on the file. The reason code and message will be available + * from {@link org.openafs.jafs.AFSFileException#getErrorCode} and + * {@link org.openafs.jafs.AFSFileException#getMessage} respectively. + *

    This exception will not be thrown if the file does not + * exist. Rather, the {@link #exists} attribute will be set to + * false. + * @see #validate() + */ + public File(String parent, String filename) throws AFSFileException + { + super(parent, filename); + path = getAbsolutePath(); + validated = setAttributes(); + if (!validated) throw new AFSFileException(errno); + } + /** + * Creates a new File instance from a parent pathname string + * and a child pathname string. + * + *

    If parent is null then the new + * File instance is created as if by invoking the + * single-argument File constructor on the given + * filename string (child pathname). + * + *

    Otherwise the parent pathname string is taken to denote + * a directory, and the filename string is taken to + * denote either a directory or a file. + * + *

    The abstract pathname will remain abstract unless the + * validate parameter is set to true. This + * means that the abstract pathname will not be validated + * and therefore the file object will not represent a qualified, attributed, + * AFS file resource. Rather, this constructor provides a method by which + * you can construct a non-validated File object (one that + * does not contain the file's complete status information). + * + *

    This constructor is useful for creating file objects of file/path names + * that you know exist, however are unauthorized to validate (or + * stat - to obtain complete status information). For example, + * if you are permitted to lookup (see: {@link #canLookup}) the + * contents of a given directory yet not permitted to read + * (see: {@link #canRead}), then this constructor would enable you to render the + * contents of the directory without validating each entry. + * + * @param parent The parent pathname string + * @param filename This file's pathname string (child of specified parent) + * @param validate A boolean flag to indicate if this abstract path + * should be validated. + * @throws NullPointerException + * If child is null + * @throws AFSFileException + * If the user constructing this AFS file object is denied + * access to stat the file or simply a stat cannot be performed + * on the file. The reason code and message will be available + * from {@link org.openafs.jafs.AFSFileException#getErrorCode} and + * {@link org.openafs.jafs.AFSFileException#getMessage} respectively. + *

    This exception will not be thrown if the file does not + * exist. Rather, the {@link #exists} attribute will be set to + * false. + * @see #File(String, String) + * @see #validate() + */ + public File(String parent, String filename, boolean validate) throws AFSFileException + { + super(parent, filename); + path = getAbsolutePath(); + if (validate) { + validated = setAttributes(); + if (!validated) throw new AFSFileException(errno); + } + } + /** + * Creates a new File instance from a parent abstract + * pathname and a child pathname string and validates it against the file system. + * + *

    If parent is null then the new + * File instance is created as if by invoking the + * single-argument File constructor on the given + * filename string (child pathname). + * + *

    Otherwise the parent abstract pathname is taken to + * denote a directory, and the filename string is taken + * to denote either a directory or a file. The directory or file will then be + * validated to represent a qualified file object. + * + * @param parent The parent abstract pathname + * @param filename This file's pathname string (child of specified parent) + * @param validate A boolean flag to indicate if this abstract path + * should be validated. + * @throws NullPointerException + * If child is null + * @throws AFSFileException + * If the user constructing this AFS file object is denied + * access to stat the file or simply a stat cannot be performed + * on the file. The reason code and message will be available + * from {@link org.openafs.jafs.AFSFileException#getErrorCode} and + * {@link org.openafs.jafs.AFSFileException#getMessage} respectively. + *

    This exception will not be thrown if the file does not + * exist. Rather, the {@link #exists} attribute will be set to + * false. + * @see #validate() + */ + public File(File parent, String filename) throws AFSFileException + { + super(parent, filename); + path = getAbsolutePath(); + validated = setAttributes(); + if (!validated) throw new AFSFileException(errno); + } + /** + * Creates a new File instance from a parent abstract + * pathname and a child pathname string. + * + *

    If parent is null then the new + * File instance is created as if by invoking the + * single-argument File constructor on the given + * filename string (child pathname). + * + *

    Otherwise the parent abstract pathname is taken to + * denote a directory, and the filename string is taken + * to denote either a directory or a file. + * + *

    The abstract pathname will remain abstract unless the + * validate parameter is set to true. This + * means that the abstract pathname will not be validated + * and therefore the file object will not represent a qualified, attributed, + * AFS file resource. Rather, this constructor provides a method by which + * you can construct a non-validated File object (one that + * does not contain the file's complete status information). + * + *

    This constructor is useful for creating file objects of file/path names + * that you know exist, however are unauthorized to validate (or + * stat - to obtain complete status information). For example, + * if you are permitted to lookup (see: {@link #canLookup}) the + * contents of a given directory yet not permitted to read + * (see: {@link #canRead}), then this constructor would enable you to render the + * contents of the directory without validating each entry. + * + * @param parent The parent abstract pathname + * @param filename This file's pathname string (child of specified parent) + * @param validate A boolean flag to indicate if this abstract path + * should be validated. + * @throws NullPointerException + * If child is null + * @throws AFSFileException + * If the user constructing this AFS file object is denied + * access to stat the file or simply a stat cannot be performed + * on the file. The reason code and message will be available + * from {@link org.openafs.jafs.AFSFileException#getErrorCode} and + * {@link org.openafs.jafs.AFSFileException#getMessage} respectively. + *

    This exception will not be thrown if the file does not + * exist. Rather, the {@link #exists} attribute will be set to + * false. + * @see #validate() + * @see #File(File, String) + */ + public File(File parent, String filename, boolean validate) throws AFSFileException + { + super(parent, filename); + path = getAbsolutePath(); + if (validate) { + validated = setAttributes(); + if (!validated) throw new AFSFileException(errno); + } + } + + /*****************************************************************************/ + + /** + * Validates this abstract pathname as an attributed AFS file object. + * This method will, if authorized, perform a stat on the + * actual AFS file and update its respective field members; defining + * this file object's attributes. + * + * @throws AFSSecurityException + * If an AFS exception occurs while attempting to stat and set this + * AFS file object's attributes. + */ + public void validate() throws AFSSecurityException + { + validated = setAttributes(); + if (!validated) throw new AFSSecurityException(errno); + } + /** + * Tests whether the file denoted by this abstract pathname has + * been validated. + * + *

    Validation is always attempted upon construction of the file object, + * therefore if this method returns false, then you are not permitted to + * validate this file and consequently all attribute accessors + * will be invalid. + * + *

    This method should return true even if this abstract + * pathname does not exist. If this is abstract pathname does not exist then + * the {@link #exists} method should return false, however this + * implies that the attribute accessors are valid and accurate; thus implying + * successful validation. + * + *

    This method is useful before calling any of the attribute accessors + * to ensure a valid response. + * + * @return true if and only if the file denoted by this + * abstract pathname has been validated during or after object construction; + * false otherwise + */ + public boolean isValidated() + { + return validated; + } + /** + * Refreshes this AFS file object by updating its attributes. + * This method currently provides the same functionality as + * {@link #validate}. + * + * @throws AFSSecurityException + * If an AFS exception occurs while attempting to stat and update this + * AFS file object's attributes. + * @see #validate() + */ + public void refresh() throws AFSSecurityException + { + validate(); + } + /*-------------------------------------------------------------------------*/ + /** + * Tests whether the file denoted by this abstract pathname is a + * directory. + * + * @return true if and only if the file denoted by this + * abstract pathname exists and is a directory; + * false otherwise + */ + public boolean isDirectory() + { + return (isDirectory || isMountPoint) ? true : false; + } + /** + * Tests whether the file denoted by this abstract pathname is a normal + * file. A file is normal if it is not a directory and, in + * addition, satisfies other system-dependent criteria. Any non-directory + * file created by a Java application is guaranteed to be a normal file. + * + * @return true if and only if the file denoted by this + * abstract pathname exists and is a normal file; + * false otherwise + */ + public boolean isFile() + { + return isFile; + } + /** + * Tests whether the file denoted by this abstract pathname is an + * AFS Volume Mount Point. + * + * @return true if and only if the file denoted by this + * abstract pathname exists and is a mount point; + * false otherwise + */ + public boolean isMountPoint() + { + return isMountPoint; + } + /** + * Tests whether the file denoted by this abstract pathname is a + * symbolic-link. + * + * @return true if and only if the file denoted by this + * abstract pathname exists and is a symbolic-link; + * false otherwise + */ + public boolean isLink() + { + return isLink; + } + /*-------------------------------------------------------------------------*/ + /** + * Tests whether the file denoted by this abstract pathname exists. + * + * @return true if and only if the file denoted by this + * abstract pathname exists; false otherwise + */ + public boolean exists() + { + return exists; + } + /** + * Returns the time that the file denoted by this abstract pathname was + * last modified. + * + * @return A long value representing the time the file was + * last modified, measured in milliseconds since the epoch + * (00:00:00 GMT, January 1, 1970), or 0L if the + * file does not exist or if an I/O error occurs + */ + public long lastModified() + { + return lastModified; + } + /** + * Returns the length of the file denoted by this abstract pathname. + * + * @return The length, in bytes, of the file denoted by this abstract + * pathname, or 0L if the file does not exist + */ + public long length() + { + return length; + } + /** + * Returns an abstract pathname string that represents the target resource of + * of this file, if it is a symbolic-link. + * + *

    If this abstract pathname does not denote a symbolic-link, then this + * method returns null. Otherwise a string is + * returned that represents the target resource of this symbolic-link. + * + * @return A string representation of this symbolic-link's target resource. + * @see #isLink() + */ + public String getTarget() + { + return target; + } + /** + * Returns an array of strings naming the files and directories in the + * directory denoted by this abstract pathname. + * + *

    If this abstract pathname does not denote a directory, then this + * method returns null. Otherwise an array of strings is + * returned, one for each file or directory in the directory. Names + * denoting the directory itself and the directory's parent directory are + * not included in the result. Each string is a file name rather than a + * complete path. + * + *

    There is no guarantee that the name strings in the resulting array + * will appear in any specific order; they are not, in particular, + * guaranteed to appear in alphabetical order. + * + * @return An array of strings naming the files and directories in the + * directory denoted by this abstract pathname. The array will be + * empty if the directory is empty. Returns null if + * this abstract pathname does not denote a directory, or if an + * I/O error occurs. + */ + public String[] list() + { + try { + if (isFile()) { + errno = ErrorTable.NOT_DIRECTORY; + return null; + } + ArrayList buffer = new ArrayList(); + dirHandle = listNative(buffer); + if (dirHandle == 0) { + return null; + } else { + return (String[])buffer.toArray(new String[0]); + } + } catch (Exception e) { + System.out.println(e); + return null; + } + } + /** + * Returns an ArrayList object containing strings naming the files and + * directories in the directory denoted by this abstract pathname. + * + *

    If this abstract pathname does not denote a directory, then this + * method returns null. Otherwise an array of strings is + * returned, one for each file or directory in the directory. Names + * denoting the directory itself and the directory's parent directory are + * not included in the result. Each string is a file name rather than a + * complete path. + * + *

    There is no guarantee that the name strings in the resulting array + * will appear in any specific order; they are not, in particular, + * guaranteed to appear in alphabetical order. + * + * @return An array of strings naming the files and directories in the + * directory denoted by this abstract pathname. The array will be + * empty if the directory is empty. Returns null if + * this abstract pathname does not denote a directory, or if an + * I/O error occurs. + * @throws AFSSecurityException + * If you are not authorized to list the contents of this directory + * @throws AFSFileException + * If this file object is not a mount point, link + * , or directory or an unexpected AFS + * error occurs. + * @see #list() + */ + public ArrayList listArray() throws AFSFileException + { + try { + if (isFile()) throw new AFSFileException(ErrorTable.NOT_DIRECTORY); + ArrayList buffer = new ArrayList(); + dirHandle = listNative(buffer); + if (dirHandle == 0) { + if (errno == ErrorTable.PERMISSION_DENIED) { + throw new AFSSecurityException(errno); + } else { + throw new AFSFileException(errno); + } + } else { + return buffer; + } + } catch (Exception e) { + System.out.println(e); + throw new AFSFileException(errno); + } + } + /*-------------------------------------------------------------------------*/ + /** + * Deletes the file or directory denoted by this abstract pathname. If + * this pathname denotes a directory, then the directory must be empty in + * order to be deleted. + * + * @return true if and only if the file or directory is + * successfully deleted; false otherwise + */ + public boolean delete() + { + try { + if(this.isDirectory()) { + return this.rmdir(); + } else if(this.isFile() || this.isLink()) { + return this.rmfile(); + } + return false; + } catch (Exception e) { + System.out.println(e); + return false; + } + } + /** + * Copies the file denoted by this abstract pathname to the destination + * file provided. Then checks the newly copied file's size to + * test for file size consistency. + * + * @param dest The new abstract pathname for the named file + * + * @return true if and only if the file that was copied + * reports the same file size (length) as that of this file; + * false otherwise + * + * @throws AFSFileException + * If an I/O or AFS exception is encountered while copying the file. + */ + public boolean copyTo(File dest) throws AFSFileException + { + FileInputStream fis = new FileInputStream(this); + FileOutputStream fos = new FileOutputStream(dest); + byte[] buf = new byte[1024]; + int i = 0; + while((i=fis.read(buf))!=-1) { + fos.write(buf, 0, i); + } + fis.close(); + fos.close(); + dest.validate(); + return (dest.length() == this.length()); + } + /*-------------------------------------------------------------------------*/ + /** + * Returns the permissions mask of the ACL for this object relative to the user accessing it. + * + * @return the permissions mask of this object based upon the current user. + * @see org.openafs.jafs.ACL.Entry#getPermissionsMask() + */ + public int getPermissionsMask() + { + return getRights(); + } + /** + * Tests whether the user can administer the ACL (see: {@link org.openafs.jafs.ACL} + * of the directory denoted by this abstract pathname. + * + * @see org.openafs.jafs.ACL.Entry#canAdmin + * @return true if and only if the directory specified by this + * abstract pathname exists and can be administered by the + * current user; false otherwise + */ + public boolean canAdmin() + { + if (acl == null) acl = new ACL.Entry(getRights()); + return acl.canAdmin(); + } + /** + * Tests whether the current user can delete the files or subdirectories of + * the directory denoted by this abstract pathname. + * + * @see org.openafs.jafs.ACL.Entry#canDelete + * @return true if and only if the directory specified by this + * abstract pathname exists and permits deletion of its files + * and subdirectories by the current user; false otherwise + */ + public boolean canDelete() + { + if (acl == null) acl = new ACL.Entry(getRights()); + return acl.canDelete(); + } + /** + * Tests whether the current user can insert a file into the directory + * denoted by this abstract pathname. + * + * @see org.openafs.jafs.ACL.Entry#canInsert + * @return true if and only if the directory specified by this + * abstract pathname exists and a file can be inserted by the + * current user; false otherwise + */ + public boolean canInsert() + { + if (acl == null) acl = new ACL.Entry(getRights()); + return acl.canInsert(); + } + /** + * Tests whether the current user can lock the file denoted by this + * abstract pathname. + * + * @see org.openafs.jafs.ACL.Entry#canLock + * @return true if and only if the file specified by this + * abstract pathname exists and can be locked by the + * current user; false otherwise + */ + public boolean canLock() + { + if (acl == null) acl = new ACL.Entry(getRights()); + return acl.canLock(); + } + /** + * Tests whether the current user can lookup the contents of the directory + * denoted by this abstract pathname. + * + * @see org.openafs.jafs.ACL.Entry#canLookup + * @return true if and only if the directory specified by this + * abstract pathname exists and its contents can be listed by the + * current user; false otherwise + */ + public boolean canLookup() + { + if (acl == null) acl = new ACL.Entry(getRights()); + return acl.canLookup(); + } + /** + * Tests whether the current user can read the file denoted by this + * abstract pathname. + * + * @see org.openafs.jafs.ACL.Entry#canRead + * @return true if and only if the file specified by this + * abstract pathname exists and can be read by the + * current user; false otherwise + */ + public boolean canRead() + { + if (acl == null) acl = new ACL.Entry(getRights()); + return acl.canRead(); + } + /** + * Tests whether the current user can modify to the file denoted by this + * abstract pathname. + * + * @see org.openafs.jafs.ACL.Entry#canWrite + * @return true if and only if the file system actually + * contains a file denoted by this abstract pathname and + * the current user is allowed to write to the file; + * false otherwise. + */ + public boolean canWrite() + { + if (acl == null) acl = new ACL.Entry(getRights()); + return acl.canWrite(); + } + /*-------------------------------------------------------------------------*/ + /** + * Closes the directory denoted by this abstract pathname. + * + * @return true if and only if the directory is + * successfully closed; false otherwise + */ + public boolean close() + { + if (dirHandle == 0) { + return false; + } + return closeDir(dirHandle); + } + /*-------------------------------------------------------------------------*/ + /** + * Returns the AFS specific error number (code). This code can be interpreted + * by use of {@link org.openafs.jafs.ErrorTable} static class method + * {@link org.openafs.jafs.ErrorTable#getMessage} + * + * @return the AFS error code (number) associated with the last action performed + * on this object. + * @see org.openafs.jafs.ErrorTable#getMessage(int) + */ + public int getErrorCode() + { + return errno; + } + /** + * Returns the AFS error message string defined by the {@link org.openafs.jafs.ErrorTable} + * class. + * + * @return the AFS error message string associated with the last action performed + * on this object. + * @see org.openafs.jafs.ErrorTable#getMessage(int) + */ + public String getErrorMessage() + { + return ErrorTable.getMessage(errno); + } + + /////////////// custom override methods //////////////////// + + /** + * Compares two File objects relative to their filenames and does not + * compare their respective absolute paths. Alphabetic case is significant in + * comparing filenames. + * + * @param file The File object to be compared to this file's filename + * + * @return Zero if the argument is equal to this file's filename, a + * value less than zero if this file's filename is + * lexicographically less than the argument, or a value greater + * than zero if this file's filename is lexicographically + * greater than the argument + * + * @since JDK1.2 + */ + public int compareTo(File file) { + return this.getName().compareTo(file.getName()); + } + /** + * Compares this file to another File object. If the other object + * is an abstract pathname, then this function behaves like {@link + * #compareTo(File)}. Otherwise, it throws a + * ClassCastException, since File objects can only be + * compared to File objects. + * + * @param o The Object to be compared to this abstract pathname + * + * @return If the argument is an File object, returns zero + * if the argument is equal to this file's filename, a value + * less than zero if this file's filename is lexicographically + * less than the argument, or a value greater than zero if this + * file's filename is lexicographically greater than the + * argument + * + * @throws ClassCastException if the argument is not an + * File object + * + * @see java.lang.Comparable + * @since JDK1.2 + */ + public int compareTo(Object o) throws ClassCastException + { + File file = (File)o; + return compareTo(file); + } + + /////////////// public native methods //////////////////// + + /** + * Creates the directory named by this abstract pathname. + * + * @return true if and only if the directory was + * created; false otherwise + */ + public native boolean mkdir(); + /** + * Renames the file denoted by this abstract pathname. + * + * @param dest The new abstract pathname for the named file + * + * @return true if and only if the renaming succeeded; + * false otherwise + * + * @throws NullPointerException + * If parameter dest is null + */ + public native boolean renameTo(File dest); + /** + * Performs a file stat on the actual AFS file and populates + * this object's respective field members with the appropriate values. + * method will, if authorized, perform a stat on the + * actual AFS file and update its respective field members; defining + * this file object's attributes. + * + *

    This method should not be used directly for refreshing or validating + * this AFS file object. Please use {@link #validate} instead. + * + * @return true if and only if the current user is allowed to stat the file; + * false otherwise. + * @see #validate() + */ + public native boolean setAttributes() throws AFSSecurityException; + + /////////////// private native methods //////////////////// + + /** + * List the contents of this directory. + * + * @return the directory handle + */ + private native long listNative(ArrayList buffer) throws AFSSecurityException; + /** + * Close the currently open directory using a previously obtained handle. + * + * @return true if the directory closes without error + */ + private native boolean closeDir(long dp) throws AFSSecurityException; + /** + * Removes/deletes the current directory. + * + * @return true if the directory is removed without error + */ + private native boolean rmdir() throws AFSSecurityException; + /** + * Removes/deletes the current file. + * + * @return true if the file is removed without error + */ + private native boolean rmfile() throws AFSSecurityException; + /** + * Returns the permission/ACL mask for this directory + * + * @return permission/ACL mask + */ + private native int getRights() throws AFSSecurityException; + /*-------------------------------------------------------------------------*/ +} + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/FileInputStream.java b/src/JAVA/classes/org/openafs/jafs/FileInputStream.java new file mode 100644 index 0000000..ea7f65c --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/FileInputStream.java @@ -0,0 +1,167 @@ +/* + * @(#)FilterInputStream.java 1.0 00/10/10 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.io.InputStream; + +/** + * This class is a file input stream for files within AFS. + * It is an input stream for reading data from a + * {@link org.openafs.jafs.File}. + * + * @version 2.1, 08/03/2001 + * @see org.openafs.jafs.File + * @see org.openafs.jafs.FileOutputStream + * @see java.io.FileInputStream + */ +public class FileInputStream extends InputStream +{ + /** Status indicator for the current state of this file input stream */ + private int fileDescriptor; + + /** + * Creates a FileInputStream by + * opening a connection to an actual AFS file, + * the file named by the path name name + * in the AFS file system. + * + * @param name the name of the file to read from + * @exception AFSFileException If an AFS specific error occurs, + * if the file does not, or cannot be opened for any + * other reason, including authorization. + */ + public FileInputStream(String name) throws AFSFileException + { + this.fileDescriptor = this.openReadOnly(name); + } + /** + * Creates a FileInputStream by + * opening a connection to an actual AFS file, + * the file represented by file file + * in the AFS file system. + * + * @param file an AFS file object representing a file to read from + * @exception AFSFileException If an AFS specific error occurs, + * if the file does not, or cannot be opened for any + * other reason, including authorization. + */ + public FileInputStream(File file) throws AFSFileException + { + this(file.getPath()); + } + + /*-------------------------------------------------------------------------*/ + + /** + * Reads the next byte of data from this input stream. The value + * byte is returned as an int in the range + * 0 to 255. If no byte is available + * because the end of the stream has been reached, the value + * -1 is returned. This method blocks until input data + * is available, the end of the stream is detected, or an exception + * is thrown. + * + *

    This method simply performs in.read() and returns + * the result. + * + * @return the next byte of data, or -1 if the end of the + * stream is reached. + * @exception AFSFileException if an I/O or other file related error occurs. + * @see java.io.FileInputStream#read + */ + public int read() throws AFSFileException + { + byte[] bytes = new byte[1]; + this.read(bytes, 0, 1); + return bytes[0]; + } + /** + * Reads up to b.length bytes of data from this input + * stream into an array of bytes. This method blocks until some input + * is available. + * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the file has been reached. + * @exception AFSFileException if an I/O or other file related error occurs. + */ + public int read(byte[] b) throws AFSFileException + { + return this.read(b, 0, b.length); + } + + /////////////// public native methods //////////////////// + + /** + * Reads up to len bytes of data from this input stream + * into an array of bytes. This method blocks until some input is + * available. + * + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the file has been reached. + * @exception AFSFileException if an I/O or other file related error occurs. + */ + public native int read(byte[] b, int off, int len) throws AFSFileException; + /** + * Skips over and discards n bytes of data from the + * input stream. The skip method may, for a variety of + * reasons, end up skipping over some smaller number of bytes, + * possibly 0. The actual number of bytes skipped is returned. + * + * @param n the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @exception AFSFileException if an I/O or other file related error occurs. + */ + public native long skip(long n) throws AFSFileException; + /** + * Closes this file input stream and releases any system resources + * associated with the stream. + * + * @exception AFSFileException if an I/O or other file related error occurs. + */ + public native void close() throws AFSFileException; + + /////////////// private native methods //////////////////// + + /** + * Opens the specified AFS file for reading. + * + * @param name fileName of file to be opened + * @return file descriptor + * @exception AFSFileException if an I/O or other file related error occurs. + */ + private native int openReadOnly(String fileName) throws AFSFileException; + + /*-------------------------------------------------------------------------*/ +} + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/FileOutputStream.java b/src/JAVA/classes/org/openafs/jafs/FileOutputStream.java new file mode 100644 index 0000000..95c92dd --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/FileOutputStream.java @@ -0,0 +1,217 @@ +/* + * @(#)FilterOutputStream.java 1.0 00/10/10 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.io.OutputStream; + +/** + * This class is a file output stream for files within AFS. + * It is an output stream for writing data to a + * {@link org.openafs.jafs.File}. + * + * @version 2.1, 08/03/2001 + * @see org.openafs.jafs.File + * @see org.openafs.jafs.FileInputStream + * @see java.io.FileOutputStream + */ +public class FileOutputStream extends OutputStream +{ + /** Status indicator for the current state of this file output stream */ + private int fileDescriptor; + + /** + * Creates an output file stream to write to the AFS file with the + * specified name. + *

    + * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a AFSFileException is thrown. + * + * @param name the name of the file to write to + * @exception AFSFileException If an AFS specific error occurs, + * if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason, including + * authorization. + */ + public FileOutputStream(String name) throws AFSFileException + { + this(name, false); + } + /** + * Creates an output file stream to write to the AFS file with the specified + * name. If the second argument is true, then + * bytes will be written to the end of the file rather than the beginning. + *

    + * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a AFSFileException is thrown. + * + * @param name the name of the file to write to + * @param append if true, then bytes will be written + * to the end of the file rather than the beginning + * @exception AFSFileException If an AFS specific error occurs, + * if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason, including + * authorization. + */ + public FileOutputStream(String name, boolean append) throws AFSFileException + { + if (append) { + fileDescriptor = this.openAppend(name); + } else { + fileDescriptor = this.openWrite(name); + } + } + /** + * Creates a file output stream to write to the AFS file represented by + * the specified File object. + *

    + * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a AFSFileException is thrown. + * + * @param file the AFS file to be opened for writing. + * @exception AFSFileException If an AFS specific error occurs, + * if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason, including + * authorization. + * @see org.openafs.jafs.File#getPath() + */ + public FileOutputStream(File file) throws AFSFileException + { + this(file.getPath(), false); + } + /** + * Creates a file output stream to write to the AFS file represented by + * the specified File object. + *

    + * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a AFSFileException is thrown. + * + * @param file the AFS file to be opened for writing. + * @param append if true, then bytes will be written + * to the end of the file rather than the beginning + * @exception AFSFileException If an AFS specific error occurs, + * if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason, including + * authorization. + * @see org.openafs.jafs.File#getPath() + */ + public FileOutputStream(File file, boolean append) throws AFSFileException + { + this(file.getPath(), append); + } + + /*-------------------------------------------------------------------------*/ + + /** + * Writes the specified byte to this file output stream. + *

    + * Implements the abstract write method of OutputStream. + * + * @param b the byte to be written. + * @exception AFSFileException if an error occurs. + */ + public void write(int b) throws AFSFileException + { + byte[] bytes = new byte[1]; + bytes[0] = (byte) b; + this.write(bytes, 0, 1); + } + /** + * Writes b.length bytes from the specified byte array + * to this file output stream. + *

    + * Implements the write method of three arguments with the + * arguments b, 0, and + * b.length. + *

    + * Note that this method does not call the one-argument + * write method of its underlying stream with the single + * argument b. + * + * @param b the data to be written. + * @exception AFSFileException if an error occurs. + * @see #write(byte[], int, int) + * @see java.io.FilterOutputStream#write(byte[], int, int) + */ + public void write(byte[] b) throws AFSFileException + { + this.write(b, 0, b.length); + } + + /////////////// public native methods //////////////////// + + /** + * Writes len bytes from the specified + * byte array starting at offset off to + * this file output stream. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @exception AFSFileException if an I/O or other file related error occurs. + * @see java.io.FilterOutputStream#write(int) + */ + public native void write(byte[] b, int off, int len) throws AFSFileException; + /** + * Closes this file output stream and releases any system resources + * associated with this stream. This file output stream may no longer + * be used for writing bytes. + * + * @exception AFSFileException if an I/O or other file related error occurs. + */ + public native void close() throws AFSFileException; + + /////////////// private native methods //////////////////// + + /** + * Opens an AFS file, with the specified name, for writing. + * + * @param filename name of file to be opened + * @return file descriptor + * @exception AFSFileException if an I/O or other file related error occurs. + */ + private native int openWrite(String filename) throws AFSFileException; + /** + * Opens an AFS file, with the specified name, for appending. + * + * @param filename name of file to be opened + * @return file descriptor + * @exception AFSFileException if an I/O or other file related error occurs. + */ + private native int openAppend(String filename) throws AFSFileException; + + /*-------------------------------------------------------------------------*/ +} + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/Group.java b/src/JAVA/classes/org/openafs/jafs/Group.java new file mode 100644 index 0000000..3b93345 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/Group.java @@ -0,0 +1,1278 @@ +/* + * @(#)Group.java 1.0 6/29/2001 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.Vector; +import java.util.Enumeration; +import java.util.ArrayList; +import java.io.Serializable; + +/** + * An abstract representation of an AFS group. It holds information about + * the group, such as what groups it owns.

    + * + * Constructing an instance of a Group does not mean an actual + * AFS group is created in a cell -- usually a Group + * object is a representation of an already existing AFS group. If, + * however, the Group is constructed with the name of a + * group that does not exist in the cell represented by the provided + * Cell, a new group with that name can be + * created in that cell by calling the {@link #create(String, int)} or + * {@link #create(String)} method. If such a group does already exist when + * one of these methods is called, an exception will be thrown.

    + * + * Each Group object has its own individual set of + * Groups that it owns and Users that belong + * to it. These represents the properties and attributes + * of an actual AFS group. + *

    + * + * + * + * Associated with an AFS group are many attributes, such as whether or not + * who is allowed to list the members of this group. The Group + * class has many "set" methods to indicate values for these attributes (i.e. + * {@link #setListMembership(int)}. However, in order for these values to be + * written to the actual AFS group, the {@link #flushInfo()} method needs to + * be called. This writes all user attributes set through this API to AFS. + * This is done to minimize calls through JNI.

    + * + * + * The following is a simple example of how to construct and use a + * Group object. It lists the name and owner of a specified + * group. + * + *

    + * import org.openafs.jafs.Cell;
    + * import org.openafs.jafs.AFSException;
    + * import org.openafs.jafs.Partition;
    + * import org.openafs.jafs.Group;
    + * ...
    + * public class ...
    + * {
    + *   ...
    + *   private Cell cell;
    + *   private Group group;
    + *   ...
    + *   public static void main(String[] args) throws Exception
    + *   {
    + *     String username   = arg[0];
    + *     String password   = arg[1];
    + *     String cellName   = arg[2];
    + *     String groupName  = arg[3];
    + * 
    + *     token = new Token(username, password, cellName);
    + *     cell   = new Cell(token);
    + *     group = new Group(groupName, cell);
    + *     
    + *     System.out.println("Owner of group " + group.getName() + " is " 
    + *                        + group.getOwnerName());
    + *     ...
    + *   }
    + *   ...
    + * }
    + * 
    + * + */ +public class Group implements PTSEntry, Serializable, Comparable +{ + /** + * Only the owner of the group has access + */ + public static final int GROUP_OWNER_ACCESS = 0; + /** + * Members of the group have access + */ + public static final int GROUP_GROUP_ACCESS = 1; + /** + * Any user has access + */ + public static final int GROUP_ANYUSER_ACCESS = 2; + + protected Cell cell; + protected int cellHandle; + protected String name; + + protected int membershipCount; + protected int nameUID; + protected int ownerUID; + protected int creatorUID; + + protected String owner; + protected String creator; + + /** + * who is allowed to execute PTS examine for this group. Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} -- any user has permission
    + */ + protected int listStatus; + /** + * who is allowed to execute PTS examine for this group. Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} -- any user has permission
    + */ + protected int listGroupsOwned; + /** + * who is allowed to execute PTS listowned for this group. Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} -- any user has permission
    + */ + protected int listMembership; + /** + * who is allowed to execute PTS adduser for this group. Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} -- any user has permission
    + */ + protected int listAdd; + /** + * who is allowed to execute PTS removeuser for this group. Valid + * values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} -- any user has permission
    + */ + protected int listDelete; + + protected ArrayList members; + protected ArrayList memberNames; + protected ArrayList groupsOwned; + protected ArrayList groupsOwnedNames; + + /** + * Whether or not the information fields of this group have been filled. + */ + protected boolean cachedInfo; + + /** + * Constructs a new Group object instance given the name + * of the AFS group and the AFS cell, represented by + * cell, to which it belongs. This does not actually + * create a new AFS group, it just represents one. + * If name is not an actual AFS group, exceptions + * will be thrown during subsequent method invocations on this + * object, unless the {@link #create(String, int)} or {@link #create(String)} + * method is explicitly called to create it. + * + * @param name the name of the group to represent + * @param cell the cell to which the group belongs. + * @exception AFSException If an error occurs in the native code + */ + public Group( String name, Cell cell ) throws AFSException + { + this.name = name; + this.cell = cell; + cellHandle = cell.getCellHandle(); + + members = null; + memberNames = null; + groupsOwned = null; + groupsOwnedNames = null; + cachedInfo = false; + } + + /** + * Constructs a new Group object instance given the name + * of the AFS group and the AFS cell, represented by + * cell, to which it belongs. This does not actually + * create a new AFS group, it just represents one. + * If name is not an actual AFS group, exceptions + * will be thrown during subsequent method invocations on this + * object, unless the {@link #create(String, int)} or {@link #create(String)} + * method is explicitly called to create it. Note that if the process + * doesn't exist and preloadAllMembers is true, an exception + * will be thrown. + * + *

    This constructor is ideal for point-in-time representation and + * transient applications. It ensures all data member values are set and + * available without calling back to the filesystem at the first request + * for them. Use the {@link #refresh()} method to address any coherency + * concerns. + * + * @param name the name of the group to represent + * @param cell the cell to which the group belongs. + * @param preloadAllMembers true will ensure all object members are + * set upon construction; + * otherwise members will be set upon access, + * which is the default behavior. + * @exception AFSException If an error occurs in the native code + * @see #refresh + */ + public Group( String name, Cell cell, boolean preloadAllMembers ) + throws AFSException + { + this(name, cell); + if (preloadAllMembers) refresh(true); + } + + /** + * Creates a blank Group given the cell to which the group + * belongs. Other methods cvan then be used to fill the fields of this + * blank object. + * + * @exception AFSException If an error occurs in the native code + * @param cell the cell to which the group belongs. + */ + Group( Cell cell ) throws AFSException + { + this( null, cell ); + } + + /*-------------------------------------------------------------------------*/ + + /** + * Creates the PTS entry for a new group in this cell. Automatically assigns + * a group id. + * + * @param ownerName the owner of this group + */ + public void create( String ownerName ) throws AFSException + { + this.create( ownerName, 0 ); + } + + /** + * Creates the PTS entry for a new group in this cell. + * + * @param ownerName the owner of this group + * @param gid the group id to assign to the new group + * @exception AFSException If an error occurs in the native code + */ + public void create( String ownerName, int gid ) throws AFSException + { + Group.create( cell.getCellHandle(), name, ownerName, gid ); + } + + /** + * Deletes the PTS entry for a group in this cell. Deletes this group + * from the membership list of the user that belonged to it, but does not + * delete the groups owned by this group. Also nullifies the Java object. + * + * @exception AFSException If an error occurs in the native code + */ + public void delete() throws AFSException + { + Group.delete( cell.getCellHandle(), name ); + + cell = null; + name = null; + owner = null; + creator = null; + members = null; + memberNames = null; + groupsOwned = null; + groupsOwnedNames = null; + try { + finalize(); + } catch( Throwable t ) { + throw new AFSException( t.getMessage() ); + } + } + + /** + * Flushes the current information of this Group object to disk. + * This will update the information of the actual AFS group to match the + * settings that have been modified in this Group object. + * This function must be called before any changes made to the information + * fields of this group will be seen by the AFS system. + * + * @exception AFSException If an error occurs in the native code + */ + public void flushInfo() throws AFSException + { + Group.setGroupInfo( cell.getCellHandle(), name, this ); + } + + /** + * Add the specified member to this group. + * + * @param userName the User object to add + * @exception AFSException If an error occurs in the native code + */ + public void addMember( User theUser ) throws AFSException + { + String userName = theUser.getName(); + + Group.addMember( cell.getCellHandle(), name, userName ); + + // add to cache + if( memberNames != null ) { + memberNames.add( userName ); + } + if( members != null ) { + members.add( new User( userName, cell ) ); + } + } + + /** + * Remove the specified member from this group. + * @param userName the User object to remove + * @exception AFSException If an error occurs in the native code + */ + public void removeMember( User theUser ) throws AFSException + { + String userName = theUser.getName(); + Group.removeMember( cell.getCellHandle(), name, userName ); + + // remove from cache + if( memberNames != null ) { + memberNames.remove( memberNames.indexOf(userName) ); + memberNames.trimToSize(); + } + if( members != null && members.indexOf(theUser) > -1) { + members.remove( members.indexOf(theUser) ); + members.trimToSize(); + } + } + + /** + * Change the owner of this group. + * + * @param ownerName the new owner User object + * @exception AFSException If an error occurs in the native code + */ + public void changeOwner( User theOwner ) throws AFSException + { + String ownerName = theOwner.getName(); + + Group.changeOwner( cell.getCellHandle(), name, ownerName ); + + if( cachedInfo ) { + owner = ownerName; + } + } + + /** + * Change the owner of this group. + * + * @param ownerName the new owner Group object + * @exception AFSException If an error occurs in the native code + */ + public void changeOwner( Group theOwner ) throws AFSException + { + String ownerName = theOwner.getName(); + Group.changeOwner( cell.getCellHandle(), name, ownerName ); + if( cachedInfo ) { + owner = ownerName; + } + } + + /** + * Change the name of this group. + * + * @param newName the new name for this group + * @exception AFSException If an error occurs in the native code + */ + public void rename( String newName ) throws AFSException + { + Group.rename( cell.getCellHandle(), name, newName ); + name = newName; + } + + /** + * Refreshes the properties of this Group object instance with values from + * the AFS group it represents. All properties that have been initialized + * and/or accessed will be renewed according to the values of the AFS group + * this Group object instance represents. + * + *

    Since in most environments administrative changes can be administered + * from an AFS command-line program or an alternate GUI application, this + * method provides a means to refresh the Java object representation and + * thereby ascertain any possible modifications that may have been made + * from such alternate administrative programs. Using this method before + * an associated instance accessor will ensure the highest level of + * representative accuracy, accommodating changes made external to the + * Java application space. If administrative changes to the underlying AFS + * system are only allowed via this API, then the use of this method is + * unnecessary. + * + * @exception AFSException If an error occurs in the native code + */ + public void refresh() throws AFSException + { + refresh(false); + } + + /** + * Refreshes the properties of this Group object instance with values from + * the AFS group it represents. If all is true + * then all of the properties of this Group object instance will be + * set, or renewed, according to the values of the AFS group it represents, + * disregarding any previously set properties. + * + *

    Thus, if all is false then properties that + * are currently set will be refreshed and properties that are not set will + * remain uninitialized. See {@link #refresh()} for more information. + * + * @param all if true set or renew all object properties; otherwise renew + * all set properties + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + protected void refresh(boolean all) throws AFSException + { + if( all || cachedInfo ) { + refreshInfo(); + } + if( all || groupsOwned != null ) { + refreshGroupsOwned(); + } + if( all || groupsOwnedNames != null ) { + refreshGroupsOwnedNames(); + } + if( all || members != null ) { + refreshMembers(); + } + if( all || memberNames != null ) { + refreshMemberNames(); + } + } + + /** + * Refreshes the information fields of this Group to reflect + * the current state of the AFS group. Does not refresh the members that + * belong to the group, nor the groups the group owns. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshInfo() throws AFSException + { + cachedInfo = true; + Group.getGroupInfo( cell.getCellHandle(), name, this ); + } + + /** + * Refreshes the current information about the User objects + * belonging to this group. Does not refresh the information fields of + * the group or groups owned. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshMembers() throws AFSException + { + User currUser; + + int iterationID = Group.getGroupMembersBegin( cell.getCellHandle(), name ); + + members = new ArrayList(); + + currUser = new User( cell ); + while( Group.getGroupMembersNext( cellHandle, iterationID, currUser ) + != 0 ) { + members.add( currUser ); + currUser = new User( cell ); + } + + Group.getGroupMembersDone( iterationID ); + } + + /** + * Refreshes the current information about the names of members belonging + * to this group. Does not refresh the information fields of the group + * or groups owned. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshMemberNames() throws AFSException + { + String currName; + int iterationID = Group.getGroupMembersBegin( cell.getCellHandle(), name ); + + memberNames = new ArrayList(); + + while( ( currName = Group.getGroupMembersNextString( iterationID ) ) + != null ) { + memberNames.add( currName ); + } + Group.getGroupMembersDone( iterationID ); + } + + /** + * Refreshes the current information about the Group objects the + * group owns. Does not refresh the information fields of the group or + * members. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshGroupsOwned() throws AFSException + { + Group currGroup; + + int iterationID = User.getGroupsOwnedBegin( cell.getCellHandle(), name ); + + groupsOwned = new ArrayList(); + + currGroup = new Group( cell ); + while( User.getGroupsOwnedNext( cellHandle, iterationID, currGroup ) + != 0 ) { + groupsOwned.add( currGroup ); + currGroup = new Group( cell ); + } + + User.getGroupsOwnedDone( iterationID ); + } + + /** + * Refreshes the current information about the names of groups the group + * owns. Does not refresh the information fields of the group or members. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshGroupsOwnedNames() throws AFSException + { + String currName; + + int iterationID = User.getGroupsOwnedBegin( cell.getCellHandle(), name ); + + groupsOwnedNames = new ArrayList(); + while( ( currName = User.getGroupsOwnedNextString( iterationID ) ) + != null ) { + groupsOwnedNames.add( currName ); + } + User.getGroupsOwnedDone( iterationID ); + } + + /** + * Adds an access control list entry for some AFS directory for this group. + * + * @param directory the full path of the place in the AFS file system + * for which to add an entry + * @param read whether or not to allow read access to this user + * @param write whether or not to allow write access to this user + * @param lookup whether or not to allow lookup access to this user + * @param delete whether or not to allow deletion access to this user + * @param insert whether or not to allow insertion access to this user + * @param lock whether or not to allow lock access to this user + * @param admin whether or not to allow admin access to this user + * @exception AFSException If an error occurs in the native code + public void setACL( String directory, boolean read, boolean write, boolean lookup, boolean delete, boolean insert, boolean lock, boolean admin ) + throws AFSException + { + Cell.setACL( directory, name, read, write, lookup, delete, insert, lock, admin ); + } + */ + + ////////////////////// accessors: /////////////// + + /** + * Returns the name of this group. + * + * @return the name of this group + */ + public String getName() + { + return name; + } + + /** + * Returns the numeric AFS id of this group. + * + * @return the AFS id of this group + * @exception AFSException If an error occurs in the native code + */ + public int getUID() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + return nameUID; + } + + /** + * Returns the Cell this group belongs to. + * + * @return the Cell this group belongs to + */ + public Cell getCell() + { + return cell; + } + + /** + * Returns an array of the User object members of this group. + * + * @return an array of the members of this group + * @exception AFSException If an error occurs in the native code + */ + public User[] getMembers() throws AFSException + { + if( members == null ) { + refreshMembers(); + } + return (User[]) members.toArray( new User[members.size()] ); + } + + /** + * Returns an array of the member names of this group. + * + * @return an array of the member names of this group + * @exception AFSException If an error occurs in the native code + */ + public String[] getMemberNames() throws AFSException + { + if( memberNames == null ) { + refreshMemberNames(); + } + return (String[]) memberNames.toArray( new String[memberNames.size()] ); + } + + /** + * Returns an array of the Group objects this group owns. + * + * @return an array of the Groups this group owns + * @exception AFSException If an error occurs in the native code + */ + public Group[] getGroupsOwned() throws AFSException + { + if( groupsOwned == null ) { + refreshGroupsOwned(); + } + return (Group[]) groupsOwned.toArray( new Group[groupsOwned.size()] ); + } + + /** + * Returns an array of the group names this group owns. + * Contains String objects. + * + * @return an array of the group names this group owns + * @exception AFSException If an error occurs in the native code + */ + public String[] getGroupsOwnedNames() throws AFSException + { + if( groupsOwnedNames == null ) { + refreshGroupsOwnedNames(); + } + return (String[]) + groupsOwnedNames.toArray(new String[groupsOwnedNames.size()] ); + } + + /** + * Returns the number of members of this group. + * + * @return the membership count + * @exception AFSException If an error occurs in the native code + */ + public int getMembershipCount() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + return membershipCount; + } + + /** + * PTS: Returns the owner of this group in the form of a {@link PTSEntry}. + * + *

    The returning object could be either a {@link User} or {@link Group}; + * to determine what type of object the {@link PTSEntry} represents, + * call the {@link PTSEntry#getType()} method. + * + * @return the owner of this group + * @exception AFSException If an error occurs in the native code + * @see PTSEntry + * @see PTSEntry#getType() + * @see #refresh() + */ + public PTSEntry getOwner() throws AFSException + { + if (!cachedInfo) refreshInfo(); + if (owner == null) return null; + if (ownerUID > 0) { + return new User(owner, cell); + } else { + return new Group(owner, cell); + } + } + + /** + * PTS: Returns the creator of this group in the form of a {@link PTSEntry}. + * + *

    The returning object could be either a {@link User} or {@link Group}; + * to determine what type of object the {@link PTSEntry} represents, + * call the {@link PTSEntry#getType()} method. + * + * @return the creator of this group + * @exception AFSException If an error occurs in the native code + * @see PTSEntry + * @see PTSEntry#getType() + * @see #refresh() + */ + public PTSEntry getCreator() throws AFSException + { + if (!cachedInfo) refreshInfo(); + if (creator == null) return null; + if (creatorUID > 0) { + return new User(creator, cell); + } else { + return new Group(creator, cell); + } + } + + /** + * Returns the type of {@link PTSEntry} this object represents. + * + *

    This method will always return {@link PTSEntry#PTS_GROUP}. + * + * @return the type of PTSEntry this object represents + (will always return {@link PTSEntry#PTS_GROUP}) + * @see PTSEntry + * @see PTSEntry#getType() + */ + public short getType() + { + return PTSEntry.PTS_GROUP; + } + + /** + * Returns who can list the status (pts examine) of this group. + * Valid values are: + *

      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @return the status listing permission + * @exception AFSException If an error occurs in the native code + */ + public int getListStatus() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return listStatus; + } + + /** + * Returns who can list the groups owned (pts listowned) by this group. + * Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @return the groups owned listing permission + * @exception AFSException If an error occurs in the native code + */ + public int getListGroupsOwned() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return listGroupsOwned; + } + + /** + * Returns who can list the users (pts membership) that belong to this group. + * Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @return the membership listing permission + * @exception AFSException If an error occurs in the native code + */ + public int getListMembership() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return listMembership; + } + + /** + * Returns who can add members (pts adduser) to this group. + * Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @return the member adding permission + * @exception AFSException If an error occurs in the native code + */ + public int getListAdd() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return listAdd; + } + + /** + * Returns who can delete members (pts removemember) from this group. + * Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @return the member deleting permission + * @exception AFSException If an error occurs in the native code + */ + public int getListDelete() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return listDelete; + } + + /////////////////// mutators: ////////////////////// + + /** + * Sets who can list the status (pts examine) of this group. + * Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @param value the value of the new list membership permission + * @exception AFSException if an error occurs in the native code + * @exception IllegalArgumentException if an invalud argument is provided + */ + public void setListStatus( int value ) throws AFSException + { + if( (value != Group.GROUP_OWNER_ACCESS) && + (value != Group.GROUP_GROUP_ACCESS) && + (value != Group.GROUP_ANYUSER_ACCESS) ) { + throw new IllegalArgumentException( "Cannot set listStatus to " + + value ); + } else { + listStatus = value; + } + } + + /** + * Sets who can list the groups owned (pts listowned) by this group. + * Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @param value the value of the new list membership permission + * @exception AFSException if an error occurs in the native code + * @exception IllegalArgumentException if an invalud argument is provided + */ + public void setListGroupsOwned( int value ) throws AFSException + { + if( (value != Group.GROUP_OWNER_ACCESS) && + (value != Group.GROUP_GROUP_ACCESS) && + (value != Group.GROUP_ANYUSER_ACCESS) ) { + throw new IllegalArgumentException( "Cannot set listGroupsOwned to " + + value ); + } else { + listGroupsOwned = value; + } + } + + /** + * Sets who can list the users (pts membership) that belong to this group. + * Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @param value the value of the new list membership permission + * @exception AFSException if an error occurs in the native code + * @exception IllegalArgumentException if an invalud argument is provided + */ + public void setListMembership( int value ) throws AFSException + { + if( (value != Group.GROUP_OWNER_ACCESS) && + (value != Group.GROUP_GROUP_ACCESS) && + (value != Group.GROUP_ANYUSER_ACCESS) ) { + throw new IllegalArgumentException( "Cannot set listMembership to " + + value ); + } else { + listMembership = value; + } + } + + /** + * Sets who can add members (pts adduser) to this group. + * Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @param value the value of the new list membership permission + * @exception AFSException if an invalid value is provided + */ + public void setListAdd( int value ) throws AFSException + { + if( (value != Group.GROUP_OWNER_ACCESS) && + (value != Group.GROUP_GROUP_ACCESS) && + (value != Group.GROUP_ANYUSER_ACCESS) ) { + throw new IllegalArgumentException( "Cannot set listAdd to " + value ); + } else { + listAdd = value; + } + } + + /** + * Sets who can delete members (pts removemember) from this group. + * Valid values are: + *
      + *
    • {@link #GROUP_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #GROUP_GROUP_ACCESS} + * -- only members of the group have permission
    • + *
    • {@link #GROUP_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @param value the value of the new list membership permission + * @exception AFSException if an invalid value is provided + */ + public void setListDelete( int value ) throws AFSException + { + if( (value != Group.GROUP_OWNER_ACCESS) && + (value != Group.GROUP_GROUP_ACCESS) && + (value != Group.GROUP_ANYUSER_ACCESS) ) { + throw new IllegalArgumentException( "Cannot set listDelete to " + + value ); + } else { + listDelete = value; + } + } + + /////////////// information methods //////////////////// + + /** + * Returns a String representation of this Group. + * Contains the information fields and members. + * + * @return a String representation of the Group + */ + protected String getInfo() + { + String r; + try { + r = "Group: " + getName() + ", uid: " + getUID() + "\n"; + r += "\towner: " + getOwner().getName() + ", uid: " + getOwner().getUID() + "\n"; + r += "\tcreator: " + getCreator().getName() + ", uid: " + + getCreator().getUID() + "\n"; + r += "\tMembership count: " + getMembershipCount() + "\n"; + r += "\tList status: " + getListStatus() + "\n"; + r += "\tList groups owned: " + getListGroupsOwned() + "\n"; + r += "\tList membership: " + getListMembership() + "\n"; + r += "\tAdd members: " + getListAdd() + "\n"; + r += "\tDelete members: " + getListDelete() + "\n"; + + r += "\tGroup members: \n"; + String names[] = getMemberNames(); + for( int i = 0; i < names.length; i++ ) { + r += "\t\t" + names[i] + "\n"; + } + + r += "\tOwns groups: \n"; + names = getGroupsOwnedNames(); + for( int i = 0; i < names.length; i++ ) { + r += "\t\t" + names[i] + "\n"; + } + return r; + } catch ( AFSException e ) { + return e.toString(); + } + } + + /////////////// custom override methods //////////////////// + + /** + * Compares two Group objects respective to their names and does not + * factor any other attribute. Alphabetic case is significant in + * comparing names. + * + * @param group The Group object to be compared to this Group instance + * + * @return Zero if the argument is equal to this Group's name, a + * value less than zero if this Group's name is + * lexicographically less than the argument, or a value greater + * than zero if this Group's name is lexicographically + * greater than the argument + */ + public int compareTo(Group group) + { + return this.getName().compareTo(group.getName()); + } + + /** + * Comparable interface method. + * + * @see #compareTo(Group) + */ + public int compareTo(Object obj) + { + return compareTo((Group)obj); + } + + /** + * Tests whether two Group objects are equal, based on their + * names. + * + * @param otherGroup the Group to test + * @return whether the specifed Group is the same as this Group + */ + public boolean equals( Group otherGroup ) + { + return name.equals( otherGroup.getName() ); + } + + /** + * Returns the name of this Group + * + * @return the name of this Group + */ + public String toString() + { + return getName(); + } + + /////////////// native methods //////////////////// + + /** + * Creates the PTS entry for a new group. Pass in 0 for the uid if PTS is to + * automatically assign the group id. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @param groupName the name of the group to create + * @param ownerName the owner of this group + * @param gid the group id to assign to the group (0 to have one + * automatically assigned) + * @exception AFSException If an error occurs in the native code + */ + protected static native void create( int cellHandle, String groupName, + String ownerName, int gid ) + throws AFSException; + + /** + * Deletes the PTS entry for a group. Deletes this group from the + * membership list of the users that belonged to it, but does not delete + * the groups owned by this group. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @param groupName the name of the group to delete + * @exception AFSException If an error occurs in the native code + */ + protected static native void delete( int cellHandle, String groupName ) + throws AFSException; + + /** + * Fills in the information fields of the provided Group. + * Fills in values based on the current PTS information of the group. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @param name the name of the group for which to get the information + * @param group the Group object in which to fill in the + * information + * @see Group + * @exception AFSException If an error occurs in the native code + */ + protected static native void getGroupInfo( int cellHandle, String name, + Group group ) + throws AFSException; + + /** + * Sets the information values of this AFS group to be the parameter values. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param name the name of the user for which to set the information + * @param theGroup the group object containing the desired information + * @exception AFSException If an error occurs in the native code + */ + protected static native void setGroupInfo( int cellHandle, String name, + Group theGroup ) + throws AFSException; + + /** + * Begin the process of getting the users that belong to the group. Returns + * an iteration ID to be used by subsequent calls to + * getGroupMembersNext and getGroupMembersDone. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @param name the name of the group for which to get the members + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getGroupMembersBegin( int cellHandle, + String name ) + throws AFSException; + + /** + * Returns the next members that belongs to the group. Returns + * null if there are no more members. + * + * @param iterationId the iteration ID of this iteration + * @see getGroupMembersBegin + * @return the name of the next member + * @exception AFSException If an error occurs in the native code + */ + protected static native String getGroupMembersNextString( int iterationId ) + throws AFSException; + + /** + * Fills the next user object belonging to that group. Returns 0 if there + * are no more users, != 0 otherwise. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @param iterationId the iteration ID of this iteration + * @see getGroupMembersBegin + * @param theUser a User object to be populated with the values of the + * next user + * @return 0 if there are no more users, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getGroupMembersNext( int cellHandle, + int iterationId, + User theUser ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see getGroupMembersBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getGroupMembersDone( int iterationId ) + throws AFSException; + + /** + * Adds a user to the specified group. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @param groupName the name of the group to which to add a member + * @param userName the name of the user to add + * @exception AFSException If an error occurs in the native code + */ + protected static native void addMember( int cellHandle, String groupName, + String userName ) + throws AFSException; + + /** + * Removes a user from the specified group. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @param groupName the name of the group from which to remove a + * member + * @param userName the name of the user to remove + * @exception AFSException If an error occurs in the native code + */ + protected static native void removeMember( int cellHandle, String groupName, + String userName ) + throws AFSException; + + /** + * Change the owner of the specified group. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @param groupName the name of the group of which to change the + * owner + * @param ownerName the name of the new owner + * @exception AFSException If an error occurs in the native code + */ + protected static native void changeOwner( int cellHandle, String groupName, + String ownerName ) + throws AFSException; + + /** + * Change the name of the specified group. + * + * @param cellHandle the handle of the cell to which the group belongs + * @see Cell#getCellHandle + * @param oldGroupName the old name of the group + * @param newGroupName the new name for the group + * @exception AFSException If an error occurs in the native code + */ + protected static native void rename( int cellHandle, String oldGroupName, + String newGroupName ) + throws AFSException; + + /** + * Reclaims all memory being saved by the group portion of the native + * library. + * This method should be called when no more Groups are expected + * to be used. + */ + protected static native void reclaimGroupMemory(); +} + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/Key.java b/src/JAVA/classes/org/openafs/jafs/Key.java new file mode 100644 index 0000000..ad20544 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/Key.java @@ -0,0 +1,467 @@ +/* + * @(#)Key.java 1.0 6/29/2001 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.GregorianCalendar; +import java.util.Date; +import java.io.Serializable; + +/** + * An abstract representation of an AFS key. It holds information about + * the key, such as what its version is. + *

    + * + * Constructing an instance of a Key does not mean an actual + * AFS key is created on a server -- usually a Key + * object is a representation of an already existing AFS key. If, + * however, the Key is constructed with the version number of a + * key that does not exist on the server represented by the provided + * Server, a new key with that version number can be + * created on that server by calling the {@link #create(String)} methods If + * such a key does already exist when this method is called, + * an exception will be thrown.

    + * + * + * The following is a simple example of how to construct and use a + * Key object. It obtains the list of Keys from + * a specified server, and prints the string representation of each key. + *
    + * import org.openafs.jafs.Cell;
    + * import org.openafs.jafs.AFSException;
    + * import org.openafs.jafs.Key;
    + * import org.openafs.jafs.Server;
    + * ...
    + * public class ...
    + * {
    + *   ...
    + *   private Cell cell;
    + *   private Server server;
    + *   ...
    + *   public static void main(String[] args) throws Exception
    + *   {
    + *     String username   = arg[0];
    + *     String password   = arg[1];
    + *     String cellName   = arg[2];
    + *     String serverName = arg[3];
    + * 
    + *     token = new Token(username, password, cellName);
    + *     cell   = new Cell(token);
    + *     server  = new Server(serverName, cell);
    + * 
    + *     System.out.println("Keys in Server " + server.getName() + ":");
    + *     Key[] keys = server.getKeys();
    + *     for (int i = 0; i < keys.length; i++) {
    + *       System.out.println(" -> " + keys[i] );
    + *     }
    + *   }
    + *   ...
    + * }
    + * 
    + * + */ +public class Key implements Serializable, Comparable +{ + protected Server server; + + protected int version; + protected long checkSum; + protected String encryptionKey; + protected int lastModDate; + protected int lastModMs; + + protected GregorianCalendar lastModDateDate; + + protected boolean cachedInfo; + + /** + * Constructs a new Key object instance given the version of + * the AFS key and the AFS server, represented by server, + * to which it belongs. This does not actually + * create a new AFS key, it just represents one. + * If version is not an actual AFS key, exceptions + * will be thrown during subsequent method invocations on this + * object, unless the {@link #create(String)} + * method is explicitly called to create it. + * + * @exception AFSException If an error occurs in the native code + * @param version the version of the key to represent + * @param server the server to which the key belongs. + */ + public Key( int version, Server server ) throws AFSException + { + this.server = server; + this.version = version; + + lastModDateDate = null; + + cachedInfo = false; + } + + /** + * Constructs a new Key object instance given the version of + * the AFS key and the AFS server, represented by server, + * to which it belongs. This does not actually + * create a new AFS key, it just represents one. + * If version is not an actual AFS key, exceptions + * will be thrown during subsequent method invocations on this + * object, unless the {@link #create(String)} + * method is explicitly called to create it. Note that if the key does not + * exist and preloadAllMembers is true, an exception will + * be thrown. + * + *

    This constructor is ideal for point-in-time representation and + * transient applications. It ensures all data member values are set and + * available without calling back to the filesystem at the first request + * for them. Use the {@link #refresh()} method to address any coherency + * concerns. + * + * @param version the version of the key to represent + * @param server the server to which the key belongs. + * @param preloadAllMembers true will ensure all object members are set + * upon construction; otherwise members will be + * set upon access, which is the default behavior. + * @exception AFSException If an error occurs in the native code + * @see #refresh + */ + public Key( int version, Server server, boolean preloadAllMembers ) + throws AFSException + { + this(version, server); + if (preloadAllMembers) refresh(true); + } + + /** + * Creates a blank Key given the server to which the key + * belongs. This blank object can then be passed into other methods to + * fill out its properties. + * + * @exception AFSException If an error occurs in the native code + * @param server the server to which the key belongs. + */ + Key( Server server ) throws AFSException + { + this( -1, server ); + } + + /*-------------------------------------------------------------------------*/ + + /** + * Refreshes the properties of this Key object instance with values from + * the AFS key it represents. All properties that have been initialized + * and/or accessed will be renewed according to the values of the AFS key + * this Key object instance represents. + * + *

    Since in most environments administrative changes can be administered + * from an AFS command-line program or an alternate GUI application, this + * method provides a means to refresh the Java object representation and + * thereby ascertain any possible modifications that may have been made + * from such alternate administrative programs. Using this method before + * an associated instance accessor will ensure the highest level of + * representative accuracy, accommodating changes made external to the + * Java application space. If administrative changes to the underlying AFS + * system are only allowed via this API, then the use of this method is + * unnecessary. + * + * @exception AFSException If an error occurs in the native code + */ + public void refresh() throws AFSException + { + refresh(false); + } + + /** + * Refreshes the properties of this Key object instance with values from + * the AFS key it represents. If all is true + * then all of the properties of this Key object instance will be + * set, or renewed, according to the values of the AFS key it represents, + * disregarding any previously set properties. + * + *

    Thus, if all is false then properties that + * are currently set will be refreshed and properties that are not set will + * remain uninitialized. See {@link #refresh()} for more information. + * + * @param all if true set or renew all object properties; otherwise renew + * all set properties + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + protected void refresh(boolean all) throws AFSException + { + if( all || cachedInfo ) { + refreshInfo(); + } + } + + /** + * Refreshes the information fields of this Key to reflect the + * current state of the AFS server key. These inlclude the last + * modification time, etc. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshInfo() throws AFSException + { + getKeyInfo( server.getBosHandle(), version, this ); + cachedInfo = true; + lastModDateDate = null; + } + + /** + * Creates a key with this Key's version number at the server, + * using the specified String for the key. + * + * @param keyString the string to use for the encryption key + * @exception AFSException If an error occurs in the native code + */ + public void create( String keyString ) throws AFSException + { + create( server.getCell().getCellHandle(), server.getBosHandle(), version, + keyString ); + } + + /** + * Removes the key with this Key's version number from + * the server. + * + * @exception AFSException If an error occurs in the native code + */ + public void delete( ) throws AFSException + { + delete( server.getBosHandle(), version ); + + encryptionKey = null; + cachedInfo = false; + } + + //////////////// accessors: //////////////////////// + + /** + * Returns the version of this key in primitive form. + * + * @return the version number of this key + */ + public int getVersion() + { + return version; + } + + /** + * Returns the server this key is associated with. + * + * @return this key's server + */ + public Server getServer() + { + return server; + } + + /** + * Returns the encrypted key as a string in octal form. This is how AFS + * prints it out on the command line. An example would be: + * '\040\205\211\241\345\002\023\211'. + * + * @return the encrypted key + * @exception AFSException If an error occurs in the native code + */ + public String getEncryptionKey() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return encryptionKey; + } + + /** + * Returns the check sum of this key. + * + * @return the check sum of this key + * @exception AFSException If an error occurs in the native code + */ + public long getCheckSum() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return checkSum; + } + + /** + * Returns the last modification date of this key. + * + * @return the last modification date of this key + * @exception AFSException If an error occurs in the native code + */ + public GregorianCalendar getLastModDate() throws AFSException + { + if (!cachedInfo) refreshInfo(); + if ( lastModDateDate == null && cachedInfo ) { + // make it into a date . . . + lastModDateDate = new GregorianCalendar(); + long longTime = ((long) lastModDate)*1000; + Date d = new Date( longTime ); + lastModDateDate.setTime( d ); + } + return lastModDateDate; + } + + /////////////// information methods //////////////////// + + /** + * Returns a String representation of this Key. + * Contains the information fields. + * + * @return a String representation of the Key + */ + protected String getInfo() + { + String r; + try { + r = "Key version number: " + getVersion() + "\n"; + r += "\tencrypted key: " + getEncryptionKey() + "\n"; + r += "\tcheck sum: " + getCheckSum() + "\n"; + r += "\tlast mod time: " + getLastModDate().getTime() + "\n"; + } catch( Exception e ) { + return e.toString(); + } + return r; + } + + /////////////// override methods //////////////////// + + /** + * Compares two Key objects respective to their key version and does not + * factor any other attribute. + * + * @param key The Key object to be compared to this Key instance + * + * @return Zero if the argument is equal to this Key's version, a + * value less than zero if this Key's version is less than + * the argument, or a value greater than zero if this Key's + * version is greater than the argument + */ + public int compareTo(Key key) + { + return (this.getVersion() - key.getVersion()); + } + + /** + * Comparable interface method. + * + * @see #compareTo(Key) + */ + public int compareTo(Object obj) + { + return compareTo((Key)obj); + } + + /** + * Tests whether two Key objects are equal, based on their + * encryption key, version, and associated Server. + * + * @param otherKey the Key to test + * @return whether the specifed Key is the same as this Key + */ + public boolean equals( Key otherKey ) + { + try { + return ( this.getEncryptionKey().equals(otherKey.getEncryptionKey()) ) && + ( this.getVersion() == otherKey.getVersion() ) && + ( this.getServer().equals(otherKey.getServer()) ); + } catch (Exception e) { + return false; + } + } + + /** + * Returns the name of this Key + * + * @return the name of this Key + */ + public String toString() + { + try { + return getVersion() + " - " + getEncryptionKey() + " - " + getCheckSum(); + } catch (Exception e) { + return e.toString(); + } + } + + /////////////// native methods //////////////////// + + /** + * Fills in the information fields of the provided Key. + * + * @param serverHandle the bos handle of the server to which the key + * belongs + * @see Server#getBosServerHandle + * @param version the version of the key for which to get the information + * @param key the Key object in which to fill in the + * information + * @see Server + * @exception AFSException If an error occurs in the native code + */ + protected static native void getKeyInfo( int serverHandle, int version, + Key key ) + throws AFSException; + + /** + * Create a server key. + * + * @param cellHandle the handle of the cell to which the server belongs + * @see Cell#getCellHandle + * @param serverHandle the bos handle of the server to which the key will + * belong + * @see Server#getBosServerHandle + * @param versionNumber the version number of the key to create (0 to 255) + * @param keyString the String version of the key that will + * be encrypted + * @exception AFSException If an error occurs in the native code + */ + protected static native void create( int cellHandle, int serverHandle, int versionNumber, String keyString ) + throws AFSException; + + /** + * Delete a server key. + * + * @param serverHandle the bos handle of the server to which the key belongs + * @see Server#getBosServerHandle + * @param versionNumber the version number of the key to remove (0 to 255) + * @exception AFSException If an error occurs in the native code + */ + protected static native void delete( int serverHandle, int versionNumber ) + throws AFSException; + + /** + * Reclaims all memory being saved by the key portion of the native library. + * This method should be called when no more Key objects are + * expected to be + * used. + */ + protected static native void reclaimKeyMemory(); + +} + + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/PTSEntry.java b/src/JAVA/classes/org/openafs/jafs/PTSEntry.java new file mode 100644 index 0000000..db3a291 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/PTSEntry.java @@ -0,0 +1,99 @@ +/* + * @(#)PTSEntry.java 1.2 10/23/2001 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +/** + * An interface representation of a PTS entry as it applies to + * AFS users and groups. This interface is implemented in both + * {@link User} and {@link Group} object abstractions. + *

    + * + * + * @version 1.0, 3/31/02 + * @see User + * @see Group + */ +public interface PTSEntry +{ + /** + * Constant for {@link User} object implementers, + * used with {@link #getType()} + */ + public static final short PTS_USER = 0; + /** + * Constant for {@link Group} object implementers, + * used with {@link #getType()} + */ + public static final short PTS_GROUP = 1; + /** + * Returns the Cell this PTS user or group belongs to. + * + * @return the Cell this PTS user or group belongs to + */ + public Cell getCell(); + /** + * Returns the creator of this PTS user or group. + * + * @return the creator of this PTS user or group + * @exception AFSException If an error occurs in the native code + */ + public PTSEntry getCreator() throws AFSException; + /** + * Returns the name of this PTS user or group. + * + * @return the name of this PTS user or group + */ + public String getName(); + /** + * Returns the owner of this PTS user or group. + * + * @return the owner of this PTS user or group + * @exception AFSException If an error occurs in the native code + */ + public PTSEntry getOwner() throws AFSException; + /** + * Returns the type of PTS entry the implementing object represents. + * + *

    Possible values are:
    + *

      + *
    • {@link #PTS_USER} + * -- a {@link User} object
    • + *
    • {@link #PTS_GROUP} + * -- a {@link Group} object
    • + *
    + * + * @return the name of this PTS user or group + */ + public short getType(); + /** + * Returns the numeric AFS id of this user or group. + * + * @return the AFS id of this user/group + * @exception AFSException If an error occurs in the native code + */ + public int getUID() throws AFSException; +} + + + diff --git a/src/JAVA/classes/org/openafs/jafs/Partition.java b/src/JAVA/classes/org/openafs/jafs/Partition.java new file mode 100644 index 0000000..98b0adc --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/Partition.java @@ -0,0 +1,1052 @@ +/* + * @(#)Partition.java 1.0 6/29/2001 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.io.Serializable; +import java.util.ArrayList; + +/** + * An abstract representation of an AFS partition. It holds information about + * the partition, such as what its total space is. + *

    + * + * Constructing an instance of a Partition does not mean + * an actual AFS partition is created on a server -- on the contrary, + * a Partition object must be a representation of an already + * existing AFS partition. There is no way to create a new AFS partition + * through this API.

    + * + * Each Partition object has its own individual set of + * Volumes. This represents the properties and attributes + * of an actual AFS cell.

    + * + * + * The following is a simple example of how to obtain and use a + * Partition object. In this example, a list of the + * Partition objects of a server are obtained, and the name + * and number of volumes is printed out for each one.

    + * + *
    + * import org.openafs.jafs.Cell;
    + * import org.openafs.jafs.AFSException;
    + * import org.openafs.jafs.Partition;
    + * import org.openafs.jafs.Server;
    + * ...
    + * public class ...
    + * {
    + *   ...
    + *   private Cell cell;
    + *   private Server server;
    + *   ...
    + *   public static void main(String[] args) throws Exception
    + *   {
    + *     String username   = arg[0];
    + *     String password   = arg[1];
    + *     String cellName   = arg[2];
    + *     String serverName = arg[3];
    + * 
    + *     token = new Token(username, password, cellName);
    + *     cell   = new Cell(token);
    + *     server = new Server(serverName, cell);
    + * 
    + *     System.out.println("Partitions in Server " + server.getName() + ":");
    + *     Partition[] partitions = server.getPartitions();
    + *     for (int i = 0; i < partitions.length; i++) {
    + *       System.out.print("Partition " + partitions[i].getName());
    + *       System.out.print("hosts " + partitions[i].getVolumeCount());
    + *       System.out.print("volumes.\n");
    + *     }
    + *   }
    + *   ...
    + * }
    + * 
    + * + */ +public class Partition implements Serializable, Comparable +{ + protected Cell cell; + protected Server server; + + /* Populated by native method */ + protected String name; + + /* Populated by native method */ + protected int id; + + /* Populated by native method */ + protected String deviceName; + + /* Populated by native method */ + protected int lockFileDescriptor; + + /* Populated by native method */ + protected int totalSpace; + + /* Populated by native method */ + protected int totalFreeSpace; + + protected int totalQuota; + + protected ArrayList volumes; + protected ArrayList volumeNames; + + protected boolean cachedInfo; + + /** + * Constructs a new Partition object instance given the + * name of the AFS partition and the AFS server, represented by + * server, to which it belongs. This does not actually + * create a new AFS partition, it just represents an existing one. + * If name is not an actual AFS partition, exceptions + * will be thrown during subsequent method invocations on this + * object. + * + * @param name the name of the partition to represent + * @param server the server on which the partition resides + * @exception AFSException If an error occurs in the native code + */ + public Partition( String name, Server server ) throws AFSException + { + this.name = name; + this.server = server; + this.cell = server.getCell(); + + id = -1; + + volumes = null; + volumeNames = null; + + cachedInfo = false; + } + + /** + * Constructs a new Partition object instance given the name + * of the AFS partition and the AFS server, represented by + * server, to which it belongs. This does not actually + * create a new AFS partition, it just represents an existing one. + * If name is not an actual AFS partition, exceptions + * will be thrown during subsequent method invocations on this + * object. + * + *

    This constructor is ideal for point-in-time representation and + * transient applications. It ensures all data member values are set and + * available without calling back to the filesystem at the first request + * for them. Use the {@link #refresh()} method to address any coherency + * concerns. + * + * @param name the name of the partition to represent + * @param server the server to which the partition belongs. + * @param preloadAllMembers true will ensure all object members are + * set upon construction; + * otherwise members will be set upon access, + * which is the default behavior. + * @exception AFSException If an error occurs in the native code + * @see #refresh + */ + public Partition( String name, Server server, boolean preloadAllMembers ) + throws AFSException + { + this(name, server); + if (preloadAllMembers) refresh(true); + } + + /** + * Creates a blank Server given the cell to which the partition + * belongs and the server on which the partition resides. This blank + * object can then be passed into other methods to fill out its properties. + * + * @exception AFSException If an error occurs in the native code + * @param cell the cell to which the partition belongs. + * @param server the server on which the partition resides + */ + Partition( Server server ) throws AFSException + { + this( null, server ); + } + + /*-------------------------------------------------------------------------*/ + + /** + * Refreshes the properties of this Partition object instance with values + * from the AFS partition + * it represents. All properties that have been initialized and/or + * accessed will be renewed according to the values of the AFS partition + * this Partition object instance represents. + * + *

    Since in most environments administrative changes can be administered + * from an AFS command-line program or an alternate GUI application, this + * method provides a means to refresh the Java object representation and + * thereby ascertain any possible modifications that may have been made + * from such alternate administrative programs. Using this method before + * an associated instance accessor will ensure the highest level of + * representative accuracy, accommodating changes made external to the + * Java application space. If administrative changes to the underlying AFS + * system are only allowed via this API, then the use of this method is + * unnecessary. + * + * @exception AFSException If an error occurs in the native code + */ + public void refresh() throws AFSException + { + refresh(false); + } + + /** + * Refreshes the properties of this Partition object instance with values + * from the AFS partition it represents. If all is + * true then all of the properties of this Partition + * object instance will be set, or renewed, according to the values of the + * AFS partition it represents, disregarding any previously set properties. + * + *

    Thus, if all is false then properties + * that are currently set will be refreshed and properties that are not + * set will remain uninitialized. See {@link #refresh()} for more + * information. + * + * @param all if true set or renew all object properties; otherwise + * renew all set properties + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + protected void refresh(boolean all) throws AFSException + { + if (all || volumes != null) { + refreshVolumes(); + } + if (all || volumeNames != null) { + refreshVolumeNames(); + } + if (all || cachedInfo) { + refreshInfo(); + } + } + + /** + * Refreshes the information fields of this Partition to + * reflect the current state of the AFS partition. These include total + * free space, id, etc. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshInfo() throws AFSException + { + getPartitionInfo( cell.getCellHandle(), server.getVosHandle(), getID(), + this ); + cachedInfo = true; + } + + /** + * Obtains the most current list of Volume objects of this + * partition. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshVolumes() throws AFSException + { + Volume currVolume; + + int iterationID = getVolumesBegin( cell.getCellHandle(), + server.getVosHandle(), getID() ); + + volumes = new ArrayList(); + + currVolume = new Volume( this ); + while( getVolumesNext( iterationID, currVolume ) != 0 ) { + volumes.add( currVolume ); + currVolume = new Volume( this ); + } + getVolumesDone( iterationID ); + } + + /** + * Obtains the most current list of volume names of this partition. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshVolumeNames() throws AFSException + { + String currName; + + int iterationID = getVolumesBegin( cell.getCellHandle(), + server.getVosHandle(), getID() ); + + volumeNames = new ArrayList(); + + while( ( currName = getVolumesNextString( iterationID ) ) != null ) { + volumeNames.add( currName ); + } + getVolumesDone( iterationID ); + } + + /** + * Syncs this partition to the VLDB. + * + * @exception AFSException If an error occurs in the native code + */ + public void syncPartition() throws AFSException + { + server.syncServerWithVLDB( cell.getCellHandle(), server.getVosHandle(), + getID() ); + } + + /** + * Syncs the VLDB to this partition. + * + * @exception AFSException If an error occurs in the native code + */ + public void syncVLDB() throws AFSException + { + server.syncVLDBWithServer( cell.getCellHandle(), server.getVosHandle(), + getID(), false ); + } + + /** + * Salvages (restores consistency to) this partition. Uses default values for + * most salvager options in order to simplify the API. + * + * @exception AFSException If an error occurs in the native code + */ + public void salvage() throws AFSException + { + server.salvage( cell.getCellHandle(), server.getBosHandle(), name, null, + 4, null, null, false, false, false, false, false, false ); + } + + //////////////// accessors: //////////////////////// + + /** + * Returns the name of this partition. + * + * @return the name of this partition + */ + public String getName() + { + return name; + } + + /** + * Returns this partition's hosting server. + * + * @return this partition's server + */ + public Server getServer() + { + return server; + } + + /** + * Returns the number of volumes contained in this partition. + * + *

    If the total list of volumes or volume names have already been + * collected (see {@link #getVolumes()}), then the returning value will + * be calculated based upon the current list. Otherwise, AFS will be + * explicitly queried for the information. + * + *

    The product of this method is not saved, and is recalculated + * with every call. + * + * @return the number of volumes contained in this partition. + * @exception AFSException If an error occurs in any + * of the associated native methods + */ + public int getVolumeCount() throws AFSException + { + if (volumes != null) { + return volumes.size(); + } else if (volumeNames != null) { + return volumeNames.size(); + } else { + return getVolumeCount( cell.getCellHandle(), + server.getVosHandle(), getID() ); + } + } + + /** + * Retrieves the Volume object (which is an abstract + * representation of an actual AFS volume of this partition) designated + * by name (i.e. "root.afs", etc.). If a volume by + * that name does not actually exist in AFS on the partition + * represented by this object, an {@link AFSException} will be + * thrown. + * + * @exception AFSException If an error occurs in the native code + * @exception NullPointerException If name is + * null. + * @param name the name of the volume to retrieve + * @return Volume designated by name. + */ + public Volume getVolume(String name) throws AFSException + { + if (name == null) throw new NullPointerException(); + Volume volume = new Volume(name, this); + return volume; + } + + /** + * Retrieves an array containing all of the Volume objects + * associated with this Partition, each of which is an + * abstract representation of an actual AFS volume of the AFS partition. + * After this method is called once, it saves the array of + * Volumes and returns that saved array on subsequent calls, + * until the {@link #refresh()} method is called and a more current list + * is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return a Volume array of the Volume + * objects of the partition. + * @see #refresh() + */ + public Volume[] getVolumes() throws AFSException + { + if (volumes == null) refreshVolumes(); + return (Volume[]) volumes.toArray( new Volume[volumes.size()] ); + } + + /** + * Returns an array containing a subset of the Volume objects + * associated with this Partition, each of which is an abstract + * representation of an actual AFS volume of the AFS partition. The subset + * is a point-in-time list of volumes (Volume objects + * representing AFS volumes) starting at the complete array's index of + * startIndex and containing up to length + * elements. + * + * If length is larger than the number of remaining elements, + * respective to startIndex, then this method will + * ignore the remaining positions requested by length and + * return an array that contains the remaining number of elements found in + * this partition's complete array of volumes. + * + *

    This method is especially useful when managing iterations of very + * large lists. {@link #getVolumeCount()} can be used to determine if + * iteration management is practical. + * + *

    This method does not save the resulting data and therefore + * queries AFS for each call. + * + *

    Example: If there are more than 50,000 volumes within this partition + * then only render them in increments of 10,000. + *

    +   * ...
    +   *   Volume[] volumes;
    +   *   if (partition.getVolumeCount() > 50000) {
    +   *     int index = 0;
    +   *     int length = 10000;
    +   *     while (index < partition.getVolumeCount()) {
    +   *       volumes = partition.getVolumes(index, length);
    +   *       for (int i = 0; i < volumes.length; i++) {
    +   *         ...
    +   *       }
    +   *       index += length;
    +   *       ...
    +   *     }
    +   *   } else {
    +   *     volumes = partition.getVolumes();
    +   *     for (int i = 0; i < volumes.length; i++) {
    +   *       ...
    +   *     }
    +   *   }
    +   * ...
    +   * 
    + * + * @param startIndex the base zero index position at which the subset array + * should start from, relative to the complete list of + * elements present in AFS. + * @param length the number of elements that the subset should contain + * @return a subset array of volumes hosted by this partition + * @exception AFSException If an error occurs in the native code + * @see #getVolumeCount() + * @see #getVolumeNames(int, int) + * @see #getVolumes() + */ + public Volume[] getVolumes(int startIndex, int length) throws AFSException + { + Volume[] volumes = new Volume[length]; + Volume currVolume = new Volume( this ); + int i = 0; + + int iterationID = getVolumesBeginAt( cell.getCellHandle(), + server.getVosHandle(), getID(), startIndex ); + + while( getVolumesNext( iterationID, currVolume ) != 0 && i < length ) { + volumes[i] = currVolume; + currVolume = new Volume( this ); + i++; + } + getVolumesDone( iterationID ); + if (i < length) { + Volume[] v = new Volume[i]; + System.arraycopy(volumes, 0, v, 0, i); + return v; + } else { + return volumes; + } + } + + /** + * Retrieves an array containing all of the names of volumes + * associated with this Partition. + * After this method is called once, it saves the array of + * Strings and returns that saved array on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * list is obtained. + * + * @return a String array of the volumes of the partition. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public String[] getVolumeNames() throws AFSException + { + if (volumeNames == null) refreshVolumeNames(); + return (String []) volumeNames.toArray( new String[volumeNames.size() ] ); + } + + /** + * Returns an array containing a subset of the names of volumes + * associated with this Partition. The subset is a + * point-in-time list of volume names starting at the complete array's + * index of startIndex and containing up to length + * elements. + * + * If length is larger than the number of remaining elements, + * respective to startIndex, then this method will + * ignore the remaining positions requested by length and + * return an array that contains the remaining number of elements found in + * this partition's complete array of volume names. + * + *

    This method is especially useful when managing iterations of very + * large lists. {@link #getVolumeCount()} can be used to determine if + * iteration management is practical. + * + *

    This method does not save the resulting data and therefore + * queries AFS for each call. + * + *

    Example: If there are more than 50,000 volumes within this partition + * then only render them in increments of 10,000. + *

    +   * ...
    +   *   String[] volumes;
    +   *   if (partition.getVolumeCount() > 50000) {
    +   *     int index = 0;
    +   *     int length = 10000;
    +   *     while (index < partition.getVolumeCount()) {
    +   *       volumes = partition.getVolumeNames(index, length);
    +   *       for (int i = 0; i < volumes.length; i++) {
    +   *         ...
    +   *       }
    +   *       index += length;
    +   *       ...
    +   *     }
    +   *   } else {
    +   *     volumes = partition.getVolumeNames();
    +   *     for (int i = 0; i < volumes.length; i++) {
    +   *       ...
    +   *     }
    +   *   }
    +   * ...
    +   * 
    + * + * @param startIndex the base zero index position at which the subset array + * should start from, relative to the complete list of + * elements present in AFS. + * @param length the number of elements that the subset should contain + * @return a subset array of volume names hosted by this partition + * @exception AFSException If an error occurs in the native code + * @see #getVolumeCount() + * @see #getVolumes(int, int) + * @see #getVolumes() + */ + public String[] getVolumeNames(int startIndex, int length) throws AFSException + { + String[] volumes = new String[length]; + String currName; + int i = 0; + + int iterationID = getVolumesBeginAt( cell.getCellHandle(), + server.getVosHandle(), getID(), startIndex ); + + while( ( currName = getVolumesNextString( iterationID ) ) != null && i < length ) { + volumes[i] = currName; + i++; + } + getVolumesDone( iterationID ); + if (i < length) { + String[] v = new String[i]; + System.arraycopy(volumes, 0, v, 0, i); + return v; + } else { + return volumes; + } + } + + /** + * Returns the id of this partition (i.e. "vicepa" = 0, etc.) + * + * @exception AFSException If an error occurs in the native code + * @return the id of this partition + */ + public int getID() throws AFSException + { + if (id == -1) id = translateNameToID( name ); + return id; + } + + /** + * Returns the device name of this partition (i.e. "hda5", etc.) + * + * @exception AFSException If an error occurs in the native code + * @return the device name of this partition + * @see #refresh() + */ + public String getDeviceName() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return deviceName; + } + + /** + * Returns the lock file descriptor of this partition + * + * @exception AFSException If an error occurs in the native code + * @return the lock file descriptor of this partition + * @see #refresh() + */ + public int getLockFileDescriptor() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return lockFileDescriptor; + } + + /** + * Returns the total space on this partition. + * + * @exception AFSException If an error occurs in the native code + * @return the total space on this partition + * @see #refresh() + */ + public int getTotalSpace() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return totalSpace; + } + + /** + * Returns the total free space on this partition. + * After this method is called once, it saves the total free space + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return the total free space on this partition + * @see #refresh() + */ + public int getTotalFreeSpace() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return totalFreeSpace; + } + + /** + * Returns the total used space on this partition. + * After this method is called once, it saves the total used space + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return the total used space on this partition + * @see #refresh() + */ + public int getUsedSpace() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return (totalSpace - totalFreeSpace); + } + + /** + * Returns the total combined quota of all volumes on this partition, + * unless a volume has configured an unlimited quota at which case an + * {@link AFSException} is thrown. + * + *

    After this method is called once, it saves the value and returns + * that value on subsequent calls, until the {@link #refresh()} + * method is called and a more current value is obtained. + * + * @exception AFSException If an error occurs while retrieving and + * calculating, or a volume has an + * unlimited quota. + * @return the total combined quota of all volumes on this partition + * @see #getTotalQuota(boolean) + * @see #hasVolumeWithUnlimitedQuota() + * @see Volume#getQuota() + */ + public int getTotalQuota() throws AFSException + { + return getTotalQuota(false); + } + + /** + * Returns the total combined quota of all volumes on this partition, + * ignoring volumes with unlimited quotas, if + * ignoreUnlimitedQuotas is true; otherwise an + * {@link AFSException} is thrown if a volume has an unlimited quota. + * + *

    After this method is called once, it saves the value and returns + * that value on subsequent calls, until the {@link #refresh()} + * method is called and a more current value is obtained. + * + * @exception AFSException If an error occurs while retrieving and + * calculating, or a volume has an + * unlimited quota. + * @return the total combined quota of all volumes on this partition + * @see #getTotalQuota() + * @see #hasVolumeWithUnlimitedQuota() + * @see Volume#getQuota() + * @see #refresh() + */ + public int getTotalQuota(boolean ignoreUnlimitedQuotas) + throws AFSException + { + if (volumes == null) refreshVolumes(); + if (totalQuota == 0 || !ignoreUnlimitedQuotas) { + Volume[] volumes = getVolumes(); + for (int i = 0; i < volumes.length; i++) { + try { + totalQuota += volumes[i].getQuota(); + } catch (AFSException e) { + if (!ignoreUnlimitedQuotas) { + totalQuota = 0; + throw e; + } + } + } + } + return totalQuota; + } + + /** + * Tests whether this partition contains a volume that has an unlimited + * quota configured. + * + * @exception AFSException If an error occurs in the native code + * @return true if a contained volume's quota is configured + * as unlimited; otherwise false. + * @see #getTotalQuota() + * @see #getTotalQuota(boolean) + * @see Volume#isQuotaUnlimited() + * @see Volume#getQuota() + * @see #refresh() + */ + public boolean hasVolumeWithUnlimitedQuota() throws AFSException + { + if (volumes == null) refreshVolumes(); + Volume[] volumes = getVolumes(); + for (int i = 0; i < volumes.length; i++) { + if (volumes[i].isQuotaUnlimited()) return true; + } + return false; + } + + /////////////// custom information methods //////////////////// + + /** + * Returns a String representation of this + * Partition. Contains the information fields and a list of + * volumes. + * + * @return a String representation of the Partition + */ + protected String getInfo() + { + String r; + + try { + + r = "Partition: " + name + "\tid: " + getID() + "\n"; + + r += "\tDevice name: " + getDeviceName() + "\n"; + r += "\tLock file descriptor: " + getLockFileDescriptor() + "\n"; + r += "\tTotal free space: " + getTotalFreeSpace() + " K\n"; + r += "\tTotal space: " + getTotalSpace() + " K\n"; + + r += "\tVolumes:\n"; + + String vols[] = getVolumeNames(); + + for( int i = 0; i < vols.length; i++ ) { + r += "\t\t" + vols[i] + "\n"; + } + + } catch( Exception e ) { + return e.toString(); + } + return r; + } + + /** + * Returns a String containing the String + * representations of all the volumes of this Partition. + * + * @return a String representation of the volumes + * @see Volume#getInfo + */ + protected String getInfoVolumes() throws AFSException + { + String r; + + r = "Partition: " + name + "\n\n"; + r += "--Volumes--\n"; + + Volume vols[] = getVolumes(); + for( int i = 0; i < vols.length; i++ ) { + r += vols[i].getInfo() + "\n"; + } + return r; + } + + /////////////// custom override methods //////////////////// + + /** + * Compares two Partition objects respective to their names and does not + * factor any other attribute. Alphabetic case is significant in + * comparing names. + * + * @param partition The Partition object to be compared to + * this Partition instance + * + * @return Zero if the argument is equal to this Partition's name, a + * value less than zero if this Partition's name is + * lexicographically less than the argument, or a value greater + * than zero if this Partition's name is lexicographically + * greater than the argument + */ + public int compareTo(Partition partition) + { + return this.getName().compareTo(partition.getName()); + } + + /** + * Comparable interface method. + * + * @see #compareTo(Partition) + */ + public int compareTo(Object obj) + { + return compareTo((Partition)obj); + } + + /** + * Tests whether two Partition objects are equal, + * based on their names and hosting server. + * + * @param otherPartition the Partition to test + * @return whether the specifed Partition is the same as this Partition + */ + public boolean equals( Partition otherPartition ) + { + return ( name.equals(otherPartition.getName()) ) && + ( getServer().equals(otherPartition.getServer()) ); + } + + /** + * Returns the name of this Partition + * + * @return the name of this Partition + */ + public String toString() + { + return getName(); + } + + /////////////// native methods //////////////////// + + /** + * Fills in the information fields of the provided Partition. + * + * @param cellHandle the handle of the cell to which the partition belongs + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server on which the + * partition resides + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition for which to get the + * info + * @param thePartition the {@link Partition Partition} object in which to + * fill in the information + * @exception AFSException If an error occurs in the native code + */ + protected static native void getPartitionInfo( int cellHandle, + int serverHandle, + int partition, + Partition thePartition ) + throws AFSException; + + /** + * Returns the total number of volumes hosted by this partition. + * + * @param cellHandle the handle of the cell to which the partition belongs + * @param serverHandle the vos handle of the server to which the partition + * belongs + * @param partition the numeric id of the partition on which the volumes + * reside + * @return total number of volumes hosted by this partition + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + * @see Server#getVosServerHandle + */ + protected static native int getVolumeCount( int cellHandle, + int serverHandle, + int partition ) + throws AFSException; + + /** + * Begin the process of getting the volumes on a partition. Returns + * an iteration ID to be used by subsequent calls to + * getVolumesNext and getVolumesDone. + * + * @param cellHandle the handle of the cell to which the partition belongs + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server to which the partition + * belongs + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the volumes + * reside + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getVolumesBegin( int cellHandle, + int serverHandle, + int partition ) + throws AFSException; + + /** + * Begin the process of getting the volumes on a partition. Returns + * an iteration ID to be used by subsequent calls to + * getVolumesNext and getVolumesDone. + * + * @param cellHandle the handle of the cell to which the partition belongs + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server to which the partition + * belongs + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the volumes + * reside + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getVolumesBeginAt( int cellHandle, + int serverHandle, + int partition, int index ) + throws AFSException; + + /** + * Returns the next volume of the partition. Returns null + * if there are no more volumes. + * + * @param iterationId the iteration ID of this iteration + * @see #getVolumesBegin + * @return the name of the next volume of the server + * @exception AFSException If an error occurs in the native code + */ + protected static native String getVolumesNextString( int iterationId ) + throws AFSException; + + /** + * Fills the next volume object of the partition. Returns 0 if there + * are no more volumes, != 0 otherwise. + * + * @param iterationId the iteration ID of this iteration + * @param theVolume the Volume object in which to fill the values + * of the next volume + * @see #getVolumesBegin + * @return 0 if there are no more volumes, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getVolumesNext( int iterationId, + Volume theVolume ) + throws AFSException; + + /** + * Fills the next volume object of the partition. Returns 0 if there + * are no more volumes, != 0 otherwise. + * + * @param iterationId the iteration ID of this iteration + * @param theVolume the Volume object in which to fill the values of the + * next volume + * @see #getVolumesBegin + * @return 0 if there are no more volumes, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getVolumesAdvanceTo( int iterationId, + Volume theVolume, + int advanceCount ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see #getVolumesBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getVolumesDone( int iterationId ) + throws AFSException; + + /** + * Translates a partition name into a partition id + * + * @param name the name of the partition in question + * @return the id of the partition in question + * @exception AFSException If an error occurs in the native code + */ + protected static native int translateNameToID( String name ) + throws AFSException; + + /** + * Translates a partition id into a partition name + * + * @param id the id of the partition in question + * @return the name of the partition in question + * @exception AFSException If an error occurs in the native code + */ + protected static native String translateIDToName( int id ) + throws AFSException; + + /** + * Reclaims all memory being saved by the partition portion of the native + * library. This method should be called when no more Partition + * objects are expected to be + * used. + */ + protected static native void reclaimPartitionMemory(); +} + + + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/Process.java b/src/JAVA/classes/org/openafs/jafs/Process.java new file mode 100644 index 0000000..b006db3 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/Process.java @@ -0,0 +1,953 @@ +/* + * @(#)Process.java 1.0 6/29/2001 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.GregorianCalendar; +import java.util.Date; +import java.io.Serializable; + +/** + * An abstract representation of an AFS process. It holds information about + * the server, such as what its state is. + *

    + * + * Constructing an instance of a Process does not mean an actual + * AFS process is created on a server -- usually a Process + * object is a representation of an already existing AFS process. If, + * however, the Process is constructed with the name of a + * process that does not exist in the server represented by the provided + * Server, a new process with that name can be + * created on that server by calling one of the {@link #createSimple(String)}, + * {@link #createFS(String)}, or {@link #createCron(String,String)} methods. If + * such a process does already exist when one of these methods are called, + * an exception will be thrown.

    + * + * + * + * + * The following is a simple example of how to construct and use a + * Process object. This example obtains the list of all + * Process objects on a particular server and prints out the + * name of each one along with its start time.

    + * + *

    + * import org.openafs.jafs.Cell;
    + * import org.openafs.jafs.AFSException;
    + * import org.openafs.jafs.Process;
    + * import org.openafs.jafs.Server;
    + * ...
    + * public class ...
    + * {
    + *   ...
    + *   private Cell cell;
    + *   private Server server;
    + *   ...
    + *   public static void main(String[] args) throws Exception
    + *   {
    + *     String username   = arg[0];
    + *     String password   = arg[1];
    + *     String cellName   = arg[2];
    + *     String serverName = arg[3];
    + * 
    + *     token = new Token(username, password, cellName);
    + *     cell   = new Cell(token);
    + *     server = new Server(serverName, cell);
    + * 
    + *     System.out.println("Processes in Server " + server.getName() + ":");
    + *     Process[] processes = server.getProcesss();
    + *     for (int i = 0; i < processes.length; i++) {
    + *       System.out.print("Process " + processes[i].getName());
    + *       System.out.print("was started: " + 
    + *                        processes[i].getStartTimeDate().getTime() + "\n");
    + *     }
    + *   }
    + *   ...
    + * }
    + * 
    + * + */ +public class Process implements Serializable, Comparable +{ + /** + * Any standard type of process except for fs (such as kaserver, + * upclientbin, etc.) + */ + public static final int SIMPLE_PROCESS = 0; + + /** + * Combination of File Server, Volume Server, and Salvager processes + */ + public static final int FS_PROCESS = 1; + + /** + * A process that should be restarted at a specific time either daily + * or weekly. + */ + public static final int CRON_PROCESS = 2; + + /** + * Process execution state stopped + */ + public static final int STOPPED = 0; + + /** + * Process execution state running + */ + public static final int RUNNING = 1; + + /** + * Process execution state stopping + */ + public static final int STOPPING = 2; + + /** + * Process execution state starting + */ + public static final int STARTING = 3; + + protected String name; + protected Server server; + protected int serverHandle; + + protected int type; + protected int state; + protected int goal; + + protected long startTime; + protected long numberStarts; + protected long exitTime; + protected long exitErrorTime; + protected long errorCode; + protected long errorSignal; + + protected boolean stateOk; + protected boolean stateTooManyErrors; + protected boolean stateBadFileAccess; + + protected GregorianCalendar startTimeDate; + protected GregorianCalendar exitTimeDate; + protected GregorianCalendar exitErrorTimeDate; + + protected boolean cachedInfo; + + /** + * Constructs a new Process object instance given the name + * of the AFS process and the AFS server, represented by + * server, to which it belongs. This does not actually + * create a new AFS process, it just represents one. + * If name is not an actual AFS process, exceptions + * will be thrown during subsequent method invocations on this + * object, unless one of the {@link #createSimple(String)}, + * {@link #createFS(String)}, or {@link #createCron(String,String)} + * methods are explicitly called to create it. + * + * @param name the name of the server to represent + * @param server the server on which the process resides + * @exception AFSException If an error occurs in the native code + */ + public Process( String name, Server server ) throws AFSException + { + this.name = name; + this.server = server; + serverHandle = server.getBosHandle(); + + startTimeDate = null; + exitTimeDate = null; + exitErrorTimeDate = null; + + cachedInfo = false; + } + + /** + * Constructs a new Process object instance given the name + * of the AFS process and the AFS server, represented by + * server, to which it belongs. This does not actually + * create a new AFS process, it just represents one. + * If name is not an actual AFS process, exceptions + * will be thrown during subsequent method invocations on this + * object, unless one of the {@link #createSimple(String)}, + * {@link #createFS(String)}, or {@link #createCron(String,String)} + * methods are explicitly called to create it. Note that if he process + * doesn't exist and preloadAllMembers is true, an exception + * will be thrown. + * + *

    This constructor is ideal for point-in-time representation and + * transient applications. It ensures all data member values are set and + * available without calling back to the filesystem at the first request + * for them. Use the {@link #refresh()} method to address any coherency + * concerns. + * + * @param name the name of the process to represent + * @param server the server to which the process belongs. + * @param preloadAllMembers true will ensure all object members are + * set upon construction; otherwise members will + * be set upon access, which is the default + * behavior. + * @exception AFSException If an error occurs in the native code + * @see #refresh + */ + public Process( String name, Server server, boolean preloadAllMembers ) + throws AFSException + { + this(name, server); + if (preloadAllMembers) refresh(true); + } + + /** + * Creates a blank Process given the server to which the process + * belongs. This blank object can then be passed into other methods to fill + * out its properties. + * + * @param server the server to which the process belongs. + * @exception AFSException If an error occurs in the native code + */ + Process( Server server ) throws AFSException + { + this( null, server ); + } + + /*-------------------------------------------------------------------------*/ + + /** + * Refreshes the properties of this Process object instance with values + * from the AFS process it represents. All properties that have been + * initialized and/or accessed will be renewed according to the values of + * the AFS process this Process object instance represents. + * + *

    Since in most environments administrative changes can be administered + * from an AFS command-line program or an alternate GUI application, this + * method provides a means to refresh the Java object representation and + * thereby ascertain any possible modifications that may have been made + * from such alternate administrative programs. Using this method before + * an associated instance accessor will ensure the highest level of + * representative accuracy, accommodating changes made external to the + * Java application space. If administrative changes to the underlying AFS + * system are only allowed via this API, then the use of this method is + * unnecessary. + * + * @exception AFSException If an error occurs in the native code + */ + public void refresh() throws AFSException + { + refresh(false); + } + + /** + * Refreshes the properties of this Process object instance with values from + * the AFS process it represents. If all is true + * then all of the properties of this Process object instance will be + * set, or renewed, according to the values of the AFS process it represents, + * disregarding any previously set properties. + * + *

    Thus, if all is false then properties that + * are currently set will be refreshed and properties that are not set will + * remain uninitialized. See {@link #refresh()} for more information. + * + * @param all if true set or renew all object properties; otherwise renew + * all set properties + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + protected void refresh(boolean all) throws AFSException + { + if (all || cachedInfo) refreshInfo(); + } + + /** + * Refreshes the information fields of this Process to reflect + * the current state of the AFS process, such as the start time, the state, + * etc. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshInfo() throws AFSException + { + getProcessInfo( server.getBosHandle(), name, this ); + cachedInfo = true; + startTimeDate = null; + exitTimeDate = null; + exitErrorTimeDate = null; + } + + /** + * Creates this process as a simple process on the server. + * + * @param executionPath the path to the process's executable + * @exception AFSException If an error occurs in the native code + */ + public void createSimple( String executionPath ) throws AFSException + { + create( server.getBosHandle(), name, SIMPLE_PROCESS, executionPath, null, + null ); + } + + /** + * Creates this process as a file server process on the server. + * + * @param executionPath the path to the process's executable + * @exception AFSException If an error occurs in the native code + */ + public void createFS( String executionPath ) throws AFSException + { + create( server.getBosHandle(), name, FS_PROCESS, executionPath, null, + null ); + } + + /** + * Creates this process as a cron process on the server. + * + * @param executionPath the path to the process's executable + * @param cronTime a String representing the time a cron process is + * to be run. Acceptable formats are:

      + *
    • for daily restarts: "23:10" or "11:10 pm"
    • + *
    • for weekly restarts: "sunday 11:10pm" or + * "sun 11:10pm"
    • + *
    + * @exception AFSException If an error occurs in the native code + */ + public void createCron( String executionPath, String cronTime ) + throws AFSException + { + create( server.getBosHandle(), name, CRON_PROCESS, executionPath, + cronTime, null ); + } + + /** + * Removes this process from the bos server + * + * @exception AFSException If an error occurs in the native code + */ + public void delete() throws AFSException + { + delete( server.getBosHandle(), name ); + } + + /** + * Stops this process. + * + * @exception AFSException If an error occurs in the native code + */ + public void stop() throws AFSException + { + state = STOPPING; + goal = STOPPED; + stop( server.getBosHandle(), name ); + } + + /** + * Starts this process + * + * @exception AFSException If an error occurs in the native code + */ + public void start() throws AFSException + { + state = STARTING; + start( server.getBosHandle(), name ); + } + + /** + * Restarts this process + * + * @exception AFSException If an error occurs in the native code + */ + public void restart() throws AFSException + { + state = STARTING; + restart( server.getBosHandle(), name ); + } + + //////////////// accessors: //////////////////////// + + /** + * Returns the name of this process. + * + * @return the name of this process + */ + public String getName() + { + return name; + } + + /** + * Returns the server hosting this process. + * + * @return this process' server + */ + public Server getServer() + { + return server; + } + + /** + * Returns the process type. Possible values are:
      + *
    • {@link #SIMPLE_PROCESS}
    • + *
    • {@link #FS_PROCESS}
    • + *
    • {@link #CRON_PROCESS}
    + * + * @return the process type + * @exception AFSException If an error occurs in the native code + */ + public int getType() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return type; + } + + /** + * Returns the process goal. Possible values are:
      + *
    • {@link #STOPPED}
    • + *
    • {@link #RUNNING}
    • + *
    • {@link #STARTING}
    • + *
    • {@link #STOPPING}
    + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the process goal + * @exception AFSException If an error occurs in the native code + */ + public int getGoal() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return goal; + } + + /** + * Returns the process execution state. Possible values are:
      + *
    • {@link #STOPPED}
    • + *
    • {@link #RUNNING}
    • + *
    • {@link #STARTING}
    • + *
    • {@link #STOPPING}
    + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the process execution state + * @exception AFSException If an error occurs in the native code + */ + public int getState() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return state; + } + + /** + * Returns the most recent start time of this process. A + * null value + * indicates no start time. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the start time + * @exception AFSException If an error occurs in the native code + */ + public long getStartTime() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return startTime; + } + + /** + * Returns the most recent start time of this process. A null + * value indicates no start time. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the start time + * @exception AFSException If an error occurs in the native code + */ + public GregorianCalendar getStartTimeDate() throws AFSException + { + if (!cachedInfo) { + refreshInfo(); + } + if( startTimeDate == null && startTime != 0 ) { + // make it into a date . . . + startTimeDate = new GregorianCalendar(); + long longTime = startTime * 1000; + Date d = new Date( longTime ); + startTimeDate.setTime( d ); + } + return startTimeDate; + } + + /** + * Returns the number of starts of the process. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the number of starts + * @exception AFSException If an error occurs in the native code + */ + public long getNumberOfStarts() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return numberStarts; + } + + /** + * Returns the most recent exit time of this process. A null + * value indicates no exit time. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the exit time + * @exception AFSException If an error occurs in the native code + */ + public long getExitTime() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return exitTime; + } + + /** + * Returns the most recent exit time of this process. A null + * value indicates no exit time + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the exit time + * @exception AFSException If an error occurs in the native code + */ + public GregorianCalendar getExitTimeDate() throws AFSException + { + if (!cachedInfo) refreshInfo(); + if( exitTimeDate == null && exitTime != 0 ) { + // make it into a date . . . + exitTimeDate = new GregorianCalendar(); + long longTime = exitTime*1000; + Date d = new Date( longTime ); + exitTimeDate.setTime( d ); + } + return exitTimeDate; + } + + /** + * Returns the most recent time this process exited with an error. A + * null value indicates no exit w/ error time. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the exit w/ error time + * @exception AFSException If an error occurs in the native code + */ + public long getExitErrorTime() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return exitErrorTime; + } + + /** + * Returns the most recent time this process exited with an error. A < + * code>null value indicates no exit w/ error time. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the exit w/ error time + * @exception AFSException If an error occurs in the native code + */ + public GregorianCalendar getExitErrorTimeDate() throws AFSException + { + if (!cachedInfo) refreshInfo(); + if (exitErrorTimeDate == null && exitErrorTime != 0) { + // make it into a date . . . + exitErrorTimeDate = new GregorianCalendar(); + long longTime = exitErrorTime*1000; + Date d = new Date( longTime ); + exitErrorTimeDate.setTime( d ); + } + return exitErrorTimeDate; + } + + /** + * Returns the error code of the process. A value of 0 indicates + * no error code. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the error code + * @exception AFSException If an error occurs in the native code + */ + public long getErrorCode() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return errorCode; + } + + /** + * Returns the error signal of the process. A value of 0 indicates no + * error signal. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the error signal + * @exception AFSException If an error occurs in the native code + */ + public long getErrorSignal() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return errorSignal; + } + + /** + * Returns whether or not the state of the process is ok. A value of + * false indicates there has been a core dump. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return whether or not the state is ok + * @exception AFSException If an error occurs in the native code + */ + public boolean getStateOk() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return stateOk; + } + + /** + * Returns whether or not the state of the process indicates too many errors. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return whether or not the state indicates too many errors + * @exception AFSException If an error occurs in the native code + */ + public boolean getStateTooManyErrors() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return stateTooManyErrors; + } + + /** + * Returns whether or not the state of the process indicates bad file access. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return whether or not the state indicates bad file access + * @exception AFSException If an error occurs in the native code + */ + public boolean getStateBadFileAccess() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return stateBadFileAccess; + } + + /////////////// custom information methods //////////////////// + + /** + * Returns a String representation of this Process. + * Contains the information fields. + * + * @return a String representation of the Process + */ + protected String getInfo() + { + String r; + try { + + r = "Process: " + name + "\n"; + + r += "\ttype: "; + switch( getType() ) { + case SIMPLE_PROCESS: + r += "simple"; + break; + case FS_PROCESS: + r += "fs"; + break; + case CRON_PROCESS: + r += "cron"; + break; + default: + r += "other - " + getType(); + } + r += "\n"; + + r += "\tstate: "; + switch( getState() ) { + case STOPPED: + r += "stopped"; + break; + case RUNNING: + r += "running"; + break; + case STOPPING: + r += "stopping"; + break; + case STARTING: + r += "starting"; + break; + default: + r += "other - " + getState(); + } + r += "\n"; + + r += "\tgoal: "; + switch( getGoal() ) { + case STOPPED: + r += "stopped"; + break; + case RUNNING: + r += "running"; + break; + case STOPPING: + r += "stopping"; + break; + case STARTING: + r += "starting"; + break; + default: + r += "other - " + getGoal(); + } + r += "\n"; + + r += "\tstartTime: "; + if( getStartTime() == 0) { + r += "0"; + } else { + r += getStartTimeDate().getTime(); + } + r += "\n"; + + r += "\tnumberStarts: " + getNumberOfStarts() + "\n"; + + r += "\texitTime: "; + if( getExitTime() == 0 ) { + r += "0"; + } else { + r += getExitTimeDate().getTime(); + } + r += "\n"; + + r += "\texitErrorTime: "; + if( getExitErrorTimeDate() == null ) { + r += "0"; + } else { + r += getExitErrorTimeDate().getTime(); + } + r += "\n"; + + r += "\terrorCode: " + getErrorCode() + "\n"; + r += "\terrorSignal: " + getErrorSignal() + "\n"; + r += "\tstateOk: " + getStateOk() + "\n"; + r += "\tstateTooManyErrors: " + getStateTooManyErrors() + "\n"; + r += "\tstateBadFileAccess: " + getStateBadFileAccess() + "\n"; + + } catch( Exception e ) { + return e.toString(); + } + return r; + } + + /////////////// custom override methods //////////////////// + + /** + * Compares two Process objects respective to their names and does not + * factor any other attribute. Alphabetic case is significant in + * comparing names. + * + * @param process The Process object to be compared to this Process + * instance + * + * @return Zero if the argument is equal to this Process' name, a + * value less than zero if this Process' name is + * lexicographically less than the argument, or a value greater + * than zero if this Process' name is lexicographically + * greater than the argument + */ + public int compareTo(Process process) + { + return this.getName().compareTo(process.getName()); + } + + /** + * Comparable interface method. + * + * @see #compareTo(Process) + */ + public int compareTo(Object obj) + { + return compareTo((Process)obj); + } + + /** + * Tests whether two Process objects are equal, based on their + * names and hosting server. + * + * @param otherProcess the Process to test + * @return whether the specifed Process is the same as this Process + */ + public boolean equals( Process otherProcess ) + { + return ( name.equals(otherProcess.getName()) ) && + ( this.getServer().equals(otherProcess.getServer()) ); + } + + /** + * Returns the name of this Process + * + * @return the name of this Process + */ + public String toString() + { + return getName(); + } + + /////////////// native methods //////////////////// + + /** + * Fills in the information fields of the provided Process. + * + * @param cellHandle the handle of the cell to which the process belongs + * @see Cell#getCellHandle + * @param processName the instance name of the process for which to get + * the information + * @param theProcess the {@link Process Process} object in which to fill + * in the information + * @exception AFSException If an error occurs in the native code + */ + protected static native void getProcessInfo( int cellHandle, + String processName, + Process theProcess ) + throws AFSException; + + /** + * Creates a processes on a server. + * + * @param serverHandle the bos handle of the server to which the key will + * belong + * @see Server#getBosServerHandle + * @param processName the instance name to give the process. See AFS + * documentation for a standard list of instance names + * @param processType the type of process this will be. + * Acceptable values are:
      + *
    • {@link #SIMPLE_PROCESS}
    • + *
    • {@link #FS_PROCESS}
    • + *
    • {@link #CRON_PROCESS}
    + * @param executionPath the execution path process to create + * @param cronTime a String representing the time a cron process is to + * be run. Acceptable formats are:
      + *
    • for daily restarts: "23:10" or "11:10 pm"
    • + *
    • for weekly restarts: "sunday 11:10pm" or + * "sun 11:10pm"
    • + *
    + * Can be null for non-cron processes. + * @param notifier the execution path to a notifier program that should + * be called when the process terminates. Can be + * null + * @exception AFSException If an error occurs in the native code + */ + protected static native void create( int serverHandle, String processName, + int processType, String executionPath, + String cronTime, String notifier ) + throws AFSException; + + /** + * Removes a process from a server. + * + * @param serverHandle the bos handle of the server to which the process + * belongs + * @see Server#getBosServerHandle + * @param processName the name of the process to remove + * @exception AFSException If an error occurs in the native code + */ + protected static native void delete( int serverHandle, String processName ) + throws AFSException; + + /** + * Start this process. + * + * @param serverHandle the bos handle of the server to which the process + * belongs + * @see Server#getBosServerHandle + * @param processName the name of the process to start + * @exception AFSException If an error occurs in the native code + */ + protected static native void start( int serverHandle, String processName ) + throws AFSException; + + /** + * Retart this process. + * + * @param serverHandle the bos handle of the server to which the process + * belongs + * @see Server#getBosServerHandle + * @param processName the name of the process to restart + * @exception AFSException If an error occurs in the native code + */ + protected static native void restart( int serverHandle, String processName ) + throws AFSException; + + /** + * Stop this process. + * + * @param serverHandle the bos handle of the server to which the process + * belongs + * @see Server#getBosServerHandle + * @param processName the name of the process to stop + * @exception AFSException If an error occurs in the native code + */ + protected static native void stop( int serverHandle, String processName ) + throws AFSException; + + /** + * Reclaims all memory being saved by the process portion of the native + * library. This method should be called when no more Process + * objects are expected to be used. + */ + protected static native void reclaimProcessMemory(); +} + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/Server.java b/src/JAVA/classes/org/openafs/jafs/Server.java new file mode 100644 index 0000000..de25385 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/Server.java @@ -0,0 +1,2351 @@ +/* + * @(#)Server.java 1.0 6/29/2001 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.io.Serializable; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; + +/** + * An abstract representation of an AFS server. It holds information about + * the server, such as what its processes are. + *

    + * + * Constructing an instance of a Server does not mean an actual + * AFS server is created and added to a cell -- on the contrary, a + * Server object must be a representation of an already existing + * AFS server. There is no way to create a new AFS server through this API. + * See OpenAFS.org for information on how + * to create a new AFS server.

    + * + * A Server object may represent either an AFS file server, + * an AFS database server, or both if the same machine serves both + * purposes.

    + * + * Each Server object has its own individual set of + * Partitions, Processes, and Keys. + * This represents the properties and attributes of an actual AFS server. + *

    + * + * + * The following is a simple example of how to construct and use a Server + * object. This example constructs a Server using the + * Cell representing teh AFS cell to which the server belongs, + * and prints out the names of all the partitions residing on the server. + *

    + * + *
    + * import org.openafs.jafs.Cell;
    + * import org.openafs.jafs.AFSException;
    + * import org.openafs.jafs.Partition;
    + * import org.openafs.jafs.Server;
    + * ...
    + * public class ...
    + * {
    + *   ...
    + *   private Cell cell;
    + *   private Server server;
    + *   ...
    + *   public static void main(String[] args) throws Exception
    + *   {
    + *     String username   = arg[0];
    + *     String password   = arg[1];
    + *     String cellName   = arg[2];
    + *     String serverName = arg[3];
    + * 
    + *     token = new Token(username, password, cellName);
    + *     cell   = new Cell(token);
    + *     server = new Server(serverName, cell);
    + * 
    + *     System.out.println("Partitions in Server " + server.getName() + ":");
    + *     if( server.isFileServer() ) {
    + *       Partition[] partitions = server.getPartitions();
    + *       for (int i = 0; i < partitions.length; i++) {
    + *         System.out.println(" -> " + partitions[i]);
    + *       }
    + *     }
    + *   }
    + *   ...
    + * }
    + * 
    + * + */ +public class Server implements Serializable, Comparable +{ + /** + * Used for binary restart time types. + */ + private static final int RESTART_BINARY = 0; + + /** + * Used for general restart time types. + */ + private static final int RESTART_GENERAL = 1; + + protected String name; + protected Cell cell; + + protected int vosHandle; + protected int bosHandle; + + protected boolean database; + protected boolean fileServer; + + // these will be true if the machine is supposedly listed as a server + // but that's wrong, or the machine is down + protected boolean badFileServer; + protected boolean badDatabase; + + // String IP Address of address[0] + protected String[] ipAddresses; + + protected ArrayList partitionNames; + protected ArrayList partitions; + protected ArrayList adminNames; + protected ArrayList admins; + protected ArrayList keys; + protected ArrayList processNames; + protected ArrayList processes; + + // Storage information + protected int totalSpace; + protected int totalQuota; + protected int totalFreeSpace; + protected int totalUsedSpace; + + protected ExecutableTime genRestartTime; + protected ExecutableTime binRestartTime; + + protected boolean cachedInfo; + + /** + * Constructs a new Server object instance given the + * name of the AFS server and the AFS cell, represented by + * cell, to which it belongs. This does not actually + * create a new AFS server, it just represents an existing one. + * If name is not an actual AFS server, exceptions + * will be thrown during subsequent method invocations on this + * object. + * + * @param name the name of the server to represent + * @param cell the cell to which the server belongs. + * @exception AFSException If an error occurs in the native code + */ + public Server( String name, Cell cell ) throws AFSException + { + this.name = name; + this.cell = cell; + + cachedInfo = false; + + vosHandle = 0; + bosHandle = 0; + + ipAddresses = new String[16]; + + partitionNames = null; + partitions = null; + adminNames = null; + admins = null; + keys = null; + processNames = null; + processes = null; + } + + /** + * Constructs a new Server object instance given the name + * of the AFS server and the AFS cell, represented by cell, + * to which it belongs. This does not actually + * create a new AFS server, it just represents an existing one. + * If name is not an actual AFS server, exceptions + * will be thrown during subsequent method invocations on this + * object. + * + *

    This constructor is ideal for point-in-time representation and + * transient applications. It ensures all data member values are set + * and available without calling back to the filesystem at the first + * request for them. Use the {@link #refresh()} method to address any + * coherency concerns. + * + * @param name the name of the server to represent + * @param cell the cell to which the server belongs. + * @param preloadAllMembers true will ensure all object members are + * set upon construction; + * otherwise members will be set upon access, + * which is the default behavior. + * @exception AFSException If an error occurs in the native code + * @see #refresh + */ + public Server( String name, Cell cell, boolean preloadAllMembers ) + throws AFSException + { + this(name, cell); + if (preloadAllMembers) refresh(true); + } + + /** + * Constructs a blank Server object instance given the cell to + * which the server belongs. This blank object can then be passed into + * other methods to fill out its properties. + * + * @param cell the cell to which the server belongs. + * @exception AFSException If an error occurs in the native code + */ + Server( Cell cell ) throws AFSException + { + this( null, cell ); + } + + /*-------------------------------------------------------------------------*/ + + /** + * Refreshes the properties of this Server object instance with values + * from the AFS server it represents. All properties that have been + * initialized and/or accessed will be renewed according to the values + * of the AFS server this Server object instance represents. + * + *

    Since in most environments administrative changes can be administered + * from an AFS command-line program or an alternate GUI application, this + * method provides a means to refresh the Java object representation and + * thereby ascertain any possible modifications that may have been made + * from such alternate administrative programs. Using this method before + * an associated instance accessor will ensure the highest level of + * representative accuracy, accommodating changes made external to the + * Java application space. If administrative changes to the underlying AFS + * system are only allowed via this API, then the use of this method is + * unnecessary. + * + * @exception AFSException If an error occurs in the native code + */ + public void refresh() throws AFSException + { + refresh(false); + } + + /** + * Refreshes the properties of this Server object instance with values + * from the AFS server it represents. If all is + * true then all of the properties of this Server + * object instance will be set, or renewed, according to the values of the + * AFS server it represents, disregarding any previously set properties. + * + *

    Thus, if all is false then properties that + * are currently set will be refreshed and properties that are not set + * will remain uninitialized. + * See {@link #refresh()} for more information. + * + * @param all if true set or renew all object properties; + * otherwise renew all set properties + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + protected void refresh(boolean all) throws AFSException + { + if ( all ) { + refreshProcesses(); + refreshProcessNames(); + refreshKeys(); + refreshAdminNames(); + refreshAdmins(); + refreshPartitionNames(); + refreshPartitions(all); + refreshInfo(); + refreshGeneralRestart(); + refreshBinaryRestart(); + } else { + if ( processes != null ) refreshProcesses(); + if ( processNames != null ) refreshProcessNames(); + if ( keys != null ) refreshKeys(); + if ( adminNames != null ) refreshAdminNames(); + if ( admins != null ) refreshAdmins(); + if ( partitionNames != null ) refreshPartitionNames(); + if ( partitions != null ) refreshPartitions(all); + if ( genRestartTime != null ) refreshGeneralRestart(); + if ( binRestartTime != null ) refreshBinaryRestart(); + if ( cachedInfo ) refreshInfo(); + } + } + + /** + * Refreshes the information fields of this Server to + * reflect the current state of the AFS server. These fields include + * the IP addresses and the fileserver types. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshInfo() throws AFSException + { + getServerInfo( cell.getCellHandle(), name, this ); + cachedInfo = true; + } + + /** + * Refreshes the general restart time fields of this Server + * to reflect the current state of the AFS server. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshGeneralRestart() throws AFSException + { + if (genRestartTime == null) genRestartTime = new ExecutableTime(); + getRestartTime( getBosHandle(), RESTART_GENERAL, genRestartTime ); + } + + /** + * Refreshes the binary restart time fields of this Server + * to reflect the current state of the AFS server. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshBinaryRestart() throws AFSException + { + if (binRestartTime == null) binRestartTime = new ExecutableTime(); + getRestartTime( getBosHandle(), RESTART_BINARY, binRestartTime ); + } + + /** + * Obtains the most current list of Partition objects + * of this server. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshPartitions() throws AFSException + { + this.refreshPartitions(false); + } + + /** + * Obtains the most current list of Partition objects of + * this server. + * + * @param refreshVolumes force all volumes contained in each + * partition to be refreshed. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshPartitions(boolean refreshVolumes) + throws AFSException + { + if (!isFileServer() || isBadFileServer()) return; + + Partition currPartition; + + int iterationID = getPartitionsBegin( cell.getCellHandle(), + getVosHandle() ); + + partitions = new ArrayList(); + + currPartition = new Partition( this ); + while( getPartitionsNext( iterationID, currPartition ) != 0 ) { + //Only volumes are necessary since volume information + //is populated at time of construction + if (refreshVolumes) currPartition.refreshVolumes(); + partitions.add( currPartition ); + currPartition = new Partition( this ); + } + getPartitionsDone( iterationID ); + totalSpace = 0; + totalQuota = 0; + totalUsedSpace = 0; + totalFreeSpace = 0; + } + + /** + * Obtains the most current list of partition names of this server. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshPartitionNames() throws AFSException + { + if (!isFileServer() || isBadFileServer()) return; + + String currName; + + int iterationID = getPartitionsBegin( cell.getCellHandle(), + getVosHandle() ); + + partitionNames = new ArrayList(); + + while( ( currName = getPartitionsNextString( iterationID ) ) != null ) { + partitionNames.add( currName ); + } + getPartitionsDone( iterationID ); + } + + /** + * Obtains the most current list of bos admin names of this server. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshAdminNames() throws AFSException + { + String currName; + + int iterationID = getBosAdminsBegin( getBosHandle() ); + + adminNames = new ArrayList(); + + while( ( currName = getBosAdminsNextString( iterationID ) ) != null ) { + adminNames.add( currName ); + } + getBosAdminsDone( iterationID ); + } + + /** + * Obtains the most current list of admin User objects of + * this server. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshAdmins() throws AFSException + { + User currUser; + + int iterationID = getBosAdminsBegin( getBosHandle() ); + + admins = new ArrayList(); + + currUser = new User( cell ); + while( getBosAdminsNext( cell.getCellHandle(), iterationID, currUser ) + != 0 ) { + admins.add( currUser ); + currUser = new User( cell ); + } + getBosAdminsDone( iterationID ); + } + + /** + * Obtains the most current list of Key objects of this server. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshKeys() throws AFSException + { + Key currKey; + + int iterationID = getKeysBegin( getBosHandle() ); + + keys = new ArrayList(); + + currKey = new Key( this ); + while( getKeysNext( iterationID, currKey ) != 0 ) { + keys.add( currKey ); + currKey = new Key( this ); + } + getKeysDone( iterationID ); + } + + /** + * Obtains the most current list of process names of this server. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshProcessNames() throws AFSException + { + String currName; + + int iterationID = getProcessesBegin( getBosHandle() ); + + processNames = new ArrayList(); + + while( ( currName = getProcessesNextString( iterationID ) ) != null ) { + processNames.add( currName ); + } + getProcessesDone( iterationID ); + } + + /** + * Obtains the most current list of Process objects of + * this server. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshProcesses() throws AFSException + { + Process currProcess; + + int iterationID = getProcessesBegin( getBosHandle() ); + + processes = new ArrayList(); + + currProcess = new Process( this ); + while( getProcessesNext( getBosHandle(), iterationID, currProcess ) + != 0 ) { + processes.add( currProcess ); + currProcess = new Process( this ); + } + getProcessesDone( iterationID ); + } + + /** + * Add a bos admin to the UserList file of this server, in order to + * given the AFS user represented by admin full bos + * administrative privileges on this server. + * + * @param admin the admin to add + * @exception AFSException If an error occurs in the native code + */ + public void addAdmin( User admin ) throws AFSException + { + String adminName = admin.getName(); + + addBosAdmin( getBosHandle(), adminName ); + if ( adminNames != null ) { + adminNames.add( adminName ); + } + } + + /** + * Remove a bos admin from the UserList file of this server, in order to + * take away from the AFS user represented by admin bos + * administrative privileges on this machine. + * + * @param admin the admin to remove + * @exception AFSException If an error occurs in the native code + */ + public void removeAdmin( User admin ) throws AFSException + { + String adminName = admin.getName(); + + removeBosAdmin( getBosHandle(), adminName ); + if ( adminNames != null ) { + adminNames.remove( adminNames.indexOf( adminName ) ); + adminNames.trimToSize(); + } + } + + /** + * Syncs this server to the VLDB. + * + * @exception AFSException If an error occurs in the native code + */ + public void syncServer() throws AFSException + { + syncServerWithVLDB( cell.getCellHandle(), getVosHandle(), -1 ); + } + + /** + * Syncs the VLDB to this server. + * + * @exception AFSException If an error occurs in the native code + */ + public void syncVLDB() throws AFSException + { + syncVLDBWithServer( cell.getCellHandle(), getVosHandle(), -1, false ); + } + + /** + * Salvages (restores consistency to) this server. Uses default values for + * most salvager options in order to simplify the API. + * + * @exception AFSException If an error occurs in the native code + */ + public void salvage() throws AFSException + { + salvage( cell.getCellHandle(), getBosHandle(), null, null, 4, null, null, + false, false, false, false, false, false ); + } + + /** + * Starts up all bos processes on this server. + * + * @exception AFSException If an error occurs in the native code + */ + public void startAllProcesses() throws AFSException + { + startAllProcesses( getBosHandle() ); + } + + /** + * Stops all bos processes on this server. + * + * @exception AFSException If an error occurs in the native code + */ + public void stopAllProcesses() throws AFSException + { + stopAllProcesses( getBosHandle() ); + } + + /** + * Restarts all bos processes on this server. + * + * @exception AFSException If an error occurs in the native code + */ + public void restartAllProcesses() throws AFSException + { + restartAllProcesses( getBosHandle(), false ); + } + + /** + * Restarts bos server and all bos processes on this server. + * + * @exception AFSException If an error occurs in the native code + */ + public void restartBosServer() throws AFSException + { + restartAllProcesses( getBosHandle(), true ); + } + + /** + * Gets the contents of a log file, in one large String. + * The log cannot be in AFS file space. + * + * @return a String containing the contents of the log file + * @exception AFSException If an error occurs in the native code + */ + public String getLog( String logLocation ) throws AFSException + { + return getLog( getBosHandle(), logLocation ); + } + + /** + * Unauthenticates all server-related tokens that have been obtained by + * this Server object, and shuts this server object down. + * This method should only be called when this Server or any + * of the objects constructed using this Server will not be + * used anymore. Note that this does not effect the actual AFS server; + * it merely closes the representation. + * + * @exception AFSException If an error occurs in the native code + */ + public void close() throws AFSException + { + if ( vosHandle != 0 ) { + closeVosServerHandle( vosHandle ); + } + if ( bosHandle != 0 ) { + closeBosServerHandle( bosHandle ); + } + + cachedInfo = false; + + vosHandle = 0; + bosHandle = 0; + + partitionNames = null; + partitions = null; + adminNames = null; + admins = null; + keys = null; + processNames = null; + processes = null; + } + + //////////////// accessors: //////////////////////// + + /** + * Returns the name of this server. + * + * @return the name of this server + */ + public String getName() + { + return name; + } + + /** + * Returns the Cell object with which this Server + * was constructed. It represents the actual AFS cell to which this + * server belongs. + * + * @return this server's cell + */ + public Cell getCell() + { + return cell; + } + + /** + * Returns the number of BOS administrators assigned to this server. + * + *

    If the total list of admins or admin names have already been + * collected (see {@link #getAdmins()}), then the returning value will + * be calculated based upon the current list. Otherwise, AFS will be + * explicitly queried for the information. + * + *

    The product of this method is not saved, and is recalculated + * with every call. + * + * @return the number of admins on this server. + * @exception AFSException If an error occurs + * in any of the associated native methods + * @see #getAdmins() + * @see #getAdminNames() + */ + public int getAdminCount() throws AFSException + { + if (adminNames != null) { + return adminNames.size(); + } else if (admins != null) { + return admins.size(); + } else { + return getBosAdminCount(getBosHandle()); + } + } + + /** + * Retrieves an array containing all of the admin User objects + * associated with this Server, each of which are an abstract + * representation of an actual bos administrator of the AFS server. + * After this method is called once, it saves the array of + * Users and returns that saved array on subsequent calls, + * until the {@link #refresh()} method is called and a more current list + * is obtained. + * + * @return a User array of the admins of the server. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public User[] getAdmins() throws AFSException + { + if ( admins == null ) refreshAdmins(); + return (User[]) admins.toArray( new User[admins.size()] ); + } + + /** + * Retrieves an array containing all of the names of bos admins + * associated with this Server. After this method + * is called once, it saves the array of Strings and returns + * that saved array on subsequent calls, until the {@link #refresh()} method + * is called and a more current list is obtained. + * + * @return a String array of the bos admin of the server. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public String[] getAdminNames() throws AFSException + { + if ( adminNames == null ) refreshAdminNames(); + return (String []) adminNames.toArray( new String[adminNames.size()] ); + } + + /** + * Returns the number of partitions on this server. + * + *

    If the total list of partitions or partition names have already been + * collected (see {@link #getPartitions()}), then the returning value will + * be calculated based upon the current list. Otherwise, AFS will be + * explicitly queried for the information. + * + *

    The product of this method is not saved, and is recalculated + * with every call. + * + * @return the number of partitions on this server. + * @exception AFSException If an error occurs + * in any of the associated native methods + * @see #getPartitions() + * @see #getPartitionNames() + */ + public int getPartitionCount() throws AFSException + { + if (partitionNames != null) { + return partitionNames.size(); + } else if (partitions != null) { + return partitions.size(); + } else { + return getPartitionCount(cell.getCellHandle(), getVosHandle()); + } + } + + /** + * Retrieves the Partition object (which is an abstract + * representation of an actual AFS partition of this server) designated + * by name (i.e. "/vicepa", etc.). If a partition by + * that name does not actually exist in AFS on the server + * represented by this object, an {@link AFSException} will be + * thrown. + * + * @param name the name of the partition to retrieve + * @return Partition designated by name. + * @exception AFSException If an error occurs in the native code + * @exception NullPointerException If name is + * null. + */ + public Partition getPartition(String name) throws AFSException + { + if (name == null) throw new NullPointerException(); + if (isFileServer() && !isBadFileServer()) { + Partition partition = new Partition(name, this); + partition.refresh(true); + return partition; + } else { + //Throw "No such entry" error + throw new AFSException("Server is not a file server.", 363524); + } + } + + /** + * Retrieves an array containing all of the Partition objects + * associated with this Server, each of which are an abstract + * representation of an actual AFS partition of the AFS server. + * After this method is called once, it saves the array of + * Partitions and returns that saved array on subsequent calls, + * until the {@link #refresh()} method is called and a more current list + * is obtained. + * + * @return a Partition array of the Partition + * objects of the server. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public Partition[] getPartitions() throws AFSException + { + if ( partitions == null ) refreshPartitions(); + return (Partition []) + partitions.toArray( new Partition[partitions.size()] ); + } + + /** + * Retrieves an array containing all of the names of partitions + * associated with this Server (i.e. "vicepa", etc.). + * After this method is called once, it saves the array of + * Strings and returns that saved array on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * list is obtained. + * + * @return a String array of the partitions of the server. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public String[] getPartitionNames() throws AFSException + { + if ( partitionNames == null ) refreshPartitionNames(); + return (String []) + partitionNames.toArray( new String[partitionNames.size()] ); + } + + /** + * Retrieves the Key object (which is an abstract + * representation of an actual AFS partition of this server) designated + * by nkeyVersion. If a key with + * that version does not actually exist in AFS on the server + * represented by this object, null is returned. + * + * @param keyVersion the version of the key to retrieve + * @return Key designated by keyVersion. + * @exception AFSException If an error occurs in the native code + */ + public Key getKey(int keyVersion) throws AFSException + { + try { + Key[] keys = this.getKeys(); + for (int i = 0; i < keys.length; i++) { + if (keys[i].getVersion() == keyVersion) { + return keys[i]; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * Returns the number of keys on this server. + * + *

    If the total list of keys has already been + * collected (see {@link #getKeys()}), then the returning value will + * be calculated based upon the current list. Otherwise, AFS will be + * explicitly queried for the information. + * + *

    The product of this method is not saved, and is recalculated + * with every call. + * + * @return the number of keys on this server. + * @exception AFSException If an error occurs + * in any of the associated native methods + * @see #getKeys() + */ + public int getKeyCount() throws AFSException + { + if (keys != null) { + return keys.size(); + } else { + return getKeyCount(getBosHandle()); + } + } + + /** + * Retrieves an array containing all of the Key objects + * associated with this Server, each of which are an abstract + * representation of an actual AFS key of the AFS server. + * After this method is called once, it saves the array of + * Keys and returns that saved array on subsequent calls, + * until the {@link #refresh()} method is called and a more current list + * is obtained. + * + * @return a Key array of the Key objects + * of the server. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public Key[] getKeys() throws AFSException + { + if ( keys == null ) refreshKeys(); + return (Key[]) keys.toArray( new Key[keys.size()] ); + } + + /** + * Retrieves the Process object (which is an abstract + * representation of an actual AFS process of this server) designated + * by name (i.e. "kaserver", etc.). If a process by + * that name does not actually exist in AFS on the server + * represented by this object, an {@link AFSException} will be + * thrown. + * + * @param name the name of the process to retrieve + * @return Process designated by name. + * @exception AFSException If an error occurs in the native code + * @exception NullPointerException If name is + * null. + */ + public Process getProcess(String name) throws AFSException + { + if (name == null) throw new NullPointerException(); + //if (isFileServer() && !isBadFileServer()) { + Process process = new Process(name, this); + process.refresh(true); + return process; + //} + } + + /** + * Returns the number of processes hosted by this server. + * + *

    If the total list of processes or process names have already been + * collected (see {@link #getProcesses()}), then the returning value will + * be calculated based upon the current list. Otherwise, AFS will be + * explicitly queried for the information. + * + *

    The product of this method is not saved, and is recalculated + * with every call. + * + * @return the number of processes on this server. + * @exception AFSException If an error occurs + * in any of the associated native methods + * @see #getProcesses() + * @see #getProcessNames() + */ + public int getProcessCount() throws AFSException + { + if (processNames != null) { + return processNames.size(); + } else if (processes != null) { + return processes.size(); + } else { + return getProcessCount(getBosHandle()); + } + } + + /** + * Retrieves an array containing all of the Process objects + * associated with this Server, each of which are an abstract + * representation of an actual AFS process of the AFS server. + * After this method is called once, it saves the array of + * Processes and returns that saved array on subsequent calls, + * until the {@link #refresh()} method is called and a more current list + * is obtained. + * + * @return a Process array of the Process + * objects of the server. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public Process[] getProcesses() throws AFSException + { + if ( processes == null ) refreshProcesses(); + return (Process[]) processes.toArray( new Process[processes.size()] ); + } + + /** + * Retrieves an array containing all of the names of processes + * associated with this Server (i.e. "kaserver", etc.). + * After this method is called once, it saves the array of + * Strings and returns that saved array on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * list is obtained. + * + * @return a String array of the processes of the server. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public String[] getProcessNames() throws AFSException + { + if ( processNames == null ) refreshProcessNames(); + return (String[]) processNames.toArray( new String[processNames.size()] ); + } + + /** + * Returns whether or not this server is a database machine, meaning it runs + * processes such as the "kaserver" and "vlserver", and participates in + * elections. + * + * @return whether or not this user this server is a database machine. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean isDatabase() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return database; + } + + /** + * Returns whether or not this server is a file server machine, meaning it + * runs the "fs" process and stores AFS volumes. + * + * @return whether or not this user this server is a file server machine. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean isFileServer() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return fileServer; + } + + /** + * Returns whether or not this server is a database machine AND + * either it isn't in reality (e.g. it's incorrectly configured) + * or it's currently down. + * + * @return whether or not this server is a database machine + * AND either it isn't in reality or it's currently down + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean isBadDatabase() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return badDatabase; + } + + /** + * Returns whether this machine thinks it's a file server AND + * either it isn't in reality (e.g. it's incorrectly configured) + * or it's currently down. + * + * @return whether or not this server is a file server machine AND + * either it isn't in reality or it's currently down + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean isBadFileServer() throws AFSException + { + if (!cachedInfo) refreshInfo(); + return badFileServer; + } + + /** + * Returns this server's IP address as a String. It returns it in + * dotted quad notation (i.e. 123.123.123.123). + * + * @return this server's IP address as a String + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public String[] getIPAddresses() throws AFSException + { + if (!cachedInfo) refreshInfo(); + int n = 16; + for (int i = 0; i < n; i++) { + if (ipAddresses[i] == null) { + n = i; + break; + } + } + String[] addresses = new String[n]; + System.arraycopy(ipAddresses, 0, addresses, 0, n); + return addresses; + } + + /** + * Returns the BOS Server's general restart time in the form of an + * ExecutableTime object. This is the time at which the bos server + * restarts itself and all running processes. After this method + * is called once, it saves the time and returns + * that value on subsequent calls, until the {@link #refresh()} method + * is called and a more current value is obtained. + * + * @return the general restart time + * @exception AFSException If an error occurs in the native code + * @see Server.ExecutableTime + * @see #refresh() + */ + public ExecutableTime getGeneralRestartTime() throws AFSException + { + if (genRestartTime == null) refreshGeneralRestart(); + return genRestartTime; + } + + /** + * Returns the BOS Server's binary restart time in the form of an + * ExecutableTime object. This is the time at which all new or newly + * modified AFS binaries are restarted. After this method + * is called once, it saves the time and returns + * that value on subsequent calls, until the {@link #refresh()} method + * is called and a more current value is obtained. + * + * @return the binary restart time + * @exception AFSException If an error occurs in the native code + * @see Server.ExecutableTime + * @see #refresh() + */ + public ExecutableTime getBinaryRestartTime() throws AFSException + { + if (binRestartTime == null) refreshBinaryRestart(); + return binRestartTime; + } + + /** + * Returns the total space on this server (a sum of the space of all the + * partitions associated with this server). If this server is not a + * file server, zero will be returned. After this method + * is called once, it saves the total space and returns + * that value on subsequent calls, until the {@link #refresh()} method + * is called and a more current value is obtained. + * + * @return the total space on this server + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getTotalSpace() throws AFSException + { + if (partitions == null) refreshPartitions(true); + if (!isFileServer() || isBadFileServer()) return 0; + if (totalSpace == 0) { + Partition[] partitions = getPartitions(); + for (int i = 0; i < partitions.length; i++) { + totalSpace += partitions[i].getTotalSpace(); + } + } + return totalSpace; + } + + /** + * Returns the total free space on this server (a sum of the free space of + * all the partitions associated with this server). If this server is not a + * file server, zero will be returned. After this method + * is called once, it saves the total free space and returns + * that value on subsequent calls, until the {@link #refresh()} method + * is called and a more current value is obtained. + * + * @return the total free space on this server + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getTotalFreeSpace() throws AFSException + { + if (partitions == null) refreshPartitions(true); + if (!isFileServer() || isBadFileServer()) return 0; + if (totalFreeSpace == 0) { + Partition[] partitions = getPartitions(); + for (int i = 0; i < partitions.length; i++) { + totalFreeSpace += partitions[i].getTotalFreeSpace(); + } + } + return totalFreeSpace; + } + + /** + * Returns the total used space on this server (a sum of the used space of + * all the partitions associated with this server). If this server is not a + * file server, zero will be returned. After this method + * is called once, it saves the total used space and returns + * that value on subsequent calls, until the {@link #refresh()} method + * is called and a more current value is obtained. + * + * @return the total space on this partition + * @exception AFSException If an error occurs in the native code + * @see #getTotalSpace() + * @see #getTotalFreeSpace() + */ + public int getTotalUsedSpace() throws AFSException + { + if (totalUsedSpace == 0) { + totalUsedSpace = getTotalSpace() - getTotalFreeSpace(); + } + return totalUsedSpace; + } + + /** + * Returns this server's vos handle. + * + * @return this server's vos handle + * @exception AFSException If an error occurs in the native code + */ + protected int getVosHandle() throws AFSException + { + if ( vosHandle == 0 ) { + vosHandle = getVosServerHandle( cell.getCellHandle(), name ); + } + return vosHandle; + } + + /** + * Returns this server's bos handle. + * + * @return this server's bos handle + * @exception AFSException If an error occurs in the native code + */ + protected int getBosHandle() throws AFSException + { + if ( bosHandle == 0 ) { + bosHandle = getBosServerHandle( cell.getCellHandle(), name ); + } + return bosHandle; + } + + //////////////// mutators: //////////////////////// + + /** + * Sets the BOS general restart time. This is the time at which the bos + * server restarts itself and all running processes. + * + * @param executableTime Executable time object that represents what + * the BOS Server's general restart time should be. + * @exception AFSException If an error occurs in the native code + * @see Server.ExecutableTime + */ + public void setGeneralRestartTime( ExecutableTime executableTime ) + throws AFSException + { + this.setRestartTime( getBosHandle(), RESTART_GENERAL, executableTime ); + } + + /** + * Sets the BOS binary restart time. This is the time at which all new + * or newly modified AFS binaries are restarted. + * + * @param executableTime Executable time object that represents what + * the BOS Server's binary restart time should be. + * @exception AFSException If an error occurs in the native code + * @see Server.ExecutableTime + */ + public void setBinaryRestartTime( ExecutableTime executableTime ) + throws AFSException + { + this.setRestartTime( getBosHandle(), RESTART_BINARY, executableTime ); + } + + /////////////// custom information methods //////////////////// + + /** + * Returns a String representation of this Server. + * Contains the information fields and a list of partitions, admin, and + * processes. + * + * @return a String representation of the Server + */ + protected String getInfo() + { + String r; + try { + + r = "Server: " + name + "\n"; + + r += "\tdatabase: " + isDatabase() + "\t\tfileServer: " + + isFileServer() + "\n"; + r += "\tbad database: " + isBadDatabase() + "\tbad fileServer: " + + isBadFileServer() + "\n"; + //r += "\tAddress: " + getIPAddress()[0] + "\n"; + + // restart times: + r += "\tGeneral restart date: " + getGeneralRestartTime() + "\n"; + r += "\tBinary restart date: " + getBinaryRestartTime() + "\n"; + + if ( isFileServer() && !isBadFileServer() ) { + r += "\tPartitions:\n"; + + String parts[] = getPartitionNames(); + + for( int i = 0; i < parts.length; i++ ) { + r += "\t\t" + parts[i] + "\n"; + } + } + + if ( (isDatabase() && !isBadDatabase()) || + (isFileServer() && !isBadFileServer()) ) { + r += "\tAdmins:\n"; + + String ads[] = getAdminNames(); + + for( int i = 0; i < ads.length; i++ ) { + r += "\t\t" + ads[i] + "\n"; + } + } + + if ( (isDatabase() && !isBadDatabase()) || + (isFileServer() && !isBadFileServer()) ) { + r += "\tProcesses:\n"; + + String pros[] = getProcessNames(); + + for( int i = 0; i < pros.length; i++ ) { + r += "\t\t" + pros[i] + "\n"; + } + } + + } catch( Exception e ) { + return e.toString(); + } + return r; + } + + /** + * Returns a String containing the String + * representations of all the partitions of this Server. + * + * @return a String representation of the partitions + * @see Partition#getInfo + */ + protected String getInfoPartitions() throws AFSException + { + String r; + r = "Server: " + name + "\n\n"; + r += "--Partitions--\n"; + + Partition parts[] = getPartitions(); + + for( int i = 0; i < parts.length; i++ ) { + r += parts[i].getInfo() + "\n"; + } + return r; + } + + /** + * Returns a String containing the String + * representations of all the keys of this Server. + * + * @return a String representation of the keys + * @see Key#getInfo + */ + protected String getInfoKeys() throws AFSException + { + String r; + + r = "Server: " + name + "\n\n"; + r += "--Keys--\n"; + + Key kys[] = getKeys(); + + for( int i = 0; i < kys.length; i++ ) { + r += kys[i].getInfo() + "\n"; + } + + return r; + } + + /** + * Returns a String containing the String + * representations of all the processes of this Server. + * + * @return a String representation of the processes + * @see Process#getInfo + */ + protected String getInfoProcesses() throws AFSException + { + String r; + + r = "Server: " + name + "\n\n"; + r += "--Processes--\n"; + + Process pros[] = getProcesses(); + + for( int i = 0; i < pros.length; i++ ) { + r += pros[i].getInfo() + "\n"; + } + return r; + } + + /////////////// custom override methods //////////////////// + + /** + * Compares two Server objects respective to their names and does not + * factor any other attribute. Alphabetic case is significant in + * comparing names. + * + * @param server The Server object to be compared to this + * Server instance + * + * @return Zero if the argument is equal to this Server's name, a + * value less than zero if this Server's name is + * lexicographically less than the argument, or a value greater + * than zero if this Server's name is lexicographically + * greater than the argument + */ + public int compareTo(Server server) + { + return this.getName().compareTo(server.getName()); + } + + /** + * Comparable interface method. + * + * @see #compareTo(Server) + */ + public int compareTo(Object obj) + { + return compareTo((Server)obj); + } + + /** + * Tests whether two Server objects are equal, based on their + * names and hosting Cell. + * + * @param otherServer the Server to test + * @return whether the specifed Server is the same as this Server + */ + public boolean equals( Server otherServer ) + { + return ( name.equals(otherServer.getName()) ) && + ( this.getCell().equals(otherServer.getCell()) ); + } + + /** + * Returns the name of this Server + * + * @return the name of this Server + */ + public String toString() + { + return getName(); + } + + /////////////// native methods //////////////////// + + /** + * Opens a server for administrative vos use, based on the cell handle + * provided. Returns a vos server handle to be used by other + * methods as a means of identification. + * + * @param cellHandle a cell handle previously returned by + * a call to {@link #getCellHandle} + * @param serverName the name of the server for which to retrieve + * a vos handle + * @return a vos handle to the server + * @exception AFSException If an error occurs in the native code + * @see #getCellHandle + */ + protected static native int getVosServerHandle( int cellHandle, + String serverName ) + throws AFSException; + + /** + * Closes the given currently open vos server handle. + * + * @param vosHandle the vos server handle to close + * @exception AFSException If an error occurs in the native code + */ + protected static native void closeVosServerHandle( int vosHandle ) + throws AFSException; + + /** + * Opens a server for administrative bos use, based on the cell handle + * provided. Returns a bos server handle to be used by other methods + * as a means of identification. + * + * @param cellHandle a cell handle previously returned by a call + * to {@link #getCellHandle} + * @param serverName the name of the server for which to retrieve + * a bos handle + * @return a bos handle to the server + * @exception AFSException If an error occurs in the native code + * @see #getCellHandle + */ + protected static native int getBosServerHandle( int cellHandle, + String serverName ) + throws AFSException; + + /** + * Closes the given currently open bos server handle. + * + * @param bosHandle the bos server handle to close + * @exception AFSException If an error occurs in the native code + */ + protected static native void closeBosServerHandle( int bosHandle ) + throws AFSException; + + /** + * Fills in the information fields of the provided Server. + * + * @param cellHandle the handle of the cell to which the server belongs + * @see Cell#getCellHandle + * @param name the name of the server for which to get the information + * @param server the Server object in which to fill in + * the information + * @see Server + * @exception AFSException If an error occurs in the native code + */ + protected static native void getServerInfo( int cellHandle, String name, + Server server ) + throws AFSException; + + /** + * Returns the total number of partitions hosted by the server denoted by + * serverHandle, if the server is a fileserver. + * + * @param cellHandle the handle of the cell to which the server belongs + * @param serverHandle the vos handle of the server to which the + * partitions belong + * @return total number of partitions + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + * @see #getVosServerHandle + */ + protected static native int getPartitionCount( int cellHandle, + int serverHandle ) + throws AFSException; + + /** + * Begin the process of getting the partitions on a server. Returns + * an iteration ID to be used by subsequent calls to + * getPartitionsNext and getPartitionsDone. + * + * @param cellHandle the handle of the cell to which the server belongs + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server to which the + * partitions belong + * @see #getVosServerHandle + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getPartitionsBegin( int cellHandle, + int serverHandle ) + throws AFSException; + + /** + * Returns the next partition of the server. Returns null + * if there are no more partitions. + * + * @param iterationId the iteration ID of this iteration + * @see #getPartitionsBegin + * @return the name of the next partition of the server + * @exception AFSException If an error occurs in the native code + */ + protected static native String getPartitionsNextString( int iterationId ) + throws AFSException; + + /** + * Fills the next partition object of the server. Returns 0 if there + * are no more partitions, != 0 otherwise + * + * @param iterationId the iteration ID of this iteration + * @param thePartition the Partition object in which to fill the + * values of the next partition + * @see #getPartitionsBegin + * @return 0 if there are no more servers, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getPartitionsNext( int iterationId, + Partition thePartition ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see #getPartitionsBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getPartitionsDone( int iterationId ) + throws AFSException; + + /** + * Returns the total number of processes hosted by the server denoted by + * serverHandle. + * + * @param serverHandle the vos handle of the server to which the + * processes belong + * @return total number of processes + * @exception AFSException If an error occurs in the native code + * @see #getVosServerHandle + */ + protected static native int getProcessCount( int serverHandle ) + throws AFSException; + + /** + * Begin the process of getting the processes on a server. Returns + * an iteration ID to be used by subsequent calls to + * getProcessesNext and getProcessesDone. + * + * @param serverHandle the bos handle of the server to which the + * processes belong + * @see #getBosServerHandle + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getProcessesBegin( int serverHandle ) + throws AFSException; + + /** + * Returns the next process of the server. Returns null + * if there are no more processes. + * + * @param iterationId the iteration ID of this iteration + * @see #getProcessesBegin + * @return the name of the next process of the cell + * @exception AFSException If an error occurs in the native code + */ + protected static native String getProcessesNextString( int iterationId ) + throws AFSException; + + /** + * Fills the next process object of the server. Returns 0 if there + * are no more processes, != 0 otherwise. + * + * @param serverHandle the handle of the BOS server that hosts the process + * @see #getBosHandle + * @param iterationId the iteration ID of this iteration + * @param theProcess the Process object in which to fill the + * values of the next process + * @see #getProcessesBegin + * @return 0 if there are no more processes, != otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getProcessesNext( int serverHandle, + int iterationId, + Process theProcess ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see #getProcessesBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getProcessesDone( int iterationId ) + throws AFSException; + + /** + * Returns the total number of keys hosted by the server denoted by + * serverHandle. + * + * @param serverHandle the vos handle of the server to which the + * keys belong + * @return total number of keys + * @exception AFSException If an error occurs in the native code + * @see #getVosServerHandle + */ + protected static native int getKeyCount( int serverHandle ) + throws AFSException; + + /** + * Begin the process of getting the keys of a server. Returns + * an iteration ID to be used by subsequent calls to + * getKeysNext and getKeysDone. + * + * @param serverHandle the bos handle of the server to which the keys belong + * @see #getBosServerHandle + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getKeysBegin( int serverHandle ) + throws AFSException; + + /** + * Returns the next key of the server. Returns 0 if there + * are no more keys, != 0 otherwise. + * + * @param iterationId the iteration ID of this iteration + * @param theKey a {@link Key Key} object, in which to fill in the + * properties of the next key. + * @see #getKeysBegin + * @return 0 if there are no more keys, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getKeysNext( int iterationId, Key theKey ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see #getKeysBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getKeysDone( int iterationId ) + throws AFSException; + + /** + * Returns the total number of BOS administrators associated with the server + * denoted by serverHandle. + * + * @param serverHandle the vos handle of the server to which the + * BOS admins belong + * @return total number of BOS administrators + * @exception AFSException If an error occurs in the native code + * @see #getVosServerHandle + */ + protected static native int getBosAdminCount( int serverHandle ) + throws AFSException; + + /** + * Begin the process of getting the bos amdinistrators on a server. Returns + * an iteration ID to be used by subsequent calls to + * getBosAdminsNext and getBosAdminsDone. + * + * @param serverHandle the bos handle of the server to which the + * partitions belong + * @see #getBosServerHandle + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getBosAdminsBegin( int serverHandle ) + throws AFSException; + + /** + * Returns the next bos admin of the server. Returns null + * if there are no more admins. + * + * @param iterationId the iteration ID of this iteration + * @see #getBosAdminsBegin + * @return the name of the next admin of the server + * @exception AFSException If an error occurs in the native code + */ + protected static native String getBosAdminsNextString( int iterationId ) + throws AFSException; + + /** + * Returns the next bos admin of the server. Returns 0 if there + * are no more admins, != 0 otherwise. + * + * @param cellHandle the handle of the cell to which these admins belong + * @see #getCellHandle + * @param iterationId the iteration ID of this iteration + * @see #getBosAdminsBegin + * @param theUser the user object in which to fill the values of this admin + * @return 0 if no more admins, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getBosAdminsNext( int cellHandle, + int iterationId, User theUser ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see #getBosAdminsBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getBosAdminsDone( int iterationId ) + throws AFSException; + + /** + * Adds the given to name to the list of bos administrators on that server. + * + * @param serverHandle the bos handle of the server to which the + * partitions belong + * @see #getBosServerHandle + * @param adminName the name of the admin to add to the list + * @exception AFSException If an error occurs in the native code + */ + protected static native void addBosAdmin( int serverHandle, + String adminName ) + throws AFSException; + + /** + * Removes the given to name from the list of bos administrators on + * that server. + * + * @param serverHandle the bos handle of the server to which the + * partitions belong + * @see #getBosServerHandle + * @param adminName the name of the admin to remove from the list + * @exception AFSException If an error occurs in the native code + */ + protected static native void removeBosAdmin( int serverHandle, + String adminName ) + throws AFSException; + + /** + * Salvages (restores consistency to) a volume, partition, or server + * + * @param cellHandle the handle of the cell to which the volume belongs + * @see #getCellHandle + * @param serverHandle the bos handle of the server on which the + * volume resides + * @see #getBosServerHandle + * @param partitionName the name of the partition to salvage, + * can be null only if volName is + * null + * @param volName the name of the volume to salvage, + * can be null + * @param numSalvagers the number of salvager processes to run in parallel + * @param tempDir directory to place temporary files, can be + * null + * @param logFile where salvager log will be written, can be + * null + * @param inspectAllVolumes whether or not to inspect all volumes, + * not just those marked as active at crash + * @param removeBadlyDamaged whether or not to remove a volume if it's + * badly damaged + * @param writeInodes whether or not to record a list of inodes modified + * @param writeRootInodes whether or not to record a list of AFS + * inodes owned by root + * @param forceDirectory whether or not to salvage an entire directory + * structure + * @param forceBlockReads whether or not to force the salvager to read + * the partition + * one block at a time and skip badly damaged + * blocks. Use if partition has disk errors + */ + protected static native void salvage( int cellHandle, int serverHandle, + String partitionName, String volName, + int numSalvagers, String tempDir, + String logFile, + boolean inspectAllVolumes, + boolean removeBadlyDamaged, + boolean writeInodes, + boolean writeRootInodes, + boolean forceDirectory, + boolean forceBlockReads) + throws AFSException; + + /** + * Synchronizes a particular server with the volume location database. + * + * @param cellHandle the handle of the cell to which the server belongs + * @see #getCellHandle + * @param serverHandle the vos handle of the server + * @see #getVosServerHandle + * @param partition the id of the partition to sync, can be -1 to ignore + * @exception AFSException If an error occurs in the native code + */ + protected static native void syncServerWithVLDB( int cellHandle, + int serverHandle, + int partition ) + throws AFSException; + + /** + * Synchronizes the volume location database with a particular server. + * + * @param cellHandle the handle of the cell to which the server belongs + * @see #getCellHandle + * @param serverHandle the vos handle of the server + * @see #getVosServerHandle + * @param partition the id of the partition to sync, can be -1 to ignore + * @param forceDeletion whether or not to force the deletion of bad volumes + * @exception AFSException If an error occurs in the native code + */ + protected static native void syncVLDBWithServer( int cellHandle, + int serverHandle, + int partition, + boolean forceDeletion ) + throws AFSException; + + /** + * Retrieves a specified bos log from a server. Right now this + * method will simply return a huge String containing the log, but + * hopefully we can devise a better way to make this work more efficiently. + * + * @param serverHandle the bos handle of the server to which the key belongs + * @see #getBosServerHandle + * @param logLocation the full path and name of the desired bos log + * @exception AFSException If an error occurs in the native code + */ + protected static native String getLog( int serverHandle, String logLocation ) + throws AFSException; + + /** + * Fills in the restart time fields of the given {@link Server Server} + * object. + * + * @param serverHandle the bos handle of the server to which the key belongs + * @see #getBosServerHandle + * @param restartType whether to get the general or binary restart. + * Acceptable values are:

      + *
    • {@link RESTART_BINARY}
    • + *
    • {@link RESTART_GENERAL}
    + * @param theServer the Server object, in which to fill + * the restart time fields + * @exception AFSException If an error occurs in the native code + */ + private static native void getRestartTime( int serverHandle, + int restartType, + ExecutableTime executableTime ) + throws AFSException; + + /** + * Sets the restart time of the bos server. + * + * @param serverHandle the bos handle of the server to which the key belongs + * @see #getBosServerHandle + * @param restartType whether this is to be a general or binary restart. + * Acceptable values are:
      + *
    • {@link RESTART_BINARY}
    • + *
    • {@link RESTART_GENERAL}
    + * @param theServer the server object containing the desired information + * @exception AFSException If an error occurs in the native code + */ + private static native void setRestartTime( int serverHandle, + int restartType, + ExecutableTime executableTime ) + throws AFSException; + + /** + * Start all server processes. + * + * @param serverHandle the bos handle of the server to which the + * processes belong + * @see #getBosServerHandle + * @exception AFSException If an error occurs in the native code + */ + protected static native void startAllProcesses( int serverHandle ) + throws AFSException; + + /** + * Restart all server processes. + * + * @param serverHandle the bos handle of the server to which the + * processes belong + * @see #getBosServerHandle + * @param restartBosServer whether or not to restart the bos server as well + * @exception AFSException If an error occurs in the native code + */ + protected static native void restartAllProcesses( int serverHandle, + boolean restartBosServer ) + throws AFSException; + + /** + * Stop all server processes. + * + * @param serverHandle the bos handle of the server to which the + * processes belong + * @see #getBosServerHandle + * @exception AFSException If an error occurs in the native code + */ + protected static native void stopAllProcesses( int serverHandle ) + throws AFSException; + + /** + * Reclaims all memory being saved by the server portion of the native + * library. This method should be called when no more Server + * objects are expected to be used. + */ + protected static native void reclaimServerMemory(); + + /*====================================================================*/ + /* INNER CLASSES */ + /*====================================================================*/ + public static final class ExecutableTime implements Serializable + { + public static final short NEVER = 0; + public static final short NOW = 1; + + public static final short EVERYDAY = -1; + public static final short SUNDAY = 0; + public static final short MONDAY = 1; + public static final short TUESDAY = 2; + public static final short WEDNESDAY = 3; + public static final short THURSDAY = 4; + public static final short FRIDAY = 5; + public static final short SATURDAY = 6; + + static final DecimalFormat formatter = + (DecimalFormat)DecimalFormat.getInstance(); + + private short second; + private short minute; + private short hour; + private short day; + private boolean now; + private boolean never; + + static + { + formatter.applyPattern("00"); + } + + /** + * Internal constructor used to construct an empty object that will + * be passed to JNI for member synchronization of the BOS Server + * executable time this object represents. + */ + ExecutableTime() + { + this.second = (short) 0; + this.minute = (short) 0; + this.hour = (short) 0; + this.day = (short) -1; + this.now = false; + this.never = false; + } + + /** + * Constructs an ExecutableTime object that represents either + * a "now" or "never" BOS Executable + * Restart Time. + * + *

    Valid values for the type parameter are ExecutableTime.NOW + * or ExecutableTime.NEVER. If a value other than these two is used an + * IllegalArgumentException will be thrown. + * + * @param type either ExecutableTime.NOW or ExecutableTime.NEVER + * @exception IllegalArgumentException + * If a value other than ExecutableTime.NOW or + * ExecutableTime.NEVER is used for the type + * parameter. + * @see #isNow() + * @see #isNever() + * @see #Server.ExecutableTime(short, short, short) + */ + public ExecutableTime(short type) throws IllegalArgumentException + { + if (type == NOW) { + this.now = true; + this.never = false; + } else if (type == NEVER) { + this.now = false; + this.never = true; + } else { + throw new IllegalArgumentException("You must specify either " + + "ExecutableTime.NOW or " + + "ExecutableTime.NEVER when " + + "using this constructor."); + } + this.second = (short) 0; + this.minute = (short) 0; + this.hour = (short) 0; + this.day = (short) -1; + } + + /** + * Constructs an ExecutableTime object that may be used to + * represent a daily BOS Executable Restart Time of a process. + * + * @param second the second field for this representation of a + * BOS Server restart time value (range: 0-59) + * @param minute the minute field for this representation of a + * BOS Server restart time value (range: 0-59) + * @param hour the hour field for this representation of a BOS + * Server restart time value (range: 0-23) + * @exception IllegalArgumentException + * If any of the parameters values are out of range + * of their respective fields. + * @see #Server.ExecutableTime(short, short, short, short) + * @see #getSecond() + * @see #getMinute() + * @see #getHour() + */ + public ExecutableTime(short second, short minute, short hour) + throws IllegalArgumentException + { + this(second, minute, hour, ExecutableTime.EVERYDAY); + } + + /** + * Constructs an ExecutableTime object that may be used to + * represent the BOS Executable Restart Time of a process. + * + * @param second the second field for this representation of a + * BOS Server restart time value (range: 0-59) + * @param minute the minute field for this representation of a + * BOS Server restart time value (range: 0-59) + * @param hour the hour field for this representation of a BOS + * Server restart time value (range: 0-23) + * @param day the day field for this representation of a BOS + * Server restart time value.

      Valid values include: + * ExecutableTime.EVERYDAY (see also {@link + * #Server.ExecutableTime(short, short, short)})
      + * + * ExecutableTime.SUNDAY
      + * ExecutableTime.MONDAY
      + * ExecutableTime.TUESDAY
      + * ExecutableTime.WEDNESDAY
      + * ExecutableTime.THURSDAY
      + * ExecutableTime.FRIDAY
      + * ExecutableTime.SATURDAY
      + *
    + * @exception IllegalArgumentException + * If any of the parameters values are out of range + * of their respective fields. + * @see #Server.ExecutableTime(short, short, short) + * @see #getSecond() + * @see #getMinute() + * @see #getHour() + * @see #getDay() + */ + public ExecutableTime(short second, short minute, short hour, short day) + { + if ( (0 > second || second > 59) || + (0 > minute || minute > 59) || + (0 > hour || hour > 24) || + (-1 > day || day > 6) ) { + throw new IllegalArgumentException("One of the specified values " + + "are invalid."); + } + this.second = second; + this.minute = minute; + this.hour = hour; + this.day = day; + this.now = false; + this.never = false; + } + + /** + * Returns the second of this ExecutableTime object. + * + * @return the second of this ExecutableTime object. + * @exception IllegalStateException + * If the executable time this object represents has a value of + * "now" or "never". + */ + public short getSecond() throws IllegalStateException + { + if (now || never) { + throw new IllegalStateException("Executable time is set to 'now' or" + + " 'never'."); + } + return second; + } + + /** + * Returns the minute of this ExecutableTime object. + * + * @return the minute of this ExecutableTime object. + * @exception IllegalStateException + * If the executable time this object represents has a value of + * "now" or "never". + */ + public short getMinute() throws IllegalStateException + { + if (now || never) { + throw new IllegalStateException("Executable time is set to 'now' or" + + " 'never'."); + } + return minute; + } + + /** + * Returns the hour of this ExecutableTime object, in 24 hour time. + * + * @return the hour of this ExecutableTime object. + * @exception IllegalStateException + * If the executable time this object represents has a value of + * "now" or "never". + */ + public short getHour() throws IllegalStateException + { + if (now || never) { + throw new IllegalStateException("Executable time is set to 'now' or" + + " 'never'."); + } + return hour; + } + + /** + * Returns a numeric representation of the day of this ExecutableTime + * object. If it is daily, the value of ExecutableTime.EVERYDAY is returned. + * + *

    Possible return values are:
    + * + * ExecutableTime.EVERYDAY
    + *
    + * ExecutableTime.SUNDAY
    + * ExecutableTime.MONDAY
    + * ExecutableTime.TUESDAY
    + * ExecutableTime.WEDNESDAY
    + * ExecutableTime.THURSDAY
    + * ExecutableTime.FRIDAY
    + * ExecutableTime.SATURDAY
    + *
    + * + * @return a numeric representation of the day of this ExecutableTime + * object. + * @exception IllegalStateException + * If the executable time this object represents has a value of + * "now" or "never". + */ + public short getDay() throws IllegalStateException + { + if (now || never) { + throw new IllegalStateException("Executable time is set to 'now' or" + + " 'never'."); + } + return day; + } + + /** + * Returns a String representation, name for the day of the week or + * "Everyday", of this object's day property. + * + *

    Possible return values are: + *

    +     * Sunday
    +     * Monday
    +     * Tuesday
    +     * Wednesday
    +     * Thursday
    +     * Friday
    +     * Saturday
    +     * 
    +     * Everyday
    +     * 
    + * + * @return the day of this ExecutableTime object. + * @exception IllegalStateException + * If the executable time this object represents has a value of + * "now" or "never". + * @see #getDay() + */ + public String getDayString() throws IllegalStateException + { + switch (getDay()) + { + case 0: + return "Sunday"; + case 1: + return "Monday"; + case 2: + return "Tuesday"; + case 3: + return "Wednesday"; + case 4: + return "Thursday"; + case 5: + return "Friday"; + case 6: + return "Saturday"; + default: + return "Everyday"; + } + } + + /** + * Returns whether or not the BOS restart time, represented by this + * ExecutableTime object, is set to "now" or not. + * This means that at some point in the past, when someone set it to + * "now", the bosserver restarted all its processes, + * and never again. + * + * @return whether or not the restart time is "now" + */ + public boolean isNow() + { + return now; + } + + /** + * Returns the second of this ExecutableTime object. + * + * @return the second of this ExecutableTime object. + */ + /** + * Returns whether or not the BOS restart time, represented by this + * ExecutableTime object, is set to "never" or not. + * This means that the bosserver will never restart its processes. + * + * @return whether or not the restart time is "never" + */ + public boolean isNever() + { + return never; + } + + /** + * Tests whether two ExecutableTime objects are equal, + * based on a + * comparison of each of their respective properties. If + * "now" or "never" is set in either object, + * only those properties are analyzed. + * + * @param time the ExecutableTime to test against + * @return whether the specifed ExecutableTime is the same as this + * ExecutableTime as defined above + */ + public boolean equals( ExecutableTime time ) + { + boolean same = false; + try { + same = ( (second == time.getSecond()) && + (minute == time.getMinute()) && + (hour == time.getHour() ) && + (day == time.getDay() ) ); + } catch (Exception e) { + same = ( (now == time.isNow() ) && + (never == time.isNever() ) ); + + } + return same; + } + + /** + * Returns the String representation of time value of this + * ExecutableTime object. + * + *

    Possible return values:
    + *

  • "Now"
    + *
  • "Never"
    + *
  • Day and time string in the form:
         + * <day> at <hh>:<MM>[:<ss>] + *

    + * + * Example Return Values:
    +     * Sunday at 04:00
    +     * Sunday at 05:10:30
    +     * Everyday at 20:00
    + * + * @return the String representation of this ExecutableTime + * object + */ + public String toString() + { + if (now) { + return "Now"; + } else if (never) { + return "Never"; + } else { + try { + if (second != 0) { + return getDayString() + " at " + + ExecutableTime.formatter.format(hour) + ":" + + ExecutableTime.formatter.format(minute) + ":" + + ExecutableTime.formatter.format(second); + } else { + return getDayString() + " at " + + ExecutableTime.formatter.format(hour) + ":" + + ExecutableTime.formatter.format(minute); + } + } catch (Exception e) { + return "(unknown)"; + } + } + } + + } + /*====================================================================*/ + +} + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/Token.java b/src/JAVA/classes/org/openafs/jafs/Token.java new file mode 100644 index 0000000..5fe2ef7 --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/Token.java @@ -0,0 +1,493 @@ +/* + * @(#)Token.java 1.2 05/06/2002 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.io.Serializable; + +/** + * An abstract representation of an AFS authentication token. It conveniently + * maintains the handle associated with token and the cell to which the token + * is authenticated. + *

    + * + * Constructing a Token object results in an immediate attempt to + * authenticate the user within the specified cell. If this attempt fails, an + * {@link AFSException} will be thrown. Therefore, if the + * construction of the object succeeds without an exception, then the + * Token is considered authenticated. + * + * The construction of a Token object acts as an entry point + * for authentication into the AFS system. Thus, when you construct a + * {@link Cell} object, you must pass in an instance of a + * Token that has been authenticated within the AFS cell that + * Cell is intended to represent. You will only be + * allowed to perform actions that the user, used to authenticate + * Token, is authorized to perform. You must construct a + * Token object before constructing a Cell object, + * which is required by all other objects within this package either directly + * or indirectly.

    + * + * If an error occurs during a method call, an + * AFSException will be thrown. This class is the Java + * equivalent of errors thrown by AFS; see {@link AFSException} + * for a complete description.

    + * + * + * The following is a simple example of how to construct and use a + * Token object. It shows how to construct a Cell + * using a Token. See {@link Cell} for a more detailed example + * of constructing and using a Cell object.

    + * + *
    + * import org.openafs.jafs.AFSException;
    + * import org.openafs.jafs.Cell;
    + * import org.openafs.jafs.Token;
    + * ...
    + * public class ...
    + * {
    + *   ...
    + *   private Cell cell;
    + *   private Token token;
    + *   ...
    + *   public static void main(String[] args) throws Exception
    + *   {
    + *     String username   = arg[0];
    + *     String password   = arg[1];
    + *     String cellName   = arg[2];
    + *     String serverName = arg[3];
    + * 
    + *     token = new Token(username, password, cellName);
    + *     cell   = new Cell(token);
    + *     ...
    + *   }
    + *   ...
    + * }
    + * 
    + * + */ + +public class Token implements Serializable, Comparable +{ + public static int ANYUSER_PAG_ID; + + protected int tokenHandle; + protected int pagID = -1; + protected int errno; + + protected String cellName; + protected String username; + private String password; + + private boolean hasInitialized = false; + + /** + * Load the native libraries libjafs and + * libjafs. + */ + static + { + try { + Class.forName("org.openafs.jafs.AFSLibraryLoader"); + try { + initializeAdminClient(); + } catch (Exception e) { + System.err.println(e); + } + } catch (ClassNotFoundException e) { + /* Most likely running on a client, do nothing */ + } + } + + /** + * Constructs a new Token object instance given + * the name of the AFS cell it represents and the username and password + * of the user to be Tokend for + * administrative access. + * + * @param username the name of the user to Token with + * @param password the password of that user + * @param cellName the name of the cell to Token into + * @param login if true, automatically login upon construction + * @exception AFSException If an error occurs in the native code + */ + protected Token( String username, String password, String cellName, + boolean automaticallyLogin ) + throws AFSException + { + this.username = username; + this.password = password; + this.cellName = cellName; + + /* By default lets authenticate the user using libafsauthent.a */ + if (automaticallyLogin) login(); + } + + /** + * Constructs a new Token object instance given + * the name of the AFS cell it represents and the username and password + * of the user to be Tokend for + * administrative access. + * + * @param username the name of the user to Token with + * @param password the password of that user + * @param cellName the name of the cell to Token into + * @exception AFSException If an error occurs in the native code + */ + public Token( String username, String password, String cellName ) + throws AFSException + { + this.username = username; + this.password = password; + this.cellName = cellName; + +System.out.println(username + ", " + cellName); + /* By default lets authenticate the user using libafsauthent.a */ + login(); + } + + /** + * Returns the name of the AFS cell that this Token was + * authenticated against. + * + * @exception AFSException If an error occurs in the native code + * @return the name of the AFS cell associated with this Token. + */ + public String getCellName() + { + return cellName; + } + + /** + * Returns the username of user to whom this token belongs. + * + * @exception AFSException If an error occurs in the native code + * @return the username of the user represented by this Token + */ + public String getUsername() + { + return username; + } + + /** + * Returns a token handle that can be used to prove this authentication + * later. + * + * @exception AFSException If an error occurs in the native code + * @return a token representing the authentication + */ + protected int getHandle() + { + return tokenHandle; + } + + /** + * Closes the given currently open token. + * + * @exception AFSException If an error occurs in the native code + */ + public void close() throws AFSException + { + close(tokenHandle); + } + + /** + * Gets the expiration time for a given token. + * + * @return a long representing the UTC time for the token expiration + * @exception AFSException If an error occurs in the native code + */ + public long getExpiration() throws AFSException + { + return getExpiration(tokenHandle); + } + + /** + * Authenticates a user in kas, and binds that authentication + * to the current process. + * + * @exception AFSException If an error occurs in the native code + */ + public void klog() throws AFSException + { + if (!hasInitialized) { + initializeUserSpace(); + hasInitialized = true; + } + if (pagID > -1) { + relog(pagID); + } else { + pagID = klog(username, password, cellName, pagID); + } + } + + /** + * Authenticates a user in KAS, and binds that authentication + * to the current process. + * + * @exception AFSException If an error occurs in the native code + */ + public void login() throws AFSException + { + this.tokenHandle = this.getToken(cellName, username, password); +System.out.println("Token handle -> " + tokenHandle); + } + + /** + * Initialize the user space AFS client (libjafs). + * + *

    The user space client must be initialized prior to any + * user space related methods, including: klog, unlog, relog, + * and shutdown. + * + * @exception AFSException If an error occurs in the native code + */ + protected static void initializeUserSpace() throws AFSException + { + try { + Token.initUserSpace(); + } catch (AFSException e) { + System.err.println(e.getMessage()); + } + try { + Runtime.getRuntime().addShutdownHook(new AFSShutdownHandler()); + } catch (Exception e) { + System.err.println("Could not register shutdown hook: " + e.toString()); + } + } + + /////////////// custom override methods //////////////////// + + /** + * Compares two ACL objects respective to their paths and does not + * factor any other attribute. Alphabetic case is significant in + * comparing names. + * + * @param acl The ACL object to be compared to this ACL + * instance + * + * @return Zero if the argument is equal to this ACL's path, a + * value less than zero if this ACL's path is + * lexicographically less than the argument, or a value greater + * than zero if this ACL's path is lexicographically + * greater than the argument + */ + public int compareTo(Token token) + { + return this.toString().compareTo(token.toString()); + } + + /** + * Comparable interface method. + * + * @see #compareTo(Token) + */ + public int compareTo(Object obj) + { + return compareTo((Token)obj); + } + + /** + * Tests whether two Cell objects are equal, based on their + * names. Does not test whether the objects are actually the same + * representational instance of the AFS cell. + * + * @param otherCell the Cell to test + * @return whether the specifed user is the same as this user + */ + public boolean equals( Token token ) + { + return this.toString().equals( token.toString() ); + } + + /** + * Returns the name of this Cell + * + * @return the name of this Cell + */ + public String toString() + { + return username + "@" + cellName + ":" + tokenHandle; + } + + /////////////// native methods found in *Token.c //////////////////// + + /** + * Initialize the user space library. + * + * @exception AFSException If an error occurs in the native code + */ + private static native void initUserSpace() throws AFSException; + + /** + * Initialize the administrative library. + * + * @exception AFSException If an error occurs in the native code + */ + protected static native void initializeAdminClient() throws AFSException; + + /** + * Returns a token handle that can be used to prove this authentication + * later. + * + * @param cellName the name of the cell in which to Token this user + * @param userName the name of the user to Token + * @param password the password of the user + * @exception AFSException If an error occurs in the native code + * @return a token representing the authentication + */ + protected native int getToken( String cellName, String username, + String password ) + throws AFSException; + + /** + * Closes the given currently open token. + * + * @param tokenHandle the token to close + * @exception AFSException If an error occurs in the native code + */ + protected native void close( int tokenHandle ) throws AFSException; + + /** + * Gets the expiration time for a given token. + * + * @param tokenHandle a token handle previously returned by a call + * to {@link #getToken} + * @see #getToken + * @return a long representing the UTC time for the token expiration + * @exception AFSException If an error occurs in the native code + */ + protected native long getExpiration( int tokenHandle ) + throws AFSException; + + /** + * Authenticates a user in KAS, and binds that authentication + * to the current thread or native process. + * + * @param username the login to authenticate + * (expected as username@cellname) + * @param password the password of the login + * @param cellName the name of the cell to authenticate into + * @param id the existing pag (or 0) + * + * @return the assigned pag + * @exception AFSException If an error occurs in the native code + */ + protected native int klog(String username, String password, + String cellName, int id) + throws AFSException; + + /** + * Authenticates a user in KAS by a previously acquired PAG ID, and binds + * that authentication to the current thread or native process. + * + *

    This method does not require the user's username and password to + * fully authenticate their request. Rather it utilizes the user's PAG ID + * to recapture the user's existing credentials. + * + *

    This method is called by the public klog method, which + * internally manages the PAG ID. Additionally, an application needs only + * call klog, this reduces the amount of complexity and ensures + * that relog is never called before a klog. + * + * @param int User's current PAG (process authentication group) ID + * @exception AFSException If an error occurs in the native code + */ + protected native void relog(int id) throws AFSException; + + /** + * Manually discards all AFS credentials associated with the bound user. + * + * @exception AFSException If an error occurs in the native code + */ + public native void unlog() throws AFSException; + + /** + * Inform the native library that the application is + * shutting down and will be unloading. + * + *

    The library will make a call informing the file server that it will + * no longer be available for callbacks. + */ + protected static native void shutdown(); + + /** + * Reclaims all memory being saved by the authentication portion of + * the native library. + * This method should be called when no more authentications are expected. + */ + protected static native void reclaimAuthMemory(); +} + +/*=======================================================================*/ +/** + * Class that loads the native libraries required for direct communication with + * AFS. Since the Token class is serializable the function of loading the + * native libraries must be performed in a non-serialized class, one that will + * not be included in any client side application packages. + * + * @version 1.0, 06/13/2001 + */ +class AFSLibraryLoader +{ + static + { + System.loadLibrary("jafs"); + System.loadLibrary("jafsadm"); + } +} +/*=======================================================================*/ +/** + * Class that handles graceful AFS application shutdown procedures by + * instructing the native library to inform the file system server that + * it is shutting down. + * + * @version 1.0, 06/13/2001 + */ +class AFSShutdownHandler extends Thread +{ + public AFSShutdownHandler() {} + + /** + * This is the execution method satisfying the interface requirement as a + * stand alone runnable thread. + * + *

    This method will automatically be invoked by the Thread instantiator. + * + * @see Token#shutdown() + */ + public void run() + { + System.out.println("Shutting down Java AFS library..."); + org.openafs.jafs.Token.shutdown(); + } +} +/*=======================================================================*/ + + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/User.java b/src/JAVA/classes/org/openafs/jafs/User.java new file mode 100644 index 0000000..b34293f --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/User.java @@ -0,0 +1,1948 @@ +/* + * @(#)User.java 1.0 6/29/2001 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.GregorianCalendar; +import java.util.Date; +import java.util.ArrayList; +import java.io.Serializable; + +/** + * An abstract representation of an AFS user. It holds information about + * the user, such as what groups it belongs to. + *

    + * + * Constructing an instance of a User does not mean an actual + * AFS user is created in a cell -- usually a User + * object is a representation of an already existing AFS user. If, + * however, the User is constructed with the name of a + * user that does not exist in the cell represented by the provided + * Cell, a new user with that name can be + * created in that server by calling the {@link #create(String, int)} or + * {@link #create(String)} method. If such a user does already exist when + * one of these methods is called, an exception will be thrown.

    + * + * Each User object has its own individual set of + * Groups that it owns and Groups for which + * it is a member. These represents the properties and attributes + * of an actual AFS user. + *

    + * + * Since this User object is a union of both the PTS and KAS + * properties of AFS users, some methods meant for users with a PTS entry + * will throw exceptions if used on a user with only a KAS entry, and vice + * versa.

    + * + * + * + * Associated with an AFS user are many attributes, such as whether or not + * it can change its own password, or who is allowed to find out the groups + * to which this user belongs. The User class has many + * "set" methods to indicate values for these attributes (i.e. + * {@link #setChangePassword(boolean)} and {@link #setListMembership(int)}). + * However, in order for these values to be written to the actual AFS user, + * the {@link #flushInfo()} method needs to be called. This writes all user + * attributes set through this API to AFS. This is done to minimize calls + * through JNI.

    + * + * + * The following is a simple example of how to construct and use a + * User object. It iterates through the list of users + * (a union of pts and kas users) for a cell, and prints out the name and + * id of each. + * + *

    + * import org.openafs.jafs.Cell;
    + * import org.openafs.jafs.AFSException;
    + * import org.openafs.jafs.User;
    + * ...
    + * public class ...
    + * {
    + *   ...
    + *   private Cell cell;
    + *   ...
    + *   public static void main(String[] args) throws Exception
    + *   {
    + *     String username   = arg[0];
    + *     String password   = arg[1];
    + *     String cellName   = arg[2];
    + * 
    + *     token  = new Token(username, password, cellName);
    + *     cell   = new Cell(token);
    + *     server = cell.getServer(serverName);
    + * 
    + *     System.out.println("Users in Cell " + cell.getName() + ":");
    + *     User[] users = cell.getUsers();
    + *     for (int i = 0; i < users.length; i++) {
    + *       System.out.println(" -> " + users[i] + ": " users[i].getID());
    + *     }
    + *   }
    + *   ...
    + * }
    + * 
    + * + */ +public class User implements PTSEntry, Serializable, Comparable +{ + /** + * Only the owner of the user has access + */ + public static final int USER_OWNER_ACCESS = 0; + /** + * Any user has access + */ + public static final int USER_ANYUSER_ACCESS = 1; + + /** + * User has administrative kas privileges + */ + public static final int ADMIN = 0; + /** + * User has no administrative kas privileges + */ + public static final int NO_ADMIN = 1; + + /** + * TGS will grant tickets for user + */ + public static final int GRANT_TICKETS = 0; + /** + * TGS will not grant tickets for user + */ + public static final int NO_GRANT_TICKETS = 1; + + /** + * TGS can use user's key for an encryption key + */ + public static final int ENCRYPT = 0; + /** + * TGS cannot use user's key for an encryption key + */ + public static final int NO_ENCRYPT = 1; + + /** + * User can change their password + */ + public static final int CHANGE_PASSWORD = 0; + /** + * User cannot change their password + */ + public static final int NO_CHANGE_PASSWORD = 1; + + /** + * User can reuse their password + */ + public static final int REUSE_PASSWORD = 0; + /** + * User cannot reuse their password + */ + public static final int NO_REUSE_PASSWORD = 1; + + protected Cell cell; + protected int cellHandle; + protected String name; + + /** + * Does this user have a kas entry? + */ + protected boolean kas; + /** + * Does this user have a pts entry? + */ + protected boolean pts; + + // pts fields + protected int groupCreationQuota; + protected int groupMembershipCount; + protected int nameUID; + protected int ownerUID; + protected int creatorUID; + + /** + * who is allowed to execute pts examine for this user. Valid values are: + *
      + *
    • {@link #USER_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #USER_ANYUSER_ACCESS} + * -- any user has permission
    + */ + protected int listStatus; + /** + * who is allowed to execute pts listowned for this user. Valid values are: + *
      + *
    • {@link #USER_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #USER_ANYUSER_ACCESS} + * -- any user has permission
    + */ + protected int listGroupsOwned; + /** + * who is allowed to execute pts membership for this user. Valid values are: + *
      + *
    • {@link #USER_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #USER_ANYUSER_ACCESS} + * -- any user has permission
    + */ + protected int listMembership; + protected String owner; + protected String creator; + + // lists + protected ArrayList groups; + protected ArrayList groupNames; + protected ArrayList groupsOwned; + protected ArrayList groupsOwnedNames; + + // kas fields + /** + * whether or not this user has kas administrative privileges. + * Valid values are: + *
      + *
    • {@link #ADMIN}
    • + *
    • {@link #NO_ADMIN}
    + */ + protected int adminSetting; + /** + * whether the TGS will grant tickets for this user. Valid values are: + *
      + *
    • {@link #GRANT_TICKETS}
    • + *
    • {@link #NO_GRANT_TICKETS}
    + */ + protected int tgsSetting; + /** + * whether the TGS can use this user's key as an encryption key. Valid values are: + *
      + *
    • {@link #ENCRYPT}
    • + *
    • {@link #NO_ENCRYPT}
    + */ + protected int encSetting; + /** + * whether this user is allowed to change its password. Valid values are: + *
      + *
    • {@link #CHANGE_PASSWORD}
    • + *
    • {@link #NO_CHANGE_PASSWORD}
    + */ + protected int cpwSetting; + /** + * whether this user is allowed to reuse its password. Valid values are: + *
      + *
    • {@link #REUSE_PASSWORD}
    • + *
    • {@link #NO_REUSE_PASSWORD}
    + */ + protected int rpwSetting; + protected int userExpiration; + protected int lastModTime; + protected String lastModName; + protected int lastChangePasswordTime; + protected int maxTicketLifetime; + protected int keyVersion; + protected String encryptionKey; + protected long keyCheckSum; + protected int daysToPasswordExpire; + protected int failLoginCount; + protected int lockTime; + protected int lockedUntil; + + // Dates and times + protected GregorianCalendar lockedUntilDate; + protected GregorianCalendar userExpirationDate; + protected GregorianCalendar lastModTimeDate; + protected GregorianCalendar lastChangePasswordTimeDate; + + /** + * Whether or not the information fields of this user have been filled. + */ + protected boolean cachedInfo; + + /** + * Constructs a new User object instance given the name + * of the AFS user and the AFS cell, represented by + * cell, to which it belongs. This does not actually + * create a new AFS user, it just represents one. + * If name is not an actual AFS user, exceptions + * will be thrown during subsequent method invocations on this + * object, unless the {@link #create(String, int)} or {@link #create(String)} + * method is explicitly called to create it. + * + * @param name the name of the user to represent + * @param cell the cell to which the user belongs. + * @exception AFSException If an error occurs in the native code + */ + public User( String name, Cell cell ) throws AFSException + { + this.name = name; + this.cell = cell; + cellHandle = cell.getCellHandle(); + + groups = null; + groupNames = null; + groupsOwned = null; + groupsOwnedNames = null; + cachedInfo = false; + kas = false; + pts = false; + } + + /** + * Constructs a new User object instance given the name + * of the AFS user and the AFS cell, represented by + * cell, to which it belongs. This does not actually + * create a new AFS user, it just represents one. + * If name is not an actual AFS user, exceptions + * will be thrown during subsequent method invocations on this + * object, unless the {@link #create(String, int)} or {@link #create(String)} + * method is explicitly called to create it. Note that if the process + * doesn't exist and preloadAllMembers is true, an exception + * will be thrown. + * + *

    This constructor is ideal for point-in-time representation and + * transient applications. It ensures all data member values are set and + * available without calling back to the filesystem at the first request + * for them. Use the {@link #refresh()} method to address any coherency + * concerns. + * + * @param name the name of the user to represent + * @param cell the cell to which the user belongs. + * @param preloadAllMembers true will ensure all object members are + * set upon construction; + * otherwise members will be set upon access, + * which is the default behavior. + * @exception AFSException If an error occurs in the native code + * @see #refresh + */ + public User( String name, Cell cell, boolean preloadAllMembers ) + throws AFSException + { + this(name, cell); + if (preloadAllMembers) refresh(true); + } + + /** + * Constructs a blank User object given the cell to which + * the user belongs. This blank object can then be passed into other + * methods to fill out its properties. + * + * @exception AFSException If an error occurs in the native code + * @param cell the cell to which the user belongs. + */ + User( Cell cell ) throws AFSException + { + this( null, cell ); + } + + /*-------------------------------------------------------------------------*/ + + /** + * Creates the kas and pts entries for a new user in this cell. + * Automatically assigns a user id. + * * + * @param password the password for the new user + * @exception AFSException If an error occurs in the native code + */ + public void create( String password ) throws AFSException + { + create( password, 0 ); + } + + /** + * Creates the kas and pts entries for a new user in this cell. + * + * @param password the password for the new user + * @param uid the user id to assign to the new user + * + * @exception AFSException If an error occurs in the native code + */ + public void create( String password, int uid ) throws AFSException + { + create( cell.getCellHandle(), name, password, uid ); + } + + /** + * Deletes the pts and kas entries for a user in this cell. Deletes this user + * from the membership list of the groups to which it belonged, but does not + * delete the groups owned by this user. Also nullifies this corresponding + * Java object. + * + * @exception AFSException If an error occurs in the native code + */ + public void delete() throws AFSException + { + delete( cell.getCellHandle(), name ); + + cell = null; + name = null; + kas = false; + pts = false; + owner = null; + creator = null; + groups = null; + groupsOwned = null; + groupNames = null; + groupsOwnedNames = null; + lastModName = null; + encryptionKey = null; + lockedUntilDate = null; + userExpirationDate = null; + lastModTimeDate = null; + lastChangePasswordTimeDate = null; + try { + finalize(); + } catch( java.lang.Throwable t ) { + throw new AFSException( t.getMessage() ); + } + } + + /** + * Unlocks the given user if they were locked out of the cell. + * + * @param userName the name of the user to unlock + * @exception AFSException If an error occurs in the native code + */ + public void unlock() throws AFSException + { + unlock( cell.getCellHandle(), name ); + lockedUntil = 0; + lockedUntilDate = null; + } + + /** + * Flushes the current information of this User object to disk. + * This will update the information of the actual AFS user to match the + * settings that have been modified within this User object. + * This function must be called before any changes made to the information + * fields of this user will be seen by AFS. + * + * @exception AFSException If an error occurs in the native code + */ + public void flushInfo() throws AFSException + { + setUserInfo( cell.getCellHandle(), name, this ); + } + + /** + * Change the name of this user. Automatically flushes the info of this + * user in order to update kas entry of the new name. NOTE: renaming a + * locked user will unlock that user. + * + * @param newName the new name for this user + * @exception AFSException If an error occurs in the native code + */ + public void rename( String newName ) throws AFSException + { + rename( cell.getCellHandle(), name, newName ); + name = newName; + flushInfo(); + } + + /** + * Refreshes the properties of this User object instance with values from + * the AFS user it represents. All properties that have been initialized + * and/or accessed will be renewed according to the values of the AFS user + * this User object instance represents. + * + *

    Since in most environments administrative changes can be administered + * from an AFS command-line program or an alternate GUI application, this + * method provides a means to refresh the Java object representation and + * thereby ascertain any possible modifications that may have been made + * from such alternate administrative programs. Using this method before + * an associated instance accessor will ensure the highest level of + * representative accuracy, accommodating changes made external to the + * Java application space. If administrative changes to the underlying AFS + * system are only allowed via this API, then the use of this method is + * unnecessary. + * + * @exception AFSException If an error occurs in the native code + */ + public void refresh() throws AFSException + { + refresh(false); + } + + /** + * Refreshes the properties of this User object instance with values from + * the AFS user it represents. If all is true + * then all of the properties of this User object instance will be + * set, or renewed, according to the values of the AFS user it represents, + * disregarding any previously set properties. + * + *

    Thus, if all is false then properties that + * are currently set will be refreshed and properties that are not set will + * remain uninitialized. See {@link #refresh()} for more information. + * + * @param all if true set or renew all object properties; otherwise renew + * all set properties + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + protected void refresh(boolean all) throws AFSException + { + if ( all || cachedInfo ) { + refreshInfo(); + } + if ( all || groupsOwned != null ) { + refreshGroupsOwned(); + } + if ( all || groupsOwnedNames != null ) { + refreshGroupsOwnedNames(); + } + if ( all || groups != null ) { + refreshGroups(); + } + if ( all || groupNames != null ) { + refreshGroupNames(); + } + } + + /** + * Refreshes the information fields of this User to reflect + * the current state of the AFS user. Does not refresh the groups to which + * the user belongs or groups owned by the user. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshInfo() throws AFSException + { + getUserInfo( cell.getCellHandle(), name, this ); + cachedInfo = true; + lastModTimeDate = null; + lastChangePasswordTimeDate = null; + lockedUntilDate = null; + userExpirationDate = null; + } + + /** + * Refreshes the current information about the group names to which the + * user belongs. Does not refresh the information fields of the user or + * the groups owned. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshGroupNames() throws AFSException + { + String currName; + int iterationID = getUserGroupsBegin( cell.getCellHandle(), name ); + groupNames = new ArrayList(); + while( ( currName = getUserGroupsNextString( iterationID ) ) != null ) { + groupNames.add( currName ); + } + getUserGroupsDone( iterationID ); + } + + /** + * Refreshes the current information about the group objects to which the + * user belongs. Does not refresh the information fields of the user or + * the groups owned. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshGroups() throws AFSException + { + Group currGroup; + int iterationID = getUserGroupsBegin( cell.getCellHandle(), name ); + + groups = new ArrayList(); + + currGroup = new Group( cell ); + while( getUserGroupsNext( cellHandle, iterationID, currGroup ) != 0 ) { + groups.add( currGroup ); + currGroup = new Group( cell ); + } + getUserGroupsDone( iterationID ); + } + + /** + * Refreshes the current information about the group names that the user + * owns. Does not refresh the information fields of the user or the groups + * belonged to. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshGroupsOwnedNames() throws AFSException + { + String currName; + int iterationID = this.getGroupsOwnedBegin( cell.getCellHandle(), name ); + groupsOwnedNames = new ArrayList(); + while( ( currName = this.getGroupsOwnedNextString( iterationID ) ) + != null ) { + groupsOwnedNames.add( currName ); + } + this.getGroupsOwnedDone( iterationID ); + } + + /** + * Refreshes the current information about the group objects that the user \ + * owns. Does not refresh the information fields of the user or the groups + * belonged to. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshGroupsOwned() throws AFSException + { + Group currGroup; + int iterationID = getGroupsOwnedBegin( cell.getCellHandle(), name ); + groupsOwned = new ArrayList(); + currGroup = new Group( cell ); + while( getGroupsOwnedNext( cellHandle, iterationID, currGroup ) != 0 ) { + groupsOwned.add( currGroup ); + currGroup = new Group( cell ); + } + getGroupsOwnedDone( iterationID ); + } + + /** + * Adds an access control list entry for some AFS directory for this user. + * + * @param directory the full path of the place in the AFS file system + * for which to add an entry + * @param read whether or not to allow read access to this user + * @param write whether or not to allow write access to this user + * @param lookup whether or not to allow lookup access to this user + * @param delete whether or not to allow deletion access to this user + * @param insert whether or not to allow insertion access to this user + * @param lock whether or not to allow lock access to this user + * @param admin whether or not to allow admin access to this user + * @exception AFSException If an error occurs in the native code + public void setACL( String directory, boolean read, boolean write, boolean lookup, boolean delete, boolean insert, boolean lock, boolean admin ) throws AFSException + { + cell.setACL( directory, name, read, write, lookup, delete, insert, lock, admin ); + } + */ + + //////////////// ACCESSORS //////////////////////// + + /** + * Returns the name of this user. + * + * @return the name of this user + */ + public String getName() + { + return name; + } + + /** + * Returns the Cell this user belongs to. + * + * @return the Cell this user belongs to + */ + public Cell getCell() + { + return cell; + } + + /** + * Returns whether or not this user has a kas entry. + * + * @return whether or not this user has a kas entry + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean isKAS() throws AFSException + { + if ( !cachedInfo ) refreshInfo(); + return kas; + } + + /** + * Returns whether or not this user has a pts entry. + * + * @return whether or not this user has a pts entry + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean isPTS() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return pts; + } + + /** + * PTS: Returns an array of the Group objects + * to which this user belongs. + * + * @return an array of the groups to which this user belongs + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public Group[] getGroups() throws AFSException + { + if( groups == null ) refreshGroups(); + return (Group[]) groups.toArray( new Group[groups.size()] ); + } + + /** + * PTS: Returns the total count of groups this user owns. + * + *

    If the total list of groups or group names have already been + * collected (see {@link #getGroupsOwned()}), then the returning value + * will be calculated based upon the current list. Otherwise, PTS will + * be explicitly queried for the information. + * + * @return total count of groups this user owns + * @exception AFSException If an error occurs in the native code + * @see #getGroupsOwned() + * @see #getGroupsOwnedNames() + */ + public int getGroupsOwnedCount() throws AFSException + { + if( groupsOwned != null ) { + return groupsOwned.size(); + } else if ( groupsOwnedNames != null ) { + return groupsOwnedNames.size(); + } else { + return getGroupsOwnedCount( cell.getCellHandle(), name ); + } + } + + /** + * PTS: Returns an array of the Group objects + * this user owns. + * + * @return an array of the Groups this user owns + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public Group[] getGroupsOwned() throws AFSException + { + if( groupsOwned == null ) refreshGroupsOwned(); + return (Group[]) groupsOwned.toArray( new Group[groupsOwned.size()] ); + } + + /** + * PTS: Returns a String array of the group names + * to which this user belongs. + * + * @return a String array of the groups to which this + * user belongs + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public String[] getGroupNames() throws AFSException + { + if( groupNames == null ) refreshGroupNames(); + return (String []) groupNames.toArray( new String[groupNames.size() ] ); + } + + /** + * PTS: Returns a String array of the group names + * this user owns. + * + * @return a String array of the groups this user owns + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public String[] getGroupsOwnedNames() throws AFSException + { + if( groupsOwnedNames == null ) refreshGroupsOwnedNames(); + return (String []) groupsOwnedNames.toArray( new String[groupsOwnedNames.size() ] ); + } + + /** + * PTS: Returns the numeric AFS id of this user. + * + * @return the AFS id of this user + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getUID() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return nameUID; + } + + /** + * PTS: Returns how many more groups this user is allowed to create. + * -1 indicates unlimited. + * + * @return the group creation quota + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getGroupCreationQuota() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return groupCreationQuota; + } + + /** + * PTS: Returns the number of groups to which this user belongs. + * + * @return the group membership count + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getGroupMembershipCount() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return groupMembershipCount; + } + + /** + * PTS: Returns the owner of this user in the form of a {@link PTSEntry}. + * + *

    The returning object could be either a {@link User} or {@link Group}; + * to determine what type of object the {@link PTSEntry} represents, + * call the {@link PTSEntry#getType()} method. + * + * @return the owner of this user + * @exception AFSException If an error occurs in the native code + * @see PTSEntry + * @see PTSEntry#getType() + * @see #refresh() + */ + public PTSEntry getOwner() throws AFSException + { + if (!cachedInfo) refreshInfo(); + if (owner == null) return null; + if (ownerUID > 0) { + return new User(owner, cell); + } else { + return new Group(owner, cell); + } + } + + /** + * PTS: Returns the creator of this user in the form of a {@link PTSEntry}. + * + *

    The returning object could be either a {@link User} or {@link Group}; + * to determine what type of object the {@link PTSEntry} represents, + * call the {@link PTSEntry#getType()} method. + * + * @return the creator of this user + * @exception AFSException If an error occurs in the native code + * @see PTSEntry + * @see PTSEntry#getType() + * @see #refresh() + */ + public PTSEntry getCreator() throws AFSException + { + if (!cachedInfo) refreshInfo(); + if (creator == null) return null; + if (creatorUID > 0) { + return new User(creator, cell); + } else { + return new Group(creator, cell); + } + } + + /** + * Returns the type of {@link PTSEntry} this object represents. + * + *

    This method will always return {@link PTSEntry#PTS_USER}. + * + * @return the type of PTSEntry this object represents + (will always return {@link PTSEntry#PTS_USER}) + * @see PTSEntry + * @see PTSEntry#getType() + */ + public short getType() + { + return PTSEntry.PTS_USER; + } + + /** + * PTS: Returns who can list the status (pts examine) of this user. + * Valid values are: + *

      + *
    • {@link #USER_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #USER_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @return the status listing permission + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getListStatus() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return listStatus; + } + + /** + * PTS: Returns who can list the groups owned (pts listowned) by this user. + * Valid values are: + *
      + *
    • {@link #USER_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #USER_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @return the groups owned listing permission + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getListGroupsOwned() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return listGroupsOwned; + } + + /** + * PTS: Returns who can list the groups (pts membership) to which this + * user belongs. + * Valid values are: + *
      + *
    • {@link #USER_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #USER_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @return the membership listing permission + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getListMembership() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return listMembership; + } + + /** + * KAS: Returns whether or not this user has kas administrative privileges + * + * @return whether or not this user has kas administrative priveleges + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean isAdmin() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return (adminSetting == this.ADMIN); + } + + /** + * KAS: Returns whether or not TGS will issue tickets for this user + * + * @return whether or not TGS will issue tickets for this user + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean willGrantTickets() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return (tgsSetting == this.GRANT_TICKETS); + } + + /** + * KAS: Returns whether or not TGS can use this users ticket for an encryption key + * + * @return whether or not TGS can use this users ticket for an encryption key + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean canEncrypt() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return (encSetting == this.ENCRYPT); + } + + /** + * KAS: Returns whether or not the user can change their password + * + * @return whether or not the user can change their password + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean canChangePassword() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return (cpwSetting == this.CHANGE_PASSWORD); + } + + /** + * KAS: Returns whether or not the user can reuse their password + * + * @return whether or not the user can reuse their password + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public boolean canReusePassword() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return (rpwSetting == this.REUSE_PASSWORD); + } + + /** + * KAS: Returns the date and time the user expires. + * A null value indicates the user never exipres (or that + * there is no kas entry for this user). + * + * @return the date and time the user expires + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getUserExpiration() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return userExpiration; + } + /** + * KAS: Returns the date and time the user expires. + * A null value indicates the user never expires (or that + * there is no kas entry for this user). + * + * @return the date and time the user expires + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public GregorianCalendar getUserExpirationDate() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + if( userExpirationDate == null && userExpiration != 0 ) { + // make it into a date . . . + if( userExpiration == 0 ) { + userExpirationDate = null; + } else { + userExpirationDate = new GregorianCalendar(); + long longTime = ((long) userExpiration)*1000; + Date d = new Date( longTime ); + userExpirationDate.setTime( d ); + } + } + return userExpirationDate; + } + + /** + * KAS: Returns the date and time (in UTC) the user's KAS entry was + * last modified. + * + * @return the date and time (in UTC) the user was last modified + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getLastModTime() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return lastModTime; + } + /** + * KAS: Returns the date and time the user was last modified. + * + * @return the date and time the user was last modified + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public GregorianCalendar getLastModTimeDate() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + if( lastModTimeDate == null ) { + // make it into a date . . . + lastModTimeDate = new GregorianCalendar(); + long longTime = ((long) lastModTime)*1000; + Date d = new Date( longTime ); + lastModTimeDate.setTime( d ); + } + return lastModTimeDate; + } + + /** + * KAS: Returns the name of the user that last modified this user. + * + * @return the name of this user that last modified this user. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public String getLastModName() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return lastModName; + } + + /** + * KAS: Returns the last date and time the user changed its password. + * + * @return the last date and time the user changed its password. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public GregorianCalendar getLastChangePasswordTimeDate() + throws AFSException + { + if( !cachedInfo ) refreshInfo(); + if( lastChangePasswordTimeDate == null ) { + // make it into a date . . . + lastChangePasswordTimeDate = new GregorianCalendar(); + long longTime = ((long) lastChangePasswordTime)*1000; + Date d = new Date( longTime ); + lastChangePasswordTimeDate.setTime( d ); + } + return lastChangePasswordTimeDate; + } + + /** + * KAS: Returns the last date and time (in UTC) the user changed + * its password. + * + * @return the last date and time (in UTC) the user changed its password. + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getLastChangePasswordTime() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return lastChangePasswordTime; + } + + /** + * KAS: Returns the maximum lifetime of a ticket issued to this user + * (in seconds). + * + * @return the maximum lifetime of a ticket issued to this user (in seconds). + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getMaxTicketLifetime() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return maxTicketLifetime; + } + + /** + * KAS: Returns the number of days a password is valid before it expires. + * A value of 0 indicates passwords never expire. + * + * @return the number of days for which a password is valid + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getDaysToPasswordExpire() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return daysToPasswordExpire; + } + + /** + * KAS: Returns the number of failed login attempts this user is allowed + * before being locked out. A value of 0 indicates there is no limit. + * + * @return the number of failed login attempts a user is allowed + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getFailLoginCount() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return failLoginCount; + } + + /** + * KAS: Returns the amount of time (in seconds) a user is locked out when + * it exceeds the maximum number of allowable failed login attempts. + * A value of 0 indicates an infinite lockout time. + * + * @return the number of failed login attempts a user is allowed + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getLockTime() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return lockTime; + } + + /** + * KAS: Returns the encryption key, in octal form, of this user. An + * example of a key in octal form is: + * '\040\205\211\241\345\002\023\211'. + * + * @return the encryption key + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public String getEncryptionKey() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return encryptionKey; + } + + /** + * KAS: Returns the check sum of this user's key. + * + * @return the check sum + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public long getKeyCheckSum() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return keyCheckSum; + } + + /** + * KAS: Returns the version number of the user's key. + * + * @return the key version + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getKeyVersion() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return keyVersion; + } + + /** + * KAS: Returns the date and time (in UTC) at which the user stops + * being locked out. A value of 0 indicates the user is not currently + * locked out. If the user is locked out forever, the value + * will be equal to -1. + * + * @return the date and time (in UTC) at which the user stops being + * locked out + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public int getLockedUntil() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return lockedUntil; + } + + /** + * KAS: Returns the date and time at which the user stops being locked out. + * A value of null indicates the user is not currently locked + * out. If the user is locked out forever, the value + * getLockedUntil().getTime().getTime() will be equal to -1. + * + * @return the date and time at which the user stops being locked out + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + public GregorianCalendar getLockedUntilDate() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + if( lockedUntilDate == null ) { + // make it into a date . . . + Date d; + if( lockedUntil == 0 ) { + lockedUntilDate = null; + } else if( lockedUntil == -1 ) { + d = new Date( lockedUntil ); + lockedUntilDate = new GregorianCalendar(); + lockedUntilDate.setTime( d ); + } else { + d = new Date( ((long) lockedUntil)*1000 ); + lockedUntilDate = new GregorianCalendar(); + lockedUntilDate.setTime( d ); + } + } + return lockedUntilDate; + } + + /////////////// mutators //////////////////// + + /** + * PTS: Sets how many more groups this user is allowed to create. + * -1 indicates unlimited. + * + * @param quota the new group creation quota + */ + public void setGroupCreationQuota( int quota ) + { + groupCreationQuota = quota; + } + + + /** + * PTS: Sets who can list the status (pts examine) of this user. + * Valid values are: + *
      + *
    • {@link #USER_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #USER_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @param value the value of the new list status permission + * @exception AFSException if an error occurs in the native code + * @exception IllegalArgumentException if an invalud argument is provided + */ + public void setListStatus( int value ) throws AFSException + { + if( (value != this.USER_OWNER_ACCESS) && + (value != this.USER_ANYUSER_ACCESS) ) { + throw new IllegalArgumentException( "Cannot set listStatus to " + + value ); + } else { + listStatus = value; + } + } + + /** + * PTS: Sets who can list the groups owned (pts listowned) by this user. + * Valid values are: + *
      + *
    • {@link #USER_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #USER_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @param value the value of the new list groups owned permission + * @exception AFSException if an error occurs in the native code + * @exception IllegalArgumentException if an invalud argument is provided + */ + public void setListGroupsOwned( int value ) throws AFSException + { + if( (value != this.USER_OWNER_ACCESS) && + (value != this.USER_ANYUSER_ACCESS) ) { + throw new IllegalArgumentException( "Cannot set listGroupsOwned to " + + value ); + } else { + listGroupsOwned = value; + } + } + + /** + * PTS: Sets who can list the groups (pts membership) to which this + * user belongs. + * Valid values are: + *
      + *
    • {@link #USER_OWNER_ACCESS} + * -- only the owner has permission
    • + *
    • {@link #USER_ANYUSER_ACCESS} + * -- any user has permission
    • + *
    + * + * @param value the value of the new list membership permission + * @exception AFSException if an error occurs in the native code + * @exception IllegalArgumentException if an invalud argument is provided + */ + public void setListMembership( int value ) throws AFSException + { + if( (value != this.USER_OWNER_ACCESS) && + (value != this.USER_ANYUSER_ACCESS) ) { + throw new IllegalArgumentException( "Cannot set listMembership to " + + value ); + } else { + listMembership = value; + } + } + + /** + * KAS: Sets whether or not this user has kas administrative privileges + * + * @param setting whether or not this user has kas + * administrative privileges + */ + public void setAdmin( boolean setting ) + { + if ( setting ) { + adminSetting = this.ADMIN; + } else { + adminSetting = this.NO_ADMIN; + } + } + + /** + * KAS: Sets whether or not TGS will issue tickets for this user + * + * @param setting whether or not TGS will issue tickets for this user + */ + public void setGrantTickets( boolean setting ) + { + if ( setting ) { + tgsSetting = this.GRANT_TICKETS; + } else { + tgsSetting = this.NO_GRANT_TICKETS; + } + } + + /** + * KAS: Sets whether or not TGS can use this users ticket for an + * encryption key + * + * @param setting whether or not TGS can use this users ticket for an + * encryption key + */ + public void setEncrypt( boolean setting ) + { + if ( setting ) { + encSetting = this.ENCRYPT; + } else { + encSetting = this.NO_ENCRYPT; + } + } + + /** + * KAS: Sets whether or not the user can change their password + * + * @param setting whether or not the user can change their password + */ + public void setChangePassword( boolean setting ) + { + if ( setting ) { + cpwSetting = this.CHANGE_PASSWORD; + } else { + cpwSetting = this.NO_CHANGE_PASSWORD; + } + } + + /** + * KAS: Sets whether or not the user can reuse their password + * + * @param setting whether or not the user can reuse their password + */ + public void setReusePassword( boolean setting ) + { + if ( setting ) { + rpwSetting = this.REUSE_PASSWORD; + } else { + rpwSetting = this.NO_REUSE_PASSWORD; + } + } + + /** + * KAS: Sets the date and time the user expires. + * A null value indicates the user never exipres. + * + * @param expirationDate the date and time the user expires + */ + public void setUserExpiration( GregorianCalendar expirationDate ) + { + userExpirationDate = expirationDate; + if( expirationDate == null ) { + userExpiration = -1; + } else { + Date d = expirationDate.getTime(); + long millis = d.getTime(); + userExpiration = (int) (millis/((long)1000)); + } + } + + /** + * KAS: Sets the maximum lifetime of a ticket issued to this user + * (in seconds). + * + * @param seconds the maximum lifetime of a ticket issued to this user (in seconds). + */ + public void setMaxTicketLifetime( int seconds ) + { + maxTicketLifetime = seconds; + } + + /** + * KAS: Sets the number of days a password is valid before it expires. + * A value of 0 indicates passwords never expire. + * + * @param days the number of days for which a password is valid + */ + public void setDaysToPasswordExpire( int days ) + { + daysToPasswordExpire = days; + } + + /** + * KAS: Sets the number of failed login attempts this user is allowed before + * being locked out. A value of 0 indicates there is no limit. + * + * @param logins the number of failed login attempts a user is allowed + */ + public void setFailLoginCount( int logins ) + { + failLoginCount = logins; + } + + /** + * KAS: Sets the amount of time (in seconds) a user is locked out when it + * exceeds the maximum number of allowable failed login attempts. + * A value of 0 indicates an infinite lockout time. Any nonzero value gets + * rounded up to the next highest multiple of 8.5 minutes, and any value over + * 36 hours gets rounded down to 36 hours. + * + * @param seconds the number of failed login attempts a user is allowed + */ + public void setLockTime( int seconds ) + { + lockTime = seconds; + } + + /** + * Sets the password of this user to something new. Sets the key version + * to 0 automatically. + * + * @param newPassword the new password for this user + * @exception AFSException If an error occurs in the native code + */ + public void setPassword( String newPassword ) throws AFSException + { + this.setPassword( cell.getCellHandle(), name, newPassword ); + } + + /////////////// custom information methods //////////////////// + + /** + * Returns a String representation of this User. + * Contains the information fields and groups. + * + * @return a String representation of the User + */ + protected String getInfo() + { + String r; + try { + + r = "User: " + name; + + if( pts ) { + r += ", uid: " + getUID(); + } + r += "\n"; + r += "\tKAS: " + isKAS() + "\tPTS: " + isPTS() + "\n"; + + if( pts ) { + r += "\towner: " + getOwner().getName() + ", uid: " + + getOwner().getUID() + "\n"; + r += "\tcreator: " + getCreator().getName() + ", uid: " + + getCreator().getUID() + "\n"; + r += "\tGroup creation quota: " + getGroupCreationQuota() + "\n"; + r += "\tGroup membership count: " + getGroupMembershipCount() + + "\n"; + r += "\tList status: " + getListStatus() + "\n"; + r += "\tList groups owned: " + getListGroupsOwned() + "\n"; + r += "\tList membership: " + getListMembership() + "\n"; + } + + if( kas ) { + r += "\tKAS admin status: "; + + if( isAdmin() ) { + r += "Yes\n"; + } else { + r += "No\n"; + } + + r += "\tTGS grant tickets: "; + if( willGrantTickets() ) { + r += "Yes\n"; + } else { + r += "No\n"; + } + + r += "\tUse key as encryption key: "; + if( canEncrypt() ) { + r += "Yes\n"; + } else { + r += "No\n"; + } + + + r += "\tCan change password: "; + + if( canChangePassword() ) { + r += "Yes\n"; + } else { + r += "No\n"; + } + + r += "\tCan reuse password: "; + if( canReusePassword() ) { + r += "Yes\n"; + } else { + r += "No\n"; + } + + if( userExpiration != 0 ) { + r += "\tExpiration date: " + + getUserExpirationDate().getTime() + "\n"; + } else { + r += "\tUser never expires\n"; + } + r += "\tLast modified " + getLastModTimeDate().getTime() + + " by " + getLastModName() + "\n"; + r += "\tLast changed password " + + getLastChangePasswordTimeDate().getTime() + "\n"; + r += "\tMax ticket lifetime: " + getMaxTicketLifetime() + "\n"; + r += "\tKey: " + getEncryptionKey() + ", version: " + + getKeyVersion() + ", checksum: " + getKeyCheckSum() + "\n"; + r += "\tDays till password expires: " + getDaysToPasswordExpire() + + "\n"; + r += "\tAllowed failed logins: " + getFailLoginCount() + "\n"; + r += "\tLock time after failed logins: " + getLockTime() + "\n"; + if( lockedUntil == 0 ) { + r += "\tNot locked\n"; + } else if( getLockedUntilDate().getTime().getTime() == -1 ) { + r += "\tLocked forever\n"; + } else { + r += "\tLocked until: " + getLockedUntilDate().getTime() + + "\n"; + } + + } + if( pts ) { + + r += "\tBelongs to groups: \n"; + + String grps[] = getGroupNames(); + for( int i = 0; i < grps.length; i++ ) { + r += "\t\t" + grps[i] + "\n"; + } + + r += "\tOwns groups: \n"; + grps = getGroupsOwnedNames(); + for( int i = 0; i < grps.length; i++ ) { + r += "\t\t" + grps[i] + "\n"; + } + + } + } catch( AFSException e ) { + return e.toString(); + } + return r; + } + + /** + * Returns a String containing the String + * representations of all the groups to which this user belongs. + * + * @return a String representation of the groups belonged to + * @see Group#toString + */ + protected String getInfoGroups() throws AFSException + { + String r; + r = "User: " + name + "\n\n"; + r += "--Member of Groups:--\n"; + + Group grps[] = getGroups(); + for( int i = 0; i < grps.length; i++ ) { + r += grps[i].getInfo() + "\n"; + } + return r; + } + + /** + * Returns a String containing the String + * representations of all the groups that this user owns. + * + * @return a String representation of the groups owned + * @see Group#toString + */ + protected String getInfoGroupsOwned() throws AFSException + { + String r; + r = "User: " + name + "\n\n"; + r += "--Owns Groups:--\n"; + Group grps[] = getGroupsOwned(); + for( int i = 0; i < grps.length; i++ ) { + r += grps[i].getInfo() + "\n"; + } + return r; + } + + /////////////// custom override methods //////////////////// + + /** + * Compares two User objects respective to their names and does not + * factor any other attribute. Alphabetic case is significant in + * comparing names. + * + * @param user The User object to be compared to this User instance + * + * @return Zero if the argument is equal to this User's name, a + * value less than zero if this User's name is + * lexicographically less than the argument, or a value greater + * than zero if this User's name is lexicographically + * greater than the argument + */ + public int compareTo(User user) + { + return this.getName().compareTo(user.getName()); + } + + /** + * Comparable interface method. + * + * @see #compareTo(User) + */ + public int compareTo(Object obj) + { + return compareTo((User)obj); + } + + /** + * Tests whether two User objects are equal, based on their + * names. + * + * @param otherUser the user to test + * @return whether the specifed user is the same as this user + */ + public boolean equals( User otherUser ) + { + return name.equals(otherUser.getName()); + } + + /** + * Returns the name of this User + * + * @return the name of this User + */ + public String toString() + { + return getName(); + } + + + /////////////// native methods //////////////////// + + /** + * Creates the kas and pts entries for a new user. Pass in 0 for the uid + * if pts is to automatically assign the user id. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param userName the name of the user to create + * @param password the password for the new user + * @param uid the user id to assign to the user (0 to have one + * automatically assigned) + * @exception AFSException If an error occurs in the native code + */ + protected static native void create( int cellHandle, String userName, + String password, int uid ) + throws AFSException; + + /** + * Deletes the pts and kas entry for a user. Deletes this user from the + * membership list of the groups to which it belonged, but does not delete + * the groups owned by this user. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param groupName the name of the user to delete + * @exception AFSException If an error occurs in the native code + */ + protected static native void delete( int cellHandle, String userName ) + throws AFSException; + + /** + * Unlocks a user. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param groupName the name of the user to unlock + * @exception AFSException If an error occurs in the native code + */ + protected static native void unlock( int cellHandle, String userName ) + throws AFSException; + + /** + * Fills in the information fields of the provided User. + * Fills in values based on the current pts and kas information of the user. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param name the name of the user for which to get the information + * @param user the User object in which to fill in the + * information + * @see User + * @exception AFSException If an error occurs in the native code + */ + protected static native void getUserInfo( int cellHandle, String name, + User user ) + throws AFSException; + + /** + * Sets the information values of this AFS user to be the parameter values. + * Sets both kas and pts fields. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param name the name of the user for which to set the information + * @param theUser the User object containing the desired + * information + * @exception AFSException If an error occurs in the native code + */ + protected static native void setUserInfo( int cellHandle, String name, + User theUser ) + throws AFSException; + + /** + * Renames the given user. Does not update the info fields of the kas entry + * -- the calling code is responsible for that. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param oldName the name of the user to rename + * @param newName the new name for the user + * @exception AFSException If an error occurs in the native code + */ + protected static native void rename( int cellHandle, String oldName, + String newName ) + throws AFSException; + + /** + * Sets the password of the given user. Sets the key version to 0. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param userName the name of the user for which to set the password + * @param newPassword the new password for the user + * @exception AFSException If an error occurs in the native code + */ + protected static native void setPassword( int cellHandle, String userName, + String newPassword ) + throws AFSException; + + /** + * Begin the process of getting the groups to which the user belongs. + * Returns an iteration ID to be used by subsequent calls to + * getUserGroupsNext and getUserGroupsDone. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param name the name of the user for which to get the groups + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getUserGroupsBegin( int cellHandle, String name ) + throws AFSException; + + /** + * Returns the next group to which the user belongs. Returns + * null if there are no more groups. + * + * @param iterationId the iteration ID of this iteration + * @see getUserGroupsBegin + * @return the name of the next group + * @exception AFSException If an error occurs in the native code + */ + protected static native String getUserGroupsNextString( int iterationId ) + throws AFSException; + + /** + * Fills the next group object of which the user belongs. Returns 0 if there + * are no more groups, != 0 otherwise. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @param iterationId the iteration ID of this iteration + * @see getUserGroupsBegin + * @param theGroup a Group object to be populated with the values of the + * next group + * @return 0 if there are no more users, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getUserGroupsNext( int cellHandle, + int iterationId, + Group theGroup ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see getUserGroupsBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getUserGroupsDone( int iterationId ) + throws AFSException; + + /** + * Returns the total number of groups owned by the user. + * + * @param cellHandle the handle of the cell to which the user belongs + * @param name the name of the user for which to get the groups + * @return total number of groups owned by the user + * @exception AFSException If an error occurs in the native code + * @see Cell#getCellHandle + */ + protected static native int getGroupsOwnedCount( int cellHandle, String name ) + throws AFSException; + + /** + * Begin the process of getting the groups that a user or group owns. + * Returns an iteration ID to be used by subsequent calls to + * getGroupsOwnedNext and getGroupsOwnedDone. + * + * @param cellHandle the handle of the cell to which the user belongs + * @see Cell#getCellHandle + * @param name the name of the user or group for which to get the groups + * @return an iteration ID + * @exception AFSException If an error occurs in the native code + */ + protected static native int getGroupsOwnedBegin( int cellHandle, + String name ) + throws AFSException; + + /** + * Returns the next group the user or group owns. Returns null + * if there are no more groups. + * + * @param iterationId the iteration ID of this iteration + * @see getGroupsOwnedBegin + * @return the name of the next group + * @exception AFSException If an error occurs in the native code + */ + protected static native String getGroupsOwnedNextString( int iterationId ) + throws AFSException; + + /** + * Fills the next group object that the user or group owns. Returns 0 if + * there are no more groups, != 0 otherwise. + * + * @param cellHandle the handle of the cell to which the users belong + * @see Cell#getCellHandle + * @param iterationId the iteration ID of this iteration + * @see getGroupsOwnedBegin + * @param theGroup a Group object to be populated with the values of the + * next group + * @return 0 if there are no more users, != 0 otherwise + * @exception AFSException If an error occurs in the native code + */ + protected static native int getGroupsOwnedNext( int cellHandle, + int iterationId, + Group theGroup ) + throws AFSException; + + /** + * Signals that the iteration is complete and will not be accessed anymore. + * + * @param iterationId the iteration ID of this iteration + * @see getGroupsOwnedBegin + * @exception AFSException If an error occurs in the native code + */ + protected static native void getGroupsOwnedDone( int iterationId ) + throws AFSException; + + /** + * Reclaims all memory being saved by the user portion of the native library. + * This method should be called when no more Users are expected + * to be used. + */ + protected static native void reclaimUserMemory(); +} + + + + + + + + + diff --git a/src/JAVA/classes/org/openafs/jafs/Volume.java b/src/JAVA/classes/org/openafs/jafs/Volume.java new file mode 100644 index 0000000..88cf7de --- /dev/null +++ b/src/JAVA/classes/org/openafs/jafs/Volume.java @@ -0,0 +1,1394 @@ +/* + * @(#)Volume.java 1.0 6/29/2001 + * + * Copyright (c) 2001 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.openafs.jafs; + +import java.util.GregorianCalendar; +import java.util.Date; +import java.io.Serializable; + +/** + * An abstract representation of an AFS volume. It holds information about + * the server, such as what its quota is. + *

    + * + * Constructing an instance of a Volume does not mean an actual + * AFS partition is created on a partition -- usually a Volume + * object is a representation of an already existing AFS volume. If, + * however, the Volume is constructed with the name of a + * volume that does not exist in the cell to which the provided + * Partition belongs, a new AFS volume with that name can be + * created on that partition by calling the {@link #create(int)} method. If + * such a volume does already exist when this method is called, an exception + * will be thrown.

    + * + * + * The following is a simple example of how to construct and use a + * Volume object. This example obtains the list of + * Volume objects residing on a particular partition, and prints + * out the name and id of each one.

    + * + *
    + * import org.openafs.jafs.Cell;
    + * import org.openafs.jafs.AFSException;
    + * import org.openafs.jafs.Partition;
    + * import org.openafs.jafs.Server;
    + * import org.openafs.jafs.Volume;
    + * ...
    + * public class ...
    + * {
    + *   ...
    + *   private Cell cell;
    + *   private Server server;
    + *   private Partition partition;
    + *   ...
    + *   public static void main(String[] args) throws Exception
    + *   {
    + *     String username      = arg[0];
    + *     String password      = arg[1];
    + *     String cellName      = arg[2];
    + *     String serverName    = arg[3];
    + *     String partitionName = arg[4];
    + * 
    + *     token  = new Token(username, password, cellName);
    + *     cell   = new Cell(token);
    + *     server = cell.getServer(serverName);
    + *     partition = cell.getPartition(partitionName);
    + * 
    + *     System.out.println("Volumes in Partition " + partition.getName() + ":");
    + *     Volume[] volumes = partition.getVolumes();
    + *     for (int i = 0; i < volumes.length; i++) {
    + *       System.out.println(" -> " + volumes[i] + ": " + volumes[i].getID());
    + *     }
    + *   }
    + *   ...
    + * }
    + * 
    + * + */ +public class Volume implements Serializable, Comparable +{ + /** + * Read-write volume type + */ + public static final int VOLUME_TYPE_READ_WRITE = 0; + /** + * Read-only volume type + */ + public static final int VOLUME_TYPE_READ_ONLY = 1; + /** + * Backup volume type + */ + public static final int VOLUME_TYPE_BACKUP = 2; + + /** + * Status/disposition ok + */ + public static final int VOLUME_OK = 0; + /** + * Status/disposition salvage + */ + public static final int VOLUME_SALVAGE = 1; + /** + * Status/disposition no vnode + */ + public static final int VOLUME_NO_VNODE = 2; + /** + * Status/disposition no volume + */ + public static final int VOLUME_NO_VOL = 3; + /** + * Status/disposition volume exists + */ + public static final int VOLUME_VOL_EXISTS = 4; + /** + * Status/disposition no service + */ + public static final int VOLUME_NO_SERVICE = 5; + /** + * Status/disposition offline + */ + public static final int VOLUME_OFFLINE = 6; + /** + * Status/disposition online + */ + public static final int VOLUME_ONLINE = 7; + /** + * Status/disposition disk full + */ + public static final int VOLUME_DISK_FULL = 8; + /** + * Status/disposition over quota + */ + public static final int VOLUME_OVER_QUOTA = 9; + /** + * Status/disposition busy + */ + public static final int VOLUME_BUSY = 10; + /** + * Status/disposition moved + */ + public static final int VOLUME_MOVED = 11; + + protected Cell cell; + protected Server server; + protected Partition partition; + + protected String name; + + protected int id; + protected int readWriteID; + protected int readOnlyID; + protected int backupID; + + protected long creationDate; + protected long lastAccessDate; + protected long lastUpdateDate; + protected long lastBackupDate; + protected long copyCreationDate; + + protected int accessesSinceMidnight; + protected int fileCount; + protected int maxQuota; + protected int currentSize; + protected int status; + protected int disposition; + protected int type; + + protected GregorianCalendar creationDateCal; + protected GregorianCalendar lastUpdateDateCal; + protected GregorianCalendar copyCreationDateCal; + + protected boolean cachedInfo; + + /** + * Constructs a new Volume object instance given the name of + * the AFS volume and the AFS cell, represented by partition, + * to which it belongs. This does not actually + * create a new AFS volume, it just represents one. + * If name is not an actual AFS volume, exceptions + * will be thrown during subsequent method invocations on this + * object, unless the {@link #create(int)} method is explicitly called + * to create it. + * + * @param name the name of the volume to represent + * @param partition the partition on which the volume resides + * @exception AFSException If an error occurs in the native code + */ + public Volume( String name, Partition partition ) throws AFSException + { + this.partition = partition; + this.server = partition.getServer(); + this.cell = server.getCell(); + this.name = name; + + creationDateCal = null; + lastUpdateDateCal = null; + copyCreationDateCal = null; + + id = -1; + cachedInfo = false; + } + + /** + * Constructs a new Volume object instance given the name of + * the AFS volume and the AFS partition, represented by + * partition, to which it belongs. This does not actually + * create a new AFS volume, it just represents one. + * If name is not an actual AFS volume, exceptions + * will be thrown during subsequent method invocations on this + * object, unless the {@link #create(int)} method is explicitly called + * to create it. Note that if the volume doesn't exist and + * preloadAllMembers is true, an exception will be thrown. + * + *

    This constructor is ideal for point-in-time representation and + * transient applications. It ensures all data member values are set + * and available without calling back to the filesystem at the first request + * for them. Use the {@link #refresh()} method to address any coherency + * concerns. + * + * @param name the name of the volume to represent + * @param partition the partition on which the volume resides. + * @param preloadAllMembers true will ensure all object members are set + * upon construction; otherwise members will be + * set upon access, which is the default behavior. + * @exception AFSException If an error occurs in the native code + * @see #refresh + */ + public Volume( String name, Partition partition, boolean preloadAllMembers ) + throws AFSException + { + this(name, partition); + if (preloadAllMembers) refresh(true); + } + + /** + * Creates a blank Volume given the cell to which the volume + * belongs, the server on which the partition resides, and + * the partition on which the volume resides. This blank + * object can then be passed into other methods to fill out its properties. + * + * @exception AFSException If an error occurs in the native code + * @param cell the cell to which the server belongs. + * @param server the server on which the partition resides + * @param partition the partition on which the volume resides + */ + Volume( Partition partition ) throws AFSException + { + this( null, partition ); + } + + /*-------------------------------------------------------------------------*/ + + /** + * Refreshes the properties of this Volume object instance with values from + * the AFS volume it represents. All properties that have been initialized + * and/or accessed will be renewed according to the values of the AFS volume + * this Volume object instance represents. + * + *

    Since in most environments administrative changes can be administered + * from an AFS command-line program or an alternate GUI application, this + * method provides a means to refresh the Java object representation and + * thereby ascertain any possible modifications that may have been made + * from such alternate administrative programs. Using this method before + * an associated instance accessor will ensure the highest level of + * representative accuracy, accommodating changes made external to the + * Java application space. If administrative changes to the underlying AFS + * system are only allowed via this API, then the use of this method is + * unnecessary. + * + * @exception AFSException If an error occurs in the native code + */ + public void refresh() throws AFSException + { + refresh(false); + } + + /** + * Refreshes the properties of this Volume object instance with values from + * the AFS volume it represents. If all is true + * then all of the properties of this Volume object instance will be + * set, or renewed, according to the values of the AFS volume it represents, + * disregarding any previously set properties. + * + *

    Thus, if all is false then properties that + * are currently set will be refreshed and properties that are not set will + * remain uninitialized. See {@link #refresh()} for more information. + * + * @param all if true set or renew all object properties; otherwise renew + * all set properties + * @exception AFSException If an error occurs in the native code + * @see #refresh() + */ + protected void refresh(boolean all) throws AFSException + { + if (all || cachedInfo) refreshInfo(); + } + + /** + * Refreshes the information fields of this Volume to reflect + * the current state of the AFS volume. These include the last update time, + * file count, etc. + * + * @exception AFSException If an error occurs in the native code + */ + protected void refreshInfo() throws AFSException + { + getVolumeInfo( cell.getCellHandle(), server.getVosHandle(), + partition.getID(), getID(), this ); + cachedInfo = true; + creationDateCal = null; + lastUpdateDateCal = null; + copyCreationDateCal = null; + } + + /** + * Creates a new volume on the server and partition given upon construction. + * + * @param quota the quota for the volume in K, 0 indicates an unlimited + * quota + * + * @exception AFSException If an error occurs in the native code + */ + public void create( int quota ) throws AFSException + { + id = create( cell.getCellHandle(), server.getVosHandle(), + partition.getID(), name, quota ); + maxQuota = quota; + } + + /** + * Creates a backup volume for this volume. + * + * @return the Volume object representation for the + * backup volume that was created + * @exception AFSException If an error occurs in the native code + */ + public Volume createBackup( ) throws AFSException + { + createBackupVolume( cell.getCellHandle(), getID() ); + return new Volume( name + ".backup", partition ); + } + + /** + * Creates a readonly site for this volume on the specified server and + * partition. Automatically releases the volume. + * + * @param sitePartition the partition on which the readonly volume is + * to reside + * + * @return the Volume representation for the + * read-only volume that was created + * @exception AFSException If an error occurs in the native code + */ + public Volume createReadOnly( Partition sitePartition ) + throws AFSException + { + Server siteServer = sitePartition.getServer(); + createReadOnlyVolume( cell.getCellHandle(), siteServer.getVosHandle(), + sitePartition.getID(), getID() ); + release( false ); + return new Volume( name + ".readonly", sitePartition ); + } + + /** + * Deletes the volume from the cell. + * + * @exception AFSException If an error occurs in the native code + */ + public void delete() throws AFSException + { + delete( cell.getCellHandle(), server.getVosHandle(), partition.getID(), + getID() ); + name = null; + creationDateCal = null; + lastUpdateDateCal = null; + copyCreationDateCal = null; + cell = null; + server = null; + partition = null; + } + + /** + * Releases this volume, which updates the read-only copies of it. + * + *

    This method will force a complete release; a complete release updates + * all read-only sites even if the VLDB entry has a flag. + * + * @exception AFSException If an error occurs in the native code + */ + public void release() throws AFSException + { + this.release( true ); + } + + /** + * Releases this volume, which updates the read-only copies of it. + * + * @param forceComplete whether or not to force a complete release; + * a complete release updates all read-only sites + * even if the VLDB entry has a flag + * @exception AFSException If an error occurs in the native code + */ + public void release( boolean forceComplete ) throws AFSException + { + release( cell.getCellHandle(), getID(), forceComplete ); + } + + /** + * Dumps this volume to a file. If you use the dumpSince argument you will + * create an incremental dump, but you can leave it null + * for a full dump. + * + * @param fileName the path name of the file on the client machine to + * which to dump this volume + * @param dumpSince dump only files that have been modified more recently + * than this date + * @exception AFSException If an error occurs in the native code + */ + public void dump( String fileName, GregorianCalendar dumpSince ) + throws AFSException + { + int startTime = 0; + if ( dumpSince != null ) { + startTime = (int) ((dumpSince.getTime().getTime())/((long) 1000)); + } + dump( cell.getCellHandle(), server.getVosHandle(), partition.getID(), + getID(), startTime, fileName ); + } + + /** + * Dumps this volume to a file. Creates a full dump. + * + * @param fileName the path name of the file to which to dump this volume + * @exception AFSException If an error occurs in the native code + */ + public void dump( String fileName ) throws AFSException + { + this.dump( fileName, null ); + } + + /** + * Restores a file to this volume. Note that this does not have to be an + * existing volume in order to be restored - you may create a + * Volume as a volume that doesn't yet exist and then restore + * a file to it. Or you can restore over an existing volume. If a new + * volume is being created with this method, the id will be automatically + * assigned. + * + * @param fileName the path name of the file on the client machine from + * which to restore this volume + * @param incremental if true, restores an incremental dump over an + * existing volume + * @exception AFSException If an error occurs in the native code + */ + public void restore( String fileName, boolean incremental ) + throws AFSException + { + restore( fileName, incremental, 0 ); + } + + /** + * Restores a file to this volume. Note that this does not have to be an + * existing volume in order to be restored - you may create a + * Volume as a volume that doesn't yet exist and then restore + * a file to it. Or you can restore over an existing volume. + * + * @param fileName the path name of the file on the client machine from + * which to restore this volume + * @param incremental if true, restores an incremental dump over an + * existing volume + * @param id the id to assign this volume + * @exception AFSException If an error occurs in the native code + */ + public void restore( String fileName, boolean incremental, int id ) + throws AFSException + { + restore( cell.getCellHandle(), server.getVosHandle(), partition.getID(), + id, name, fileName, incremental ); + } + + /** + * Mounts this volume, bringing it online and making it accessible. + * + * @exception AFSException If an error occurs in the native code + */ + public void mount( ) throws AFSException + { + mount( server.getVosHandle(), partition.getID(), getID(), 0, true ); + } + + /** + * Unmounts this volume, bringing it offline and making it inaccessible. + * + * @exception AFSException If an error occurs in the native code + */ + public void unmount( ) throws AFSException + { + unmount( server.getVosHandle(), partition.getID(), getID() ); + } + + /** + * Locks the VLDB enrty for this volume + * + * @exception AFSException If an error occurs in the native code + */ + public void lock( ) throws AFSException + { + lock( cell.getCellHandle(), getID() ); + } + + /** + * Unlocks the VLDB entry for this volume + * + * @exception AFSException If an error occurs in the native code + */ + public void unlock( ) throws AFSException + { + unlock( cell.getCellHandle(), getID() ); + } + + /** + * Moves this volume to the specified partition (which indirectly + * specifies a new server, as well). Caution: This will remove any backup + * volumes at the original site. + * + * @param newPartition the partition to which to move the volume + * + * @exception AFSException If an error occurs in the native code + */ + public void moveTo( Partition newPartition ) throws AFSException + { + Server newServer = newPartition.getServer(); + move( cell.getCellHandle(), server.getVosHandle(), partition.getID(), + newServer.getVosHandle(), newPartition.getID(), getID() ); + + server = newServer; + partition = newPartition; + } + + /** + * Renames this volume. + * + * @param newName the new name for this volume + * @exception AFSException If an error occurs in the native code + */ + public void rename( String newName ) throws AFSException + { + rename( cell.getCellHandle(), getID(), newName ); + name = newName; + } + + /** + * Salvages (restores consistency to) this volume. Uses default values for + * most salvager options in order to simplify the API. + * + * @exception AFSException If an error occurs in the native code + */ + public void salvage() throws AFSException + { + Server.salvage( cell.getCellHandle(), server.getBosHandle(), + partition.getName(), name, 4, null, null, false, false, + false, false, false, false ); + } + + /** + * Creates a read-write mount point for this volume. Does not ensure the + * volume already exists. + * + * @param directory the name of the directory where this volume + * should be mounted + * @exception AFSException If an error occurs in the native code + */ + public void createMountPoint( String directory ) throws AFSException + { + createMountPoint(directory, true); + } + + /** + * Creates a mount point for this volume. Does not ensure the volume + * already exists. + * + * @param directory the name of the directory where this volume should be + * mounted + * @param readWrite whether or not this mount point should be read-write + * @exception AFSException If an error occurs in the native code + */ + public void createMountPoint( String directory, boolean readWrite ) + throws AFSException + { + Cell.createMountPoint( cell.getCellHandle(), directory, getName(), + readWrite, false ); + } + + //////////////// accessors: //////////////////////// + + /** + * Returns the name of this volume. + * + * @return the name of this volume + */ + public String getName() + { + return name; + } + + /** + * Returns this volume's hosting partition. + * + * @return this volume's partition + */ + public Partition getPartition() + { + return partition; + } + + /** + * Returns the id of this volume. + * + * @exception AFSException If an error occurs in the native code + * @return the id of this volume + */ + public int getID() throws AFSException + { + if( id == -1 && name != null ) { + String nameNoSuffix; + if( name.endsWith( "backup" ) ) { + type = VOLUME_TYPE_BACKUP; + nameNoSuffix = name.substring( 0, name.lastIndexOf( '.' ) ); + } else if( name.endsWith( "readonly" ) ) { + type = VOLUME_TYPE_READ_ONLY; + nameNoSuffix = name.substring( 0, name.lastIndexOf( '.' ) ); + } else { + type = VOLUME_TYPE_READ_WRITE; + nameNoSuffix = name; + } + id = translateNameToID( cell.getCellHandle(), + nameNoSuffix, type ); + } + return id; + } + + /** + * Returns the read-write ID of this volume + * + * @exception AFSException If an error occurs in the native code + * @return the read-write id + */ + public int getReadWriteID() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + return readWriteID; + } + + /** + * Returns the read-only ID of this volume + * + * @exception AFSException If an error occurs in the native code + * @return the read-only id + */ + public int getReadOnlyID() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + return readOnlyID; + } + + /** + * Returns the backup ID of this volume + * + * @exception AFSException If an error occurs in the native code + * @return the backup id + */ + public int getBackupID() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + return backupID; + } + + /** + * Returns the date the volume was created + * + * @return the date the volume was created + * @exception AFSException If an error occurs in the native code + */ + public GregorianCalendar getCreationDate() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + if( creationDateCal == null ) { + // make it into a date . . . + creationDateCal = new GregorianCalendar(); + Date d = new Date( creationDate*1000 ); + creationDateCal.setTime( d ); + } + return creationDateCal; + } + + /** + * Returns the date the volume was last updated. + * After this method is called once, it saves the date + * and returns that date on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the date the volume was last updated + * @exception AFSException If an error occurs in the native code + */ + public GregorianCalendar getLastUpdateDate() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + if( lastUpdateDateCal == null ) { + // make it into a date . . . + lastUpdateDateCal = new GregorianCalendar(); + Date d = new Date( lastUpdateDate*1000 ); + lastUpdateDateCal.setTime( d ); + } + return lastUpdateDateCal; + } + + /** + * Returns the date the volume was copied. + * After this method is called once, it saves the date + * and returns that date on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @return the date the volume was copied + * @exception AFSException If an error occurs in the native code + */ + public GregorianCalendar getCopyCreationDate() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + if( copyCreationDateCal == null ) { + // make it into a date . . . + copyCreationDateCal = new GregorianCalendar(); + Date d = new Date( copyCreationDate*1000 ); + copyCreationDateCal.setTime( d ); + } + return copyCreationDateCal; + } + + /** + * Returns the number of accesses since midnight. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return the number of accesses since midnight + */ + public int getAccessesSinceMidnight() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + return accessesSinceMidnight; + } + + /** + * Returns file count. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return the file count + */ + public int getFileCount() throws AFSException + { + if( !cachedInfo ) { + refreshInfo(); + } + return fileCount; + } + + /** + * Returns current volume size in K. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return the current volume size in K + */ + public int getCurrentSize() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return currentSize; + } + + /** + * Returns the difference between quota and current volume size (in K). + * + *

    Please note: the product of this method is not saved. + * + * @exception AFSException If an error occurs in the native code + * @return the current free space in K + */ + public int getTotalFreeSpace() throws AFSException + { + if ( !cachedInfo ) refreshInfo(); + return (maxQuota - currentSize); + } + + /** + * Returns this volume's quota, expressed in kilobyte blocks (1024 + * kilobyte blocks equal one megabyte). After this method is called once, + * it saves the value and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + *

    Note: A quota value of zero, "0", grants an unlimited quota + * in AFS. Consequently, to avoid delusion this method will throw an + * {@link AFSException} if the returning value is zero. + * + * @exception AFSException If an error occurs in the native code or + * this volume's quota is configured as + * unlimited. + * @return the volume quota in K + * @see #isQuotaUnlimited() + */ + public int getQuota() throws AFSException + { + if ( !cachedInfo ) refreshInfo(); + if (maxQuota == 0) { + throw new AFSException("Volume with id " + id + + " has an unlimited quota configured.", 0); + } + return maxQuota; + } + + /** + * Tests whether this volume's quota is configured as unlimited. + * + *

    After this method is called once, it saves the value and returns + * that value on subsequent calls, until the {@link #refresh()} + * method is called and a more current value is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return true if this volume's quota is configured as + * unlimited; otherwise false. + * @see #getQuota() + */ + public boolean isQuotaUnlimited() throws AFSException + { + if ( !cachedInfo ) refreshInfo(); + return (maxQuota == 0); + } + + /** + * Returns volume status. Possible values are:

      + *
    • {@link #VOLUME_OK}
    • + *
    • {@link #VOLUME_SALVAGE}
    • + *
    • {@link #VOLUME_NO_VNODE}
    • + *
    • {@link #VOLUME_NO_VOL}
    • + *
    • {@link #VOLUME_VOL_EXISTS}
    • + *
    • {@link #VOLUME_NO_SERVICE}
    • + *
    • {@link #VOLUME_OFFLINE}
    • + *
    • {@link #VOLUME_ONLINE}
    • + *
    • {@link #VOLUME_DISK_FULL}
    • + *
    • {@link #VOLUME_OVER_QUOTA}
    • + *
    • {@link #VOLUME_BUSY}
    • + *
    • {@link #VOLUME_MOVED}
    + * Typical value is VOLUME_OK. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return volume status + */ + public int getStatus() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return status; + } + + /** + * Returns volume disposition. Possible values are:
      + *
    • {@link #VOLUME_OK}
    • + *
    • {@link #VOLUME_SALVAGE}
    • + *
    • {@link #VOLUME_NO_VNODE}
    • + *
    • {@link #VOLUME_NO_VOL}
    • + *
    • {@link #VOLUME_VOL_EXISTS}
    • + *
    • {@link #VOLUME_NO_SERVICE}
    • + *
    • {@link #VOLUME_OFFLINE}
    • + *
    • {@link #VOLUME_ONLINE}
    • + *
    • {@link #VOLUME_DISK_FULL}
    • + *
    • {@link #VOLUME_OVER_QUOTA}
    • + *
    • {@link #VOLUME_BUSY}
    • + *
    • {@link #VOLUME_MOVED}
    + * Typical value is VOLUME_ONLINE. + * After this method is called once, it saves the value + * and returns that value on subsequent calls, + * until the {@link #refresh()} method is called and a more current + * value is obtained. + * + * @exception AFSException If an error occurs in the native code + * @return volume disposition + */ + public int getDisposition() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return disposition; + } + + /** + * Returns volume type. Possible values are:
      + *
    • {@link #VOLUME_TYPE_READ_WRITE}
    • + *
    • {@link #VOLUME_TYPE_READ_ONLY}
    • + *
    • {@link #VOLUME_TYPE_BACKUP}
    + * + * @exception AFSException If an error occurs in the native code + * @return volume type + */ + public int getType() throws AFSException + { + if( !cachedInfo ) refreshInfo(); + return type; + } + + //////////////// mutators: //////////////////////// + + /** + * Sets quota of volume, 0 denotes an unlimited quota. + * + * @exception AFSException If an error occurs in the native code + * @param quota the new volume quota in K (0 for unlimited) + */ + public void setQuota( int quota ) throws AFSException + { + this.changeQuota( cell.getCellHandle(), server.getVosHandle(), + partition.getID(), getID(), quota ); + maxQuota = quota; + } + + /////////////// custom information methods //////////////////// + + /** + * Returns a String representation of this Volume. + * Contains the information fields. + * + * @return a String representation of the Volume + */ + protected String getInfo() + { + String r; + try { + r = "Volume: " + name + "\tid: " + getID() + "\n"; + + r += "\tread-write id: " + getReadWriteID() + "\tread-only id: " + + getReadOnlyID() + "\n"; + r += "\tbackup id: " + getBackupID() + "\n"; + + r += "\tcreation date: " + getCreationDate().getTime() + "\n"; + r += "\tlast update date: " + getLastUpdateDate().getTime() + "\n"; + r += "\tcopy creation date: " + getCopyCreationDate().getTime() + "\n"; + r += "\taccesses since midnight: " + getAccessesSinceMidnight() + "\n"; + r += "\tfile count: " + getFileCount() + "\n"; + r += "\tcurrent size: " + getCurrentSize() + " K\tquota: " + + getQuota() + " K\n"; + r += "\tstatus: "; + switch( getStatus() ) { + case VOLUME_OK: + r += "OK"; + break; + default: + r += "OTHER"; + } + + r += "\tdisposition: "; + switch( getDisposition() ) { + case VOLUME_ONLINE: + r += "ONLINE"; + break; + default: + r += "OTHER - " + getDisposition(); + } + r += "\n"; + + r += "\ttype: "; + switch( getType() ) { + case VOLUME_TYPE_READ_WRITE: + r += "read-write"; + break; + case VOLUME_TYPE_READ_ONLY: + r += "read-only"; + break; + case VOLUME_TYPE_BACKUP: + r += "backup"; + break; + default: + r += "OTHER"; + } + r += "\n"; + + } catch( Exception e ) { + return e.toString(); + } + return r; + } + + /////////////// custom override methods //////////////////// + + /** + * Compares two Volume objects respective to their names and does not + * factor any other attribute. Alphabetic case is significant in + * comparing names. + * + * @param volume The Volume object to be compared to this Volume + * instance + * + * @return Zero if the argument is equal to this Volume's name, a + * value less than zero if this Volume's name is + * lexicographically less than the argument, or a value greater + * than zero if this Volume's name is lexicographically + * greater than the argument + */ + public int compareTo(Volume volume) + { + return this.getName().compareTo(volume.getName()); + } + + /** + * Comparable interface method. + * + * @see #compareTo(Volume) + */ + public int compareTo(Object obj) + { + return compareTo((Volume)obj); + } + + /** + * Tests whether two Volume objects are equal, based on their + * names and hosting partition. + * + * @param otherVolume the Volume to test + * @return whether the specifed Volume is the same as this Volume + */ + public boolean equals( Volume otherVolume ) + { + return ( name.equals(otherVolume.getName()) ) && + ( this.getPartition().equals(otherVolume.getPartition()) ); + } + + /** + * Returns the name of this Volume + * + * @return the name of this Volume + */ + public String toString() + { + return getName(); + } + + + /////////////// native methods //////////////////// + + /** + * Fills in the information fields of the provided Volume. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server on which the volume + * resides + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the volume + * resides + * @param volId the numeric id of the volume for which to get the info + * @param theVolume the {@link Volume Volume} object in which to fill in + * the information + * @exception AFSException If an error occurs in the native code + */ + protected static native void getVolumeInfo( int cellHandle, int serverHandle, + int partition, int volId, + Volume theVolume ) + throws AFSException; + + /** + * Creates a volume on a particular partition. + * + * @param cellHandle the handle of the cell in which to create the volume + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server on which to create + * the volume + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which to create + * the volume + * @param volumeName the name of the volume to create + * @param quota the amount of space (in KB) to set as this volume's quota + * @return the numeric ID assigned to the volume + * @exception AFSException If an error occurs in the native code + */ + protected static native int create( int cellHandle, int serverHandle, + int partition, String volumeName, + int quota ) + throws AFSException; + + /** + * Deletes a volume from a particular partition. + * + * @param cellHandle the handle of the cell in which to delete the volume + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server from which to delete + * the volume + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition from which to delete + * the volume + * @param volId the numeric id of the volume to delete + * @exception AFSException If an error occurs in the native code + */ + protected static native void delete( int cellHandle, int serverHandle, + int partition, int volId ) + throws AFSException; + + /** + * Creates a backup volume for the specified regular volume. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @param volId the numeric id of the volume for which to create a backup + * volume + * @see Cell#getCellHandle + */ + protected static native void createBackupVolume( int cellHandle, int volId ) + throws AFSException; + + /** + * Creates a read-only volume for the specified regular volume. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @param serverHandle the vos handle of the server on which the read-only + * volume is to reside + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the read-only + volume is to reside + * @param volId the numeric id of the volume for which to create a read-only volume + * @see Cell#getCellHandle + */ + protected static native void createReadOnlyVolume( int cellHandle, + int serverHandle, + int partition, int volId ) + throws AFSException; + + /** + * Deletes a read-only volume for the specified regular volume. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @param serverHandle the vos handle of the server on which the read-only + * volume residea + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the read-only + * volume resides + * @param volId the numeric read-write id of the volume for which to + * delete the read-only volume + * @see Cell#getCellHandle + */ + protected static native void deleteReadOnlyVolume( int cellHandle, + int serverHandle, + int partition, int volId ) + throws AFSException; + + /** + * Changes the quota of the specified volume. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server on which the volume + * resides + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the volume + * resides + * @param volId the numeric id of the volume for which to change the quota + * @param newQuota the new quota (in KB) to assign the volume + * @exception AFSException If an error occurs in the native code + */ + protected static native void changeQuota( int cellHandle, int serverHandle, + int partition, int volId, + int newQuota ) + throws AFSException; + + /** + * Move the specified volume to a different site. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @see Cell#getCellHandle + * @param fromServerHandle the vos handle of the server on which the volume + * currently resides + * @see Server#getVosServerHandle + * @param fromPartition the numeric id of the partition on which the volume + * currently resides + * @param toServerHandle the vos handle of the server to which the volume + * should be moved + * @param toPartition the numeric id of the partition to which the volume + * should be moved + * @param volId the numeric id of the volume to move + * @exception AFSException If an error occurs in the native code + */ + protected static native void move( int cellHandle, int fromServerHandle, + int fromPartition, int toServerHandle, + int toPartition, int volId ) + throws AFSException; + + /** + * Releases the specified volume that has readonly volume sites. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @param volId the numeric id of the volume to release + * @param forceComplete whether or not to force a complete release + * @see Cell#getCellHandle + */ + protected static native void release( int cellHandle, int volId, + boolean forceComplete ) + throws AFSException; + + /** + * Dumps the specified volume to a file. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server on which the volume + * resides + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the + * volume resides + * @param volId the numeric id of the volume to dump + * @param startTime files with a modification time >= to this time will + * be dumped + * @param dumpFile the full path of the file to which to dump + * @exception AFSException If an error occurs in the native code + */ + protected static native void dump( int cellHandle, int serverHandle, + int partition, int volId, int startTime, + String dumpFile ) + throws AFSException; + + /** + * Restores the specified volume from a dump file. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @see Cell#getCellHandle + * @param serverHandle the vos handle of the server on which the volume is + * to reside + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the volume is + * to reside + * @param volId the numeric id to assign the restored volume (can be 0) + * @param volumeName the name of the volume to restore as + * @param dumpFile the full path of the dump file from which to restore + * @param incremental if true, restores an incremental dump over an existing + * volume (server and partition values must correctly + * indicate the current position of the existing volume), + * otherwise restores a full dump + * @exception AFSException If an error occurs in the native code + */ + protected static native void restore( int cellHandle, int serverHandle, + int partition, int volId, + String volumeName, String dumpFile, + boolean incremental ) + throws AFSException; + + /** + * Renames the specified read-write volume. + * + * @param cellHandle the handle of the cell to which the volume belongs + * @see Cell#getCellHandle + * @param volId the numeric id of the read-write volume to rename + * @param newVolumeName the new name for the volume + * @exception AFSException If an error occurs in the native code + */ + protected static native void rename( int cellHandle, int volId, + String newVolumeName ) + throws AFSException; + + /** + * "Mounts" the specified volume, bringing it online. + * + * @param serverHandle the vos handle of the server on which the volume + * resides + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the volume + * resides + * @param volId the numeric id of the volume to bring online + * @param sleepTime ? (not sure what this is yet, possibly a time to wait + * before brining it online) + * @param offline ? (not sure what this is either, probably the current + * status of the volume -- busy or offline) + * @exception AFSException If an error occurs in the native code + */ + protected static native void mount( int serverHandle, int partition, + int volId, int sleepTime, + boolean offline ) + throws AFSException; + + /** + * "Unmounts" the specified volume, bringing it offline. + * + * @param serverHandle the vos handle of the server on which the volume + * resides + * @see Server#getVosServerHandle + * @param partition the numeric id of the partition on which the volume + * resides + * @param volId the numeric id of the volume to bring offline + * @exception AFSException If an error occurs in the native code + */ + protected static native void unmount( int serverHandle, int partition, + int volId ) + throws AFSException; + + /** + * Locks the VLDB entry specified volume + * + * @param cellHandle the handle of the cell on which the volume resides + * @see Cell#getCellHandle + * @param volId the numeric id of the volume to lock + * @exception AFSException If an error occurs in the native code + */ + protected static native void lock( int cellHandle, int volId ) + throws AFSException; + + /** + * Unlocks the VLDB entry of the specified volume + * + * @param cellHandle the handle of the cell on which the volume resides + * @see Cell#getCellHandle + * @param volId the numeric id of the volume to unlock + * @exception AFSException If an error occurs in the native code + */ + protected static native void unlock( int cellHandle, int volId ) + throws AFSException; + + /** + * Translates a volume name into a volume id + * + * @param cellHandle the handle of the cell to which the volume belongs + * @see Cell#getCellHandle + * @param name the name of the volume in question, cannot end in backup or + * readonly + * @param type the type of volume: read-write, read-only, or backup. + * Acceptable values are:
      + *
    • {@link #VOLUME_TYPE_READ_WRITE}
    • + *
    • {@link #VOLUME_TYPE_READ_ONLY}
    • + *
    • {@link #VOLUME_TYPE_BACKUP}
    + * @return the id of the volume in question + * @exception AFSException If an error occurs in the native code + */ + protected static native int translateNameToID( int cellHandle, String name, + int volumeType ) + throws AFSException; + + /** + * Reclaims all memory being saved by the volume portion of the native + * library. This method should be called when no more Volume + * objects are expected to be used. + */ + protected static native void reclaimVolumeMemory(); +} + + + + + + + + + + + + + diff --git a/src/JAVA/libjafs/ACL.c b/src/JAVA/libjafs/ACL.c new file mode 100644 index 0000000..7770bb6 --- /dev/null +++ b/src/JAVA/libjafs/ACL.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_ACL.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +#define ACL_LEN 1024 + +extern int errno; + +/** + * Returns a formatted string representing the ACL for the specified path. + * + * path the directory path + * returns NULL if an exception is encountered. + */ +char* getACL(char *path) +{ + struct ViceIoctl params; + char *buffer; + + params.in = NULL; + params.in_size = 0; + buffer = (char*) malloc(ACL_LEN); + + if (!buffer) { + fprintf(stderr, "ERROR: ACL::getACL -> could not allocate buffer\n"); + return NULL; + } + + params.out = buffer; + params.out_size = ACL_LEN; + + if(call_syscall(AFSCALL_PIOCTL, path, VIOCGETAL, ¶ms, 1)) { + fprintf(stderr, "ERROR: ACL::getACL -> VIOCGETAL failed: %d\n", errno); + free(buffer); + return NULL; + } + + return params.out; +} + +/** + * Sets the ACL for the specified path using the provided string + * representation. + * + * path the directory path + * aclString string representation of ACL to be set + * returns TRUE if the operation succeeds; otherwise FALSE; + */ +jboolean setACL(char *path, char *aclString) +{ + struct ViceIoctl params; + char *redirect, *parentURI, *cptr; + + params.in = aclString; + params.in_size = strlen(aclString) + 1; + params.out = NULL; + params.out_size = 0; + + if(call_syscall(AFSCALL_PIOCTL, path, VIOCSETAL, ¶ms, 1)) { + fprintf(stderr, "ERROR: ACL::setACL -> VIOCSETAL failed: %d\n", errno); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +/** + * Returns a formatted string representing the ACL for the specified path. + * + * The string format is in the form of a ViceIoctl and is as follows: + * printf("%d\n%d\n", positiveEntriesCount, negativeEntriesCount); + * printf("%s\t%d\n", userOrGroupName, rightsMask); + * + * path the directory path + * returns NULL if an exception is encountered. + */ +JNIEXPORT jstring JNICALL Java_org_openafs_jafs_ACL_getACLString + (JNIEnv *env, jobject obj, jstring pathUTF) +{ + char *path, *acl; + jstring answer = NULL; + + path = (char*) (*env)->GetStringUTFChars(env, pathUTF, 0); + + if(path == NULL) { + fprintf(stderr, "ERROR: ACL::getACLString ->"); + fprintf(stderr, "GetStringUTFChars() returned path = NULL\n"); + throwMessageException( env, "Path is NULL" ); + return NULL; + } + + acl = getACL(path); + (*env)->ReleaseStringUTFChars(env, pathUTF, path); + + if(acl) { + answer = (*env) -> NewStringUTF(env, acl); + free(acl); + } else { + throwAFSException( env, errno ); + } + + return answer; +} + +/** + * Sets the ACL for the specified path using the provided string + * representation. + * + * The string format is in the form of a ViceIoctl and is as follows: + * printf("%d\n%d\n", positiveEntriesCount, negativeEntriesCount); + * printf("%s\t%d\n", userOrGroupName, rightsMask); + * + * path the directory path + * aclString string representation of ACL to be set + * throws an afsAdminExceptionName if an internal exception is encountered. + */ +JNIEXPORT void JNICALL Java_org_openafs_jafs_ACL_setACLString + (JNIEnv *env, jobject obj, jstring pathUTF, jstring aclStringUTF) +{ + char *path, *aclString; + + if(!pathUTF) { + fprintf(stderr, "ERROR: ACL::setACLString -> pathUTF == NULL\n"); + throwMessageException( env, "pathUTF == NULL" ); + return; + } + + path = (char*) (*env)->GetStringUTFChars(env, pathUTF, 0); + + if(path == NULL) { + fprintf(stderr, "ERROR: ACL::setACLString -> failed to get path\n"); + throwMessageException( env, "Failed to get path" ); + return; + } + + if(!aclStringUTF) { + fprintf(stderr, "ERROR: ACL::setACLString -> aclStringUTF == NULL\n"); + throwMessageException( env, "aclStringUTF == NULL" ); + return; + } + + aclString = (char*) (*env)->GetStringUTFChars(env, aclStringUTF, 0); + + if(aclString == NULL) { + fprintf(stderr, "ERROR: ACL::setACLString -> failed to get aclString\n"); + (*env)->ReleaseStringUTFChars(env, pathUTF, path); + throwMessageException( env, "aclString == NULL" ); + return; + } + + if (!setACL(path, aclString)) { + throwAFSException( env, errno ); + } + + (*env)->ReleaseStringUTFChars(env, pathUTF, path); + (*env)->ReleaseStringUTFChars(env, aclStringUTF, aclString); +} + + + diff --git a/src/JAVA/libjafs/AdminToken.c b/src/JAVA/libjafs/AdminToken.c new file mode 100644 index 0000000..b1d3358 --- /dev/null +++ b/src/JAVA/libjafs/AdminToken.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_Cell.h" +#include "org_openafs_jafs_Token.h" + +#include +#include +#include +#include +#include +#include +#include + +/** + * Static function used to initialize the client library and the + * jafs library. + * + * env the Java environment + * obj the current Java object + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Token_initializeAdminClient(JNIEnv *env, jclass cls) +{ + afs_status_t ast; + if( !afsclient_Init( &ast ) ) { + throwAFSException( env, ast ); + return; + } +} + + +/** + * Authenticates the given user and password in the cell. Returns + * a token that can be used to prove this authentication later. + * + * env the Java environment + * obj the current Java object + * jcellName the name of the cell in which to authenticate this user + * juserName the name of the user to authenticate + * jpassword the password of the user + * returns a token representing the authentication + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Token_getToken + (JNIEnv *env, jobject obj, jstring jcellName, jstring juserName, + jstring jpassword) +{ + afs_status_t ast; + const char *cellName; + const char *userName; + const char *password; + void *tokenHandle; + int rc; + + // convert java strings + if( jcellName != NULL ) { + cellName = (*env)->GetStringUTFChars(env, jcellName, 0); + if( !cellName ) { + throwAFSException( env, JAFSADMNOMEM ); + return 0; + } + } else { + cellName = NULL; + } + if( juserName != NULL ) { + userName = (*env)->GetStringUTFChars(env, juserName, 0); + if( !userName ) { + throwAFSException( env, JAFSADMNOMEM ); + return 0; + } + } else { + userName = NULL; + } + if( jpassword != NULL ) { + password = (*env)->GetStringUTFChars(env, jpassword, 0); + if( !password ) { + throwAFSException( env, JAFSADMNOMEM ); + return 0; + } + } else { + password = NULL; + } + + if ( !(afsclient_TokenGetNew( cellName, userName, password, &tokenHandle, + &ast) ) ) { + // release converted strings + if( cellName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcellName, cellName); + } + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + throwAFSException( env, ast ); + return 0; + } + + // release converted strings + if( cellName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcellName, cellName); + } + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + + return (jint) tokenHandle; +} + +/** + * Closes the given currently open token. + * + * env the Java environment + * obj the current Java object + * tokenHandle the token to close + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Token_close + (JNIEnv *env, jobject obj, jint tokenHandle) +{ + afs_status_t ast; + + if( !afsclient_TokenClose( (void *) tokenHandle, &ast ) ) { + throwAFSException( env, ast ); + return; + } +} + +/** + * Opens a cell for administrative use, based on the token provided. + * Returns a cell handle to be used by other methods as a means of + * authentication. + * + * env the Java environment + * obj the current Java object + * jcellName the name of the cell for which to get the handle + * tokenHandle a token handle previously returned by a call to getToken + * returns a handle to the open cell + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getCellHandle + (JNIEnv *env, jobject obj, jstring jcellName, jint tokenHandle) +{ + afs_status_t ast; + const char *cellName; + void *cellHandle; + + if( jcellName != NULL ) { + cellName = (*env)->GetStringUTFChars(env, jcellName, 0); + if( !cellName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + cellName = NULL; + } + + if( !afsclient_CellOpen( cellName, (void *) tokenHandle, + &cellHandle, &ast ) ) { + if( cellName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcellName, cellName); + } + throwAFSException( env, ast ); + return; + } + + if( cellName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcellName, cellName); + } + return (jint) cellHandle; +} + +/** + * Closes the given currently open cell handle. + * + * env the Java environment + * obj the current Java object + * cellHandle the cell handle to close + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_closeCell (JNIEnv *env, jobject obj, + jint cellHandle) +{ + + afs_status_t ast; + + if( !afsclient_CellClose( (void *) cellHandle, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Opens a server for administrative vos use, based on the cell handle + * provided. Returns a vos server handle to be used by other + * methods as a means of identification. + * + * env the Java environment + * obj the current Java object + * cellHandle a cell handle previously returned by + * a call to getCellHandle + * jserverName the name of the server for which to retrieve + * a vos handle + * returns a vos handle to the server + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getVosServerHandle + (JNIEnv *env, jobject obj, jint cellHandle, jstring jserverName) +{ + afs_status_t ast; + void *serverHandle; + // convert java string + const char *serverName; + + if( jserverName != NULL ) { + serverName = (*env)->GetStringUTFChars(env, jserverName, 0); + if( !serverName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + serverName = NULL; + } + + if( !vos_ServerOpen( (void *) cellHandle, serverName, + (void **) &serverHandle, &ast ) ) { + if( serverName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jserverName, serverName); + } + throwAFSException( env, ast ); + return 0; + } + + // release converted string + if( serverName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jserverName, serverName); + } + + return (jint) serverHandle; +} + +/** + * Closes the given currently open vos server handle. + * + * env the Java environment + * obj the current Java object + * vosServerHandle the vos server handle to close + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_closeVosServerHandle + (JNIEnv *env, jobject obj, jint vosServerHandle) +{ + afs_status_t ast; + + if( !vos_ServerClose( (void *) vosServerHandle, &ast ) ) { + throwAFSException( env, ast ); + return; + } +} + +/** + * Opens a server for administrative bos use, based on the cell handle + * provided. Returns a bos server handle to be used by other methods + * as a means of identification. + * + * env the Java environment + * obj the current Java object + * cellHandle a cell handle previously returned by a call + * to getCellHandle + * jserverName the name of the server for which to retrieve + * a bos handle + * returns a bos handle to the server + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getBosServerHandle + (JNIEnv *env, jobject obj, jint cellHandle, jstring jserverName) +{ + afs_status_t ast; + void *serverHandle; + // convert java string + const char *serverName; + + if( jserverName != NULL ) { + serverName = (*env)->GetStringUTFChars(env, jserverName, 0); + if( !serverName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + serverName = NULL; + } + + if( !bos_ServerOpen( (void *) cellHandle, serverName, + (void **) &serverHandle, &ast ) ) { + if( serverName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jserverName, serverName); + } + throwAFSException( env, ast ); + return 0; + } + + // release converted string + if( serverName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jserverName, serverName); + } + + return (jint) serverHandle; +} + +/** + * Closes the given currently open bos server handle. + * + * env the Java environment + * obj the current Java object + * bosServerHandle the bos server handle to close + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_closeBosServerHandle + (JNIEnv *env, jobject obj, jint bosServerHandle) +{ + afs_status_t ast; + + if( !bos_ServerClose( (void *) bosServerHandle, &ast ) ) { + throwAFSException( env, ast ); + return; + } +} + +/** + * Gets the expiration time for a given token. + * + * env the Java environment + * obj the current Java object + * + * tokenHandle a token handle previously returned by a call + * to getToken + * returns a long representing the UTC time for the token expiration + */ +JNIEXPORT jlong JNICALL +Java_org_openafs_jafs_Token_getExpiration + (JNIEnv *env, jobject obj, jint tokenHandle) +{ + afs_status_t ast; + unsigned long expTime; + char *prince = malloc( sizeof(char)*KAS_MAX_NAME_LEN ); + char *inst = malloc( sizeof(char)*KAS_MAX_NAME_LEN ); + char *cell = malloc( sizeof(char)*AFS_MAX_SERVER_NAME_LEN ); + int hkt; + + if( !prince || !inst || !cell ) { + if( prince ) { + free( prince ); + } + if( inst ) { + free( inst ); + } + if( cell ) { + free( cell ); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !afsclient_TokenQuery( (void *) tokenHandle, &expTime, prince, inst, + cell, &hkt, &ast ) ) { + free( prince ); + free( inst ); + free( cell ); + throwAFSException( env, ast ); + return 0; + } + + free( prince ); + free( inst ); + free( cell ); + + return (jlong) expTime; +} + +// reclaim global memory used by this portion +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Token_reclaimAuthMemory (JNIEnv *env, jclass cls) +{ +} + + + + + + diff --git a/src/JAVA/libjafs/Cell.c b/src/JAVA/libjafs/Cell.c new file mode 100644 index 0000000..47bb0df --- /dev/null +++ b/src/JAVA/libjafs/Cell.c @@ -0,0 +1,1485 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_Cell.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//// definitions in Internal.c ////////////////// + +extern jclass userCls; +//extern jfieldID user_cellHandleField; +extern jfieldID user_nameField; +extern jfieldID user_cachedInfoField; + +extern jclass groupCls; +//extern jfieldID group_cellHandleField; +extern jfieldID group_nameField; +extern jfieldID group_cachedInfoField; + +extern jclass serverCls; +//extern jfieldID server_cellHandleField; +extern jfieldID server_cachedInfoField; + +////////////////////////////////////////////////////////// + +///// definition in jafs_User.c ///////////////// + +extern void getUserInfoChar (JNIEnv *env, int cellHandle, const char *name, + jobject user); + +/////////////////////////////////////////////////// + +///// definition in jafs_Group.c ///////////////// + +extern void getGroupInfoChar (JNIEnv *env, int cellHandle, const char *name, + jobject group); + +/////////////////////////////////////////////////// + +///// definition in jafs_Server.c ///////////////// + +extern void fillServerInfo (JNIEnv *env, jint cellHandle, jobject server, + afs_serverEntry_t servEntry); + +/////////////////////////////////////////////////// + +/** + * Returns the total number of KAS users belonging to the cell denoted + * by cellHandle. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * returns total count of KAS users + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getKasUserCount (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + void *iterationId; + kas_identity_t who; + int i = 0; + + if( !kas_PrincipalGetBegin( (void *) cellHandle, NULL, + &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return -1; + } + + while ( kas_PrincipalGetNext( (void *) iterationId, &who, &ast ) ) i++; + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + + +/** + * Begin the process of getting the kas users that belong to the cell. + * Returns an iteration ID to be used by subsequent calls to + * getKasUsersNextString (or getKasUsersNext) + * and getKasUsersDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getKasUsersBegin (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + void *iterationId; + + if( !kas_PrincipalGetBegin( (void *) cellHandle, NULL, &iterationId, + &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return (jint) iterationId; + +} + +/** + * Begin the process of getting the KAS users, starting at + * startIndex, that belong to the cell. + * Returns an iteration ID to be used by subsequent calls to + * getKasUsersNextString (or getKasUsersNext) + * and getKasUsersDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * startIndex the starting base-zero index + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getKasUsersBeginAt (JNIEnv *env, jclass cls, + jint cellHandle, + jint startIndex) { + + afs_status_t ast; + void *iterationId; + kas_identity_t who; + int i; + + if( !kas_PrincipalGetBegin( (void *) cellHandle, NULL, + &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + for ( i = 1; i < startIndex; i++) { + if( !kas_PrincipalGetNext( (void *) iterationId, &who, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + } + + return (jint) iterationId; + +} + +/** + * Returns the next kas user of the cell. Returns null if there + * are no more users. Appends instance names to principal names as follows: + * principal.instance + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next user of the cell + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Cell_getKasUsersNextString (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + kas_identity_t who; + jstring juser; + + if( !kas_PrincipalGetNext( (void *) iterationId, &who, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return NULL; + // other + } else { + throwAFSException( env, ast ); + return; + } + } + + if( strcmp( who.instance, "" ) ) { + char *fullName = (char *) malloc( sizeof(char)*( strlen( who.principal ) + + strlen( who.instance ) + + 2 ) ); + if( !fullName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + *fullName = '\0'; + strcat( fullName, who.principal ); + strcat( fullName, "." ); + strcat( fullName, who.instance ); + juser = (*env)->NewStringUTF(env, fullName ); + free( fullName ); + } else { + juser = (*env)->NewStringUTF(env, who.principal); + } + + return juser; + +} + +/** + * Fills the next kas user object of the cell. Returns 0 if there + * are no more users, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * iterationId the iteration ID of this iteration + * juserObject a User object to be populated with the values of + * the next kas user + * returns 0 if there are no more users, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getKasUsersNext (JNIEnv *env, jclass cls, + jint cellHandle, + jint iterationId, + jobject juserObject) { + + afs_status_t ast; + kas_identity_t who; + jstring juser; + char *fullName = NULL; + + + if( !kas_PrincipalGetNext( (void *) iterationId, &who, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return 0; + // other + } else { + throwAFSException( env, ast ); + return 0; + } + } + + // take care of the instance stuff(by concatenating with a period in between) + if( strcmp( who.instance, "" ) ) { + fullName = (char *) malloc( sizeof(char)*( strlen( who.principal ) + + strlen( who.instance ) + 2 ) ); + if( !fullName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + *fullName = '\0'; + strcat( fullName, who.principal ); + strcat( fullName, "." ); + strcat( fullName, who.instance ); + juser = (*env)->NewStringUTF(env, fullName ); + } else { + juser = (*env)->NewStringUTF(env, who.principal); + } + + if( userCls == 0 ) { + internal_getUserClass( env, juserObject ); + } + + (*env)->SetObjectField(env, juserObject, user_nameField, juser); + + if( fullName != NULL ) { + getUserInfoChar( env, (int) cellHandle, fullName, juserObject ); + free( fullName ); + } else { + getUserInfoChar( env, (int) cellHandle, who.principal, juserObject ); + } + (*env)->SetBooleanField( env, juserObject, user_cachedInfoField, TRUE ); + + return 1; + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_getKasUsersDone (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + + if( !kas_PrincipalGetDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Returns the name of the cell. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * returns the name of the cell + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Cell_getCellName (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + char *cellName; + jstring jcellName; + + if( !afsclient_CellNameGet( (void *) cellHandle, + (const char **) &cellName, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + jcellName = (*env)->NewStringUTF(env, cellName); + + return jcellName; + +} + +/** + * Returns the total number of PTS users belonging to the cell denoted + * by cellHandle. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * returns total number of PTS users + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getPtsUserCount (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + void *iterationId; + char *userName; + int i = 0; + + if( !pts_UserListBegin( (void *) cellHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return -1; + } + + userName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !userName ) { + throwAFSException( env, JAFSADMNOMEM ); + return -1; + } + + while ( pts_UserListNext( (void *) iterationId, userName, &ast ) ) i++; + + free( userName ); + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Returns the total number of PTS users, belonging to the cell denoted + * by cellHandle, that are not in KAS. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * returns total number of users that are in PTS and not KAS + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getPtsOnlyUserCount (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + void *iterationId; + kas_identity_p who = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + kas_principalEntry_t kasEntry; + char *userName; + int i = 0; + + if( !who ) { + throwAFSException( env, JAFSADMNOMEM ); + return -1; + } + + if( !pts_UserListBegin( (void *) cellHandle, &iterationId, &ast ) ) { + free( who ); + throwAFSException( env, ast ); + return -1; + } + + userName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !userName ) { + free( who ); + throwAFSException( env, JAFSADMNOMEM ); + return -1; + } + + while ( pts_UserListNext( (void *) iterationId, userName, &ast ) ) { + if( strcmp( userName, "anonymous" ) != 0 ) { + // make sure the name is within the allowed bounds + if( strlen( userName ) > KAS_MAX_NAME_LEN ) { + free( who ); + free( userName ); + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return -1; + } + + // if there is a kas entry, recurse + internal_makeKasIdentity( userName, who ); + if( !kas_PrincipalGet( (void *) cellHandle, NULL, who, + &kasEntry, &ast ) ) i++; + } + } + + free( userName ); + free( who ); + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Begin the process of getting the pts users that belong to the cell. + * Returns an iteration ID to be used by subsequent calls to + * getPtsUsersNextString (or getPtsUsersNext) + * and getPtsUsersDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getPtsUsersBegin (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + void *iterationId; + + if( !pts_UserListBegin( (void *) cellHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return (jint) iterationId; + +} + +/** + * Returns the next pts user of the cell. Returns null if + * there are no more users. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next user of the cell + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Cell_getPtsUsersNextString (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + char *userName; + jstring juser; + + userName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !userName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_UserListNext( (void *) iterationId, userName, &ast ) ) { + free( userName ); + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + if( strcmp( userName, "anonymous" ) == 0 ) { + free( userName ); + return Java_org_openafs_jafs_Cell_getPtsUsersNextString( env, cls, + iterationId ); + } + + juser = (*env)->NewStringUTF(env, userName); + free( userName ); + return juser; + +} + +/** + * Returns the next pts user (who is not a kas user) of the cell. + * Returns null if there are no more users. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * cellHandle the cell handle to which these users will belong + * returns the name of the next pts user (not kas user) of the cell + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Cell_getPtsOnlyUsersNextString (JNIEnv *env, + jclass cls, + jint iterationId, + jint cellHandle) { + + kas_identity_p who = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + kas_principalEntry_t kasEntry; + afs_status_t ast; + char *userName; + jstring juser; + + if( !who ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + userName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !userName ) { + free( who ); + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + while( 1 ) { + + if( !pts_UserListNext( (void *) iterationId, userName, &ast ) ) { + free( userName ); + free( who ); + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + if( strcmp( userName, "anonymous" ) == 0 ) { + continue; + } + + // make sure the name is within the allowed bounds + if( strlen( userName ) > KAS_MAX_NAME_LEN ) { + free( who ); + free( userName ); + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return; + } + + // if there is a kas entry, recurse + internal_makeKasIdentity( userName, who ); + if( kas_PrincipalGet( (void *) cellHandle, NULL, who, + &kasEntry, &ast ) ) { + continue; + } + + juser = (*env)->NewStringUTF(env, userName); + free( userName ); + free( who ); + return juser; + + } + +} + +/** + * Fills the next pts user object of the cell. Returns 0 if there + * are no more users, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * iterationId the iteration ID of this iteration + * juserObject a User object to be populated with the values of + * the next pts user + * returns 0 if there are no more users, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getPtsUsersNext (JNIEnv *env, jclass cls, + jint cellHandle, + jint iterationId, + jobject juserObject ) { + + afs_status_t ast; + char *userName; + jstring juser; + + userName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !userName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_UserListNext( (void *) iterationId, userName, &ast ) ) { + free( userName ); + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + if( strcmp( userName, "anonymous" ) == 0 ) { + free( userName ); + return Java_org_openafs_jafs_Cell_getPtsUsersNext( env, cls, + cellHandle, + iterationId, + juserObject ); + } + + juser = (*env)->NewStringUTF(env, userName); + + if( userCls == 0 ) { + internal_getUserClass( env, juserObject ); + } + + (*env)->SetObjectField(env, juserObject, user_nameField, juser); + + getUserInfoChar( env, (int) cellHandle, userName, juserObject ); + (*env)->SetBooleanField( env, juserObject, user_cachedInfoField, TRUE ); + + free( userName ); + return 1; + +} + +/** + * Fills the next pts user (who does not have a kas entry) object of + * the cell. Returns 0 if there are no more users, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * iterationId the iteration ID of this iteration + * juserObject a User object to be populated with the values of + * the next pts (with no kas) user + * returns 0 if there are no more users, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getPtsOnlyUsersNext (JNIEnv *env, jclass cls, + jint cellHandle, + jint iterationId, + jobject juserObject ) { + + kas_identity_p who = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + kas_principalEntry_t kasEntry; + afs_status_t ast; + char *userName; + jstring juser; + + if( !who ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + userName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !userName ) { + free( who ); + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + while( 1 ) { + + if( !pts_UserListNext( (void *) iterationId, userName, &ast ) ) { + free( userName ); + free( who ); + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + if( strcmp( userName, "anonymous" ) == 0 ) { + continue; + } + + // make sure the name is within the allowed bounds + if( strlen( userName ) > KAS_MAX_NAME_LEN ) { + free( userName ); + free( who ); + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return 0; + } + + if( userCls == 0 ) { + internal_getUserClass( env, juserObject ); + } + + + // if there is a kas entry, recurse + internal_makeKasIdentity( userName, who ); + if( kas_PrincipalGet( (void *) cellHandle, NULL, who, + &kasEntry, &ast ) ) { + continue; + } + + juser = (*env)->NewStringUTF(env, userName); + + (*env)->SetObjectField(env, juserObject, user_nameField, juser); + getUserInfoChar( env, (int) cellHandle, userName, juserObject ); + (*env)->SetBooleanField( env, juserObject, user_cachedInfoField, TRUE ); + + free( who ); + free( userName ); + return 1; + + } + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_getPtsUsersDone (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + + if( !pts_UserListDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Returns the total number of groups belonging to the cell denoted + * by cellHandle. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the groups belong + * returns total number of groups + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getGroupCount (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + void *iterationId; + char *groupName; + int i = 0; + + if( !pts_GroupListBegin( (void *) cellHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return -1; + } + + groupName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return -1; + } + + while ( pts_GroupListNext( (void *) iterationId, groupName, &ast ) ) i++; + + free( groupName ); + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Begin the process of getting the groups that belong to the cell. Returns + * an iteration ID to be used by subsequent calls to + * getGroupsNextString (or getGroupsNext) and + * getGroupsDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the groups belong + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getGroupsBegin (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + void *iterationId; + + if( !pts_GroupListBegin( (void *) cellHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return (jint) iterationId; + +} + +/** + * Begin the process of getting the groups that belong to the cell, starting + * with element index startIndex. Returns an iteration ID to + * be used by subsequent calls to getGroupsNextString + * (or getGroupsNext) and getGroupsDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the groups belong + * startIndex the starting base-zero index + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getGroupsBeginAt (JNIEnv *env, jclass cls, + jint cellHandle, + jint startIndex) { + + afs_status_t ast; + void *iterationId; + char *groupName; + int i; + + groupName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !pts_GroupListBegin( (void *) cellHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return 0; + } + + for ( i = 1; i < startIndex; i++) { + if( !pts_GroupListNext( (void *) iterationId, groupName, &ast ) ) { + free( groupName ); + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + } + + free( groupName ); + return (jint) iterationId; + +} + +/** + * Returns the next group of the cell. Returns null if there + * are no more groups. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next user of the cell + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Cell_getGroupsNextString (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + char *groupName; + jstring jgroup; + + groupName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_GroupListNext( (void *) iterationId, groupName, &ast ) ) { + free( groupName ); + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + jgroup = (*env)->NewStringUTF(env, groupName); + free( groupName ); + return jgroup; + +} + +/** + * Fills the next group object of the cell. Returns 0 if there + * are no more groups, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * iterationId the iteration ID of this iteration + * jgroupObject a Group object to be populated with the values of + * the next group + * returns 0 if there are no more users, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getGroupsNext (JNIEnv *env, jclass cls, + jint cellHandle, + jint iterationId, + jobject jgroupObject) { + + afs_status_t ast; + char *groupName; + jstring jgroup; + + groupName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN ); + + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_GroupListNext( (void *) iterationId, groupName, &ast ) ) { + free( groupName ); + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + jgroup = (*env)->NewStringUTF(env, groupName); + + if( groupCls == 0 ) { + internal_getGroupClass( env, jgroupObject ); + } + + (*env)->SetObjectField(env, jgroupObject, group_nameField, jgroup); + + getGroupInfoChar( env, (int) cellHandle, groupName, jgroupObject ); + (*env)->SetBooleanField( env, jgroupObject, group_cachedInfoField, TRUE ); + + free( groupName ); + return 1; + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_getGroupsDone (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + + if( !pts_GroupListDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Gets the maximum group pts ID that's been used within a cell. + * The next auto-assigned group ID will be one less (more negative) + * than this value. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * returns an integer reresenting the max group id in a cell + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getMaxGroupID (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + jint maxID; + + if( !pts_GroupMaxGet( (void *) cellHandle, (int *) &maxID, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return maxID; + +} + +/** + * Sets the maximum group pts ID that's been used within a cell. The next + * auto-assigned group ID will be one less (more negative) than this value. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * maxID an integer reresenting the new max group id in a cell + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_setMaxGroupID (JNIEnv *env, jclass cls, + jint cellHandle, jint maxID) { + + afs_status_t ast; + + if( !pts_GroupMaxSet( (void *) cellHandle, (int) maxID, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Gets the maximum user pts ID that's been used within a cell. + * The next auto-assigned user ID will be one greater (more positive) + * than this value. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * returns an integer reresenting the max user id in a cell + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getMaxUserID (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + jint maxID; + + if( !pts_UserMaxGet( (void *) cellHandle, (int *) &maxID, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return maxID; + +} + +/** + * Sets the maximum user pts ID that's been used within a cell. The next + * auto-assigned user ID will be one greater (more positive) than this value. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * maxID an integer reresenting the new max user id in a cell + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_setMaxUserID (JNIEnv *env, jclass cls, + jint cellHandle, jint maxID) { + + afs_status_t ast; + + if( !pts_UserMaxSet( (void *) cellHandle, (int) maxID, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Returns the total number of servers belonging to the cell denoted + * by cellHandle. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the servers belong + * returns total number of servers + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getServerCount (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + void *iterationId; + afs_serverEntry_t servEntry; + int i = 0; + + if( !afsclient_AFSServerGetBegin( (void *) cellHandle, + &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return -1; + } + + while ( afsclient_AFSServerGetNext( (void *) iterationId, + &servEntry, &ast ) ) i++; + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Begin the process of getting the servers in the cell. Returns + * an iteration ID to be used by subsequent calls to + * getServersNextString and getServersDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the servers belong + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getServersBegin (JNIEnv *env, jclass cls, + jint cellHandle) { + + afs_status_t ast; + void *iterationId; + + if( !afsclient_AFSServerGetBegin( (void *) cellHandle, + &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return (jint) iterationId; + +} + +/** + * Returns the next server of the cell. Returns null if there + * are no more servers. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next server of the cell + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Cell_getServersNextString (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + jstring jserver; + afs_serverEntry_t servEntry; + + if( !afsclient_AFSServerGetNext( (void *) iterationId, &servEntry, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + return jserver; + +} + +/** + * Fills the next server object of the cell. Returns 0 if there are no + * more servers, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * iterationId the iteration ID of this iteration + * jserverObject a Server object to be populated with the values + * of the next server + * returns 0 if there are no more servers, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Cell_getServersNext + (JNIEnv *env, jclass cls, jint cellHandle, jint iterationId, + jobject jserverObject) +{ + afs_status_t ast; + jstring jserver; + afs_serverEntry_t servEntry; + jintArray jaddress; + + if( !afsclient_AFSServerGetNext( (void *) iterationId, &servEntry, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + // get the class fields if need be + if( serverCls == 0 ) { + internal_getServerClass( env, jserverObject ); + } + + fillServerInfo( env, (int) cellHandle, jserverObject, servEntry ); + + (*env)->SetBooleanField( env, jserverObject, server_cachedInfoField, TRUE ); + + return 1; +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_getServersDone + (JNIEnv *env, jclass cls, jint iterationId) +{ + afs_status_t ast; + + if( !afsclient_AFSServerGetDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Creates a mount point for a volume within the file system. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * jdirectory the full path of the place in the AFS file system + * at which to mount the volume + * jvolumeName the name of the volume to mount + * readWrite whether or not this is to be a readwrite mount point + * forceCheck whether or not to check if this volume name exists + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_createMountPoint (JNIEnv *env, jclass cls, + jint cellHandle, + jstring jdirectory, + jstring jvolumeName, + jboolean readWrite, + jboolean forceCheck) { + + afs_status_t ast; + const char *directory; + const char *volumeName; + vol_type_t type; + vol_check_t check; + + if( jdirectory != NULL ) { + directory = (*env)->GetStringUTFChars(env, jdirectory, 0); + if( !directory ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + directory = NULL; + } + if( jvolumeName != NULL ) { + volumeName = (*env)->GetStringUTFChars(env, jvolumeName, 0); + if( !volumeName ) { + if( directory != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdirectory, directory); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + volumeName = NULL; + } + + if( readWrite ) { + type = READ_WRITE; + } else { + type = READ_ONLY; + } + + if( forceCheck ) { + check = CHECK_VOLUME; + } else { + check = DONT_CHECK_VOLUME; + } + + if( !afsclient_MountPointCreate( (void *) cellHandle, directory, + volumeName, type, check, &ast ) ) { + if( volumeName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolumeName, volumeName); + } + if( directory != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdirectory, directory); + } + throwAFSException( env, ast ); + return; + } + + if( volumeName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolumeName, volumeName); + } + if( directory != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdirectory, directory); + } + +} + +/* + * Sets an ACL for a given place in the AFS file system. + * + * env the Java environment + * cls the current Java class + * jdirectory the full path of the place in the AFS file system + * for which to add an entry + * jusername the name of the user or group for which to add an entry + * read whether or not to allow read access to this user + * write whether or not to allow write access to this user + * lookup whether or not to allow lookup access to this user + * delete whether or not to allow deletion access to this user + * insert whether or not to allow insertion access to this user + * lock whether or not to allow lock access to this user + * admin whether or not to allow admin access to this user + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_setACL (JNIEnv *env, jclass cls, + jstring jdirectory, jstring juserName, + jboolean read, jboolean write, + jboolean lookup, jboolean delete, + jboolean insert, jboolean lock, + jboolean admin) { + + afs_status_t ast; + const char *directory; + const char *userName; + acl_t acl; + + // Added by MP + if( !afsclient_Init( &ast ) ) { + throwAFSException( env, ast ); + return; + } + + if( jdirectory != NULL ) { + directory = (*env)->GetStringUTFChars(env, jdirectory, 0); + if( !directory ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + directory = NULL; + } + if( juserName != NULL ) { + userName = (*env)->GetStringUTFChars(env, juserName, 0); + if( !userName ) { + if( directory != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdirectory, directory); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + userName = NULL; + } + + if( read ) { + acl.read = READ; + } else { + acl.read = NO_READ; + } + + if( write ) { + acl.write = WRITE; + } else { + acl.write = NO_WRITE; + } + + if( lookup ) { + acl.lookup = LOOKUP; + } else { + acl.lookup = NO_LOOKUP; + } + + if( delete ) { + acl.del = DELETE; + } else { + acl.del = NO_DELETE; + } + + if( insert ) { + acl.insert = INSERT; + } else { + acl.insert = NO_INSERT; + } + + if( lock ) { + acl.lock = LOCK; + } else { + acl.lock = NO_LOCK; + } + + if( admin ) { + acl.admin = ADMIN; + } else { + acl.admin = NO_ADMIN; + } + + if( !afsclient_ACLEntryAdd( directory, userName, &acl, &ast ) ) { + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( directory != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdirectory, directory); + } + throwAFSException( env, ast ); + return; + } + + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( directory != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdirectory, directory); + } + +} + +// reclaim global memory used by this portion +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Cell_reclaimCellMemory (JNIEnv *env, jclass cls) { + +} + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/JAVA/libjafs/Exceptions.h b/src/JAVA/libjafs/Exceptions.h new file mode 100644 index 0000000..1692cfd --- /dev/null +++ b/src/JAVA/libjafs/Exceptions.h @@ -0,0 +1,12 @@ +#ifndef _Jafsadm_Exceptions +#define _Jafsadm_Exceptions + +static char *afsExceptionName = "org/openafs/jafs/AFSException"; +static char *afsFileExceptionName = "org/openafs/jafs/AFSFileException"; +static char *afsSecurityExceptionName = "org/openafs/jafs/AFSSecurityException"; + +#endif + + + + diff --git a/src/JAVA/libjafs/File.c b/src/JAVA/libjafs/File.c new file mode 100644 index 0000000..4adcfd0 --- /dev/null +++ b/src/JAVA/libjafs/File.c @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_File.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Access Rights */ +#define UAFS_READ 1 +#define UAFS_WRITE 2 +#define UAFS_INSERT 4 +#define UAFS_LOOKUP 8 +#define UAFS_DELETE 16 +#define UAFS_LOCK 32 +#define UAFS_ADMIN 64 + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +void setFileNotExistsAttributes(JNIEnv *env, jobject *obj); + +typedef struct { + char *fileName; + void *next; +} FileNameNode; + +/*static char compile_date[] = COMPILE_DATE;*/ + +int sub_time(struct timeval *tv1, struct timeval *tv2) +{ + if (tv2->tv_usec > tv1->tv_usec) { + tv1->tv_usec += 1000000; + tv1->tv_usec -= 1; + } + + tv1->tv_usec -= tv2->tv_usec; + tv1->tv_sec -= tv2->tv_sec; +} + +/** + * Sets dirName to the absolute path according to the path field + * within the Java File object (obj). + * + * env the Java environment + * obj the current Java object + */ +char* getAbsolutePath(JNIEnv *env, jobject *obj, char *dirName) +{ + jclass thisClass; + jstring jDirName; + jmethodID getAbsolutePathID; + const char *auxDirName; + jfieldID fid; + + thisClass = (*env)->GetObjectClass(env, *obj); + if(thisClass == NULL) { + fprintf(stderr, "File::getAbsolutePath(): GetObjectClass failed\n"); + return NULL; + } + fid = (*env)->GetFieldID(env, thisClass, "path", "Ljava/lang/String;"); + if (fid == 0) { + fprintf(stderr, "File::getAbsolutePath(): GetFieldID (path) failed\n"); + return NULL; + } + jDirName = (*env)->GetObjectField(env, *obj, fid); + + if(jDirName == NULL) { + fprintf(stderr, "File::getAbsolutePath(): failed to get file name\n"); + return NULL; + } + auxDirName = (*env) -> GetStringUTFChars(env, jDirName, 0); + strcpy(dirName, auxDirName); + (*env) -> ReleaseStringUTFChars(env, jDirName, auxDirName); +} + +/** + * Performs a file stat on the actual AFS file and populates + * the Java object's respective field members with the appropriate values. + * method will, if authorized, perform a stat on the + * actual AFS file and update its respective field members; defining + * this file object's attributes. + * + * env the Java environment + * obj the current Java object + * + * return true if and only if the current user is allowed to stat the file; + * false otherwise. + * + * throws AFSException + */ +JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_setAttributes + (JNIEnv *env, jobject obj) +{ + char target[FILENAME_MAX+1]; + char dirName[FILENAME_MAX]; + jclass thisClass; + jfieldID fid; + struct stat st; + int rc, fd; + int mtpoint = 0; + jboolean islink = JNI_FALSE; + int i; + struct timeval tv0, tv1; + struct timezone tz; + + /*memset(target, 0, FILENAME_MAX);*/ + + *dirName = '\0'; + getAbsolutePath(env, &obj, dirName); + + /*fprintf(stderr, "dirName=%s\n", dirName);*/ + + if(*dirName == '\0') { + fprintf(stderr, "File::setAttributes(): failed to get dirName\n"); + return JNI_FALSE; + } + + thisClass = (*env) -> GetObjectClass(env, obj); + if(thisClass == NULL) { + fprintf(stderr, "File::setAttributes(): GetObjectClass failed\n"); + return JNI_FALSE; + } + + gettimeofday(&tv0, &tz); + if ((strcmp(dirName, "/afs") == 0) || (strcmp(dirName, "/afs/") == 0)) { + rc = 1; /* special case for /afs since statmountpoint fails on it */ + } else { + rc = uafs_statmountpoint(dirName); + gettimeofday(&tv1, &tz); + sub_time(&tv1, &tv0); + /*printf("%s: statmountpoint %d.%06d\n", dirName, tv1.tv_sec, tv1.tv_usec);*/ + } + + if(rc < 0) { + setError(env, &obj, errno); + if(errno == ENOENT) { + setFileNotExistsAttributes(env, &obj); + return JNI_TRUE; /* not really an error */ + } else { + fprintf(stderr, "File::setAttributes(): uafs_statmountpoint failed " + "for %s (%s)\n", dirName, error_message(errno)); + return JNI_FALSE; + } + } + + if (rc == 1) { + /* this is an AFS mount point; we don't want to stat it */ + /* fake up a stat entry instead */ + mtpoint = 1; + st.st_mtime = 0; + st.st_size = 2048; + st.st_mode = 0; /* don't match anything */ + } else { + mtpoint = 0; + fid = (*env)->GetFieldID(env, thisClass, "isLink", "Z"); + if (fid == 0) { + fprintf(stderr, "File::setAttributes(): GetFieldID (isLink) failed\n"); + setError(env, &obj, -1); + return JNI_FALSE; + } + islink = (*env)->GetBooleanField(env, obj, fid); + if (islink != JNI_TRUE) { + rc = uafs_lstat(dirName, &st); + } else { + /* Here we are being called on a link object for the second time, + so we want info on the object pointed to by the link. */ + fprintf(stderr, "islink = TRUE on file %s\n", dirName); + rc = uafs_stat(dirName, &st); + } + + if(rc < 0) { + setError(env, &obj, errno); + fprintf(stderr, "uafs_lstat failed for dir %s: error %d\n", + dirName, errno); + if(errno == ENOENT) { + setFileNotExistsAttributes(env, &obj); + return JNI_TRUE; + } + fprintf(stderr, + "File::setAttributes(): uafs_stat failed for %s (%s)\n", + dirName, error_message(errno)); + return JNI_FALSE; + } + } + + fid = (*env)->GetFieldID(env, thisClass, "exists", "Z"); + if (fid == 0) { + fprintf(stderr, + "File::setAttributes(): GetFieldID (exists) failed\n"); + setError(env, &obj, -1); + return JNI_FALSE; + } + (*env)->SetBooleanField(env, obj, fid, JNI_TRUE); + + fid = (*env)->GetFieldID(env, thisClass, "isDirectory", "Z"); + if (fid == 0) { + fprintf(stderr, + "File::setAttributes(): GetFieldID (isDirectory) failed\n"); + setError(env, &obj, -1); + return JNI_FALSE; + } + if ((st.st_mode & S_IFMT) == S_IFDIR && !mtpoint) { + (*env)->SetBooleanField(env, obj, fid, JNI_TRUE); + } else { + (*env)->SetBooleanField(env, obj, fid, JNI_FALSE); + } + + fid = (*env)->GetFieldID(env, thisClass, "isFile", "Z"); + if (fid == 0) { + fprintf(stderr, + "File::setAttributes(): GetFieldID (isFile) failed\n"); + setError(env, &obj, -1); + return JNI_FALSE; + } + if ((st.st_mode & S_IFMT) == S_IFREG) { + (*env)->SetBooleanField(env, obj, fid, JNI_TRUE); + } else { + (*env)->SetBooleanField(env, obj, fid, JNI_FALSE); + } + + fid = (*env)->GetFieldID(env, thisClass, "isLink", "Z"); + if (fid == 0) { + fprintf(stderr, + "File::setAttributes(): GetFieldID (isLink) failed\n"); + setError(env, &obj, -1); + return JNI_FALSE; + } + + if (islink != JNI_TRUE) { /* don't re-process link */ + if ((st.st_mode & S_IFMT) == S_IFLNK) { + (*env)->SetBooleanField(env, obj, fid, JNI_TRUE); + + /* Find the target of the link */ + rc = uafs_readlink(dirName, target, FILENAME_MAX); + if (rc < 0) { + fprintf(stderr, "File::setAttributes(): uafs_readlink failed\n"); + setError(env, &obj, errno); + return JNI_FALSE; + } else { + target[rc] = 0; /* weird that we have to do this */ + /*fprintf(stderr, "readlink %s succeeded, target=%s, rc=%d\n", dirName, + target, rc);*/ + } + + rc = setString(env, &obj, "target", target); + if (rc < 0) { + fprintf(stderr, "setString dirName=%s target=%s failed\n", + dirName, target); + } + } else { + (*env)->SetBooleanField(env, obj, fid, JNI_FALSE); + } + } + + fid = (*env)->GetFieldID(env, thisClass, "isMountPoint", "Z"); + if (fid == 0) { + fprintf(stderr, + "File::setAttributes(): GetFieldID (isMountPoint) failed\n"); + setError(env, &obj, -1); + return JNI_FALSE; + } + + if (mtpoint) { + (*env)->SetBooleanField(env, obj, fid, JNI_TRUE); + } else { + (*env)->SetBooleanField(env, obj, fid, JNI_FALSE); + } + + fid = (*env)->GetFieldID(env, thisClass, "lastModified", "J"); + if (fid == 0) { + fprintf(stderr, + "File::setAttributes(): GetFieldID (lastModified) failed\n"); + setError(env, &obj, -1); + return JNI_FALSE; + } + (*env)->SetLongField(env, obj, fid, ((jlong) st.st_mtime)*1000); + + fid = (*env)->GetFieldID(env, thisClass, "length", "J"); + if (fid == 0) { + fprintf(stderr, + "File::setAttributes(): GetFieldID (length) failed\n"); + setError(env, &obj, -1); + return JNI_FALSE; + } + (*env)->SetLongField(env, obj, fid, st.st_size); + + setError(env, &obj, 0); + + return JNI_TRUE; +} + +/** + * Returns the permission/ACL mask for the represented directory + * + * env the Java environment + * obj the current Java object + * + * return permission/ACL mask + */ +JNIEXPORT jint JNICALL Java_org_openafs_jafs_File_getRights + (JNIEnv *env, jobject obj) +{ + char dirName[FILENAME_MAX]; + jclass thisClass; + jfieldID fid; + int rc; + int afs_rights; + int rights; + + *dirName = '\0'; + getAbsolutePath(env, &obj, dirName); + + if(*dirName == '\0') { + fprintf(stderr, "File::getRights(): failed to get dirName\n"); + setError(env, &obj, -1); + return JNI_FALSE; + } + + /*-Access Rights- + * UAFS_READ 1 + * UAFS_WRITE 2 + * UAFS_INSERT 4 + * UAFS_LOOKUP 8 + * UAFS_DELETE 16 + * UAFS_LOCK 32 + * UAFS_ADMIN 64 + */ + + rights = 0; + afs_rights = uafs_getRights(dirName); + if (afs_rights < 0) { + setError(env, &obj, errno); + return -1; + } + + if (afs_rights & PRSFS_READ) + rights |= UAFS_READ; + if (afs_rights & PRSFS_WRITE) + rights |= UAFS_WRITE; + if (afs_rights & PRSFS_INSERT) + rights |= UAFS_INSERT; + if (afs_rights & PRSFS_LOOKUP) + rights |= UAFS_LOOKUP; + if (afs_rights & PRSFS_DELETE) + rights |= UAFS_DELETE; + if (afs_rights & PRSFS_LOCK) + rights |= UAFS_LOCK; + if (afs_rights & PRSFS_ADMINISTER) + rights |= UAFS_ADMIN; + + return rights; +} + + +/** + * List the contents of the represented directory. + * + * env the Java environment + * obj the current Java object + * + * return the directory handle + */ +JNIEXPORT jlong JNICALL Java_org_openafs_jafs_File_listNative + (JNIEnv *env, jobject obj, jobject buffer) +{ + char dirName[FILENAME_MAX]; + jclass arrayListClass; + jmethodID addID; + jstring entryJString; + usr_DIR *dirp; + struct usr_dirent *enp; + int i, dirSize; + + *dirName='\0'; + getAbsolutePath(env, &obj, dirName); + if(*dirName == '\0') { + fprintf(stderr, "File::listNative(): failed to get dirName\n"); + setError(env, &obj, -1); + return 0; + } + arrayListClass = (*env)->GetObjectClass(env, buffer); + if(arrayListClass == NULL) { + fprintf(stderr, "File::listNative(): GetObjectClass failed\n"); + setError(env, &obj, -1); + return 0; + } + addID = (*env) -> GetMethodID(env, arrayListClass, "add", + "(Ljava/lang/Object;)Z"); + if(addID == 0) { + fprintf(stderr, + "File::listNative(): failed to get addID\n"); + setError(env, &obj, -1); + return 0; + } + dirp = uafs_opendir(dirName); + if(dirp == NULL) { + fprintf(stderr, "File::listNative(): uafs_opendir(%s) failed(%s)\n", + dirName, error_message(errno)); + setError(env, &obj, errno); + //throwAFSSecurityException( env, errno ); + return 0; + } + while((enp = uafs_readdir(dirp)) != NULL) { + if(strcmp(enp->d_name, ".") == 0 || strcmp(enp->d_name, "..") == 0) { + continue; + } + entryJString = (*env) -> NewStringUTF(env, enp->d_name); + if(entryJString == NULL) { + fprintf(stderr, "File::listNative(): NewStringUTF failed\n"); + setError(env, &obj, -1); + return 0; + } + (*env) -> CallBooleanMethod(env, buffer, addID, entryJString); + } + /*uafs_closedir(dirp);*/ + + setError(env, &obj, 0); + + return (jlong) dirp; +} + +/** + * Close the currently open directory using a provided directory handle. + * + * env the Java environment + * obj the current Java object + * + * return true if the directory closes without error + */ +JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_closeDir + (JNIEnv *env, jobject obj, jlong dp) +{ + usr_DIR *dirp = (usr_DIR *) dp; + int rc; + + rc = uafs_closedir(dirp); + if (rc < 0) { + setError(env, &obj, errno); + return JNI_FALSE; + } + else return JNI_TRUE; +} + + +/** + * Removes/deletes the represented file. + * + * env the Java environment + * obj the current Java object + * + * return true if the file is removed without error + */ +JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_rmfile + (JNIEnv *env, jobject obj) +{ + char dirName[FILENAME_MAX]; + int rc; + + *dirName='\0'; + getAbsolutePath(env, &obj, dirName); + if(*dirName == '\0') { + setError(env, &obj, EINVAL); + fprintf(stderr, "File::rmfile(): failed to get dirName\n"); + return JNI_FALSE; + } + rc = uafs_unlink(dirName); + if(rc < 0) { + setError(env, &obj, errno); + fprintf(stderr, "File::rmfile(): uafs_unlink failed\n"); + return JNI_FALSE; + } + setError(env, &obj, 0); + return JNI_TRUE; +} + +/** + * Removes/deletes the represented directory. + * + * env the Java environment + * obj the current Java object + * + * return true if the directory is removed without error + */ +JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_rmdir + (JNIEnv *env, jobject obj) +{ + char dirName[FILENAME_MAX]; + int rc; + + *dirName='\0'; + getAbsolutePath(env, &obj, dirName); + if(*dirName == '\0') { + setError(env, &obj, -1); + fprintf(stderr, "File::rmdir(): failed to get dirName\n"); + return JNI_FALSE; + } + rc = uafs_rmdir(dirName); + if(rc < 0) { + setError(env, &obj, errno); + fprintf(stderr, "File::rmdir(): uafs_unlink failed\n"); + return JNI_FALSE; + } + setError(env, &obj, 0); + return JNI_TRUE; +} + +/** + * Creates the directory named by this abstract pathname. + * + * env the Java environment + * obj the current Java object + * + * return true if and only if the directory was + * created; false otherwise + */ +JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_mkdir + (JNIEnv *env, jobject obj) +{ + char dirName[FILENAME_MAX]; + int rc; + + *dirName='\0'; + getAbsolutePath(env, &obj, dirName); + if(*dirName == '\0') { + setError(env, &obj, EINVAL); + fprintf(stderr, "File::mkdir(): failed to get dirName\n"); + return JNI_FALSE; + } + rc = uafs_mkdir(dirName, 0755); + if(rc < 0) { + setError(env, &obj, errno); + fprintf(stderr, "File::mkdir(): uafs_mkdir failed\n"); + return JNI_FALSE; + } + setError(env, &obj, 0); + return JNI_TRUE; +} + +/** + * Renames the file denoted by this abstract pathname. + * + * env the Java environment + * obj the current Java object + * dest the new abstract pathname for the named file + * + * return true if and only if the renaming succeeded; + * false otherwise + * + * throws NullPointerException + * If parameter dest is null + */ +JNIEXPORT jboolean JNICALL Java_org_openafs_jafs_File_renameTo + (JNIEnv *env, jobject obj, jobject newFile) +{ + char thisDirName[FILENAME_MAX], newDirName[FILENAME_MAX]; + int rc; + + *thisDirName='\0'; + getAbsolutePath(env, &obj, thisDirName); + if(*thisDirName == '\0') { + setError(env, &obj, -1); + fprintf(stderr, "File::renameTo(): failed to get dirName for this \n"); + return JNI_FALSE; + } + *newDirName='\0'; + getAbsolutePath(env, &newFile, newDirName); + if(*newDirName == '\0') { + setError(env, &obj, -1); + fprintf(stderr, "File::renameTo(): failed to get dirName for new \n"); + return JNI_FALSE; + } + rc = uafs_rename(thisDirName, newDirName); + if(rc < 0) { + setError(env, &obj, errno); + fprintf(stderr, "File::renameTo(): uafs_rename failed\n"); + return JNI_FALSE; + } + return JNI_TRUE; +} + +/** + * Set all the necessary fields within the Java File class to indicate the + * does not exist. + * + * env the Java environment + * obj the current Java object + */ +void setFileNotExistsAttributes + (JNIEnv *env, jobject *obj) +{ + jclass thisClass; + jfieldID fid; + + thisClass = (*env) -> GetObjectClass(env, *obj); + if(thisClass == NULL) { + fprintf(stderr, + "File::setFileNotExistsAttributes(): GetObjectClass failed\n"); + return; + } + + fid = (*env)->GetFieldID(env, thisClass, "exists", "Z"); + if (fid == 0) { + fprintf(stderr, + "File::setFileNotExistsAttributes(): GetFieldID (exists) failed\n"); + return; + } + (*env)->SetBooleanField(env, *obj, fid, JNI_FALSE); + + fid = (*env)->GetFieldID(env, thisClass, "isDirectory", "Z"); + if (fid == 0) { + fprintf(stderr, + "File::setFileNotExistsAttributes(): GetFieldID (isDirectory) + failed\n"); + return; + } + (*env)->SetBooleanField(env, *obj, fid, JNI_FALSE); + + fid = (*env)->GetFieldID(env, thisClass, "isFile", "Z"); + if (fid == 0) { + fprintf(stderr, + "File::setFileNotExistsAttributes(): GetFieldID (isDirectory) + failed\n"); + return; + } + (*env)->SetBooleanField(env, *obj, fid, JNI_FALSE); + + fid = (*env)->GetFieldID(env, thisClass, "lastModified", "J"); + if (fid == 0) { + fprintf(stderr, + "File::setFileNotExistsAttributes(): GetFieldID (lastModified) failed\n"); + return; + } + (*env)->SetLongField(env, *obj, fid, 0); + + + fid = (*env)->GetFieldID(env, thisClass, "length", "J"); + if (fid == 0) { + fprintf(stderr, + "File::setFileNotExistsAttributes(): GetFieldID (length) failed\n"); + return; + } + (*env)->SetLongField(env, *obj, fid, 0); + + return; +} + + diff --git a/src/JAVA/libjafs/FileInputStream.c b/src/JAVA/libjafs/FileInputStream.c new file mode 100644 index 0000000..95b9327 --- /dev/null +++ b/src/JAVA/libjafs/FileInputStream.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_FileInputStream.h" + +#include + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +extern int errno; + +/** + * Be carefull with the memory management: + * + * - For every GetStringUTFChars call the corresponding ReleaseStringUTFChars. + * - For every GetArrayElements call the corresponding + * ReleaseArrayElements + * - For every malloc call the corresponding free. + */ + +/*-------------------------------------------------------------------------*/ + +/** + * Opens an AFS file, with the specified name, for appending. + * + * env the Java environment + * obj the current Java object + * fileNameUTF name of file to be opened + * + * @return file descriptor + * @exception AFSFileException if an I/O or other file related error occurs. + */ +JNIEXPORT jint JNICALL Java_org_openafs_jafs_FileInputStream_openReadOnly + (JNIEnv *env, jobject obj, jstring fileNameUTF) +{ + int err; + int fd = -1; //file descriptor + + fd = openAFSFile(env, fileNameUTF, O_RDONLY, 0, &err); + if (fd < 0) { + fprintf(stderr, "FileInputStream::openReadOnly(): err=%d\n", err); + throwAFSFileException( env, err, NULL ); + } + return fd; +} + +/** + * Reads up to 'length' bytes of data from this input stream + * into an array of bytes. This method blocks until some input is + * available. + * + * env the Java environment + * obj the current Java object + * jbytes the data to be written + * offset the start offset in the data + * length the number of bytes that are written + * + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the file has been reached. + * @exception AFSFileException if an I/O or other file related error occurs. + */ +JNIEXPORT jint JNICALL Java_org_openafs_jafs_FileInputStream_read + (JNIEnv *env, jobject obj, jbyteArray jbytes, jint offset, jint length) +{ + int fd, bytesLen, bytesRead; + jclass thisClass; + jmethodID getFileDescriptorID; + jbyte *bytes; + jfieldID fid; + + /* If we have to read 0 bytes just return */ + if(length == 0) return 0; + + thisClass = (*env)->GetObjectClass(env, obj); + fid = (*env)->GetFieldID(env, thisClass, "fileDescriptor", "I"); + fd = (*env)->GetIntField(env, obj, fid); + + if(fd < 0) { + fprintf(stderr, "FileInputStream::read(): invalid file state\n"); + throwAFSFileException(env, 0, "Invalid file state"); + return -1; + } + + bytes = (*env) -> GetByteArrayElements(env, jbytes, 0); + bytesLen = (*env) -> GetArrayLength(env, jbytes); + bytesRead = uafs_read(fd, bytes, bytesLen); + + if (errno != 0) throwAFSFileException(env, errno, NULL); + + (*env) -> ReleaseByteArrayElements(env, jbytes, bytes, 0); + return (bytesRead > 0) ? bytesRead : -1; +} + +/** + * Closes this file input stream and releases any system resources + * associated with this stream. This file input stream may no longer + * be used for writing bytes. + * + * env the Java environment + * obj the current Java object + * + * @exception AFSFileException if an I/O or other file related error occurs. + */ +JNIEXPORT void JNICALL Java_org_openafs_jafs_FileInputStream_close + (JNIEnv *env, jobject obj) +{ + int fd, rc; + jclass thisClass; + jmethodID getFileDescriptorID; + jfieldID fid; + char *bytes; + + thisClass = (*env)->GetObjectClass(env, obj); + fid = (*env)->GetFieldID(env, thisClass, "fileDescriptor", "I"); + fd = (*env)->GetIntField(env, obj, fid); + + if(fd < 0) { + fprintf(stderr, "FileInputStream::close(): invalid file state\n"); + throwAFSFileException(env, 0, "Invalid file state"); + return; + } + + rc = uafs_close(fd); + + if (rc != 0) { + throwAFSFileException(env, errno, NULL); + } +} + + + diff --git a/src/JAVA/libjafs/FileOutputStream.c b/src/JAVA/libjafs/FileOutputStream.c new file mode 100644 index 0000000..ed3e617 --- /dev/null +++ b/src/JAVA/libjafs/FileOutputStream.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_FileOutputStream.h" + +#include +#include +#include + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +/** + * Be carefull with the memory management: + * + * - For every GetStringUTFChars call the corresponding ReleaseStringUTFChars. + * - For every GetArrayElements call the corresponding + * ReleaseArrayElements + * - For every malloc call the corresponding free. + */ + +/*-------------------------------------------------------------------------*/ + +/** + * Opens an AFS file, with the specified name, for appending. + * + * env the Java environment + * obj the current Java object + * fileNameUTF name of file to be opened + * + * @returns file descriptor + * @exception AFSFileException if an I/O or other file related error occurs. + */ +JNIEXPORT jint JNICALL Java_org_openafs_jafs_FileOutputStream_openWrite + (JNIEnv *env, jobject obj, jstring fileNameUTF) +{ + int err; + jint fd = -1; //file descriptor + + fd = openAFSFile(env, fileNameUTF, O_CREAT | O_TRUNC, 0644, &err); + if (fd < 0) { + fprintf(stderr, "FileOutputStream::openWrite(): err=%d\n", err); + throwAFSFileException(env, err, NULL); + } + return fd; +} + +/** + * Opens an AFS file, with the specified name, for writing. + * + * env the Java environment + * obj the current Java object + * fileNameUTF name of file to be opened + * + * @return file descriptor + * @exception AFSFileException if an I/O or other file related error occurs. + */ +JNIEXPORT jint JNICALL Java_org_openafs_jafs_FileOutputStream_openAppend + (JNIEnv *env, jobject obj, jstring fileNameUTF) +{ + int err; + jint fd = -1; //file descriptor + + fd = openAFSFile(env, fileNameUTF, O_CREAT | O_APPEND, 0644, &err); + if (fd < 0) { + fprintf(stderr, "FileOutputStream::openAppend(): err=%d\n", err); + throwAFSFileException(env, err, NULL); + } + return fd; +} + +/** + * Writes 'lenght' bytes from the specified byte array starting at offset + * 'offset' to this file output stream. + * + * env the Java environment + * obj the current Java object + * jbytes the data to be written + * offset the start offset in the data + * length the number of bytes that are written + * + * @exception AFSFileException if an I/O or other file related error occurs. + */ +JNIEXPORT void JNICALL Java_org_openafs_jafs_FileOutputStream_write + (JNIEnv *env, jobject obj, jbyteArray jbytes, jint offset, jint length) +{ + int fd, written, toWrite; + jint twritten; + jclass thisClass; + jmethodID getFileDescriptorID; + char *bytes; + jfieldID fid; + + thisClass = (*env)->GetObjectClass(env, obj); + fid = (*env)->GetFieldID(env, thisClass, "fileDescriptor", "I"); + fd = (*env)->GetIntField(env, obj, fid); + if(fd < 0) { + fprintf(stderr, "FileOutputStream::write(): failed to get file + descriptor\n"); + throwAFSFileException(env, 0, "Failed to get file descriptor!"); + } + bytes = (char*) malloc(length); + if(bytes == NULL) { + fprintf(stderr, "FileOutputStream::write(): malloc failed of %d bytes\n", + length); + throwAFSFileException(env, 0, "Failed to allocate memory!"); + } + (*env) -> GetByteArrayRegion(env, jbytes, offset, length, bytes); + toWrite = length; + twritten = 0; + while(toWrite>0) { + written = uafs_write(fd, bytes, length); + twritten += written; + if(written<0) { + free(bytes); + throwAFSFileException(env, errno, NULL); + } + toWrite -= written; + } + free(bytes); +} + +/** + * Closes this file output stream and releases any system resources + * associated with this stream. This file output stream may no longer + * be used for writing bytes. + * + * env the Java environment + * obj the current Java object + * + * @exception AFSFileException if an I/O or other file related error occurs. + */ +JNIEXPORT void JNICALL Java_org_openafs_jafs_FileOutputStream_close + (JNIEnv *env, jobject obj) +{ + int fd, rc; + jclass thisClass; + jmethodID getFileDescriptorID; + char *bytes; + jfieldID fid; + + thisClass = (*env)->GetObjectClass(env, obj); + fid = (*env)->GetFieldID(env, thisClass, "fileDescriptor", "I"); + fd = (*env)->GetIntField(env, obj, fid); + if(fd < 0) { + fprintf(stderr, "FileOutputStream::close(): failed to get file descriptor\n"); + throwAFSFileException(env, 0, "Failed to get file descriptor!"); + } + rc = uafs_close(fd); + if (rc != 0) { + throwAFSFileException(env, rc, NULL); + } +} + + diff --git a/src/JAVA/libjafs/Group.c b/src/JAVA/libjafs/Group.c new file mode 100644 index 0000000..7b944ff --- /dev/null +++ b/src/JAVA/libjafs/Group.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_Group.h" + +#include +#include +#include +#include +#include +#include + +///// definitions in Internal.c /////////////// + +extern jclass userCls; +//extern jfieldID user_cellHandleField; +extern jfieldID user_nameField; +extern jfieldID user_cachedInfoField; + +extern jclass groupCls; +extern jfieldID group_nameField; +extern jfieldID group_nameUidField; +extern jfieldID group_ownerUidField; +extern jfieldID group_creatorUidField; +extern jfieldID group_listStatusField; +extern jfieldID group_listGroupsOwnedField; +extern jfieldID group_listMembershipField; +extern jfieldID group_listAddField; +extern jfieldID group_listDeleteField; +extern jfieldID group_membershipCountField; +extern jfieldID group_ownerField; +extern jfieldID group_creatorField; + +////////////////////////////////////////////////////// + + +/** + * Creates the PTS entry for a new group. Pass in 0 for the uid if PTS is to + * automatically assign the group id. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * jgroupName the name of the group to create + * jownerName the owner of this group + * gid the group id to assign to the group (0 to have one + * automatically assigned) + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_create + (JNIEnv *env, jclass cls, jint cellHandle, jstring jgroupName, + jstring jownerName, jint gid ) +{ + afs_status_t ast; + // convert java strings + const char *groupName; + const char *ownerName; + + if( jgroupName != NULL ) { + groupName = (*env)->GetStringUTFChars(env, jgroupName, 0); + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + groupName = NULL; + } + + if( jownerName != NULL ) { + ownerName = (*env)->GetStringUTFChars(env, jownerName, 0); + if( !ownerName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + ownerName = NULL; + } + + // make sure the name is within the allowed bounds + if( groupName != NULL && strlen( groupName ) > PTS_MAX_NAME_LEN ) { + // release converted java strings + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + if( ownerName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jownerName, ownerName); + } + throwAFSException( env, ADMPTSGROUPNAMETOOLONG ); + return; + } + + if( !pts_GroupCreate( (void *) cellHandle, groupName, ownerName, + (int *) &gid, &ast ) ) { + // release converted java strings + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + if( ownerName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jownerName, ownerName); + } + throwAFSException( env, ast ); + return; + } + + // release converted java strings + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + if( ownerName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jownerName, ownerName); + } + +} + +/** + * Deletes the PTS entry for a group. Deletes this group from the + * membership list of the users that belonged to it, but does not delete + * the groups owned by this group. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * jgroupName the name of the group to delete + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_delete + (JNIEnv *env, jclass cls, jint cellHandle, jstring jgroupName ) +{ + afs_status_t ast; + // convert java strings + const char *groupName; + + if( jgroupName != NULL ) { + groupName = (*env)->GetStringUTFChars(env, jgroupName, 0); + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + groupName = NULL; + } + + if( !pts_GroupDelete( (void *) cellHandle, groupName, &ast ) ) { + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + throwAFSException( env, ast ); + return; + } + + // release converted java strings + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + +} + +/** + * Retrieve the information for the specified group and populate the + * given object + * + * env the Java environment + * cellHandle the handle of the cell to which the user belongs + * name the name of the group for which to get the info + * group the Group object to populate with the info + */ +void getGroupInfoChar + ( JNIEnv *env, jint cellHandle, const char *name, jobject group ) +{ + + jstring jowner; + jstring jcreator; + pts_GroupEntry_t entry; + afs_status_t ast; + // get the field ids if you haven't already + if( groupCls == 0 ) { + internal_getGroupClass( env, group ); + } + + if ( !pts_GroupGet( (void *) cellHandle, name, &entry, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + // set the fields + (*env)->SetIntField(env, group, group_nameUidField, entry.nameUid); + (*env)->SetIntField(env, group, group_ownerUidField, entry.ownerUid); + (*env)->SetIntField(env, group, group_creatorUidField, entry.creatorUid); + (*env)->SetIntField(env, group, group_membershipCountField, + entry.membershipCount); + + if( entry.listStatus == PTS_GROUP_OWNER_ACCESS ) { + (*env)->SetIntField(env, group, group_listStatusField, + org_openafs_jafs_Group_GROUP_OWNER_ACCESS); + } else if( entry.listStatus == PTS_GROUP_ACCESS ) { + (*env)->SetIntField(env, group, group_listStatusField, + org_openafs_jafs_Group_GROUP_GROUP_ACCESS); + } else { + (*env)->SetIntField(env, group, group_listStatusField, + org_openafs_jafs_Group_GROUP_ANYUSER_ACCESS); + } + + if( entry.listGroupsOwned == PTS_GROUP_OWNER_ACCESS ) { + (*env)->SetIntField(env, group, group_listGroupsOwnedField, + org_openafs_jafs_Group_GROUP_OWNER_ACCESS); + } else if( entry.listGroupsOwned == PTS_GROUP_ACCESS ) { + (*env)->SetIntField(env, group, group_listGroupsOwnedField, + org_openafs_jafs_Group_GROUP_GROUP_ACCESS); + } else { + (*env)->SetIntField(env, group, group_listGroupsOwnedField, + org_openafs_jafs_Group_GROUP_ANYUSER_ACCESS); + } + + if( entry.listMembership == PTS_GROUP_OWNER_ACCESS ) { + (*env)->SetIntField(env, group, group_listMembershipField, + org_openafs_jafs_Group_GROUP_OWNER_ACCESS); + } else if( entry.listMembership == PTS_GROUP_ACCESS ) { + (*env)->SetIntField(env, group, group_listMembershipField, + org_openafs_jafs_Group_GROUP_GROUP_ACCESS); + } else { + (*env)->SetIntField(env, group, group_listMembershipField, + org_openafs_jafs_Group_GROUP_ANYUSER_ACCESS); + } + + if( entry.listAdd == PTS_GROUP_OWNER_ACCESS ) { + (*env)->SetIntField(env, group, group_listAddField, + org_openafs_jafs_Group_GROUP_OWNER_ACCESS); + } else if( entry.listAdd == PTS_GROUP_ACCESS ) { + (*env)->SetIntField(env, group, group_listAddField, + org_openafs_jafs_Group_GROUP_GROUP_ACCESS); + } else { + (*env)->SetIntField(env, group, group_listAddField, + org_openafs_jafs_Group_GROUP_ANYUSER_ACCESS); + } + + if( entry.listDelete == PTS_GROUP_OWNER_ACCESS ) { + (*env)->SetIntField(env, group, group_listDeleteField, + org_openafs_jafs_Group_GROUP_OWNER_ACCESS); + } else if( entry.listDelete == PTS_GROUP_ACCESS ) { + (*env)->SetIntField(env, group, group_listDeleteField, + org_openafs_jafs_Group_GROUP_GROUP_ACCESS); + } else { + (*env)->SetIntField(env, group, group_listDeleteField, + org_openafs_jafs_Group_GROUP_ANYUSER_ACCESS); + } + + jowner = (*env)->NewStringUTF(env, entry.owner); + jcreator = (*env)->NewStringUTF(env, entry.creator); + + (*env)->SetObjectField(env, group, group_ownerField, jowner); + (*env)->SetObjectField(env, group, group_creatorField, jcreator); + +} + +/** + * Fills in the information fields of the provided Group. + * Fills in values based on the current PTS information of the group. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * name the name of the group for which to get the information + * group the Group object in which to fill in the + * information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_getGroupInfo + (JNIEnv *env, jclass cls, jint cellHandle, jstring jname, jobject group) +{ + + const char *name; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + getGroupInfoChar( env, cellHandle, name, group ); + + // get class fields if need be + if( groupCls == 0 ) { + internal_getGroupClass( env, group ); + } + + // set name in case blank object + (*env)->SetObjectField(env, group, group_nameField, jname); + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + +} + +/** + * Sets the information values of this AFS group to be the parameter values. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * name the name of the user for which to set the information + * theGroup the group object containing the desired information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_setGroupInfo + (JNIEnv *env, jclass cls, jint cellHandle, jstring jname, jobject group) +{ + const char *name; + pts_GroupUpdateEntry_t ptsEntry; + afs_status_t ast; + + jint jlistStatus; + jint jlistGroupsOwned; + jint jlistMembership; + jint jlistAdd; + jint jlistDelete; + + // get the field ids if you haven't already + if( groupCls == 0 ) { + internal_getGroupClass( env, group ); + } + + jlistStatus = (*env)->GetIntField(env, group, group_listStatusField); + jlistGroupsOwned = (*env)->GetIntField(env, group, + group_listGroupsOwnedField); + jlistMembership = (*env)->GetIntField(env, group, group_listMembershipField); + jlistAdd = (*env)->GetIntField(env, group, group_listAddField); + jlistDelete = (*env)->GetIntField(env, group, group_listDeleteField); + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + if( jlistStatus == org_openafs_jafs_Group_GROUP_OWNER_ACCESS ) { + ptsEntry.listStatus = PTS_GROUP_OWNER_ACCESS; + } else if( jlistStatus == org_openafs_jafs_Group_GROUP_GROUP_ACCESS ) { + ptsEntry.listStatus = PTS_GROUP_ACCESS; + } else { + ptsEntry.listStatus = PTS_GROUP_ANYUSER_ACCESS; + } + if( jlistGroupsOwned == org_openafs_jafs_Group_GROUP_OWNER_ACCESS ) { + ptsEntry.listGroupsOwned = PTS_GROUP_OWNER_ACCESS; + } else if( jlistGroupsOwned == + org_openafs_jafs_Group_GROUP_GROUP_ACCESS ) { + ptsEntry.listGroupsOwned = PTS_GROUP_ACCESS; + } else { + ptsEntry.listGroupsOwned = PTS_GROUP_ANYUSER_ACCESS; + } + if( jlistMembership == org_openafs_jafs_Group_GROUP_OWNER_ACCESS ) { + ptsEntry.listMembership = PTS_GROUP_OWNER_ACCESS; + } else if( jlistMembership == + org_openafs_jafs_Group_GROUP_GROUP_ACCESS ) { + ptsEntry.listMembership = PTS_GROUP_ACCESS; + } else { + ptsEntry.listMembership = PTS_GROUP_ANYUSER_ACCESS; + } + if( jlistAdd == org_openafs_jafs_Group_GROUP_OWNER_ACCESS ) { + ptsEntry.listAdd = PTS_GROUP_OWNER_ACCESS; + } else if( jlistAdd == org_openafs_jafs_Group_GROUP_GROUP_ACCESS ) { + ptsEntry.listAdd = PTS_GROUP_ACCESS; + } else { + ptsEntry.listAdd = PTS_GROUP_ANYUSER_ACCESS; + } + if( jlistDelete == org_openafs_jafs_Group_GROUP_OWNER_ACCESS ) { + ptsEntry.listDelete = PTS_GROUP_OWNER_ACCESS; + } else if( jlistDelete == org_openafs_jafs_Group_GROUP_GROUP_ACCESS ) { + ptsEntry.listDelete = PTS_GROUP_ACCESS; + } else { + ptsEntry.listDelete = PTS_GROUP_ANYUSER_ACCESS; + } + if( !pts_GroupModify( (void *) cellHandle, name, &ptsEntry, &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + +} + +/** + * Begin the process of getting the users that belong to the group. Returns + * an iteration ID to be used by subsequent calls to + * getGroupMembersNext and getGroupMembersDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * jname the name of the group for which to get the members + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Group_getGroupMembersBegin + (JNIEnv *env, jclass cls, jint cellHandle, jstring jname) +{ + const char *name; + afs_status_t ast; + void *iterationId; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + if( !pts_GroupMemberListBegin( (void *) cellHandle, name, &iterationId, + &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + + return (jint) iterationId; + +} + +/** + * Returns the next members that belongs to the group. Returns + * null if there are no more members. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next member + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Group_getGroupMembersNextString + (JNIEnv *env, jclass cls, jint iterationId) +{ + afs_status_t ast; + char *userName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + jstring juser; + + if( !userName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_GroupMemberListNext( (void *) iterationId, userName, &ast ) ) { + free( userName ); + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + juser = (*env)->NewStringUTF(env, userName); + free( userName ); + return juser; +} + +/** + * Fills the next user object belonging to that group. Returns 0 if there + * are no more users, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * iterationId the iteration ID of this iteration + * juserObject a User object to be populated with the values of the + * next user + * returns 0 if there are no more users, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Group_getGroupMembersNext + (JNIEnv *env, jclass cls, jint cellHandle, jint iterationId, + jobject juserObject) +{ + afs_status_t ast; + char *userName; + jstring juser; + + userName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !userName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_GroupMemberListNext( (void *) iterationId, userName, &ast ) ) { + free( userName ); + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + juser = (*env)->NewStringUTF(env, userName); + + if( userCls == 0 ) { + internal_getUserClass( env, juserObject ); + } + + (*env)->SetObjectField(env, juserObject, user_nameField, juser); + + getUserInfoChar( env, (void *) cellHandle, userName, juserObject ); + (*env)->SetBooleanField( env, juserObject, user_cachedInfoField, TRUE ); + + free( userName ); + return 1; + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_getGroupMembersDone + (JNIEnv *env, jclass cls, jint iterationId) +{ + afs_status_t ast; + + if( !pts_GroupMemberListDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Adds a user to the specified group. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * jgroupName the name of the group to which to add a member + * juserName the name of the user to add + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_addMember + (JNIEnv *env, jclass cls, jint cellHandle, jstring jgroupName, + jstring juserName ) +{ + afs_status_t ast; + const char *groupName; + const char *userName; + + if( jgroupName != NULL ) { + groupName = (*env)->GetStringUTFChars(env, jgroupName, 0); + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + groupName = NULL; + } + + if( juserName != NULL ) { + userName = (*env)->GetStringUTFChars(env, juserName, 0); + if( !userName ) { + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + userName = NULL; + } + + if( !pts_GroupMemberAdd( (void *) cellHandle, userName, groupName, &ast ) ) { + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + throwAFSException( env, ast ); + return; + } + + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } +} + +/** + * Removes a user from the specified group. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * jgroupName the name of the group from which to remove a + * member + * juserName the name of the user to remove + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_removeMember + (JNIEnv *env, jclass cls, jint cellHandle, jstring jgroupName, + jstring juserName) +{ + afs_status_t ast; + const char *groupName; + const char *userName; + + if( jgroupName != NULL ) { + groupName = (*env)->GetStringUTFChars(env, jgroupName, 0); + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + groupName = NULL; + } + + if( juserName != NULL ) { + userName = (*env)->GetStringUTFChars(env, juserName, 0); + if( !userName ) { + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + userName = NULL; + } + + if( !pts_GroupMemberRemove( (void *)cellHandle, userName, + groupName, &ast ) ) { + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + throwAFSException( env, ast ); + return; + } + + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } +} + +/** + * Change the owner of the specified group. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * jgroupName the name of the group of which to change the + * owner + * jownerName the name of the new owner + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_changeOwner + (JNIEnv *env, jclass cls, jint cellHandle, jstring jgroupName, + jstring jownerName ) +{ + afs_status_t ast; + const char *groupName; + const char *ownerName; + + if( jgroupName != NULL ) { + groupName = (*env)->GetStringUTFChars(env, jgroupName, 0); + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + groupName = NULL; + } + + if( jownerName != NULL ) { + ownerName = (*env)->GetStringUTFChars(env, jownerName, 0); + if( !ownerName ) { + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + ownerName = NULL; + } + + if( !pts_GroupOwnerChange( (void *)cellHandle, groupName, + ownerName, &ast ) ) { + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + if( ownerName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jownerName, ownerName); + } + throwAFSException( env, ast ); + return; + } + + if( groupName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupName, groupName); + } + if( ownerName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jownerName, ownerName); + } + +} + +/** + * Change the name of the specified group. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the group belongs + * joldGroupName the old name of the group + * jnewGroupName the new name for the group + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_rename + (JNIEnv *env, jclass cls, jint cellHandle, jstring jgroupOldName, + jstring jgroupNewName ) +{ + afs_status_t ast; + const char *groupOldName; + const char *groupNewName; + + if( jgroupOldName != NULL ) { + groupOldName = (*env)->GetStringUTFChars(env, jgroupOldName, 0); + if( !groupOldName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + groupOldName = NULL; + } + + if( jgroupNewName != NULL ) { + groupNewName = (*env)->GetStringUTFChars(env, jgroupNewName, 0); + if( !groupNewName ) { + if( groupOldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupOldName, groupOldName); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + groupNewName = NULL; + } + + if( !pts_GroupRename( (void *)cellHandle, groupOldName, + groupNewName, &ast ) ) { + if( groupOldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupOldName, groupOldName); + } + if( groupNewName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupNewName, groupNewName); + } + throwAFSException( env, ast ); + return; + } + + if( groupOldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupOldName, groupOldName); + } + if( groupNewName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jgroupNewName, groupNewName); + } +} + +// reclaim global memory used by this portion +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Group_reclaimGroupMemory (JNIEnv *env, jclass cls) +{ + if( groupCls ) { + (*env)->DeleteGlobalRef(env, groupCls); + groupCls = 0; + } +} + + + diff --git a/src/JAVA/libjafs/Internal.c b/src/JAVA/libjafs/Internal.c new file mode 100644 index 0000000..c43bcb4 --- /dev/null +++ b/src/JAVA/libjafs/Internal.c @@ -0,0 +1,909 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +extern int errno; + +#ifndef LIBJUAFS +// user class and fields // +jclass userCls = 0; +jfieldID user_ptsField = 0; +jfieldID user_kasField = 0; +jfieldID user_nameField = 0; +//jfieldID user_cellHandleField = 0; +jfieldID user_cachedInfoField = 0; +//pts fields +jfieldID user_nameUidField = 0; +jfieldID user_ownerUidField = 0; +jfieldID user_creatorUidField = 0; +jfieldID user_listStatusField = 0; +jfieldID user_listGroupsOwnedField = 0; +jfieldID user_listMembershipField = 0; +jfieldID user_groupCreationQuotaField = 0; +jfieldID user_groupMembershipCountField = 0; +jfieldID user_ownerField = 0; +jfieldID user_creatorField = 0; +// kas fields +jfieldID user_adminSettingField = 0; +jfieldID user_tgsSettingField = 0; +jfieldID user_encSettingField = 0; +jfieldID user_cpwSettingField = 0; +jfieldID user_rpwSettingField = 0; +jfieldID user_userExpirationField = 0; +jfieldID user_lastModTimeField = 0; +jfieldID user_lastModNameField = 0; +jfieldID user_lastChangePasswordTimeField = 0; +jfieldID user_maxTicketLifetimeField = 0; +jfieldID user_keyVersionField = 0; +jfieldID user_encryptionKeyField = 0; +jfieldID user_keyCheckSumField = 0; +jfieldID user_daysToPasswordExpireField = 0; +jfieldID user_failLoginCountField = 0; +jfieldID user_lockTimeField = 0; +jfieldID user_lockedUntilField = 0; + +// group class and fields // +jclass groupCls = 0; +jfieldID group_nameField = 0; +//jfieldID group_cellHandleField = 0; +jfieldID group_cachedInfoField = 0; +jfieldID group_nameUidField = 0; +jfieldID group_ownerUidField = 0; +jfieldID group_creatorUidField = 0; +jfieldID group_listStatusField = 0; +jfieldID group_listGroupsOwnedField = 0; +jfieldID group_listMembershipField = 0; +jfieldID group_listAddField = 0; +jfieldID group_listDeleteField = 0; +jfieldID group_membershipCountField = 0; +jfieldID group_ownerField = 0; +jfieldID group_creatorField = 0; + +// server class and fields // +jclass serverCls = 0; +jfieldID server_nameField = 0; +//jfieldID server_cellHandleField = 0; +jfieldID server_cachedInfoField = 0; +jfieldID server_databaseField = 0; +jfieldID server_fileServerField = 0; +jfieldID server_badDatabaseField = 0; +jfieldID server_badFileServerField = 0; +jfieldID server_IPAddressField = 0; + +// executable time class and fields // +jclass exectimeCls = 0; +jfieldID exectime_HourField = 0; +jfieldID exectime_MinField = 0; +jfieldID exectime_SecField = 0; +jfieldID exectime_DayField = 0; +jfieldID exectime_NowField = 0; +jfieldID exectime_NeverField = 0; + +// partition class and fields // +jclass partitionCls = 0; +jfieldID partition_nameField = 0; +jfieldID partition_cachedInfoField = 0; +jfieldID partition_idField = 0; +jfieldID partition_deviceNameField = 0; +jfieldID partition_lockFileDescriptorField = 0; +jfieldID partition_totalSpaceField = 0; +jfieldID partition_totalFreeSpaceField = 0; + +// volume class and fields // +jclass volumeCls = 0; +jfieldID volume_nameField = 0; +jfieldID volume_cachedInfoField = 0; +jfieldID volume_idField = 0; +jfieldID volume_readWriteIdField = 0; +jfieldID volume_readOnlyIdField = 0; +jfieldID volume_backupIdField = 0; +jfieldID volume_creationDateField = 0; +jfieldID volume_lastAccessDateField = 0; +jfieldID volume_lastUpdateDateField = 0; +jfieldID volume_lastBackupDateField = 0; +jfieldID volume_copyCreationDateField = 0; +jfieldID volume_accessesSinceMidnightField = 0; +jfieldID volume_fileCountField = 0; +jfieldID volume_maxQuotaField = 0; +jfieldID volume_currentSizeField = 0; +jfieldID volume_statusField = 0; +jfieldID volume_dispositionField = 0; +jfieldID volume_typeField = 0; + +// key class and fields // +jclass keyCls = 0; +jfieldID key_cachedInfoField = 0; +jfieldID key_versionField = 0; +jfieldID key_encryptionKeyField = 0; +jfieldID key_lastModDateField = 0; +jfieldID key_lastModMsField = 0; +jfieldID key_checkSumField = 0; + +// process class and fields // +jclass processCls = 0; +jfieldID process_cachedInfoField = 0; +jfieldID process_nameField = 0; +//jfieldID process_serverHandleField = 0; +jfieldID process_typeField = 0; +jfieldID process_stateField = 0; +jfieldID process_goalField = 0; +jfieldID process_startTimeField = 0; +jfieldID process_numberStartsField = 0; +jfieldID process_exitTimeField = 0; +jfieldID process_exitErrorTimeField = 0; +jfieldID process_errorCodeField = 0; +jfieldID process_errorSignalField = 0; +jfieldID process_stateOkField = 0; +jfieldID process_stateTooManyErrorsField = 0; +jfieldID process_stateBadFileAccessField = 0; +#endif /* !LIBJUAFS */ + +/** + * Throws an exception up to the Java layer, using ast as the error code + * for the exception. See Exceptions.h for the available + * exceptions. + */ +void throwException + (JNIEnv *env, jclass *excCls, char *excClsName, jmethodID *initID, int code) +{ + jobject exc; + if( *excCls == 0 ) { + *excCls = (*env)->NewGlobalRef(env, (*env)->FindClass(env, excClsName )); + if( !*excCls ) { + fprintf(stderr, "ERROR: Internal::throwException()\n + Cannot find class: %s\n", excClsName); + return; + } + *initID = (*env)->GetMethodID( env, *excCls, "", "(I)V" ); + if( !*initID ) { + fprintf(stderr, "ERROR: Internal::throwException()\n + Cannot find construction method: %s\n", + excClsName); + return; + } + } + + exc = (*env)->NewObject( env, *excCls, *initID, code ); + if( !exc ) { + fprintf(stderr, "ERROR: Internal::throwException()\n + Cannot construct new exception object: %s\n", + excClsName); + return; + } + (*env)->Throw(env, exc); +} + +/** + * Throws an exception up to the Java layer, constructing it with msg. + * This function should only be used when a valid AFS error number/code + * is unavailable and it is necessary to interrupt the Java call with an + * exception. See Exceptions.h for the available exceptions. + */ +void throwMessageException( JNIEnv *env, char *msg ) +{ + jclass excCls = (*env)->FindClass(env, afsExceptionName); + if(excCls == 0) { + fprintf(stderr, "ERROR: Internal::throwMessageException()\n + Cannot find class: %s\n", afsExceptionName); + return; + } + (*env)->ThrowNew(env, excCls, msg); +} + +/** + * Throws an exception up to the Java layer, using ast as the error code + * for the exception. See Exceptions.h for the available + * exceptions. + */ +void throwAFSException( JNIEnv *env, int code ) +{ + jclass afsExceptionCls; + jmethodID afsExceptionInit; + jthrowable exc; + + afsExceptionCls = (*env)->FindClass(env, afsExceptionName); + if( !afsExceptionCls ) { + fprintf(stderr, "ERROR: Internal::throwAFSException()\n + Cannot find class: %s\n", afsExceptionName); + return; + } + + afsExceptionInit = (*env)->GetMethodID( env, afsExceptionCls, + "", "(I)V" ); + if( !afsExceptionInit ) { + fprintf(stderr, "ERROR: Internal::throwAFSException()\n + Cannot find construction method: %s\n", + afsExceptionName); + return; + } + + exc = (*env)->NewObject( env, afsExceptionCls, afsExceptionInit, code ); + + if( !exc ) { + fprintf(stderr, "ERROR: Internal::throwAFSException()\n + Cannot construct new exception object: %s\n", + afsExceptionName); + return; + } + (*env)->Throw(env, exc); +} + +/** + * Throws an exception up to the Java layer, using ast as the error code + * for the exception. See Exceptions.h for the available + * exceptions. + */ +void throwAFSFileException( JNIEnv *env, int code, char *msg ) +{ + jclass afsFileExceptionCls; + jmethodID afsFileExceptionInit; + jthrowable exc; + + afsFileExceptionCls = (*env)->FindClass(env, afsFileExceptionName); + if( !afsFileExceptionCls ) { + fprintf(stderr, "ERROR: Internal::throwAFSFileException()\n + Cannot find class: %s\n", afsFileExceptionName); + return; + } + + afsFileExceptionInit = (*env)->GetMethodID( env, afsFileExceptionCls, + "", "(Ljava/lang/String;I)V" ); + if( !afsFileExceptionInit ) { + fprintf(stderr, "ERROR: Internal::throwAFSFileException()\n + Cannot find construction method: %s\n", + afsFileExceptionName); + return; + } + + exc = (*env)->NewObject( env, afsFileExceptionCls, + afsFileExceptionInit, msg, code ); + if( !exc ) { + fprintf(stderr, "ERROR: Internal::throwAFSFileException()\n + Cannot construct new exception object: %s\n", + afsFileExceptionName); + return; + } + (*env)->Throw(env, exc); +} + +/** + * Throws an exception up to the Java layer, using ast as the error code + * for the exception. See Exceptions.h for the available + * exceptions. + */ +void throwAFSSecurityException( JNIEnv *env, int code ) +{ + jclass afsSecurityExceptionCls; + jmethodID afsSecurityExceptionInit; + jthrowable exc; + + afsSecurityExceptionCls = (*env)->FindClass(env, afsSecurityExceptionName); + if( !afsSecurityExceptionCls ) { + fprintf(stderr, "ERROR: Internal::throwAFSSecurityException()\n + Cannot find class: %s\n", afsSecurityExceptionName); + return; + } + + afsSecurityExceptionInit = (*env)->GetMethodID( env, afsSecurityExceptionCls, + "", "(I)V" ); + if( !afsSecurityExceptionInit ) { + fprintf(stderr, "ERROR: Internal::throwAFSSecurityException()\n + Cannot find construction method: %s\n", + afsSecurityExceptionName); + return; + } + + exc = (*env)->NewObject( env, afsSecurityExceptionCls, + afsSecurityExceptionInit, code ); + if( !exc ) { + fprintf(stderr, "ERROR: Internal::throwAFSSecurityException()\n + Cannot construct new exception object: %s\n", + afsSecurityExceptionName); + return; + } + (*env)->Throw(env, exc); +} + +int setError(JNIEnv *env, jobject *obj, int code) +{ + jfieldID fid; + jclass cls = (*env)->GetObjectClass(env, *obj); + if (cls != NULL) { + fid = (*env)->GetFieldID(env, cls, "errno", "I"); + if (fid) + { + (*env)->SetIntField(env, *obj, fid, code); + return 0; + } + } + return -1; +} + +#ifdef LIBJUAFS + +/** + * Opens an AFS file, with the specified name, using the specified flags + * with in the specified mode (permission mode). + * + * env the Java environment + * fileNameUTF name of file to be opened + * flags open mode: O_CREAT, O_APPEND + * mode UNIX permission mode mask + * err error variable + * + * @returns file descriptor + */ +int openAFSFile + (JNIEnv *env, jstring fileNameUTF, int flags, int mode, int *err) +{ + char *fileName; + int fd = -1; + + *err = 0; + errno = 0; + fileName=(char*) (*env)->GetStringUTFChars(env, fileNameUTF, 0); + if(fileName == NULL) { + fprintf(stderr, "Internal::openAFSFile(): failed to get fileName\n"); + *err = -1; + return fd; + } + fd = uafs_open(fileName, flags, mode); + *err = errno; + if (errno != 0) { + fprintf(stderr, "Internal::openAFSFile(): errno=%d\n", errno); + fprintf(stderr, "Internal::openAFSFile(): fd=%d\n", fd); + } + (*env)->ReleaseStringUTFChars(env, fileNameUTF, fileName); + if (fd < 0) { + fprintf(stderr, "Internal::openAFSFile(): failed to open fileName\n"); + fprintf(stderr, "Internal::openAFSFile(): fd=%d\n", fd); + return -1; + } + return fd; +} + +int readCacheParms(char *afsMountPoint, char *afsConfDir, char *afsCacheDir, + int *cacheBlocks, int *cacheFiles, int *cacheStatEntries, + int *dCacheSize, int *vCacheSize, int *chunkSize, + int *closeSynch, int *debug, int *nDaemons, int *cacheFlags, + char *logFile) +{ + FILE *f; + char line[100]; + char *p; + int len1, len2, n; + char cacheConfigFile[100]; + + p = (char *)getenv("LIBJAFS_CACHE_CONFIG"); + if (p) { + strcpy(cacheConfigFile, p); + } else { + strcpy(cacheConfigFile, "/usr/afswsp/etc/CacheConfig"); + } + + f = fopen(cacheConfigFile, "r"); + if (!f) { + fprintf(stderr, "Could not open cache config file: %s\n", + cacheConfigFile); + return -1; + } + + while (1) { + fgets(line, 100, f); + if (feof(f)) break; + p = (char *)strchr(line, '\n'); + if (p) *p = '\0'; + if (strncmp(line, "#", 1) == 0) continue; /* comment */ + + p = (char *)strchr(line, ' '); + if (!p) continue; + len1 = p - line; + p++; len2 = strlen(p); + + if (strncmp(line, "MountPoint", len1) == 0) + strcpy(afsMountPoint, p); + else if (strncmp(line, "ConfDir", len1) == 0) + strcpy(afsConfDir, p); + else if (strncmp(line, "CacheDir", len1) == 0) + strcpy(afsCacheDir, p); + else if (strncmp(line, "CacheBlocks", len1) == 0) + *cacheBlocks = atoi(p); + else if (strncmp(line, "CacheFiles", len1) == 0) + *cacheFiles = atoi(p); + else if (strncmp(line, "CacheStatEntries", len1) == 0) + *cacheStatEntries = atoi(p); + else if (strncmp(line, "DCacheSize", len1) == 0) + *dCacheSize = atoi(p); + else if (strncmp(line, "VCacheSize", len1) == 0) + *vCacheSize = atoi(p); + else if (strncmp(line, "ChunkSize", len1) == 0) + *chunkSize = atoi(p); + else if (strncmp(line, "CloseSynch", len1) == 0) + *closeSynch = atoi(p); + else if (strncmp(line, "Debug", len1) == 0) + *debug = atoi(p); + else if (strncmp(line, "NDaemons", len1) == 0) + *nDaemons = atoi(p); + else if (strncmp(line, "CacheFlags", len1) == 0) + *cacheFlags = atoi(p); + else if (strncmp(line, "LogFile", len1) == 0) + strcpy(logFile, p); + } + return 0; +} + +int setString(JNIEnv *env, jobject *obj, char *field, char *string) +{ + jclass cls; + jstring jstr; + jfieldID fid; + + cls = (*env)->GetObjectClass(env, *obj); + /*fprintf(stderr, "setString: env=0x%x, obj=0x%x, cls=0x%x\n", env, obj, cls);*/ + if (cls != NULL) { + fid = (*env)->GetFieldID(env, cls, field, "Ljava/lang/String;"); + /*fprintf(stderr, "setString: field=%s, fid=0x%x\n", field, fid);*/ + if (fid) { + jstr = (*env)->NewStringUTF(env, (string)); + /*fprintf(stderr, "jstr = 0x%x\n", jstr);*/ + (*env)->SetObjectField(env, *obj, fid, jstr); + return 0; + } + } + return -1; +} + +#else + +/** + * Makes a kas identity given the full name of a kas user. If the + * name contains a period, everything after the first period is + * considered to be the instance of that name, otherwise + * the instance is the empty string. The memory for who + * that's passed in should be fully allocated in advance. + */ +void internal_makeKasIdentity( const char *fullName, + kas_identity_p who ) { + + char *period; + + if( (period = (char *) strchr( fullName, '.' )) != NULL ) { + strncpy( who->principal, fullName, period - fullName ); + who->principal[period - fullName] = '\0'; + strncpy( who->instance, period + 1, + strlen(fullName) - (period - fullName) ); + } else { + strcpy( who->principal, fullName); + strcpy( who->instance, "" ); + } + +} + +/** + * Given a Java environment and an instance of a user, gets the object and + * field information for the user object from the Java environment. + */ +void internal_getUserClass( JNIEnv *env, jobject user ) { + if( userCls == 0 ) { + userCls = (*env)->NewGlobalRef( env, (*env)->GetObjectClass(env, user) ); + if( !userCls ) { + throwAFSException( env, JAFSADMCLASSNOTFOUND ); + return; + } + user_ptsField = (*env)->GetFieldID( env, userCls, "pts", "Z" ); + user_kasField = (*env)->GetFieldID( env, userCls, "kas", "Z" ); + user_nameField = (*env)->GetFieldID( env, userCls, "name", + "Ljava/lang/String;" ); + user_cachedInfoField = (*env)->GetFieldID( env, userCls, "cachedInfo", + "Z" ); + // pts fields + user_nameUidField = (*env)->GetFieldID( env, userCls, "nameUID", "I" ); + user_ownerUidField = (*env)->GetFieldID( env, userCls, "ownerUID", "I" ); + user_creatorUidField = (*env)->GetFieldID( env, userCls, "creatorUID", + "I" ); + user_listStatusField = (*env)->GetFieldID( env, userCls, "listStatus", + "I" ); + user_listGroupsOwnedField = (*env)->GetFieldID( env, userCls, + "listGroupsOwned", "I" ); + user_listMembershipField = (*env)->GetFieldID( env, userCls, + "listMembership", "I" ); + user_groupCreationQuotaField = (*env)->GetFieldID( env, userCls, + "groupCreationQuota", + "I" ); + user_groupMembershipCountField = (*env)->GetFieldID( env, userCls, + "groupMembershipCount", + "I" ); + user_ownerField = (*env)->GetFieldID( env, userCls, "owner", + "Ljava/lang/String;" ); + user_creatorField = (*env)->GetFieldID( env, userCls, "creator", + "Ljava/lang/String;" ); + // kas fields + user_adminSettingField = (*env)->GetFieldID( env, userCls, "adminSetting", + "I" ); + user_tgsSettingField = (*env)->GetFieldID( env, userCls, "tgsSetting", + "I" ); + user_encSettingField = (*env)->GetFieldID( env, userCls, "encSetting", + "I" ); + user_cpwSettingField = (*env)->GetFieldID( env, userCls, "cpwSetting", + "I" ); + user_rpwSettingField = (*env)->GetFieldID( env, userCls, "rpwSetting", + "I" ); + user_userExpirationField = (*env)->GetFieldID( env, userCls, + "userExpiration", "I" ); + user_lastModTimeField = (*env)->GetFieldID( env, userCls, "lastModTime", + "I" ); + user_lastModNameField = (*env)->GetFieldID( env, userCls, "lastModName", + "Ljava/lang/String;" ); + user_lastChangePasswordTimeField = (*env)->GetFieldID( env, userCls, + "lastChangePasswordTime", + "I" ); + user_maxTicketLifetimeField = (*env)->GetFieldID( env, userCls, + "maxTicketLifetime", + "I" ); + user_keyVersionField = (*env)->GetFieldID( env, userCls, "keyVersion", + "I" ); + user_encryptionKeyField = (*env)->GetFieldID( env, userCls, + "encryptionKey", + "Ljava/lang/String;" ); + user_keyCheckSumField = (*env)->GetFieldID( env, userCls, "keyCheckSum", + "J" ); + user_daysToPasswordExpireField = (*env)->GetFieldID( env, userCls, + "daysToPasswordExpire", + "I" ); + user_failLoginCountField = (*env)->GetFieldID( env, userCls, + "failLoginCount", "I" ); + user_lockTimeField = (*env)->GetFieldID( env, userCls, "lockTime", "I" ); + user_lockedUntilField = (*env)->GetFieldID( env, userCls, "lockedUntil", + "I" ); + if( !user_ptsField || !user_kasField || !user_nameField || + !user_cachedInfoField || !user_nameUidField || !user_ownerUidField || + !user_creatorUidField || !user_listStatusField || + !user_listGroupsOwnedField || !user_listMembershipField || + !user_groupCreationQuotaField || !user_groupMembershipCountField || + !user_ownerField || !user_creatorField || !user_adminSettingField || + !user_tgsSettingField || !user_encSettingField || + !user_cpwSettingField || !user_rpwSettingField || + !user_userExpirationField || !user_lastModTimeField || + !user_lastModNameField || !user_lastChangePasswordTimeField || + !user_maxTicketLifetimeField || !user_keyVersionField || + !user_encryptionKeyField || !user_keyCheckSumField || + !user_daysToPasswordExpireField || !user_failLoginCountField || + !user_lockTimeField || !user_lockedUntilField ) { + + throwAFSException( env, JAFSADMFIELDNOTFOUND ); + return; + + } + } +} + +/** + * Given a Java environment and an instance of a group, gets the object and + * field information for the group object from the Java environment. + */ +void internal_getGroupClass( JNIEnv *env, jobject group ) { + if( groupCls == 0 ) { + groupCls = (*env)->NewGlobalRef( env, (*env)->GetObjectClass(env, group) ); + if( !groupCls ) { + throwAFSException( env, JAFSADMCLASSNOTFOUND ); + return; + } + group_nameField = (*env)->GetFieldID( env, groupCls, "name", + "Ljava/lang/String;" ); + group_cachedInfoField = (*env)->GetFieldID( env, groupCls, "cachedInfo", + "Z" ); + group_nameUidField = (*env)->GetFieldID( env, groupCls, "nameUID", "I" ); + group_ownerUidField = (*env)->GetFieldID( env, groupCls, "ownerUID", "I" ); + group_creatorUidField = (*env)->GetFieldID( env, groupCls, "creatorUID", + "I" ); + group_listStatusField = (*env)->GetFieldID( env, groupCls, "listStatus", + "I" ); + group_listGroupsOwnedField = (*env)->GetFieldID( env, groupCls, + "listGroupsOwned", "I" ); + group_listMembershipField = (*env)->GetFieldID( env, groupCls, + "listMembership", "I" ); + group_listAddField = (*env)->GetFieldID( env, groupCls, "listAdd", "I" ); + group_listDeleteField = (*env)->GetFieldID( env, groupCls, "listDelete", + "I" ); + group_membershipCountField = (*env)->GetFieldID( env, groupCls, + "membershipCount", "I" ); + group_ownerField = (*env)->GetFieldID( env, groupCls, "owner", + "Ljava/lang/String;" ); + group_creatorField = (*env)->GetFieldID( env, groupCls, "creator", + "Ljava/lang/String;" ); + if( !group_nameField || !group_cachedInfoField || !group_nameUidField || + !group_ownerUidField || !group_creatorUidField || + !group_listStatusField || !group_listGroupsOwnedField || + !group_listMembershipField || !group_listAddField || + !group_listDeleteField || !group_membershipCountField || + !group_ownerField || !group_creatorField ) { + + throwAFSException( env, JAFSADMFIELDNOTFOUND ); + return; + + } + } +} + +/** + * Given a Java environment and an instance of a server, gets the object and + * field information for the server object from the Java environment. + */ +void internal_getServerClass( JNIEnv *env, jobject server ) { + if( serverCls == 0 ) { + serverCls = (*env)->NewGlobalRef( env, + (*env)->GetObjectClass(env, server) ); + if( !serverCls ) { + throwAFSException( env, JAFSADMCLASSNOTFOUND ); + return; + } + server_nameField = (*env)->GetFieldID( env, serverCls, "name", + "Ljava/lang/String;" ); + server_cachedInfoField = (*env)->GetFieldID( env, serverCls, "cachedInfo", + "Z" ); + server_databaseField = (*env)->GetFieldID( env, serverCls, "database", + "Z" ); + server_fileServerField = (*env)->GetFieldID( env, serverCls, "fileServer", + "Z" ); + server_badDatabaseField = (*env)->GetFieldID( env, serverCls, + "badDatabase", "Z" ); + server_badFileServerField = (*env)->GetFieldID( env, serverCls, + "badFileServer", "Z" ); + server_IPAddressField = (*env)->GetFieldID( env, serverCls, "ipAddresses", + "[Ljava/lang/String;" ); + if( !server_nameField || !server_cachedInfoField || !server_databaseField + || !server_fileServerField || !server_badDatabaseField || + !server_badFileServerField || !server_IPAddressField ) { + + throwAFSException( env, JAFSADMFIELDNOTFOUND ); + return; + + } + } +} + +/** + * Given a Java environment and an instance of an executableTime, gets the + * object and field information for the executableTime object from the + * Java environment. + */ +void internal_getExecTimeClass( JNIEnv *env, jobject exectime ) { + if( exectimeCls == 0 ) { + exectimeCls = (*env)->NewGlobalRef( env, + (*env)->GetObjectClass(env, exectime) ); + if( !exectimeCls ) { + throwAFSException( env, JAFSADMCLASSNOTFOUND ); + return; + } + exectime_HourField = (*env)->GetFieldID( env, exectimeCls, "hour", "S" ); + exectime_MinField = (*env)->GetFieldID( env, exectimeCls, "minute", + "S" ); + exectime_SecField = (*env)->GetFieldID( env, exectimeCls, "second", + "S" ); + exectime_DayField = (*env)->GetFieldID( env, exectimeCls, "day", "S" ); + exectime_NowField = (*env)->GetFieldID( env, exectimeCls, "now", "Z" ); + exectime_NeverField = (*env)->GetFieldID( env, exectimeCls, "never", "Z" ); + if( !exectime_HourField || !exectime_MinField || !exectime_SecField || + !exectime_DayField || !exectime_NowField || !exectime_NeverField ) { + + throwAFSException( env, JAFSADMFIELDNOTFOUND ); + return; + + } + } +} + +/** + * Given a Java environment and an instance of a partition, gets the object and + * field information for the partition object from the Java environment. + */ +void internal_getPartitionClass( JNIEnv *env, jobject partition ) { + if( partitionCls == 0 ) { + partitionCls = (*env)->NewGlobalRef( env, + (*env)->GetObjectClass(env, partition) ); + if( !partitionCls ) { + throwAFSException( env, JAFSADMCLASSNOTFOUND ); + return; + } + partition_nameField = (*env)->GetFieldID( env, partitionCls, "name", + "Ljava/lang/String;" ); + partition_deviceNameField = (*env)->GetFieldID( env, partitionCls, + "deviceName", + "Ljava/lang/String;" ); + partition_idField = (*env)->GetFieldID( env, partitionCls, "id", "I" ); + partition_cachedInfoField = (*env)->GetFieldID( env, partitionCls, + "cachedInfo", "Z" ); + partition_lockFileDescriptorField = (*env)->GetFieldID( env, partitionCls, + "lockFileDescriptor", + "I" ); + partition_totalSpaceField = (*env)->GetFieldID( env, partitionCls, + "totalSpace", "I" ); + partition_totalFreeSpaceField = (*env)->GetFieldID( env, partitionCls, + "totalFreeSpace", "I"); + if( !partition_nameField || !partition_cachedInfoField || + !partition_idField || !partition_deviceNameField || + !partition_lockFileDescriptorField || !partition_totalSpaceField || + !partition_totalFreeSpaceField ) { + + throwAFSException( env, JAFSADMFIELDNOTFOUND ); + return; + + } + } +} + +/** + * Given a Java environment and an instance of a volume, gets the object and + * field information for the volume object from the Java environment. + */ +void internal_getVolumeClass( JNIEnv *env, jobject volume ) { + if( volumeCls == 0 ) { + volumeCls = (*env)->NewGlobalRef( env, + (*env)->GetObjectClass(env, volume) ); + if( !volumeCls ) { + throwAFSException( env, JAFSADMCLASSNOTFOUND ); + return; + } + volume_nameField = (*env)->GetFieldID( env, volumeCls, "name", + "Ljava/lang/String;" ); + volume_cachedInfoField = (*env)->GetFieldID( env, volumeCls, "cachedInfo", + "Z" ); + volume_idField = (*env)->GetFieldID( env, volumeCls, "id", "I" ); + volume_readWriteIdField = (*env)->GetFieldID( env, volumeCls, + "readWriteID", "I" ); + volume_readOnlyIdField = (*env)->GetFieldID( env, volumeCls, "readOnlyID", + "I" ); + volume_backupIdField = (*env)->GetFieldID( env, volumeCls, "backupID", + "I" ); + volume_creationDateField = (*env)->GetFieldID( env, volumeCls, + "creationDate", "J" ); + volume_lastAccessDateField = (*env)->GetFieldID( env, volumeCls, + "lastAccessDate", "J" ); + volume_lastUpdateDateField = (*env)->GetFieldID( env, volumeCls, + "lastUpdateDate", "J" ); + volume_lastBackupDateField = (*env)->GetFieldID( env, volumeCls, + "lastBackupDate", "J" ); + volume_copyCreationDateField = (*env)->GetFieldID( env, volumeCls, + "copyCreationDate", + "J" ); + volume_accessesSinceMidnightField = (*env)->GetFieldID( env, volumeCls, + "accessesSinceMidnight", + "I" ); + volume_fileCountField = (*env)->GetFieldID( env, volumeCls, "fileCount", + "I" ); + volume_maxQuotaField = (*env)->GetFieldID( env, volumeCls, "maxQuota", + "I" ); + volume_currentSizeField = (*env)->GetFieldID( env, volumeCls, + "currentSize", "I" ); + volume_statusField = (*env)->GetFieldID( env, volumeCls, "status", "I" ); + volume_dispositionField = (*env)->GetFieldID( env, volumeCls, + "disposition", "I" ); + volume_typeField = (*env)->GetFieldID( env, volumeCls, "type", "I" ); + if( !volume_nameField || !volume_cachedInfoField || !volume_idField || + !volume_readWriteIdField || !volume_readOnlyIdField || + !volume_backupIdField || !volume_creationDateField || + !volume_lastAccessDateField || !volume_lastUpdateDateField || + !volume_lastBackupDateField || !volume_copyCreationDateField || + !volume_accessesSinceMidnightField || !volume_fileCountField || + !volume_maxQuotaField || !volume_currentSizeField || + !volume_statusField || !volume_dispositionField || + !volume_typeField ) { + + throwAFSException( env, JAFSADMFIELDNOTFOUND ); + return; + + } + } +} + +/** + * Given a Java environment and an instance of a key, gets the object and + * field information for the key object from the Java environment. + */ +void internal_getKeyClass( JNIEnv *env, jobject key ) { + if( keyCls == 0 ) { + keyCls = (*env)->NewGlobalRef( env, (*env)->GetObjectClass(env, key) ); + if( !keyCls ) { + throwAFSException( env, JAFSADMCLASSNOTFOUND ); + return; + } + key_encryptionKeyField = (*env)->GetFieldID( env, keyCls, + "encryptionKey", + "Ljava/lang/String;" ); + key_cachedInfoField = (*env)->GetFieldID( env, keyCls, "cachedInfo", "Z" ); + key_versionField = (*env)->GetFieldID( env, keyCls, "version", "I" ); + key_lastModDateField = (*env)->GetFieldID( env, keyCls, "lastModDate", + "I" ); + key_lastModMsField = (*env)->GetFieldID( env, keyCls, "lastModMs", "I" ); + key_checkSumField = (*env)->GetFieldID( env, keyCls, "checkSum", "J" ); + if( !key_cachedInfoField || !key_versionField || !key_encryptionKeyField + || !key_lastModDateField || !key_lastModMsField || + !key_checkSumField ) { + + throwAFSException( env, JAFSADMFIELDNOTFOUND ); + return; + + } + } +} + +/** + * Given a Java environment and an instance of a process, gets the object and + * field information for the process object from the Java environment. + */ +void internal_getProcessClass( JNIEnv *env, jobject process ) { + if( processCls == 0 ) { + processCls = (*env)->NewGlobalRef( env, + (*env)->GetObjectClass(env, process) ); + if( !processCls ) { + throwAFSException( env, JAFSADMCLASSNOTFOUND ); + return; + } + process_cachedInfoField = (*env)->GetFieldID( env, processCls, + "cachedInfo", "Z" ); + process_nameField = (*env)->GetFieldID( env, processCls, "name", + "Ljava/lang/String;" ); + process_typeField = (*env)->GetFieldID( env, processCls, "type", "I" ); + process_stateField = (*env)->GetFieldID( env, processCls, "state", "I" ); + process_goalField = (*env)->GetFieldID( env, processCls, "goal", "I" ); + process_startTimeField = (*env)->GetFieldID( env, processCls, "startTime", + "J" ); + process_numberStartsField = (*env)->GetFieldID( env, processCls, + "numberStarts", "J" ); + process_exitTimeField = (*env)->GetFieldID( env, processCls, "exitTime", + "J" ); + process_exitErrorTimeField = (*env)->GetFieldID( env, processCls, + "exitErrorTime", "J" ); + process_errorCodeField = (*env)->GetFieldID( env, processCls, "errorCode", + "J" ); + process_errorSignalField = (*env)->GetFieldID( env, processCls, + "errorSignal", "J" ); + process_stateOkField = (*env)->GetFieldID( env, processCls, "stateOk", + "Z" ); + process_stateTooManyErrorsField = (*env)->GetFieldID( env, processCls, + "stateTooManyErrors", + "Z" ); + process_stateBadFileAccessField = (*env)->GetFieldID( env, processCls, + "stateBadFileAccess", + "Z" ); + if( !process_cachedInfoField || !process_nameField || !process_typeField + || !process_stateField || !process_goalField || + !process_startTimeField || !process_numberStartsField || + !process_exitTimeField || !process_exitErrorTimeField || + !process_errorCodeField || !process_errorSignalField || + !process_stateOkField || !process_stateTooManyErrorsField || + !process_stateBadFileAccessField ) { + + throwAFSException( env, JAFSADMFIELDNOTFOUND ); + return; + + } + } +} + +#endif /* LIBJUAFS */ + + diff --git a/src/JAVA/libjafs/Internal.h b/src/JAVA/libjafs/Internal.h new file mode 100644 index 0000000..29d9129 --- /dev/null +++ b/src/JAVA/libjafs/Internal.h @@ -0,0 +1,63 @@ +#ifndef _Jafsadm_Internal +#define _Jafsadm_Internal + +#include +#include "Exceptions.h" + +#ifndef LIBJUAFS +#include +#include + +// error codes +#define JAFSADMNOMEM 1050 // Memory problems +#define JAFSADMCLASSNOTFOUND 1051 // Trouble finding a Java class +#define JAFSADMMETHODNOTFOUND 1052 // Trouble finding a Java method +#define JAFSADMFIELDNOTFOUND 1053 // Trouble finding a Java field + +// make an identity out of a full name (possibly including an instance ) +void internal_makeKasIdentity( const char *fullName, kas_identity_p who ); + +void internal_getUserClass( JNIEnv *env, jobject user ); +void internal_getGroupClass( JNIEnv *env, jobject group ); +void internal_getServerClass( JNIEnv *env, jobject server ); +void internal_getPartitionClass( JNIEnv *env, jobject partition ); +void internal_getVolumeClass( JNIEnv *env, jobject volume ); +void internal_getKeyClass( JNIEnv *env, jobject key ); +void internal_getProcessClass( JNIEnv *env, jobject process ); +#else +int openAFSFile(JNIEnv *env, jstring fileNameUTF, int flags, int mode, int *err); +int readCacheParms(char *afsMountPoint, char *afsConfDir, char *afsCacheDir, + int *cacheBlocks, int *cacheFiles, int *cacheStatEntries, + int *dCacheSize, int *vCacheSize, int *chunkSize, + int *closeSynch, int *debug, int *nDaemons, int *cacheFlags, + char *logFile); +#endif /* !LIBJUAFS */ + +// throw a non-AFS exception with a message +void throwMessageException( JNIEnv *env, char *msg ); + +// throw an AFS exception with a message +void throwAFSException( JNIEnv *env, int code ); + +// throw an AFS Admin exception with a message +void throwAFSException( JNIEnv *env, int code ); + +// throw an AFS File or I/O related exception with a message +void throwFileAdminException( JNIEnv *env, int code, char *msg ); + +// throw an AFS Security exception with a message +void throwAFSSecurityException( JNIEnv *env, int code ); + +// throw an exception with an error code +void throwException( JNIEnv *env, jclass *excCls, char *excClsName, jmethodID *initID, int code ); + +// reclaim global memory used by exceptions +void reclaimExceptionMemory( JNIEnv *env, jclass cls ); + +int setError(JNIEnv *env, jobject *obj, int code); +int setString(JNIEnv *env, jobject *obj, char *field, char *string); + +#endif + + + diff --git a/src/JAVA/libjafs/JAFS_README b/src/JAVA/libjafs/JAFS_README new file mode 100644 index 0000000..3939201 --- /dev/null +++ b/src/JAVA/libjafs/JAFS_README @@ -0,0 +1,123 @@ +Java API for OpenAFS (Jafs) README +Current as of 6/5/02 + + ########################################################################## + # Copyright (c) 2001-2002 International Business Machines Corp. # + # All rights reserved. # + # # + # This software has been released under the terms of the IBM Public # + # License. For details, see the LICENSE file in the top-level source # + # directory or online at http://www.openafs.org/dl/license10.html # + # # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # + # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # + # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # + # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR # + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # + # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # + # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # + # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # + ########################################################################## + +*** INTRODUCTION *** + +Jafs is an open source API designed to allow Java programmers the ability +to create applications for the administration or use of OpenAFS file systems. +It works by accessing libadmin and libuafs (administrative and user-level +libraries that come with OpenAFS) through JNI. It consists of a Java package +called org.openafs.jafs, and a shared libraries libjafsadm.so and libjafs.so. + +*** USE *** + +There is a version of Jafs that has been compiled on Red Hat Linux 7.1, +and can be directly used without compilation. It was compiled using +OpenAFS 1.2.4 libraries (with a modified version of libjuafs.a). It +consists of a JAR file (jafs.jar) and two shared libraries +(libjafsadm.so and libjafs.so). It was compiled using the +--enable-transarc-paths on compilation (for use with the OpenAFS RPMs), +gcc 2.96, and Java Classic VM version 1.4.0. + +When you write Java code to use this API, import the +org.openafs.jafs package. During compilation of your Java code, +ensure one of the following conditions are met: + - Use the "-classpath" option to javac to specify the jafs.jar file. + - Change your $CLASSPATH environment variable to include the + jafs.jar file (e.g. export CLASSPATH=$CLASSPATH:jafs.jar + +When running an application that uses Jafs, the shared libraries +need to be found by Java's library loader. The easiest way to +accomplish this is to copy these files into the /usr/lib/ directory, +or create symbolic links from that directory to the files. Alternatively, +the directory containing the libraries can also be added to the +LD_LIBRARY_PATH environment variable, instead. + +You also need to have an OpenAFS client set up on your machine +(preferably version 1.2.4, but it should work for some past versions as well). +You can obtain the OpenAFS client and view installation documentation at +http://www.openafs.org (the RPMs are easiest to use for Linux). Also any +cells you plan to access through the API must have entries in your +client's CellServDB file (located in the /usr/vice/etc/ directory in most +setups). + +This API is most effective when used with a cell that uses the kaserver +for authentication. It does not currently support alternative methods of +authentication such as Kerberos V. + +If you have successfully set up your Linux 7.1 environment as described +above, you will be able to develop and execute applications that use +the Jafs API. + +*** BUILD *** + +The first step in compiling your own versions of the library and jar file +is to download the OpenAFS source code. If the code doesn't contain the +libjuafs version of the libuafs library -- noted by the README file located +in the src/libuafs directory (if a README file doesn't exist in this directory +then the libjuafs patch (libuafs.diff) has not been applied) -- you must +first apply the libjuafs patch. You can apply the libjuafs patch with the +following command, executed from the root directory of the download code +(i.e. openafs-1.2.4/): + + patch -p1 < libuafs.diff + +Next, if the code doesn't contain the src/JAVA/libjafs directory, you can +apply the jafs patch to it with the following command, executed from the +root directory of the download code (i.e. openafs-1.2.4/): + + patch -p1 < jafs.diff + +Note that the source code you download needs to be newer than 4/22/02, +in order for the full functionality of the API to be effective. Otherwise, +you may experience link errors. + +From that same directory, run the configure script as you normally would +to compile OpenAFS, but run it with a java_home argument so the script can +find your java distribution. For example: + + ./configure [other options] --java_home=/usr/local/jdk + +The configure script will ensure that this directory contains bin/ and lib/ +subdirectories, and that there are /bin/javac and/bin/javah executables and +an include/jni.h file. If you don't supply a command line argument for the +java home, the script will look for it in environment variables: first in +$JAVA_HOME and then in $JDK_HOME. Also, note that if you have installed +(or are planning to install) OpenAFS by using the RPMs for Linux, you +should provide the --enable-transarc-paths configuration option. If you +get a "** Can't determine local cell name" error message, the most likely +reason is that you didn't supply this option. + +Next, do a full build of OpenAFS by executing a make in the current +directory. After it finishes, you are ready to compile Jafs. Execute +'make jafs' from that same directory. Afterward, there will be +libjafsadm.so and libjafs.so in the lib/ directory, and a jafs.jar in the +jlib/ directory. These can be used according to the instructions in the +'USE' section of this document. + +If you'd like to edit the source code, you'll find the native C code in +the src/libjafs directory, and the Java code in the +src/JAVA/org/openafs/jafs/ directory. Please reference the +src/TechNotes-JavaAPI document for more information. + diff --git a/src/JAVA/libjafs/Key.c b/src/JAVA/libjafs/Key.c new file mode 100644 index 0000000..a9ddac9 --- /dev/null +++ b/src/JAVA/libjafs/Key.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_Key.h" + +#include +#include +#include + +//// definitions in Internal.c ////////////////// +extern jclass keyCls; +extern jfieldID key_versionField; +extern jfieldID key_encryptionKeyField; +extern jfieldID key_lastModDateField; +extern jfieldID key_lastModMsField; +extern jfieldID key_checkSumField; + +////////////////////////////////////////////////////////////////// + +/** + * Extract the information from the given key entry and populate the + * given object + * + * env the Java environment + * key the Key object to populate with the info + * keyEntry the container of the key's information + */ +void fillKeyInfo( JNIEnv *env, jobject key, bos_KeyInfo_t keyEntry ) +{ + jstring jencryptionKey; + char *convertedKey; + int i; + + // get the class fields if need be + if( keyCls == 0 ) { + internal_getKeyClass( env, key ); + } + + // set all the fields + (*env)->SetIntField( env, key, key_versionField, keyEntry.keyVersionNumber ); + + convertedKey = (char *) malloc( sizeof(char *)* + (sizeof(keyEntry.key.key)*4+1) ); + if( !convertedKey ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + for( i = 0; i < sizeof(keyEntry.key.key); i++ ) { + sprintf( &(convertedKey[i*4]), "\\%0.3o", keyEntry.key.key[i] ); + } + jencryptionKey = (*env)->NewStringUTF(env, convertedKey); + (*env)->SetObjectField( env, key, key_encryptionKeyField, jencryptionKey ); + + (*env)->SetIntField( env, key, key_lastModDateField, + keyEntry.keyStatus.lastModificationDate ); + (*env)->SetIntField( env, key, key_lastModMsField, + keyEntry.keyStatus.lastModificationMicroSeconds ); + (*env)->SetLongField( env, key, key_checkSumField, + (unsigned int) keyEntry.keyStatus.checkSum ); + + free( convertedKey ); +} + +/** + * Fills in the information fields of the provided Key. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the key + * belongs + * version the version of the key for which to get the information + * key the Key object in which to fill in the + * information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Key_getKeyInfo + (JNIEnv *env, jclass cls, jint serverHandle, jint version, jobject key) +{ + afs_status_t ast; + bos_KeyInfo_t keyEntry; + void *iterationId; + int done; + + if( !bos_KeyGetBegin( (void *) serverHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + done = FALSE; + + // there's no KeyGet function, so we must iterate and find the + // one with the matching version + while( !done ) { + + if( !bos_KeyGetNext( iterationId, &keyEntry, &ast ) ) { + // no matching key + if( ast == ADMITERATORDONE ) { + afs_status_t astnew; + if( !bos_KeyGetDone( iterationId, &astnew ) ) { + throwAFSException( env, astnew ); + return; + } + throwAFSException( env, KAUNKNOWNKEY ); + return; + // other + } else { + throwAFSException( env, ast ); + return; + } + } + + if( keyEntry.keyVersionNumber == version ) { + done = TRUE; + } + + } + + fillKeyInfo( env, key, keyEntry ); + + if( !bos_KeyGetDone( iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Create a server key. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the server belongs + * serverHandle the bos handle of the server to which the key will + * belong + * versionNumber the version number of the key to create (0 to 255) + * jkeyString the String version of the key that will + * be encrypted + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Key_create + (JNIEnv *env, jclass cls, jint cellHandle, jint serverHandle, jint version, + jstring jkeyString) +{ + afs_status_t ast; + const char *keyString; + char *cellName; + kas_encryptionKey_p key = + (kas_encryptionKey_p) malloc( sizeof(kas_encryptionKey_t) ); + + if( !key ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( jkeyString != NULL ) { + keyString = (*env)->GetStringUTFChars(env, jkeyString, 0); + if( !keyString ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + keyString = NULL; + } + + if( !afsclient_CellNameGet( (void *) cellHandle, &cellName, &ast ) ) { + free( key ); + if( keyString != NULL ) { + (*env)->ReleaseStringUTFChars(env, jkeyString, keyString); + } + throwAFSException( env, ast ); + return; + } + + if( !kas_StringToKey( cellName, keyString, key, &ast ) ) { + free( key ); + if( keyString != NULL ) { + (*env)->ReleaseStringUTFChars(env, jkeyString, keyString); + } + throwAFSException( env, ast ); + return; + } + + if( !bos_KeyCreate( (void *) serverHandle, version, key, &ast ) ) { + free( key ); + if( keyString != NULL ) { + (*env)->ReleaseStringUTFChars(env, jkeyString, keyString); + } + throwAFSException( env, ast ); + return; + } + + free( key ); + if( keyString != NULL ) { + (*env)->ReleaseStringUTFChars(env, jkeyString, keyString); + } +} + +/** + * Delete a server key. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the key belongs + * versionNumber the version number of the key to remove (0 to 255) + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Key_delete + (JNIEnv *env, jclass cls, jint serverHandle, jint version ) +{ + afs_status_t ast; + + if( !bos_KeyDelete( (void *) serverHandle, version, &ast ) ) { + throwAFSException( env, ast ); + return; + } +} + +// reclaim global memory being used by this portion +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Key_reclaimKeyMemory (JNIEnv *env, jclass cls) +{ + if( keyCls ) { + (*env)->DeleteGlobalRef(env, keyCls); + keyCls = 0; + } +} + + + + diff --git a/src/JAVA/libjafs/Makefile.in b/src/JAVA/libjafs/Makefile.in new file mode 100644 index 0000000..24bc8e6 --- /dev/null +++ b/src/JAVA/libjafs/Makefile.in @@ -0,0 +1,240 @@ +# Copyright 2000, International Business Machines Corporation and others. +# All Rights Reserved. +# +# This software has been released under the terms of the IBM Public +# License. For details, see the LICENSE file in the top-level source +# directory or online at http://www.openafs.org/dl/license10.html + +DEST=@DEST@ +TOP_SRCDIR=@TOP_SRCDIR@ +TOP_INCDIR=@TOP_INCDIR@ +TOP_LIBDIR=@TOP_LIBDIR@ +TOP_JLIBDIR=@TOP_JLIBDIR@ +JAVA_HOME=@JAVA_HOME@ +JNI_INC=@JNI_INC@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +sbindir=@sbindir@ +libexecdir=@libexecdir@ +libdir=@libdir@ +includedir=@includedir@ +mandir=@mandir@ +afssrvbindir=@afssrvbindir@ +afssrvsbindir=@afssrvsbindir@ +afssrvlibexecdir=@afssrvlibexecdir@ +COMPILE_ET=${TOP_SRCDIR}/comerr/compile_et +RXGEN=${TOP_SRCDIR}/rxgen/rxgen +SYS_NAME=@AFS_SYSNAME@ + + +CC = ${MT_CC} +SHARED_FLAGS = -shared +OBJECT_FLAGS = -fPIC -c + +ifeq "$(BUILD_TYPE)" "admin" + INC := -I${TOP_INCDIR} -I${TOP_INCDIR}/afs/ -I${JAVA_HOME}/include ${JNI_INC} + CFLAGS := ${INC} ${OPTMZ} ${DBG} -I${TOP_SRCDIR}/config ${MT_CFLAGS} +else + INC := -I${TOP_SRCDIR}/libuafs -I${TOP_INCDIR} -I${JAVA_HOME}/include ${JNI_INC} + CFLAGS := ${INC} ${FSINCLUDES} -D_REENTRANT -DLIBJUAFS ${DBUG} ${MT_CFLAGS} +endif + + +LIBJAFSADMDIR = ./ +ROOTPACKAGEDIR = ../classes +RELPACKAGEDIR = org/openafs/jafs/ +PACKAGEDIR = ${ROOTPACKAGEDIR}/${RELPACKAGEDIR} +JAVADOCSDIR = javadocs/ + +JAVAH = ${JAVA_HOME}/bin/javah -classpath ${ROOTPACKAGEDIR} -jni -d ${LIBJAFSADMDIR} +JAVAC = ${JAVA_HOME}/bin/javac -classpath ${ROOTPACKAGEDIR} + +J_NATIVE_PREFIX = org.openafs.jafs. +C_NATIVE_PREFIX = org_openafs_jafs_ + +PACKAGE =\ + ${PACKAGEDIR}ACL.class \ + ${PACKAGEDIR}AFSException.class \ + ${PACKAGEDIR}AFSFileException.class \ + ${PACKAGEDIR}AFSSecurityException.class \ + ${PACKAGEDIR}Cell.class \ + ${PACKAGEDIR}File.class \ + ${PACKAGEDIR}FileInputStream.class \ + ${PACKAGEDIR}FileOutputStream.class \ + ${PACKAGEDIR}Group.class \ + ${PACKAGEDIR}Key.class \ + ${PACKAGEDIR}Partition.class \ + ${PACKAGEDIR}Process.class \ + ${PACKAGEDIR}Server.class \ + ${PACKAGEDIR}Token.class \ + ${PACKAGEDIR}User.class \ + ${PACKAGEDIR}Volume.class + +LIBJAFS_OBJS =\ + ${LIBJAFSADMDIR}ACL.o \ + ${LIBJAFSADMDIR}File.o \ + ${LIBJAFSADMDIR}FileInputStream.o \ + ${LIBJAFSADMDIR}FileOutputStream.o \ + ${LIBJAFSADMDIR}Internal.o \ + ${LIBJAFSADMDIR}UserToken.o + +LIBJAFSADM_OBJS =\ + ${LIBJAFSADMDIR}AdminToken.o \ + ${LIBJAFSADMDIR}Cell.o \ + ${LIBJAFSADMDIR}Group.o \ + ${LIBJAFSADMDIR}Internal.o \ + ${LIBJAFSADMDIR}Key.o \ + ${LIBJAFSADMDIR}Partition.o \ + ${LIBJAFSADMDIR}Process.o \ + ${LIBJAFSADMDIR}Server.o \ + ${LIBJAFSADMDIR}User.o \ + ${LIBJAFSADMDIR}Volume.o + +CORRELATING_SOURCE_FILES =\ + ${LIBJAFSADMDIR}ACL.c \ + ${LIBJAFSADMDIR}Cell.c \ + ${LIBJAFSADMDIR}File.c \ + ${LIBJAFSADMDIR}FileInputStream.c \ + ${LIBJAFSADMDIR}FileOutputStream.c \ + ${LIBJAFSADMDIR}Group.c \ + ${LIBJAFSADMDIR}Key.c \ + ${LIBJAFSADMDIR}Partition.c \ + ${LIBJAFSADMDIR}Process.c \ + ${LIBJAFSADMDIR}Server.c \ + ${LIBJAFSADMDIR}User.c \ + ${LIBJAFSADMDIR}Volume.c + +JAVA_HEADERS = ${PACKAGE:${PACKAGEDIR}%.class=${C_NATIVE_PREFIX}%.h} + +BOSADMINLIB = ${TOP_LIBDIR}/libbosadmin.a +VOSADMINLIB = ${TOP_LIBDIR}/libvosadmin.a +PTSADMINLIB = ${TOP_LIBDIR}/libptsadmin.a +KASADMINLIB = ${TOP_LIBDIR}/libkasadmin.a +CFGADMINLIB = ${TOP_LIBDIR}/libcfgadmin.a +UTILADMINLIB = ${TOP_LIBDIR}/libafsadminutil.a +CLIENTADMINLIB = ${TOP_LIBDIR}/libclientadmin.a + +LIBJAFS_LIBS =\ + ${TOP_LIBDIR}/libjuafs.a \ + ${TOP_LIBDIR}/libdes.a \ + -lresolv \ + -lpthread + +LIBJAFSADM_LIBS =\ + ${CLIENTADMINLIB} \ + ${VOSADMINLIB} \ + ${BOSADMINLIB} \ + ${PTSADMINLIB} \ + ${KASADMINLIB} \ + ${CFGADMINLIB} \ + ${UTILADMINLIB} \ + ${TOP_LIBDIR}/libafsauthent.a \ + ${TOP_LIBDIR}/libafsrpc.a \ + ${TOP_LIBDIR}/libcmd.a \ + -lresolv \ + -lpthread + + +JARFILE = jafs.jar + +include ../../config/Makefile.${SYS_NAME} + +all: ${TOP_JLIBDIR} libjafs libjafsadm ${PACKAGE} all_jar + +install: all ${DESTDIR}${libdir}/libjafs.so ${DESTDIR}${libdir}/libjafsadm.so ${PACKAGE} install_jar + if [ ! -e /usr/afswsp ]; then \ + mkdir -p /usr/afswsp/; \ + fi; \ + if [ ! -e /usr/afswsp/etc ]; then \ + mkdir -p /usr/afswsp/etc/; \ + cp ./etc/CacheConfig /usr/afswsp/etc/; \ + fi; \ + if [ ! -e /usr/afswsp/log ]; then \ + mkdir -p /usr/afswsp/log/; \ + fi; \ + if [ ! -e /usr/afswsp/cache ]; then \ + mkdir -p /usr/afswsp/cache/; \ + fi; \ + if [ ! -L /usr/vice/etc/CellServDB ]; then \ + ln -s /usr/vice/etc/CellServDB /usr/afswsp/etc/; \ + fi; \ + if [ ! -L /usr/vice/etc/ThisCell ]; then \ + ln -s /usr/vice/etc/ThisCell /usr/afswsp/etc/; \ + fi + +clean: + ${RM} -f ${PACKAGEDIR}*.class ${LIBJAFSADMDIR}*.o ${LIBJAFSADMDIR}${C_NATIVE_PREFIX}*.h + +setup: FORCE + if [ ! -e ./h ]; then \ + ln -s /usr/include/sys h; \ + fi; \ + +${TOP_JLIBDIR}: + mkdir -p $@ + +FORCE: ; + +############# Shared library ############################### + +libjafs: setup + ${RM} -f ${LIBJAFSADMDIR}Internal.o; \ + export BUILD_TYPE=user; \ + ${MAKE} ${TOP_LIBDIR}/libjafs.so + +libjafsadm: + ${RM} -f ${LIBJAFSADMDIR}Internal.o; \ + export BUILD_TYPE=admin; \ + ${MAKE} ${TOP_LIBDIR}/libjafsadm.so + +${TOP_LIBDIR}/libjafs.so: ${LIBJAFS_OBJS} + ${CC} ${CFLAGS} ${SHARED_FLAGS} -o $@ $^ ${LIBJAFS_LIBS} + +${DESTDIR}${libdir}/libjafs.so: ${LIBJAFS_OBJS} + ${CC} ${CFLAGS} ${SHARED_FLAGS} -o $@ $^ ${LIBJAFS_LIBS} + +${TOP_LIBDIR}/libjafsadm.so: ${LIBJAFSADM_OBJS} + ${CC} ${CFLAGS} ${SHARED_FLAGS} -o $@ $^ ${LIBJAFSADM_LIBS} + +${DESTDIR}${libdir}/libjafsadm.so: ${LIBJAFSADM_OBJS} + ${CC} ${CFLAGS} ${SHARED_FLAGS} -o $@ $^ ${LIBJAFSADM_LIBS} + +############## Object files ################################ + +${LIBJAFSADM_OBJS}: %.o: %.c + ${CC} ${CFLAGS} ${OBJECT_FLAGS} -o $@ $< + +############## C files ##################################### + +${CORRELATING_SOURCE_FILES}: ${LIBJAFSADMDIR}%.c: ${LIBJAFSADMDIR}${C_NATIVE_PREFIX}%.h ${LIBJAFSADMDIR}Internal.h + +${LIBJAFSADMDIR}AdminToken.c: ${LIBJAFSADMDIR}${C_NATIVE_PREFIX}Token.h ${LIBJAFSADMDIR}${C_NATIVE_PREFIX}Cell.h + +${LIBJAFSADMDIR}Internal.c: ${LIBJAFSADMDIR}Internal.h + +${LIBJAFSADMDIR}UserToken.c: ${LIBJAFSADMDIR}${C_NATIVE_PREFIX}Token.h + +############## Package javac section ######################### + +${PACKAGEDIR}%.class: ${PACKAGEDIR}%.java + ${JAVAC} $< + +############## Javah section ############################### + +${JAVA_HEADERS}: ${C_NATIVE_PREFIX}%.h: ${PACKAGEDIR}%.class + ${JAVAH} ${J_NATIVE_PREFIX}$* + +############# JAR file ##################################### + +all_jar: clean_jar + cd ${ROOTPACKAGEDIR}; ${JAVA_HOME}/bin/jar -cMf ${TOP_JLIBDIR}/${JARFILE} *.properties ${RELPACKAGEDIR}*.class + +install_jar: clean_jar + cd ${ROOTPACKAGEDIR}; ${JAVA_HOME}/bin/jar -cMf ${JAVA_HOME}/lib/${JARFILE} *.properties ${RELPACKAGEDIR}*.class + +clean_jar: + ${RM} -f ${TOP_JLIBDIR}/${JARFILE} + + + diff --git a/src/JAVA/libjafs/Partition.c b/src/JAVA/libjafs/Partition.c new file mode 100644 index 0000000..6b35c12 --- /dev/null +++ b/src/JAVA/libjafs/Partition.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_Partition.h" + +#include +#include + +//// definitions in Internal.c ////////////////// + +extern jclass partitionCls; +extern jfieldID partition_nameField; +extern jfieldID partition_idField; +extern jfieldID partition_deviceNameField; +extern jfieldID partition_lockFileDescriptorField; +extern jfieldID partition_totalSpaceField; +extern jfieldID partition_totalFreeSpaceField; + +extern jclass volumeCls; +extern jfieldID volume_cachedInfoField; + +////////////////////////////////////////////////////////// + +///// definition in jafs_Volume.c ///////////////// + +extern void fillVolumeInfo + ( JNIEnv *env, jobject volume, vos_volumeEntry_t volEntry ); + +/////////////////////////////////////////////////// + + +/** + * Extract the information from the given partition entry and populate the + * given object + * + * env the Java environment + * partition the Partition object to populate with the info + * partEntry the container of the partition's information + */ +void fillPartitionInfo + (JNIEnv *env, jobject partition, vos_partitionEntry_t partEntry) +{ + jstring jdeviceName; + jstring jpartition; + jint id; + afs_status_t ast; + + // get the class fields if need be + if( partitionCls == 0 ) { + internal_getPartitionClass( env, partition ); + } + + // fill name and id in case it's a blank object + jpartition = (*env)->NewStringUTF(env, partEntry.name); + // get the id + if( !vos_PartitionNameToId( partEntry.name, (int *) &id, &ast ) ) { + throwAFSException( env, ast ); + return; + } + (*env)->SetObjectField(env, partition, partition_nameField, jpartition); + (*env)->SetIntField(env, partition, partition_idField, id); + + jdeviceName = (*env)->NewStringUTF(env, partEntry.deviceName); + (*env)->SetObjectField(env, partition, partition_deviceNameField, + jdeviceName); + + (*env)->SetIntField(env, partition, partition_lockFileDescriptorField, + partEntry.lockFileDescriptor); + (*env)->SetIntField(env, partition, partition_totalSpaceField, + partEntry.totalSpace); + (*env)->SetIntField(env, partition, partition_totalFreeSpaceField, + partEntry.totalFreeSpace); + +} + +/** + * Fills in the information fields of the provided Partition. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the partition belongs + * serverHandle the vos handle of the server on which the + * partition resides + * partition the numeric id of the partition for which to get the + * info + * jpartitionObject the Partition object in which to + * fill in the information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Partition_getPartitionInfo + (JNIEnv *env, jclass cls, jint cellHandle, jint serverHandle, + jint partition, jobject jpartitionObject) +{ + afs_status_t ast; + vos_partitionEntry_t partEntry; + + // get the partition entry + if ( !vos_PartitionGet( (void *) cellHandle, (void *) serverHandle, NULL, + (unsigned int) partition, &partEntry, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + fillPartitionInfo( env, jpartitionObject, partEntry ); + +} + +/** + * Translates a partition name into a partition id + * + * env the Java environment + * cls the current Java class + * jname the name of the partition in question + * returns the id of the partition in question + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Partition_translateNameToID + (JNIEnv *env, jclass cls, jstring jname) +{ + afs_status_t ast; + jint id; + const char *name; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + // get the id + if( !vos_PartitionNameToId( name, (unsigned int *) &id, &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return -1; + } + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + + return id; + +} + +/** + * Translates a partition id into a partition name + * + * env the Java environment + * cls the current Java class + * id the id of the partition in question + * returns the name of the partition in question + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Partition_translateIDToName + (JNIEnv *env, jclass cls, jint id) +{ + afs_status_t ast; + char *name = (char *) malloc( sizeof(char)*VOS_MAX_PARTITION_NAME_LEN); + jstring jname; + + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + // get the name + if( !vos_PartitionIdToName( (unsigned int) id, name, &ast ) ) { + free(name); + throwAFSException( env, ast ); + return NULL; + } + + jname = (*env)->NewStringUTF(env, name); + free(name); + return jname; + +} + +/** + * Returns the total number of volumes hosted by this partition. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the partition belongs + * serverHandle the vos handle of the server to which the partition + * belongs + * partition the numeric id of the partition on which the volumes + * reside + * returns total number of volumes hosted by this partition + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Partition_getVolumeCount + (JNIEnv *env, jclass cls, jint cellHandle, jint serverHandle, jint partition) +{ + afs_status_t ast; + void *iterationId; + vos_volumeEntry_t volEntry; + int i = 0; + + if( !vos_VolumeGetBegin( (void *) cellHandle, (void *) serverHandle, NULL, + (unsigned int) partition, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return -1; + } + + while ( vos_VolumeGetNext( (void *) iterationId, &volEntry, &ast ) ) i++; + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Begin the process of getting the volumes on a partition. Returns + * an iteration ID to be used by subsequent calls to + * getVolumesNext and getVolumesDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the partition belongs + * serverHandle the vos handle of the server to which the partition + * belongs + * partition the numeric id of the partition on which the volumes + * reside + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Partition_getVolumesBegin + (JNIEnv *env, jclass cls, jint cellHandle, jint serverHandle, jint partition) +{ + + afs_status_t ast; + void *iterationId; + + if( !vos_VolumeGetBegin( (void *) cellHandle, (void *) serverHandle, NULL, + (unsigned int) partition, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return (jint) iterationId; +} + +/** + * Begin the process of getting the volumes on a partition. Returns + * an iteration ID to be used by subsequent calls to + * getVolumesNext and getVolumesDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the partition belongs + * serverHandle the vos handle of the server to which the partition + * belongs + * partition the numeric id of the partition on which the volumes + * reside + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Partition_getVolumesBeginAt + (JNIEnv *env, jclass cls, jint cellHandle, jint serverHandle, + jint partition, jint index) +{ + + afs_status_t ast; + void *iterationId; + vos_volumeEntry_t volEntry; + int i; + + if( !vos_VolumeGetBegin( (void *) cellHandle, (void *) serverHandle, NULL, + (unsigned int) partition, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + for ( i = 1; i < index; i++) { + if( !vos_VolumeGetNext( (void *) iterationId, &volEntry, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + } + + return (jint) iterationId; + +} + +/** + * Returns the next volume of the partition. Returns null + * if there are no more volumes. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next volume of the server + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Partition_getVolumesNextString + (JNIEnv *env, jclass cls, jint iterationId) +{ + afs_status_t ast; + jstring jvolume; + vos_volumeEntry_t volEntry; + + if( !vos_VolumeGetNext( (void *) iterationId, &volEntry, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + jvolume = (*env)->NewStringUTF(env, volEntry.name); + return jvolume; + +} + +/** + * Fills the next volume object of the partition. Returns 0 if there + * are no more volumes, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * jvolumeObject the Volume object in which to fill the values + * of the next volume + * returns 0 if there are no more volumes, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Partition_getVolumesNext + (JNIEnv *env, jclass cls, jint iterationId, jobject jvolumeObject) +{ + afs_status_t ast; + jstring jvolume; + vos_volumeEntry_t volEntry; + + if( !vos_VolumeGetNext( (void *) iterationId, &volEntry, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + + fillVolumeInfo( env, jvolumeObject, volEntry ); + + // get the class fields if need be + if( volumeCls == 0 ) { + internal_getVolumeClass( env, jvolumeObject ); + } + (*env)->SetBooleanField( env, jvolumeObject, volume_cachedInfoField, TRUE ); + + return 1; + +} + +/** + * Fills the next volume object of the partition. Returns 0 if there + * are no more volumes, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * jvolumeObject the Volume object in which to fill the values of the + * next volume + * advanceCount the number of volumes to advance past + * returns 0 if there are no more volumes, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Partition_getVolumesAdvanceTo + (JNIEnv *env, jclass cls, jint iterationId, jobject jvolumeObject, + jint advanceCount) +{ + afs_status_t ast; + jstring jvolume; + vos_volumeEntry_t volEntry; + int i; + + for ( i = 0; i < advanceCount; i++) { + if( !vos_VolumeGetNext( (void *) iterationId, &volEntry, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + } + + + fillVolumeInfo( env, jvolumeObject, volEntry ); + + // get the class fields if need be + if( volumeCls == 0 ) { + internal_getVolumeClass( env, jvolumeObject ); + } + (*env)->SetBooleanField( env, jvolumeObject, volume_cachedInfoField, TRUE ); + + return 1; +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Partition_getVolumesDone + (JNIEnv *env, jclass cls, jint iterationId) +{ + afs_status_t ast; + + if( !vos_VolumeGetDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } +} + +// reclaim global memory being used by this portion +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Partition_reclaimPartitionMemory + (JNIEnv *env, jclass cls) +{ + if( partitionCls ) { + (*env)->DeleteGlobalRef(env, partitionCls); + partitionCls = 0; + } +} + + + + + + + + + + + + + + + + + + + diff --git a/src/JAVA/libjafs/Process.c b/src/JAVA/libjafs/Process.c new file mode 100644 index 0000000..25c0add --- /dev/null +++ b/src/JAVA/libjafs/Process.c @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_Process.h" + +#include + +///// definitions in Internal.c //////////////////// + +extern jclass processCls; +extern jfieldID process_nameField; +extern jfieldID process_typeField; +extern jfieldID process_stateField; +extern jfieldID process_goalField; +extern jfieldID process_startTimeField; +extern jfieldID process_numberStartsField; +extern jfieldID process_exitTimeField; +extern jfieldID process_exitErrorTimeField; +extern jfieldID process_errorCodeField; +extern jfieldID process_errorSignalField; +extern jfieldID process_stateOkField; +extern jfieldID process_stateTooManyErrorsField; +extern jfieldID process_stateBadFileAccessField; + +////////////////////////////////////////////////////////////////// + +/** + * Retrieve the information for the specified process and populate the + * given object + * + * env the Java environment + * serverHandle the bos handle of the server on which the process resides + * processName the name of the process for which to get the info + * process the Process object to populate with the info + */ +void getProcessInfoChar( JNIEnv *env, void *serverHandle, + const char *processName, jobject process ) { + + afs_status_t ast; + bos_ProcessType_t type; + bos_ProcessInfo_t infoEntry; + bos_ProcessExecutionState_t state; + char *auxStatus; + + // get class fields if need be + if( processCls == 0 ) { + internal_getProcessClass( env, process ); + } + + if( !bos_ProcessInfoGet( serverHandle, processName, &type, + &infoEntry, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + // set type variable + switch( type ) { + case BOS_PROCESS_SIMPLE : + (*env)->SetIntField(env, process, process_typeField, + org_openafs_jafs_Process_SIMPLE_PROCESS); + break; + case BOS_PROCESS_FS : + (*env)->SetIntField(env, process, process_typeField, + org_openafs_jafs_Process_FS_PROCESS); + break; + case BOS_PROCESS_CRON : + (*env)->SetIntField(env, process, process_typeField, + org_openafs_jafs_Process_CRON_PROCESS); + break; + default: + throwAFSException( env, type ); + return; + } + + // set goal variable + switch( infoEntry.processGoal ) { + case BOS_PROCESS_STOPPED : + (*env)->SetIntField(env, process, process_goalField, + org_openafs_jafs_Process_STOPPED); + break; + case BOS_PROCESS_RUNNING : + (*env)->SetIntField(env, process, process_goalField, + org_openafs_jafs_Process_RUNNING); + break; + case BOS_PROCESS_STOPPING : + (*env)->SetIntField(env, process, process_goalField, + org_openafs_jafs_Process_STOPPING); + break; + case BOS_PROCESS_STARTING : + (*env)->SetIntField(env, process, process_goalField, + org_openafs_jafs_Process_STARTING); + break; + default: + throwAFSException( env, infoEntry.processGoal ); + return; + } + + // set state variable + auxStatus = (char *) malloc( sizeof(char)*BOS_MAX_NAME_LEN ); + if( !auxStatus ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + if( !bos_ProcessExecutionStateGet( (void *) serverHandle, processName, + &state, auxStatus, &ast ) ) { + free( auxStatus ); + throwAFSException( env, ast ); + return; + } + free( auxStatus ); + switch( state ) { + case BOS_PROCESS_STOPPED : + (*env)->SetIntField(env, process, process_stateField, + org_openafs_jafs_Process_STOPPED); + break; + case BOS_PROCESS_RUNNING : + (*env)->SetIntField(env, process, process_stateField, + org_openafs_jafs_Process_RUNNING); + break; + case BOS_PROCESS_STOPPING : + (*env)->SetIntField(env, process, process_stateField, + org_openafs_jafs_Process_STOPPING); + break; + case BOS_PROCESS_STARTING : + (*env)->SetIntField(env, process, process_stateField, + org_openafs_jafs_Process_STARTING); + break; + default: + throwAFSException( env, state ); + return; + } + + // set longs + (*env)->SetLongField(env, process, process_startTimeField, + infoEntry.processStartTime ); + (*env)->SetLongField(env, process, process_numberStartsField, + infoEntry.numberProcessStarts ); + (*env)->SetLongField(env, process, process_exitTimeField, + infoEntry.processExitTime ); + (*env)->SetLongField(env, process, process_exitErrorTimeField, + infoEntry.processExitErrorTime ); + (*env)->SetLongField(env, process, process_errorCodeField, + infoEntry.processErrorCode ); + (*env)->SetLongField(env, process, process_errorSignalField, + infoEntry.processErrorSignal ); + + // set stateOk to true if no core dump + if( infoEntry.state & BOS_PROCESS_CORE_DUMPED ) { + (*env)->SetBooleanField(env, process, process_stateOkField, FALSE ); + } else { + (*env)->SetBooleanField(env, process, process_stateOkField, TRUE ); + } + + // set stateTooManyErrors + if( infoEntry.state & BOS_PROCESS_TOO_MANY_ERRORS ) { + (*env)->SetBooleanField(env, process, + process_stateTooManyErrorsField, TRUE ); + } else { + (*env)->SetBooleanField(env, process, + process_stateTooManyErrorsField, FALSE ); + } + + // set stateBadFileAccess + if( infoEntry.state & BOS_PROCESS_BAD_FILE_ACCESS ) { + (*env)->SetBooleanField(env, process, + process_stateBadFileAccessField, TRUE ); + } else { + (*env)->SetBooleanField(env, process, + process_stateBadFileAccessField, FALSE ); + } + +} + +/** + * Fills in the information fields of the provided Process. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the process belongs + * jname the instance name of the process for which to get + * the information + * process the Process object in which to fill + * in the information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Process_getProcessInfo (JNIEnv *env, jclass cls, + jint serverHandle, + jstring jname, + jobject process) { + + const char *name; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + getProcessInfoChar( env, (void *) serverHandle, name, process ); + + // set name in case blank object + if( name != NULL ) { + if( processCls == 0 ) { + internal_getProcessClass( env, process ); + } + (*env)->SetObjectField(env, process, process_nameField, jname); + (*env)->ReleaseStringUTFChars(env, jname, name); + } + +} + +/** + * Creates a process on a server. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the key will + * belong + * jname the instance name to give the process. See AFS + * documentation for a standard list of instance names + * jtype the type of process this will be. + * Acceptable values are: + * org_openafs_jafs_Process_SIMPLE_PROCESS + * org_openafs_jafs_Process_FS_PROCESS + * org_openafs_jafs_Process_CRON_PROCESS + * jpath the execution path process to create + * jcronTime a String representing the time a cron process is to + * be run. Acceptable formats are: + * for daily restarts: "23:10" or "11:10 pm" + * for weekly restarts: "sunday 11:10pm" or + * "sun 11:10pm" + * Can be null for non-cron processes. + * jnotifier the execution path to a notifier program that should + * be called when the process terminates. Can be + * null + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Process_create (JNIEnv *env, jclass cls, + jint serverHandle, jstring jname, + jint jtype, jstring jpath, + jstring jcronTime, + jstring jnotifier) { + + afs_status_t ast; + bos_ProcessType_t type; + const char *name; + const char *path; + const char *cronTime; + const char *notifier; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + if( jpath != NULL ) { + path = (*env)->GetStringUTFChars(env, jpath, 0); + if( !path ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + path = NULL; + } + + switch( jtype ) { + case org_openafs_jafs_Process_SIMPLE_PROCESS: + type = BOS_PROCESS_SIMPLE; + break; + case org_openafs_jafs_Process_FS_PROCESS: + type = BOS_PROCESS_FS; + break; + case org_openafs_jafs_Process_CRON_PROCESS: + type = BOS_PROCESS_CRON; + break; + default: + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + if( path != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpath, path); + } + throwAFSException( env, jtype ); + return; + } + + if( jcronTime != NULL ) { + cronTime = (*env)->GetStringUTFChars(env, jcronTime, 0); + if( !cronTime ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + if( path != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpath, path); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + cronTime = NULL; + } + + if( jnotifier != NULL ) { + notifier = (*env)->GetStringUTFChars(env, jnotifier, 0); + if( !notifier ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + if( path != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpath, path); + } + if( cronTime != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcronTime, cronTime); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + notifier = NULL; + } + + if( !bos_ProcessCreate( (void *) serverHandle, name, type, path, + cronTime, notifier, &ast ) ) { + // release strings + if( cronTime != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcronTime, cronTime); + } + if( notifier != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnotifier, notifier); + } + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + if( path != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpath, path); + } + throwAFSException( env, ast ); + return; + } + + + // release strings + if( cronTime != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcronTime, cronTime); + } + if( notifier != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnotifier, notifier); + } + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + if( path != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpath, path); + } + +} + +/** + * Removes a process from a server. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the process + * belongs + * jname the name of the process to remove + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Process_delete (JNIEnv *env, jclass cls, + jint serverHandle, jstring jname) { + + afs_status_t ast; + const char *name; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + if( !bos_ProcessDelete( (void *) serverHandle, name, &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + +} + +/** + * Stop this process. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the process + * belongs + * jname the name of the process to stop + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Process_stop (JNIEnv *env, jclass cls, + jint serverHandle, jstring jname) { + + afs_status_t ast; + const char *name; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + if( !bos_ProcessExecutionStateSet( (void *) serverHandle, name, + BOS_PROCESS_STOPPED, &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + +} + +/** + * Start this process. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the process + * belongs + * jname the name of the process to start + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Process_start (JNIEnv *env, jclass cls, + jint serverHandle, jstring jname) { + + afs_status_t ast; + const char *name; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + if( !bos_ProcessExecutionStateSet( (void *) serverHandle, name, + BOS_PROCESS_RUNNING, &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + +} + +/** + * Retart this process. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the process + * belongs + * jname the name of the process to restart + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Process_restart (JNIEnv *env, jclass cls, + jint serverHandle, jstring jname) { + + afs_status_t ast; + const char *name; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + if( !bos_ProcessRestart( (void *) serverHandle, name, &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + +} + +// reclaim global memory being used by this portion +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Process_reclaimProcessMemory (JNIEnv *env, + jclass cls) { + + if( processCls ) { + (*env)->DeleteGlobalRef(env, processCls); + processCls = 0; + } + +} + + + + + + diff --git a/src/JAVA/libjafs/Server.c b/src/JAVA/libjafs/Server.c new file mode 100644 index 0000000..ce3f504 --- /dev/null +++ b/src/JAVA/libjafs/Server.c @@ -0,0 +1,1657 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_Server.h" + +#include +#include +#include +#include +#include +#include + +//// definitions in Internal.c ////////////////// + +extern jclass serverCls; +extern jfieldID server_nameField; +extern jfieldID server_nameField; +extern jfieldID server_databaseField; +extern jfieldID server_fileServerField; +extern jfieldID server_badDatabaseField; +extern jfieldID server_badFileServerField; +extern jfieldID server_IPAddressField; + +extern jclass exectimeCls; +extern jfieldID exectime_HourField; +extern jfieldID exectime_MinField; +extern jfieldID exectime_SecField; +extern jfieldID exectime_DayField; +extern jfieldID exectime_NowField; +extern jfieldID exectime_NeverField; + +extern jclass partitionCls; +extern jfieldID partition_cachedInfoField; + +extern jclass keyCls; +extern jfieldID key_cachedInfoField; + +extern jclass processCls; +extern jfieldID process_cachedInfoField; +extern jfieldID process_nameField; +//extern jfieldID process_serverHandleField; + +extern jclass userCls; +extern jfieldID user_nameField; +extern jfieldID user_cachedInfoField; +////////////////////////////////////////////////////////// + +///// definition in jafs_Partition.c ///////////////// + +extern void fillPartitionInfo( JNIEnv *env, jobject partition, + vos_partitionEntry_t partEntry ); + +/////////////////////////////////////////////////// + +///// definition in jafs_Key.c ///////////////// + +extern void fillKeyInfo( JNIEnv *env, jobject key, bos_KeyInfo_t keyEntry ); + +/////////////////////////////////////////////////// + +///// definition in jafs_Process.c ///////////////// + +extern void getProcessInfoChar( JNIEnv *env, void *serverHandle, + const char *processName, jobject process ); + +/////////////////////////////////////////////////// + +/** + * Extract the information from the given server entry and populate the + * given object + * + * env the Java environment + * cellHandle the handle of the cell to which the server belongs + * server the Server object to populate with the info + * servEntry the container of the server's information + */ +void fillServerInfo + ( JNIEnv *env, jint cellHandle, jobject server, afs_serverEntry_t servEntry ) +{ + jstring jip; + jobjectArray jaddresses; + jstring jserver; + int i = 0; + + // get the class fields if need be + if( serverCls == 0 ) { + internal_getServerClass( env, server ); + } + + // in case it's blank + jserver = (*env)->NewStringUTF(env, servEntry.serverName); + (*env)->SetObjectField(env, server, server_nameField, jserver); + + // let's convert just the addresses in the address array into an IP + jaddresses = (jobjectArray) (*env)->GetObjectField( env, server, + server_IPAddressField ); + for (i = 0; i < 16; i++) { + if (servEntry.serverAddress[i] != 0) { + jip = + (*env)->NewStringUTF(env, (char *) + inet_ntoa(htonl(servEntry.serverAddress[i]))); + (*env)->SetObjectArrayElement(env, jaddresses, i, jip); + } else { + break; + } + } + + // let's check if this is really a database server + (*env)->SetBooleanField(env, server, server_databaseField, + servEntry.serverType & DATABASE_SERVER); + if( servEntry.serverType & DATABASE_SERVER ) { + // for now, if it thinks it's a database server than it is + // later, add checks for database configuration, and actual + // on-ness of the machine + (*env)->SetBooleanField(env, server, server_badDatabaseField, FALSE); + } else { + (*env)->SetBooleanField(env, server, server_badDatabaseField, FALSE); + } + + // we should check to see if this is truly a file server or not + // it could just be an old remnant, left over inside the vldb that + // should be removed. + // if it is a file server, mark it as such. If not, mark it as faulty. + (*env)->SetBooleanField(env, server, server_fileServerField, + servEntry.serverType & FILE_SERVER); + if( servEntry.serverType & FILE_SERVER ) { + + // to see if it's really a file server, make sure the + // "fs" process is running + void *bosHandle; + afs_status_t ast; + bos_ProcessType_t processTypeT; + bos_ProcessInfo_t processInfoT; + char *fileServerProcessName = "fs"; + + // set the file server to true (it thinks it's a file server) + (*env)->SetBooleanField(env, server, server_fileServerField, TRUE); + + if( !bos_ServerOpen( (void *) cellHandle, servEntry.serverName, + &bosHandle, &ast ) ) { + throwAFSException( env, ast ); + return; + } + if( !bos_ProcessInfoGet( bosHandle, fileServerProcessName, &processTypeT, + &processInfoT, &ast ) ) { + // if the machine does not have a fs process or is not responding + // or is part of another cell + if( ast == BZNOENT || ast == -1 || ast == RXKADBADTICKET ) { + (*env)->SetBooleanField(env, server, server_badFileServerField, TRUE); + // otherwise + } else { + throwAFSException( env, ast ); + return; + } + } else { + // it's good + (*env)->SetBooleanField(env, server, server_badFileServerField, FALSE); + } + } else { + (*env)->SetBooleanField(env, server, server_badFileServerField, FALSE); + } + +} + +/** + * Fills in the information fields of the provided Server. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the server belongs + * jname the name of the server for which to get the information + * server the Server object in which to fill in + * the information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_getServerInfo (JNIEnv *env, jclass cls, + jint cellHandle, jstring jname, + jobject server) { + + const char *name; + afs_status_t ast; + afs_serverEntry_t servEntry; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + // get the server entry + if ( !afsclient_AFSServerGet( (void *) cellHandle, name, + &servEntry, &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + + fillServerInfo( env, cellHandle, server, servEntry ); + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + +} + +/** + * Returns the total number of partitions hosted by the server denoted by + * serverHandle, if the server is a fileserver. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the server belongs + * serverHandle the vos handle of the server to which the + * partitions belong + * returns total number of partitions + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getPartitionCount (JNIEnv *env, jclass cls, + jint cellHandle, + jint serverHandle) { + + afs_status_t ast; + void *iterationId; + vos_partitionEntry_t partEntry; + int i = 0; + + if( !vos_PartitionGetBegin( (void *) cellHandle, (void *) serverHandle, + NULL, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return -1; + } + + while ( vos_PartitionGetNext( (void *) iterationId, &partEntry, &ast ) ) i++; + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Begin the process of getting the partitions on a server. Returns + * an iteration ID to be used by subsequent calls to + * getPartitionsNext and getPartitionsDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the server belongs + * serverHandle the vos handle of the server to which the + * partitions belong + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getPartitionsBegin (JNIEnv *env, jclass cls, + jint cellHandle, + jint serverHandle) { + + afs_status_t ast; + void *iterationId; + + if( !vos_PartitionGetBegin( (void *) cellHandle, (void *) serverHandle, + NULL, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return (jint) iterationId; + +} + +/** + * Returns the next partition of the server. Returns null + * if there are no more partitions. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next partition of the server + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Server_getPartitionsNextString (JNIEnv *env, + jclass cls, + jint iterationId) { + + afs_status_t ast; + jstring jpartition; + vos_partitionEntry_t partEntry; + + if( !vos_PartitionGetNext( (void *) iterationId, &partEntry, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + jpartition = (*env)->NewStringUTF(env, partEntry.name); + return jpartition; + +} + +/** + * Fills the next partition object of the server. Returns 0 if there + * are no more partitions, != 0 otherwise + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * thePartition the Partition object in which to fill the + * values of the next partition + * returns 0 if there are no more servers, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getPartitionsNext (JNIEnv *env, jclass cls, + jint iterationId, + jobject jpartitionObject) { + + afs_status_t ast; + vos_partitionEntry_t partEntry; + + if( !vos_PartitionGetNext( (void *) iterationId, &partEntry, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + fillPartitionInfo( env, jpartitionObject, partEntry ); + + // get the class fields if need be + if( partitionCls == 0 ) { + internal_getPartitionClass( env, jpartitionObject ); + } + (*env)->SetBooleanField( env, jpartitionObject, partition_cachedInfoField, + TRUE ); + + + return 1; + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_getPartitionsDone (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + + if( !vos_PartitionGetDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Adds the given to name to the list of bos administrators on that server. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the + * partitions belong + * jnewAdmin the name of the admin to add to the list + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_addBosAdmin (JNIEnv *env, jclass cls, + jint serverHandle, + jstring jnewAdmin) { + + afs_status_t ast; + const char *newAdmin; + + if( jnewAdmin != NULL ) { + newAdmin = (*env)->GetStringUTFChars(env, jnewAdmin, 0); + if( !newAdmin ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + newAdmin = NULL; + } + + if( !bos_AdminCreate( (void *) serverHandle, newAdmin, &ast ) ) { + if( newAdmin != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewAdmin, newAdmin); + } + throwAFSException( env, ast ); + return; + } + + if( newAdmin != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewAdmin, newAdmin); + } + +} + +/** + * Removes the given to name from the list of bos administrators on + * that server. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the + * partitions belong + * joldAdmin the name of the admin to remove from the list + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_removeBosAdmin (JNIEnv *env, jclass cls, + jint serverHandle, + jstring joldAdmin) { + + afs_status_t ast; + const char *oldAdmin; + + if( joldAdmin != NULL ) { + oldAdmin = (*env)->GetStringUTFChars(env, joldAdmin, 0); + if( !oldAdmin ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + oldAdmin = NULL; + } + + if( !bos_AdminDelete( (void *) serverHandle, oldAdmin, &ast ) ) { + if( oldAdmin != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldAdmin, oldAdmin); + } + throwAFSException( env, ast ); + return; + } + + if( oldAdmin != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldAdmin, oldAdmin); + } + +} + +/** + * Returns the total number of BOS administrators associated with the server + * denoted by serverHandle. + * + * env the Java environment + * cls the current Java class + * serverHandle the vos handle of the server to which the + * BOS admins belong + * returns total number of BOS administrators + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getBosAdminCount (JNIEnv *env, jclass cls, + jint serverHandle) { + + afs_status_t ast; + void *iterationId; + char *admin; + jstring jadmin; + int i = 0; + + if( !bos_AdminGetBegin( (void *) serverHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return -1; + } + + admin = (char *) malloc( sizeof(char)*BOS_MAX_NAME_LEN); + + if( !admin ) { + throwAFSException( env, JAFSADMNOMEM ); + return -1; + } + + while ( bos_AdminGetNext( (void *) iterationId, admin, &ast ) ) i++; + + free(admin); + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Begin the process of getting the bos amdinistrators on a server. Returns + * an iteration ID to be used by subsequent calls to + * getBosAdminsNext and getBosAdminsDone. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the + * partitions belong + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getBosAdminsBegin (JNIEnv *env, jclass cls, + jint serverHandle) { + + afs_status_t ast; + void *iterationId; + + if( !bos_AdminGetBegin( (void *) serverHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return (jint) iterationId; + +} + +/** + * Returns the next bos admin of the server. Returns null + * if there are no more admins. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next admin of the server + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Server_getBosAdminsNextString (JNIEnv *env, + jclass cls, + jint iterationId) { + + afs_status_t ast; + jstring jadmin; + char *admin = (char *) malloc( sizeof(char)*BOS_MAX_NAME_LEN ); + + if( !admin ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !bos_AdminGetNext( (void *) iterationId, admin, &ast ) ) { + free(admin); + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + jadmin = (*env)->NewStringUTF(env, admin); + free(admin); + return jadmin; + +} + +/** + * Returns the next bos admin of the server. Returns 0 if there + * are no more admins, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which these admins belong + * iterationId the iteration ID of this iteration + * juserObject the user object in which to fill the values of this admin + * returns 0 if no more admins, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getBosAdminsNext (JNIEnv *env, jclass cls, + jint cellHandle, + jint iterationId, + jobject juserObject ) { + + afs_status_t ast; + char *admin; + jstring jadmin; + + admin = (char *) malloc( sizeof(char)*BOS_MAX_NAME_LEN); + + if( !admin ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !bos_AdminGetNext( (void *) iterationId, admin, &ast ) ) { + free( admin ); + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + jadmin = (*env)->NewStringUTF(env, admin); + + if( userCls == 0 ) { + internal_getUserClass( env, juserObject ); + } + + (*env)->SetObjectField(env, juserObject, user_nameField, jadmin); + + getUserInfoChar( env, cellHandle, admin, juserObject ); + (*env)->SetBooleanField( env, juserObject, user_cachedInfoField, TRUE ); + + free( admin ); + return 1; + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_getBosAdminsDone (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + + if( !bos_AdminGetDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Returns the total number of keys hosted by the server denoted by + * serverHandle. + * + * env the Java environment + * cls the current Java class + * serverHandle the vos handle of the server to which the + * keys belong + * returns total number of keys + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getKeyCount (JNIEnv *env, jclass cls, + jint serverHandle) { + + afs_status_t ast; + void *iterationId; + bos_KeyInfo_t keyEntry; + int i = 0; + + if( !bos_KeyGetBegin( (void *) serverHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return -1; + } + + while ( bos_KeyGetNext( (void *) iterationId, &keyEntry, &ast ) ) i++; + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Begin the process of getting the keys of a server. Returns + * an iteration ID to be used by subsequent calls to + * getKeysNext and getKeysDone. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the keys belong + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getKeysBegin (JNIEnv *env, jclass cls, + jint serverHandle) { + + afs_status_t ast; + void *iterationId; + + if( !bos_KeyGetBegin( (void *) serverHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return (jint) iterationId; + +} + +/** + * Returns the next key of the server. Returns 0 if there + * are no more keys, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * jkeyObject a Key object, in which to fill in the + * properties of the next key. + * returns 0 if there are no more keys, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getKeysNext (JNIEnv *env, jclass cls, + jint iterationId, + jobject jkeyObject) { + + afs_status_t ast; + bos_KeyInfo_t keyEntry; + + if( !bos_KeyGetNext( (void *) iterationId, &keyEntry, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + fillKeyInfo( env, jkeyObject, keyEntry ); + + // get the class fields if need be + if( keyCls == 0 ) { + internal_getKeyClass( env, jkeyObject ); + } + + (*env)->SetBooleanField( env, jkeyObject, key_cachedInfoField, TRUE ); + + return 1; + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_getKeysDone (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + + if( !bos_KeyGetDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Returns the total number of processes hosted by the server denoted by + * serverHandle. + * + * env the Java environment + * cls the current Java class + * serverHandle the vos handle of the server to which the + * processes belong + * returns total number of processes + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getProcessCount (JNIEnv *env, jclass cls, + jint serverHandle) { + + afs_status_t ast; + void *iterationId; + char *process; + jstring jprocess; + int i = 0; + + if( !bos_ProcessNameGetBegin( (void *) serverHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return -1; + } + + process = (char *) malloc( sizeof(char)*BOS_MAX_NAME_LEN ); + + if( !process ) { + throwAFSException( env, JAFSADMNOMEM ); + return -1; + } + + while ( bos_ProcessNameGetNext( (void *) iterationId, process, &ast ) ) i++; + + free( process ); + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Begin the process of getting the processes on a server. Returns + * an iteration ID to be used by subsequent calls to + * getProcessesNext and getProcessesDone. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the + * processes belong + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getProcessesBegin (JNIEnv *env, jclass cls, + jint serverHandle) { + + afs_status_t ast; + void *iterationId; + + if( !bos_ProcessNameGetBegin( (void *) serverHandle, &iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + return (jint) iterationId; + +} + +/** + * Returns the next process of the server. Returns null + * if there are no more processes. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next process of the cell + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Server_getProcessesNextString (JNIEnv *env, + jclass cls, + jint iterationId) { + + afs_status_t ast; + jstring jprocess; + char *process = (char *) malloc( sizeof(char)*BOS_MAX_NAME_LEN ); + + if( !process ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !bos_ProcessNameGetNext( (void *) iterationId, process, &ast ) ) { + free( process ); + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + jprocess = (*env)->NewStringUTF(env, process); + free( process ); + return jprocess; + +} + +/** + * Fills the next process object of the server. Returns 0 if there + * are no more processes, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * serverHandle the handle of the BOS server that hosts the process + * iterationId the iteration ID of this iteration + * jprocessObject the Process object in which to fill the + * values of the next process + * returns 0 if there are no more processes, != otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Server_getProcessesNext (JNIEnv *env, jclass cls, + jint serverHandle, + jint iterationId, + jobject jprocessObject) { + + afs_status_t ast; + char *process = (char *) malloc( sizeof(char)*BOS_MAX_NAME_LEN ); + jstring jprocess; + + if( !process ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !bos_ProcessNameGetNext( (void *) iterationId, process, &ast ) ) { + if( ast == ADMITERATORDONE ) { + return 0; + } else { + free( process ); + throwAFSException( env, ast ); + return 0; + } + } + + // get the class fields if need be + if( processCls == 0 ) { + internal_getProcessClass( env, jprocessObject ); + } + + jprocess = (*env)->NewStringUTF(env, process); + (*env)->SetObjectField(env, jprocessObject, process_nameField, jprocess); + + getProcessInfoChar( env, (void *) serverHandle, process, jprocessObject ); + + (*env)->SetBooleanField( env, jprocessObject, + process_cachedInfoField, TRUE ); + + free( process ); + return 1; + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_getProcessesDone (JNIEnv *env, jclass cls, + jint iterationId) { + + afs_status_t ast; + + if( !bos_ProcessNameGetDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Salvages (restores consistency to) a volume, partition, or server + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * serverHandle the bos handle of the server on which the + * volume resides + * jpartName the name of the partition to salvage, + * can be null only if volName is + * null + * jvolName the name of the volume to salvage, + * can be null + * numSalvagers the number of salvager processes to run in parallel + * jtempDir directory to place temporary files, can be + * null + * jlogFile where salvager log will be written, can be + * null + * inspectAllVolumes whether or not to inspect all volumes, + * not just those marked as active at crash + * removeBadlyDamaged whether or not to remove a volume if it's + * badly damaged + * writeInodes whether or not to record a list of inodes modified + * writeRootInodes whether or not to record a list of AFS + * inodes owned by root + * forceDirectory whether or not to salvage an entire directory + * structure + * forceBlockReads whether or not to force the salvager to read + * the partition + * one block at a time and skip badly damaged + * blocks. Use if partition has disk errors + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_salvage (JNIEnv *env, jclass cls, + jint cellHandle, jint serverHandle, + jstring jpartName, jstring jvolName, + jint numSalvagers, jstring jtempDir, + jstring jlogFile, + jboolean inspectAllVolumes, + jboolean removeBadlyDamaged, + jboolean writeInodes, + jboolean writeRootInodes, + jboolean forceDirectory, + jboolean forceBlockReads) { + + afs_status_t ast; + const char *partName; + const char *volName; + const char *tempDir; + const char *logFile; + vos_force_t force; + bos_SalvageDamagedVolumes_t sdv; + bos_WriteInodes_t wi; + bos_WriteRootInodes_t wri; + bos_ForceDirectory_t forceD; + bos_ForceBlockRead_t forceBR; + + // convert strings + if( jpartName != NULL ) { + partName = (*env)->GetStringUTFChars(env, jpartName, 0); + if( !partName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + partName = NULL; + } + if( jvolName != NULL ) { + volName = (*env)->GetStringUTFChars(env, jvolName, 0); + if( !volName ) { + if( partName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpartName, partName); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + volName = NULL; + } + if( jtempDir != NULL ) { + tempDir = (*env)->GetStringUTFChars(env, jtempDir, 0); + if( !tempDir ) { + if( partName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpartName, partName); + } + if( volName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolName, volName); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + tempDir = NULL; + } + if( jlogFile != NULL ) { + logFile = (*env)->GetStringUTFChars(env, jlogFile, 0); + if( !logFile ) { + if( partName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpartName, partName); + } + if( volName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolName, volName); + } + if( tempDir != NULL ) { + (*env)->ReleaseStringUTFChars(env, jtempDir, tempDir); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + logFile = NULL; + } + + // deal with booleans + if( inspectAllVolumes ) { + force = VOS_FORCE; + } else { + force = VOS_NORMAL; + } + if( removeBadlyDamaged ) { + sdv = BOS_DONT_SALVAGE_DAMAGED_VOLUMES; + } else { + sdv = BOS_SALVAGE_DAMAGED_VOLUMES; + } + if( writeInodes ) { + wi = BOS_SALVAGE_WRITE_INODES; + } else { + wi = BOS_SALVAGE_DONT_WRITE_INODES; + } + if( writeRootInodes ) { + wri = BOS_SALVAGE_WRITE_ROOT_INODES; + } else { + wri = BOS_SALVAGE_DONT_WRITE_ROOT_INODES; + } + if( forceDirectory ) { + forceD = BOS_SALVAGE_FORCE_DIRECTORIES; + } else { + forceD = BOS_SALVAGE_DONT_FORCE_DIRECTORIES; + } + if( forceBlockReads ) { + forceBR = BOS_SALVAGE_FORCE_BLOCK_READS; + } else { + forceBR = BOS_SALVAGE_DONT_FORCE_BLOCK_READS; + } + + //salvage! + if( !bos_Salvage( (void *) cellHandle, (void *) serverHandle, partName, + volName, (int) numSalvagers, tempDir, logFile, force, sdv, + wi, wri, forceD, forceBR, &ast ) ) { + if( partName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpartName, partName); + } + if( volName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolName, volName); + } + if( tempDir != NULL ) { + (*env)->ReleaseStringUTFChars(env, jtempDir, tempDir); + } + if( logFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jlogFile, logFile); + } + throwAFSException( env, ast ); + return; + } + + // release strings + if( partName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpartName, partName); + } + if( volName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolName, volName); + } + if( tempDir != NULL ) { + (*env)->ReleaseStringUTFChars(env, jtempDir, tempDir); + } + if( logFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jlogFile, logFile); + } + +} + +/** + * Fills in the restart time fields of the given Server + * object. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the key belongs + * jtype whether to get the general or binary restart. + * Acceptable values are: + * org_opemafs_jafs_Server_RESTART_BINARY + * org_opemafs_jafs_Server_RESTART_GENERAL + * execTime the ExecutableTime object, in which + * to fill the restart time fields + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_getRestartTime + (JNIEnv *env, jclass cls, jint serverHandle, jint jtype, jobject exectime) +{ + afs_status_t ast; + bos_Restart_t type; + bos_RestartTime_t time; + jfieldID hourField; + jfieldID minField; + jfieldID secField; + jfieldID dayField; + jfieldID neverField; + jfieldID nowField; + + // get the class fields if need be + if( exectimeCls == 0 ) { + internal_getExecTimeClass( env, exectime ); + } + + if( jtype == org_openafs_jafs_Server_RESTART_BINARY ) { + type = BOS_RESTART_DAILY; + } else { + type = BOS_RESTART_WEEKLY; + } + + hourField = exectime_HourField; + minField = exectime_MinField; + secField = exectime_SecField; + dayField = exectime_DayField; + neverField = exectime_NeverField; + nowField = exectime_NowField; + + if( !bos_ExecutableRestartTimeGet( (void *) serverHandle, type, + &time, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + // set now + (*env)->SetBooleanField(env, exectime, nowField, + (time.mask & BOS_RESTART_TIME_NOW) ); + + // set never + (*env)->SetBooleanField(env, exectime, neverField, + (time.mask & BOS_RESTART_TIME_NEVER) ); + + // set hour + (*env)->SetShortField(env, exectime, hourField, time.hour ); + + // set minute + (*env)->SetShortField(env, exectime, minField, time.min ); + + // set second + (*env)->SetShortField(env, exectime, secField, time.sec ); + + // set day + if( time.mask & BOS_RESTART_TIME_DAY ) { + (*env)->SetShortField(env, exectime, dayField, time.day ); + } else { + (*env)->SetShortField(env, exectime, dayField, (jshort) -1 ); + } + +} + +/** + * Sets the restart time of the bos server. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the key belongs + * jtype whether this is to be a general or binary restart. + * Acceptable values are: + * org_opemafs_jafs_Server_RESTART_BINARY + * org_opemafs_jafs_Server_RESTART_GENERAL + * executableTime the ExecutableTime object containing the + * desired information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_setRestartTime (JNIEnv *env, jclass cls, + jint serverHandle, jint jtype, + jobject exectime ) { + + afs_status_t ast; + bos_Restart_t type; + bos_RestartTime_t time; + jboolean doHour; + jboolean doMinute; + jboolean doSecond; + jboolean doDay; + jboolean doNever; + jboolean doNow; + jshort hour; + jshort minute; + jshort second; + jshort day; + jfieldID hourField; + jfieldID minField; + jfieldID secField; + jfieldID dayField; + jfieldID neverField; + jfieldID nowField; + + // get the class fields if need be + if( exectimeCls == 0 ) { + internal_getExecTimeClass( env, exectime ); + } + + if( jtype == org_openafs_jafs_Server_RESTART_BINARY ) { + type = BOS_RESTART_DAILY; + } else { + type = BOS_RESTART_WEEKLY; + } + + hourField = exectime_HourField; + minField = exectime_MinField; + secField = exectime_SecField; + dayField = exectime_DayField; + neverField = exectime_NeverField; + nowField = exectime_NowField; + + hour = (*env)->GetShortField(env, exectime, hourField ); + if( hour != 0 ) { + doHour = TRUE; + } else { + doHour = FALSE; + } + minute = (*env)->GetShortField(env, exectime, minField ); + if( minute != 0 ) { + doMinute = TRUE; + } else { + doMinute = FALSE; + } + second = (*env)->GetShortField(env, exectime, secField ); + if( second != 0 ) { + doSecond = TRUE; + } else { + doSecond = FALSE; + } + day = (*env)->GetShortField(env, exectime, dayField ); + if( day != -1 ) { + doDay = TRUE; + } else { + doDay = FALSE; + } + doNever = (*env)->GetBooleanField(env, exectime, neverField ); + doNow = (*env)->GetBooleanField(env, exectime, nowField ); + + bzero(&time, sizeof(time)); + + if( jtype == org_openafs_jafs_Server_RESTART_BINARY ) { + type = BOS_RESTART_DAILY; + } else { + type = BOS_RESTART_WEEKLY; + } + + if( doHour ) { + time.mask |= BOS_RESTART_TIME_HOUR; + } + if( doMinute ) { + time.mask |= BOS_RESTART_TIME_MINUTE; + } + if( doSecond ) { + time.mask |= BOS_RESTART_TIME_SECOND; + } + if( doDay ) { + time.mask |= BOS_RESTART_TIME_DAY; + } + if( doNever ) { + time.mask |= BOS_RESTART_TIME_NEVER; + } + if( doNow ) { + time.mask |= BOS_RESTART_TIME_NOW; + } + + time.hour = hour; + time.min = minute; + time.sec = second; + time.day = day; + + if( !bos_ExecutableRestartTimeSet( (void *) serverHandle, type, + time, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Synchronizes a particular server with the volume location database. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the server belongs + * serverHandle the vos handle of the server + * partition the id of the partition to sync, can be -1 to ignore + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_syncServerWithVLDB (JNIEnv *env, jclass cls, + jint cellHandle, + jint serverHandle, + jint partition) { + + afs_status_t ast; + int *part; + + if( partition == -1 ) { + part = NULL; + } else { + part = (int *) &partition; + } + + if( !vos_ServerSync( (void *) cellHandle, (void *) serverHandle, + NULL, part, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Synchronizes the volume location database with a particular server. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the server belongs + * serverHandle the vos handle of the server + * partition the id of the partition to sync, can be -1 to ignore + * forceDeletion whether or not to force the deletion of bad volumes + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_syncVLDBWithServer (JNIEnv *env, jclass cls, + jint cellHandle, + jint serverHandle, + jint partition, + jboolean forceDeletion) { + + afs_status_t ast; + int *part; + vos_force_t force; + + if( partition == -1 ) { + part = NULL; + } else { + part = (int *) &partition; + } + + if( forceDeletion ) { + force = VOS_FORCE; + } else { + force = VOS_NORMAL; + } + + if( !vos_VLDBSync( (void *) cellHandle, (void *) serverHandle, NULL, part, + force, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Start all server processes. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the + * processes belong + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_startAllProcesses (JNIEnv *env, jclass cls, + jint serverHandle) { + + afs_status_t ast; + + if( !bos_ProcessAllStart( (void *) serverHandle, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Stop all server processes. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the + * processes belong + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_stopAllProcesses (JNIEnv *env, jclass cls, + jint serverHandle) { + + afs_status_t ast; + + if( !bos_ProcessAllStop( (void *) serverHandle, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Restart all server processes. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the + * processes belong + * restartBosServer whether or not to restart the bos server as well + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_restartAllProcesses (JNIEnv *env, jclass cls, + jint serverHandle, + jboolean restartBosServer) { + + afs_status_t ast; + bos_RestartBosServer_t rbs; + + if( restartBosServer ) { + rbs = BOS_RESTART_BOS_SERVER; + } else { + rbs = BOS_DONT_RESTART_BOS_SERVER; + } + + if( !bos_ProcessAllStopAndRestart( (void *) serverHandle, rbs, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Retrieves a specified bos log from a server. Right now this + * method will simply return a huge String containing the log, but + * hopefully we can devise a better way to make this work more efficiently. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the key belongs + * jlogFile the full path and name of the desired bos log + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_Server_getLog(JNIEnv *env, jclass cls, + jint serverHandle, jstring jlogFile) { + + afs_status_t ast; + const char *logFile; + char *logData; + unsigned long currInLogSize = 1; + unsigned long currOutLogSize = 0; + jstring logOut; + + if( jlogFile != NULL ) { + logFile = (*env)->GetStringUTFChars(env, jlogFile, 0); + if( !logFile ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + logFile = NULL; + } + + logData = (char *) malloc( sizeof(char)*currInLogSize ); + if( !logData ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + // check how big the log is . . . + if( !bos_LogGet( (void *) serverHandle, logFile, + &currOutLogSize, logData, &ast ) ) { + // anything but not enough room in buffer + if( ast != ADMMOREDATA ) { + free( logData ); + if( logFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jlogFile, logFile); + } + throwAFSException( env, ast ); + return NULL; + } + } + + free( logData ); + + // increase log size (plus one for terminator) + currInLogSize = currOutLogSize + 1; + // allocate buffer + logData = (char *) malloc( sizeof(char)*currInLogSize ); + if( !logData ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !logData ) { + // memory exception + if( logFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jlogFile, logFile); + } + throwAFSException( env, ast ); + return NULL; + } + + // get the log for real + if( !bos_LogGet( (void *) serverHandle, logFile, &currOutLogSize, + logData, &ast ) ) { + free( logData ); + if( logFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jlogFile, logFile); + } + (*env)->ReleaseStringUTFChars(env, jlogFile, logFile); + throwAFSException( env, ast ); + return NULL; + } + + logData[currOutLogSize] == '\0'; + + logOut = (*env)->NewStringUTF(env, logData); + + free( logData ); + if( logFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jlogFile, logFile); + } + return logOut; + +} + + +/** + * Executes any command on the specified server. + * + * env the Java environment + * cls the current Java class + * serverHandle the bos handle of the server to which the key belongs + * jcommand the text of the commmand to execute + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_executeCommand (JNIEnv *env, jclass cls, + jint serverHandle, + jstring jcommand) { + + afs_status_t ast; + const char *command; + + if( jcommand != NULL ) { + command = (*env)->GetStringUTFChars(env, jcommand, 0); + if( !command ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + command = NULL; + } + + if( !bos_CommandExecute( (void *) serverHandle, command, &ast ) ) { + if( command != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcommand, command); + } + throwAFSException( env, ast ); + return; + } + + if( command != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcommand, command); + } + +} + +// reclaim global memory being used by this portion +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Server_reclaimServerMemory (JNIEnv *env, jclass cls) { + + if( serverCls ) { + (*env)->DeleteGlobalRef(env, serverCls); + serverCls = 0; + } + +} + + + + + + + + + + + + + + + + + + + + diff --git a/src/JAVA/libjafs/User.c b/src/JAVA/libjafs/User.c new file mode 100644 index 0000000..cf57acb --- /dev/null +++ b/src/JAVA/libjafs/User.c @@ -0,0 +1,1484 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_User.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +///// definitions in Internal.c //////////////////// + +extern jclass userCls; +extern jfieldID user_nameField; +extern jfieldID user_ptsField; +extern jfieldID user_kasField; +//pts fields +extern jfieldID user_nameUidField; +extern jfieldID user_ownerUidField; +extern jfieldID user_creatorUidField; +extern jfieldID user_listStatusField; +extern jfieldID user_listGroupsOwnedField; +extern jfieldID user_listMembershipField; +extern jfieldID user_groupCreationQuotaField; +extern jfieldID user_groupMembershipCountField; +extern jfieldID user_ownerField; +extern jfieldID user_creatorField; +// kas fields +extern jfieldID user_adminSettingField; +extern jfieldID user_tgsSettingField; +extern jfieldID user_encSettingField; +extern jfieldID user_cpwSettingField; +extern jfieldID user_rpwSettingField; +extern jfieldID user_userExpirationField; +extern jfieldID user_lastModTimeField; +extern jfieldID user_lastModNameField; +extern jfieldID user_lastChangePasswordTimeField; +extern jfieldID user_maxTicketLifetimeField; +extern jfieldID user_keyVersionField; +extern jfieldID user_encryptionKeyField; +extern jfieldID user_keyCheckSumField; +extern jfieldID user_daysToPasswordExpireField; +extern jfieldID user_failLoginCountField; +extern jfieldID user_lockTimeField; +extern jfieldID user_lockedUntilField; + +extern jclass groupCls; +//extern jfieldID group_cellHandleField; +extern jfieldID group_nameField; +extern jfieldID group_cachedInfoField; + +////////////////////////////////////////////////////////////////// + +/** + * Creates the kas and pts entries for a new user. Pass in 0 for the uid + * if pts is to automatically assign the user id. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * juserName the name of the user to create + * jpassword the password for the new user + * uid the user id to assign to the user (0 to have one + * automatically assigned) + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_create + (JNIEnv *env, jclass cls, jint cellHandle, jstring juserName, + jstring jpassword, jint uid ) +{ + afs_status_t ast; + const char *userName; + const char *password; + kas_identity_p who = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + + if( !who ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + // convert java strings + if( juserName != NULL ) { + userName = (*env)->GetStringUTFChars(env, juserName, 0); + if( !userName ) { + free( who ); + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + userName = NULL; + } + if( jpassword != NULL ) { + password = (*env)->GetStringUTFChars(env, jpassword, 0); + if( !password ) { + free( who ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + password = NULL; + } + + // make sure the name is within the allowed bounds + if( userName != NULL && strlen( userName ) > KAS_MAX_NAME_LEN ) { + free( who ); + // release converted java strings + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return; + } + + // make sure name doesn't have ":" in it + if( userName != NULL && strchr( userName, ':' ) != (int) NULL ) { + free(who); + // release converted java strings + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + throwAFSException( env, PRBADNAM ); + return; + } + + // make sure the id isn't negative + if( uid < 0 ) { + free(who); + // release converted java strings + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + // use the "bad arg" error code even though it's an ID exception. + // There isn't a bad user ID error code + throwAFSException( env, PRBADARG ); + return; + } + + if( userName != NULL ) { + internal_makeKasIdentity( userName, who ); + } + + // create the kas entry + if (!kas_PrincipalCreate( (void *) cellHandle, NULL, who, + password, &ast ) ) { + free(who); + // release converted java strings + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + throwAFSException( env, ast ); + return; + } + + // create the pts entry - if there's an error, make sure to delete + // the kas entry + if( !pts_UserCreate( (void *) cellHandle, userName, (int *) &uid, &ast ) ) { + afs_status_t ast_kd; + kas_PrincipalDelete( (void *) cellHandle, NULL, who, &ast_kd ); + free( who ); + // release converted java strings + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + throwAFSException( env, ast ); + return; + } + + free( who ); + // release converted java strings + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + +} + +/** + * Deletes the pts and kas entry for a user. Deletes this user from the + * membership list of the groups to which it belonged, but does not delete + * the groups owned by this user. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * juserName the name of the user to delete + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_delete + (JNIEnv *env, jclass cls, jint cellHandle, jstring juserName ) +{ + afs_status_t ast; + const char *userName; + kas_identity_p who = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + int kas; + + if( !who ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( juserName != NULL ) { + userName = (*env)->GetStringUTFChars(env, juserName, 0); + if( !userName ) { + free( who ); + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + userName = NULL; + } + + // make sure the name is within the allowed bounds + if( userName != NULL && strlen( userName ) > KAS_MAX_NAME_LEN ) { + free( who ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return; + } + + if( userName != NULL ) { + internal_makeKasIdentity( userName, who ); + } + + // delete the kas entry + if( !kas_PrincipalDelete( (void *) cellHandle, NULL, who, &ast ) ) { + if( ast != KANOENT ) { + free(who); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + throwAFSException( env, ast ); + return; + } else { + kas = FALSE; + } + } + + //delete the pts entry + if( !pts_UserDelete( (void *) cellHandle, userName, &ast ) ) { + // throw exception if there was no such pts user only if there was + // also no such kas user + if( (ast == ADMPTSFAILEDNAMETRANSLATE && !kas ) || + ast != ADMPTSFAILEDNAMETRANSLATE ) { + free( who ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + throwAFSException( env, ast ); + return; + } + } + + free( who ); + // release converted java strings + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } +} + +/** + * Unlocks a user. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * juserName the name of the user to unlock + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_unlock + (JNIEnv *env, jclass cls, jint cellHandle, jstring juserName ) +{ + afs_status_t ast; + const char *userName; + kas_identity_p who = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + + if( !who ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + // convert java strings + if( juserName != NULL ) { + userName = (*env)->GetStringUTFChars(env, juserName, 0); + if( !userName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + userName = NULL; + } + + // make sure the name is within the allowed bounds + if( userName != NULL && strlen( userName ) > KAS_MAX_NAME_LEN ) { + free( who ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return; + } + + if( userName != NULL ) { + internal_makeKasIdentity( userName, who ); + } + + if( !kas_PrincipalUnlock( (void *) cellHandle, NULL, who, &ast ) ) { + free( who ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + throwAFSException( env, ast ); + return; + } + + free( who ); + // release converted java strings + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } +} + +/** + * Retrieve the information for the specified user and populate the + * given object + * + * env the Java environment + * cellHandle the handle of the cell to which the user belongs + * name the name of the user for which to get the info + * user the User object to populate with the info + */ +void getUserInfoChar + (JNIEnv *env, int cellHandle, const char *name, jobject user) +{ + jstring jowner; + jstring jcreator; + jstring jlastModName; + jstring jencryptionKey; + jboolean pts; + jboolean kas; + pts_UserEntry_t ptsEntry; + afs_status_t ast; + kas_identity_p who = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + kas_principalEntry_t kasEntry; + unsigned int lockedUntil; + + if( !who ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + // make sure the name is within the allowed bounds + if( name != NULL && strlen( name ) > KAS_MAX_NAME_LEN ) { + free( who ); + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return; + } + + if( name != NULL ) { + internal_makeKasIdentity( name, who ); + } + + // get all the field ids, if you haven't done so already + if( userCls == 0 ) { + internal_getUserClass( env, user ); + } + + // get the pts entry + if ( !pts_UserGet( (void *) cellHandle, name, &ptsEntry, &ast ) ) { + // if the user has no pts ptsEntry + if( ast == ADMPTSFAILEDNAMETRANSLATE ) { + pts = FALSE; + } else { + free( who ); + throwAFSException( env, ast ); + return; + } + } else { + pts = TRUE; + } + + + // get the kas entry + if( !kas_PrincipalGet( (void *) cellHandle, NULL, who, &kasEntry, &ast ) ) { + // no kas entry + if( ast == KANOENT ) { + if( !pts ) { + free( who ); + throwAFSException( env, ast ); + return; + } else { + kas = FALSE; + } + // other + } else { + free( who ); + throwAFSException( env, ast ); + return; + } + } else { + kas = TRUE; + } + + // get the lock status + if( kas && !kas_PrincipalLockStatusGet( (void *) cellHandle, NULL, who, + &lockedUntil, &ast ) ) { + free( who ); + throwAFSException( env, ast ); + return; + } + + (*env)->SetBooleanField(env, user, user_ptsField, pts); + (*env)->SetBooleanField(env, user, user_kasField, kas); + + // set the pts fields + if( pts ) { + (*env)->SetIntField(env, user, user_nameUidField, ptsEntry.nameUid); + (*env)->SetIntField(env, user, user_ownerUidField, ptsEntry.ownerUid); + (*env)->SetIntField(env, user, user_creatorUidField, + ptsEntry.creatorUid); + (*env)->SetIntField(env, user, user_groupCreationQuotaField, + ptsEntry.groupCreationQuota); + (*env)->SetIntField(env, user, user_groupMembershipCountField, + ptsEntry.groupMembershipCount); + + if( ptsEntry.listStatus == PTS_USER_OWNER_ACCESS ) { + (*env)->SetIntField(env, user, user_listStatusField, + org_openafs_jafs_User_USER_OWNER_ACCESS); + } else { + (*env)->SetIntField(env, user, user_listStatusField, + org_openafs_jafs_User_USER_ANYUSER_ACCESS); + } + if( ptsEntry.listGroupsOwned == PTS_USER_OWNER_ACCESS ) { + (*env)->SetIntField(env, user, user_listGroupsOwnedField, + org_openafs_jafs_User_USER_OWNER_ACCESS); + } else { + (*env)->SetIntField(env, user, user_listGroupsOwnedField, + org_openafs_jafs_User_USER_ANYUSER_ACCESS); + } + if( ptsEntry.listMembership == PTS_USER_OWNER_ACCESS ) { + (*env)->SetIntField(env, user, user_listMembershipField, + org_openafs_jafs_User_USER_OWNER_ACCESS); + } else { + (*env)->SetIntField(env, user, user_listMembershipField, + org_openafs_jafs_User_USER_ANYUSER_ACCESS); + } + + jowner = (*env)->NewStringUTF(env, ptsEntry.owner); + jcreator = (*env)->NewStringUTF(env, ptsEntry.creator); + + (*env)->SetObjectField(env, user, user_ownerField, jowner); + (*env)->SetObjectField(env, user, user_creatorField, jcreator); + + } + + // set the kas fields + if( kas ) { + char *convertedKey; + int i; + if( kasEntry.adminSetting == KAS_ADMIN ) { + (*env)->SetIntField(env, user, user_adminSettingField, + org_openafs_jafs_User_ADMIN); + } else { + (*env)->SetIntField(env, user, user_adminSettingField, + org_openafs_jafs_User_NO_ADMIN); + } + if( kasEntry.tgsSetting == TGS ) { + (*env)->SetIntField(env, user, user_tgsSettingField, + org_openafs_jafs_User_GRANT_TICKETS); + } else { + (*env)->SetIntField(env, user, user_tgsSettingField, + org_openafs_jafs_User_NO_GRANT_TICKETS); + } + if( kasEntry.encSetting != NO_ENCRYPT ) { + (*env)->SetIntField(env, user, user_encSettingField, + org_openafs_jafs_User_ENCRYPT); + } else { + (*env)->SetIntField(env, user, user_encSettingField, + org_openafs_jafs_User_NO_ENCRYPT); + } + if( kasEntry.cpwSetting == CHANGE_PASSWORD ) { + (*env)->SetIntField(env, user, user_cpwSettingField, + org_openafs_jafs_User_CHANGE_PASSWORD); + } else { + (*env)->SetIntField(env, user, user_cpwSettingField, + org_openafs_jafs_User_NO_CHANGE_PASSWORD); + } + if( kasEntry.rpwSetting == REUSE_PASSWORD ) { + (*env)->SetIntField(env, user, user_rpwSettingField, + org_openafs_jafs_User_REUSE_PASSWORD); + } else { + (*env)->SetIntField(env, user, user_rpwSettingField, + org_openafs_jafs_User_NO_REUSE_PASSWORD); + } + (*env)->SetIntField(env, user, user_userExpirationField, + kasEntry.userExpiration); + (*env)->SetIntField(env, user, user_lastModTimeField, + kasEntry.lastModTime); + (*env)->SetIntField(env, user, user_lastChangePasswordTimeField, + kasEntry.lastChangePasswordTime); + (*env)->SetIntField(env, user, user_maxTicketLifetimeField, + kasEntry.maxTicketLifetime); + (*env)->SetIntField(env, user, user_keyVersionField, + kasEntry.keyVersion); + (*env)->SetLongField(env, user, user_keyCheckSumField, + (unsigned int) kasEntry.keyCheckSum); + (*env)->SetIntField(env, user, user_daysToPasswordExpireField, + kasEntry.daysToPasswordExpire); + (*env)->SetIntField(env, user, user_failLoginCountField, + kasEntry.failLoginCount); + (*env)->SetIntField(env, user, user_lockTimeField, kasEntry.lockTime); + (*env)->SetIntField(env, user, user_lockedUntilField, lockedUntil); + + jlastModName = (*env)->NewStringUTF(env, + kasEntry.lastModPrincipal.principal); + (*env)->SetObjectField(env, user, user_lastModNameField, jlastModName); + + convertedKey = (char *) malloc( sizeof(char *)* + (sizeof(kasEntry.key.key)*4+1) ); + if( !convertedKey ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + for( i = 0; i < sizeof(kasEntry.key.key); i++ ) { + sprintf( &(convertedKey[i*4]), "\\%0.3o", kasEntry.key.key[i] ); + } + jencryptionKey = (*env)->NewStringUTF(env, convertedKey); + (*env)->SetObjectField(env, user, user_encryptionKeyField, + jencryptionKey); + free( convertedKey ); + } + free(who); +} + +/** + * Fills in the information fields of the provided User. + * Fills in values based on the current pts and kas information of the user. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * jname the name of the user for which to get the information + * user the User object in which to fill in the + * information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_getUserInfo + (JNIEnv *env, jclass cls, jint cellHandle, jstring jname, jobject user) +{ + const char *name; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + getUserInfoChar( env, cellHandle, name, user ); + + // get class fields if need be + if( userCls == 0 ) { + internal_getUserClass( env, user ); + } + + // set name in case blank object + (*env)->SetObjectField(env, user, user_nameField, jname); + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } +} + +/** + * Sets the information values of this AFS user to be the parameter values. + * Sets both kas and pts fields. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * jname the name of the user for which to set the information + * user the User object containing the desired + * information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_setUserInfo + (JNIEnv *env, jclass cls, jint cellHandle, jstring jname, jobject user ) +{ + const char *name; + kas_identity_p who = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + pts_UserUpdateEntry_t ptsEntry; + afs_status_t ast; + kas_admin_t isAdmin; + kas_tgs_t grantTickets; + kas_enc_t canEncrypt; + kas_cpw_t canChangePassword; + kas_rpw_t passwordReuse; + unsigned int expirationDate; + unsigned int maxTicketLifetime; + unsigned int passwordExpires; + unsigned int failedPasswordAttempts; + unsigned int failedPasswordLockTime; + int kas; + int pts; + + if( !who ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + // make sure the name is within the allowed bounds + if( name != NULL && strlen( name ) > KAS_MAX_NAME_LEN ) { + free( who ); + (*env)->ReleaseStringUTFChars(env, jname, name); + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return; + } + + if( name != NULL ) { + internal_makeKasIdentity( name, who ); + } + + // get class fields if need be + if( userCls == 0 ) { + internal_getUserClass( env, user ); + } + + kas = (*env)->GetBooleanField(env, user, user_kasField); + pts = (*env)->GetBooleanField(env, user, user_ptsField); + + if( pts ) { + // set the pts fields: + ptsEntry.flag = PTS_USER_UPDATE_GROUP_CREATE_QUOTA | + PTS_USER_UPDATE_PERMISSIONS; + ptsEntry.groupCreationQuota = + (*env)->GetIntField(env, user, user_groupCreationQuotaField); + if( (*env)->GetIntField(env, user, user_listStatusField) == + org_openafs_jafs_User_USER_OWNER_ACCESS ) { + ptsEntry.listStatus = PTS_USER_OWNER_ACCESS; + } else { + ptsEntry.listStatus = PTS_USER_ANYUSER_ACCESS; + } + if( (*env)->GetIntField(env, user, user_listGroupsOwnedField) == + org_openafs_jafs_User_USER_OWNER_ACCESS ) { + ptsEntry.listGroupsOwned = PTS_USER_OWNER_ACCESS; + } else { + ptsEntry.listGroupsOwned = PTS_USER_ANYUSER_ACCESS; + } + if( (*env)->GetIntField(env, user, user_listMembershipField) == + org_openafs_jafs_User_USER_OWNER_ACCESS ) { + ptsEntry.listMembership = PTS_USER_OWNER_ACCESS; + } else { + ptsEntry.listMembership = PTS_USER_ANYUSER_ACCESS; + } + if( !pts_UserModify( (void *) cellHandle, name, &ptsEntry, &ast ) ) { + free( who ); + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + } + + if( kas ) { + // set the kas fields: + if( (*env)->GetIntField(env, user, user_adminSettingField) == + org_openafs_jafs_User_ADMIN ) { + isAdmin = KAS_ADMIN; + } else { + isAdmin = NO_KAS_ADMIN; + } + if( (*env)->GetIntField(env, user, user_tgsSettingField) == + org_openafs_jafs_User_GRANT_TICKETS ) { + grantTickets = TGS; + } else { + grantTickets = NO_TGS; + } + if( (*env)->GetIntField(env, user, user_encSettingField) == + org_openafs_jafs_User_ENCRYPT ) { + canEncrypt = 0; + } else { + canEncrypt = NO_ENCRYPT; + } + if( (*env)->GetIntField(env, user, user_cpwSettingField) == + org_openafs_jafs_User_CHANGE_PASSWORD ) { + canChangePassword = CHANGE_PASSWORD; + } else { + canChangePassword = NO_CHANGE_PASSWORD; + } + if( (*env)->GetIntField(env, user, user_rpwSettingField) == + org_openafs_jafs_User_REUSE_PASSWORD ) { + passwordReuse = REUSE_PASSWORD; + } else { + passwordReuse = NO_REUSE_PASSWORD; + } + expirationDate = (*env)->GetIntField(env, user, + user_userExpirationField); + maxTicketLifetime = (*env)->GetIntField(env, user, + user_maxTicketLifetimeField); + passwordExpires = (*env)->GetIntField(env, user, + user_daysToPasswordExpireField); + failedPasswordAttempts = (*env)->GetIntField(env, user, + user_failLoginCountField); + failedPasswordLockTime = (*env)->GetIntField(env, user, + user_lockTimeField); + + if( !kas_PrincipalFieldsSet( (void *) cellHandle, NULL, who, &isAdmin, + &grantTickets, &canEncrypt, + &canChangePassword, &expirationDate, + &maxTicketLifetime, &passwordExpires, + &passwordReuse, &failedPasswordAttempts, + &failedPasswordLockTime, &ast ) ) { + free( who ); + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + } + + free( who ); + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } +} + +/** + * Renames the given user. Does not update the info fields of the kas entry + * -- the calling code is responsible for that. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * joldName the name of the user to rename + * jnewName the new name for the user + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_rename + (JNIEnv *env, jclass cls, jint cellHandle, jstring joldName, jstring jnewName) +{ + + const char *oldName; + const char *newName; + kas_identity_p whoOld = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + kas_identity_p whoNew = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + kas_principalEntry_t kasEntry; + pts_UserEntry_t ptsEntry; + afs_status_t ast; + int kas; + + if( !whoOld || !whoNew ) { + if( whoOld ) { + free( whoOld ); + } + if( whoNew ) { + free( whoNew ); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( joldName != NULL ) { + oldName = (*env)->GetStringUTFChars(env, joldName, 0); + if( !oldName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + oldName = NULL; + } + if( jnewName != NULL ) { + newName = (*env)->GetStringUTFChars(env, jnewName, 0); + if( !newName ) { + if( oldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldName, oldName); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + newName = NULL; + } + + // make sure the names are within the allowed bounds + if( oldName != NULL && strlen( oldName ) > KAS_MAX_NAME_LEN ) { + free( whoOld ); + free( whoNew ); + if( oldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldName, oldName); + } + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return; + } + if( newName != NULL && strlen( newName ) > KAS_MAX_NAME_LEN ) { + free( whoOld ); + free( whoNew ); + if( oldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldName, oldName); + } + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return; + } + + if( oldName != NULL ) { + internal_makeKasIdentity( oldName, whoOld ); + } + if( newName != NULL ) { + internal_makeKasIdentity( newName, whoNew ); + } + + // retrieve the old kas info + if( !kas_PrincipalGet( (void *) cellHandle, NULL, whoOld, + &kasEntry, &ast ) ) { + if( ast != KANOENT ) { + free( whoOld ); + free( whoNew ); + if( oldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldName, oldName); + } + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } + throwAFSException( env, ast ); + return; + } else { + kas = FALSE; + } + } else { + kas = TRUE; + } + + if( kas ) { + // create a new kas entry + // temporarily set the password equal to the new name + if (!kas_PrincipalCreate( (void *) cellHandle, NULL, whoNew, + newName, &ast ) ) { + free( whoOld ); + free( whoNew ); + if( oldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldName, oldName); + } + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } + throwAFSException( env, ast ); + return; + } + + // set the password + ast = 0; + // For some reason kas_PrincipalKeySet doesn't set the return code + // correctly. It always returns 0. + // So instead of checking the return code, we see if there's an + // error in the status variable. + kas_PrincipalKeySet( (void *) cellHandle, NULL, whoNew, 0, + &(kasEntry.key), &ast ); + if( ast ) { + afs_status_t ast_kd; + kas_PrincipalDelete( (void *) cellHandle, NULL, whoNew, &ast_kd ); + free( whoOld ); + free( whoNew ); + if( oldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldName, oldName); + } + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } + throwAFSException( env, ast ); + return; + } + } + + // rename the pts entry + if( !pts_UserRename( (void *) cellHandle, oldName, newName, &ast ) ) { + // throw exception if there was no such pts user only if + // there was also no such kas user + if( (ast == ADMPTSFAILEDNAMETRANSLATE && !kas ) || + ast != ADMPTSFAILEDNAMETRANSLATE ) { + afs_status_t ast_kd; + if( kas ) { + kas_PrincipalDelete( (void *) cellHandle, NULL, whoNew, + &ast_kd ); + } + free( whoOld ); + free( whoNew ); + if( oldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldName, oldName); + } + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } + throwAFSException( env, ast ); + return; + } + } + + if( kas ) { + // delete the old kas entry + if( !kas_PrincipalDelete( (void *) cellHandle, NULL, whoOld, &ast ) ) { + free( whoOld ); + free( whoNew ); + if( oldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldName, oldName); + } + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } + throwAFSException( env, ast ); + return; + } + } + + free( whoOld ); + free( whoNew ); + if( oldName != NULL ) { + (*env)->ReleaseStringUTFChars(env, joldName, oldName); + } + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } +} + +/** + * Sets the password of the given user. Sets the key version to 0. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * juserName the name of the user for which to set the password + * jnewPassword the new password for the user + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_setPassword + (JNIEnv *env, jclass cls, jint cellHandle, jstring juserName, + jstring jnewPassword) +{ + afs_status_t ast; + char *cellName; + const char *userName; + const char *newPassword; + kas_encryptionKey_p newKey = + (kas_encryptionKey_p) malloc( sizeof(kas_encryptionKey_t) ); + kas_identity_p who = (kas_identity_p) malloc( sizeof(kas_identity_t) ); + + if( !who || !newKey ) { + if( who ) { + free( who ); + } + if( newKey ) { + free( newKey ); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( juserName != NULL ) { + userName = (*env)->GetStringUTFChars(env, juserName, 0); + if( !userName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + userName = NULL; + } + if( jnewPassword != NULL ) { + newPassword = (*env)->GetStringUTFChars(env, jnewPassword, 0); + if( !newPassword ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + newPassword = NULL; + } + + // make sure the name is within the allowed bounds + if( userName != NULL && strlen( userName ) > KAS_MAX_NAME_LEN ) { + free(who); + free( newKey ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( newPassword != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewPassword, newPassword); + } + throwAFSException( env, ADMPTSUSERNAMETOOLONG ); + return; + } + + if( !afsclient_CellNameGet( (void *) cellHandle, &cellName, &ast ) ) { + free(who); + free( newKey ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( newPassword != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewPassword, newPassword); + } + throwAFSException( env, ast ); + return; + } + + if( !kas_StringToKey( cellName, newPassword, newKey, &ast ) ) { + free(who); + free( newKey ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( newPassword != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewPassword, newPassword); + } + throwAFSException( env, ast ); + return; + } + + if( userName != NULL ) { + internal_makeKasIdentity( userName, who ); + } + + ast = 0; + // For some reason kas_PrincipalKeySet doesn't set the return code correctly. + // It always returns 0. + // So instead of checking the return code, we see if there's an error + // in the status variable. + kas_PrincipalKeySet( (void *) cellHandle, NULL, who, 0, newKey, &ast ); + if( ast ) { + free( who ); + free( newKey ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( newPassword != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewPassword, newPassword); + } + throwAFSException( env, ast ); + return; + } + + free( who ); + free( newKey ); + if( userName != NULL ) { + (*env)->ReleaseStringUTFChars(env, juserName, userName); + } + if( newPassword != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewPassword, newPassword); + } + +} + +/** + * Begin the process of getting the groups to which the user belongs. + * Returns an iteration ID to be used by subsequent calls to + * getUserGroupsNext and getUserGroupsDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * jname the name of the user for which to get the groups + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_User_getUserGroupsBegin + (JNIEnv *env, jclass cls, jint cellHandle, jstring jname) +{ + const char *name; + afs_status_t ast; + void *iterationId; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + if( !pts_UserMemberListBegin( (void *) cellHandle, name, &iterationId, + &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + + return (jint) iterationId; + +} + +/** + * Returns the next group to which the user belongs. Returns + * null if there are no more groups. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next group + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_User_getUserGroupsNextString + (JNIEnv *env, jclass cls, jint iterationId) +{ + afs_status_t ast; + char *groupName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + jstring jgroup; + + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_UserMemberListNext( (void *) iterationId, groupName, &ast ) ) { + free( groupName ); + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + jgroup = (*env)->NewStringUTF(env, groupName); + free( groupName ); + return jgroup; +} + +/** + * Fills the next group object of which the user belongs. Returns 0 if there + * are no more groups, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * iterationId the iteration ID of this iteration + * jgroupObject a Group object to be populated with the values of the + * next group + * returns 0 if there are no more users, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_User_getUserGroupsNext + (JNIEnv *env, jclass cls, jint cellHandle, jint iterationId, + jobject jgroupObject) +{ + afs_status_t ast; + char *groupName; + jstring jgroup; + + groupName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_UserMemberListNext( (void *) iterationId, groupName, &ast ) ) { + free( groupName ); + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + jgroup = (*env)->NewStringUTF(env, groupName); + + if( groupCls == 0 ) { + internal_getGroupClass( env, jgroupObject ); + } + + (*env)->SetObjectField(env, jgroupObject, group_nameField, jgroup); + + getGroupInfoChar( env, (void *) cellHandle, groupName, jgroupObject ); + (*env)->SetBooleanField( env, jgroupObject, group_cachedInfoField, TRUE ); + + free( groupName ); + return 1; + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_getUserGroupsDone + (JNIEnv *env, jclass cls, jint iterationId) +{ + afs_status_t ast; + + if( !pts_UserMemberListDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } +} + +/** + * Returns the total number of groups owned by the user. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * jname the name of the user for which to get the groups + * returns total number of groups owned by the user + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_User_getGroupsOwnedCount + (JNIEnv *env, jclass cls, jint cellHandle, jstring jname) +{ + afs_status_t ast; + void *iterationId; + char *groupName; + int i = 0; + + iterationId = + (void *) Java_org_openafs_jafs_User_getGroupsOwnedBegin( env, cls, + cellHandle, + jname ); + + groupName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return -1; + } + + while ( pts_OwnedGroupListNext( (void *) iterationId, groupName, &ast ) ) + i++; + + free( groupName ); + + if( ast != ADMITERATORDONE ) { + throwAFSException( env, ast ); + return -1; + } + + return i; +} + +/** + * Begin the process of getting the groups that a user or group owns. + * Returns an iteration ID to be used by subsequent calls to + * getGroupsOwnedNext and getGroupsOwnedDone. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the user belongs + * jname the name of the user or group for which to get the groups + * returns an iteration ID + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_User_getGroupsOwnedBegin + (JNIEnv *env, jclass cls, jint cellHandle, jstring jname) +{ + const char *name; + afs_status_t ast; + void *iterationId; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + if( !pts_OwnedGroupListBegin( (void *) cellHandle, name, + &iterationId, &ast ) ) { + if( jname != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return; + } + + if( jname != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + + return (jint) iterationId; + +} + +/** + * Returns the next group the user or group owns. Returns null + * if there are no more groups. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + * returns the name of the next group + */ +JNIEXPORT jstring JNICALL +Java_org_openafs_jafs_User_getGroupsOwnedNextString + (JNIEnv *env, jclass cls, jint iterationId) +{ + afs_status_t ast; + char *groupName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + jstring jgroup; + + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_OwnedGroupListNext( (void *) iterationId, groupName, &ast ) ) { + free( groupName ); + if( ast == ADMITERATORDONE ) { + return NULL; + } else { + throwAFSException( env, ast ); + return; + } + } + + jgroup = (*env)->NewStringUTF(env, groupName); + free( groupName ); + return jgroup; + +} + +/** + * Fills the next group object that the user or group owns. Returns 0 if + * there are no more groups, != 0 otherwise. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the users belong + * iterationId the iteration ID of this iteration + * jgroupObject a Group object to be populated with the values of the + * next group + * returns 0 if there are no more users, != 0 otherwise + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_User_getGroupsOwnedNext + (JNIEnv *env, jclass cls, jint cellHandle, jint iterationId, + jobject jgroupObject) +{ + afs_status_t ast; + char *groupName; + jstring jgroup; + + groupName = (char *) malloc( sizeof(char)*PTS_MAX_NAME_LEN); + + if( !groupName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + + if( !pts_OwnedGroupListNext( (void *) iterationId, groupName, &ast ) ) { + free( groupName ); + if( ast == ADMITERATORDONE ) { + return 0; + } else { + throwAFSException( env, ast ); + return 0; + } + } + + jgroup = (*env)->NewStringUTF(env, groupName); + + if( groupCls == 0 ) { + internal_getGroupClass( env, jgroupObject ); + } + + (*env)->SetObjectField(env, jgroupObject, group_nameField, jgroup); + + getGroupInfoChar( env, (void *) cellHandle, groupName, jgroupObject ); + (*env)->SetBooleanField( env, jgroupObject, group_cachedInfoField, TRUE ); + + free( groupName ); + return 1; + +} + +/** + * Signals that the iteration is complete and will not be accessed anymore. + * + * env the Java environment + * cls the current Java class + * iterationId the iteration ID of this iteration + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_getGroupsOwnedDone + (JNIEnv *env, jclass cls, jint iterationId) +{ + afs_status_t ast; + + if( !pts_OwnedGroupListDone( (void *) iterationId, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +// reclaim global memory being used by this portion +JNIEXPORT void JNICALL +Java_org_openafs_jafs_User_reclaimUserMemory + (JNIEnv *env, jclass cls) +{ + if( userCls ) { + (*env)->DeleteGlobalRef(env, userCls); + userCls = 0; + } + +} + + + diff --git a/src/JAVA/libjafs/UserToken.c b/src/JAVA/libjafs/UserToken.c new file mode 100644 index 0000000..86a91d2 --- /dev/null +++ b/src/JAVA/libjafs/UserToken.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_Token.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +pthread_mutex_t jafs_init_lock; +extern pthread_mutex_t jafs_login_lock; +extern int readCacheParms(char *afsMountPoint, char *afsConfDir, + char *afsCacheDir, int *cacheBlocks, + int *cacheFiles, int *cacheStatEntries, + int *dCacheSize, int *vCacheSize, int *chunkSize, + int *closeSynch, int *debug, int *nDaemons, + int *cacheFlags, char *logFile); + +/** + * Be carefull with the memory management: + * + * - For every GetStringUTFChars call the corresponding ReleaseStringUTFChars. + * - For every GetArrayElements call the corresponding + * ReleaseArrayElements + * - For every malloc call the corresponding free. + */ + +int osi_audit(void) +{ + return 0; +} + +JNIEXPORT void JNICALL Java_org_openafs_jafs_Token_callDebugger + (JNIEnv *env, jobject obj) +{ + fprintf(stderr, "callDebugger called\n"); + __asm__("int $0x3"); +} + +/** + * Initialize the user space library. + * + * The user space client must be initialized prior to any + * user space related methods, including: klog, unlog, relog, + * and shutdown. + * + * env the Java environment + * cls the current Java class + * + * throws AFSException + */ +JNIEXPORT void JNICALL Java_org_openafs_jafs_Token_initUserSpace + (JNIEnv *env, jclass cls) +{ + char afsMountPoint[100], afsConfDir[100], afsCacheDir[100], logFile[100]; + jfieldID fid; + int pagval; + + /* Initialize each init parameter with its associated default value */ + int cacheBlocks = 100000; + int cacheFiles = 12500; + int cacheStatEntries = 8192; + int dCacheSize = 11398; + int vCacheSize = 128; + int chunkSize = 0; + int closeSynch = 0; + int debug = 0; + int nDaemons = 3; + int cacheFlags = -1; + + /* Initialize each init parameter with its associated default value */ + strcpy(afsMountPoint, "/afs"); + strcpy(afsConfDir, "/usr/afswsp/etc"); + strcpy(afsCacheDir, "/usr/afswsp/cache"); + strcpy(logFile, "/usr/afswsp/log/libjafs.log"); + + pthread_mutex_init(&jafs_init_lock, NULL); + pthread_mutex_lock(&jafs_init_lock); + + readCacheParms(afsMountPoint, afsConfDir, afsCacheDir, + &cacheBlocks, &cacheFiles, &cacheStatEntries, + &dCacheSize, &vCacheSize, &chunkSize, + &closeSynch, &debug, &nDaemons, &cacheFlags, + logFile); + + /* See cache.tune for configuration details */ + if (debug) { + fprintf(stderr, "uafs_Init(\"init_native\", \"%s\", \"%s\", \"%s\", + %d, %d, %d, + %d, %d, %d, + %d, %d, %d, %d, \"%s\");\n", + afsMountPoint, afsConfDir, afsCacheDir, + cacheBlocks, cacheFiles, cacheStatEntries, + dCacheSize, vCacheSize, chunkSize, + closeSynch, debug, nDaemons, cacheFlags, logFile); + } + uafs_Init("init_native", afsMountPoint, afsConfDir, afsCacheDir, + cacheBlocks, cacheFiles, cacheStatEntries, + dCacheSize, vCacheSize, chunkSize, + closeSynch, debug, nDaemons, cacheFlags, logFile); + + + /* make the initial pag the unauthenticated pag */ + afs_setpag(); + uafs_unlog(); + pagval = afs_getpag_val(); + + fid = (*env)->GetStaticFieldID(env, cls, "ANYUSER_PAG_ID", "I"); + if (fid == 0) { + fprintf(stderr, + "UserToken::init(): GetFieldID (ANYUSER_PAG_ID) failed\n"); + return; + } + + (*env)->SetStaticIntField(env, cls, fid, pagval); + + pthread_mutex_unlock(&jafs_init_lock); +} + +/** + * Authenticates a user in kas, and binds that authentication + * to the current process. + * + * env the Java environment + * obj the current Java class + * loginUTF the login to authenticate (expected as username@cellname) + * passwordUTF the password of the login + * id the existing pag (or 0) + * + * returns the assigned pag + * + * throws AFSException + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Token_klog (JNIEnv *env, jobject obj, + jstring jusername, jstring jpassword, jstring jcell, jint id) +{ + char *username; + char *password; + char *cell; + char *reason; + jint rc = -1; + int code; + + if( jcell != NULL ) { + cell = (char*) (*env)->GetStringUTFChars(env, jcell, 0); + if( !cell ) { + char *error = "UserToken::klog(): failed to get cell name\n"; + fprintf(stderr, error); + throwMessageException( env, error ); + return -1; + } + } else { + cell = NULL; + } + + if( jusername != NULL ) { + username = (char*) (*env)->GetStringUTFChars(env, jusername, 0); + if( !username ) { + char *error = "UserToken::klog(): failed to get username\n"; + (*env)->ReleaseStringUTFChars(env, jcell, cell); + fprintf(stderr, error); + throwMessageException( env, error ); + return -1; + } + } else { + username = NULL; + } + if( jpassword != NULL ) { + password = (char*) (*env)->GetStringUTFChars(env, jpassword, 0); + if( !password ) { + char *error = "UserToken::klog(): failed to get password\n"; + (*env)->ReleaseStringUTFChars(env, jcell, cell); + (*env)->ReleaseStringUTFChars(env, jusername, username); + fprintf(stderr, error); + throwMessageException( env, error ); + return -1; + } + } else { + password = NULL; + } + + if (id == 0) { + code = uafs_klog(username, cell, password, &reason); + } else { + /* Use existing PAG for this thread */ + code = afs_setpag_val(id); + if (code != 0) code = 180492L; /* KABADARGUMENT */ + if (!code) code = uafs_klog_nopag(username, cell, password, &reason); + } + + if (code != 0) { + if( cell != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcell, cell); + } + if( username != NULL ) { + (*env)->ReleaseStringUTFChars(env, jusername, username); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + fprintf(stderr, "UserToken::klog(): uafs_klog failed to cell %s: %s\n", + cell, reason); + fprintf(stderr, "code = %d\n", code); + throwAFSException( env, code ); + } + + /* Get the PAG we were assigned as the return value */ + rc = afs_getpag_val(); + + /* clean up */ + if( cell != NULL ) { + (*env)->ReleaseStringUTFChars(env, jcell, cell); + } + if( username != NULL ) { + (*env)->ReleaseStringUTFChars(env, jusername, username); + } + if( password != NULL ) { + (*env)->ReleaseStringUTFChars(env, jpassword, password); + } + + /* return PAG ID */ + return rc; +} + +/** + * Authenticates a user in KAS by a previously acquired PAG ID, and binds + * that authentication to the current thread or native process. + * + *

    This method does not require the user's username and password to + * fully authenticate their request. Rather it utilizes the user's PAG ID + * to recapture the user's existing credentials. + * + * env the Java environment + * obj the current Java class + * id User's current PAG (process authentication group) ID + * + * throws AFSException + */ +JNIEXPORT void JNICALL Java_org_openafs_jafs_Token_relog + (JNIEnv *env, jobject obj, jint id) +{ + int rc; + + rc = afs_setpag_val(id); + + if (rc != 0) { + throwAFSException( env, rc ); + } +} + +/** + * Authenticates a user in KAS, and binds that authentication + * to the current process. + * + * env the Java environment + * obj the current Java class + * + * throws AFSException + */ +JNIEXPORT void JNICALL Java_org_openafs_jafs_Token_unlog + (JNIEnv *env, jobject obj) +{ + int rc; + + rc = uafs_unlog(); + + if (rc != 0) { + throwAFSException( env, rc ); + } +} + +/** + * Inform the native library that the application is + * shutting down and will be unloading. + * + *

    The library will make a call informing the file server that it will + * no longer be available for callbacks. + * + * env the Java environment + * obj the current Java class + * + * throws AFSException + */ +JNIEXPORT void JNICALL Java_org_openafs_jafs_Token_shutdown + (JNIEnv *env, jobject obj) +{ + uafs_Shutdown(); +} + + + + diff --git a/src/JAVA/libjafs/Volume.c b/src/JAVA/libjafs/Volume.c new file mode 100644 index 0000000..de687b2 --- /dev/null +++ b/src/JAVA/libjafs/Volume.c @@ -0,0 +1,901 @@ +/* + * Copyright (c) 2001-2002 International Business Machines Corp. + * All rights reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Internal.h" +#include "org_openafs_jafs_Volume.h" + +#include +#include + +//// definitions in Internal.c ////////////////// + +extern jclass volumeCls; +extern jfieldID volume_nameField; +extern jfieldID volume_idField; +extern jfieldID volume_readWriteIdField; +extern jfieldID volume_readOnlyIdField; +extern jfieldID volume_backupIdField; +extern jfieldID volume_creationDateField; +extern jfieldID volume_lastAccessDateField; +extern jfieldID volume_lastUpdateDateField; +extern jfieldID volume_lastBackupDateField; +extern jfieldID volume_copyCreationDateField; +extern jfieldID volume_accessesSinceMidnightField; +extern jfieldID volume_fileCountField; +extern jfieldID volume_maxQuotaField; +extern jfieldID volume_currentSizeField; +extern jfieldID volume_statusField; +extern jfieldID volume_dispositionField; +extern jfieldID volume_typeField; + +////////////////////////////////////////////////////////// + +/** + * Extract the information from the given volume entry and populate the + * given object + * + * env the Java environment + * volume the Volume object to populate with the info + * volEntry the container of the volume's information + */ +extern void fillVolumeInfo( JNIEnv *env, jobject volume, + vos_volumeEntry_t volEntry ) { + + jstring jvolume; + + // get the class fields if need be + if( volumeCls == 0 ) { + internal_getVolumeClass( env, volume ); + } + + // set name, just in case it was a completely blank object + jvolume = (*env)->NewStringUTF(env, volEntry.name); + (*env)->SetObjectField(env, volume, volume_nameField, jvolume); + + (*env)->SetIntField(env, volume, volume_idField, volEntry.id); + (*env)->SetIntField(env, volume, volume_readWriteIdField, + volEntry.readWriteId); + (*env)->SetIntField(env, volume, volume_readOnlyIdField, + volEntry.readOnlyId); + (*env)->SetIntField(env, volume, volume_backupIdField, volEntry.backupId); + (*env)->SetLongField(env, volume, volume_creationDateField, + volEntry.creationDate); + (*env)->SetLongField(env, volume, volume_lastAccessDateField, + volEntry.lastAccessDate); + (*env)->SetLongField(env, volume, volume_lastUpdateDateField, + volEntry.lastUpdateDate); + (*env)->SetLongField(env, volume, volume_lastBackupDateField, + volEntry.lastBackupDate); + (*env)->SetLongField(env, volume, volume_copyCreationDateField, + volEntry.copyCreationDate); + (*env)->SetIntField(env, volume, volume_accessesSinceMidnightField, + volEntry.accessesSinceMidnight); + (*env)->SetIntField(env, volume, volume_fileCountField, volEntry.fileCount); + (*env)->SetIntField(env, volume, volume_maxQuotaField, volEntry.maxQuota); + (*env)->SetIntField(env, volume, volume_currentSizeField, + volEntry.currentSize); + + // set status variable + switch( volEntry.status ) { + case VOS_OK : + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_OK); + break; + case VOS_SALVAGE : + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_SALVAGE); + break; + case VOS_NO_VNODE: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_NO_VNODE); + break; + case VOS_NO_VOL: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_NO_VOL); + break; + case VOS_VOL_EXISTS: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_VOL_EXISTS); + break; + case VOS_NO_SERVICE: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_NO_SERVICE); + break; + case VOS_OFFLINE: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_OFFLINE); + break; + case VOS_ONLINE: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_ONLINE); + break; + case VOS_DISK_FULL: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_DISK_FULL); + break; + case VOS_OVER_QUOTA: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_OVER_QUOTA); + break; + case VOS_BUSY: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_BUSY); + break; + case VOS_MOVED: + (*env)->SetIntField(env, volume, volume_statusField, + org_openafs_jafs_Volume_VOLUME_MOVED); + break; + default: + throwAFSException( env, volEntry.status ); + } + + // set disposition variable + switch( volEntry.volumeDisposition ) { + case VOS_OK : + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_OK); + break; + case VOS_SALVAGE : + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_SALVAGE); + break; + case VOS_NO_VNODE: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_NO_VNODE); + break; + case VOS_NO_VOL: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_NO_VOL); + break; + case VOS_VOL_EXISTS: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_VOL_EXISTS); + break; + case VOS_NO_SERVICE: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_NO_SERVICE); + break; + case VOS_OFFLINE: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_OFFLINE); + break; + case VOS_ONLINE: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_ONLINE); + break; + case VOS_DISK_FULL: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_DISK_FULL); + break; + case VOS_OVER_QUOTA: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_OVER_QUOTA); + break; + case VOS_BUSY: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_BUSY); + break; + case VOS_MOVED: + (*env)->SetIntField(env, volume, volume_dispositionField, + org_openafs_jafs_Volume_VOLUME_MOVED); + break; + default: + throwAFSException( env, volEntry.volumeDisposition ); + } + + // set type variable + switch( volEntry.type ) { + case VOS_READ_WRITE_VOLUME: + (*env)->SetIntField(env, volume, volume_typeField, + org_openafs_jafs_Volume_VOLUME_TYPE_READ_WRITE); + break; + case VOS_READ_ONLY_VOLUME: + (*env)->SetIntField(env, volume, volume_typeField, + org_openafs_jafs_Volume_VOLUME_TYPE_READ_ONLY); + break; + case VOS_BACKUP_VOLUME: + (*env)->SetIntField(env, volume, volume_typeField, + org_openafs_jafs_Volume_VOLUME_TYPE_BACKUP); + break; + default: + throwAFSException( env, volEntry.type ); + } + +} + +/** + * Fills in the information fields of the provided Volume. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * serverHandle the vos handle of the server on which the volume + * resides + * partition the numeric id of the partition on which the volume + * resides + * volId the numeric id of the volume for which to get the info + * jvolumeObject the Volume object in which to fill in + * the information + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_getVolumeInfo (JNIEnv *env, jclass cls, + jint cellHandle, + jint serverHandle, + jint partition, jint volID, + jobject jvolumeObject) { + + afs_status_t ast; + vos_volumeEntry_t volEntry; + + // get the volume entry + if ( !vos_VolumeGet( (void *) cellHandle, (void *) serverHandle, NULL, + (unsigned int) partition, (unsigned int) volID, + &volEntry, &ast ) ) { + throwAFSException( env, ast ); + return; + } + + fillVolumeInfo( env, jvolumeObject, volEntry ); + +} + +/** + * Creates a volume on a particular partition. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell in which to create the volume + * serverHandle the vos handle of the server on which to create + * the volume + * partition the numeric id of the partition on which to create + * the volume + * jvolName the name of the volume to create + * quota the amount of space (in KB) to set as this volume's quota + * returns the numeric ID assigned to the volume + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Volume_create (JNIEnv *env, jclass cls, + jint cellHandle, jint serverHandle, + jint partition, jstring jvolName, + jint quota) { + + afs_status_t ast; + const char *volName; + int id; + + if( jvolName != NULL ) { + volName = (*env)->GetStringUTFChars(env, jvolName, 0); + if( !volName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + volName = NULL; + } + + if( !vos_VolumeCreate( (void *) cellHandle, (void *) serverHandle, NULL, + (unsigned int) partition, volName, + (unsigned int) quota, &id, &ast ) ) { + if( volName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolName, volName); + } + throwAFSException( env, ast ); + return; + } + + if( volName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolName, volName); + } + return (jint) id; + +} + +/** + * Deletes a volume from a particular partition. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell in which to delete the volume + * serverHandle the vos handle of the server from which to delete + * the volume + * partition the numeric id of the partition from which to delete + * the volume + * volId the numeric id of the volume to delete + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_delete (JNIEnv *env, jclass cls, + jint cellHandle, jint serverHandle, + jint partition, jint volID) { + + afs_status_t ast; + + if( !vos_VolumeDelete( (void *) cellHandle, (void *) serverHandle, NULL, + (unsigned int) partition, + (unsigned int) volID, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Creates a backup volume for the specified regular volume. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * volId the numeric id of the volume for which to create a backup + * volume + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_createBackupVolume (JNIEnv *env, jclass cls, + jint cellHandle, + jint volID) { + + afs_status_t ast; + + if( !vos_BackupVolumeCreate( (void *) cellHandle, NULL, + (unsigned int) volID, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Creates a read-only volume for the specified regular volume. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * serverHandle the vos handle of the server on which the read-only + * volume is to reside + * partition the numeric id of the partition on which the read-only + * volume is to reside + * volId the numeric id of the volume for which to + * create a read-only volume + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_createReadOnlyVolume (JNIEnv *env, jclass cls, + jint cellHandle, + jint serverHandle, + jint partition, + jint volID) { + + afs_status_t ast; + + if( !vos_VLDBReadOnlySiteCreate( (void *) cellHandle, (void *) serverHandle, + NULL, (unsigned int) partition, + (unsigned int) volID, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Deletes a read-only volume for the specified regular volume. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * serverHandle the vos handle of the server on which the read-only + * volume residea + * partition the numeric id of the partition on which the read-only + * volume resides + * volId the numeric read-write id of the volume for which to + * delete the read-only volume + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_deleteReadOnlyVolume (JNIEnv *env, jclass cls, + jint cellHandle, + jint serverHandle, + jint partition, + jint volID) { + + afs_status_t ast; + + if( !vos_VLDBReadOnlySiteDelete( (void *) cellHandle, (void *) serverHandle, + NULL, (unsigned int) partition, + (unsigned int) volID, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Changes the quota of the specified volume. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * serverHandle the vos handle of the server on which the volume + * resides + * partition the numeric id of the partition on which the volume + * resides + * volId the numeric id of the volume for which to change the quota + * newQuota the new quota (in KB) to assign the volume + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_changeQuota (JNIEnv *env, jclass cls, + jint cellHandle, + jint serverHandle, + jint partition, jint volID, + jint newQuota) { + + afs_status_t ast; + + if( !vos_VolumeQuotaChange( (void *) cellHandle, (void *) serverHandle, + NULL, (unsigned int) partition, + (unsigned int) volID, (unsigned int) newQuota, + &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Move the specified volume to a different site. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * fromServerHandle the vos handle of the server on which the volume + * currently resides + * fromPartition the numeric id of the partition on which the volume + * currently resides + * toServerHandle the vos handle of the server to which the volume + * should be moved + * toPartition the numeric id of the partition to which the volume + * should be moved + * volId the numeric id of the volume to move + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_move + (JNIEnv *env, jclass cls, jint cellHandle, jint fromServerHandle, + jint fromPartition, jint toServerHandle, jint toPartition, jint volID) +{ + afs_status_t ast; + + if( !vos_VolumeMove( (void *) cellHandle, NULL, (unsigned int) volID, + (void *) fromServerHandle, (unsigned int) fromPartition, + (void *) toServerHandle, (unsigned int) toPartition, + &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Releases the specified volume that has readonly volume sites. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * volId the numeric id of the volume to release + * forceComplete whether or not to force a complete release + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_release + (JNIEnv *env, jclass cls, jint cellHandle, jint volID, jboolean forceComplete) +{ + afs_status_t ast; + vos_force_t force; + + if( forceComplete ) { + force = VOS_FORCE; + } else { + force = VOS_NORMAL; + } + + if( !vos_VolumeRelease( (void *) cellHandle, NULL, (unsigned int) volID, + force, &ast )) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Dumps the specified volume to a file. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * serverHandle the vos handle of the server on which the volume + * resides + * partition the numeric id of the partition on which the + * volume resides + * volId the numeric id of the volume to dump + * startTime files with a modification time >= to this time will + * be dumped + * jdumpFile the full path of the file to which to dump + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_dump (JNIEnv *env, jclass cls, + jint cellHandle, jint serverHandle, + jint partition, jint volID, + jint startTime, jstring jdumpFile) { + + afs_status_t ast; + const char *dumpFile; + + if( jdumpFile != NULL ) { + dumpFile = (*env)->GetStringUTFChars(env, jdumpFile, 0); + if( !dumpFile ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + dumpFile = NULL; + } + + if( !vos_VolumeDump( (void *) cellHandle, (void *) serverHandle, NULL, + (unsigned int *) &partition, (unsigned int) volID, + (unsigned int) startTime, dumpFile, &ast ) ) { + if( dumpFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdumpFile, dumpFile); + } + throwAFSException( env, ast ); + return; + } + + if( dumpFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdumpFile, dumpFile); + } + +} + +/** + * Restores the specified volume from a dump file. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * serverHandle the vos handle of the server on which the volume is + * to reside + * partition the numeric id of the partition on which the volume is + * to reside + * volId the numeric id to assign the restored volume (can be 0) + * jvolName the name of the volume to restore as + * jdumpFile the full path of the dump file from which to restore + * incremental if true, restores an incremental dump over an existing + * volume (server and partition values must correctly + * indicate the current position of the existing volume), + * otherwise restores a full dump + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_restore (JNIEnv *env, jclass cls, + jint cellHandle, jint serverHandle, + jint partition, jint volID, + jstring jvolName, jstring jdumpFile, + jboolean incremental) { + + afs_status_t ast; + const char *volName; + const char *dumpFile; + int *volumeIDp; + vos_volumeRestoreType_t vrt; + + if( jvolName != NULL ) { + volName = (*env)->GetStringUTFChars(env, jvolName, 0); + if( !volName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + volName = NULL; + } + + if( jdumpFile != NULL ) { + dumpFile = (*env)->GetStringUTFChars(env, jdumpFile, 0); + if( !dumpFile ) { + if( volName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolName, volName); + } + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + dumpFile = NULL; + } + + if( volID == 0 ) { + volumeIDp = NULL; + } else { + volumeIDp = (int *) &volID; + } + + if( incremental ) { + vrt = VOS_RESTORE_INCREMENTAL; + } else { + vrt = VOS_RESTORE_FULL; + } + + if( !vos_VolumeRestore( (void *) cellHandle, (void *) serverHandle, NULL, + (unsigned int) partition, (unsigned int *) volumeIDp, + volName, dumpFile, vrt, &ast ) ) { + if( volName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolName, volName); + } + if( dumpFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdumpFile, dumpFile); + } + throwAFSException( env, ast ); + return; + } + + if( dumpFile != NULL ) { + (*env)->ReleaseStringUTFChars(env, jdumpFile, dumpFile); + } + if( volName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jvolName, volName); + } + +} + +/** + * Renames the specified read-write volume. + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * volId the numeric id of the read-write volume to rename + * jnewName the new name for the volume + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_rename (JNIEnv *env, jclass cls, + jint cellHandle, jint volID, + jstring jnewName) { + + afs_status_t ast; + const char *newName; + + if( jnewName != NULL ) { + newName = (*env)->GetStringUTFChars(env, jnewName, 0); + if( !newName ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + newName = NULL; + } + + if( !vos_VolumeRename( (void *) cellHandle, NULL, (unsigned int) volID, + newName, &ast ) ) { + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } + throwAFSException( env, ast ); + return; + } + + if( newName != NULL ) { + (*env)->ReleaseStringUTFChars(env, jnewName, newName); + } + +} + +/** + * "Mounts" the specified volume, bringing it online. + * + * env the Java environment + * cls the current Java class + * serverHandle the vos handle of the server on which the volume + * resides + * partition the numeric id of the partition on which the volume + * resides + * volId the numeric id of the volume to bring online + * sleepTime ? (not sure what this is yet, possibly a time to wait + * before brining it online) + * offline ? (not sure what this is either, probably the current + * status of the volume -- busy or offline) + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_mount (JNIEnv *env, jclass cls, + jint serverHandle, jint partition, + jint volID, jint sleepTime, + jboolean offline) { + + afs_status_t ast; + vos_volumeOnlineType_t volumeStatus; + + if( offline ) { + volumeStatus = VOS_ONLINE_OFFLINE; + } else { + volumeStatus = VOS_ONLINE_BUSY; + } + + if( !vos_VolumeOnline( (void *) serverHandle, NULL, (unsigned int) partition, + (unsigned int) volID, (unsigned int) sleepTime, + volumeStatus, &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * "Unmounts" the specified volume, bringing it offline. + * + * env the Java environment + * cls the current Java class + * serverHandle the vos handle of the server on which the volume + * resides + * partition the numeric id of the partition on which the volume + * resides + * volId the numeric id of the volume to bring offline + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_unmount (JNIEnv *env, jclass cls, + jint serverHandle, jint partition, + jint volID) { + + afs_status_t ast; + + if( !vos_VolumeOffline( (void *) serverHandle, NULL, + (unsigned int) partition, (unsigned int) volID, + &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Locks the VLDB entry specified volume + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell on which the volume resides + * volId the numeric id of the volume to lock + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_lock (JNIEnv *env, jclass cls, + jint cellHandle, jint volID ) { + + afs_status_t ast; + + if( !vos_VLDBEntryLock( (void *) cellHandle, NULL, (unsigned int) volID, + &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Unlocks the VLDB entry of the specified volume + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell on which the volume resides + * volId the numeric id of the volume to unlock + */ +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_unlock (JNIEnv *env, jclass cls, + jint cellHandle, jint volID) { + + afs_status_t ast; + + if( !vos_VLDBEntryUnlock( (void *) cellHandle, NULL, (unsigned int) volID, + &ast ) ) { + throwAFSException( env, ast ); + return; + } + +} + +/** + * Translates a volume name into a volume id + * + * env the Java environment + * cls the current Java class + * cellHandle the handle of the cell to which the volume belongs + * jname the name of the volume in question, cannot end in backup or + * readonly + * type the type of volume: read-write, read-only, or backup. + * Acceptable values are: + * org_openafs_jafs_Volume_VOLUME_TYPE_READ_WRITE + * org_openafs_jafs_Volume_VOLUME_TYPE_READ_ONLY + * org_openafs_jafs_Volume_VOLUME_TYPE_BACKUP + * returns the id of the volume in question + */ +JNIEXPORT jint JNICALL +Java_org_openafs_jafs_Volume_translateNameToID (JNIEnv *env, jclass cls, + jint cellHandle, + jstring jname, jint type) { + + afs_status_t ast; + const char *name; + vos_vldbEntry_t vldbEntry; + + if( jname != NULL ) { + name = (*env)->GetStringUTFChars(env, jname, 0); + if( !name ) { + throwAFSException( env, JAFSADMNOMEM ); + return; + } + } else { + name = NULL; + } + + // get the id + if( !vos_VLDBGet( (void *) cellHandle, NULL, NULL, name, + &vldbEntry, &ast ) ) { + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + throwAFSException( env, ast ); + return -1; + } + + if( name != NULL ) { + (*env)->ReleaseStringUTFChars(env, jname, name); + } + + if( type == org_openafs_jafs_Volume_VOLUME_TYPE_READ_WRITE ) { + return vldbEntry.volumeId[VOS_READ_WRITE_VOLUME]; + } else if( type == org_openafs_jafs_Volume_VOLUME_TYPE_READ_ONLY ) { + return vldbEntry.volumeId[VOS_READ_ONLY_VOLUME]; + } else { + return vldbEntry.volumeId[VOS_BACKUP_VOLUME]; + } + +} + + +// reclaim global memory being used by this portion +JNIEXPORT void JNICALL +Java_org_openafs_jafs_Volume_reclaimVolumeMemory (JNIEnv *env, jclass cls) { + + if( volumeCls ) { + (*env)->DeleteGlobalRef(env, volumeCls); + volumeCls = 0; + } + +} + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/JAVA/libjafs/etc/CacheConfig b/src/JAVA/libjafs/etc/CacheConfig new file mode 100644 index 0000000..e184b2e --- /dev/null +++ b/src/JAVA/libjafs/etc/CacheConfig @@ -0,0 +1,16 @@ +MountPoint /afs +ConfDir /usr/afswsp/etc +CacheDir /usr/afswsp/cache +LogFile /usr/afswsp/log/libjafs.log +CacheBlocks 40000 +CacheFiles 3000 +CacheStatEntries 3000 +DCacheSize 100 +VCacheSize 1000 +ChunkSize 0 +CloseSynch 0 +Debug 0 +NDaemons 3 +CacheFlags -1 + + diff --git a/src/JAVA/libjafs/etc/CacheConfig.100MB b/src/JAVA/libjafs/etc/CacheConfig.100MB new file mode 100644 index 0000000..e433ca1 --- /dev/null +++ b/src/JAVA/libjafs/etc/CacheConfig.100MB @@ -0,0 +1,16 @@ +MountPoint /afs +ConfDir /usr/afswsp/etc +CacheDir /usr/afswsp/cache +LogFile /usr/afswsp/log/libjafs.log +CacheBlocks 100000 +CacheFiles 6000 +CacheStatEntries 6000 +DCacheSize 250 +VCacheSize 2000 +ChunkSize 0 +CloseSynch 0 +Debug 0 +NDaemons 3 +CacheFlags -1 + + diff --git a/src/JAVA/libjafs/etc/CacheConfig.40MB b/src/JAVA/libjafs/etc/CacheConfig.40MB new file mode 100644 index 0000000..e184b2e --- /dev/null +++ b/src/JAVA/libjafs/etc/CacheConfig.40MB @@ -0,0 +1,16 @@ +MountPoint /afs +ConfDir /usr/afswsp/etc +CacheDir /usr/afswsp/cache +LogFile /usr/afswsp/log/libjafs.log +CacheBlocks 40000 +CacheFiles 3000 +CacheStatEntries 3000 +DCacheSize 100 +VCacheSize 1000 +ChunkSize 0 +CloseSynch 0 +Debug 0 +NDaemons 3 +CacheFlags -1 + + diff --git a/src/TechNotes-JavaAPI b/src/TechNotes-JavaAPI new file mode 100644 index 0000000..52ddd24 --- /dev/null +++ b/src/TechNotes-JavaAPI @@ -0,0 +1,94 @@ +Java API (Jafs): Technical Notes +----------------------------------------- + +Overview +-------- + +The Java API (Jafs) is a Java package with a shared library +written in C. It is meant for use by programmers who wish to develop +tools in Java for OpenAFS administration and use. This document briefly +outlines the architecture of Jafs. + +Shared library +-------------- + +The source code for the shared library resides in the src/JAVA/libjafs +directory. See the JAFS_README file in that directory for information +on how to compile this package. The code is broken up logically into +files by the type of AFS object they relate to (i.e. cell, user, volume, +etc.), which closely mirrors the different classes of the Java package. +This library is built on top of the libadmin and libuafs libraries, and +mainly serves as a translation layer between the Java package and the +OpenAFS code. It is closely tied to the Java package, in that it often +accesses the actual Java objects by calls up through JNI, in order to +retrieve or populate member fields of those objects. Also, if an error +occurs in this code or in another C library, a Java exception is +constructed with the appropriate error code, and is thrown back to the +Java layer to be dealt with. + +In order to provide user-level functions such as ACL setting and mount +point iteration, the shared library needs to be linked with a specialized +version of libuafs called libjuafs.a. Please view the README file in the +src/libuafs directory for more information regarding libjuafs and how it +is built. + +Java package +------------ + +The code for the org.openafs.jafs package resides in the +src/JAVA/org/openafs/jafs/ directory. It is broken into classes +in the same way that the OpenAFS file system breaks down into logical +components: Cell, User, Group, Server, Partition, Volume, Process, Key, +Token, ACL, and File. There are also classes for file input and +output streams, and specialized exception classes. + +Publicly, the developer only has access to these objects and their +instance functions, which provide a solid, object-oriented view of +OpenAFS administration and use. The first thing a programmer would do to +use this package in his or her code would be to construct a Token object by +giving it a cell name, a user name, and a password for that user. From +there, the programmer could easily construct a Cell object and then list, +for example, all the servers in a cell, create a new user, move a volume to +a different partition, etc. + +When one of these objects is constructed, it does not actually create +the corresponding component in OpenAFS. The object is supposed to +represent the object. If the programmer wants to actually create a +new user in OpenAFS, for example, he or she would construct a new User +object with the name of the user to create, and then explicitly call +the object's create method. + +When an object first accesses information about itself from OpenAFS +by calling down through JNI to the shared library, it saves the +information and will return it to the application on subsequent +requests. This minimizes the overhead of expensive JNI calls. This +saved information can be updated to reflect the most current state of +OpenAFS by calling the objects refresh method. + +There are usually two ways to list something: getting an array of the +names of the elements in the list, or getting an array of the actual +objects themselves. For example, the Cell object can provide the +programmer with an array of the names of all users in the cell, or +an array of actual User objects, with relevant member fields already set +to the correct values. + +Almost every method in the package declares AFSException in its +throws clause. This is thrown from the shared library whenever an +error occurs, and contains an OpenAFS error code as a member. The +programmer is expected to deal with these exceptions however they see fit. + +The native methods that act as the interface between the Java layer and +the shared library are declared protected, so they can be used directly +by developers who wish to subclass these classes for their applications +and possibly implement their own versions of the Java API calls. + +Known Issues +------------ + +Some issues not yet dealt with in this API include: + - Alternative methods of authentication, other than Kaserver (i.e. + Kerberos V). There has been some discussion about how to abstract + the User object to be more general, but so far it has not been + implemented. + - Access to VLDB functionality such as listing VLDB entries and + zapping volumes. diff --git a/src/config/Makefile.config.in b/src/config/Makefile.config.in index 09fd6f4..b92c828 100644 --- a/src/config/Makefile.config.in +++ b/src/config/Makefile.config.in @@ -62,6 +62,7 @@ SHLIB_SUFFIX = @SHLIB_SUFFIX@ SYS_NAME = @AFS_SYSNAME@ TOP_INCDIR = @TOP_INCDIR@ TOP_LIBDIR = @TOP_LIBDIR@ +TOP_JLIBDIR= @TOP_JLIBDIR@ TOP_OBJDIR = @TOP_OBJDIR@ TOP_SRCDIR = @TOP_SRCDIR@ TXLIBS = @TXLIBS@ -- 1.9.4