diff options
author | Kotresh HR <khiremat@redhat.com> | 2018-04-30 04:43:58 -0400 |
---|---|---|
committer | Amar Tumballi <amarts@redhat.com> | 2018-05-06 07:09:18 +0530 |
commit | 487aaafacac8af16c08eb44fe9bf178768d372fa (patch) | |
tree | 69a8ff6a8be0f40e129a71bf28ef5e4a558d5109 | |
parent | f8fe0771f0b450713595a7d298ed5a758cf2ce3e (diff) |
utime: ctime client side xlator
The client side utime xlator does two things.
1. Update unix epoch time in frame->root->ctime
2. Update the frame->root->flags based on the fop
which indicates time attributes that should be
updated for the parent/entry.
Credits: Rafi KC <rkavunga@redhat.com>
Updates: #208
Change-Id: I9cad297040c70798a0a8468a080eb4aeff73138d
Signed-off-by: Kotresh HR <khiremat@redhat.com>
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | glusterfs.spec.in | 1 | ||||
-rw-r--r-- | xlators/features/Makefile.am | 3 | ||||
-rw-r--r-- | xlators/features/utime/Makefile.am | 3 | ||||
-rw-r--r-- | xlators/features/utime/src/Makefile.am | 39 | ||||
-rw-r--r-- | xlators/features/utime/src/utime-autogen-fops-tmpl.c | 28 | ||||
-rw-r--r-- | xlators/features/utime/src/utime-autogen-fops-tmpl.h | 22 | ||||
-rw-r--r-- | xlators/features/utime/src/utime-gen-fops-c.py | 118 | ||||
-rw-r--r-- | xlators/features/utime/src/utime-gen-fops-h.py | 34 | ||||
-rw-r--r-- | xlators/features/utime/src/utime-helpers.c | 95 | ||||
-rw-r--r-- | xlators/features/utime/src/utime-helpers.h | 24 | ||||
-rw-r--r-- | xlators/features/utime/src/utime.c | 229 | ||||
-rw-r--r-- | xlators/features/utime/src/utime.h | 19 |
13 files changed, 616 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 63340e2c114..b818d3fac0d 100644 --- a/configure.ac +++ b/configure.ac @@ -180,6 +180,8 @@ AC_CONFIG_FILES([Makefile xlators/features/leases/src/Makefile xlators/features/cloudsync/Makefile xlators/features/cloudsync/src/Makefile + xlators/features/utime/Makefile + xlators/features/utime/src/Makefile xlators/playground/Makefile xlators/playground/template/Makefile xlators/playground/template/src/Makefile diff --git a/glusterfs.spec.in b/glusterfs.spec.in index 0be94ca4e89..c03577d7695 100644 --- a/glusterfs.spec.in +++ b/glusterfs.spec.in @@ -1086,6 +1086,7 @@ exit 0 %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/barrier.so %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/cdc.so %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/changelog.so + %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/utime.so %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/gfid-access.so %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/namespace.so %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/read-only.so diff --git a/xlators/features/Makefile.am b/xlators/features/Makefile.am index a8d73c83b83..81fbe856e78 100644 --- a/xlators/features/Makefile.am +++ b/xlators/features/Makefile.am @@ -1,5 +1,6 @@ SUBDIRS = locks quota read-only quiesce marker index barrier \ arbiter compress changelog changetimerecorder \ gfid-access $(GLUPY_SUBDIR) upcall snapview-client snapview-server \ - trash shard bit-rot leases selinux sdfs namespace cloudsync thin-arbiter + trash shard bit-rot leases selinux sdfs namespace cloudsync thin-arbiter \ + utime CLEANFILES = diff --git a/xlators/features/utime/Makefile.am b/xlators/features/utime/Makefile.am new file mode 100644 index 00000000000..a985f42a877 --- /dev/null +++ b/xlators/features/utime/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/xlators/features/utime/src/Makefile.am b/xlators/features/utime/src/Makefile.am new file mode 100644 index 00000000000..52f2eb5df24 --- /dev/null +++ b/xlators/features/utime/src/Makefile.am @@ -0,0 +1,39 @@ +xlator_LTLIBRARIES = utime.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features + +UTIME_SRC = $(top_srcdir)/xlators/features/utime/src + +utime_sources = $(UTIME_SRC)/utime-helpers.c +utime_sources += $(UTIME_SRC)/utime.c + +utime_la_SOURCES = $(utime_sources) +nodist_utime_la_SOURCES = utime-autogen-fops.c utime-autogen-fops.h +BUILT_SOURCES = utime-autogen-fops.h + +utime_la_LDFLAGS = -module -avoid-version +utime_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS_utime = $(UTIME_SRC)/utime-helpers.h +noinst_HEADERS_utime += $(UTIME_SRC)/utime.h +noinst_HEADERS = $(top_srcdir)/xlators/lib/src/libxlator.h +noinst_HEADERS += $(noinst_HEADERS_utime) + +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \ + -I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src \ + -I$(top_srcdir)/xlators/lib/src + +AM_CFLAGS = -Wall $(GF_CFLAGS) + +noinst_PYTHON = utime-gen-fops-c.py utime-gen-fops-h.py +EXTRA_DIST = utime-autogen-fops-tmpl.c utime-autogen-fops-tmpl.h + +utime-autogen-fops.c: utime-gen-fops-c.py utime-autogen-fops-tmpl.c + $(PYTHON) $(UTIME_SRC)/utime-gen-fops-c.py $(UTIME_SRC)/utime-autogen-fops-tmpl.c > $@ + +utime-autogen-fops.h: utime-gen-fops-h.py utime-autogen-fops-tmpl.h + $(PYTHON) $(UTIME_SRC)/utime-gen-fops-h.py $(UTIME_SRC)/utime-autogen-fops-tmpl.h > $@ + +CLEANFILES = $(nodist_utime_la_SOURCES) + +uninstall-local: + rm -f $(DESTDIR)$(xlatordir)/utime.so diff --git a/xlators/features/utime/src/utime-autogen-fops-tmpl.c b/xlators/features/utime/src/utime-autogen-fops-tmpl.c new file mode 100644 index 00000000000..b4be66eebd1 --- /dev/null +++ b/xlators/features/utime/src/utime-autogen-fops-tmpl.c @@ -0,0 +1,28 @@ +/* + Copyright (c) 2018 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +/* File: utime-autogen-fops-tmpl.c + * This file contains the utime autogenerated FOPs. This is run through + * the code generator, generator.py to generate the required FOPs. + */ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" +#include "xlator.h" +#include "logging.h" +#include "statedump.h" +#include "utime-helpers.h" +#include "timespec.h" + +#pragma generate diff --git a/xlators/features/utime/src/utime-autogen-fops-tmpl.h b/xlators/features/utime/src/utime-autogen-fops-tmpl.h new file mode 100644 index 00000000000..e2e807cdf64 --- /dev/null +++ b/xlators/features/utime/src/utime-autogen-fops-tmpl.h @@ -0,0 +1,22 @@ +/* + Copyright (c) 2018 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +/* File: utime-autogen-fops-tmpl.h + * This file contains the utime autogenerated FOPs declarations. + */ + +#ifndef _UTIME_AUTOGEN_FOPS_H +#define _UTIME_AUTOGEN_FOPS_H + +#include "xlator.h" + +#pragma generate + +#endif /* _UTIME_AUTOGEN_FOPS_H */ diff --git a/xlators/features/utime/src/utime-gen-fops-c.py b/xlators/features/utime/src/utime-gen-fops-c.py new file mode 100644 index 00000000000..4e22c2df0bc --- /dev/null +++ b/xlators/features/utime/src/utime-gen-fops-c.py @@ -0,0 +1,118 @@ +#!/usr/bin/python + +import os +import sys + +curdir = os.path.dirname(sys.argv[0]) +gendir = os.path.join(curdir, '../../../../libglusterfs/src') +sys.path.append(gendir) +from generator import ops, fop_subs, cbk_subs, generate + +FOPS_COMMON_TEMPLATE = """ +int32_t +gf_utime_@NAME@ (call_frame_t *frame, xlator_t *this, + @LONG_ARGS@) +{ + gl_timespec_get(&frame->root->ctime); + + (void) utime_update_attribute_flags(frame, GF_FOP_@UPNAME@); + STACK_WIND (frame, gf_utime_@NAME@_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->@NAME@, @SHORT_ARGS@); + return 0; +} +""" + +FOPS_CBK_COMMON_TEMPLATE = """ +int32_t +gf_utime_@NAME@_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + @LONG_ARGS@) +{ + STACK_UNWIND_STRICT (@NAME@, frame, op_ret, op_errno, @SHORT_ARGS@); + return 0; +} +""" + +FOPS_READ_TEMPLATE = """ +int32_t +gf_utime_@NAME@ (call_frame_t *frame, xlator_t *this, + @LONG_ARGS@) +{ + gl_timespec_get(&frame->root->ctime); + + (void) utime_update_attribute_flags(frame, GF_FOP_READ); + STACK_WIND (frame, gf_utime_@NAME@_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->@NAME@, @SHORT_ARGS@); + return 0; +} +""" + +FOPS_WRITE_TEMPLATE = """ +int32_t +gf_utime_@NAME@ (call_frame_t *frame, xlator_t *this, + @LONG_ARGS@) +{ + gl_timespec_get(&frame->root->ctime); + + (void) utime_update_attribute_flags(frame, GF_FOP_WRITE); + STACK_WIND (frame, gf_utime_@NAME@_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->@NAME@, @SHORT_ARGS@); + return 0; +} +""" + +FOPS_SETATTR_TEMPLATE = """ +int32_t +gf_utime_@NAME@ (call_frame_t *frame, xlator_t *this, + @LONG_ARGS@) +{ + gl_timespec_get(&frame->root->ctime); + + if (!valid) { + frame->root->flags |= MDATA_CTIME; + } + + if (valid & (GF_SET_ATTR_UID | GF_SET_ATTR_GID)) { + frame->root->flags |= MDATA_CTIME; + } + + if (valid & GF_SET_ATTR_MODE) { + frame->root->flags |= MDATA_CTIME; + } + + STACK_WIND (frame, gf_utime_@NAME@_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->@NAME@, @SHORT_ARGS@); + return 0; +} +""" + +utime_ops = ['fallocate', 'zerofill', 'opendir', 'readlink', 'mknod', 'mkdir', + 'unlink', 'rmdir', 'symlink', 'rename', 'link', 'truncate', + 'ftruncate', 'create', 'open', 'removexattr', 'fremovexattr'] + +utime_read_op = ['readv'] +utime_write_op = ['writev'] +utime_setattr_ops = ['setattr', 'fsetattr'] + +def gen_defaults(): + for name in ops: + if name in utime_ops: + print generate(FOPS_CBK_COMMON_TEMPLATE, name, cbk_subs) + print generate(FOPS_COMMON_TEMPLATE, name, fop_subs) + if name in utime_read_op: + print generate(FOPS_CBK_COMMON_TEMPLATE, name, cbk_subs) + print generate(FOPS_READ_TEMPLATE, name, fop_subs) + if name in utime_write_op: + print generate(FOPS_CBK_COMMON_TEMPLATE, name, cbk_subs) + print generate(FOPS_WRITE_TEMPLATE, name, fop_subs) + if name in utime_setattr_ops: + print generate(FOPS_CBK_COMMON_TEMPLATE, name, cbk_subs) + print generate(FOPS_SETATTR_TEMPLATE, name, fop_subs) + +for l in open(sys.argv[1], 'r').readlines(): + if l.find('#pragma generate') != -1: + print "/* BEGIN GENERATED CODE - DO NOT MODIFY */" + gen_defaults() + print "/* END GENERATED CODE */" + else: + print l[:-1] diff --git a/xlators/features/utime/src/utime-gen-fops-h.py b/xlators/features/utime/src/utime-gen-fops-h.py new file mode 100644 index 00000000000..9f0270d5ae8 --- /dev/null +++ b/xlators/features/utime/src/utime-gen-fops-h.py @@ -0,0 +1,34 @@ +#!/usr/bin/python + +import os +import sys + +curdir = os.path.dirname(sys.argv[0]) +gendir = os.path.join(curdir, '../../../../libglusterfs/src') +sys.path.append(gendir) +from generator import ops, fop_subs, generate + +OP_FOP_TEMPLATE = """ +int32_t +gf_utime_@NAME@ (call_frame_t *frame, xlator_t *this, + @LONG_ARGS@); +""" + +utime_ops = ['fallocate', 'zerofill', 'opendir', 'readlink', 'mknod', 'mkdir', + 'unlink', 'rmdir', 'symlink', 'rename', 'link', 'truncate', + 'ftruncate', 'create', 'open', 'removexattr', 'fremovexattr', + 'readv', 'writev', 'setattr', 'fsetattr'] + +def gen_defaults(): + for name, value in ops.iteritems(): + if name in utime_ops: + print generate(OP_FOP_TEMPLATE, name, fop_subs) + + +for l in open(sys.argv[1], 'r').readlines(): + if l.find('#pragma generate') != -1: + print "/* BEGIN GENERATED CODE - DO NOT MODIFY */" + gen_defaults() + print "/* END GENERATED CODE */" + else: + print l[:-1] diff --git a/xlators/features/utime/src/utime-helpers.c b/xlators/features/utime/src/utime-helpers.c new file mode 100644 index 00000000000..d8632453e62 --- /dev/null +++ b/xlators/features/utime/src/utime-helpers.c @@ -0,0 +1,95 @@ +/* + Copyright (c) 2018 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "utime-helpers.h" + +void +gl_timespec_get (struct timespec *ts) +{ + #ifdef TIME_UTC + timespec_get (ts, TIME_UTC); + #else + timespec_now (ts); + #endif +} + +void +utime_update_attribute_flags(call_frame_t *frame, glusterfs_fop_t fop) +{ + + if (!frame) { + goto out; + } + + switch (fop) { + case GF_FOP_SETXATTR: + case GF_FOP_FSETXATTR: + frame->root->flags |= MDATA_CTIME; + break; + + case GF_FOP_FALLOCATE: + case GF_FOP_ZEROFILL: + frame->root->flags |= MDATA_MTIME; + frame->root->flags |= MDATA_ATIME; + break; + + case GF_FOP_OPENDIR: + case GF_FOP_READLINK: + case GF_FOP_OPEN: + case GF_FOP_READ: + frame->root->flags |= MDATA_ATIME; + break; + + case GF_FOP_MKNOD: + case GF_FOP_MKDIR: + case GF_FOP_SYMLINK: + case GF_FOP_CREATE: + frame->root->flags |= MDATA_ATIME; + frame->root->flags |= MDATA_CTIME; + frame->root->flags |= MDATA_MTIME; + frame->root->flags |= MDATA_PAR_CTIME; + frame->root->flags |= MDATA_PAR_MTIME; + break; + + case GF_FOP_UNLINK: + case GF_FOP_RMDIR: + frame->root->flags |= MDATA_PAR_CTIME; + frame->root->flags |= MDATA_PAR_MTIME; + break; + + case GF_FOP_WRITE: + frame->root->flags |= MDATA_MTIME; + frame->root->flags |= MDATA_CTIME; + break; + + case GF_FOP_LINK: + case GF_FOP_RENAME: + frame->root->flags |= MDATA_CTIME; + frame->root->flags |= MDATA_PAR_CTIME; + frame->root->flags |= MDATA_PAR_MTIME; + break; + + case GF_FOP_TRUNCATE: + case GF_FOP_FTRUNCATE: + frame->root->flags |= MDATA_CTIME; + frame->root->flags |= MDATA_MTIME; + break; + + case GF_FOP_REMOVEXATTR: + case GF_FOP_FREMOVEXATTR: + frame->root->flags |= MDATA_CTIME; + break; + + default: + frame->root->flags = 0; + } +out: + return; +} diff --git a/xlators/features/utime/src/utime-helpers.h b/xlators/features/utime/src/utime-helpers.h new file mode 100644 index 00000000000..f526aecb063 --- /dev/null +++ b/xlators/features/utime/src/utime-helpers.h @@ -0,0 +1,24 @@ +/* + Copyright (c) 2018 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _UTIME_HELPERS_H +#define _UTIME_HELPERS_H + +#include "glusterfs-fops.h" +#include "stack.h" +#include "timespec.h" +#include <time.h> + +void +gl_timespec_get (struct timespec *ts); +void +utime_update_attribute_flags(call_frame_t *frame, glusterfs_fop_t fop); + +#endif /* _UTIME_HELPERS_H */ diff --git a/xlators/features/utime/src/utime.c b/xlators/features/utime/src/utime.c new file mode 100644 index 00000000000..27a0e260ca4 --- /dev/null +++ b/xlators/features/utime/src/utime.c @@ -0,0 +1,229 @@ +/* + Copyright (c) 2018 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "utime.h" + +int32_t +gf_utime_invalidate (xlator_t *this, + inode_t *inode) +{ + return 0; +} + + +int32_t +gf_utime_forget (xlator_t *this, + inode_t *inode) +{ + return 0; +} + + +int32_t +gf_utime_client_destroy (xlator_t *this, + client_t *client) +{ + return 0; +} + + +void +gf_utime_ictxmerge (xlator_t *this, + fd_t *fd, + inode_t *inode, + inode_t *linked_inode) +{ + return; +} + + +int32_t +gf_utime_release (xlator_t *this, + fd_t *fd) +{ + return 0; +} + + +int32_t +gf_utime_releasedir (xlator_t *this, + fd_t *fd) +{ + return 0; +} + + +int32_t +gf_utime_client_disconnect (xlator_t *this, + client_t *client) +{ + return 0; +} + + +int32_t +gf_utime_fdctx_to_dict (xlator_t *this, + fd_t *fd, + dict_t *dict) +{ + return 0; +} + + +int32_t +gf_utime_inode (xlator_t *this) +{ + return 0; +} + + +int32_t +gf_utime_inode_to_dict (xlator_t *this, + dict_t *dict) +{ + return 0; +} + + +int32_t +gf_utime_history (xlator_t *this) +{ + return 0; +} + + +int32_t +gf_utime_fd (xlator_t *this) +{ + return 0; +} + + +int32_t +gf_utime_fd_to_dict (xlator_t *this, + dict_t *dict) +{ + return 0; +} + + +int32_t +gf_utime_fdctx (xlator_t *this, + fd_t *fd) +{ + return 0; +} + + +int32_t +gf_utime_inodectx (xlator_t *this, + inode_t *ino) +{ + return 0; +} + + +int32_t +gf_utime_inodectx_to_dict (xlator_t *this, + inode_t *ino, + dict_t *dict) +{ + return 0; +} + + +int32_t +gf_utime_priv_to_dict (xlator_t *this, + dict_t *dict, char *brickname) +{ + return 0; +} + + +int32_t +gf_utime_priv (xlator_t *this) +{ + return 0; +} + + +int32_t +init (xlator_t *this) +{ + return 0; +} + +void +fini (xlator_t *this) +{ + return; +} + +int32_t +reconfigure (xlator_t *this, dict_t *dict) +{ + return 0; +} + +int +notify (xlator_t *this, int event, void *data, ...) +{ + return default_notify (this, event, data); +} + + +struct xlator_fops fops = { + /* TODO: Need to go through other fops and + * check if they modify time attributes + */ + .rename = gf_utime_rename, + .mknod = gf_utime_mknod, + .readv = gf_utime_readv, + .fremovexattr = gf_utime_fremovexattr, + .open = gf_utime_open, + .create = gf_utime_create, + .mkdir = gf_utime_mkdir, + .writev = gf_utime_writev, + .rmdir = gf_utime_rmdir, + .fallocate = gf_utime_fallocate, + .truncate = gf_utime_truncate, + .symlink = gf_utime_symlink, + .zerofill = gf_utime_zerofill, + .link = gf_utime_link, + .ftruncate = gf_utime_ftruncate, + .unlink = gf_utime_unlink, + .setattr = gf_utime_setattr, + .fsetattr = gf_utime_fsetattr, + .opendir = gf_utime_opendir, + .readlink = gf_utime_readlink, + .removexattr = gf_utime_removexattr, +}; +struct xlator_cbks cbks = { + .invalidate = gf_utime_invalidate, + .forget = gf_utime_forget, + .client_destroy = gf_utime_client_destroy, + .ictxmerge = gf_utime_ictxmerge, + .release = gf_utime_release, + .releasedir = gf_utime_releasedir, + .client_disconnect = gf_utime_client_disconnect, +}; +struct xlator_dumpops dumpops = { + .fdctx_to_dict = gf_utime_fdctx_to_dict, + .inode = gf_utime_inode, + .inode_to_dict = gf_utime_inode_to_dict, + .history = gf_utime_history, + .fd = gf_utime_fd, + .fd_to_dict = gf_utime_fd_to_dict, + .fdctx = gf_utime_fdctx, + .inodectx = gf_utime_inodectx, + .inodectx_to_dict = gf_utime_inodectx_to_dict, + .priv_to_dict = gf_utime_priv_to_dict, + .priv = gf_utime_priv, +}; diff --git a/xlators/features/utime/src/utime.h b/xlators/features/utime/src/utime.h new file mode 100644 index 00000000000..f8d5eca082e --- /dev/null +++ b/xlators/features/utime/src/utime.h @@ -0,0 +1,19 @@ +/* + Copyright (c) 2018 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef __UTIME_H__ +#define __UTIME_H__ + +#include "glusterfs.h" +#include "xlator.h" +#include "defaults.h" +#include "utime-autogen-fops.h" + +#endif /* __UTIME_H__ */ |