Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157849138
D57163.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
D57163.diff
View Options
diff --git a/lib/libsys/Makefile.sys b/lib/libsys/Makefile.sys
--- a/lib/libsys/Makefile.sys
+++ b/lib/libsys/Makefile.sys
@@ -500,7 +500,8 @@
pdfork.2 pdopenpid.2 \
pdfork.2 pdkill.2 \
pdfork.2 pdrfork.2 \
- pdfork.2 pdwait.2
+ pdfork.2 pdwait.2 \
+ pdfork.2 pddupfd.2
MLINKS+=pipe.2 pipe2.2
MLINKS+=poll.2 ppoll.2
MLINKS+=rctl_add_rule.2 rctl_get_limits.2 \
diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map
--- a/lib/libsys/Symbol.sys.map
+++ b/lib/libsys/Symbol.sys.map
@@ -391,6 +391,7 @@
};
FBSD_1.9 {
+ pddupfd;
pdopenpid;
pdrfork;
pdrfork_thread;
diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h
--- a/lib/libsys/_libsys.h
+++ b/lib/libsys/_libsys.h
@@ -476,6 +476,7 @@
typedef int (__sys_pdwait_t)(int, int *, int, struct __wrusage *, struct __siginfo *);
typedef int (__sys_renameat2_t)(int, const char *, int, const char *, int);
typedef int (__sys_pdopenpid_t)(pid_t, int);
+typedef int (__sys_pddupfd_t)(int, int, int);
_Noreturn void __sys__exit(int rval);
int __sys_fork(void);
@@ -887,6 +888,7 @@
int __sys_pdwait(int fd, int * status, int options, struct __wrusage * wrusage, struct __siginfo * info);
int __sys_renameat2(int oldfd, const char * old, int newfd, const char * new, int flags);
int __sys_pdopenpid(pid_t pid, int flags);
+int __sys_pddupfd(int pd, int fd, int flags);
__END_DECLS
#endif /* __LIBSYS_H_ */
diff --git a/lib/libsys/pdfork.2 b/lib/libsys/pdfork.2
--- a/lib/libsys/pdfork.2
+++ b/lib/libsys/pdfork.2
@@ -39,7 +39,8 @@
.Nm pdopenpid ,
.Nm pdgetpid ,
.Nm pdkill ,
-.Nm pdwait
+.Nm pdwait ,
+.Nm pddupfd
.Nd System calls to manage process descriptors
.Sh LIBRARY
.Lb libc
@@ -63,6 +64,8 @@
.Fa "struct __wrusage *wrusage"
.Fa "struct __siginfo *info"
.Fc
+.Ft int
+.Fn pddupfd "int fd" "int remotefd" "int flags"
.Sh DESCRIPTION
Process descriptors are special file descriptors that represent processes,
and are created using
@@ -168,6 +171,23 @@
.Xr wait6
system call for the behavior specification.
.Pp
+The
+.Fn pddupfd
+allows the caller to duplicate a file descriptor across the process
+boundaries.
+The function returns the new file descriptor that points to the same file
+as the file descriptor
+.Fa remotefd
+in the process specified by the
+.Fa fd
+process descriptor.
+The returned file descriptor has the
+.Va O_CLOEXEC
+flag set.
+The
+.Fa flags
+argument is reserved and must be zero.
+.Pp
The following system calls also have effects specific to process descriptors:
.Pp
.Xr fstat 2
@@ -220,8 +240,9 @@
.Fn pdopenpid ,
.Fn pdgetpid ,
.Fn pdkill ,
+.Fn pdwait ,
and
-.Fn pdwait
+.Fn pddupfd
return 0 on success and -1 on failure.
.Sh ERRORS
These functions may return the same error numbers as their PID-based equivalents
@@ -289,6 +310,30 @@
argument does not exist, or the caller does not have enough privileges
to open the process.
.El
+.Pp
+The
+.Fn pddupfd
+returns the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa flags
+argument is not zero.
+.It Bq Er ESRCH
+The process specified by the file descriptor
+.Fa fd
+exited.
+.It Bq Er EBADF
+The file descriptor
+.Fa fd
+is not a process file descriptor.
+.It Bq Er EBADF
+The file descriptor
+.Fa remotefd
+is not a valid file descriptor in the specified process.
+.It Bq Er ENOENT
+The specified process does not have a file descriptor table.
+.El
.Sh SEE ALSO
.Xr close 2 ,
.Xr fork 2 ,
@@ -315,7 +360,9 @@
.Fx 15.1 .
The
.Fn pdopenpid
-system call first appeared in
+and
+.Fn pddupfd
+system calls first appeared in
.Fx 16.0 .
.Pp
Support for process descriptors mode was developed as part of the
@@ -339,5 +386,7 @@
.An Alan Somers Aq Mt asomers@FreeBSD.org .
The
.Fn pdopenpid
-function was developed by
+and
+.Fn pddupfd
+functions were developed by
.An Konstantin Belousov Aq Mt kib@FreeBSD.org .
diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map
--- a/lib/libsys/syscalls.map
+++ b/lib/libsys/syscalls.map
@@ -827,4 +827,6 @@
__sys_renameat2;
_pdopenpid;
__sys_pdopenpid;
+ _pddupfd;
+ __sys_pddupfd;
};
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -521,4 +521,5 @@
#define FREEBSD32_SYS_freebsd32_pdwait 601
#define FREEBSD32_SYS_renameat2 602
#define FREEBSD32_SYS_pdopenpid 603
-#define FREEBSD32_SYS_MAXSYSCALL 604
+#define FREEBSD32_SYS_pddupfd 604
+#define FREEBSD32_SYS_MAXSYSCALL 605
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -609,4 +609,5 @@
"freebsd32_pdwait", /* 601 = freebsd32_pdwait */
"renameat2", /* 602 = renameat2 */
"pdopenpid", /* 603 = pdopenpid */
+ "pddupfd", /* 604 = pddupfd */
};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -671,4 +671,5 @@
{ .sy_narg = AS(freebsd32_pdwait_args), .sy_call = (sy_call_t *)freebsd32_pdwait, .sy_auevent = AUE_PDWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 601 = freebsd32_pdwait */
{ .sy_narg = AS(renameat2_args), .sy_call = (sy_call_t *)sys_renameat2, .sy_auevent = AUE_RENAMEAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 602 = renameat2 */
{ .sy_narg = AS(pdopenpid_args), .sy_call = (sy_call_t *)sys_pdopenpid, .sy_auevent = AUE_PDOPENPID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 603 = pdopenpid */
+ { .sy_narg = AS(pddupfd_args), .sy_call = (sy_call_t *)sys_pddupfd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 604 = pddupfd */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3466,6 +3466,15 @@
*n_args = 2;
break;
}
+ /* pddupfd */
+ case 604: {
+ struct pddupfd_args *p = params;
+ iarg[a++] = p->pd; /* int */
+ iarg[a++] = p->fd; /* int */
+ iarg[a++] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9368,6 +9377,22 @@
break;
};
break;
+ /* pddupfd */
+ case 604:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11306,6 +11331,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* pddupfd */
+ case 604:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -670,4 +670,5 @@
{ .sy_narg = AS(pdwait_args), .sy_call = (sy_call_t *)sys_pdwait, .sy_auevent = AUE_PDWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 601 = pdwait */
{ .sy_narg = AS(renameat2_args), .sy_call = (sy_call_t *)sys_renameat2, .sy_auevent = AUE_RENAMEAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 602 = renameat2 */
{ .sy_narg = AS(pdopenpid_args), .sy_call = (sy_call_t *)sys_pdopenpid, .sy_auevent = AUE_PDOPENPID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 603 = pdopenpid */
+ { .sy_narg = AS(pddupfd_args), .sy_call = (sy_call_t *)sys_pddupfd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 604 = pddupfd */
};
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -3156,13 +3156,20 @@
#endif
int
-fget_remote(struct thread *td, struct proc *p, int fd, struct file **fpp)
+fget_remote(struct thread *td, struct proc *p, int fd, struct filecaps *fcaps,
+ uint8_t *fd_flags, struct file **fpp)
{
struct filedesc *fdp;
struct file *fp;
int error;
- if (p == td->td_proc) /* curproc */
+ /*
+ * Both fcaps and fd_flags must be either requested together,
+ * or not at all.
+ */
+ MPASS((!(fcaps == NULL) ^ (fd_flags == NULL)));
+
+ if (p == td->td_proc && fcaps == NULL) /* curproc */
return (fget_unlocked(td, fd, &cap_no_rights, fpp));
PROC_LOCK(p);
@@ -3175,6 +3182,9 @@
fp = fget_noref(fdp, fd);
if (fp != NULL && fhold(fp)) {
*fpp = fp;
+ *fd_flags = fde_to_fd_flags(fdp->fd_ofiles[fd].
+ fde_flags);
+ *fcaps = fdp->fd_ofiles[fd].fde_caps;
error = 0;
} else {
error = EBADF;
@@ -3215,7 +3225,7 @@
}
for (fd = 0; fd <= highfd; fd++) {
- error1 = fget_remote(td, p, fd, &fp);
+ error1 = fget_remote(td, p, fd, NULL, NULL, &fp);
if (error1 != 0)
continue;
error = fn(p, fd, fp, arg);
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -3354,7 +3354,7 @@
struct kqueue *kq;
int error;
- error = fget_remote(td, p, kq_fd, &fp);
+ error = fget_remote(td, p, kq_fd, NULL, NULL, &fp);
if (error == 0) {
if (fp->f_type != DTYPE_KQUEUE) {
error = EINVAL;
diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c
--- a/sys/kern/subr_capability.c
+++ b/sys/kern/subr_capability.c
@@ -88,6 +88,7 @@
const cap_rights_t cap_mkdirat_rights = CAP_RIGHTS_INITIALIZER(CAP_MKDIRAT);
const cap_rights_t cap_mkfifoat_rights = CAP_RIGHTS_INITIALIZER(CAP_MKFIFOAT);
const cap_rights_t cap_mknodat_rights = CAP_RIGHTS_INITIALIZER(CAP_MKNODAT);
+const cap_rights_t cap_pddupfd_rights = CAP_RIGHTS_INITIALIZER(CAP_PDDUPFD);
const cap_rights_t cap_pdgetpid_rights = CAP_RIGHTS_INITIALIZER(CAP_PDGETPID);
const cap_rights_t cap_pdkill_rights = CAP_RIGHTS_INITIALIZER(CAP_PDKILL);
const cap_rights_t cap_pdwait_rights = CAP_RIGHTS_INITIALIZER(CAP_PDWAIT);
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -2185,9 +2185,9 @@
switch (type) {
case KCMP_FILE:
case KCMP_FILEOBJ:
- error = fget_remote(td, p1, idx1, &fp1);
+ error = fget_remote(td, p1, idx1, NULL, NULL, &fp1);
if (error == 0) {
- error = fget_remote(td, p2, idx2, &fp2);
+ error = fget_remote(td, p2, idx2, NULL, NULL, &fp2);
if (error == 0) {
if (type == KCMP_FILEOBJ)
res = fo_cmp(fp1, fp2, td);
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -662,3 +662,62 @@
return (EINVAL);
return (kern_pdopenpid(td, args->pid, args->flags));
}
+
+static int
+kern_pddupfd(struct thread *td, int pdfd, int fd, int flags)
+{
+ struct proc *p;
+ struct file *fp, *pfp;
+ struct procdesc *pd;
+ struct filecaps fcaps;
+ uint8_t fd_flags;
+ int error, fdr;
+
+ error = fget(td, pdfd, &cap_pddupfd_rights, &pfp);
+ if (error != 0)
+ return (error);
+ if (pfp->f_type != DTYPE_PROCDESC) {
+ error = EBADF;
+ goto out;
+ }
+ pd = pfp->f_data;
+ sx_slock(&proctree_lock);
+ p = pd->pd_proc;
+ if (p != NULL) {
+ AUDIT_ARG_PROCESS(p);
+ PROC_LOCK(p);
+ if ((p->p_flag & P_WEXIT) != 0)
+ error = ESRCH;
+ else
+ _PHOLD(p);
+ PROC_UNLOCK(p);
+ sx_sunlock(&proctree_lock);
+ if (error != 0)
+ goto out;
+
+ error = fget_remote(td, p, fd, &fcaps, &fd_flags, &fp);
+ PRELE(p);
+ if (error == 0) {
+ error = finstall_refed(td, fp, &fdr, O_CLOEXEC |
+ ((fd_flags & FD_RESOLVE_BENEATH) != 0 ?
+ O_RESOLVE_BENEATH : 0), &fcaps);
+ if (error != 0)
+ fdrop(fp, td);
+ else
+ td->td_retval[0] = fdr;
+ }
+ } else {
+ sx_sunlock(&proctree_lock);
+ }
+out:
+ fdrop(pfp, td);
+ return (error);
+}
+
+int
+sys_pddupfd(struct thread *td, struct pddupfd_args *args)
+{
+ if (args->flags != 0)
+ return (EINVAL);
+ return (kern_pddupfd(td, args->pd, args->fd, args->flags));
+}
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -609,4 +609,5 @@
"pdwait", /* 601 = pdwait */
"renameat2", /* 602 = renameat2 */
"pdopenpid", /* 603 = pdopenpid */
+ "pddupfd", /* 604 = pddupfd */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3435,5 +3435,12 @@
int flags
);
}
+604 AUE_NULL STD {
+ int pddupfd(
+ int pd,
+ int fd,
+ int flags
+ );
+ }
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3563,6 +3563,15 @@
*n_args = 2;
break;
}
+ /* pddupfd */
+ case 604: {
+ struct pddupfd_args *p = params;
+ iarg[a++] = p->pd; /* int */
+ iarg[a++] = p->fd; /* int */
+ iarg[a++] = p->flags; /* int */
+ *n_args = 3;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9542,6 +9551,22 @@
break;
};
break;
+ /* pddupfd */
+ case 604:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11575,6 +11600,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* pddupfd */
+ case 604:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/sys/caprights.h b/sys/sys/caprights.h
--- a/sys/sys/caprights.h
+++ b/sys/sys/caprights.h
@@ -90,6 +90,7 @@
extern const cap_rights_t cap_mknodat_rights;
extern const cap_rights_t cap_mmap_rights;
extern const cap_rights_t cap_no_rights;
+extern const cap_rights_t cap_pddupfd_rights;
extern const cap_rights_t cap_pdgetpid_rights;
extern const cap_rights_t cap_pdkill_rights;
extern const cap_rights_t cap_pdwait_rights;
diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h
--- a/sys/sys/capsicum.h
+++ b/sys/sys/capsicum.h
@@ -244,12 +244,7 @@
/* Process management via process descriptors. */
/* Allows for pdgetpid(2). */
#define CAP_PDGETPID CAPRIGHT(1, 0x0000000000000200ULL)
-/*
- * Allows for pdwait4(2).
- *
- * XXX: this constant was imported unused, but is targeted to be implemented
- * in the future (bug 235871).
- */
+/* Allows for pdwait(2). */
#define CAP_PDWAIT CAPRIGHT(1, 0x0000000000000400ULL)
/* Allows for pdkill(2). */
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
@@ -283,12 +278,13 @@
#define CAP_INOTIFY_ADD CAPRIGHT(1, 0x0000000000200000ULL)
#define CAP_INOTIFY_RM CAPRIGHT(1, 0x0000000000400000ULL)
+/* Allows pdgetfd(2). */
+#define CAP_PDDUPFD CAPRIGHT(1, 0x0000000000800000ULL)
+
/* All used bits for index 1. */
-#define CAP_ALL1 CAPRIGHT(1, 0x00000000007FFFFFULL)
+#define CAP_ALL1 CAPRIGHT(1, 0x0000000000FFFFFFULL)
/* Available bits for index 1. */
-#define CAP_UNUSED1_22 CAPRIGHT(1, 0x0000000000800000ULL)
-/* ... */
#define CAP_UNUSED1_57 CAPRIGHT(1, 0x0100000000000000ULL)
/* Backward compatibility. */
diff --git a/sys/sys/file.h b/sys/sys/file.h
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -281,7 +281,8 @@
int fget_fcntl(struct thread *td, int fd, const cap_rights_t *rightsp,
int needfcntl, struct file **fpp);
int _fdrop(struct file *fp, struct thread *td);
-int fget_remote(struct thread *td, struct proc *p, int fd, struct file **fpp);
+int fget_remote(struct thread *td, struct proc *p, int fd,
+ struct filecaps *fcaps, uint8_t *fd_flags, struct file **fpp);
int fget_remote_foreach(struct thread *td, struct proc *p,
int (*fn)(struct proc *, int, struct file *, void *), void *arg);
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -130,6 +130,7 @@
int pdgetpid(int, pid_t *);
int pdopenpid(pid_t, int);
int pdwait(int, int *, int, struct __wrusage *, struct __siginfo *);
+int pddupfd(int, int, int);
pid_t pdrfork_thread(int *, int, int, void *, int (*)(void *), void *);
__END_DECLS
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -542,4 +542,5 @@
#define SYS_pdwait 601
#define SYS_renameat2 602
#define SYS_pdopenpid 603
-#define SYS_MAXSYSCALL 604
+#define SYS_pddupfd 604
+#define SYS_MAXSYSCALL 605
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -445,4 +445,5 @@
pdrfork.o \
pdwait.o \
renameat2.o \
- pdopenpid.o
+ pdopenpid.o \
+ pddupfd.o
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1936,6 +1936,11 @@
char pid_l_[PADL_(pid_t)]; pid_t pid; char pid_r_[PADR_(pid_t)];
char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
};
+struct pddupfd_args {
+ char pd_l_[PADL_(int)]; int pd; char pd_r_[PADR_(int)];
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+};
int sys__exit(struct thread *, struct _exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2347,6 +2352,7 @@
int sys_pdwait(struct thread *, struct pdwait_args *);
int sys_renameat2(struct thread *, struct renameat2_args *);
int sys_pdopenpid(struct thread *, struct pdopenpid_args *);
+int sys_pddupfd(struct thread *, struct pddupfd_args *);
#ifdef COMPAT_43
@@ -3350,6 +3356,7 @@
#define SYS_AUE_pdwait AUE_PDWAIT
#define SYS_AUE_renameat2 AUE_RENAMEAT
#define SYS_AUE_pdopenpid AUE_PDOPENPID
+#define SYS_AUE_pddupfd AUE_NULL
#undef PAD_
#undef PADL_
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, May 26, 8:06 PM (7 m, 4 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33517812
Default Alt Text
D57163.diff (17 KB)
Attached To
Mode
D57163: pddupfd(2)
Attached
Detach File
Event Timeline
Log In to Comment