1 /* 2 * Copyright (c) 1990,1991 Regents of The University of Michigan. 3 * All Rights Reserved. 4 * 5 * Permission to use, copy, modify, and distribute this software and 6 * its documentation for any purpose and without fee is hereby granted, 7 * provided that the above copyright notice appears in all copies and 8 * that both that copyright notice and this permission notice appear 9 * in supporting documentation, and that the name of The University 10 * of Michigan not be used in advertising or publicity pertaining to 11 * distribution of the software without specific, written prior 12 * permission. This software is supplied as is without expressed or 13 * implied warranties of any kind. 14 * 15 * Research Systems Unix Group 16 * The University of Michigan 17 * c/o Mike Clark 18 * 535 W. William Street 19 * Ann Arbor, Michigan 20 * +1-313-763-0525 21 * netatalk@itd.umich.edu 22 */ 23 24 /*! 25 * @file 26 * @brief Part of Netatalk's AppleDouble implementatation 27 */ 28 29 #ifndef _ATALK_ADOUBLE_H 30 #define _ATALK_ADOUBLE_H 31 32 #ifdef HAVE_CONFIG_H 33 #include <config.h> 34 #endif 35 36 #include <atalk/standards.h> 37 38 #include <inttypes.h> 39 #include <sys/types.h> 40 #include <sys/stat.h> 41 #include <unistd.h> 42 #include <fcntl.h> 43 44 #include <sys/mman.h> 45 46 #include <sys/time.h> 47 48 #include <atalk/bstrlib.h> 49 50 /* version info */ 51 #define AD_VERSION2 0x00020000 52 #define AD_VERSION_EA 0x00020002 53 54 /* default */ 55 #define AD_VERSION AD_VERSION_EA 56 57 /* 58 * AppleDouble entry IDs. 59 */ 60 #define ADEID_DFORK 1 61 #define ADEID_RFORK 2 62 #define ADEID_NAME 3 63 #define ADEID_COMMENT 4 64 #define ADEID_ICONBW 5 65 #define ADEID_ICONCOL 6 66 #define ADEID_FILEI 7 /* v1, replaced by: */ 67 #define ADEID_FILEDATESI 8 /* this */ 68 #define ADEID_FINDERI 9 69 #define ADEID_MACFILEI 10 /* we don't use this */ 70 #define ADEID_PRODOSFILEI 11 /* we store prodos info here */ 71 #define ADEID_MSDOSFILEI 12 /* we don't use this */ 72 #define ADEID_SHORTNAME 13 73 #define ADEID_AFPFILEI 14 /* where the rest of the FILEI info goes */ 74 #define ADEID_DID 15 75 76 /* netatalk private note fileid reused DID */ 77 #define ADEID_PRIVDEV 16 78 #define ADEID_PRIVINO 17 79 #define ADEID_PRIVSYN 18 /* in synch with database */ 80 #define ADEID_PRIVID 19 81 #define ADEID_MAX (ADEID_PRIVID + 1) 82 83 /* These are the real ids for these entries, as stored in the adouble file */ 84 #define AD_DEV 0x80444556 85 #define AD_INO 0x80494E4F 86 #define AD_SYN 0x8053594E 87 #define AD_ID 0x8053567E 88 89 /* magic */ 90 #define AD_APPLESINGLE_MAGIC 0x00051600 91 #define AD_APPLEDOUBLE_MAGIC 0x00051607 92 #define AD_MAGIC AD_APPLEDOUBLE_MAGIC 93 94 /* sizes of relevant entry bits */ 95 #define ADEDLEN_MAGIC 4 96 #define ADEDLEN_VERSION 4 97 #define ADEDLEN_FILLER 16 98 #define ADEDLEN_NENTRIES 2 99 #define AD_HEADER_LEN (ADEDLEN_MAGIC + ADEDLEN_VERSION + ADEDLEN_FILLER + ADEDLEN_NENTRIES) /* 26 */ 100 #define AD_ENTRY_LEN 12 /* size of a single entry header */ 101 102 /* field widths */ 103 #define ADEDLEN_NAME 255 104 #define ADEDLEN_COMMENT 200 105 #define ADEDLEN_FILEI 16 106 #define ADEDLEN_FINDERI 32 107 #define ADEDLEN_FILEDATESI 16 108 #define ADEDLEN_SHORTNAME 12 /* length up to 8.3 */ 109 #define ADEDLEN_AFPFILEI 4 110 #define ADEDLEN_MACFILEI 4 111 #define ADEDLEN_PRODOSFILEI 8 112 #define ADEDLEN_MSDOSFILEI 2 113 #define ADEDLEN_DID 4 114 #define ADEDLEN_PRIVDEV 8 115 #define ADEDLEN_PRIVINO 8 116 #define ADEDLEN_PRIVSYN 8 117 #define ADEDLEN_PRIVID 4 118 119 #define ADEID_NUM_V2 13 120 #define ADEID_NUM_EA 8 121 #define ADEID_NUM_OSX 2 122 123 #define AD_DATASZ2 (AD_HEADER_LEN + ADEDLEN_NAME + ADEDLEN_COMMENT + ADEDLEN_FILEI + \ 124 ADEDLEN_FINDERI + ADEDLEN_DID + ADEDLEN_AFPFILEI + ADEDLEN_SHORTNAME + \ 125 ADEDLEN_PRODOSFILEI + ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + \ 126 ADEDLEN_PRIVSYN + ADEDLEN_PRIVID + (ADEID_NUM_V2 * AD_ENTRY_LEN)) 127 #if AD_DATASZ2 != 741 128 #error bad size for AD_DATASZ2 129 #endif 130 131 #define AD_DATASZ_EA (AD_HEADER_LEN + (ADEID_NUM_EA * AD_ENTRY_LEN) + \ 132 ADEDLEN_FINDERI + ADEDLEN_COMMENT + ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + \ 133 ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + ADEDLEN_PRIVSYN + ADEDLEN_PRIVID) 134 135 #if AD_DATASZ_EA != 402 136 #error bad size for AD_DATASZ_EA 137 #endif 138 139 #define AD_DATASZ_OSX (AD_HEADER_LEN + (ADEID_NUM_OSX * AD_ENTRY_LEN) + ADEDLEN_FINDERI) 140 141 #if AD_DATASZ_OSX != 82 142 #error bad size for AD_DATASZ_OSX 143 #endif 144 145 #define AD_DATASZ_MAX 1024 146 147 #if AD_VERSION == AD_VERSION2 148 #define AD_DATASZ AD_DATASZ2 149 #elif AD_VERSION == AD_VERSION_EA 150 #define AD_DATASZ AD_DATASZ_EA 151 #endif 152 153 /* fallback for ad:ea on filesystems without fds for EAs, like old adouble:osx */ 154 #define ADEDOFF_FINDERI_OSX (AD_HEADER_LEN + ADEID_NUM_OSX*AD_ENTRY_LEN) 155 #define ADEDOFF_RFORK_OSX (ADEDOFF_FINDERI_OSX + ADEDLEN_FINDERI) 156 157 /* special fd value used to indicate an open fork file is a (not open) symlink */ 158 #define AD_SYMLINK -2 159 160 typedef uint32_t cnid_t; 161 162 struct ad_entry { 163 off_t ade_off; 164 ssize_t ade_len; 165 }; 166 167 typedef struct adf_lock_t { 168 struct flock lock; 169 int user; 170 int *refcount; /* handle read locks with multiple users */ 171 } adf_lock_t; 172 173 struct ad_fd { 174 int adf_fd; /* -1: invalid, AD_SYMLINK: symlink */ 175 char *adf_syml; 176 int adf_flags; 177 adf_lock_t *adf_lock; 178 int adf_refcount, adf_lockcount, adf_lockmax; 179 }; 180 181 /* some header protection */ 182 #define AD_INITED 0xad494e54 /* ad"INT" */ 183 #define AD_CLOSED 0xadc10ced 184 185 struct adouble; 186 187 struct adouble_fops { 188 const char *(*ad_path)(const char *, int); 189 int (*ad_mkrf)(const char *); 190 int (*ad_rebuild_header)(struct adouble *); 191 int (*ad_header_read)(const char *, struct adouble *, const struct stat *); 192 int (*ad_header_upgrade)(struct adouble *, const char *); 193 }; 194 195 struct adouble { 196 uint32_t ad_magic; /* Official adouble magic */ 197 uint32_t ad_version; /* Official adouble version number */ 198 char ad_filler[16]; 199 struct ad_entry ad_eid[ADEID_MAX]; 200 201 struct ad_fd ad_data_fork; /* the data fork */ 202 203 struct ad_fd ad_resource_fork; /* adouble:v2 -> the adouble file * 204 * adouble:ea -> the EA fd */ 205 206 struct ad_fd *ad_rfp; /* adouble:v2 -> ad_resource_fork * 207 * adouble:ea -> ad_resource_fork */ 208 209 struct ad_fd *ad_mdp; /* adouble:v2 -> ad_resource_fork * 210 * adouble:ea -> ad_data_fork */ 211 212 int ad_vers; /* Our adouble version info (AD_VERSION*) */ 213 int ad_adflags; /* ad_open flags adflags like ADFLAGS_DIR */ 214 uint32_t ad_inited; 215 int ad_options; 216 int ad_refcount; /* multiple forks may open one adouble */ 217 int ad_data_refcount; 218 int ad_meta_refcount; 219 int ad_reso_refcount; 220 off_t ad_rlen; /* ressource fork len with AFP 3.0 * 221 * the header parameter size is too small. */ 222 char *ad_name; /* mac name (maccharset or UTF8-MAC) */ 223 struct adouble_fops *ad_ops; 224 uint16_t ad_open_forks; /* open forks (by others) */ 225 char ad_data[AD_DATASZ_MAX]; 226 }; 227 228 #define ADFLAGS_DF (1<<0) 229 #define ADFLAGS_RF (1<<1) 230 #define ADFLAGS_HF (1<<2) 231 #define ADFLAGS_DIR (1<<3) 232 #define ADFLAGS_NOHF (1<<4) /* not an error if no metadata fork */ 233 #define ADFLAGS_NORF (1<<5) /* not an error if no ressource fork */ 234 #define ADFLAGS_CHECK_OF (1<<6) /* check for open forks from us and other afpd's */ 235 #define ADFLAGS_SETSHRMD (1<<7) /* setting share mode must be done with excl fcnt lock, 236 which implies that the file must be openend rw. 237 If it can't be opened rw (eg EPERM or EROFS) it will 238 be opened ro and the fcntl locks will be shared, that 239 at least prevent other users who have rw access to the 240 file from placing excl locks. */ 241 #define ADFLAGS_RDWR (1<<8) /* open read/write */ 242 #define ADFLAGS_RDONLY (1<<9) /* open read only */ 243 #define ADFLAGS_CREATE (1<<10) /* create file, open called with O_CREAT */ 244 #define ADFLAGS_EXCL (1<<11) /* exclusive open, open called with O_EXCL */ 245 #define ADFLAGS_TRUNC (1<<12) /* truncate, open called with O_TRUNC */ 246 247 #define ADVOL_NODEV (1 << 0) 248 #define ADVOL_RO (1 << 1) 249 #define ADVOL_UNIXPRIV (1 << 2) /* adouble unix priv */ 250 #define ADVOL_INVDOTS (1 << 3) /* dot files (.DS_Store) are invisible) */ 251 #define ADVOL_FOLLO_SYML (1 << 4) 252 #define ADVOL_FORCE_STICKY_XATTR (1 << 5) 253 254 /* lock flags */ 255 #define ADLOCK_CLR (0) 256 #define ADLOCK_RD (1<<0) 257 #define ADLOCK_WR (1<<1) 258 #define ADLOCK_MASK (ADLOCK_RD | ADLOCK_WR) 259 #define ADLOCK_UPGRADE (1<<2) 260 #define ADLOCK_FILELOCK (1<<3) 261 262 /* we use this so that we can use the same mechanism for both byte 263 * locks and file synchronization locks. */ 264 #if _FILE_OFFSET_BITS == 64 265 #define AD_FILELOCK_BASE (UINT64_C(0x7FFFFFFFFFFFFFFF) - 9) 266 #else 267 #define AD_FILELOCK_BASE (UINT32_C(0x7FFFFFFF) - 9) 268 #endif 269 270 #define BYTELOCK_MAX (AD_FILELOCK_BASE - 1) 271 272 /* datafork and rsrcfork sharemode locks */ 273 #define AD_FILELOCK_OPEN_WR (AD_FILELOCK_BASE + 0) 274 #define AD_FILELOCK_OPEN_RD (AD_FILELOCK_BASE + 1) 275 #define AD_FILELOCK_RSRC_OPEN_WR (AD_FILELOCK_BASE + 2) 276 #define AD_FILELOCK_RSRC_OPEN_RD (AD_FILELOCK_BASE + 3) 277 278 #define AD_FILELOCK_DENY_WR (AD_FILELOCK_BASE + 4) 279 #define AD_FILELOCK_DENY_RD (AD_FILELOCK_BASE + 5) 280 #define AD_FILELOCK_RSRC_DENY_WR (AD_FILELOCK_BASE + 6) 281 #define AD_FILELOCK_RSRC_DENY_RD (AD_FILELOCK_BASE + 7) 282 283 #define AD_FILELOCK_OPEN_NONE (AD_FILELOCK_BASE + 8) 284 #define AD_FILELOCK_RSRC_OPEN_NONE (AD_FILELOCK_BASE + 9) 285 286 /* time stuff. we overload the bits a little. */ 287 #define AD_DATE_CREATE 0 288 #define AD_DATE_MODIFY 4 289 #define AD_DATE_BACKUP 8 290 #define AD_DATE_ACCESS 12 291 #define AD_DATE_MASK (AD_DATE_CREATE | AD_DATE_MODIFY | \ 292 AD_DATE_BACKUP | AD_DATE_ACCESS) 293 #define AD_DATE_UNIX (1 << 10) 294 #define AD_DATE_START htonl(0x80000000) 295 #define AD_DATE_DELTA 946684800 296 #define AD_DATE_FROM_UNIX(x) htonl((x) - AD_DATE_DELTA) 297 #define AD_DATE_TO_UNIX(x) (ntohl(x) + AD_DATE_DELTA) 298 299 /* various finder offset and info bits */ 300 #define FINDERINFO_FRTYPEOFF 0 301 #define FINDERINFO_FRCREATOFF 4 302 #define FINDERINFO_FRFLAGOFF 8 303 304 /* FinderInfo Flags, char in `ad ls`, valid for files|dirs */ 305 #define FINDERINFO_ISONDESK (1) /* "d", fd */ 306 #define FINDERINFO_COLOR (0x0e) 307 #define FINDERINFO_HIDEEXT (1<<4) /* "e", fd */ 308 #define FINDERINFO_ISHARED (1<<6) /* "m", f */ 309 #define FINDERINFO_HASNOINITS (1<<7) /* "n", f */ 310 #define FINDERINFO_HASBEENINITED (1<<8) /* "i", fd */ 311 #define FINDERINFO_HASCUSTOMICON (1<<10) /* "c", fd */ 312 #define FINDERINFO_ISSTATIONNERY (1<<11) /* "t", f */ 313 #define FINDERINFO_NAMELOCKED (1<<12) /* "s", fd */ 314 #define FINDERINFO_HASBUNDLE (1<<13) /* "b", fd */ 315 #define FINDERINFO_INVISIBLE (1<<14) /* "v", fd */ 316 #define FINDERINFO_ISALIAS (1<<15) /* "a", fd */ 317 318 #define FINDERINFO_FRVIEWOFF 14 319 #define FINDERINFO_CUSTOMICON 0x4 320 #define FINDERINFO_CLOSEDVIEW 0x100 321 322 /* 323 The "shared" and "invisible" attributes are opaque and stored and 324 retrieved from the FinderFlags. This fixes Bug #2802236: 325 <https://sourceforge.net/tracker/?func=detail&aid=2802236&group_id=8642&atid=108642> 326 */ 327 328 /* AFP attributes, char in `ad ls`, valid for files|dirs */ 329 #define ATTRBIT_INVISIBLE (1<<0) /* opaque from FinderInfo */ 330 #define ATTRBIT_MULTIUSER (1<<1) /* file: opaque, dir: see below */ 331 #define ATTRBIT_SYSTEM (1<<2) /* "y", fd */ 332 #define ATTRBIT_DOPEN (1<<3) /* data fork already open. Not stored, computed on the fly */ 333 #define ATTRBIT_ROPEN (1<<4) /* resource fork already open. Not stored, computed on the fly */ 334 #define ATTRBIT_NOWRITE (1<<5) /* "w", f, write inhibit(v2)/read-only(v1) bit */ 335 #define ATTRBIT_BACKUP (1<<6) /* "p", fd */ 336 #define ATTRBIT_NORENAME (1<<7) /* "r", fd */ 337 #define ATTRBIT_NODELETE (1<<8) /* "l", fd */ 338 #define ATTRBIT_NOCOPY (1<<10) /* "o", f */ 339 #define ATTRBIT_SETCLR (1<<15) /* set/clear bit (d) */ 340 341 /* AFP attributes for dirs. These should probably be computed on the fly. 342 * We don't do that, nor does e.g. OS S X 10.5 Server */ 343 #define ATTRBIT_EXPFLDR (1<<1) /* Folder is a sharepoint */ 344 #define ATTRBIT_MOUNTED (1<<3) /* Directory is mounted by a user */ 345 #define ATTRBIT_SHARED (1<<4) /* Shared area, called IsExpFolder in spec */ 346 347 /* private AFPFileInfo bits */ 348 #define AD_AFPFILEI_OWNER (1 << 0) /* any owner */ 349 #define AD_AFPFILEI_GROUP (1 << 1) /* ignore group */ 350 #define AD_AFPFILEI_BLANKACCESS (1 << 2) /* blank access permissions */ 351 352 /* 353 * String identifiers for the 16 AppleDouble filler bytes 354 */ 355 #define AD_FILLER_NETATALK "Netatalk " 356 #define AD_FILLER_OSX "Mac OS X" 357 358 #define ad_data_fileno(ad) ((ad)->ad_data_fork.adf_fd) 359 #define ad_reso_fileno(ad) ((ad)->ad_rfp->adf_fd) 360 #define ad_meta_fileno(ad) ((ad)->ad_mdp->adf_fd) 361 362 /* -1: not open, AD_SYMLINK (-2): it's a symlink */ 363 #define AD_DATA_OPEN(ad) (((ad)->ad_data_refcount) && (ad_data_fileno(ad) >= 0)) 364 #define AD_META_OPEN(ad) (((ad)->ad_meta_refcount) && (ad_meta_fileno(ad) >= 0)) 365 #define AD_RSRC_OPEN(ad) (((ad)->ad_reso_refcount) && (ad_reso_fileno(ad) >= 0)) 366 367 #define ad_getversion(ad) ((ad)->ad_version) 368 369 #define ad_getentrylen(ad,eid) ((ad)->ad_eid[(eid)].ade_len) 370 #define ad_setentrylen(ad,eid,len) ((ad)->ad_eid[(eid)].ade_len = (len)) 371 #define ad_setentryoff(ad,eid,off) ((ad)->ad_eid[(eid)].ade_off = (off)) 372 #define ad_entry(ad,eid) ((caddr_t)(ad)->ad_data + (ad)->ad_eid[(eid)].ade_off) 373 374 #define ad_get_RF_flags(ad) ((ad)->ad_rfp->adf_flags) 375 #define ad_get_MD_flags(ad) ((ad)->ad_mdp->adf_flags) 376 377 /* Refcounting open forks using one struct adouble */ 378 #define ad_ref(ad) (ad)->ad_refcount++ 379 #define ad_unref(ad) --((ad)->ad_refcount) 380 381 #define ad_get_syml_opt(ad) (((ad)->ad_options & ADVOL_FOLLO_SYML) ? 0 : O_NOFOLLOW) 382 383 /* ad_flush.c */ 384 extern int ad_rebuild_adouble_header_v2(struct adouble *); 385 extern int ad_rebuild_adouble_header_ea(struct adouble *); 386 extern int ad_rebuild_adouble_header_osx(struct adouble *ad, char *adbuf); 387 extern int ad_copy_header (struct adouble *, struct adouble *); 388 extern int ad_flush (struct adouble *); 389 extern int ad_close (struct adouble *, int); 390 extern int fsetrsrcea(struct adouble *ad, int fd, const char *eaname, const void *value, size_t size, int flags); 391 392 /* ad_lock.c */ 393 extern int ad_testlock (struct adouble *adp, int eid, off_t off); 394 extern uint16_t ad_openforks(struct adouble *adp, uint16_t); 395 extern int ad_lock(struct adouble *, uint32_t eid, int type, off_t off, off_t len, int fork); 396 extern void ad_unlock(struct adouble *, int fork, int unlckbrl); 397 extern int ad_tmplock(struct adouble *, uint32_t eid, int type, off_t off, off_t len, int fork); 398 399 /* ad_open.c */ 400 extern off_t ad_getentryoff(const struct adouble *ad, int eid); 401 extern const char *adflags2logstr(int adflags); 402 extern int ad_setfuid (const uid_t ); 403 extern uid_t ad_getfuid (void ); 404 extern char *ad_dir (const char *); 405 extern const char *ad_path (const char *, int); 406 extern const char *ad_path_ea (const char *, int); 407 extern const char *ad_path_osx (const char *path, int adflags); 408 extern int ad_mode (const char *, mode_t); 409 extern int ad_mkdir (const char *, mode_t); 410 struct vol; 411 extern void ad_init (struct adouble *, const struct vol * restrict); 412 extern void ad_init_old (struct adouble *ad, int flags, int options); 413 extern int ad_init_offsets(struct adouble *ad); 414 extern int ad_open (struct adouble *ad, const char *path, int adflags, ...); 415 extern int ad_openat (struct adouble *, int dirfd, const char *path, int adflags, ...); 416 extern int ad_refresh (const char *path, struct adouble *); 417 extern int ad_stat (const char *, struct stat *); 418 extern int ad_metadata (const char *, int, struct adouble *); 419 extern int ad_metadataat (int, const char *, int, struct adouble *); 420 extern mode_t ad_hf_mode(mode_t mode); 421 extern int ad_valid_header_osx(const char *path); 422 extern off_t ad_reso_size(const char *path, int adflags, struct adouble *ad); 423 424 /* ad_conv.c */ 425 extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, const char **newpath); 426 427 /* ad_read.c/ad_write.c */ 428 extern int sys_ftruncate(int fd, off_t length); 429 extern ssize_t ad_read(struct adouble *, uint32_t, off_t, char *, size_t); 430 extern ssize_t ad_pread(struct ad_fd *, void *, size_t, off_t); 431 extern ssize_t ad_write(struct adouble *, uint32_t, off_t, int, const char *, size_t); 432 extern ssize_t adf_pread(struct ad_fd *, void *, size_t, off_t); 433 extern ssize_t adf_pwrite(struct ad_fd *, const void *, size_t, off_t); 434 extern int ad_dtruncate(struct adouble *, off_t); 435 extern int ad_rtruncate(struct adouble *, const char *, off_t); 436 extern int copy_fork(int eid, struct adouble *add, struct adouble *ads, char *buf, size_t buflen); 437 438 /* ad_size.c */ 439 extern off_t ad_size (const struct adouble *, uint32_t ); 440 441 /* ad_mmap.c */ 442 extern void *ad_mmapread(struct adouble *, uint32_t, off_t, size_t); 443 extern void *ad_mmapwrite(struct adouble *, uint32_t, off_t, int, size_t); 444 #define ad_munmap(buf, len) (munmap((buf), (len))) 445 446 /* ad_date.c */ 447 extern int ad_setdate(struct adouble *, unsigned int, uint32_t); 448 extern int ad_getdate(const struct adouble *, unsigned int, uint32_t *); 449 450 /* ad_attr.c */ 451 extern int ad_setattr(const struct adouble *, const uint16_t); 452 extern int ad_getattr(const struct adouble *, uint16_t *); 453 extern int ad_setname(struct adouble *, const char *); 454 extern int ad_setid(struct adouble *, dev_t dev, ino_t ino, uint32_t, uint32_t, const void *); 455 extern uint32_t ad_getid(struct adouble *, dev_t, ino_t, cnid_t, const void *); 456 extern uint32_t ad_forcegetid(struct adouble *adp); 457 458 #ifdef WITH_SENDFILE 459 extern int ad_readfile_init(const struct adouble *ad, int eid, off_t *off, int end); 460 #endif 461 #ifdef WITH_RECVFILE 462 extern ssize_t ad_recvfile(struct adouble *ad, int eid, int sock, off_t off, size_t len, int); 463 #endif 464 465 #endif /* _ATALK_ADOUBLE_H */ 466