Go: الاقتراح: نظام التشغيل: إنشاء / فتح / OpenFile () قم بتعيين FILE_SHARE_DELETE على النوافذ

تم إنشاؤها على ١٦ مايو ٢٠١٩  ·  194تعليقات  ·  مصدر: golang/go

على Linux و MacOS يمكننا كتابة هذا ؛ على Windows فشل مع "انتهاك المشاركة":

path := "delete-after-open"
fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
if err != nil { ... }
err = os.Remove(path)            // or os.Rename(path, path+"2")
if err != nil { ... }
fd.Close()

إذا قمت بالتطوير على Windows ونشرت على Linux وما إلى ذلك ، وتعتمد التعليمات البرمجية الخاصة بك على هذا _undocumented_ GOOS = سلوك windows لـ os.Rename () & .Remove () ، فهو معطل وربما يكون عرضة للخطر. لاحظ أن الحزمة "os" لديها _ خمسة عشر إشارة_ لسلوك آخر خاص بـ Windows.

لإصلاح ذلك ، syscall.Open () على https://golang.org/src/syscall/syscall_windows.go#L272
يحتاج sharemode |= FILE_SHARE_DELETE

توصي Microsoft بأن يكون هذا هو الإعداد الافتراضي: https://github.com/golang/go/issues/32088#issuecomment -502850674
جعله Rust افتراضيًا: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html
جعلها Mingw-w64 افتراضيًا منذ سبع سنوات:
https://sourceforge.net/p/mingw-w64/code/HEAD/tree/stable/v3.x/mingw-w64-headers/include/ntdef.h#l858
جعله Erlang افتراضيًا منذ أكثر من ست سنوات: erlang /
لم تستطع Python اعتماده بسبب قيود وقت تشغيل MSVC: https://bugs.python.org/issue15244

~ لذلك ، يجب أن يستخدم syscall.Open ()
أ) مفتاح عام لتعطيله (لأي تطبيقات موجودة تعتمد على غيابه) ، و
ب) علامة للاستخدام مع os.OpenFile () لتعطيلها على مقبض ملف معين

التحديث بعد https://github.com/golang/go/issues/32088#issuecomment-532784947 بواسطة rsc :
أ) يجب أن يقوم os.Create / Open / OpenFile () دائمًا بتمكين file_share_delete على Windows ،
ب) يجب أن يقبل syscall.Open () على Windows علامة تمكن file_share_delete ، و
ج) يجب أن يقوم syscall على Windows بتصدير ثابت للعلامة الجديدة.

يجب أن تلاحظ المستندات الخاصة بـ os.Remove () أيضًا أنه لإعادة استخدام اسم ملف بعد حذف ملف مفتوح على Windows ، يجب على المرء القيام بما يلي: os.Rename(path, unique_path); os.Remove(unique_path) .

فوز مستندات API
https://docs.microsoft.com/ar-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea
https://docs.microsoft.com/ar-us/windows/desktop/api/fileapi/nf-fileapi-createfilea

إذا كان هناك سبب لعدم القيام بذلك ، فيجب توثيقه في os.Remove () & .Rename ().

ccalexbrainman
gopherbot إضافة OS-Windows

FrozenDueToAge OS-Windows Proposal Proposal-FinalCommentPeriod release-blocker

التعليق الأكثر فائدة

سأحاول تمثيل منظور فريق Windows هنا ... نفضل الانتقال دائمًا إلى تعيين FILE_SHARE_DELETE ، بدون أي خيار. بشكل عام ، لتسهيل النقل من / إلى Windows ، نفضل السلوك المتسق مع Linux ، ولا أرى سبب تفضيل مستخدمي Windows أو البرامج الافتراضية!

ملاحظة مثيرة للاهتمام ، على عكس تعليق mattn : في أحدث إصدار من Windows ، قمنا بتحديث DeleteFile (على NTFS) لإجراء حذف "POSIX" ، حيث تتم إزالة الملف من مساحة الاسم على الفور بدلاً من انتظار فتح الكل يعالج الملف المراد إغلاقه. لا يزال يحترم FILE_SHARE_DELETE ، ولكنه يتصرف الآن بطريقة أخرى مثل إلغاء ربط POSIX. تمت إضافة هذه الوظيفة لـ WSL واعتبرت أنها تستحق الاستخدام افتراضيًا لبرنامج Windows أيضًا.

بمعنى آخر ، إذا قمت بتشغيل برنامج اختبار mattn وتسلسل del ، dir ، إلخ على أحدث إصدار من Windows ، فسترى الملف يختفي من مساحة الاسم فورًا بعد حذف الملف ، وليس بعد انتهاء برنامج الاختبار. تمامًا مثل Linux.

لذا ، حتى في نظام Windows نفسه ، مع وجود مخاطر أكبر بشكل ملحوظ على توافق التطبيقات ، فإننا نجري تغييرات صغيرة لتسهيل نقل البرامج غير التي تعمل بنظام Windows إلى Windows. أنا حقا أشجع Go على فعل الشيء نفسه.

ال 194 كومينتر

@ ccalexbrainman

syscall.Open () على https://golang.org/src/syscall/syscall_windows.go#L272
يجب استخدام sharemode := ... | FILE_SHARE_DELETE

لماذا يجب ذلك؟

اليكس

يمكّن FILE_SHARE_DELETE مثال الكود أعلاه ، والذي يعمل على نظامي MacOS و Linux ولكنه يفشل على Windows. إنه ضروري أيضًا من أجل:

fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
defer fd.Close()
_, err = fd.Write(...)
err = fd.Sync()  // file now safe to share
err = os.Rename(path, path+"2")
_, err = fd.Read(...)

يمكّن FILE_SHARE_DELETE مثال الكود أعلاه ، والذي يعمل على نظامي MacOS و Linux ولكنه يفشل على Windows.

لماذا لا نقوم بضبط كود MacOS و Linux بدلاً من ذلك؟

إنه ضروري أيضًا من أجل:

لا أفهم ما تحاول قوله.

اليكس

networkimprov يجب استدعاء إزالة بعد الإغلاق () على Windows.

path := "delete-after-open"
fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
if err != nil { panic(err) }
fd.Close()
err = os.Remove(path)            // or os.Rename(path, path+"2")
if err != nil { panic(err) }

alexbrainman عند القيام

يمكن إعادة تسمية الملفات المفتوحة أو حذفها افتراضيًا على Unix. يبدو أنه من الخطأ عدم تعيين علامة Windows لهذه الإمكانية. أشك في أننا سنقنع فريق Go بتغيير طريقة عمله مع Linux و MacOS :-)

mattn الرجاء تطبيق الإصلاح الذي وصفته وجرب الكود الذي نشرته.

أشك في أننا سنقنع فريق Go بتغيير طريقة عمله مع Linux و MacOS :-)

أنا بخير كما هي الأمور الآن.

اليكس

هل هناك سبب منطقي لحذف هذه الإمكانية المشتركة في Windows؟

هل يمكنك توفير مفتاح في syscall_windows.go حتى نتمكن من تحديد سلوك Unix عند بدء البرنامج؟

أنا بخير لأننا نضيف واجهة برمجة تطبيقات جديدة أو أعلام. لكن لدي اعتراض على تغيير السلوك الحالي. نظرًا لأن FILE_SHARE_DELETE يختلف عن سلوك Unix.

#include <windows.h>
#include <stdio.h>

int
main(int argc, char* argv[]) {
  HANDLE h = CreateFile("test.txt",
      GENERIC_READ | GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
      NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  getchar();
  char buf[256] = {0};
  DWORD nread;
  printf("%d\n", ReadFile(h, buf, 256, &nread, NULL));
  printf("%s,%d\n", buf, nread);
  return 0;
}

قم بتجميع هذا الرمز على Windows ، وحاول تشغيله كـ test.exe . أثناء انتظار هذا التطبيق ، افتح cmd.exe جديدًا ، واحذف "test.txt" كما يلي.

image

يمكن حذف الملف ولكن يبقى هناك أثناء وجود العملية. لذلك لن يعمل هذا التغيير بشكل جيد مع ما تتوقعه.

أدرك أن إدخال الدليل لم تتم إزالته ولكن المستندات تقول

تفشل الاستدعاءات اللاحقة إلى CreateFile لفتح الملف مع ERROR_ACCESS_DENIED.

لذلك أنا لا أفهم سجل الشاشة الخاص بك.

على أي حال ، سيكون مفتاحًا كهذا جيدًا:

syscall.OpenFileShareDelete = true

أود أن أذكر أنني تعرضت للعض من هذا في العمل من قبل.

في الأساس كان لدينا:

f, err := os.Open(...)
if err != nil { ... }
defer f.Close()

// lots of code

if err := os.Rename(...); err != nil { ... }

تم تشغيل الكود بشكل جيد على منصات CI المستندة إلى نظام يونكس ، ولكنه انفجر على نظام Windows.

بافتراض عدم وجود أي آثار جانبية غريبة ، سيكون من الجيد إذا نجحت الأمور للتو .

IIRC ، لقد أجرينا بعض التعديلات على سلوك GOOS = windows & plan9 في الماضي لمطابقة دلالات Unix بشكل أوثق. لا أمانع في جعل هذه حالة أخرى من هذا القبيل إذا كانت الدلالات قريبة بما فيه الكفاية. ومع ذلك ، فإن تعليق mattn يشير إلى أن السلوك ليس قريبًا بما يكفي ، لذا فقد لا يستحق كل هذا العناء.

لا أريد أن أرى بعض الخيارات العالمية ، رغم ذلك. هذا يبدو وكأنه كابوس تصحيح الأخطاء.

تضمين التغريدة
ربما لا ، يرجى الرجوع إلى تعليقي هنا
https://groups.google.com/forum/#!topic/golang -dev / R79TJAzsBfM
أو إذا كنت تفضل ، يمكنني نسخ المحتوى هنا ، حيث يوجد أيضًا حل محتمل ، على الرغم من أنني لن أقوم بتطبيقه كسلوك افتراضي ، لأن هذا لن يكون متسقًا مع كيفية تصرف برامج windows ، بل حلًا بديلًا لإنشاء تقاطع مشابه -لنا الخبرة.

guybrand يكتب في موضوع golang-dev:

يقوم برنامجي بكتابة ملف يسمى "my.data" ، ثم يستدعي برنامجًا آخر ولا ينتظر حتى ينتهي ... يتيح هذا البرنامج لنقل هذا الملف الذي يستغرق 10 ثوانٍ (دعنا نطلق على هذا البرنامج الآخر "برنامج التحميل") .
...
عندما يستدعي برنامجي. إزالة على Windows (FILE_SHARE_DELETE قيد التشغيل):
...
سيتلقى القائم بالتحميل رسالة خطأ تفيد بإزالة الملف (ربما EOF).

بافتراض أن "برنامج الرفع" يفتح الملف قبل أن يستدعي "برنامجي" os.Remove () ، أعتقد أنك تعارضت مع مستندات Win API:

_DeleteFile يضع علامة على ملف للحذف عند الإغلاق. لذلك ، لا يتم حذف الملف حتى يتم إغلاق المؤشر الأخير للملف. تفشل الاستدعاءات اللاحقة لـ CreateFile لفتح الملف مع ERROR_ACCESS_DENIED._

إعادة "إقران _open_osfhandle () من CreateFile بـ _fdopen" ، هل يمكنك الإشارة إلى مثال التعليمات البرمجية؟

إذا أضفنا FILE_SHARE_DELETE ، فسيستخدمه العديد من المبرمجين عن طريق الخطأ لمحاكاة سلوك Unix. في هذه الحالة ، يمكنك إنشاء دالة مفصولة بقيود الإنشاء لكل نظام تشغيل. ويجب أن يُرجع os.NewFile() ، استخدم FILE_SHARE_DELETE على Windows.

اجعل دالة مفصولة بقيود البناء لكل نظام تشغيل ... إرجاع os.NewFile () ، استخدم FILE_SHARE_DELETE على Windows

للاحتفاظ بوظيفة os.OpenFile () ، يبدو أن هذه الخطة تتطلب إعادة تنفيذ كل:

os.OpenFile ()
openFileNolog ()
openFile ()
openDir ()
ملف جديد()
fixLongPath ()
syscall.Open ()
makeInheritSa ()

تضمين التغريدة

guybrand يكتب في موضوع golang-dev:

يقوم برنامجي بكتابة ملف يسمى "my.data" ، ثم يستدعي برنامجًا آخر ولا ينتظر حتى ينتهي ... يتيح هذا البرنامج لنقل هذا الملف الذي يستغرق 10 ثوانٍ (دعنا نطلق على هذا البرنامج الآخر "برنامج التحميل") .
...
عندما يستدعي برنامجي. إزالة على Windows (FILE_SHARE_DELETE قيد التشغيل):
...
سيتلقى القائم بالتحميل رسالة خطأ تفيد بإزالة الملف (ربما EOF).

بافتراض أن "برنامج الرفع" يفتح الملف قبل استدعاء "برنامجي" os.Remove () ، ألا تتعارض مع مستندات Win API؟

يقوم DeleteFile بوضع علامة على ملف للحذف عند الإغلاق. لذلك ، لا يتم حذف الملف حتى يتم إغلاق المؤشر الأخير للملف. تفشل الاستدعاءات اللاحقة إلى CreateFile لفتح الملف مع ERROR_ACCESS_DENIED.

إعادة "إقران _open_osfhandle () من CreateFile بـ _fdopen" ، هل يمكنك الإشارة إلى مثال التعليمات البرمجية؟

لا أرى أي تناقض مع واجهة برمجة تطبيقات WIndows ، يرجى الإشارة إلى ما يشبه التناقض.

بالنسبة لعينة رمز ، بحثت في Google قليلاً ووجدت هذا:
http://blog.httrack.com/blog/2013/10/05/creating-deletable-and-movable-files-on-windows/

لكن
يرجى ملاحظة أن هذا سيمنحك سلوكًا مشابهًا للنافذة داخليًا فقط ، وأي برنامج خارجي آخر يعمل معه سيؤدي إلى كسره (لأنه 99٪ يستخدم واجهة برمجة تطبيقات windows القياسية

تضمين التغريدة
إذا كنت تقصد أن "هذا يبدو مثل" dir my.data "سيعرض الملف ، بقدر ما أتذكر أن هذا كان السلوك حتى windows .... XP أو 7 (لا أتذكر أي منها) وتغيرت منذ ذلك الحين (ربما يخفي المستكشف فقط بطريقة ما) - يمكنني إعادة الاختبار في المرة التالية التي أقوم فيها بتشغيل برنامج windows. (يحدث كل بضعة أسابيع ...)

إذا كنت تقصد "هذا يبدو مثل العمليات الأخرى التي لها مقبض للملف ستظل قادرة على القراءة والكتابة إلى الملف" ، فأنا أراهن على الغداء في الثانية التي تقرأ فيها الكتابة إلى مثل هذا الملف تحصل على خطأ نمط "EOF" - ولكن يجب التأكيد مرة أخرى ليكون موجبًا بنسبة 100٪.

في كلتا الحالتين ، ستكون وجهة نظري (في هذه المرحلة - أتخذ "جانبًا" في النقطة "الأصلية مثل" مقابل نقطة "نظام التشغيل غير الحيادي") - حتى إذا قمت بتنفيذ حل نمط _fdopen ، فستحصل على عدم تناسق بين خدمتك و جميع الملفات التنفيذية الأخرى التي تتعاون معها ، لذلك يمكن أن يكون الاستخدام فقط بالتفاعل مع ملفات go التنفيذية الأخرى (أو الخدمات النادرة التي تستخدم fd مباشرة).

بعبارة أخرى - سيكون تطبيقك "أذكى طفل في الفصل" - لا يستطيع أي طفل آخر فهمه.
مثالان من العديد مما يمكنني التفكير فيه:
المدخلات :
يقوم تطبيقي بتنزيل ملف ، ويحدد برنامج مكافحة الفيروسات أنه ملفوف ويحذف / quarantines (== نوع من إعادة تسميته) ، إذا استخدمت fd - فسيظل تطبيقي قادرًا على فعل ما يريد به (وهو تجميع ، ولكن قد ينتهي حتى الإصابة بفيروس ...)
النواتج :
يقوم تطبيقي بنقل ملف إلى خدمة أخرى ("رافع" مثل) ، وحذفه ، حتى أنني أزعجت نفسي وكتبت أحد المختبرين لمعرفة أن كل شيء يعمل بشكل جيد - وينجح الاختبار.
الآن بدلاً من اختبار go الخاص بي ، أستخدم filezilla ، نحن نتحول ، dropbx API ، أيا كان
سيفشل / لا يتصرف بنفس الطريقة التي يعمل بها اختباري ...

هل ما زلت تعتقد أن تغيير هذا إلى السلوك الافتراضي أمر منطقي؟

هل هناك سبب منطقي لحذف هذه الإمكانية المشتركة في Windows؟

لم أفكر قط في هذا السؤال. لا اعرف.

تتوافق طريقة عمل ملفات Go على Windows مع جميع أدوات المطورين الأخرى التي استخدمتها في حياتي. سيكون من المدهش بالنسبة لي ، إذا كانت ملفات Go ستعمل كما تقترح. كما أظن أنه سيؤدي إلى كسر العديد من البرامج الحالية.

اليكس

كما أظن أنه سيؤدي إلى كسر العديد من البرامج الحالية.

alexbrainman لقد اقترحت أيضًا مفتاحًا لتمكينه ، بدلاً من تغيير

bradfitz هناك syscall.SocketDisableIPv6 ، وهذا لا يختلف حقًا عن علامة لضبط سلوك syscall.Open ().

منذ حالات syscall_windows * .go
func Open (سلسلة المسار ، الوضع int ، perm uint32) (معالجة fd ، خطأ err) {
....
وضع المشاركة: = uint32 (FILE_SHARE_READ | FILE_SHARE_WRITE)

و type_windows * .go
FILE_SHARE_DELETE = 0x00000004

كل شيء جاهز تمامًا ، والسؤال الوحيد هو كيفية تنفيذ العلم.
لا أحب الخيار العام كما أنه غير واضح ، وبينما قد يتذكر مطور واحد أنه قد قام بتعيين os.DeleteUponLastHandleClosed = 1 ، فهي ليست ممارسة جيدة لمطور طويل أو متعدد.
قد تكون الخيارات الأخرى إما تعيين رقم محجوز محدد للأعلام ، كما في:
fd ، err: = os.OpenFile (المسار ، os.O_RDWR | os.O_CREATE | os.DELETE_WHEN_FREED ، 0600)
بينما يمكن أن تكون قيمة DELETE_WHEN_FREED صفرًا بالنسبة إلى البيئة. بخلاف النوافذ ،

هناك خيار آخر يتمثل في استخدام المعامل perm ، وهو غير مدعوم للنوافذ ، وقد يصبح هذا الأمر محرجًا بعض الشيء
fd ، err: = os.OpenFile (المسار ، os.O_RDWR | os.O_CREATE ، 777)
777 محجوز ، لذلك سنحتاج إما 1777 أو -777 رو لدعم كلا النظامين
لجعلها قابلة للقراءة DELETE_WHEN_FREED | 777

الخيار الأخير الذي يمكنني التفكير فيه هو os.OpenDeletableFile (
الذي من شأنه أن os.OpenFile على لا شىء و
منعطف أو دور
وضع المشاركة: = uint32 (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
على النوافذ

جميع الحلول المذكورة أعلاه سهلة التنفيذ ، وقليل من الوقت للاختبار (عبر نظام التشغيل) ، فقط بحاجة إلى ناخب ...

قد تكون إحدى طرق دعم هذا السلوك دون تغيير الإعدادات الافتراضية أو توسيع سطح واجهة برمجة التطبيقات هي قبول syscall.FILE_SHARE_DELETE في المعلمة flag os.OpenFile على Windows وطيها في الحساب المحسوب sharemode value. نظرًا لأن العلامات syscall.O_* (وبالتالي os.O_* ) على Windows تستخدم قيمًا مكونة على أي حال ، يمكن تصميمها لتجنب الاصطدام بأي علامات خاصة بـ Windows يريد المرء تضمينها. لحسن الحظ ، لقد تجنبوا بالفعل الاصطدامات مع syscall.FILE_SHARE_DELETE .

على أي حال ، سأعارض بشدة تغيير السلوك الافتراضي. جعل FILE_SHARE_DELETE الخيار الافتراضي سيضعك في نفس وضع أنظمة POSIX من حيث عدم القدرة على ضمان اجتياز نظام الملفات الخالي من العرق. وجود هذه العلامة اختياري هو سبب عدم حاجة Windows إلى ما يعادل openat ، renameat ، readlinkat ، إلخ.

لم أفكر حقًا فيما يجب أن نفعله هنا ، لكني أريد أن أوضح شيئًا واحدًا:

هل يمكنك توفير مفتاح في syscall_windows.go حتى نتمكن من تحديد سلوك Unix عند بدء البرنامج؟

لن نفعل هذا. سيجعل ذلك من المستحيل على برنامج واحد استخدام حزم مختلفة تتوقع سلوكًا مختلفًا.

@ الخراب io
قد يؤدي اقتراحك إلى إنشاء برامج عرضة للخطأ مثل syscall. يختلف FILE_SHARE_DELETE عن سلوك POSIX std.
يرجى ملاحظة أن مؤلفي syscall_windows * .go كانوا على دراية بعلامة FILE_SHARE_DELETE (الموجودة هناك) وقرروا أن استخدامها لن يكون السلوك المفضل.
لماذا ا؟

لنأخذ كود ليام ، هو
تأجيل fd.Close ()
يحذف / يعيد تسمية
ثم يقرأ / يكتب

ترتيب الفرز الفعلي هو
افتح
وضع علامة على أنه محذوف
القراءة / الكتابة (وربما عملية متقاطعة / عبر الذهاب والقراءة الروتينية والكتابة أيضًا)
أغلق

سلوك الويندوز الحالي ينبه المطور "هذا خطأ" ، ربما يدفع المطور الحذف ليتم تأجيله أيضًا
إذا قمت بإضافة FILE_SHARE_DELETE ، فستسمح لك النوافذ "بوضع علامة على أنها محذوفة بالرغم من أن الملف مفتوح" ولكن عملية أخرى / goroutine تعمل بشكل متزامن والتي ستحاول الوصول إلى الملف بين الحذف والإغلاق (وهي على الأرجح المهمة الأطول في هذا الرمز ) ستفشل
النتيجة: بدلاً من السلوك المتسق "يمكنك فعل ذلك" - ستحصل على "أحيانًا - خاصةً عندما يكون هناك العديد من المستخدمين المتزامنين ، فإنه يفشل ولا أعرف السبب.
لذلك ، لا تحل المشكلة ، فقط التعامل مع حالة استخدام محددة "شغّلها المطور مرة واحدة فقط"
تصويتي هو للسلوك المتسق بالطبع ...

كيف يختلف هذا عن Posix؟
بمجرد وضع علامة "محذوف" على الملف لم يعد موجودًا في جدول الملفات ، فإنه يوجد فقط كـ fd ، مما يسمح بإجراء / عملية أخرى لإنشاء ملف بنفس الاسم.

أعتقد أننا يجب أن نتوقف عن البحث عن "نفس الحل" حيث توجد اختلافات لن نحلها داخل go (أسماء ملفات حساسة لحالة الأحرف؟ :) سنترك Linux 5.2 يفعل ذلك ...)

إجمالاً ، يبدو أنه يبحث عن حل لملف مؤقت ، إذا كان كذلك ، فإن Windows يدعم GetTempFileName والذي يمكن اعتباره حلاً قياسيًا لملف يتم "استخدامه ثم حذفه".

من ناحية أخرى ، إذا كنا نرغب في السماح للمطور بتأجيل الحذف في windows ، فهذا ممكن ، انظر اقتراحاتي أعلاه ، ولكن يجب على المطور تحمل المسؤولية عن ذلك ، وفهم الوعي - لذلك يجب أن يكون علمًا له اصطلاح جيد.

الاستخدام الأساسي لهذه الميزة هو إعادة تسمية ملف مفتوح بعد إنشائه:

fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
_, err = fd.Write(...)
err = fd.Sync()  // file now safe to share
err = os.Rename(path, shared_path)
// os.Close() at program exit

لا أعرف لماذا لا تضيف علامة os.O_WRNDEL (إعادة تسمية / حذف windows ؛ no-op على الأنظمة الأساسية الأخرى) ، وتوثيق اختلافات هذا الوضع مع Unix ؛ أن الملف المحذوف يبقى في دليله ، ولكن لا يمكن فتحه ، حتى os.Close (). اذكر أيضًا أن نقل الملف إلى مسار مؤقت قبل حذفه يوفر سلوكًا يشبه سلوك يونكس.

guybrand أعتقد أنك ربما تسيء فهم اقتراحي. أنا لا أدعو إلى تمكين FILE_SHARE_DELETE افتراضيًا - في الحقيقة أنا أعارض ذلك للأسباب المذكورة في الفقرة الثانية من تعليقي. كان اقتراحي يتعلق بآلية تسمح للمستخدمين بالاشتراك في سلوك FILE_SHARE_DELETE (على أساس كل ملف) مع الاستمرار في استخدام البنية التحتية لملفات الحزمة os . يوفر هذا الاقتراح آلية للقيام بذلك دون تمديد سطح API لأي حزمة.

لا أعرف سبب عدم إضافة علامة os.O_WRNDEL (إعادة تسمية / حذف windows ؛ منع تشغيل على الأنظمة الأساسية الأخرى)

networkimprov هذا ما syscall.FILE_SHARE_DELETE . سيكون التغيير الوحيد في التنفيذ هو مراقبة هذه العلامة في syscall.Open على Windows وإضافة الشيكات لضمان عدم تعارض أي إضافات مستقبلية إلى syscall.O_* / os.O_* مع هذه العلامة. يمكن بعد ذلك تحديث وثائق os.OpenFile لتعكس قبول هذه العلامة على Windows.

@ havoc-io آسف لسوء التفاهم ، كان هذا إخراجي من:
"... لقبول syscall.FILE_SHARE_DELETE ... في الوضع المشترك المحسوب ..."

إضافة os.O_WRNDEL يطابق اقتراحي الثاني بصرف النظر عن كونه غير واضح بما يكفي للمطور من حيث "ما هو السلوك" ، ربما os.WADRNDEL - يسمح Windows بإعادة التسمية / الحذف المؤجلة).

alexbrainman لقد اقترحت أيضًا مفتاحًا لتمكينه ، بدلاً من تغيير

لست مهتما. شكرا لك.

اليكس

لم يتم تأجيل guybrand إعادة تسمية ملف مفتوح ، راجعت.

آسف ، أنا أسأل مرة أخرى ما هو اقتراحك؟ حذف الملف الافتتاحي؟ إعادة تسمية ملف الافتتاح؟ على حد سواء؟

ثلاثة منا يقترحون الآن علمًا جديدًا ، على سبيل المثال

fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE| os._WRNDEL, 0600)

fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE| syscall.FILE_SHARE_DELETE, 0600)

ثلاثة منا يقترحون الآن علمًا جديدًا

أعتقد أن العلم الجديد غير مناسب ، خاصة العلم الذي لا يمكن تحليله بسهولة بواسطة شخص يقرأ الكود. قد يكون استخدام syscall.FILE_SHARE_DELETE أكثر وضوحًا ووضوحًا ، حيث يشير على الفور إلى القارئ أن شيئًا خاصًا بالمنصة يحدث.

هذا مسموح به بالفعل على منصات POSIX. هناك العديد من العلامات الخاصة بـ POSIX (وحتى الخاصة بالنظام الأساسي) open التي لم يتم دمجها في حزمة os . على سبيل المثال ، لن يكون من المنطقي إضافة شيء مثل os._DEVTONLY لدعم علم Darwin O_EVTONLY ، لأنه يمكنك فقط تمرير العلم من الحزمة syscall مباشرة إلى os.OpenFile ، على سبيل المثال:

os.OpenFile(..., os.O_RDONLY | syscall.O_EVTONLY, ...)

في هذه الحالة ، سيتم تمرير العلامة الخاصة بالمنصة إلى استدعاء النظام الأساسي open .

إذا كان السلوك FILE_SHARE_DELETE أمرًا يحتاجه الناس حقًا ، فأعتقد أن الإجابة هي ببساطة جعل os.OpenFile قادرًا على ربط إشارات التسلسل بالمثل إلى CreateFileW call على Windows. على الأقل مقابل FILE_SHARE_DELETE .

يمكن العثور على مثال للتنفيذ هنا .

تضمين التغريدة

ثلاثة منا يقترحون الآن علمًا جديدًا ، على سبيل المثال

ماذا تتوقع العلم؟

لم يتم تأجيل guybrand إعادة تسمية ملف مفتوح ، راجعت.

صحيح ، لكن كلاهما يحتاج إلى FILE_SHARE_DELETE للسماح به أثناء فتح الملف
إذا كنت تشير إلى المصطلحات المقترحة ، فيمكننا ذلك
os.WARNDFDEL - يسمح Windows بإعادة التسمية والحذف المؤجل طويل جدًا ، سأستخدم اختصارًا على الإطلاق WINDOWS_ALLOW_OPENNED_FILE_RENAME_OR_DEFFERED_DELETE
هو أفضل IMO.

guybrand لا أرى حقًا قيمة إضافة علامة جديدة خاصة بالمنصة مع اسم معقد وسلوك معتم إلى حزمة os عندما يكون هناك علامة جيدة تمامًا لهذا الأمر منذ عقود ( FILE_SHARE_DELETE ). استخدام syscall.FILE_SHARE_DELETE كعلم لهذا الأمر أكثر وضوحًا ووضوحًا. كما ذكرت أعلاه ، هناك العديد من العلامات الخاصة بـ POSIX والخاصة بالنظام الأساسي التي لم تتم إضافتها إلى حزمة os ولكنها لا تزال مقبولة من قبلها.

syscall.FILE_SHARE_DELETE هو windows فقط ؛ نحن بحاجة إلى شيء غير متوفر في مكان آخر. ربما يجب أن يظهر في pkg os ، ببادئة WIN أو WINDOWS؟

mattn الرجاء الاطلاع على التصحيح أعلاه من @ havoc-io

نحن بحاجة إلى شيء غير متوفر في مكان آخر.

networkimprov لا يلزم وجود العلامة في مكان آخر. سيبدو رمز Windows الخاص بك كما يلي:

import (
    "syscall"
    "os"
)

file, err := os.OpenFile(..., os.O_RDWR | syscall.FILE_SHARE_DELETE, ...)

نعم ، يجب أن يتم وضع هذا الرمز على النظام الأساسي ، ولكن ربما ستحتاج إلى القيام بذلك على أي حال لأن السلوك باستخدام هذه العلامة لن يتطابق مع سلوك أنظمة POSIX. أو ، إذا كنت ترغب في الحصول على نفس الرمز على جميع الأنظمة الأساسية ، يمكنك تحديد الثابت الخاص بك (بقيمة syscall.FILE_SHARE_DELETE على Windows و 0 على الأنظمة التي لا تعمل بنظام Windows) واجتياز إلى os.OpenFile . هذا هو بالضبط ما ستفعله إذا أردت إحضار علامة O_* خاصة بالمنصة التي لم تكن جزءًا من حزمة os (على سبيل المثال O_EVTONLY في داروين أو O_ASYNC على Linux).

عندما أكتب رمزًا أتوقع أن يكون عبر النظام الأساسي ، فإن FILE_SHARE_DELETE غير موجود في syscall_ * فقط windows one (وبالتالي لن يتم تجميع anf على أنظمة أخرى).

هل يمكننا استخدام 0x4 const ، على النحو التالي:
FILE_SHARE_DELETE = 0x00000004

بصرف النظر عن كونها قبيحة ،
netbsd_arm
O_NDELAY = 0x4
O_NONBLOCK = 0x4

لذا فإن استخدام 0x4 سيخلق الكود الذي يختلف في netbsd_arm.

لذلك إما أن نضيف FILE_SHARE_DELETE إلى جميع الأنظمة الأساسية ، فإن windows منها سيكون 0x4 والبعض الآخر سيكون 0x0 وبالتالي "نتجاهله" ، أو ننشئ علامة محددة لهذه المشكلة.

وعلى أية حال يجب علينا تغيير syscall_windows *
func مفتوح (
...
وضع المشاركة: = uint32 (FILE_SHARE_READ | FILE_SHARE_WRITE | isDeleteOn)
حيث سيتحقق isDeleteOn مما إذا كان الوضع يتضمن العلم الجديد

تضمين التغريدة

عندما أكتب رمزًا أتوقع أن يكون عبر النظام الأساسي

أود أن أحذرك من أنه لمجرد أن نفس المكالمة os.OpenFile تجميعها على منصات متعددة ، فهذا لا يعني أن الكود الخاص بك يعمل عبر الأنظمة الأساسية. هناك عدد من اعتبارات الأمان على نظام التشغيل Windows والتي يجب أن تأخذها في الاعتبار عند استخدام FILE_SHARE_DELETE ، وتختلف دلالات دورات حياة الملفات بين أنظمة POSIX و Windows بحيث يصعب تخيل سيناريو يكون فيه لن يبدو رمز معالجة الملفات مختلفًا قليلاً على الأقل بين الأنظمة الأساسية. يؤدي استخدام FILE_SHARE_DELETE أساسي إلى وضعك في وضع ما قبل POSIX.1-2008 ، دون أي وسيلة لضمان اجتياز نظام الملفات الخالي من العرق (وبدون الاستفادة من POSIX's post- unlink وصول ملف للفتح الملفات).

على أي حال ، إذا كنت تريد علامة بقيمة syscall.FILE_SHARE_DELETE على Windows و 0 على الأنظمة الأساسية الأخرى ، فلا يزال بإمكانك القيام بذلك بسهولة باستخدام تعريفك الثابت الذي يتم التحكم فيه بواسطة علامات الإنشاء ، ثم يمكن أن تكون الكود الرئيسي الذي يستدعي os.OpenFile هو نفسه على جميع الأنظمة الأساسية (باستخدام هذا العلم المخصص).

هناك العديد من العلامات الخاصة بالمنصة الموجودة في حزم الأنظمة الأساسية الأخرى ' syscall ، لكن لا يمكن كشفها جميعًا بواسطة حزمة os ولا يمكن تشغيلها على الأنظمة الأساسية حيث لا توجد' ر المدعومة. إذا كنت تريد رمزًا وسلوكًا خاصين بالمنصة ، فمن الضروري الوصول إلى حزمة syscall .

الشيء الوحيد الذي يجب أن تفعله مكتبة Go القياسية هنا هو دعم syscall.FILE_SHARE_DELETE في syscall.Open (وبالتالي os.OpenFile ) على Windows.

كما ذكرت أعلاه ، إذا أضفنا FILE_SHARE_DELETE ، فسيستخدمه العديد من المبرمجين عن طريق الخطأ لمحاكاة سلوك Unix. لكنها ليست جيدة. على سبيل المثال ، يرجى التفكير في حالة إنشاء تطبيق لمشاهدة الملف موجود. من المفترض ألا يتم العثور على ملف من تطبيقات أخرى إذا قام أحد التطبيقات بحذف ملف. لكن FILE_SHARE_DELETE لا يضع علامة إلا للحذف لاحقًا. الملف متبقي. في UNIX ، يعمل بشكل جيد ، لكن Windows لا يعمل. الرجاء عدم استخدام FILE_SHARE_DELETE لمحاكاة سلوك UNIX.

mattn أتفق مع مخاوفك - قد يحاول الأشخاص استخدام العلامة كوسيلة راحة لجعل رمز Windows "يعمل بنفس الطريقة" مثل أنظمة POSIX دون فهم الآثار الدقيقة. ومع ذلك ، أعتقد أنه إذا كان عليهم الانتقال إلى الحزمة syscall للوصول إلى هذه العلامة ، فربما يكونون قد استغرقوا الوقت الكافي لفهم ما يفعله.

mattn ، لسلوك يشبه Unix ، ستحتاج التطبيقات إلى سطرين إضافيين من التعليمات البرمجية المحايدة للنظام الأساسي:

fd, err := os.OpenFile(path, ... | syscall.FILE_SHARE_DELETE, 0600)
...
tmp_path := mkTempName()
err = os.Rename(path, tmp_path)  // works immediately; path is now available
err = os.Remove(tmp_path)

يتطلب توثيق ذلك جملة واحدة في المستندات لـ os.OpenFile ().

الرجاء عدم جعلني أقوم بتوزيع تصحيح على pkg syscall الذي يجب على كل من يعمل على رمز windows الخاص بي تطبيقه! راجع أيضًا https://github.com/golang/go/issues/32088#issuecomment -493876119.

أعتقد أننا نتفق جميعًا على معظم الحقائق ، ما عليك سوى صياغتها بشكل مختلف لذلك سأحاول تلخيصها وإعداد مسار للعمل:

  1. متفق عليه: يختلف Windows و POSIX في السلوك أعلاه ويجب ألا نحاول استهداف نفس السلوك.
  2. تمت الموافقة: طلب السماح بـ FILE_SHARE_DELETE كعلامة مفيد
  3. اقتراح: دعنا نغير التذكرة إلى "دعم FILE_SHARE_DELETE" حتى يبدو الأمر وكأنه طلب ميزة وليس خطأ
  4. متفق عليه في الغالب: يجب أن تكون الميزة علامة مطور على مستوى البرنامج ، وليس الانتقال إلى الحزمة الأساسية.

خطوات العمل:

  1. قم بتغيير syscall_windows.go
    func مفتوح (
    ...
    وضع المشاركة: = uint32 (FILE_SHARE_READ | FILE_SHARE_WRITE | (الوضع & FILE_SHARE_DELETE) )
  2. المطور الذي يرغب في الاستفادة من هذا السلوك إما
    file, err := os.OpenFile(..., os.O_RDWR | syscall.FILE_SHARE_DELETE, ...)
    أو إذا كانوا يرغبون في أن يكون برنامجهم عبر الأنظمة الأساسية ، فسيؤدي ذلك إلى إنشاء علم داخلي لـ:

mycode_windows.go
const OPENFILEFLAG = syscall.FILE_SHARE_DELETE
mycode_others.go
const OPENFILEFLAG = 0

ثم استخدم:
file, err := os.OpenFile(..., os.O_RDWR | OPENFILEFLAG, ...)

إذا تم الاتفاق على هذا ، يكون الإصلاح ضئيلًا (بطانة واحدة) ، مع مخاطر منخفضة جدًا

دعنا نصوت على هذا ، ويمكننا إصلاح هذا بسرعة

تمت الموافقة: طلب السماح بـ FILE_SHARE_DELETE كعلامة مفيد

لا أتفق مع هذا حتى الآن لأنني لا أفهم ما هو الغرض من هذه المشكلة؟

mattn الرجاء مراجعة https://github.com/golang/go/issues/32088#issuecomment -494305074

الغرض: السماح للمطورين بإعادة تسمية الملفات المفتوحة أو حذفها.

ما هو مفقود: syscall_windows.go حاليًا مشفر بشكل ثابت :
func Open(path string, mode int, perm uint32) (fd Handle, err error) {
...
sharemode := uint32(**FILE_SHARE_READ | FILE_SHARE_WRITE**)

التغيير المقترح:
عندما يقوم المطور بتمرير معلمة وضع مع تشغيل bitwise 4 (FILE_SHARE_DELETE) ، سيتغير وضع المشاركة وفقًا لذلك بواسطة
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | **(mode & FILE_SHARE_DELETE)** )

ما زلت أتساءل لماذا لا تتصل بإغلاق () قبل إعادة تسمية () أو إزالة (). يمكنك قراءة كود مكتبة Go القياسية. يتم إغلاق الملفات عن طريق إغلاق () قبل إعادة تسمية () أو إزالة (). لماذا يجب عليك استدعاء Close () بعد Renamoe / Rename؟

لست متأكدًا من حالة العمل التي تفكر فيها إخراجي من هذا الملف عبارة عن ملف مشترك مؤقت - يستخدم تطبيقي وتطبيق آخر هذا الملف ، أريد التأكد (حتى إذا تعطل تطبيقي) من هذا الملف لن يكون موجودًا بعد أن انتهيت - لذلك أقوم بإنشائه وإزالته () وعندما أقوم بإغلاقه أو إغلاق تطبيقي - تتم إزالة الملف.

ولكن يبدو أن @ networkimprov يريد استخدام Rename () ، لذلك من المحتمل أن يكون هناك حالة استخدام مختلفة.

كما هو مذكور في https://github.com/golang/go/issues/32088#issuecomment -494305074 ، قد لا نحتاج إلى إغلاق ملف تمت إعادة تسميته حتى إنهاء البرنامج.

mattn ، الثابتة والمتنقلة لا تصر على عدم استخدام ميزة نظام التشغيل التي يمكن لمطوري C و C ++ استخدامها.

أريد أن أتأكد (حتى في حالة تعطل تطبيقي) أن هذا الملف لن يكون موجودًا بعد أن انتهيت

guybrand لا يمكن ضمان تشغيل عبارة defer في كل نوع من التعطل ، لذلك إذا كنت تحاول التأكد من حذف الملف ، فإن تأجيل عملية os.Remove لا يعد طريقة موثوقة اذهب عن ذلك. إذا كنت تريد ملفًا يتم حذفه تلقائيًا ، فإن الملف المؤقت الذي يحذفه النظام هو خيار أفضل. إذا كنت تريد موقع ملف يتم مشاركته بواسطة برنامجين ، فيجب تنسيقه بواسطة أقفال (على سبيل المثال ، أقفال fcntl على POSIX و LockFileEx / UnlockFileEx على Windows) ، وليس وجود ملف .

كما هو مذكور في # 32088 (تعليق) ، قد لا نحتاج إلى إغلاق ملف تمت إعادة تسميته حتى إنهاء البرنامج.
mattn ، الثابتة والمتنقلة لا تصر على عدم استخدام ميزة نظام التشغيل التي يمكن لمطوري C و C ++ استخدامها.

networkimprov تعتبر عملية إعادة HANDLE ، ألا يمكنك فعل ذلك بالفعل؟ سيكون الغرض الوحيد من FILE_SHARE_DELETE هو السماح لعمليات أخرى بإعادة تسمية الملف أثناء فتحه. في أي حال، يمكنك استخدام FILE_SHARE_DELETE الآن، تحتاج فقط إلى يدويا استدعاء و CreateFileW وتمرير نتيجة قبالة ل os.NewFile . يمكنك العثور على مثال لما يبدو عليه هذا هنا . الناتج HANDLE يمكن فقط تمريره إلى os.NewFile .

mattn لقد بدأت أتفق معك على أن هذا العلم سيكون بمثابة مسدس قدم أكثر من كونه أداة مفيدة. فقط لكي أكون واضحًا ، لا أريد هذه العلامة فعليًا ، والحجج الوحيدة التي يمكنني رؤيتها لوجودها هي الاكتمال والتكافؤ في التحكم بين POSIX و Windows. من ناحية أخرى ، كما ذكرت أعلاه ، من السهل نسبيًا أيضًا استدعاء CreateFileW يدويًا (مع تحديد هذه العلامة) ثم تسليم النتيجة إلى os.NewFile ، لذلك ربما لا تكون هناك حاجة إلى أضف الدعم لذلك.

@ havoc-io لا يوجد ملف os.Rename (). سيكون هذا حلاً جيدًا ، لكنه رفع ثقيل نسبيًا.

إعادة CreateFileW + os.NewFile () ، راجع https://github.com/golang/go/issues/32088#issuecomment -493876119.

@ الخراب io

أريد أن أتأكد (حتى في حالة تعطل تطبيقي) أن هذا الملف لن يكون موجودًا بعد أن انتهيت
guybrand لا يمكن ضمان تشغيل بيان
كان هذا بالضبط ما قصدته ، عندما قلت "حتى لو تعطل تطبيقي".

الحجج الوحيدة التي يمكنني رؤيتها لوجودها هي اكتمال وتكافؤ التحكم بين POSIX و Windows
لا أوافق على أن هذا من شأنه أن يجلب "اكتمال وتكافؤ التحكم بين POSIX و Windows" - IMO سوف يربك المطور فقط ليعتقد أن السلوك هو نفسه عندما لا يكون كذلك ، لقد أعطيت بعض الأمثلة أعلاه.

من السهل استدعاء CreateFileW يدويًا
هذا حقًا تعديل ، سهل أم لا ، وبعبارة أخرى: "لا نريد دعم هذا أثناء التنقل" ، وهو بالمناسبة قرار IMO جيد ، لكن الطالب @ networkimprov ليس أنا.

لمعلوماتك ، إليك سبب تخلينا عن استخدام FILE_SHARE_DELETE.

CL: https://codereview.appspot.com/8203043/

الالتزام في erlang / otp: https://github.com/erlang/otp/commit/0e02f488971b32ff9ab88a3f0cb144fe5db161b2

بايثون: https://bugs.python.org/issue15244

@ havoc-io لا يوجد ملف os.Rename (). سيكون هذا حلاً جيدًا ، لكنه رفع ثقيل نسبيًا.
إعادة CreateFileW + os.NewFile () ، راجع # 32088 (تعليق).

networkimprov ألا يمكنك استخدام os.Rename(file.Name(), <target>) ؟ هذا هو جمال Go عدم وجود FILE_SHARE_DELETE افتراضيًا - أنت تعلم أن file.Name() سيظل يشير إلى شيء صالح نظرًا لأنك تحتفظ بالملف HANDLE (شيء يمكنك القيام به ' ضمان على POSIX ، حتى مع renameat ). بالنسبة إلى CreateFileW + os.NewFile ، فإن معظم المكدس الموصوف في تعليقك سيصبح غير ذي صلة ، ومن المؤكد تقريبًا أن makeInheritSa شيء لا تريده (إنه موجود فقط لمحاكاة POSIX's سلوك وراثة واصف ملف افتراضي سيء - ليس هذا هو الوضع الافتراضي). الشيء الوحيد الذي ستفقده هو وظيفة المسار fixLongPath ، والتي ربما لن تكون ضرورية لحالات الاستخدام التي وصفتها.

guybrand فقط لتوضيح ما أعنيه ...

الاكتمال: اكتمال سطح واجهة برمجة التطبيقات (أي القدرة على استخدام FILE_SHARE_DELETE إذا كنت تريد استخدامه لسبب ما)
تماثل التحكم: القدرة على تحديد الإشارات إلى CreateFileW عبر معلمة os.OpenFile 's flag . على سبيل المثال ، يمكنني توجيه syscall.O_NOFOLLOW عبر os.OpenFile على POSIX ، لكن لا يمكنني توجيه syscall.FILE_FLAG_OPEN_REPARSE_POINT عبر os.OpenFile على Windows. على الرغم من ذلك ، أعتقد مرة أخرى أن التكافؤ الكلي للتحكم هنا هو حلم بعيد المنال لأن الحزمة os مصممة على غرار POSIX APIs. أنا سعيد جدًا بالوصول إلى syscall.CreateFileW عندما يكون ذلك ضروريًا.

mattn شكرا على الروابط. كان Go CL هو تصحيح مكالمة النظام. Open () _default_. لا تقدم المناقشة أي سبب عام لعدم السماح بـ _flag_ لـ Open (). يشير إلى أنه يمكن لحزمة جهة خارجية إرجاع ملف نظام التشغيل يفتقر إلى العلامة ، ولكن هذه مشكلة فقط إذا حاول المتصل إعادة تسمية / حذف هذا الملف - وهي حالة زاوية نادرة.

يشير موضوع Python إلى أنه يجب عليك إعادة تسمية ملف مفتوح قبل حذفه ، كما كتبت أعلاه.

لقد كان لدى إرلانج file_share_delete باعتباره _default_ لما يزيد عن ستة أعوام .

بالنظر إلى تجربة Erlang وخيط Python المرتبط أعلاه ، من الواضح أن:

  1. File_share_delete كإعداد افتراضي يعمل بشكل جيد في بيئة عبر الأنظمة الأساسية ؛ التحذير الوحيد هو أن كود المستخدم يجب أن يعيد تسمية الملف إلى اسم فريد على الفور قبل إزالته (تغيير تافه) إذا كان من الممكن إعادة استخدام اسم الملف الأصلي.
  2. لا يمكن لمعظم برامج Windows استخدام file_share_delete لمجرد أن وقت تشغيل MSVC يسمح فقط بالاشتراك مع O_TEMPORARY.

لذلك استنتج أن syscall.Open () يجب أن يستخدم file_share_delete افتراضيًا ، ويجب أن يوفر syscall علامة عامة لتعطيله عند الضرورة (مثل تصحيح الأخطاء).

إذا ظهرت مشاكل مع هذا النهج أثناء دورة 1.14 ، فيمكن تطبيق طريقة العلم الصريح بدلاً من ذلك.

لذلك استنتج أن syscall.Open () يجب أن يستخدم file_share_delete افتراضيًا ، ويجب أن يوفر syscall علامة عامة لتعطيله عند الضرورة (مثل تصحيح الأخطاء).

networkimprov بصرف النظر عن كسر عدد كبير من البرامج الحالية بطرق خفية وغير دقيقة ، فإن حقيقة الأمر هي أن تقديم هذه العلامة الآن سيكون مشكلة أمنية للبرامج التي تعتمد على غياب FILE_SHARE_DELETE . على وجه الخصوص ، سيفتح عددًا من الثغرات الأمنية من وقت التحقق إلى وقت الاستخدام للبرامج التي تعتمد على ثبات الملفات والأدلة التي تحتفظ بها مفتوحة.

تحرير: لمزيد من القراءة حول سبب كون تغيير الإعداد الافتراضي فكرة سيئة ومن شبه المؤكد كسر البرامج الحالية ، يرجى الاطلاع على قانون Hyrum .

أكثر حالات Go on Windows شيوعًا هي التطوير ، للنشر على Linux أو Unix الأخرى.

إذا كانت شفرتك تعتمد على أي سلوك GOOS = windows ، فسيكون معطلاً وربما يكون عرضة للهجوم على Linux. لذلك لدينا بالفعل مشكلة أمنية محتملة.

os.Rename () & .Remove () لا يوثق الاختلافات على Windows ، لذلك لن يخمن أحد وجودها. لن يؤدي توثيقها الآن إلى إصلاح الكود الحالي. من شأن إصلاح عدم التوافق ونشر منشور مدونة عليه أن يساعد كثيرًا.

لاحظ أن Erlang كان موجودًا لفترة من الوقت قبل أن يتبنى file_share_delete كإعداد افتراضي.

أكثر حالات Go on Windows شيوعًا هي التطوير ، للنشر على Linux أو Unix الأخرى.

إذا كانت شفرتك تعتمد على أي سلوك GOOS = windows ، فسيكون معطلاً وربما يكون عرضة للهجوم على Linux. لذلك لدينا بالفعل مشكلة أمنية محتملة.

تضمين التغريدة

من خلال هذا المنطق ، يجب أيضًا تعديل البنية الأساسية لفتح الملف على Windows لجعل واصفات الملفات قابلة للتوريث افتراضيًا عبر إنشاء العملية ، من أجل مطابقة السلوك الافتراضي لـ POSIX. يمكن إلقاء اللوم على البرامج الحالية لاعتمادها على وقت التشغيل / السلوك الافتراضي السابق للمكتبة القياسية ، ويمكن تضمين نموذج CVE في ملاحظات الإصدار للمستخدمين لتقديمه لبرامجهم.

لكن هذا ليس ما تم فعله بالطبع ، وبدلاً من ذلك ينحني وقت تشغيل Go والمكتبة القياسية للخلف للتغلب على سلوك POSIX الافتراضي وسوء التصميم ، في محاولة لعكس ما يفعله Windows.

الوضع هو نفسه مع الوصول إلى الملفات المشتركة. يمكن القول إن Windows حصل على التصميم الصحيح ، وكان على POSIX.1-2008 إضافة عدد من الوظائف للتغلب على قيود التصميم الخاصة به.

أيضا، كماmattn وقد ذكر عدة مرات أعلاه، بما في ذلك FILE_SHARE_DELETE عند فتح الملفات لا يجعل ويندوز تتصرف مثل POSIX - ستظل هناك الاختلافات السلوكية الهامة التي سوف تصبح أكثر وضوحا مع هذا العلم من اختلاف os.Remove السلوك os.Rename .

أود أن أزعم أنه إذا كانت التعليمات البرمجية الخاصة بك تعتمد عالميًا على سلوك أي نظام أساسي ، فإنها معطلة وربما ضعيفة على الأنظمة الأساسية الأخرى (وهذا يشمل الاعتماد على سلوك POSIX على Windows). إذا كنت لا تأخذ الوقت الكافي لفهم ومعالجة الاختلافات في النظام الأساسي في التعليمات البرمجية الخاصة بك ، فأنت لا تقوم بالتطوير عبر الأنظمة الأساسية.

على أي حال ، رفضianlancetaylor بالفعل فكرة استخدام علم عالمي للتحكم في تشغيل هذا ، لذلك أشك بشدة في أنك ستحصل على إيقاف تشغيله بعد تغيير الإعداد الافتراضي.

في رأيي ، الخيار الوحيد غير المنفصل (وعدم المساس بالأمان) هنا هو إضافة دعم لـ syscall.FILE_SHARE_DELETE في syscall.Open s flag وسيطة ، أو فقط فرض المستخدمون الذين يريدون وظائف FILE_SHARE_DELETE لاستخدام CreateFileW + os.NewFile . نعم ، يتطلب الأمر القليل من العمل من المطورين الذين يريدون هذا السلوك ، لكن Win32 و POSIX هما وحشان مختلفان تمامًا ، ومن المدهش أن يقوم وقت التشغيل والمكتبة القياسية بعمل جيد كما يفعلان في التغلب على اختلافاتهما. هناك العديد من الاختلافات المهمة بين هذه الأنظمة الأساسية التي تظهر في المكتبة القياسية ، على سبيل المثال نماذج أذونات مختلفة تمامًا ، حقيقة أن os.File.Chmod لا يعمل على Windows ، os.Chown لا يعمل عليها Windows ، حقيقة أن أداة الاستقصاء الداخلية تدعم أنواعًا مختلفة من الملفات على منصات مختلفة ، وما إلى ذلك ، فإن وقت تشغيل Go والمكتبة القياسية يبذلان قصارى جهدهما (ويفعلان ذلك جيدًا) ، لكنهما ليسا الدواء الشافي لمشاكل التطوير عبر الأنظمة الأساسية. في مرحلة ما ، يتعين على المطورين التعامل مع هذه الاختلافات بأنفسهم. إضافة تغيير فاصل لتعديل (لاحظ أنني لم أقله بشكل صحيح ) ، فإن حالة الحافة السلوكية الغامضة لا تعني لي أي معنى.

كنت أرغب في مشاركة حالة استخدام أخرى لهذا الغرض.

في الوقت الحالي ، عندما يعمل منطق تدوير سجل Docker بالطريقة التي سيعيد بها محرك Docker تسمية السجل النشط إلى الاسم .1 ، أنشئ واحدًا جديدًا بالاسم القديم.
أي عميل يتابع السجل بنشاط باستخدام الأمر docker logs --follow <container>
ستلاحظ أنه من أحداث نظام الملفات:
https://github.com/moby/moby/blob/916eabd459fe707b5c4a86377d12e2ad1871b353/daemon/logger/loggerutils/logfile.go#L552 -L593

هناك أيضًا هذا المنطق الذي يجعل Windows يلاحظ هذه الأحداث على الفور:
https://github.com/moby/moby/blob/916eabd459fe707b5c4a86377d12e2ad1871b353/daemon/logger/loggerutils/logfile.go#L670 -L676

كل هذا يعمل بشكل جيد على Linux ولكن في Windows log rotate يفشل في الخطأ The process cannot access the file because it is being used by another process. إذا كان هناك أي عملاء يتبعون السجل (المشكلة: https://github.com/moby/moby/issues/39274)

نظرًا لأنه من الممكن أن يكون لديك عدد n من هؤلاء العملاء الذين يتابعون السجل ، فسيكون من الصعب جدًا أولاً جمع كل مقابض الملفات المفتوحة هذه وإغلاقها قبل تدوير الملف ، لذلك أود حقًا أن أرى أنه من الجيد الحصول على دعم لـ syscall.FILE_SHARE_DELETE علم.

مرحبا! خلفية سريعة: أعمل على البنية الأساسية لـ Chrome CI. نحن ننقل رمز العامل منخفض المستوى إلى Go. نجري مئات الآلاف من استدعاء الاختبارات على Windows يوميًا.

لقد قرأت جميع التعليقات وآمل أن يكون ما يلي ملخصًا واضحًا وصحيحًا لرأي كل فرد.

حالة الاستخدام لدينا هي إنشاء ملفات Go التنفيذية على Windows للتشغيل على Windows ، على عكس التوصيف المدهش لـ سأتجاهل حالة استخدام "افتراض سلوك POSIX على Windows" في هذا التعليق لأنه مجرد افتراض غير صحيح وسحب خلافية ، أدناه أكثر من ذلك.

كجزء من عملية الترحيل ، نحتاج إلى FILE_SHARE_DELETE ، ويرجع ذلك جزئيًا إلى تدوير ملف السجل ، على غرار # 39274. يحدث أنها أيضًا مشكلة في الإصدار رقم 25965.

أتفق مع ianlancetaylor تغيير سلوك toolchain بالكامل ، كما هو مقترح في https://codereview.appspot.com/8203043/ ليس فكرة جيدة. إحدى المشكلات الفورية التي تتبادر إلى الذهن هذا الاقتراح عند استخدام مقبض ملف كملف قفل. نحن نستخدم هذا السلوك. وماذا قال @ havoc-io. لذلك دعونا نتجاهل هذا أيضًا.

لإعادة التأكيد ، سأتجاهل هذه المقترحات في بقية هذا التعليق:

  • محاولة التصرف مثل POSIX تمامًا ، لن ينجح ذلك
  • غيّر السلوك العالمي على أنه إلغاء الاشتراك (أو عدم الانسحاب!) ، مما يزعج المستخدمين

هذا يترك لنا علامة لكل مكالمة مع اسم خاص بنظام Windows بشكل واضح. هذا هو بالضبط ما يقترحه guybrand .

مع كل الاحترام الواجب ، لا أفهم اعتراض mattn . ما يقترحه guybrand معقول. نعم ، يتصرف Windows بشكل مختلف فيما يتعلق بمشاركة الملفات. إنها مثل حقوق حذف الملفات ، فهي مختلفة جدًا على Windows . انها بالفعل تتباعد بطرق عديدة . إن وجود اعتراض على علامة خاصة بـ Windows بشأن الموقف القائل بأن "المطورين قد يسيئون فهم سلوكها" ليس حقيقة ، إنه رأي. أنت تفترض أن المطورين لا يعرفون ماذا يفعلون أو لن يقرأوا الوثائق الموجودة على MSDN. هذا اعتراض عادل للحالة العامة 😎 ، لكنه ليس اعتراضًا قويًا على أساس حظر حالة استخدام مشروعة كعلم اختياري.

ومن المفارقات أن هذا يعني أنه حتى يتم حل هذه المشكلة ، لإصلاح # 25965 ، سيتعين علي تغيير "go run" للاتصال بـ CreateFileW مباشرة 🙃 لأننا نحتاج أيضًا إلى FILE_FLAG_DELETE_ON_CLOSE .

شكرا!

أريد فقط أن أعرف كيف يمكن أن توجد الحالة لمعرفة ما إذا كان يجب علينا تنفيذ وظيفة جديدة (golang.org/x/sys؟) لفتح / إنشاء ملف بسمات جديدة ، أو تغيير السلوك الأصلي. حاليًا ، على حد علمي من التعليقات أعلاه:

  1. إنشاء ملف قابل للحذف (قابل لإعادة التسمية) للتسجيل.
  2. إنشاء ملف للملف المؤقت الذي سيتم حذفه عند الإغلاق.

بالنسبة إلى 1 ، يمكن توفيره من وظيفة جديدة لإنشاء / فتح ملف بالسمات. ويمكننا ضبط الملف باستخدام logger.SetOutput (ملف).

لمدة 2 ، يمكن أيضًا إنشاء / فتح باستخدام وظيفة جديدة.

راجع للشغل ، أعتقد أن # 25965 لا علاقة له بهذه المشكلة. ربما ، هذا هو قيود على نظام التشغيل Windows.

(على أي حال ، لا يمكننا حذف الدليل حيث يوجد الملف المفتوح بهذه السمة)

mattn هل يمكنك شرح المقايضة بين:

  • إضافة وظيفة جديدة تمامًا في golang.org/x/sys
  • دعم علامة جديدة (محددة بالفعل!) لـ OpenFile (). [1]

لا أفهم لماذا يجب أن نفضل الأول بدلاً من الثاني.

[1] لقد أدركت للتو أنني افترضت هنا تغيير سلوك os.OpenFile () لكن المشكلة تستدعي Open ().

بادئ ذي بدء ، تم تأمين حزمة syscall بالفعل. لذا فأنا أبحث عن طريقة لإصلاح ذلك بدون تغيير حزمة syscall.

راجع للشغل ، أعتقد أن # 25965 لا علاقة له بهذه المشكلة. ربما ، هذا هو قيود على نظام التشغيل Windows.

(على أي حال ، لا يمكننا حذف الدليل حيث يوجد الملف المفتوح بهذه السمة)

mattn هذا ليس صحيحا تماما. سيتيح لك FILE_SHARE_DELETE flag نقل هذه الملفات إلى مجلد آخر حتى تتمكن من إزالة المجلد الأصلي. فيما يلي مثال بسيط على PowerShell على ذلك:

# Create folder and open new file with FILE_SHARE_DELETE flag
New-Item -Type Directory -Path C:\folder1
$file = [System.IO.File]::Open("C:\folder1\test.txt", "Create", "ReadWrite", "Delete")

# Create temp folder and move all open files to there
New-Item -Type Directory -Path C:\folder1-removing
Get-ChildItem -Path C:\folder1 -Recurse | Move-Item -Destination C:\folder1-removing\

# Remove original folder
Remove-Item -Path C:\folder1

# Trigger removal for files on temp folder (NOTE! Those will exist on disk until they are closed).
Get-ChildItem -Path C:\folder1-removing -File -Recurse | Remove-Item -Force

# Close file and remove temp folder
$file.Close()
Remove-Item -Path C:\folder1-removing

بادئ ذي بدء ، تم تأمين حزمة syscall بالفعل. لذا فأنا أبحث عن طريقة لإصلاح ذلك بدون تغيير حزمة syscall.

mattn إذا كانت المشكلة تتعلق فقط بتجميد واجهة برمجة التطبيقات ، فكما ذكرت / عرضًا سابقًا ، يمكن تعديل syscall.Open فقط لفهم syscall.FILE_SHARE_DELETE ، وحل المشكلة دون تغيير واجهة برمجة التطبيقات.

إذا كان تجميد التنفيذ ، فيمكن إجراء التغيير على وظيفة golang.org/x/sys/windows Open ومن ثم بيعها في حزمة internal/syscall . الكود file_windows.go يستخدم بالفعل وظائف من internal/syscall . سيكون التناقض الوحيد إذن هو أن syscall.Open لن يفهم هذه العلامة ، لكن معظم الأشخاص الذين يتطلعون إلى الوصول إلى وظائف Windows API ذات المستوى المنخفض يستخدمون golang.org/x/sys/windows أي حال ، وربما يستخدمون CreateFile بدلاً من Open .

ينص الاقتراح الذي بدأ "تأمين" حزمة syscall على ما يلي:
_ لن يعتمد المستودع الأساسي على حزم go.sys_

لذا فإن تغيير x / sys لن يساعد المتصلين بـ os.OpenFile (). لكن الداخلي / syscall يمكن أن يضيف Open () ، وسيطلق عليه os.OpenFile ().

maruel ، مشروع Docker ، ويفترض أن العديد من الآخرين ، افترضوا سلوك Unix لـ os.Rename () &. إزالة () من الملفات المفتوحة لأن الحزمة "os" لا تذكر السلوك الخاص بـ Windows بالنسبة لهم ، ومع ذلك فقد ذكر __ خمسة عشر إشارة__ من سلوك Windows الآخر.

لن يعتمد المستودع الأساسي على حزم go.sys
لكن الداخلي / syscall يمكن أن يضيف Open () ، وسيطلق عليه os.OpenFile ().

networkimprov حسنًا ، كان لدي انطباع خاطئ بأن internal/syscall كان مجموعة فرعية موردة من golang.org/x/sys ، لكن في كلتا الحالتين أعتقد أن هذه هي الإستراتيجية الصحيحة (إضافة internal/syscall/windows.Open ). بالطبع ، سيكون هذا على افتراض أن سلوك syscall.Open غير قابل للتغيير بسبب التجميد. من الناحية المثالية ، يمكن تعديله مباشرةً ، مع احتمال حدوث تغييرات مقابلة في golang.org/x/sys/windows.Open .

على الرغم من تجميد حزمة syscall ، يمكننا تغييرها لإصلاح الأخطاء أو معالجة أوجه القصور الخطيرة. على وجه الخصوص يمكننا تغييره لدعم حزمة نظام التشغيل بشكل أفضل.

ولكن إذا كان الأشخاص يتصلون بـ syscall.Open مباشرةً ، فيجب عليهم استخدام حزمة x / sys / windows ، وليس حزمة syscall.

ولكن إذا كان الأشخاص يتصلون بـ syscall.Open مباشرةً ، فيجب عليهم استخدام حزمة x / sys / windows ، وليس حزمة syscall.

لا أعتقد أن أي شخص يتطلع إلى الاتصال بـ syscall.Open مباشرة - إنه هدف المناقشة فقط لأنه يكمن وراء os.OpenFile (لذا فإن إضافة دعم FILE_SHARE_DELETE في syscall.Open يضيف دعمًا لاستخدام العلم مع os.OpenFile ).

شكرا. لا بأس في تغيير حزمة syscall لدعم التغييرات في حزمة نظام التشغيل.

شكرا ianlancetaylor و @ havoc-io. اقتراح أكثر رسمية مما أشرت إليه أعلاه:

  • قم بتعديل syscall.Open () بقصد واضح وهو السماح لـ os.OpenFile () بقبول FILE_SHARE_DELETE (وفي النهاية FILE_FLAG_DELETE_ON_CLOSE كمتابعة محتملة)
  • قم بتحديث وثائق os.OpenFile () لوصف علامة Windows الجديدة فقط.
  • قم بتحديث وثائق os.OpenFile () و os.Rename () و os.Remove () لتوضيح الاختلاف في السلوك بين POSIX و Windows.

النقطة الثالثة هي معالجة مخاوف Networkimprov . أتفهم التحدي هناك ، وعلى الرغم من أنه لا ينبغي أن تكون مسؤولية اللغة لوصف كيفية عمل نظام التشغيل ، فقد بدأت أتفق مع mattn على أن هذه الحالات دقيقة بما يكفي لضمان المزيد من التوثيق. أعتقد أنه يمكن تحسين مستند إعادة التسمية والإزالة على الفور ، فلا داعي لانتظار أي تغيير في السلوك.

سأكون على استعداد للمساهمة في هذا إذا كانت هناك موافقة.

هذا يترك لنا علامة لكل مكالمة مع اسم خاص بنظام Windows بشكل واضح.

هل تقترح علمًا جديدًا لنظام التشغيل المفتوح؟ ثم يجب أن تكون العلامة مدعومة من قبل جميع أنظمة التشغيل - وهذه نقطة كاملة من حزمة نظام التشغيل - تكون مستقلة عن نظام التشغيل. إذن ما هي دلالات هذا العلم؟ وستحتاج إلى بعض الاختبارات الجديدة التي تتحقق من عمل العلامة كما هو موثق.

لا أفهم لماذا لا يمكنك كتابة أي كود تحتاجه باستخدام حزمة syscall. لا أعتقد أن التعليمات البرمجية الخاصة بك سوف تتعايش بشكل جيد مع برامج Windows الأخرى. وربما يكون الأمر على ما يرام في ظروف خاصة. لكني لا أريد أن يستخدم الأشخاص هذه الوظيفة بشكل خفيف - لذلك لا ينبغي أن تكون جزءًا من المكتبة القياسية.

اليكس

تضمين التغريدة
من فضلك انظر هذا

تضمين التغريدة
من فضلك انظر هذا

لقد نظرت. ما زلت لا أرى كيف ستعمل جميع التغييرات المقترحة على أنظمة تشغيل أخرى؟ ما الاختبارات التي سيتعين عليك إجراؤها لتنفيذ التغيير المقترح؟

اليكس

نقلا عن هذا

بينما يمكن أن تكون قيمة DELETE_WHEN_FREED صفرًا بالنسبة إلى البيئة. بخلاف النوافذ

لذلك - لا شيء للاختبار على أنظمة تشغيل أخرى ، الدعوة إلى:
fd ، err: = os.OpenFile (المسار ، os.O_RDWR | os.O_CREATE | os.DELETE_WHEN_FREED ، 0600)
في windows سيتم ترجمة const إلى 4
fd ، err: = os.OpenFile (المسار ، os.O_RDWR | os.O_CREATE | 4 ، 0600)
في حين أن الآخرين ( 0 )
fd ، err: = os.OpenFile (المسار ، os.O_RDWR | os.O_CREATE | 0 ، 0600)

لا شيء لاختباره على أنظمة تشغيل أخرى

لا أرى كيف يمكننا إضافة حزمة أو متغير جديد لحزمة نظام التشغيل لا يمكن استخدامه إلا على Windows.

c:\>go doc os
package os // import "os"

Package os provides a platform-independent interface to operating system
functionality. 
...
The os interface is intended to be uniform across all operating systems.
Features not generally available appear in the system-specific package
syscall.

اليكس

أليكس ورد إجابة اعتراضك هنا https://github.com/golang/go/issues/32088#issuecomment -494157514

الاختبار تافه

_, err := os.OpenFile(path, os.O_CREATE | syscall.FILE_SHARE_DELETE, 0);
err = os.Rename(path, path+"2")

نحن في المرحلة التي يمكن فيها لأي شخص إرسال تصحيح ؛ أظن أن ianlancetaylor سيقبل ذلك.

لقد تحققت من إعداد FILE_SHARE_DELETE كجزء من # 32188 ، لكن وجدت أن إعداده لم يقلل بشكل تجريبي من معدل الأخطاء من os.Rename و io.ReadFile للمكالمات ؛ لا تزال هناك حاجة إلى حلقة إعادة المحاولة على أي حال.

سأكون مهتمًا جدًا برؤية اختبار يوضح اختلافًا ملحوظًا يمكن ملاحظته من وضع هذه العلامة ، لأنني لا أفهم حقًا آثارها بنفسي.

لقد جربت FILE_SHARE_DELETE منذ بضع سنوات ، وقد نجحت بالفعل
بشكل مختلف.
ربما يمكنني إعادة تشغيل النوافذ البيئية الخاصة بي. وابحث عنه ، إذا كان سيساعدك ،
ولكن سيكون ~ Go 1.3 أو نحو ذلك.

يوم الاثنين ، 10 حزيران (يونيو) 2019 الساعة 17:44 ، بريان سي ميلز [email protected]
كتب:

لقد تحققت من إعداد FILE_SHARE_DELETE كجزء من # 32188
https://github.com/golang/go/issues/32188 ، لكن وجدت هذا الإعداد
لم يقلل بشكل تجريبي من معدل الأخطاء من OS.Rename و
مكالمات io.ReadFile ؛ لا تزال هناك حاجة إلى حلقة إعادة المحاولة على أي حال.

سأكون مهتمًا جدًا برؤية اختبار يوضح أهمية
اختلاف ملحوظ من وضع هذا العلم ، لأنني لا أفعل ذلك حقًا
أفهم آثارها بنفسي.

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/golang/go/issues/32088؟email_source=notifications&email_token=ABNEY4VVIVJ2IEWQPWCWBZTPZZSETA5CNFSM4HNPNYIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LN
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/ABNEY4STTW7U526HPO6TUHDPZZSETANCNFSM4HNPNYIA
.

bcmills ، قراءة # 32188 أعلم أنك كنت ترى أخطاء من os.Rename () في ملف _ لم يتم فتحه_ أثناء إعادة التسمية؟ أتخيل أنه يمكن للمرء أن يتفوق على مجلة NTFS ، والتي أعتقد أنها مكتوبة لجميع عمليات تغيير الدليل ، وبالتالي التسبب في حدوث خطأ ؛ لكن ليس لدي أي فكرة عن الخطأ الذي سيكون.

الطلب هنا لتمكين FILE_SHARE_DELETE في syscall.Open () هو السماح لـ os.Rename () بالعمل على الملفات المفتوحة. لقد اختبرت هذا العلم مع 1.12 على Win7 ، وهو يعمل ؛ ويفشل بدونها.

لم أختبر على وجه التحديد os.Rename () على النوافذ "تحت التحميل" ، لكنني لم أر أي أخطاء غير متوقعة من os.Rename () على الملفات المفتوحة منذ تمكين fsd سأبلغ عنها إذا فعلت ذلك.

أعلم أنك كنت ترى أخطاء من os.Rename () في ملف لم يكن مفتوحًا أثناء إعادة التسمية؟

نعم.

ليس لدي أي فكرة عن الخطأ الذي سيكون.

من الناحية التجريبية ، الأخطاء التي أراها (من MoveFileEx ، ReplaceFile ، و / أو CreateFile ) هي ERROR_ACCESS_DENIED ، ERROR_SHARING_VIOLATION ، و ERROR_FILE_NOT_FOUND .

الطلب هنا لتمكين FILE_SHARE_DELETE في syscall.Open () هو السماح لـ os.Rename () بالعمل على الملفات المفتوحة. لقد اختبرت هذا العلم مع 1.12 على Win7 ، وهو يعمل ؛ ويفشل بدونها.

حق؛ المشاكل ذات الصلة التي أحاول حلها هي السماح للمكالمات المتزامنة بـ os.Rename بالنجاح ، والسماح للمكالمات إلى io.ReadFile المتزامنة مع os.Rename للنجاح. قد يكون الحصول على os.Rename للعمل مع المقابض المفتوحة خطوة في الاتجاه الصحيح ، لكنني لا أعتقد أنها كافية لنوع حالات الاستخدام التي نستخدم فيها POSIX rename .

سأكون مهتمًا جدًا برؤية اختبار يوضح اختلافًا ملحوظًا يمكن ملاحظته من وضع هذه العلامة ، لأنني لا أفهم حقًا آثارها بنفسي.

bcmills مثال PowerShell لأنني أكتب أسرع بكثير من Go

New-Item -Type Directory -Path C:\folder1
for($i=0; $i -le 1000; $i++)
{
    $temp = [System.IO.File]::Open("C:\folder1\test.txt", "Create", "ReadWrite", "Delete")
    Set-Variable -Name "file$i" -Value $temp -Force
    $TempName = "C:\folder1\test.txt." + (New-Guid).Guid
    Rename-Item -Path C:\folder1\test.txt -NewName $TempName
    Remove-Item -Path $TempName -Force
}

بعد الانتهاء من ذلك ، سيكون هناك ألف test.txt.??? الملفات تحت C:\folder1 ولكن عند إغلاق PowerShell ستتم إزالة هذه الملفات.

إذن ما هو FILE_SHARE_DELETE flag يسمح لك بالفعل بإعادة تسمية / نقل / إزالة الملفات المفتوحة ولكنك لا تزال بحاجة إلى التأكد من أن أسماء الملفات الوجهة فريدة لأنها ستكون موجودة على القرص طالما أن المقابض مفتوحة.

"استخدام إعادة تسمية POSIX" أمر مستحيل في النوافذ ، وربما يكون هذا هو سبب الأخطاء التي تحصل عليها.

بوسيكس:

إنشاء ملف "filename"
القراءة / الكتابة من "اسم الملف"
حذف "اسم الملف"

إنشاء ملف "filename"
...
حذف "اسم الملف"

سيعمل ، حيث سيكون لكل ملف إنشاء فرق fd.

شبابيك:
إنشاء ملف "filename"
القراءة / الكتابة من "اسم الملف"
حذف "اسم الملف"

إنشاء ملف "اسم الملف" - بوم ، انتهاك تقاسم

يجب أن تكون عملية إعادة البناء سهلة للغاية ...

ما الذي يمكن أن يفعله FILE_SHARE_DELETE إذن؟
السماح بحذف deffered أثناء فتح الملف.

هذا هو.

يوم الإثنين ، 10 يونيو 2019 الساعة 19:32 ، أولي جاناتوينن [email protected]
كتب:

سأكون مهتمًا جدًا برؤية اختبار يوضح أهمية
اختلاف ملحوظ من وضع هذا العلم ، لأنني لا أفعل ذلك حقًا
أفهم آثارها بنفسي.

bcmills https://github.com/bcmills مثال PowerShell وأنا أكتب ذلك
أسرع بكثير من Go

New-Item -Type Directory -Path C: folder1for ($ i = 0؛ $ i -le 1000؛ $ i ++)
{
$ temp = [System.IO.File] :: فتح ("C: folder1test.txt"، "Create"، "ReadWrite"، "Delete")
Set-Variable -Name "file $ i" -Value $ temp -Force
$ TempName = "C: folder1test.txt." + (نيو غيد)
إعادة تسمية العنصر - المسار C: folder1test.txt -NewName $ TempName
إزالة العنصر المسار $ TempName -Force
}

بعد أن تنتهي سيكون هناك ألف test.txt. ؟؟؟ الملفات تحت
C: folder1 ولكن عند إغلاق PowerShell ستتم إزالة هذه الملفات.

إذن ما تتيحه لك علامة FILE_SHARE_DELETE بالفعل
إعادة تسمية / نقل / إزالة الملفات المفتوحة ولكن ما زلت بحاجة إلى التأكد من تلك الوجهة
أسماء الملفات فريدة لأنها ستكون موجودة على القرص طالما المقابض
مفتوح.

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/golang/go/issues/32088؟email_source=notifications&email_token=ABNEY4WSTWIUVNVHLYMBFY3PZZ62DA5CNFSM4HNPNYIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNM99
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/ABNEY4VS5XF3EXB6QPBWVQ3PZZ62DANCNFSM4HNPNYIA
.

السماح باستدعاءات io.ReadFile المتزامنة مع os.Rename لتحقيق النجاح

bcmills أعتقد أنه يجب على المرء دائمًا العمل مع مجموعة إشارات fsd ، بافتراض أنه لا يعمل بشكل متزامن مع خيوط أخرى تحاول نفس التسلسل على ملفات غير ذات صلة. وعادة ما يفشل بدون العلم.

وجد هذا الجانب من البرنامج النصي للاختبار خطأً صحيحًا في Windows syscall.Open (). لكن لا يوجد شخص آخر يعلق في هذا الموضوع يريد إصلاحه :- (لذا نعم ، قم بتصحيح البرنامج النصي.

TLDR:
تغيير طفيف آمن إلى syscal_windows.go ويعمل كما هو متوقع.

شرح:
إذن ، هذا ما فعلته ، ويعمل كما هو متوقع ، ولا يوجد أي مخاطرة (IMO)

  1. قرص syscal_windows.go
func Open(path string, mode int, perm uint32) (fd Handle, err error) {

sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | (mode & FILE_SHARE_DELETE))

الإضافة هي: "| (الوضع & FILE_SHARE_DELETE)"
إذا لم يرسل المطور الوضع & 4 مجموعة (لماذا يجب عليه - لم يكن هذا يعمل من قبل ...) - لم يتغير شيء ، لذلك رمز مثل

os.OpenFile(filename,os.O_RDWR|os.O_CREATE, 0600)

سيتصرف تمامًا كما كان يفعل قبل التغيير ، فقط المطورين الذين سيفعلون ذلك

os.OpenFile(filename,os.O_RDWR|os.O_CREATE  | 4 , 0600)

سوف "تشعر" بالتغيير

  1. شغل الكود
package main

import (
    "fmt"
    "os"
)

func main() {
    filename := "./myfile"
    if f ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("Open file %s error : %s" , filename, err.Error())
    } else if _,err:= f.WriteString("bla bla") ;err!=nil{
        fmt.Printf("writing to %s returned error : %s" , filename, err.Error())
    } else if err := os.Remove(filename);err!=nil{
        fmt.Printf("removing %s returned error : %s" , filename, err.Error())
    }
}

وعملت

  1. شغّل التعليمات البرمجية بدون | 4 وفشلت
  2. شغل الكود بإضافة صغيرة:
package main

import (
    "fmt"
    "os"
)

func main() {
    filename := "./myfile"
    if f ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("Open file %s error : %s" , filename, err.Error())
    } else if _,err:= f.WriteString("bla bla") ;err!=nil{
        fmt.Printf("writing to %s returned error : %s" , filename, err.Error())
    } else if err := os.Remove(filename);err!=nil{
        fmt.Printf("removing %s returned error : %s" , filename, err.Error())
    } else if secondF ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("reOpen file %s error : %s" , filename, err.Error())
    } else {
        secondF.Close()
    }
}

وبالطبع فشلت في الثانية F.
ولكن هذا هو السلوك المتوقع في Windows - لا حاجة إلى "اختبار التحميل" - لا يوجد خيار التزامن مؤجل. إزالة ، لذلك أعتقد أنه يمكننا إضافة نصف سطر هذا بأمان إلى syscal_windows ، دون المساس بأي كود موجود ، والسماح للمطورين فقط تريد حقًا استخدام هذا الوضع لتتمكن من تأجيل الحذف.

كل ما يتعين علينا القيام به (بخط عريض):
syscal_windows.go:
وضع المشاركة: = uint32 (FILE_SHARE_READ | FILE_SHARE_WRITE | (الوضع & FILE_SHARE_DELETE) )

لقد تحققت من إعداد FILE_SHARE_DELETE كجزء من # 32188 ، لكن وجدت أن إعداده لم يقلل بشكل تجريبي من معدل الأخطاء من os.Rename و io.ReadFile للمكالمات ؛ لا تزال هناك حاجة إلى حلقة إعادة المحاولة على أي حال.

سأكون مهتمًا جدًا برؤية اختبار يوضح اختلافًا ملحوظًا يمكن ملاحظته من وضع هذه العلامة ، لأنني لا أفهم حقًا آثارها بنفسي.

bcmills الآن يمكنك العثور على اختبارات الوحدة / الانحدار لهذا من https://github.com/olljanat/go/commit/3828f1a5d0ebb69b4c459d5243799ded36ac1ee8 حاليًا فشل في الخطأ The process cannot access the file because it is being used by another process. على Windows ويبدأ العمل بعد FILE_SHARE_DELETE يتم تضمين

ملحوظة! أنه على نظام التشغيل Windows ، ما زلت بحاجة إلى هذه الخطوة التي تنقل ملف السجل example.log.1 إلى اسم عشوائي / فريد لأن سببًا آخر لإعادة تسمية example.log إلى example.log.1 قد يفشل إلى Access is denied. خطأ حتى عند تمكين العلم FILE_SHARE_DELETE . هذا شيء خاص بالنظام الأساسي يحتاج المطور إلى الاهتمام به.

/ سم مكعبjhowardmsft @ jterry75jstarksddebroy لمعلوماتك. قد تكون مهتمًا بهذا أيضًا.

kevpar - لمعلوماتك لأنك تعمل على

إذا كان أي من الأشخاص الذين ينضمون إلى سلسلة الرسائل يمكنهم التعبير عن أسباب (على سبيل المثال ، تم كسر الشفرة الحالية) لجعل هذا الخيار الافتراضي ، مقابل علامة متوفرة عبر علامة Windows فقط في نظام التشغيل os.OpenFile () ، قم بعمل توجيه!

networkimprov IMO يجب التعامل معه بعلامة Windows فقط لأن المطور مطلوب للتعامل أيضًا مع بعض الأشياء الأخرى الخاصة بـ Windows على أي حال مثل مثال تدوير السجل الخاص بي.

ومع ذلك ، وكما أرى ، تمت دعوة اثنين من موظفي Microsoft للمناقشة ، لذا من المثير للاهتمام معرفة ما إذا كانا يختلفان في هذا الأمر.

هل بدأ أي شخص بالمناسبة في تطوير حل جديد لهذا الحل؟ أي متطوعين؟

olljanat
إذا كان الإصلاح كعلم ، فإن الإصلاح عبارة عن خط واحد ، يرجى قراءة:
https://github.com/golang/go/issues/32088#issuecomment -500562223

سأحاول تمثيل منظور فريق Windows هنا ... نفضل الانتقال دائمًا إلى تعيين FILE_SHARE_DELETE ، بدون أي خيار. بشكل عام ، لتسهيل النقل من / إلى Windows ، نفضل السلوك المتسق مع Linux ، ولا أرى سبب تفضيل مستخدمي Windows أو البرامج الافتراضية!

ملاحظة مثيرة للاهتمام ، على عكس تعليق mattn : في أحدث إصدار من Windows ، قمنا بتحديث DeleteFile (على NTFS) لإجراء حذف "POSIX" ، حيث تتم إزالة الملف من مساحة الاسم على الفور بدلاً من انتظار فتح الكل يعالج الملف المراد إغلاقه. لا يزال يحترم FILE_SHARE_DELETE ، ولكنه يتصرف الآن بطريقة أخرى مثل إلغاء ربط POSIX. تمت إضافة هذه الوظيفة لـ WSL واعتبرت أنها تستحق الاستخدام افتراضيًا لبرنامج Windows أيضًا.

بمعنى آخر ، إذا قمت بتشغيل برنامج اختبار mattn وتسلسل del ، dir ، إلخ على أحدث إصدار من Windows ، فسترى الملف يختفي من مساحة الاسم فورًا بعد حذف الملف ، وليس بعد انتهاء برنامج الاختبار. تمامًا مثل Linux.

لذا ، حتى في نظام Windows نفسه ، مع وجود مخاطر أكبر بشكل ملحوظ على توافق التطبيقات ، فإننا نجري تغييرات صغيرة لتسهيل نقل البرامج غير التي تعمل بنظام Windows إلى Windows. أنا حقا أشجع Go على فعل الشيء نفسه.

jstarks ، شكرًا لك على

أود أن أقترح خيارًا عالميًا لتعطيل fsd في حالة اعتماد أي عمليات نشر لـ Windows على السلوك الحالي غير الموثق.

ianlancetaylor هل توافق؟

نظرًا لأن السلوك الافتراضي لـ CreateFile هو أنه لا يمكن حذف الملف الافتتاحي ، أعتقد أنه يجب علينا الاحتفاظ بالسلوك الافتراضي. قد يرغب شخص ما في السلوك الأصلي. على سبيل المثال ، قد يكون هناك مبرمجون يتحققون من أن تطبيقاتهم تعمل باستخدام طريقة غير ممكنة لحذف الملف.

سلوك Python هو نفس سلوك Go الحالي. ولم أسمع أبدًا أن Python لديها خطة لتغيير السلوك الذي لا يمكنه حذف الملفات المفتوحة.

لم آخذ الوقت الكافي لتكوين رأي جاد حول هذه المسألة ، لكنني لا أعتقد أن الخيار العالمي هو خيار جيد. يجب علينا إما الاحتفاظ بالسلوك الحالي (وربما إضافة علامة لتحديد السلوك الآخر) أو يجب علينا تغيير السلوك (وربما إضافة علامة لتحديد السلوك الأصلي الحالي).

فيما يتعلق بما إذا كان يجب تغيير السلوك الافتراضي أم لا ، أعتقد أنه يتعين علينا أن نسأل عما إذا كان من المرجح أن يؤدي تغيير السلوك إلى إصلاح برنامج Go المكتوب للتشغيل عبر أنظمة Unix و Windows أو ما إذا كان من المرجح أن يتم تغيير السلوك سوف يكسر برنامج Go المكتوب للتشغيل على أنظمة Windows. لا أعرف الجواب على ذلك.

كما يقترح mattn ، يجدر أيضًا السؤال عما تفعله اللغات الأخرى.

إذا أصبح الخيار الافتراضي ، وتعتمد أي عمليات نشر لـ Windows عليه ، أتخيل أنهم يريدون كلاً من علامة os.OpenFile () وخيار عام للعودة للأغراض الانتقالية.

هناك خيار عام لتعطيل IPv6 ، آخر مرة قمت بتحديده.

تتمثل إحدى طرق اكتشاف التأثير في تغييره على معلومات سرية (والإعلان في المدونة؟) ومعرفة ما يتم الإبلاغ عنه.

تم ذكر كل من Python و Erlang في نص العدد:
جعله Erlang افتراضيًا منذ أكثر من ست سنوات: erlang /
أرادت Python ذلك ولكنها لم تستطع ، بسبب قيود وقت تشغيل MSVC: https://bugs.python.org/issue15244

سأحاول تمثيل منظور فريق Windows هنا ... نفضل الانتقال دائمًا إلى تعيين FILE_SHARE_DELETE ، بدون أي خيار. بشكل عام ، لتسهيل النقل من / إلى Windows ، نفضل السلوك المتسق مع Linux ، ولا أرى سبب تفضيل مستخدمي Windows أو البرامج الافتراضية!

في أحدث إصدار من Windows ، قمنا بتحديث DeleteFile (على NTFS) لإجراء حذف "POSIX" ، حيث تتم إزالة الملف من مساحة الاسم على الفور بدلاً من انتظار إغلاق جميع المقابض المفتوحة للملف. لا يزال يحترم FILE_SHARE_DELETE ، ولكنه يتصرف الآن بطريقة أخرى مثل إلغاء ربط POSIX. تمت إضافة هذه الوظيفة لـ WSL واعتبرت أنها تستحق الاستخدام افتراضيًا لبرنامج Windows أيضًا.

jstarks هذه تفاصيل مثيرة للاهتمام للغاية. هل هذا شيء يمكننا توقعه من Microsoft backporting إلى إصدارات نظام التشغيل الأقدم أيضًا؟ أعتقد بشكل خاص أن Windows Server 2019 هو الإصدار الأحدث الذي تم إصداره للتو LTSC والذي سيتم دعمه لفترة طويلة.

كما لو أن Microsoft تفعل ذلك ، فأنا أفضل تمكين FILE_SHARE_DELETE افتراضيًا على Go أيضًا.

Java و C # وجميع اللغات الرئيسية الأخرى التي أدرك أنها تتخذ سلوك نظام التشغيل الافتراضي. في رأيي ، يجب ترك السلوك الافتراضي لمنفذ نظام التشغيل. إذا كان Windows يريد حقًا التعامل مع POSIX فيما يتعلق بفتح الملفات ، فيجب عليهم المخاطرة والقيام بذلك كما فعلوا مع DeleteFile.

أعتقد أن مكتبة Go يجب أن تجعل من الممكن إنشاء / فتح ملفات حذف المشاركة. يمكنني إعطاء مثال عملي واحد في التعامل مع وضع الملف. عند نقل Hadoop إلى Windows ، يتعين علينا بذل جهود إضافية لإنشاء طريقة خاصة في JNI للحصول على معالجة ملف الحذف المشترك أو التدفق.

https://github.com/apache/hadoop/search؟q=getShareDeleteFileInputStream&unscoped_q=getShareDeleteFileInputStream

تضمين التغريدة

عندما تقول

في أحدث إصدار من Windows ، قمنا بتحديث DeleteFile (على NTFS) لإجراء حذف "POSIX" ، حيث تتم إزالة الملف من مساحة الاسم على الفور

هل تقصد أن الملف المفتوح يبقى فقط على هيئة fd ، والكود أدناه:

package main

import (
    "fmt"
    "os"
)

func main() {
    filename := "./myfile"
    if f ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("Open file %s error : %s" , filename, err.Error())
    } else if _,err:= f.WriteString("bla bla") ;err!=nil{
        fmt.Printf("writing to %s returned error : %s" , filename, err.Error())
    } else if err := os.Remove(filename);err!=nil{
        fmt.Printf("removing %s returned error : %s" , filename, err.Error())
    } else if secondF ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("reOpen file %s error : %s" , filename, err.Error())
    } else {
        secondF.Close()
    }
}

لن تفشل في

} else if secondF ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{

بعد تطبيق الإصلاح المقترح ؟

إذا كان الأمر كذلك ، فهذا رائع حقًا!

فيما يتعلق بما إذا كان يجب تغيير السلوك الافتراضي أم لا ، أعتقد أنه يتعين علينا أن نسأل عما إذا كان من المرجح أن يؤدي تغيير السلوك إلى إصلاح برنامج Go المكتوب للتشغيل عبر أنظمة Unix و Windows أو ما إذا كان من المرجح أن يتم تغيير السلوك سوف يكسر برنامج Go المكتوب للتشغيل على أنظمة Windows. لا أعرف الجواب على ذلك.

لا يوجد برنامج Unix problem to be fixed يعمل بنظام التشغيل Windows. يتعامل Windows مع حذف الملفات المفتوحة بشكل مختلف عن نظام Unix. إنه مشابه لحساسية حالة اسم الملف: Unix حساس لحالة الأحرف ، و Windows غير حساس لحالة الأحرف. لا شيء يمكننا القيام به حيال كلا الاختلافين.

وبينما يؤكد جون أن Microsoft تحاول تغيير الأشياء ، سأنتظر حتى يأتي التغيير. ولا يزال الكثير من مستخدمي Windows يستخدمون Windows 7 وجميع إصدارات Windows الأخرى. جون هل ستقوم بتحديث Windows 7 أيضًا؟

أعتقد أننا يجب أن ندع مايكروسوفت تتعامل مع التغيير. إذا أصلحنا مستخدمي Go ، فسيظل هناك مطورو غير تابعين لـ Go. لذلك سيتعين على Microsoft التعامل مع هذا بغض النظر.

أيضًا ، لدى FILE_SHARE_DELETE أدواته الخاصة. على سبيل المثال ، قراءة https://bugs.python.org/issue15244

في الواقع ، إنها ليست نفس الدلالات مثل يونكس.

بعد حذف الملف لا يمكنك إنشاء ملف بنفس الاسم أو حذف الدليل الذي يحتوي عليه حتى يتم إغلاق المؤشر.

ومع ذلك ، يمكن للمرء حل ذلك عن طريق نقل الملف إلى مكان آخر (مثل الدليل الجذر) قبل حذفه.

هناك ، على الأرجح ، العديد من الأشخاص الآخرين الذين لا نعرف شيئًا عنهم. لم نستخدم FILE_SHARE_DELETE إطلاقًا. هل تقترح ، نقوم بتغيير Go libs لاستخدام FILE_SHARE_DELETE افتراضيًا ، ثم تنتظر حتى يشكو المستخدمون من برامجهم المعطلة؟

كما يقترح mattn ، يجدر أيضًا السؤال عما تفعله اللغات الأخرى.

لقد تحققت من Mingw C فقط - إنه يتصرف تمامًا مثل Go. بمجرد فتح الملف باستخدام fopen ، لا يمكن حذفه حتى يتم استدعاء fclose. سأندهش إذا كانت أي من أدوات تطوير Microsoft (C و C ++ و C # و VB وغيرها) مختلفة.

ولا أرى كيف يمكننا تغيير السلوك الافتراضي من هذا القبيل. قد يتم فتح ملف في بعض البرامج على وجه التحديد ، لذلك لا يمكن حذفه بواسطة برنامج آخر. هذا هو النهج الصحيح على Windows من وجهة نظري. علينا أن ندعمها في المستقبل.

اليكس

أضيف منذ 7 سنوات ، أعتقد:
https://sourceforge.net/p/mingw-w64/code/HEAD/tree/stable/v3.x/mingw-w64-headers/include/ntdef.h#l858

حتى الآن ، لم ينشر أحد أي حالات لتطبيقات Go التي تعتمد على سلوك Windows الحالي غير الموثق. لكننا سمعنا ما لا يقل عن 4 حالات من تطبيقات Go التي فشلت على Windows بسبب ذلك.

كما هو مذكور أعلاه ، هناك إصلاح بسيط لإعادة استخدام اسم الملف بعد os.Remove () ، والذي يجب علينا توثيقه:
os.Rename(path, unique_path); os.Remove(unique_path)

حتى الآن ، لم ينشر أحد أي حالات لتطبيقات Go التي تعتمد على سلوك Windows الحالي غير الموثق.

هؤلاء الأشخاص لا يعرفون حتى أنه من الممكن الإبلاغ عن أخطاء Go.

يجب ألا تتوقع أن يقوم هؤلاء المستخدمون بمراقبة قائمة مشكلات الانتقال على أمل أن يؤثر عليهم شيء ما. لديهم حياة ليعيشوها. يقع على عاتقنا عدم كسر الأدوات التي يستخدمونها.

اليكس

أليكس ، من الواضح أنك غير مقتنع. ثم أرى مسارين محتملين للأمام حتى يتمكن الأشخاص من كتابة كود محمول في Go:

  1. علامة اشتراك جديدة إلى Open وهذا يعني FILE_SHARE_DELETE لنظام التشغيل Windows ويتم تجاهله في أنظمة تشغيل أخرى. ثم نشجع أي شخص يكتب رمزًا ويتوقع أن تمرر دلالات POSIX هذه العلامة في كل مكان ؛ أو،
  2. حزمة Go جديدة posix (في بعض الريبو في مكان ما) مع وظيفة واحدة ، Open ، والتي تغلف CreateFile مع FILE_SHARE_DELETE ولكن بخلاف ذلك تتصرف مثل os.Open . على الأنظمة الأساسية بخلاف Windows ، سيتصل فقط بـ os.Open مباشرة. نشجع بعد ذلك أي شخص يكتب رمزًا ويتوقع أن تستخدم دلالات POSIX posix.Open بدلاً من os.Open كل مكان.

تتطلب هاتان الطريقتان من مطوري Linux اتخاذ إجراءات إضافية للحفاظ على سلوك POSIX على Windows ، ولكن هذه على الأقل أفضل من كتابة أغلفة CreateFile لمرة واحدة (كما فعلنا للتو مع containerd).

أليكس ، من الواضح أنك غير مقتنع.

أنا غير مقتنع. لكنك لست بحاجة إلى إقناعي ، فأنت بحاجة إلى إقناع Go Team. سوف يتخذون القرار.

  1. علامة اشتراك جديدة إلى Open وهذا يعني FILE_SHARE_DELETE لنظام التشغيل Windows ويتم تجاهله في أنظمة تشغيل أخرى. ثم نشجع أي شخص يكتب رمزًا ويتوقع أن تمرر دلالات POSIX هذه العلامة في كل مكان ؛ أو،

لا أحب هذا الخيار أيضًا.

بادئ ذي بدء ، من المفترض أن توفر حزمة نظام التشغيل وسيلة متاحة لأي نظام تشغيل. يجب أن ينتقل أي شيء خاص بنظام التشغيل إلى syscall أو golang.org/x/sys/windows أو أي حزمة أخرى نحبها.

ثانيًا ، أشعر بالقلق من أن ينتهي بي الأمر بنوع ملف FILE_SHARE_DELETE في برنامجي ، حتى لو لم أرغب في ذلك. تخيل ، إذا قمت باستيراد حزمة خارجية قررت استخدام وضع ملف FILE_SHARE_DELETE . كيف لي أن أعرف أن بعض الكود الخاص بي يستخدم FILE_SHARE_DELETE ؟ سأضطر إلى grep حزمة التعليمات البرمجية المصدر. أو سيتعين على وثائق الحزمة تحذير مستخدميها. أفترض أن هذا يمكن أن يحدث أيضًا ، إذا استخدم بعض مؤلفي الحزم syscall.CreateFile مع FILE_SHARE_DELETE مباشرة. ولكن ، على ما أعتقد ، إذا كان ينعم FILE_SHARE_DELETE لحزمة نظام التشغيل ، فسيكون هذا أكثر شيوعًا. أظن أن مستخدمي Linux ، الذين لا يعرفون شيئًا عن Windows ، سيستخدمون هذه العلامة افتراضيًا ، لجعل منفذ برنامج Linux الخاص بهم "أسهل" على Windows.

ثالثًا ، علينا توثيق العلم FILE_SHARE_DELETE . لا يمكننا أن نقول فقط POSIX. سيتعين علينا وصف ما يفعله العلم. بكلمات بسيطة. تذكر أيضا:

في الواقع ، إنها ليست نفس الدلالات مثل يونكس.

بعد حذف الملف لا يمكنك إنشاء ملف بنفس الاسم أو حذف الدليل الذي يحتوي عليه حتى يتم إغلاق المؤشر.

ومع ذلك ، يمكن للمرء حل ذلك عن طريق نقل الملف إلى مكان آخر (مثل الدليل الجذر) قبل حذفه.

من https://github.com/golang/go/issues/32088#issuecomment -504321027. سيتعين علينا توثيق ذلك أيضًا. وجميع الوظائف الأخرى التي يوفرها العلم FILE_SHARE_DELETE .

رابعًا ، سنحتاج إلى إضافة اختبارات جديدة مقابل FILE_SHARE_DELETE . ماذا ستكون هذه الاختبارات؟ ماذا يحدث ، إذا نسينا اختبار بعض الوظائف ، فقط لنكتشف لاحقًا أنه لا يمكن تحقيق الوظيفة باستخدام FILE_SHARE_DELETE flag؟ لا يمكننا إزالة العلم FILE_SHARE_DELETE ، إذا لم يعجبنا. بمجرد دخولها ، فإنها تبقى. وعلينا أن ندعمها في المستقبل.

2. حزمة Go جديدة posix (في بعض الريبو في مكان ما) مع وظيفة واحدة ، Open ، والتي تغلف CreateFile مع FILE_SHARE_DELETE ولكن بخلاف ذلك تتصرف مثل os.Open

لا أرى كيف يكون ذلك ممكنا. ولكن ، إذا كان ذلك ممكنًا ، يجب أن تكون قادرًا على إنشاء الحزمة بنفسك. على سبيل المثال ، مثل github.com/jstarks/posix. رقم؟ يمكننا إضافة الحزمة ضمن golang.org/x/sys/windows/posix أو شيء من هذا القبيل ، لكنني لا أرى فرقًا كبيرًا.

اليكس

من المفترض أن توفر حزمة نظام التشغيل منشأة متاحة لأي نظام تشغيل ...
سيتعين علينا توثيق علامة FILE_SHARE_DELETE. لا يمكننا أن نقول فقط POSIX ...
سنحتاج إلى إضافة اختبارات جديدة لـ FILE_SHARE_DELETE. ماذا ستكون هذه الاختبارات؟

كل هذه تم تناولها أعلاه.

إذا قمت باستيراد حزمة خارجية قررت استخدام وضع ملف FILE_SHARE_DELETE. كيف لي أن أعرف

هذه حجة أخرى لجعله الافتراضي ، وتوفير علم عالمي لتعطيله.

لقد أرسلت إلى golang-nuts للبحث عن تطبيقات Windows المتأثرة ؛ سأقوم باختبار اتصاله كل بضعة أيام لإبقائه مرئيًا. إذا لم يظهر ذلك كثيرًا ، فإن جعله الخيار الافتراضي عند الإكرامية لـ 1.14 يجب أن يوضح الأمور.
https://groups.google.com/d/topic/golang-nuts/8BiP_mPoCd4/discussion

هذه حجة أخرى لجعله الافتراضي ، وتوفير علم عالمي لتعطيله.

بالمناسبة. ما الذي يجب أن يفعله هذا العلم على Linux؟ Afaiu نحن في الواقع نفتقد أيضًا وظائف لفتح الملفات في Linux بطريقة لا يمكن حذفها بواسطة العمليات الأخرى؟ بناءً على https://gavv.github.io/articles/file-locks/#open -file-description-locks-fcntl ، يجب أن يكون من الممكن تنفيذه على الإصدارات الحديثة من Linux.

سيتم تعريف العلامة (مثل var OpenWithout_FILE_SHARE_DELETE = false ) في syscall_windows.go ، لأنها تؤثر على سلوك syscall.Open ().

سيكون لعلم شيء خاص بنظام Linux اسم مختلف ، ويتم تعريفه في syscall_linux.go. مرتجلاً لا أعرف كيفية منع حذف ملف مفتوح على Linux بخلاف الأذونات الموجودة في دليله. الارتباط الذي قدمته يصف التأمين "الاستشاري".

jstarks قبل أن نفكر في تقديم علامة FILE_SHARE_DELETE ، نحتاج أيضًا إلى تحديد ما يجب فعله حيال عدم قدرة Go على حذف الملف القابل للتنفيذ قيد التشغيل. لا أعتقد أن العلم FILE_SHARE_DELETE يمكنه مساعدتنا هنا. وسعها؟ إذا لم نتمكن من تنفيذ حذف الملف القابل للتنفيذ الذي لا يزال قيد التشغيل ، فلا يمكننا المطالبة بأي توافق مع POSIX. ويبدو العلم FILE_SHARE_DELETE وكأنه نصف حل.

أكثر من ذلك ، نفشل أحيانًا في حذف الملف القابل للتنفيذ لعملية انتهت حتى. راجع ، على سبيل المثال ، # 25965 و # 19491 و # 32188 للحصول على التفاصيل. نحن في الأساس نسمي WaitForSingleObject على مقبض العملية حتى يشير. لكن هذا لا يضمن إمكانية حذف الملف القابل للتنفيذ. كان علينا إضافة 5 مللي ثانية من الانتظار قبل محاولة حذف الملف. وحتى هذا لا يعمل دائمًا - https://github.com/golang/go/issues/25965#issuecomment -482037476

أيضًا ، لا علاقة لها بهذه المشكلة ، ولكن نظرًا لاهتمامكم ، ربما يمكنك مساعدتنا في إحياء منفذ windows-arm. انظر # 32135 لمزيد من التفاصيل. في الأساس @ jordanrh1 استدار انتقل إلى windows-arm ، لكن ليس لدينا منشئ windows-arm بعد الآن. لذلك لا نعرف حتى ما إذا كان المنفذ لا يزال يعمل أم معطلاً. إذا كان بإمكانك مساعدتنا في تشغيل المنشئ ، فربما يمكننا محاولة ومواصلة دعم منفذ windows-am. وإلا فقد تتم إزالة المنفذ - https://github.com/golang/go/wiki/PortingPolicy لا أعرف ، إذا كان شخص ما مهتمًا بتشغيل برامج Go على Windows 10 Iot ، لكن لدينا هذا الدعم بالفعل. سيكون من المحزن أن نفقده لمجرد أنه ليس لدينا عامل بناء.

شكرا لك.

اليكس

لاحظ هذا الحل المقترح لحذف الملفات التنفيذية المؤقتة: https://github.com/golang/go/issues/25965#issuecomment -495636291

لا توجد نتائج من مشاركات golang-nuts ؛ بدأ موضوع جديد:
https://groups.google.com/d/topic/golang-nuts/aRvSo3iKvJY/discussion

أحد المخاوف غير الافتراضية التي أعتقد أنه يجب التحقيق فيها سيكون التأثير على تأمين الملفات والبرامج التي تعتمد عليها.

سيؤدي فتح كل مقبض ملف باستخدام FILE_SHARE_DELETE إلى إضعاف دلالات LockFileEx بشكل فعال إلى تلك الخاصة بأقفال POSIX الاستشارية ، لأنه يمكن إزالة أي ملف محدد به FILE_SHARE_DELETE ، حتى إذا كان القفل محددًا محتجز في منطقة من هذا الملف. 1

بالطبع لن ينطبق هذا إلا على مكالمات LockFileEx التي تم إجراؤها باستخدام الواصف المرتجع من os.File.Fd ، ولكن هذا هو بالضبط ما يتم فعله في مكتبة Go file locking الأكثر شيوعًا (التي تضم حاليًا 33 مستوردًا معروفًا ، بما في ذلك Docker و gVisor و Kubernetes). يتم ذلك أيضًا في Terraform ، ويتم استخدام LockFileEx في الكثير من كود Go الآخر .

ما زلت أعتقد أن هذا التغيير يبدو وكأنه محاولة غير حكيمة في أفضل الأحوال (ومصنع لمكافحة التطرف العنيف في أسوأ الحالات). أنا حقًا لا أرى كيف تفوق الفوائد الغامضة الكسر الواضح للشفرة الذي سيحدث.

أعتقد أيضًا أن معظم مستخدمي golang-nuts لن يتأملوا تمامًا تداعيات هذا التغيير. بإذن من فريق Go ، قد يكون المنشور على golang-dev أكثر فاعلية في توليد المناقشة (خاصة وأن هذا يعد تغييرًا أساسيًا). في الواقع ، إنه يؤثر تقنيًا على سلسلة أدوات Go ، والتي تستخدم أيضًا LockFileEx بالطريقة المذكورة أعلاه .


1 نعم ، أعلم أن بعض إجراءات فرض قفل Windows ستظل أقوى مما كانت عليه في POSIX ، ولكن إذا كان بإمكانك إيقاف تشغيل الملف ، فإن استخدام ملف قفل لحجز الموارد يخرج من النافذة.

لقد أرسلت إلى golang-dev عندما فتحت الإصدار.
https://groups.google.com/d/topic/golang-dev/R79TJAzsBfM/discussion

هل أي من المكتبات التي أدرجتها _ تعتمد على سلوك GOOS = windows؟ لقد زعمت مرارًا وتكرارًا أن هذا التغيير سيؤدي إلى كسر الشفرة الحالية ، لكنك لم تقدم أي دليل على الإطلاق.

يرجى التوقف عن الإدلاء ببيانات مثيرة لا يمكن دعمها. إنه لا يوضح شيئًا ، وأنا أجده مسيئًا.

لقد أرسلت إلى golang-dev عندما فتحت الإصدار. https://groups.google.com/d/topic/golang-dev/R79TJAzsBfM/discussion

يبدو أن كل شخص هناك أسقط الفكرة لأسباب خاصة بهم (جميعها مماثلة لتلك المذكورة سابقًا في هذا الموضوع) ، ولكن إذا تم طرح الفكرة الآن لتطبيق هذا التغيير في Go 1.14 ، فستكون متابعة لذلك قد يكون الموضوع مفيدًا (مع رابط تذكير لهذه المناقشة).

هل أي من المكتبات التي أدرجتها تعتمد على سلوك GOOS = windows؟ لقد زعمت مرارًا وتكرارًا أن هذا التغيير سيؤدي إلى كسر الشفرة الحالية ، لكنك لم تقدم أي دليل على الإطلاق.

سيتطلب ذلك تقييمًا أمنيًا كاملًا ( لكثير من التعليمات البرمجية) ليقوله على وجه اليقين. أعتقد أنني قدمت بالتأكيد دليلًا كافيًا على أن الناس يعتمدون على سلوك من شأنه أن يتغير بشكل واضح مع إدخال هذا العلم. وهذا مجرد رمز متاح للجمهور على GitHub.

يرجى التوقف عن الإدلاء ببيانات مثيرة لا يمكن دعمها. إنه لا يوضح شيئًا ، وأنا أجده مسيئًا.

إذا لم تكن الروابط والرموز مدعومة بشكل كافٍ ، فأنا لا أعرف ماذا سيكون في كتابك. لن تجد رمزًا يتوقف عن التجميع بسبب هذا التغيير ، لكنك ستجد بالتأكيد رمزًا يتصرف بشكل مختلف معه ، وسيعتبر الكثير من الأشخاص أن الرمز "معطّل" بسبب تلك التغييرات في السلوك.

لا تأخذ اعتراضي بشكل شخصي ، أعتقد أن الجميع هنا (بما فيهم أنت) يحاول فقط إضافة مدخلاتهم لتحسين اللغة. إذا كنت ستدافع عن تغيير جوهري ، فيجب أن تتوقع مقاومة صحية.

كما أوضحت أعلاه ، فإن حذف الملف باستخدام FILE_SHARE_DELETE لا يحتوي على نفس ميزة UNIX. على سبيل المثال ، يرجى تجربة هذه الخطوات.

ج الرئيسية

#include <windows.h>
#include <stdio.h>

int
main() {
  // ensure delete the file
  DeleteFile("test.txt");

  // create test.txt with FILE_SHARE_DELETE
  HANDLE h = CreateFile("test.txt",
      GENERIC_READ | GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
      NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  puts("waiting 10sec, please run watch.exe on another cmd.exe");
  Sleep(10000);
  if (DeleteFile("test.txt")) {
    puts("deleted");
  }
  getchar();
  return 0;
}

مشاهدة

#include <stdio.h>
#include <shlwapi.h>

int
main() {
  // waiting test.txt will be removed.
  while (PathFileExists("test.txt")) {
    puts("watching...");
    Sleep(1000);
  }
  // now test.txt should not exists. So this is possible to create new file
  system("notepad test.txt");
  return 0;
}

Makefile

all : main.exe watch.exe

watch.exe : watch.c
    gcc -o watch.exe watch.c -lshlwapi

main.exe : main.c
    gcc -o main.exe main.c

في البداية ، يرجى تشغيل main.exe ثم تشغيل watch.exe التالي. في نظام UNIX ، قم بإلغاء ربط (2) وقم بإزالة الملف على الفور. لذا فإن العمليات الأخرى التي تراقب وجود الملف يمكن أن تكون إنشاء ملف جديد بنفس اسم الملف. ولكن في نظام التشغيل Windows ، يُظهر notepad.exe مربع حوار خطأ "انتهاك وصول" نظرًا لأن Windows لا يحذف الملف على الفور. لا استطيع ان اقول لكم ما سيحدث مع هذا. مشكلة أمنية؟ هل فقدت الملفات المهمة؟ اسف لا اعرف.

@ havoc-io لن يقوم Windows بحذف ملف مفتوح حتى يتم إغلاقه ، ويحتفظ فقط بأقفال الملفات المفتوحة. لذا فإن استخدام القفل لا يعني الاعتماد على فشل نظام التشغيل. الرجاء تقديم أمثلة تعتمد بشكل خاص على هذا الفشل.

سأقوم باختبار اتصال golang-dev الأسبوع المقبل. شخصان رد عليهما ؛ لم يقرأ أحد هذه المسألة ، ولم يقدم أي أمثلة.

الادعاءات المثيرة التي لا يمكن دعمها ليست "مقاومة صحية".

@ havoc-io لن يقوم Windows بحذف ملف مفتوح حتى يتم إغلاقه ، ويحتفظ فقط بأقفال الملفات المفتوحة. لذا فإن استخدام القفل لا يعني الاعتماد على فشل نظام التشغيل. الرجاء تقديم أمثلة تعتمد بشكل خاص على هذا الفشل.

networkimprov أنت تخلط بين نوعين مختلفين من التأمين.

عادةً ما يتم استخدام ملفات القفل (كما تم تأمينها بـ LockFileEx ) لحماية مورد. قد يكون أحد الأمثلة هو التأكد من وجود مثيل واحد فقط من البرنامج الخفي قيد التشغيل. إذا فتح برنامج Windows Go الخفي ملفًا ثم نفذ LockFileEx على الملف واكتسب بنجاح قفلًا حصريًا ، فقد يفترض بحق أنه لن تتم إزالة ملف القفل من تحته. ولكن ، إذا تم تمكين FILE_SHARE_DELETE افتراضيًا ، فلن تكون جميع التعليمات البرمجية الموجودة التي تفترض هذا الافتراض صحيحة. إذا قام وكيل إضافي بإزالة ملف القفل هذا (على سبيل المثال ، حذف المستخدم دليلًا عن غير قصد) ، فمن المحتمل أن يظل البرنامج الخفي الأصلي قيد التشغيل عندما يقرر ملف جديد البدء.

يمكن أيضًا استخدام ملفات القفل لأوامر خط الأنابيب إذا تم حذف علامة LOCKFILE_FAIL_IMMEDIATELY ، مما يتسبب في انتظار LockFileEx دوره للحصول على القفل. إذا تمت إزالة ملف القفل عن غير قصد ، فقد يتسبب ذلك في تنفيذ أوامر متعددة في وقت واحد كان من المفترض أن يتم توجيهها.

الادعاءات المثيرة التي لا يمكن دعمها ليست "مقاومة صحية".

لا أحد يقدم ادعاءات مثيرة أو غير قابلة للدعم في هذا الموضوع. قدم كل شخص لم يوافق على اقتراحك ، بمن فيهم أنا ، حججًا سليمة مدعومة برمز. كما فعل الأشخاص الذين أيدوا اقتراحك.

الرجاء مراجعة مستندات WinAPI ؛ لن يحذف Windows ملفًا مفتوحًا حتى يتم إغلاقه ، ويحتفظ فقط بأقفال LockFileEx () للملفات المفتوحة ، لذلك لا يمكن أن يستمر القفل عند إغلاق الملف ، بغض النظر عن الحذف. قد تظهر خطأ محاولة فتح ملف مقفل (أي مفتوح) بعد الحذف ، لذلك لا يمكن الحصول على قفل ثانٍ. الخيوط المنتظرة على القفل تجعل الملف مفتوحًا ، لذلك لن يتم تعطيله بالحذف.

ما لم أخطئ في قراءة المستندات ، فإن السيناريوهين الأخيرين لك غير مدعومين. وكان هذا مثيرًا وغير مدعوم: "يبدو هذا التغيير وكأنه ... مصنع مكافحة التطرف العنيف في أسوأ الحالات. أنا حقًا لا أرى كيف تفوق الفوائد الغامضة الكسر الواضح للشفرة الذي سيحدث."

networkimprov المشكلة هي أن ملفات تأمين تقييد الموارد عادة ما تستند إلى مسار الملف. قد لا يتم حذف كائن الملف الأساسي حتى يتم إغلاق الملف ، ولكن إذا تمت إزالته عبر DeleteFile ، فلن يمكن الوصول إليه من المسار السابق في نظام الملفات 1 ، وسيتيح ذلك إنشاء ملفات قفل أخرى في هذا المسار ، مما يلغي الغرض من ملف القفل.

لا أعتقد أنه كان تعليقًا مثيرًا للإثارة - يبدو من الواضح جدًا أن شيئًا كهذا قد يتسبب في مشكلة أمنية إذا كان الكود يعتمد على بعض ثوابت نظام التشغيل التي لم تعد صحيحة. ويبدو أن الفوائد هنا غامضة للغاية (كما علق العديد من الأشخاص: هذا لا يتوافق مع سلوك Windows مع POSIX) ويبدو الكسر واضحًا جدًا (على الأقل يكسر سلوكيات قفل معينة).

1 يبدو أن هذا هو الحال على الأقل عند الاختبار وبناءً على هذا التعليق .

بالنسبة إلى "أحدث إصدار من Windows ، قمنا بتحديث DeleteFile (على NTFS) لإجراء حذف" POSIX "، حيث تتم إزالة الملف من مساحة الاسم على الفور" من https://github.com/golang/go/issues/ 32088 # issuecomment -502850674. AFAIK لم يتم إصدار هذا الإصدار من Windows. ما الاختبار الذي تشير إليه؟

إعادة الفوائد ، أعتقد أنه يجب عليك مراجعة الموضوع بأكمله.

AFAIK لم يتم إصدار هذا الإصدار من Windows.

networkimprov أعتقد أن هذا هو الحال بالفعل على Windows 10. يبدو أنني قادر على إزالة ملف مقفل بـ LockFileEx إذا تم تحديد FILE_SHARE_DELETE إلى CreateFileW عند فتح الملف.

لن يعطي DeleteFileW () خطأ في هذا السيناريو. كيف تعرف أنه تمت إزالته على الفور من نظام الملفات ، مقابل إزالته عند إغلاق الملف / التطبيق؟ هل حاولت فتح / إعادة إنشاء الملف بعد إزالته؟

في الواقع ، إنه يؤثر تقنيًا على سلسلة أدوات Go ، والتي _أيضًا_ تستخدم LockFileEx بالطريقة المذكورة أعلاه.

ضمن الأمر go نريد بشدة دلالات POSIX ، ويجب ألا نعتمد بأي شكل من الأشكال على غياب FILE_SHARE_DELETE . في الواقع ، لقد أضفت حزمة cmd/go/internal/robustio خصيصًا للعمل على الطرق التي ينحرف بها قفل ملفات Windows عن POSIX.

ianlancetaylor لقد نشرت مرارًا وتكرارًا إلى golang-nuts & -dev للحصول على تعليق من أي مشروع يعتمد على سلوك Windows syscall.Open الحالي (غير الموثق). لم تظهر حالة استخدام واحدة.

نظرًا لظهور العديد من حالات الاستخدام التي تحتاج إلى FILE_SHARE_DELETE أعلاه (وبما أن Microsoft طلبت تحديدًا منا استخدامها) ، فلنقم بتعيين هذه العلامة افتراضيًا في الإصدار التجريبي 1.14 ، ونعيد تقييم ما إذا كانت هناك أي حالات استخدام لسطح السلوك الأصلي أثناء الدورة.

كما هو مقترح سابقًا في سلسلة الرسائل هذه ، يمكن للشخص الذي يحتاج إلى مكالمة مفتوحة () بدون هذه العلامة أن يقوم باستدعاء خاص به ، باستخدام CreateFileW() & os.NewFile() .

هل يمكننا على الأقل الكشف عن مقبض لهذا؟

هذا مفيد للغاية لتنفيذ تدوير السجل على النوافذ.

هذا مفيد للغاية لتنفيذ تدوير السجل على النوافذ.

لا أتأكد ولكني أعتقد أنه لن يعمل لأن FILE_SHARE_DELETE لا يسمح بإنشاء ملف جديد باسم الملف الأصلي إذا لم يتم إغلاق مقبض الملف.

@ Random-Liu هل تسأل عن طريقة لتمكين fsd عند الفتح () ، أم تعطيلها؟

mattn إنه يعمل بالنسبة لي. بعد os.Rename ملف السجل القديم ، يمكنني إنشاء ملف سجل جديد بالاسم الأصلي ، وإبلاغ البرنامج الخفي لإعادة فتح ملف السجل.

networkimprov أريد طريقة لتمكين FILE_SHARE_DELETE . أستخدم حاليًا syscall.CreateFile مباشرةً.

إصدار الويندوز الخاص بي:

Major  Minor  Build  Revision
-----  -----  -----  --------
10     0      17763  0

@ Random-Liu لكني أعتقد أننا لا نستطيع استخدام هذا لمحاكاة سلوك UNIX.

https://github.com/golang/go/issues/32088#issuecomment -510345908

لا يمكن للتطبيق الخارجي الوصول إلى اسم الملف الأصلي.

ماتن ، ليست هناك حاجة لتكرار هذه النقطة. لقد ذكرنا بالفعل أنه يجب علينا توثيق الحاجة (على Windows) لإعادة تسمية ملف قبل حذفه عندما يجب إعادة استخدام اسم الملف قبل إغلاق المقبض.

إذا كان يعيد تسمية الملف قبل إغلاقه بواسطة التطبيق نفسه ، فأنا أشعر أنه لا يوجد محترفون للمستخدمين الذين يريدون تسجيل الدخول.

ianlancetaylor أعد المحاولة: https://github.com/golang/go/issues/32088#issuecomment -526074116

لقد حددت هذه المشكلة على أنها مانع للإصدارات.

bcmills هل يمكنني الاهتمام بنشر CL؟

هذا السطر: https://golang.org/src/syscall/syscall_windows.go#L291
يحتاج فقط: sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)

تحرير: اختبار للتحقق من أنه سينشئ ملفًا ، ثم حاول إعادة تسميته قبل إغلاقه.

نحتاج إلى هذا قريبًا ، لذلك هناك وقت لتظهر أي مشكلات قبل التجميد ...

يجب أيضًا أن تذكر مستندات os.Remove () أنه في نظام التشغيل Windows ، يجب إعادة تسمية الملف المفتوح قبل إزالته إذا كان اسم الملف بحاجة إلى أن يكون متاحًا لإعادة الاستخدام قبل إغلاق الملف. لا يكمل Windows حذف ملف مفتوح حتى يتم إغلاقه.

يبدو أن أحدث إصدار من Windows يتوافق مع https://github.com/golang/go/issues/32088#issuecomment -502850674. راجع https://github.com/papertrail/go-tail/pull/10#issuecomment -529460973 للحصول على التفاصيل. يمكننا الآن إعادة استخدام اسم الملف المحذوف ، حتى إذا كان لا يزال هناك مقابض مفتوحة للملف القديم ، بشرط أن يتم فتح هذه المقابض باستخدام وضع المشاركة FILE_SHARE_DELETE . لا حاجة لإعادة التسمية قبل الحذف. ربما يكون من المنطقي أخيرًا تعيين FILE_SHARE_DELETE افتراضيًا في Go؟

هذا هو القصد. نحن فقط بحاجة إلى شخص ما لإرسال CL. (كنت سأفعل ، لكن لا يمكنني التوقيع على CLA.)
تصف تعليقي السابقتين التغييرات الضرورية ...

jstarks @ jordanrh1thaJeztah

سؤال:
كيف نحصل على سلوك ثابت؟
إذا تم تشغيل البرنامج على "أحدث إصدار من Windows" ، فسيسمح بإنشاء ملف باسم مشابه لملف "الحذف المعلق" ، وسوف ينكسر الإصدار الأقدم عند حدوث خطأ.

قد يقول هذا في الواقع: "اجتاز الاختبارات / qa ولكنه لا يعمل على معظم الأهداف" الآن ، و
"يعمل عادةً ، وأحيانًا لا" في المستقبل (لن يتمكن مطور بعد عامين من ظهور خطأ "خروج الملف بالفعل" من إعادة الإنتاج).

نحتاج إلى معرفة كيفية تحديد الإصدارات "القديمة" وإما تغيير السلوك الافتراضي لتلك الإصدارات أو تحسين الخطأ إذا كان "هناك حذف معلق" - لست متأكدًا من كيفية القيام بذلك.
وإذا كنا غير قادرين ، فكيف نتعامل مع التناقض.

guybrand كما هو مذكور أعلاه ، سنقوم بتوثيق أنه على Windows "يجب إعادة تسمية ملف مفتوح قبل إزالته إذا كان اسم الملف بحاجة إلى أن يكون متاحًا لإعادة الاستخدام قبل إغلاق الملف."

يعمل هذا مع إصدارات Windows القديمة والجديدة بالإضافة إلى POSIX.

يبدو هذا وكأنه أسلوب مختلف: "إعادة التسمية دائمًا قبل إعادة الاستخدام ، حتى على Windows أو POSIX الجديد"
يعجبني - إنه يؤيد ممارسة شائعة ستنجح في كل مكان.

تغيير https://golang.org/cl/194957 يذكر هذه المشكلة: syscall: allow FILE_SHARE_DELETE on syscall.Open on Windows

موضوع golang-nuts موجود هنا ، ولم يتلق أي ردود. يبدو أن هذا يشير إلى أنه لا يوجد من يقرأ golang-nuts ويعرف عن هذا السلوك يعتمد عليه.

سلاسل golang-dev موجودة هنا وهنا ، وهذا الأخير (الخيط الأحدث) أيضًا لم يحظ بأي اعتراض.

alexbrainman -2'd CL لتنفيذه بناءً على نقص واضح في القرار ، لذلك قمت بإعادة تسمية هذه المشكلة بـ NeedsDecision حتى نتمكن من الحصول على اتجاه واضح.

شخصيًا ، يبدو القرار واضحًا بالنسبة لي: نظرًا لأن الأشخاص من Microsoft في هذا الموضوع يدعمون تغيير السلوك الافتراضي لاستخدام FILE_SHARE_DELETE (https://github.com/golang/go/issues/32088 # issuecomment-502850674) ، وأنه لا يبدو أن أي شخص على golang-nuts يهتم بطريقة أو بأخرى ، أعتقد أننا يجب أن نفعل ذلك.

الاعتراضات التي رأيتها في هذا الموضوع تنقسم إلى فئتين:

  1. قلق alexbrainman (https://github.com/golang/go/issues/32088#issuecomment-504321027) و mattn (https://github.com/golang/go/issues/32088#issuecomment-494417146) يبدو أنه نظرًا لأن السلوك لا يزال غير مطابق لـ POSIX ، فقد يتم الخلط بين المستخدمين الذين يتوقعون دلالات POSIX. (ولكن الأمر كذلك بالفعل هو أن Open على Windows لا يوفر دلالات POSIX ، لذلك يبدو لي هذا القلق مستقلاً عن التغيير المقترح.)

  2. يبدو أن قلق @ havoc-io (https://github.com/golang/go/issues/32088#issuecomment-510314947) هو أن FILE_SHARE_DELETE سيقلل من الثوابت التي توفرها حزم تأمين الملفات عند التشغيل على Windows . لكن هذه الحجة تبدو مربكة بعض الشيء بالنسبة لي ، لأن الحزمة الملموسة الموجودة كمثال ( github.com/gofrs/flock ) تشير صراحةً إلى أن "سلوكيات القفل غير مضمونة لتكون هي نفسها في كل منصة" ، ومن تدقيق سريع لا يبدو أن أيًا من الأمثلة الملموسة يعتمد على التفاعل الخاص بـ Windows بين القفل وحذف الملفات.

التعليق في https://github.com/golang/go/issues/32088#issuecomment -498690757 يثير اهتمامي ، على الرغم من:

أتفق مع ianlancetaylor تغيير سلوك toolchain بالكامل ، كما هو مقترح في https://codereview.appspot.com/8203043/ ليس فكرة جيدة. إحدى المشكلات الفورية التي تتبادر إلى الذهن هذا الاقتراح عند استخدام مقبض ملف كملف قفل. نحن نستخدم هذا السلوك.

maruel ، هل يمكنك إعطاء مزيد من التفاصيل حول كيفية اعتماد برنامجك على التفاعل الخاص بنظام Windows بين قفل الملفات وحذف الملف أو إعادة تسميته؟

نحن في Chrome Infra نستخدم وجود الملف كآلية قفل. أود أن أقول أنه لا داعي للقلق كثيرًا بشأن حالة الاستخدام هذه. عمليًا مما أفهمه O_CREATE + FILE_FLAG_DELETE_ON_CLOSE الدلالات كافية لهذه الحاجة ويمكن استبدالها بـ mutex في مساحة الاسم Global\\ ، وهو ما نقوم به بالفعل في قاعدة كود Python.

لم يذكر هذا الحل:

path := "delete-after-open"
fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
if err != nil { ... }
// defer statements are executed in LIFO
defer os.Remove(path)            // or defer os.Rename(path, path+"2")
if err != nil { ... }
defer fd.Close()

له عيبان:

  • إغلاق () ليس صحيحًا بعد الفتح ()
  • استعادة رمز الخطأ أكثر تعقيدًا

iwdgo هذا الحل مخصص للاستخدام في عملية واحدة. تدور معظم المناقشة أعلاه حول الوصول المتزامن من عمليات متعددة. هذا ما يجعل العلم مهمًا.

لاستكمال bcmills re-cap للمشكلة ، نظرنا في ثلاث أدوات تطوير أخرى عبر الأنظمة الأساسية:

جعلها Mingw-w64 افتراضيًا منذ سبع سنوات:
https://sourceforge.net/p/mingw-w64/code/HEAD/tree/stable/v3.x/mingw-w64-headers/include/ntdef.h#l858

جعله Erlang افتراضيًا منذ أكثر من ست سنوات: erlang /

لم تستطع Python اعتماده بسبب قيود وقت تشغيل MSVC في الوقت الذي اعتبروه: https://bugs.python.org/issue15244

كما لم ير الخيط الثاني golang-nuts أي اعتراضات:
https://groups.google.com/d/topic/golang-nuts/aRvSo3iKvJY/discussion

هل تريد جعل FILE_SHARE_DELETE افتراضيًا لـ Open ()؟ مناقشتنا لا ينبغي أن يكون ذلك.

  1. قلق alexbrainman ( # 32088 (تعليق) ) ... يبدو أنه بما أن السلوك لا يزال غير مطابق لـ POSIX ...

قلقي الرئيسي هو كسر برامج الناس. مشابه لما قاله minux على https://codereview.appspot.com/8203043/#msg10

سبب آخر: الأشخاص الذين يستخدمون windows يقبلون عدم القدرة على إعادة تسمية أو
إزالة ملف مفتوح هو القاعدة وقد اعتاد بالفعل على هذه الحقيقة.

لا يمكننا تغيير سلوك برنامج Go 1.0 بصمت هنا ، ربما الأشخاص
تعتمد عليه في الواقع.

ماذا حدث لوعد التوافق مع Go 1.0 هنا؟ أين تقول في https://golang.org/doc/go1compat ، أنه من المقبول تغيير سلوك الملف المفتوح إذا أعلنت عن نيتك في go-nuts؟

ربما يمكننا تغيير هذا السلوك بمجرد تقديم Go 2؟ هل يمكننا استخدام الوحدات النمطية لحماية التعليمات البرمجية الموجودة من الانهيار؟ هل أنا مخطئ في افتراض أن هذا هو الغرض من تصميم الوحدات؟

شخصيًا ، يبدو القرار واضحًا بالنسبة لي: نظرًا لأن الأشخاص من Microsoft في هذا الموضوع يدعمون تغيير السلوك الافتراضي لاستخدام FILE_SHARE_DELETE ...

إذا كانت Microsoft هي السلطة بالنسبة لك في هذا الموضوع ، فعليك أن تنظر في ما تفعله أدوات تطوير Microsoft.

لقد استخدمت هذا البرنامج https://play.golang.org/p/4ZPmV6Df3SD مشابه لما نشره mattn على https://github.com/golang/go/issues/32088#issuecomment -493753714 لقد قمت ببنائه باستخدام مترجم C الأخير

Microsoft (R) C / C ++ Optimizing Compiler Version 19.16.27030.1 لـ x64
حقوق النشر (C) لشركة Microsoft Corporation. كل الحقوق محفوظة.

وعندما أقوم بتشغيل البرنامج ، لم أتمكن من حذف ملف C:\Users\Alex\AppData\Local\Temp\a.txt حتى وجود البرنامج.

نفس الشيء مع برنامج C # المماثل https://play.golang.org/p/SuM2iWYpZir الذي استخدمته مؤخرًا

Microsoft (R) Visual C # Compiler الإصدار 2.10.0.0 (b9fb1610)
حقوق النشر (C) لشركة Microsoft Corporation. كل الحقوق محفوظة.

وبالمثل ، فإن برنامج C هذا https://play.golang.org/p/6HgxePzEW_W الذي تم إنشاؤه باستخدام Mingw الأخير

مجلس التعاون الخليجي (x86_64-win32-seh-rev0 ، تم إنشاؤه بواسطة مشروع MinGW-W64) 7.3.0
حقوق النشر (C) 2017 مؤسسة البرمجيات الحرة ، Inc.

لها نفس التأثير. لذلك لم يتم تعيين علامة FILE_SHARE_DELETE افتراضيًا في أيٍّ من هذه الأدوات.

وأنا شخصياً لا أرى أي فوائد من هذا التغيير. يتضمن مساهماتي Go. ما زلنا غير قادرين على حذف الملفات القابلة للتنفيذ أثناء تشغيل العملية. سنظل نواجه مشاكل في حذف الدلائل إذا تم تعيين الأدلة الحالية الخاصة بأي عملية هناك.

اليكس

هل تريد جعل FILE_SHARE_DELETE افتراضيًا لـ Open ()؟

القصد من ذلك هو جعل os.Open يستخدم FILE_SHARE_DELETE افتراضيًا. هذا https://golang.org/cl/194957 هو الخطة.

اليكس

قلقي الرئيسي هو كسر برامج الناس

حتى الآن ، لا يمكن لأحد أن يشير إلى مثال واحد لبرنامج قد ينكسر لأنه يعتمد على الحصول على خطأ عند محاولة إعادة تسمية / إزالة ملف تم فتحه باستخدام Go. ولكن هناك حالات موثقة يكسر فيها السلوك الحالي تطبيقات Go على Windows.

ماذا حدث لوعد التوافق مع Go 1.0 هنا؟

تظل مستندات Go لـ os.Rename () & .Remove () صامتة بشأن ميزة Windows هذه ، ولكن لها 15 إشارة إلى سلوك آخر خاص بـ Windows. راجع للشغل ، تم شحن Go 2: https://blog.golang.org/go2-here-we-come

مجلس التعاون الخليجي (x86_64-win32-seh-rev0 ، تم إنشاؤه بواسطة مشروع MinGW-W64) 7.3.0

لمن تستخدم C-lib مع دول مجلس التعاون الخليجي - ربما Microsoft؟ الإصدار Mingw-w64 هو الإصدار 6.0 ويتضمن FILE_SHARE_DELETE في FILE_SHARE_VALID_FLAGS.

كما هو موثق أعلاه في Python ، في الماضي ، كان وقت تشغيل MSVC يمنع بعض تركيبات إشارات CreateFile () لأسباب غير معروفة. لا أعرف ما إذا كان هذا هو الحال ، ولكن قد يكون السبب وراء عدم تغيير MS لـ C-lib fopen ().

لا أرى أي فوائد من هذا التغيير.

تم شرح الفوائد مرارًا وتكرارًا أعلاه ، من قبل العديد من الأشخاص ؛ يسمح بشكل خاص لـ os.Rename () في ملف مفتوح.

وضع علامة كاقتراح لأن المناقشة لا تتقارب بسهولة.

لمحاولة تلخيص القضية والمناقشة حتى الآن:

  • في أنظمة Unix ، إذا فتحت عملية واحدة ملفًا ، يمكن لعملية ثانية إزالة هذا الملف. يمكن أن تستمر العملية الأصلية في استخدام الملف (لم يعد له اسم بعد الآن) ، بما في ذلك عمليات القراءة والكتابة ، والتي تنجح. لا تتم إزالة محتوى الملف من القرص حتى يختفي آخر مرجع مفتوح.

  • في أنظمة Windows ، افتراضيًا ، إذا فتحت عملية واحدة ملفًا ، فإن العملية الثانية _لا يمكن_ إزالة هذا الملف. يمكن إزالة الملف فقط عندما لا يتم فتحه في أي عملية أخرى. تغير علامة FILE_SHARE_DELETE هذا السلوك: إذا تم فتح جميع المراجع المفتوحة للملف باستخدام FILE_SHARE_DELETE ، فيمكن لعملية أخرى استدعاء DeleteFile ، وستنجح بدلاً من الفشل.

يبدو أن سلوك Windows مع FILE_SHARE_DELETE لا يزال مختلفًا تمامًا عن Unix. صفحة MSDN تقول:

تفشل وظيفة DeleteFile إذا حاول أحد التطبيقات حذف ملف له مقابض أخرى مفتوحة للإدخال / الإخراج العادي أو كملف معين للذاكرة (يجب تحديد FILE_SHARE_DELETE عند فتح مقابض أخرى).

تقوم الدالة DeleteFile بوضع علامة على ملف للحذف عند الإغلاق. لذلك ، لا يتم حذف الملف حتى يتم إغلاق المؤشر الأخير للملف. تفشل الاستدعاءات اللاحقة إلى CreateFile لفتح الملف مع ERROR_ACCESS_DENIED.

أي أن الملف _name_ لا يتم إزالته من نظام الملفات حتى تختفي المراجع المفتوحة. هذا يختلف عن Unix ، حيث يختفي الاسم قبل إغلاق المراجع المفتوحة. لذلك ، إذا كنت تقوم بإزالة الملف استعدادًا لإعادة إنشاء ملف يحمل نفس الاسم ، فإن هذا يعمل في نظام Unix ولكن ليس في Windows ، ولا حتى مع FILE_SHARE_DELETE.

كان الاقتراح الأصلي هو تغيير syscall. افتح لتعيين هذه العلامة دائمًا. بالنظر إلى أنه من المفترض أن يكون طلب النظام قريبًا من واجهة kernel ، فإن إضافة هذه العلامة تبدو في غير محلها. لكن يمكننا بدلاً من ذلك التفكير فيما إذا كان يجب تعيينه أثناء os.Open / os.OpenFile.

قالalexbrainman أن الحجة القائلة بأن نظامي Unix و Windows مختلفان ،

تقولjstarks من Microsoft أن Microsoft تفضل تعيين FILE_SHARE_DELETE تلقائيًا وأن "أحدث إصدار" من Windows (غير واضح

يناقش networkimprov أننا يجب أن نجري التغيير وأنه لا توجد أمثلة فعلية للبرامج التي قد

alexbrainman لا يزال يبدو غير مقتنع.

اقترح mattn أيضًا أنه لا ينبغي لنا تعيين العلامة تلقائيًا ، جزئيًا لأنه (على الأقل حتى يستخدم الجميع أحدث Windows) سيظل مختلفًا عن Unix.

بشكل عام ، يحاول نظام التشغيل الحزمة تقديم واجهة برمجة تطبيقات محمولة ، ويبدو - خاصة مع تغيير نظام التشغيل Windows - أن تعيين العلامة تلقائيًا سيساعد في ذلك. هناك علامات أخرى قمنا بتعيينها تلقائيًا في os.Open للمساعدة في جعل السلوك أقل إثارة للدهشة للمستخدمين ، ولا سيما O_CLOEXEC (close-on-exec). أي برنامج يتعطل على نظام التشغيل Windows بسبب تعيين هذه العلامة في نظام التشغيل OS.Open سيتعطل بالضرورة على نظام التشغيل Unix ، أليس كذلك؟

خاصة وأن مهندسًا واحدًا على الأقل في Microsoft يقول أنه يجب علينا إعداده ، يبدو أنه سيكون من الجيد التعيين في نظام التشغيل الحزمة. يمكن للأشخاص الذين لا يريدون مجموعة العلامات الرجوع إلى حزمة syscall.

alexbrainman و mattn ، لنفترض أننا وضعنا العلم في os.Open. نحن نعلم أن بعض البرامج ستعمل بشكل أفضل. هل لديك أمثلة محددة لبرامج حقيقية (أو محتملة) يمكن أن تتعطل؟ ألن يتم كسر هذه البرامج على يونكس بالفعل؟ شكرا.

rsc ، شكرا

لتوضيح ملخصك ، حدود العملية ليست عاملاً ؛ التأثيرات هي نفسها خلال عملية واحدة. ويؤثر العلم أيضًا على إعادة تسمية الملف ؛ مع العلم أنه يكمل على الفور على عكس حذف الملف. (وهذا يسمح بحل بديل لتوافر اسم الملف بعد الحذف مباشرة.)

شكراًnetworkimprov. نعم ، أفهم أن حدود العملية ليست وثيقة الصلة ؛ إنه يجعل المواقف أسهل في الوصف.

لقد قمت بتغيير العنوان ومراجعة خطة العمل في نص العدد:

أ) يجب أن يقوم os.Create / Open / OpenFile () دائمًا بتمكين file_share_delete على Windows ،
ب) يجب أن يقبل syscall.Open () على Windows علامة تمكن file_share_delete ، و
ج) يجب أن يقوم syscall على Windows بتصدير ثابت للعلامة الجديدة.

يجب أن تلاحظ المستندات الخاصة بـ os.Remove () أيضًا أنه لإعادة استخدام اسم ملف بعد حذف ملف مفتوح على Windows ، يجب على المرء القيام بما يلي: os.Rename(path, unique_path); os.Remove(unique_path) .

لا يمكن إنكار احتمال وجود مستخدم يقوم بتنفيذ معالجة حصرية باستخدام نظام التشغيل OS.Open الحالي الخاص بـ Go.

ولكن هناك حالات موثقة يكسر فيها السلوك الحالي تطبيقات Go على Windows.

ما هذه؟ ما هي أرقام الإصدار؟ وماذا تقصد بكلمة break ؟ متى كسروا؟

لمن تستخدم C-lib مع دول مجلس التعاون الخليجي - ربما Microsoft؟ الإصدار Mingw-w64 هو الإصدار 6.0 ويتضمن FILE_SHARE_DELETE في FILE_SHARE_VALID_FLAGS.

لا اعرف. لقد قمت للتو بتنزيل ملف x86_64-7.3.0-release-win32-seh-rt_v5-rev0.7z من الإنترنت. يمكنك جوجل لذلك. إنه من الإصدار 7.3.

لا أرى أي فوائد من هذا التغيير.

تم شرح الفوائد مرارًا وتكرارًا أعلاه ، ...

لقد تركت الكلمة personally من عرض الأسعار. أتحدث عن احتياجاتي الخاصة. وهذا يشمل مساهماتي في مشروع Go.

لمحاولة تلخيص القضية والمناقشة حتى الآن:

أنت لم تقل أن أدوات مطور Microsoft على Windows لا توفر هذه العلامة افتراضيًا. انظر تعليقي https://github.com/golang/go/issues/32088#issuecomment -531713562

لقد تجاهلت أيضًا تعليقي حول توافق Go 1

ماذا حدث لوعد التوافق مع Go 1.0 هنا؟ أين تقول في https://golang.org/doc/go1compat ، أنه من المقبول تغيير سلوك الملف المفتوح إذا أعلنت عن نيتك في go-nuts؟

كيف يتوافق هذا التغيير مع وعد التوافق مع Go 1.0؟

بشكل عام ، يحاول نظام التشغيل الحزمة تقديم واجهة برمجة تطبيقات محمولة ، ويبدو - خاصة مع تغيير نظام التشغيل Windows - أن تعيين العلامة تلقائيًا سيساعد في ذلك.

أوافق على أن هذا التغيير يهدف إلى نقل الأشخاص لبرنامج Unix إلى Windows.

للأسف على حساب مستخدمي Windows. سيكون هذا التغيير مفاجئًا لمستخدمي Windows والمطورين ، لأنه لا توجد برامج أو أدوات أخرى على Windows تعمل بهذه الطريقة. ربما في المستقبل ، لكن ليس بعد.

وحتى بالنسبة للأشخاص الذين ينقلون برامج Unix إلى Windows ، فإن هذا التغيير يقوم بعمل سيء للغاية IMHO. انظر جزء We still won't be able to delete executable files while process is running. We will still have problems deleting directories if any process have their current directories set there. من تعليقي https://github.com/golang/go/issues/32088#issuecomment -531713562

هناك علامات أخرى قمنا بتعيينها تلقائيًا في os.Open للمساعدة في جعل السلوك أقل إثارة للدهشة للمستخدمين ، ولا سيما O_CLOEXEC (close-on-exec). أي برنامج يتعطل على نظام التشغيل Windows بسبب تعيين هذه العلامة في نظام التشغيل OS.Open سيتعطل بالضرورة على نظام التشغيل Unix ، أليس كذلك؟

انا لا اعرف ماذا تقصد هنا يعني O_CLOEXEC على Windows منع هروب مؤشرات الملفات إلى العملية التابعة. ويتم دائمًا تعيين O_CLOEXEC في os.Open على Windows. لذلك لا يمكن الوصول إلى أي ملف مفتوح مع os.Open من خلال عملية الطفل على Windows. وماذا في ذلك؟ يبدو معقولا.

ألن يتم كسر هذه البرامج على يونكس بالفعل؟

أنا لا أفهم سؤالك.

هل لديك أمثلة محددة لبرامج حقيقية (أو محتملة) يمكن أن تتعطل؟

لا أعرف ، إذا كان لدي مثل هذه البرامج. يستحيل قول ذلك. لا أتذكر كل البرامج التي كتبتها. لا أتذكر ما يفعلونه.

لكن يمكنني تخيل أن خدمة Windows تفتح ملفًا محددًا مسبقًا ، لنفترض أن c:\mysvc.txt ، وتبقيه مفتوحًا. تخيل أن برنامجًا آخر يتحقق من أن الخدمة نشطة ، ويعيد تشغيل الخدمة ، إذا لزم الأمر. يمكن لهذا البرنامج الآخر فقط محاولة حذف c:\mysvc.txt ، وإذا اختفى الملف ، فيمكنه افتراض أن عملية الخدمة قد ماتت.

يمكنني أيضًا أن أتخيل أن بعض البرامج قد ترغب في منع المستخدمين من حذف ملفاتهم أو نقلها - https://stackoverflow.com/questions/11318663/prevent-a-user-from-deleting-moving-or-renaming-a-file

اليكس

فيما يلي نقطة بيانات لإعادة نشر Go على Windows:
تم شحن Win8 منذ 7 سنوات.
تم الإبلاغ عن خطأ Go هذا الذي يؤثر على Win8 + منذ 5 أشهر فقط: # 31528

rsc أي برنامج يتوقع حدوث خطأ عند محاولة إعادة تسمية / إزالة ملف مفتوح باستخدام Go معطّل على Unix. على سبيل المثال ، سيناريو Alex's c:\mysvc.txt .

إذا طور أحدهم على Windows وانتشر على Linux / إلخ (أو العكس) ، فقد يكون هذا مصدرًا للأخطاء.

حالة الاستخدام لدينا هي أن لدينا أداة تسجيل تقوم بتسجيل الدخول إلى ملف.
يدعم ملف السجل التدوير (على سبيل المثال ، الكتابة التالية إذا كان ملف السجل> maxSize ثم تدوير).
لدينا أيضًا قراء يفتحون هذه الملفات ويبقونها مفتوحة أثناء قراءتها.

حتى بدون القدرة على تعيين FILE_SHARE_DELETE لا يمكننا إجراء تناوب (إعادة تسمية و / أو حذف) أثناء وجود قارئين نشطين.

@ ماتن :

لا يمكن إنكار احتمال وجود مستخدم يقوم بتنفيذ معالجة حصرية باستخدام نظام التشغيل OS.Open الحالي الخاص بـ Go.

قد يكون هذا صحيحًا ، لكن هذا الرمز غير صحيح على Unix على أي حال. من المفترض أن تكون Package os واجهة محمولة. كما أننا مهتمون بالبرامج "الواقعية" أكثر من الاهتمام بالاحتمالات.

alexbrainman :

أنت لم تقل أن أدوات مطور Microsoft على Windows لا توفر هذه العلامة افتراضيًا. انظر تعليقي # 32088 (تعليق)

نعم ولكن هذا هو C ؛ نحن نتحدث عن Go. نحن لا نحاكي C APIs بشكل عام. نحاول تقديم تجريد محمول في الغالب في حزمة نظام التشغيل. كانت النقطة حول O_CLOEXEC أنه في أنظمة Unix ، يحدد os.Open O_CLOEXEC على الرغم من أنه لم يتم تعيينه افتراضيًا في استدعاء C المقابل. نحن نحاول توفير الإعدادات الافتراضية المفيدة التي تتصرف تقريبًا بالطريقة نفسها في جميع الأنظمة.

فيما يتعلق بتوافق Go 1 ، يبدو أن تغيير سلوك حالة الركن على أحد أنظمة التشغيل لتتماشى بشكل أفضل مع أنظمة تشغيل أخرى أمر جيد. نحن لا نعد بالحفاظ على جميع حالات عدم التوافق عبر الأنظمة في جميع الأوقات.

يتمتع مستخدمو Windows الذين يصرون على السلوك الخاص بالنافذة دائمًا بخيار استخدام حزمة syscall ، مما يوضح أن السلوك الذي يتم الوصول إليه ينطبق بالفعل على Windows فقط.

مرة أخرى ، هل لديك أمثلة ملموسة لبرامج حقيقية يمكن أن تتعطل؟

@ cpuguy83 ، شكرًا لحالة الاستخدام الواقعية للبرنامج الذي سيتم مساعدته.

rsc كما قلت ، لم

ومع ذلك ، بمجرد تضمين Go هذا التغيير الذي يمكنه حذف الملف ، يتوقع المستخدم هذا السلوك على الرغم من أن Go لا يمكنه تنفيذ logrotate على Windows من خلال هذا التغيير. لذلك علينا التفكير مليًا في هذا التغيير. بشكل أساسي ، لا يمكن لـ Windows حذف الملفات التي لم يتم وضع علامة عليها باستخدام FILE_SHARE_DELETE. قد يعتقد المستخدمون أن هذا التغيير سيسمح لـ Go بحذف أي ملفات. على وجه الخصوص ، يمكن للملفات التي تم إنشاؤها بواسطة os.NewFile مع مقبض التعامل مع طرق بنية os.File على الرغم من عدم تعيين هذه العلامة. يجب أن يعلم المبرمج أنه يمكن حذف الملف على Windows أم لا من قبل نفسه ، على ما أعتقد. أفضل آلية تسمح بتمرير FILE_SHARE_DELETE بواسطة علامة لـ os.OpenFile بدلاً من الافتراضي. أعتقد أنه يجب اتباع السلوك الافتراضي لسلوك نظام التشغيل.

نعم ولكن هذا هو C ؛ نحن نتحدث عن Go.

و C # أيضا. لم أحقق في الأمر ، لكنني متأكد تمامًا من أن أي أداة تطوير أخرى على Windows تتصرف بهذه الطريقة.

فيما يتعلق بتوافق Go 1 ، يبدو أن تغيير سلوك حالة الركن على أحد أنظمة التشغيل لتتماشى بشكل أفضل مع أنظمة تشغيل أخرى أمر جيد.

إنها حالة ركنية لغير مستخدمي Windows. بالنسبة لمستخدمي Windows ، يعتبر هذا السلوك قياسيًا.

مرة أخرى ، هل لديك أمثلة ملموسة لبرامج حقيقية يمكن أن تتعطل؟

خذ بعين الاعتبار مثال خدمتي أعلاه ملموسة.

@ cpuguy83 ، شكرًا لحالة الاستخدام الواقعية للبرنامج الذي سيتم مساعدته.

@ cpuguy83 هل يمكنك قول المزيد عن مشكلتك. أود أن أرى كيف سيحل هذا التغيير مشكلتك ، لذلك أود أن أرى بعض التعليمات البرمجية الحقيقية. إذا كان بإمكانك توفير بعض البرامج الصغيرة ، فهذا معطل الآن ، ولكنه سيعمل بمجرد حل هذه المشكلة ، فسيكون ذلك موضع تقدير. ليس من الضروري أن يبني ، ولكن على الأقل يجب أن يوفر ما يكفي ليحكم عليه الجميع. شكرا لك.

بشكل أساسي ، لا يمكن لـ Windows حذف الملفات التي لم يتم وضع علامة عليها باستخدام FILE_SHARE_DELETE. قد يعتقد المستخدمون أن هذا التغيير سيسمح لـ Go بحذف أي ملفات.

أوافق على أن هذه نقطة جيدة. يمكن حذف الملفات التي فتحتها برامج Go فقط. لكن جميع الملفات الأخرى التي تم فتحها بواسطة برامج غير Go ستظل غير قابلة للحذف. سيؤدي ذلك إلى جعل عملية إزالة نظام التشغيل غير متوقعة - في بعض الأحيان ستنجح ، وفي بعض الأحيان لن تنجح.

اليكس

لدي رمز استدعاء syscall مصححة.فتح () الذي يعيد تسمية الملفات المفتوحة. هذه هي الطريقة التي تنفذ بها سجل التناوب ؛ إنها تعمل.

// several processes or goroutines do this
   fd, err := os.OpenFile("log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, ...)
   _, err = fd.Write(log_entry) // one or more times
   err = fd.Close()

// log rotator process does this
   err := os.Rename("log", "log_old") // active writers not disturbed
   fmt.Println(err) // "sharing violation" without FILE_SHARE_DELETE

لكنك لست بحاجة إلى أي شخص يخبرك أن: - /

من الطبيعي أن يكون لملف os. من os.NewFile () العديد من الخصائص المختلفة عن تلك الموجودة في os.Create / Open / OpenFile () ، وهذه ميزة وليست مفاجأة.

تدعي أن سلوك Microsoft C fopen () هو سلوك Windows الافتراضي؛ هذا ليس صحيحا. لا يوجد وضع مشاركة افتراضي CreateFile () ؛ إنه ليس FILE_SHARE_READ | FILE_SHARE_WRITE .

أنت تؤكد أن برامج Windows التي تم نشرها تفترض عمومًا أن __البرامج التي يقوم بها بائعون آخرون__ تفتح دائمًا الملفات بطريقة معينة. إذا كان الأمر كذلك ، فلن تطلب منا Microsoft تمكين file_share_delete افتراضيًا.

تضمين التغريدة

لكنك لست بحاجة إلى أي شخص يخبرك أن: - /

أريد أن أعرف أن العملية الخارجية يمكنها إزالة الملف وإعادة تسميته بشكل صحيح مع أي حالات.

ما أريد معرفته هو: بعد تضمين هذا التغيير ، يتم إخراج ملف السجل من Go ، ويعمل logrotate بواسطة العملية الخارجية بشكل جيد ، ويعمل كإنتاج جاهز دون أي أخطاء.

تضمين التغريدة

لسوء الحظ ، الكود معقد ، لكن هذا هو رمز العالم الحقيقي الفعلي: https://github.com/moby/moby/blob/master/daemon/logger/loggerutils/logfile.go

التخفيف المقترح حاليًا هو فقط شكل os.OpenFile و syscall. افتح: https://github.com/moby/moby/pull/39974/files

لكي نكون واضحين ، مجرد وجود خيار المرور عبر FILE_SHARE_DELETE من OpenFile أو حتى syscall.Open سيكون كافيًا للتعامل مع قضيتنا.

لسوء الحظ ، الكود معقد ، لكن هذا هو رمز العالم الحقيقي الفعلي: https://github.com/moby/moby/blob/master/daemon/logger/loggerutils/logfile.go

التخفيف المقترح حاليًا هو فقط شكل os.OpenFile و syscall. افتح: https://github.com/moby/moby/pull/39974/files

@ cpuguy83 شكرا للمؤشر.

لسوء الحظ ، لا توفر نظرة سريعة على ذلك معلومات كافية للحكم على ما إذا كانت هذه المشكلة الحالية هي الحل. يجب أن أبدأ بـ repro (ربما هذا https://github.com/moby/moby/issues/39274#issuecomment-497966709) وأخذها من هناك. لست متأكدا متى سيكون لدي الوقت لأقضيه في هذا الأمر. إذا كان لديك اقتراح أفضل ثم خطتي ، أخبرني.

اليكس

يوجد أدناه عرض توضيحي عملي لتدوير سجل الممارسة القياسية ، مع 100 goroutines يسجل كل منها 50 سطرًا بفواصل زمنية تتراوح من 0.1 إلى 2 ثانية في كل مرة يفتحون فيها ملف السجل ، ويقوم غوروتين آخر بتدوير السجل على فترات زمنية مدتها دقيقة واحدة. قمت بتشغيل هذا لعدة ساعات بالأمس على كمبيوتر محمول Win7 بدون أخطاء.

تم إنشاؤه باستخدام تصحيح للاتصال syscall.Open () الذي يتيح FILE_SHARE_DELETE ؛ فشل خلاف ذلك. يمكن للمرء أن يلفق نظام تسجيل أكثر تعقيدًا بدون هذه العلامة ، ولكن هناك العديد من الاستخدامات الأخرى له ؛ الكود الخاص بي يعيد تسمية الملفات المفتوحة لأسباب مختلفة.

rsc ، أعتقد أن هذا يكمل حالة اقتراحك ، إذا كان لا يزال هناك أي شك. (وكما هو مذكور أعلاه ، لقد نشرت مرارًا وتكرارًا في golang-dev و golang-nuts طالبًا بمشاريع تعتمد على السلوك الحالي ، بدون نتائج.)

package main

import (
   "fmt"
   "os"
   "math/rand"
   "syscall"
   "time"
)

const kLogFile = "winrotate"

func main() {
   syscall.Open_FileShareDelete = true
   rand.Seed(time.Now().UnixNano())

   for a := 0; a < 100; a++ {
      go runLog()
   }

   fmt.Println("rotating to "+ kLogFile +"N.txt")
   for a := 0; true; a++ {
      if a >= 5 {
         a = 0
      }
      time.Sleep(60 * time.Second)
      err := os.Rename(kLogFile +".txt", kLogFile + string('0'+a) +".txt")
      if err != nil {
         fmt.Println(err)
         os.Exit(1)
      }
   }
}

const kLineVal = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func runLog() {
   aLine := make([]byte, 102)
   for {
      aFd, err := os.OpenFile(kLogFile +".txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
      if err != nil {
         fmt.Println(err)
         return
      }
      for _, aV := range kLineVal {
         for a := range aLine {
            aLine[a] = byte(aV)
         }
         aEnd := aV - ('z' - 100) // limit line len to 100
         copy(aLine[aEnd:], []byte{'\r','\n'})
         _, err = aFd.Write(aLine[:aEnd + 2])
         if err != nil {
            fmt.Println(err)
            return
         }
         time.Sleep(time.Duration(100 + rand.Intn(1900)) * time.Millisecond)
      }
      err = aFd.Close()
      if err != nil {
         fmt.Println(err)
         return
      }
   }
}

التصحيح إلى syscall_windows.go:

diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index de05840..e1455d5 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -245,6 +245,8 @@ func makeInheritSa() *SecurityAttributes {
    return &sa
 }

+var Open_FileShareDelete = false
+
 func Open(path string, mode int, perm uint32) (fd Handle, err error) {
    if len(path) == 0 {
        return InvalidHandle, ERROR_FILE_NOT_FOUND
@@ -270,6 +272,9 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
        access |= FILE_APPEND_DATA
    }
    sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
+   if Open_FileShareDelete {
+       sharemode |= FILE_SHARE_DELETE
+   }
    var sa *SecurityAttributes
    if mode&O_CLOEXEC == 0 {
        sa = makeInheritSa()

networkimprov لم تتم إعادة تسمية الملف بواسطة عملية خارجية. إذا كانت إعادة تسمية الملف تتم بنفس العملية ، فهناك بعض الطرق الأخرى لتنفيذه.

https://github.com/mattn/go-sizedwriter/blob/master/_example/example.go#L14

يوجد أدناه عرض توضيحي عملي لتناوب سجل الممارسة القياسية

شكرًا لك على مثالك ،

المشكلة الوحيدة في التعليمات البرمجية هي أنه إذا كانت هناك عملية خارجية ستفتح الملفات التي تكتب إليها بدون FILE_SHARE_DELETE ، فستواجه نفس المشكلة التي تواجهها الآن بغض النظر عن التغييرات التي نجريها في Go.

@ cpuguy83 لن أنظر إلى مشكلتك (كما وعدت هنا https://github.com/golang/go/issues/32088#issuecomment-536233195) ، لأن مثال @ networkimprov أعطني صورة لما يحاول لكى يفعل.

اليكس

أليكس ، يمكن للمرء تكرار محاولة إعادة التسمية إذا كان الوصول الخارجي مسموحًا به ، أو تقييد ملف السجل النشط إذا لم يكن كذلك.

Mattn ، عادةً ما تتم إعادة تسمية التدوير من خلال عملية منفصلة.

يبدو أنه لا يوجد إجماع واضح هنا. يبدو أن المطورين الذين لديهم خلفيات Unix يؤيدون ذلك ، لكن اثنين من أكثر مطوري Windows نشاطًا ( alexbranman وmattn) ليسوا كذلك. سيؤدي التغيير أيضًا إلى توحيد أحدث إصدار من Windows الذي يحتوي على سلوك جديد مشابه لـ Unix لـ FILE_SHARE_DELETE.

قد يكون من المفيد إعادة النظر في هذا الموضوع في غضون بضع سنوات ، لمعرفة مدى توفر سلوك العلم الجديد على نطاق واسع وما إذا كانت اللغات الأخرى قد تقاربت من سلوك مشترك. إذا أراد شخص ما تقديم مشكلة جديدة في غضون عامين ، على سبيل المثال ، لإعادة التفكير في ذلك ، فسيكون ذلك جيدًا.

لكن في الوقت الحالي ، نظرًا لغياب الإجماع ، يبدو أن هذا تراجع محتمل .

يترك مفتوحا لمدة أسبوع للتعليقات النهائية.

هل هناك خلاف على مجرد إتاحة الخيار؟

إذا كنا نبحث عن المزيد من الأصوات التي تتناغم معها ، فسأؤيد بالتأكيد القيام بشيء ما. في الوقت الحالي ، الحل الوحيد هو نسخ مجموعة من الأكواد من مكتبة Go القياسية ، وتغيير سطر واحد ، ثم الحفاظ على هذه الشوكة إلى الأبد. يبدو أن كل تطبيق لرصد السجل أو "الذيل" المباشر يقوم بذلك في النهاية.

للحصول على مثال ، راجع https://github.com/elastic/beats/blob/master/libbeat/common/file/file_windows.go#L85 -L103

إذا اتبعت بشكل صحيح ، فإن هذا الاقتراح يتكون في الواقع من جزأين:

  1. السماح باستخدام العلامة FILE_SHARE_DELETE عند فتح ملف -
    يجب أن يكون التنفيذ سهلاً وآمنًا ، على المطور أن يفعل ذلك بشكل صريح
    اطلب هذا الوضع عند فتح ملف جديد
  2. قم بتشغيل هذه العلامة افتراضيًا - يمكن أن تكون محفوفة بالمخاطر ومدعومة جيدًا فقط
    عند استخدام أحدث إصدار من windows 10.

إذا اتفق الجميع على 1 ، فربما يمكننا فقط السماح للعلامة عند المطور
اطلبها صراحة في الوقت الحالي ، وراجع 2 في غضون عامين.

في الأربعاء ، 2 أكتوبر 2019 ، الساعة 19:32 ، كتب مارك داشر ، [email protected] :

إذا كنا نبحث عن المزيد من الأصوات التي تتناغم معها ، فسأكون بالتأكيد مؤيدة
لفعل شيء ما . في الوقت الحالي ، الحل الوحيد هو نسخ ملف
مجموعة من التعليمات البرمجية من مكتبة Go القياسية ، قم بتغيير سطر واحد ، ثم
حافظ على تلك الشوكة إلى الأبد. كل تنفيذ لمراقبة سجل أو العيش
يبدو أن "الذيل" يفعل ذلك في النهاية.

على سبيل المثال ، انظر
https://github.com/elastic/beats/blob/master/libbeat/common/file/file_windows.go#L85 -L103

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https: //github.com/golang/go/issues/32088؟email_source=notifications&email_token=ABNEY4VFQLSYVI66ENT6G4LQMTLJ7A5CNFSM4HNPNYIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63H4DFVREXG43VMVBW63HM11
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/ABNEY4U5L3WFZYNIUOSEY2TQMTLJ7ANCNFSM4HNPNYIA
.

بالتأكيد لصالح _ على الأقل _ لديك 1. (السماح باستخدام العلامة FILE_SHARE_DELETE عند فتح ملف)

فقط لإعادة النظر في اقتراحي السابق والمتابعة مع مثال التنفيذ :

ستلائم العلامة syscall.FILE_SHARE_DELETE بشكل جيد المعلمة os.OpenFile flag وستوفر آلية تافهة لتمكين هذا السلوك عند الطلب. لا يتعارض مع أي أعلام أخرى os.O_* على Windows (ويمكن فرض ذلك / هندسته) ويوفر طريقة اصطلاحية لتحديد سلوك فتح الملفات الخاص بالنظام (بقدر os ' يمكن اعتبار واجهة POSIX الموجهة s اصطلاحية في Windows). هذا هو نفس المسار المستخدم بالفعل لتمرير سلوك فتح الملفات الخاص بالنظام على منصات POSIX (على سبيل المثال syscall.O_DIRECTORY على Linux).

حتى إذا تم اتخاذ القرار بعدم تشغيله افتراضيًا (والذي أعتقد أنه الاتصال الصحيح) ، فأنا أوافق على أن للعلامة حالات الاستخدام الخاصة بها (بما في ذلك تلك التي أشار إليهاnetworkimprov) وأنه سيكون من المفيد قادر على تشغيله دون الحاجة إلى اللجوء إلى مكالمات CreateFileW ونسخ الكود المعياري.

يرجى النظر في البديل [1] أعلاه والذي يتيح للمطورين خيار تعيين FILE_SHARE_DELETE عند الضرورة ومنع الأجزاء المتشعبة من كود مكتبة Go القياسي.

__الصدأ__ يعيّن أيضًا هذه العلامة افتراضيًا ، ويسمح لك بإيقاف تشغيل أي من خيارات FILE_SHARE_ *.
https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html

rsc هل يمكنني أن أسأل أي من الحجج الفنية المقدمة ضد الاقتراح لم يتم تفنيدها؟

networkimprov بعد قراءة الاقتراح والمناقشة بالكامل ، أعتقد أنك بحاجة إلى إغلاق هذا وإعادة فتح مشكلة جديدة بشكل صريح حول إضافة علامة خاصة بنوافذ جديدة إلى حزمة ossyscall. وهذا من شأنه أن يضمن أن السلوك الجديد هو الاشتراك بدلاً من الانسحاب. الاقتراح الحالي يعني تغيير الكود الحالي ، الأمر الذي يقلق الناس.

rsc هل يمكنني أن أسأل أي من الحجج الفنية المقدمة ضد الاقتراح لم يتم تفنيدها؟

أنا آسف ، ولكن هذه ليست الطريقة التي تعمل بها عملية الاقتراح . لا يكفي "دحض" حجج الآخرين. الهدف من عملية الاقتراح هو التوصل الى توافق عام حول النتيجة في الوقت المناسب. لا يوجد إجماع واضح حول المسار إلى الأمام هنا. تم تقديم الحجج التقنية ، ولم يقنعوا مطوري Go الرئيسيين الذين قدموا مساهمات كبيرة في منفذ Windows (أي alexbrainman وmattn). بالإضافة إلى عدم وجود إجماع واضح ، لا توجد علامة واضحة على ضرورة القيام بشيء ما اليوم: Go يعمل بشكل جيد على Windows لما يقرب من 10 سنوات قبل رفع هذه المشكلة. كما أفهمها ، فإن ترك كل شيء بمفرده يعني أن Go ستستمر في العمل كما فعلت دائمًا.

لقد قدمت رقم 34681 لتقديم طريقة أسهل لفتح الملفات باستخدام FILE_SHARE_DELETE في الحدث (الذي لا يزال محتملاً) الذي تم رفض هذا الملف. بدا أنه من المفيد أن تبدأ سلسلة محادثات جديدة تقتصر على هذه الفكرة بدلاً من الاستمرار في هذه الفكرة ، التي أصبحت طويلة جدًا.

rsc ، قبل أن ترفض هذا ، دعنا نسمع رأي Alex في اقتراح O_ALLOW_DELETE الخاص بك.

في وقت مبكر من هذه المناقشة ، كان ضد علامة os.OpenFile () الجديدة التي تحدد file_share_delete ، لنفس الأسباب التي لم يوافق عليها مع اقتراح os.Create / Open / OpenFile () الخاص بك. إنه قلق من أن البرامج الأخرى تفترض أنه لا أحد يفتح الملفات بهذه الطريقة ، لأن MSVC fopen () لا يمكنه القيام بذلك. وبالتالي فإن هذه البرامج (التي لا تزال غير محددة) ستكسر برامج Go التي تحدد العلم.

أليكس ، يمكن للمرء أن يكرر محاولة إعادة التسمية إذا سمح بالوصول الخارجي ، ...

إذا كنت مستعدًا لتكرار إعادة التسمية ، فلن تحتاج إلى تغيير أي شيء في كود Go repo. سيعمل برنامجك جيدًا كما يعمل الآن.

في الوقت الحالي ، الحل الوحيد هو نسخ مجموعة من الأكواد من مكتبة Go القياسية ، وتغيير سطر واحد ، ثم الحفاظ على هذه الشوكة إلى الأبد.

أعتقد أن نسخ الكود إلى حزمة منفصلة أمر جيد. أثناء التحقيق في https://github.com/moby/moby/pull/39974 خطرت لي نفس الفكرة. لا أعتقد أن هناك الكثير من التعليمات البرمجية هناك للحفاظ عليها. في الحقيقة لقد نفذت ذلك بالضبط

https://github.com/alexbrainman/goissue34681

لا تتردد في النسخ أو الاستخدام كما هو. ربما ، نظرًا لوجود الكثير من الاهتمام بهذه الوظيفة ، فأنت تقوم بالفعل بإنشاء حزمة مناسبة يمكن مشاركتها واستخدامها من قبل الآخرين. بهذه الطريقة يمكنك تحديثها باستمرار وإصلاح الأخطاء.

rsc ، قبل أن ترفض هذا ، دعنا نسمع رأي Alex في اقتراح O_ALLOW_DELETE الخاص بك.

أرجوك حاول

https://github.com/alexbrainman/goissue34681

أول. إذا لم تكن راضيًا لسبب ما ، فيمكننا مناقشة إضافة وظائف جديدة إلى Go repo.

شكرا لك.

اليكس

أشعر بخيبة أمل حقًا من هذا الرد.

نسخ هذه المجموعة الكبيرة من التعليمات البرمجية ، والتي لم يتم فهمها إلى حد كبير (مثل
لماذا يفعل هذا ما يفعله) فقط حتى نتمكن من إضافة خيار واحد
أن النظام نفسه يدعمه ، فقط هذا Go ، على الأرجح أفترض أنه لا
حتى عن قصد ، لا يوفر وسيلة لتمرير الخيار حتى
syscall.Open يبدو وكأنه موقف مثير للسخرية.

لماذا يجب علي إعادة كتابة syscall.Open لتمرير هذا الخيار؟

في السبت 5 أكتوبر 2019 الساعة 18:43 كتب Alex Brainman [email protected] :

أليكس ، يمكن للمرء أن يكرر محاولة إعادة التسمية إذا سمح بالوصول الخارجي ، ...

إذا كنت مستعدًا لإجراء تكرار لإعادة التسمية ، فلن تحتاج إلى تغيير أي شيء
في Go repo code. سيعمل برنامجك جيدًا كما يعمل الآن.

في الوقت الحالي ، الحل الوحيد هو نسخ مجموعة من التعليمات البرمجية حرفياً من
مكتبة Go القياسية ، وغير سطرًا واحدًا ، ثم احتفظ بهذه الشوكة إلى الأبد.

أعتقد أن نسخ الكود إلى حزمة منفصلة أمر جيد. أثناء التحقيق
moby / moby # 39974 https://github.com/moby/moby/pull/39974 حصلت على نفس الشيء
فكرة. لا أعتقد أن هناك الكثير من التعليمات البرمجية هناك للحفاظ عليها. في الحقيقة، أنا
نفذت ذلك فقط

https://github.com/alexbrainman/goissue34681

لا تتردد في النسخ أو الاستخدام كما هو. ربما ، في ضوء ذلك ، هناك الكثير من الاهتمام
هذه الوظيفة ، تقوم بالفعل بإنشاء حزمة مناسبة يمكن مشاركتها
ويستخدمه الآخرون. بهذه الطريقة يمكنك تحديثها باستمرار وإصلاح الأخطاء.

rsc https://github.com/rsc ، قبل أن ترفض هذا ، دعنا نسمع ماذا
يفكر أليكس في اقتراح O_ALLOW_DELETE الخاص بك.

أرجوك حاول

https://github.com/alexbrainman/goissue34681

أول. إذا لم تكن راضيًا لسبب ما ، فيمكننا مناقشة إضافة جديد
وظائف للذهاب الريبو.

شكرا لك.

اليكس

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/golang/go/issues/32088؟email_source=notifications&email_token=AAGDCZXHULQEMHAPTO6ZUJTQNFGE7A5CNFSM4HNPNYIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMEC38LXG43VMVBW63LN
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/AAGDCZWYUNMCTAGO567AV73QNFGE7ANCNFSM4HNPNYIA
.

>

  • بريان جوف

أشعر بخيبة أمل حقًا من هذا الرد.

أنا آسف لأنك تشعر بهذه الطريقة. لكن هل حاولت بالفعل استخدام الحزمة الخاصة بي؟

اليكس

rsc ، بما أن Alex يعارض أيضًا علامة () os.OpenFile ، ألا يجب أن نفعل شيئًا؟

ماذا عن وضع هذه الميزة خلف علم البناء؟

فيما يتعلق بما إذا كان Go يعمل بشكل جيد على Windows لما يقرب من 10 سنوات ، فهو بالتأكيد لم يحدث ، في حالة احتياجك إلى إعادة تسمية ملف مفتوح. (تم كسره أيضًا على أجهزة الكمبيوتر المحمولة التي تعمل بنظام Windows 8/10 على مدار السنوات السبع الماضية.)

لدي تفرع خاص بي من os.OpenFile و syscall.Open بالفعل في moby / moby.

لماذا نحن هنا رافضين للغاية؟

في الثلاثاء 8 أكتوبر 2019 الساعة 01:47 كتب Alex Brainman [email protected] :

أشعر بخيبة أمل حقًا من هذا الرد.

أنا آسف لأنك تشعر بهذه الطريقة. لكن هل حاولت بالفعل استخدام الحزمة الخاصة بي؟

اليكس

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/golang/go/issues/32088؟email_source=notifications&email_token=AAGDCZRV72GY4IJQJVJWMYTQNRCIHA5CNFSM4HNPNYIKYYY3PNVWWK3TUL52HS4DFVREXG43VMVBW39
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/AAGDCZRNYSMIE6BX77XJVWDQNRCIHANCNFSM4HNPNYIA
.

>

  • بريان جوف

أقترح رفض هذا الاقتراح المحدد. لن نقدم مجموعة من أخطاء أمان TOCTOU لمستخدمي Windows الذين اعتمدوا على السلوك الحالي لـ os.OpenFile.

السؤال الأكبر هنا هو ، "كيف يمكننا الكشف عن مجموعة كبيرة ومتنوعة من العلامات الشيقة لوظائف Windows CreateFile و NtCreateFile ؟" أتوقع أننا سنكون قادرين على معالجة تلك المقترحات المختلفة ، ولكن بالتأكيد ليس عن طريق تشغيلها جميعًا بشكل افتراضي كما يوحي هذا هنا.

@ zx2c4 هل قرأت الموضوع بأكمله؟ لم نتمكن من تحديد حالة واحدة لمستخدم Go الذي يعتمد على السلوك الحالي غير الموثق ، على الرغم من المحاولات المتكررة.

لقد مر أسبوع منذ https://github.com/golang/go/issues/32088#issuecomment -537590826 ، ولا يزال هناك الكثير من الإجماع الواضح ، مما يعني أنه يجب علينا رفض ذلك.

رفض.

لقد قمت بنشر ملخص للخيارات مع الإيجابيات والسلبيات في https://github.com/golang/go/issues/34681#issuecomment -565853605.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات